mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	Add CollatorNode and make validators request blocks from it
This commit is contained in:
		
							parent
							
								
									996c23e506
								
							
						
					
					
						commit
						53270a00e6
					
				
					 25 changed files with 577 additions and 33 deletions
				
			
		| 
						 | 
					@ -739,6 +739,10 @@ _ OracleBridgeParams = ConfigParam 71; // Ethereum bridge
 | 
				
			||||||
_ OracleBridgeParams = ConfigParam 72; // Binance Smart Chain bridge
 | 
					_ OracleBridgeParams = ConfigParam 72; // Binance Smart Chain bridge
 | 
				
			||||||
_ OracleBridgeParams = ConfigParam 73; // Polygon bridge
 | 
					_ OracleBridgeParams = ConfigParam 73; // Polygon bridge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set of collators: each collator is (workchain:int32 shard:int64 adnl_id:int256)
 | 
				
			||||||
 | 
					colator_set#a0 collators:(HashmapE 352 Unit) = CollatorSet;
 | 
				
			||||||
 | 
					_ CollatorSet = ConfigParam 81;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  PROOFS
 | 
					//  PROOFS
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,6 +253,10 @@ class PublicKey {
 | 
				
			||||||
  td::BufferSlice export_as_slice() const;
 | 
					  td::BufferSlice export_as_slice() const;
 | 
				
			||||||
  static td::Result<PublicKey> import(td::Slice s);
 | 
					  static td::Result<PublicKey> import(td::Slice s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool is_ed25519() const {
 | 
				
			||||||
 | 
					    return pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pubkeys::Ed25519 ed25519_value() const {
 | 
					  pubkeys::Ed25519 ed25519_value() const {
 | 
				
			||||||
    CHECK(pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>());
 | 
					    CHECK(pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>());
 | 
				
			||||||
    return pub_key_.get<pubkeys::Ed25519>();
 | 
					    return pub_key_.get<pubkeys::Ed25519>();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -572,6 +572,7 @@ engine.dht id:int256 = engine.Dht;
 | 
				
			||||||
engine.validatorTempKey key:int256 expire_at:int = engine.ValidatorTempKey;
 | 
					engine.validatorTempKey key:int256 expire_at:int = engine.ValidatorTempKey;
 | 
				
			||||||
engine.validatorAdnlAddress id:int256 expire_at:int = engine.ValidatorAdnlAddress;
 | 
					engine.validatorAdnlAddress id:int256 expire_at:int = engine.ValidatorAdnlAddress;
 | 
				
			||||||
engine.validator id:int256 temp_keys:(vector engine.validatorTempKey) adnl_addrs:(vector engine.validatorAdnlAddress) election_date:int expire_at:int = engine.Validator;
 | 
					engine.validator id:int256 temp_keys:(vector engine.validatorTempKey) adnl_addrs:(vector engine.validatorAdnlAddress) election_date:int expire_at:int = engine.Validator;
 | 
				
			||||||
 | 
					engine.collator adnl_id:int256 workchain:int shard:long = engine.Validator;
 | 
				
			||||||
engine.liteServer id:int256 port:int = engine.LiteServer;
 | 
					engine.liteServer id:int256 port:int = engine.LiteServer;
 | 
				
			||||||
engine.controlProcess id:int256 permissions:int = engine.ControlProcess;
 | 
					engine.controlProcess id:int256 permissions:int = engine.ControlProcess;
 | 
				
			||||||
engine.controlInterface id:int256 port:int allowed:(vector engine.controlProcess) = engine.ControlInterface; 
 | 
					engine.controlInterface id:int256 port:int allowed:(vector engine.controlProcess) = engine.ControlInterface; 
 | 
				
			||||||
| 
						 | 
					@ -582,7 +583,7 @@ engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNode
 | 
				
			||||||
engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
 | 
					engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
 | 
				
			||||||
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl) 
 | 
					engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl) 
 | 
				
			||||||
        dht:(vector engine.dht)
 | 
					        dht:(vector engine.dht)
 | 
				
			||||||
        validators:(vector engine.validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave)
 | 
					        validators:(vector engine.Validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave)
 | 
				
			||||||
        fullnodemasters:(vector engine.validator.fullNodeMaster)
 | 
					        fullnodemasters:(vector engine.validator.fullNodeMaster)
 | 
				
			||||||
        liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
 | 
					        liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
 | 
				
			||||||
        gc:engine.gc = engine.validator.Config; 
 | 
					        gc:engine.gc = engine.validator.Config; 
 | 
				
			||||||
| 
						 | 
					@ -690,6 +691,8 @@ engine.validator.generateBlockCandidate block_id:tonNode.BlockId = db.Candidate;
 | 
				
			||||||
engine.validator.getRequiredBlockCandidates = engine.validator.RequiredBlockCandidates;
 | 
					engine.validator.getRequiredBlockCandidates = engine.validator.RequiredBlockCandidates;
 | 
				
			||||||
engine.validator.importBlockCandidate block:db.candidate = engine.validator.Success;
 | 
					engine.validator.importBlockCandidate block:db.candidate = engine.validator.Success;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					engine.validator.addCollator adnl_id:int256 workchain:int shard:long = engine.validator.Success;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---types---
 | 
					---types---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
storage.pong = storage.Pong;
 | 
					storage.pong = storage.Pong;
 | 
				
			||||||
| 
						 | 
					@ -741,3 +744,10 @@ validatorSession.statsRound timestamp:long producers:(vector validatorSession.st
 | 
				
			||||||
validatorSession.stats id:tonNode.blockId timestamp:long self:int256 creator:int256 total_validators:int total_weight:long
 | 
					validatorSession.stats id:tonNode.blockId timestamp:long self:int256 creator:int256 total_validators:int total_weight:long
 | 
				
			||||||
    signatures:int signatures_weight:long approve_signatures:int approve_signatures_weight:long
 | 
					    signatures:int signatures_weight:long approve_signatures:int approve_signatures_weight:long
 | 
				
			||||||
    first_round:int rounds:(vector validatorSession.statsRound) = validatorSession.Stats;
 | 
					    first_round:int rounds:(vector validatorSession.statsRound) = validatorSession.Stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					collatorNode.generateBlockSuccess candidate:db.Candidate = collatorNode.GenerateBlockResult;
 | 
				
			||||||
 | 
					collatorNode.generateBlockError code:int message:string = collatorNode.GenerateBlockResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---functions---
 | 
				
			||||||
 | 
					collatorNode.generateBlock workchain:int shard:long min_mc_id:tonNode.blockIdExt prev_blocks:(vector tonNode.blockIdExt)
 | 
				
			||||||
 | 
					    creator:int256 = collatorNode.GenerateBlockResult;
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -397,6 +397,9 @@ struct Ed25519_PublicKey {
 | 
				
			||||||
  bool operator==(const Ed25519_PublicKey& other) const {
 | 
					  bool operator==(const Ed25519_PublicKey& other) const {
 | 
				
			||||||
    return _pubkey == other._pubkey;
 | 
					    return _pubkey == other._pubkey;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  bool operator!=(const Ed25519_PublicKey& other) const {
 | 
				
			||||||
 | 
					    return _pubkey != other._pubkey;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  bool clear() {
 | 
					  bool clear() {
 | 
				
			||||||
    _pubkey.set_zero();
 | 
					    _pubkey.set_zero();
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
| 
						 | 
					@ -479,4 +482,9 @@ struct ValidatorSessionConfig {
 | 
				
			||||||
  static const td::uint32 BLOCK_HASH_COVERS_DATA_FROM_VERSION = 2;
 | 
					  static const td::uint32 BLOCK_HASH_COVERS_DATA_FROM_VERSION = 2;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct CollatorNodeDescr {
 | 
				
			||||||
 | 
					  ShardIdFull shard;
 | 
				
			||||||
 | 
					  NodeIdShort adnl_id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ton
 | 
					}  // namespace ton
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1091,3 +1091,24 @@ td::Status ImportBlockCandidateQuery::receive(td::BufferSlice data) {
 | 
				
			||||||
  td::TerminalIO::out() << "successfully imported a block candidate\n";
 | 
					  td::TerminalIO::out() << "successfully imported a block candidate\n";
 | 
				
			||||||
  return td::Status::OK();
 | 
					  return td::Status::OK();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td::Status AddCollatorQuery::run() {
 | 
				
			||||||
 | 
					  TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token<ton::PublicKeyHash>());
 | 
				
			||||||
 | 
					  TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
 | 
				
			||||||
 | 
					  TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
 | 
				
			||||||
 | 
					  return td::Status::OK();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td::Status AddCollatorQuery::send() {
 | 
				
			||||||
 | 
					  auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addCollator>(
 | 
				
			||||||
 | 
					      adnl_id_.tl(), wc_, shard_);
 | 
				
			||||||
 | 
					  td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
 | 
				
			||||||
 | 
					  return td::Status::OK();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td::Status AddCollatorQuery::receive(td::BufferSlice data) {
 | 
				
			||||||
 | 
					  TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
 | 
				
			||||||
 | 
					                    "received incorrect answer: ");
 | 
				
			||||||
 | 
					  td::TerminalIO::out() << "successfully added collator\n";
 | 
				
			||||||
 | 
					  return td::Status::OK();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1163,3 +1163,27 @@ class ImportBlockCandidateQuery : public Query {
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  std::string file_;
 | 
					  std::string file_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddCollatorQuery : public Query {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  AddCollatorQuery(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 data) override;
 | 
				
			||||||
 | 
					  static std::string get_name() {
 | 
				
			||||||
 | 
					    return "addcollator";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  static std::string get_help() {
 | 
				
			||||||
 | 
					    return "addcollator <adnl_id> <workchain> <shard>\tadd 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_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,6 +144,7 @@ void ValidatorEngineConsole::run() {
 | 
				
			||||||
  add_query_runner(std::make_unique<QueryRunnerImpl<GenerateBlockCandidateQuery>>());
 | 
					  add_query_runner(std::make_unique<QueryRunnerImpl<GenerateBlockCandidateQuery>>());
 | 
				
			||||||
  add_query_runner(std::make_unique<QueryRunnerImpl<GetRequiredBlockCandidatesQuery>>());
 | 
					  add_query_runner(std::make_unique<QueryRunnerImpl<GetRequiredBlockCandidatesQuery>>());
 | 
				
			||||||
  add_query_runner(std::make_unique<QueryRunnerImpl<ImportBlockCandidateQuery>>());
 | 
					  add_query_runner(std::make_unique<QueryRunnerImpl<ImportBlockCandidateQuery>>());
 | 
				
			||||||
 | 
					  add_query_runner(std::make_unique<QueryRunnerImpl<AddCollatorQuery>>());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
					bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,15 +125,24 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
 | 
				
			||||||
  for (auto &dht : config.dht_) {
 | 
					  for (auto &dht : config.dht_) {
 | 
				
			||||||
    config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure();
 | 
					    config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  for (auto &val : config.validators_) {
 | 
					  for (auto &v : config.validators_) {
 | 
				
			||||||
    auto key = ton::PublicKeyHash{val->id_};
 | 
					    ton::ton_api::downcast_call(
 | 
				
			||||||
    config_add_validator_permanent_key(key, val->election_date_, val->expire_at_).ensure();
 | 
					        *v, td::overloaded(
 | 
				
			||||||
    for (auto &temp : val->temp_keys_) {
 | 
					                [&](ton::ton_api::engine_validator &val) {
 | 
				
			||||||
      config_add_validator_temp_key(key, ton::PublicKeyHash{temp->key_}, temp->expire_at_).ensure();
 | 
					                  auto key = ton::PublicKeyHash{val.id_};
 | 
				
			||||||
    }
 | 
					                  config_add_validator_permanent_key(key, val.election_date_, val.expire_at_).ensure();
 | 
				
			||||||
    for (auto &adnl : val->adnl_addrs_) {
 | 
					                  for (auto &temp : val.temp_keys_) {
 | 
				
			||||||
      config_add_validator_adnl_id(key, ton::PublicKeyHash{adnl->id_}, adnl->expire_at_).ensure();
 | 
					                    config_add_validator_temp_key(key, ton::PublicKeyHash{temp->key_}, temp->expire_at_).ensure();
 | 
				
			||||||
    }
 | 
					                  }
 | 
				
			||||||
 | 
					                  for (auto &adnl : val.adnl_addrs_) {
 | 
				
			||||||
 | 
					                    config_add_validator_adnl_id(key, ton::PublicKeyHash{adnl->id_}, adnl->expire_at_).ensure();
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                [&](ton::ton_api::engine_collator &col) {
 | 
				
			||||||
 | 
					                  auto key = ton::PublicKeyHash{col.adnl_id_};
 | 
				
			||||||
 | 
					                  ton::ShardIdFull shard(col.workchain_, col.shard_);
 | 
				
			||||||
 | 
					                  config_add_collator(key, shard).ensure();
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure();
 | 
					  config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -192,7 +201,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
 | 
				
			||||||
    dht_vec.push_back(ton::create_tl_object<ton::ton_api::engine_dht>(x.tl()));
 | 
					    dht_vec.push_back(ton::create_tl_object<ton::ton_api::engine_dht>(x.tl()));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator>> val_vec;
 | 
					  std::vector<ton::tl_object_ptr<ton::ton_api::engine_Validator>> val_vec;
 | 
				
			||||||
  for (auto &val : validators) {
 | 
					  for (auto &val : validators) {
 | 
				
			||||||
    std::vector<ton::tl_object_ptr<ton::ton_api::engine_validatorTempKey>> temp_vec;
 | 
					    std::vector<ton::tl_object_ptr<ton::ton_api::engine_validatorTempKey>> temp_vec;
 | 
				
			||||||
    for (auto &t : val.second.temp_keys) {
 | 
					    for (auto &t : val.second.temp_keys) {
 | 
				
			||||||
| 
						 | 
					@ -205,6 +214,10 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
 | 
				
			||||||
    val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator>(
 | 
					    val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator>(
 | 
				
			||||||
        val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at));
 | 
					        val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  for (auto &col : collators) {
 | 
				
			||||||
 | 
					    val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_collator>(
 | 
				
			||||||
 | 
					        col.adnl_id.tl(), col.shard.workchain, col.shard.shard));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeSlave>> full_node_slaves_vec;
 | 
					  std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeSlave>> full_node_slaves_vec;
 | 
				
			||||||
  for (auto &x : full_node_slaves) {
 | 
					  for (auto &x : full_node_slaves) {
 | 
				
			||||||
| 
						 | 
					@ -383,6 +396,18 @@ td::Result<bool> Config::config_add_validator_adnl_id(ton::PublicKeyHash perm_ke
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td::Result<bool> Config::config_add_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};
 | 
				
			||||||
 | 
					  if (std::find(collators.begin(), collators.end(), c) != collators.end()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  collators.push_back(c);
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::Result<bool> Config::config_add_full_node_adnl_id(ton::PublicKeyHash id) {
 | 
					td::Result<bool> Config::config_add_full_node_adnl_id(ton::PublicKeyHash id) {
 | 
				
			||||||
  if (full_node == id) {
 | 
					  if (full_node == id) {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
| 
						 | 
					@ -1836,6 +1861,19 @@ void ValidatorEngine::start_lite_server() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ValidatorEngine::started_lite_server() {
 | 
					void ValidatorEngine::started_lite_server() {
 | 
				
			||||||
 | 
					  start_collator();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ValidatorEngine::start_collator() {
 | 
				
			||||||
 | 
					  for (auto &c : config_.collators) {
 | 
				
			||||||
 | 
					    td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator,
 | 
				
			||||||
 | 
					                            ton::adnl::AdnlNodeIdShort(c.adnl_id), c.shard);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  started_collator();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ValidatorEngine::started_collator() {
 | 
				
			||||||
  start_control_interface();
 | 
					  start_control_interface();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3395,6 +3433,47 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_importBlo
 | 
				
			||||||
                          });
 | 
					                          });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCollator &query,
 | 
				
			||||||
 | 
					                                        td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
 | 
				
			||||||
 | 
					                                        td::Promise<td::BufferSlice> 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::ShardIdFull(query.workchain_, query.shard_);
 | 
				
			||||||
 | 
					  if (!shard.is_valid_ext()) {
 | 
				
			||||||
 | 
					    promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "invalid shard")));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto R = config_.config_add_collator(id, shard);
 | 
				
			||||||
 | 
					  if (R.is_error()) {
 | 
				
			||||||
 | 
					    promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!R.move_as_ok()) {
 | 
				
			||||||
 | 
					    promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!validator_manager_.empty()) {
 | 
				
			||||||
 | 
					    td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator,
 | 
				
			||||||
 | 
					                            ton::adnl::AdnlNodeIdShort(id), shard);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  write_config([promise = std::move(promise)](td::Result<td::Unit> 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<ton::ton_api::engine_validator_success>(), true));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
 | 
					void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
 | 
				
			||||||
                                            ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
 | 
					                                            ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
 | 
				
			||||||
                                            td::Promise<td::BufferSlice> promise) {
 | 
					                                            td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,14 @@ struct Config {
 | 
				
			||||||
    ton::UnixTime election_date;
 | 
					    ton::UnixTime election_date;
 | 
				
			||||||
    ton::UnixTime expire_at;
 | 
					    ton::UnixTime expire_at;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  struct Collator {
 | 
				
			||||||
 | 
					    ton::PublicKeyHash adnl_id;
 | 
				
			||||||
 | 
					    ton::ShardIdFull shard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool operator==(const Collator& b) const {
 | 
				
			||||||
 | 
					      return adnl_id == b.adnl_id && shard == b.shard;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  struct Control {
 | 
					  struct Control {
 | 
				
			||||||
    ton::PublicKeyHash key;
 | 
					    ton::PublicKeyHash key;
 | 
				
			||||||
    std::map<ton::PublicKeyHash, td::uint32> clients;
 | 
					    std::map<ton::PublicKeyHash, td::uint32> clients;
 | 
				
			||||||
| 
						 | 
					@ -81,6 +89,7 @@ struct Config {
 | 
				
			||||||
  std::map<ton::PublicKeyHash, AdnlCategory> adnl_ids;
 | 
					  std::map<ton::PublicKeyHash, AdnlCategory> adnl_ids;
 | 
				
			||||||
  std::set<ton::PublicKeyHash> dht_ids;
 | 
					  std::set<ton::PublicKeyHash> dht_ids;
 | 
				
			||||||
  std::map<ton::PublicKeyHash, Validator> validators;
 | 
					  std::map<ton::PublicKeyHash, Validator> validators;
 | 
				
			||||||
 | 
					  std::vector<Collator> collators;
 | 
				
			||||||
  ton::PublicKeyHash full_node = ton::PublicKeyHash::zero();
 | 
					  ton::PublicKeyHash full_node = ton::PublicKeyHash::zero();
 | 
				
			||||||
  std::vector<FullNodeSlave> full_node_slaves;
 | 
					  std::vector<FullNodeSlave> full_node_slaves;
 | 
				
			||||||
  std::map<td::int32, ton::PublicKeyHash> full_node_masters;
 | 
					  std::map<td::int32, ton::PublicKeyHash> full_node_masters;
 | 
				
			||||||
| 
						 | 
					@ -104,6 +113,7 @@ struct Config {
 | 
				
			||||||
                                                 ton::UnixTime expire_at);
 | 
					                                                 ton::UnixTime expire_at);
 | 
				
			||||||
  td::Result<bool> config_add_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id,
 | 
					  td::Result<bool> config_add_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id,
 | 
				
			||||||
                                                ton::UnixTime expire_at);
 | 
					                                                ton::UnixTime expire_at);
 | 
				
			||||||
 | 
					  td::Result<bool> config_add_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard);
 | 
				
			||||||
  td::Result<bool> config_add_full_node_adnl_id(ton::PublicKeyHash id);
 | 
					  td::Result<bool> config_add_full_node_adnl_id(ton::PublicKeyHash id);
 | 
				
			||||||
  td::Result<bool> config_add_full_node_slave(td::IPAddress addr, ton::PublicKey id);
 | 
					  td::Result<bool> config_add_full_node_slave(td::IPAddress addr, ton::PublicKey id);
 | 
				
			||||||
  td::Result<bool> config_add_full_node_master(td::int32 port, ton::PublicKeyHash id);
 | 
					  td::Result<bool> config_add_full_node_master(td::int32 port, ton::PublicKeyHash id);
 | 
				
			||||||
| 
						 | 
					@ -293,6 +303,8 @@ class ValidatorEngine : public td::actor::Actor {
 | 
				
			||||||
  void add_lite_server(ton::PublicKeyHash id, td::uint16 port);
 | 
					  void add_lite_server(ton::PublicKeyHash id, td::uint16 port);
 | 
				
			||||||
  void start_lite_server();
 | 
					  void start_lite_server();
 | 
				
			||||||
  void started_lite_server();
 | 
					  void started_lite_server();
 | 
				
			||||||
 | 
					  void start_collator();
 | 
				
			||||||
 | 
					  void started_collator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void add_control_interface(ton::PublicKeyHash id, td::uint16 port);
 | 
					  void add_control_interface(ton::PublicKeyHash id, td::uint16 port);
 | 
				
			||||||
  void add_control_process(ton::PublicKeyHash id, td::uint16 port, ton::PublicKeyHash pub, td::int32 permissions);
 | 
					  void add_control_process(ton::PublicKeyHash id, td::uint16 port, ton::PublicKeyHash pub, td::int32 permissions);
 | 
				
			||||||
| 
						 | 
					@ -419,6 +431,8 @@ class ValidatorEngine : public td::actor::Actor {
 | 
				
			||||||
                         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_importBlockCandidate &query, td::BufferSlice data,
 | 
					  void run_control_query(ton::ton_api::engine_validator_importBlockCandidate &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_addCollator &query, td::BufferSlice data,
 | 
				
			||||||
 | 
					                         ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
 | 
				
			||||||
  template <class T>
 | 
					  template <class T>
 | 
				
			||||||
  void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
 | 
					  void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
 | 
				
			||||||
                         td::Promise<td::BufferSlice> promise) {
 | 
					                         td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,7 @@ set(VALIDATOR_HEADERS
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  import-db-slice.hpp
 | 
					  import-db-slice.hpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  collator-node.hpp
 | 
				
			||||||
  manager-disk.h
 | 
					  manager-disk.h
 | 
				
			||||||
  manager-disk.hpp
 | 
					  manager-disk.hpp
 | 
				
			||||||
  manager-init.h
 | 
					  manager-init.h
 | 
				
			||||||
| 
						 | 
					@ -68,6 +69,7 @@ set(VALIDATOR_HEADERS
 | 
				
			||||||
set(VALIDATOR_SOURCE
 | 
					set(VALIDATOR_SOURCE
 | 
				
			||||||
  apply-block.cpp
 | 
					  apply-block.cpp
 | 
				
			||||||
  block-handle.cpp
 | 
					  block-handle.cpp
 | 
				
			||||||
 | 
					  collator-node.cpp
 | 
				
			||||||
  get-next-key-blocks.cpp
 | 
					  get-next-key-blocks.cpp
 | 
				
			||||||
  import-db-slice.cpp
 | 
					  import-db-slice.cpp
 | 
				
			||||||
  shard-client.cpp
 | 
					  shard-client.cpp
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										145
									
								
								validator/collator-node.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								validator/collator-node.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,145 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    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 "collator-node.hpp"
 | 
				
			||||||
 | 
					#include "ton/ton-tl.hpp"
 | 
				
			||||||
 | 
					#include "fabric.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ton {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace validator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CollatorNode::CollatorNode(adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ValidatorManager> manager,
 | 
				
			||||||
 | 
					                           td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp)
 | 
				
			||||||
 | 
					    : local_id_(local_id), manager_(std::move(manager)), adnl_(std::move(adnl)), rldp_(std::move(rldp)) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CollatorNode::start_up() {
 | 
				
			||||||
 | 
					  class Cb : public adnl::Adnl::Callback {
 | 
				
			||||||
 | 
					   public:
 | 
				
			||||||
 | 
					    Cb(td::actor::ActorId<CollatorNode> id) : id_(std::move(id)) {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data,
 | 
				
			||||||
 | 
					                       td::Promise<td::BufferSlice> promise) override {
 | 
				
			||||||
 | 
					      td::actor::send_closure(id_, &CollatorNode::receive_query, src, std::move(data), std::move(promise));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   private:
 | 
				
			||||||
 | 
					    td::actor::ActorId<CollatorNode> id_;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id_,
 | 
				
			||||||
 | 
					                          adnl::Adnl::int_to_bytestring(ton_api::collatorNode_generateBlock::ID),
 | 
				
			||||||
 | 
					                          std::make_unique<Cb>(actor_id(this)));
 | 
				
			||||||
 | 
					  td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl::AdnlNodeIdShort(local_id_));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CollatorNode::tear_down() {
 | 
				
			||||||
 | 
					  td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id_,
 | 
				
			||||||
 | 
					                          adnl::Adnl::int_to_bytestring(ton_api::collatorNode_generateBlock::ID));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CollatorNode::add_shard(ShardIdFull shard) {
 | 
				
			||||||
 | 
					  LOG(INFO) << "Collator node: local_id=" << local_id_ << " , shard=" << shard.to_str();
 | 
				
			||||||
 | 
					  shards_.push_back(shard);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static td::BufferSlice serialize_error(td::Status error) {
 | 
				
			||||||
 | 
					  return create_serialize_tl_object<ton_api::collatorNode_generateBlockError>(error.code(), error.message().c_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CollatorNode::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
 | 
				
			||||||
 | 
					                                 td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
 | 
					  auto status = [&]() -> td::Status {
 | 
				
			||||||
 | 
					    TRY_RESULT(f, fetch_tl_object<ton_api::collatorNode_generateBlock>(std::move(data), true));
 | 
				
			||||||
 | 
					    ShardIdFull shard(f->workchain_, f->shard_);
 | 
				
			||||||
 | 
					    if (!shard.is_valid_ext()) {
 | 
				
			||||||
 | 
					      return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    bool found = false;
 | 
				
			||||||
 | 
					    for (ShardIdFull our_shard : shards_) {
 | 
				
			||||||
 | 
					      if (shard_is_ancestor(shard, our_shard)) {
 | 
				
			||||||
 | 
					        found = true;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!found) {
 | 
				
			||||||
 | 
					      return td::Status::Error(PSTRING() << "this node doesn't collate shard " << shard.to_str());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (f->prev_blocks_.size() != 1 && f->prev_blocks_.size() != 2) {
 | 
				
			||||||
 | 
					      return td::Status::Error(PSTRING() << "invalid size of prev_blocks: " << f->prev_blocks_.size());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::vector<BlockIdExt> prev_blocks;
 | 
				
			||||||
 | 
					    for (const auto& b : f->prev_blocks_) {
 | 
				
			||||||
 | 
					      prev_blocks.push_back(create_block_id(b));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    BlockIdExt min_mc_id = create_block_id(f->min_mc_id_);
 | 
				
			||||||
 | 
					    Ed25519_PublicKey creator(f->creator_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LOG(INFO) << "Query from " << src << ": shard=" << shard.to_str() << ", min_mc_id=" << min_mc_id.to_str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto P = td::PromiseCreator::lambda([=, SelfId = actor_id(this), prev_blocks = std::move(prev_blocks),
 | 
				
			||||||
 | 
					                                         promise = std::move(promise)](td::Result<td::Ref<ShardState>> R) mutable {
 | 
				
			||||||
 | 
					      if (R.is_error()) {
 | 
				
			||||||
 | 
					        LOG(WARNING) << "Query from " << src << ", error: " << R.error();
 | 
				
			||||||
 | 
					        promise.set_result(serialize_error(R.move_as_error_prefix("failed to get masterchain state: ")));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        td::Ref<MasterchainState> state(R.move_as_ok());
 | 
				
			||||||
 | 
					        if (state.is_null()) {
 | 
				
			||||||
 | 
					          LOG(WARNING) << "Query from " << src << ", error: failed to get masterchain state";
 | 
				
			||||||
 | 
					          promise.set_result(serialize_error(R.move_as_error_prefix("failed to get masterchain state: ")));
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        td::actor::send_closure(SelfId, &CollatorNode::receive_query_cont, src, shard, std::move(state),
 | 
				
			||||||
 | 
					                                std::move(prev_blocks), creator, std::move(promise));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, min_mc_id, 1, td::Timestamp::in(5.0),
 | 
				
			||||||
 | 
					                            std::move(P));
 | 
				
			||||||
 | 
					    return td::Status::OK();
 | 
				
			||||||
 | 
					  }();
 | 
				
			||||||
 | 
					  if (status.is_error()) {
 | 
				
			||||||
 | 
					    LOG(WARNING) << "Query from " << src << ", error: " << status;
 | 
				
			||||||
 | 
					    promise.set_result(serialize_error(std::move(status)));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CollatorNode::receive_query_cont(adnl::AdnlNodeIdShort src, ShardIdFull shard,
 | 
				
			||||||
 | 
					                                      td::Ref<MasterchainState> min_mc_state, std::vector<BlockIdExt> prev_blocks,
 | 
				
			||||||
 | 
					                                      Ed25519_PublicKey creator, td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
 | 
					  auto P = td::PromiseCreator::lambda([promise = std::move(promise), src](td::Result<BlockCandidate> R) mutable {
 | 
				
			||||||
 | 
					      if (R.is_error()) {
 | 
				
			||||||
 | 
					        LOG(WARNING) << "Query from " << src << ", error: " << R.error();
 | 
				
			||||||
 | 
					        promise.set_result(serialize_error(R.move_as_error()));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        LOG(INFO) << "Query from " << src << ", success";
 | 
				
			||||||
 | 
					        auto block = R.move_as_ok();
 | 
				
			||||||
 | 
					        auto result = create_serialize_tl_object<ton_api::collatorNode_generateBlockSuccess>(
 | 
				
			||||||
 | 
					            create_tl_object<ton_api::db_candidate>(PublicKey{pubkeys::Ed25519{block.pubkey.as_bits256()}}.tl(),
 | 
				
			||||||
 | 
					                                                    create_tl_block_id(block.id), std::move(block.data),
 | 
				
			||||||
 | 
					                                                    std::move(block.collated_data)));
 | 
				
			||||||
 | 
					        promise.set_result(std::move(result));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run_collate_query(shard, min_mc_state->get_block_id(), std::move(prev_blocks), creator,
 | 
				
			||||||
 | 
					                    min_mc_state->get_validator_set(shard), manager_, td::Timestamp::in(10.0), std::move(P));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace validator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ton
 | 
				
			||||||
							
								
								
									
										51
									
								
								validator/collator-node.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								validator/collator-node.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    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 "interfaces/validator-manager.h"
 | 
				
			||||||
 | 
					#include "rldp/rldp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ton {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace validator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ValidatorManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CollatorNode : public td::actor::Actor {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  CollatorNode(adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ValidatorManager> manager,
 | 
				
			||||||
 | 
					               td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp);
 | 
				
			||||||
 | 
					  void start_up() override;
 | 
				
			||||||
 | 
					  void tear_down() override;
 | 
				
			||||||
 | 
					  void add_shard(ShardIdFull shard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
 | 
				
			||||||
 | 
					  void receive_query_cont(adnl::AdnlNodeIdShort src, ShardIdFull shard, td::Ref<MasterchainState> min_mc_state,
 | 
				
			||||||
 | 
					                          std::vector<BlockIdExt> prev_blocks, Ed25519_PublicKey creator,
 | 
				
			||||||
 | 
					                          td::Promise<td::BufferSlice> promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  adnl::AdnlNodeIdShort local_id_;
 | 
				
			||||||
 | 
					  td::actor::ActorId<ValidatorManager> manager_;
 | 
				
			||||||
 | 
					  td::actor::ActorId<adnl::Adnl> adnl_;
 | 
				
			||||||
 | 
					  td::actor::ActorId<rldp::Rldp> rldp_;
 | 
				
			||||||
 | 
					  std::vector<ShardIdFull> shards_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace validator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ton
 | 
				
			||||||
| 
						 | 
					@ -364,7 +364,8 @@ td::Status MasterchainStateQ::mc_init() {
 | 
				
			||||||
td::Status MasterchainStateQ::mc_reinit() {
 | 
					td::Status MasterchainStateQ::mc_reinit() {
 | 
				
			||||||
  auto res = block::ConfigInfo::extract_config(
 | 
					  auto res = block::ConfigInfo::extract_config(
 | 
				
			||||||
      root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet |
 | 
					      root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet |
 | 
				
			||||||
                       block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks);
 | 
					                       block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks |
 | 
				
			||||||
 | 
					                       block::ConfigInfo::needWorkchainInfo);
 | 
				
			||||||
  cur_validators_.reset();
 | 
					  cur_validators_.reset();
 | 
				
			||||||
  next_validators_.reset();
 | 
					  next_validators_.reset();
 | 
				
			||||||
  if (res.is_error()) {
 | 
					  if (res.is_error()) {
 | 
				
			||||||
| 
						 | 
					@ -510,6 +511,27 @@ bool MasterchainStateQ::check_old_mc_block_id(const ton::BlockIdExt& blkid, bool
 | 
				
			||||||
  return config_ && config_->check_old_mc_block_id(blkid, strict);
 | 
					  return config_ && config_->check_old_mc_block_id(blkid, strict);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<CollatorNodeDescr> MasterchainStateQ::get_collator_set() const {
 | 
				
			||||||
 | 
					  block::gen::CollatorSet::Record rec;
 | 
				
			||||||
 | 
					  auto cell = config_->get_config_param(81);
 | 
				
			||||||
 | 
					  if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  vm::Dictionary dict{rec.collators->prefetch_ref(), 32 + 64 + 256};
 | 
				
			||||||
 | 
					  std::vector<CollatorNodeDescr> collators;
 | 
				
			||||||
 | 
					  dict.check_for_each([&](Ref<vm::CellSlice>, td::ConstBitPtr key, int n) {
 | 
				
			||||||
 | 
					    CHECK(n == 32 + 64 + 256);
 | 
				
			||||||
 | 
					    auto workchain = (td::int32)key.get_int(32);
 | 
				
			||||||
 | 
					    key.advance(32);
 | 
				
			||||||
 | 
					    td::uint64 shard = key.get_uint(64);
 | 
				
			||||||
 | 
					    key.advance(64);
 | 
				
			||||||
 | 
					    td::Bits256 adnl_id(key);
 | 
				
			||||||
 | 
					    collators.push_back({ShardIdFull(workchain, shard), adnl_id});
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return collators;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
 | 
					td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
 | 
				
			||||||
  if (!config_) {
 | 
					  if (!config_) {
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,6 +147,10 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
 | 
				
			||||||
      return td::make_ref<ConfigHolderQ>(config_);
 | 
					      return td::make_ref<ConfigHolderQ>(config_);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  block::WorkchainSet get_workchain_list() const override {
 | 
				
			||||||
 | 
					    return config_ ? config_->get_workchain_list() : block::WorkchainSet();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  std::vector<CollatorNodeDescr> get_collator_set() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  ZeroStateIdExt zerostate_id_;
 | 
					  ZeroStateIdExt zerostate_id_;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -448,7 +448,6 @@ bool ValidateQuery::init_parse() {
 | 
				
			||||||
    return reject_query("after_merge value mismatch in block header");
 | 
					    return reject_query("after_merge value mismatch in block header");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  rand_seed_ = extra.rand_seed;
 | 
					  rand_seed_ = extra.rand_seed;
 | 
				
			||||||
  created_by_ = extra.created_by;
 | 
					 | 
				
			||||||
  if (created_by_ != extra.created_by) {
 | 
					  if (created_by_ != extra.created_by) {
 | 
				
			||||||
    return reject_query("block candidate "s + id_.to_str() + " has creator " + created_by_.to_hex() +
 | 
					    return reject_query("block candidate "s + id_.to_str() + " has creator " + created_by_.to_hex() +
 | 
				
			||||||
                        " but the block header contains different value " + extra.created_by.to_hex());
 | 
					                        " but the block header contains different value " + extra.created_by.to_hex());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,6 +81,8 @@ class MasterchainState : virtual public ShardState {
 | 
				
			||||||
                                   ton::LogicalTime* end_lt = nullptr) const = 0;
 | 
					                                   ton::LogicalTime* end_lt = nullptr) const = 0;
 | 
				
			||||||
  virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0;
 | 
					  virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0;
 | 
				
			||||||
  virtual td::Result<td::Ref<ConfigHolder>> get_config_holder() const = 0;
 | 
					  virtual td::Result<td::Ref<ConfigHolder>> get_config_holder() const = 0;
 | 
				
			||||||
 | 
					  virtual block::WorkchainSet get_workchain_list() const = 0;
 | 
				
			||||||
 | 
					  virtual std::vector<CollatorNodeDescr> get_collator_set() const = 0;
 | 
				
			||||||
  virtual td::Status prepare() {
 | 
					  virtual td::Status prepare() {
 | 
				
			||||||
    return td::Status::OK();
 | 
					    return td::Status::OK();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -384,6 +384,10 @@ class ValidatorManagerImpl : public ValidatorManager {
 | 
				
			||||||
    UNREACHABLE();
 | 
					    UNREACHABLE();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
 | 
				
			||||||
 | 
					    UNREACHABLE();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  PublicKeyHash local_id_;
 | 
					  PublicKeyHash local_id_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -443,6 +443,9 @@ class ValidatorManagerImpl : public ValidatorManager {
 | 
				
			||||||
    UNREACHABLE();
 | 
					    UNREACHABLE();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
 | 
				
			||||||
 | 
					    UNREACHABLE();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  td::Ref<ValidatorManagerOptions> opts_;
 | 
					  td::Ref<ValidatorManagerOptions> opts_;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2025,7 +2025,8 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
 | 
				
			||||||
    auto validator_id = get_validator(shard, validator_set);
 | 
					    auto validator_id = get_validator(shard, validator_set);
 | 
				
			||||||
    CHECK(!validator_id.is_zero());
 | 
					    CHECK(!validator_id.is_zero());
 | 
				
			||||||
    auto G = td::actor::create_actor<ValidatorGroup>(
 | 
					    auto G = td::actor::create_actor<ValidatorGroup>(
 | 
				
			||||||
        "validatorgroup", shard, validator_id, session_id, validator_set, opts, keyring_, adnl_, rldp_, overlays_,
 | 
					        "validatorgroup", shard, validator_id, session_id, validator_set, last_masterchain_state_->get_collator_set(),
 | 
				
			||||||
 | 
					        opts, keyring_, adnl_, rldp_, overlays_,
 | 
				
			||||||
        db_root_, actor_id(this), init_session,
 | 
					        db_root_, actor_id(this), init_session,
 | 
				
			||||||
        opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), true);
 | 
					        opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), true);
 | 
				
			||||||
    return G;
 | 
					    return G;
 | 
				
			||||||
| 
						 | 
					@ -2692,6 +2693,15 @@ void ValidatorManagerImpl::cleanup_old_pending_candidates(BlockId block_id, td::
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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>("collatornode", id, actor_id(this), adnl_, rldp_);
 | 
				
			||||||
 | 
					    it = collator_nodes_.emplace(id, std::move(actor)).first;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  td::actor::send_closure(it->second, &CollatorNode::add_shard, shard);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
 | 
					td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
 | 
				
			||||||
    td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
 | 
					    td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
 | 
				
			||||||
    td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
 | 
					    td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@
 | 
				
			||||||
#include "state-serializer.hpp"
 | 
					#include "state-serializer.hpp"
 | 
				
			||||||
#include "rldp/rldp.h"
 | 
					#include "rldp/rldp.h"
 | 
				
			||||||
#include "token-manager.h"
 | 
					#include "token-manager.h"
 | 
				
			||||||
 | 
					#include "collator-node.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
| 
						 | 
					@ -539,6 +540,8 @@ class ValidatorManagerImpl : public ValidatorManager {
 | 
				
			||||||
  void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
 | 
					  void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
 | 
				
			||||||
  void wait_block_candidate(BlockId block_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise) override;
 | 
					  void wait_block_candidate(BlockId block_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  td::Timestamp resend_shard_blocks_at_;
 | 
					  td::Timestamp resend_shard_blocks_at_;
 | 
				
			||||||
  td::Timestamp check_waiters_at_;
 | 
					  td::Timestamp check_waiters_at_;
 | 
				
			||||||
| 
						 | 
					@ -606,6 +609,8 @@ class ValidatorManagerImpl : public ValidatorManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::map<BlockId, std::vector<std::pair<td::Promise<BlockCandidate>, td::Timestamp>>> pending_block_candidates_;
 | 
					  std::map<BlockId, std::vector<std::pair<td::Promise<BlockCandidate>, td::Timestamp>>> pending_block_candidates_;
 | 
				
			||||||
  void cleanup_old_pending_candidates(BlockId block_id, td::Timestamp now);
 | 
					  void cleanup_old_pending_candidates(BlockId block_id, td::Timestamp now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::map<adnl::AdnlNodeIdShort, td::actor::ActorOwn<CollatorNode>> collator_nodes_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace validator
 | 
					}  // namespace validator
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,9 +248,11 @@ void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> pro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ShardClient::build_shard_overlays() {
 | 
					void ShardClient::build_shard_overlays() {
 | 
				
			||||||
  auto v = masterchain_state_->get_shards();
 | 
					  auto v = masterchain_state_->get_shards();
 | 
				
			||||||
 | 
					  std::set<WorkchainId> workchains;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (auto &x : v) {
 | 
					  for (auto &x : v) {
 | 
				
			||||||
    auto shard = x->shard();
 | 
					    auto shard = x->shard();
 | 
				
			||||||
 | 
					    workchains.insert(shard.workchain);
 | 
				
			||||||
    if (opts_->need_monitor(shard)) {
 | 
					    if (opts_->need_monitor(shard)) {
 | 
				
			||||||
      auto d = masterchain_state_->soft_min_split_depth(shard.workchain);
 | 
					      auto d = masterchain_state_->soft_min_split_depth(shard.workchain);
 | 
				
			||||||
      auto l = shard_prefix_length(shard.shard);
 | 
					      auto l = shard_prefix_length(shard.shard);
 | 
				
			||||||
| 
						 | 
					@ -264,6 +266,20 @@ void ShardClient::build_shard_overlays() {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const auto &wpair : masterchain_state_->get_workchain_list()) {
 | 
				
			||||||
 | 
					    ton::WorkchainId wc = wpair.first;
 | 
				
			||||||
 | 
					    const block::WorkchainInfo *winfo = wpair.second.get();
 | 
				
			||||||
 | 
					    if (workchains.count(wc) == 0 && winfo->active && winfo->enabled_since <= masterchain_state_->get_unix_time()) {
 | 
				
			||||||
 | 
					      auto shard = ShardIdFull(wc);
 | 
				
			||||||
 | 
					      if (opts_->need_monitor(shard) && created_overlays_.count(shard) == 0) {
 | 
				
			||||||
 | 
					        td::actor::send_closure(manager_, &ValidatorManager::subscribe_to_shard, shard);
 | 
				
			||||||
 | 
					        BlockIdExt block_id(shard.workchain, shard.shard, 0, winfo->zerostate_root_hash, winfo->zerostate_file_hash);
 | 
				
			||||||
 | 
					        td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, block_id, 0,
 | 
				
			||||||
 | 
					                                      td::Timestamp::in(5.0), [](td::Result<td::Ref<ShardState>>) {});
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {
 | 
					void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "td/utils/overloaded.h"
 | 
					#include "td/utils/overloaded.h"
 | 
				
			||||||
#include "common/delay.h"
 | 
					#include "common/delay.h"
 | 
				
			||||||
#include "ton/ton-tl.hpp"
 | 
					#include "ton/ton-tl.hpp"
 | 
				
			||||||
 | 
					#include "td/utils/Random.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ton {
 | 
					namespace ton {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,19 +37,7 @@ void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<B
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (lite_mode_) {
 | 
					  if (lite_mode_) {
 | 
				
			||||||
    auto P = td::PromiseCreator::lambda(
 | 
					    send_collate_query(round_id, td::Timestamp::in(10.0), std::move(promise));
 | 
				
			||||||
        [promise = std::move(promise),
 | 
					 | 
				
			||||||
         pubkey = Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}](td::Result<BlockCandidate> R) mutable {
 | 
					 | 
				
			||||||
          if (R.is_error()) {
 | 
					 | 
				
			||||||
            promise.set_error(R.move_as_error());
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            BlockCandidate candidate = R.move_as_ok();
 | 
					 | 
				
			||||||
            candidate.pubkey = pubkey;
 | 
					 | 
				
			||||||
            promise.set_result(std::move(candidate));
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    td::actor::send_closure(manager_, &ValidatorManager::wait_block_candidate, create_next_block_id_simple(),
 | 
					 | 
				
			||||||
                            td::Timestamp::in(15.0), std::move(P));
 | 
					 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  run_collate_query(shard_, min_masterchain_block_id_, prev_block_ids_,
 | 
					  run_collate_query(shard_, min_masterchain_block_id_, prev_block_ids_,
 | 
				
			||||||
| 
						 | 
					@ -65,6 +54,17 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
 | 
				
			||||||
    promise.set_error(td::Status::Error(ErrorCode::notready, "too old"));
 | 
					    promise.set_error(td::Status::Error(ErrorCode::notready, "too old"));
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (approved_candidates_cache_round_ != round_id) {
 | 
				
			||||||
 | 
					    approved_candidates_cache_round_ = round_id;
 | 
				
			||||||
 | 
					    approved_candidates_cache_.clear();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  CacheKey cache_key = block_to_cache_key(block);
 | 
				
			||||||
 | 
					  auto it = approved_candidates_cache_.find(cache_key);
 | 
				
			||||||
 | 
					  if (it != approved_candidates_cache_.end()) {
 | 
				
			||||||
 | 
					    promise.set_result(it->second);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), round_id, block = block.clone(),
 | 
					  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), round_id, block = block.clone(),
 | 
				
			||||||
                                       promise = std::move(promise)](td::Result<ValidateCandidateResult> R) mutable {
 | 
					                                       promise = std::move(promise)](td::Result<ValidateCandidateResult> R) mutable {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
| 
						 | 
					@ -80,11 +80,16 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
 | 
				
			||||||
          td::Timestamp::in(0.1));
 | 
					          td::Timestamp::in(0.1));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      auto v = R.move_as_ok();
 | 
					      auto v = R.move_as_ok();
 | 
				
			||||||
      v.visit(td::overloaded([&](UnixTime ts) { promise.set_result(ts); },
 | 
					      v.visit(td::overloaded(
 | 
				
			||||||
                             [&](CandidateReject reject) {
 | 
					          [&](UnixTime ts) {
 | 
				
			||||||
                               promise.set_error(td::Status::Error(ErrorCode::protoviolation,
 | 
					            td::actor::send_closure(SelfId, &ValidatorGroup::update_approve_cache, round_id, block_to_cache_key(block),
 | 
				
			||||||
                                                                   PSTRING() << "bad candidate: " << reject.reason));
 | 
					                                    ts);
 | 
				
			||||||
                             }));
 | 
					            promise.set_result(ts);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          [&](CandidateReject reject) {
 | 
				
			||||||
 | 
					            promise.set_error(
 | 
				
			||||||
 | 
					                td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad candidate: " << reject.reason));
 | 
				
			||||||
 | 
					          }));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  if (!started_) {
 | 
					  if (!started_) {
 | 
				
			||||||
| 
						 | 
					@ -98,6 +103,14 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
 | 
				
			||||||
                     td::Timestamp::in(10.0), std::move(P), lite_mode_ ? ValidateMode::lite : 0);
 | 
					                     td::Timestamp::in(10.0), std::move(P), lite_mode_ ? ValidateMode::lite : 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ValidatorGroup::update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value) {
 | 
				
			||||||
 | 
					  if (approved_candidates_cache_round_ != round_id) {
 | 
				
			||||||
 | 
					    approved_candidates_cache_round_ = round_id;
 | 
				
			||||||
 | 
					    approved_candidates_cache_.clear();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  approved_candidates_cache_[key] = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block_data,
 | 
					void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block_data,
 | 
				
			||||||
                                            RootHash root_hash, FileHash file_hash,
 | 
					                                            RootHash root_hash, FileHash file_hash,
 | 
				
			||||||
                                            std::vector<BlockSignature> signatures,
 | 
					                                            std::vector<BlockSignature> signatures,
 | 
				
			||||||
| 
						 | 
					@ -339,6 +352,91 @@ void ValidatorGroup::get_session_info(
 | 
				
			||||||
  td::actor::send_closure(session_, &validatorsession::ValidatorSession::get_session_info, std::move(P));
 | 
					  td::actor::send_closure(session_, &validatorsession::ValidatorSession::get_session_info, std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ValidatorGroup::send_collate_query(td::uint32 round_id, td::Timestamp timeout,
 | 
				
			||||||
 | 
					                                        td::Promise<BlockCandidate> promise) {
 | 
				
			||||||
 | 
					  adnl::AdnlNodeIdShort collator = adnl::AdnlNodeIdShort::zero();
 | 
				
			||||||
 | 
					  // TODO: some other way for storing and choosing collators for real network
 | 
				
			||||||
 | 
					  int cnt = 0;
 | 
				
			||||||
 | 
					  for (const CollatorNodeDescr& c : collator_set_) {
 | 
				
			||||||
 | 
					    if (shard_is_ancestor(shard_, c.shard) && td::Random::fast(0, cnt) == 0) {
 | 
				
			||||||
 | 
					      collator = adnl::AdnlNodeIdShort(c.adnl_id);
 | 
				
			||||||
 | 
					      ++cnt;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (collator.is_zero()) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error(PSTRING() << "no collator for shard " << shard_.to_str()));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev_blocks;
 | 
				
			||||||
 | 
					  for (const BlockIdExt &p : prev_block_ids_) {
 | 
				
			||||||
 | 
					    prev_blocks.push_back(create_tl_block_id(p));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  td::BufferSlice query = create_serialize_tl_object<ton_api::collatorNode_generateBlock>(
 | 
				
			||||||
 | 
					      shard_.workchain, shard_.shard, create_tl_block_id(min_masterchain_block_id_), std::move(prev_blocks),
 | 
				
			||||||
 | 
					      local_id_full_.ed25519_value().raw());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto P = td::PromiseCreator::lambda(
 | 
				
			||||||
 | 
					      [SelfId = actor_id(this), round_id, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
 | 
					        if (R.is_error()) {
 | 
				
			||||||
 | 
					          promise.set_error(R.move_as_error_prefix("rldp query failed: "));
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        td::actor::send_closure(SelfId, &ValidatorGroup::receive_collate_query_response, round_id, R.move_as_ok(),
 | 
				
			||||||
 | 
					                                std::move(promise));
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  LOG(INFO) << "collate query for " << shard_.to_str() << ": send query to " << collator;
 | 
				
			||||||
 | 
					  size_t max_answer_size = config_.max_block_size + config_.max_collated_data_size + 256;
 | 
				
			||||||
 | 
					  td::actor::send_closure(rldp_, &rldp::Rldp::send_query_ex, adnl::AdnlNodeIdShort(local_id_), collator, "collatequery",
 | 
				
			||||||
 | 
					                          std::move(P), timeout, std::move(query), max_answer_size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ValidatorGroup::receive_collate_query_response(td::uint32 round_id, td::BufferSlice data,
 | 
				
			||||||
 | 
					                                                    td::Promise<BlockCandidate> promise) {
 | 
				
			||||||
 | 
					  if (round_id < last_known_round_id_) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error("too old"));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::collatorNode_GenerateBlockResult>(data, true));
 | 
				
			||||||
 | 
					  tl_object_ptr<ton_api::db_candidate> b;
 | 
				
			||||||
 | 
					  ton_api::downcast_call(*f, td::overloaded(
 | 
				
			||||||
 | 
					                                 [&](ton_api::collatorNode_generateBlockError &r) {
 | 
				
			||||||
 | 
					                                   td::Status error = td::Status::Error(r.code_, r.message_);
 | 
				
			||||||
 | 
					                                   promise.set_error(error.move_as_error_prefix("collate query: "));
 | 
				
			||||||
 | 
					                                 },
 | 
				
			||||||
 | 
					                                 [&](ton_api::collatorNode_generateBlockSuccess &r) { b = std::move(r.candidate_); }));
 | 
				
			||||||
 | 
					  if (!b) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  auto key = PublicKey{b->source_};
 | 
				
			||||||
 | 
					  if (!key.is_ed25519()) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  auto e_key = Ed25519_PublicKey{key.ed25519_value().raw()};
 | 
				
			||||||
 | 
					  if (e_key != Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  auto block_id = ton::create_block_id(b->id_);
 | 
				
			||||||
 | 
					  if (block_id.shard_full() != shard_) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error("collate query: shard mismatch"));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  auto collated_data_hash = td::sha256_bits256(b->collated_data_);
 | 
				
			||||||
 | 
					  BlockCandidate candidate(e_key, block_id, collated_data_hash, std::move(b->data_), std::move(b->collated_data_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto P = td::PromiseCreator::lambda(
 | 
				
			||||||
 | 
					      [candidate = candidate.clone(), promise = std::move(promise)](td::Result<UnixTime> R) mutable {
 | 
				
			||||||
 | 
					        if (R.is_error()) {
 | 
				
			||||||
 | 
					          promise.set_error(R.move_as_error_prefix("validate received block error: "));
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        promise.set_result(std::move(candidate));
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  validate_block_candidate(round_id, std::move(candidate), std::move(P));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace validator
 | 
					}  // namespace validator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ton
 | 
					}  // namespace ton
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,12 +55,14 @@ class ValidatorGroup : public td::actor::Actor {
 | 
				
			||||||
      init_ = false;
 | 
					      init_ = false;
 | 
				
			||||||
      create_session();
 | 
					      create_session();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl::AdnlNodeIdShort(local_id_));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void get_session_info(td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise);
 | 
					  void get_session_info(td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ValidatorGroup(ShardIdFull shard, PublicKeyHash local_id, ValidatorSessionId session_id,
 | 
					  ValidatorGroup(ShardIdFull shard, PublicKeyHash local_id, ValidatorSessionId session_id,
 | 
				
			||||||
                 td::Ref<ValidatorSet> validator_set, validatorsession::ValidatorSessionOptions config,
 | 
					                 td::Ref<ValidatorSet> validator_set, std::vector<CollatorNodeDescr> collator_set,
 | 
				
			||||||
 | 
					                 validatorsession::ValidatorSessionOptions config,
 | 
				
			||||||
                 td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
 | 
					                 td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
 | 
				
			||||||
                 td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
 | 
					                 td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
 | 
				
			||||||
                 std::string db_root, td::actor::ActorId<ValidatorManager> validator_manager, bool create_session,
 | 
					                 std::string db_root, td::actor::ActorId<ValidatorManager> validator_manager, bool create_session,
 | 
				
			||||||
| 
						 | 
					@ -69,6 +71,7 @@ class ValidatorGroup : public td::actor::Actor {
 | 
				
			||||||
      , local_id_(std::move(local_id))
 | 
					      , local_id_(std::move(local_id))
 | 
				
			||||||
      , session_id_(session_id)
 | 
					      , session_id_(session_id)
 | 
				
			||||||
      , validator_set_(std::move(validator_set))
 | 
					      , validator_set_(std::move(validator_set))
 | 
				
			||||||
 | 
					      , collator_set_(std::move(collator_set))
 | 
				
			||||||
      , config_(std::move(config))
 | 
					      , config_(std::move(config))
 | 
				
			||||||
      , keyring_(keyring)
 | 
					      , keyring_(keyring)
 | 
				
			||||||
      , adnl_(adnl)
 | 
					      , adnl_(adnl)
 | 
				
			||||||
| 
						 | 
					@ -83,6 +86,8 @@ class ValidatorGroup : public td::actor::Actor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  std::unique_ptr<validatorsession::ValidatorSession::Callback> make_validator_session_callback();
 | 
					  std::unique_ptr<validatorsession::ValidatorSession::Callback> make_validator_session_callback();
 | 
				
			||||||
 | 
					  void send_collate_query(td::uint32 round_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise);
 | 
				
			||||||
 | 
					  void receive_collate_query_response(td::uint32 round_id, td::BufferSlice data, td::Promise<BlockCandidate> promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct PostponedAccept {
 | 
					  struct PostponedAccept {
 | 
				
			||||||
    RootHash root_hash;
 | 
					    RootHash root_hash;
 | 
				
			||||||
| 
						 | 
					@ -105,6 +110,7 @@ class ValidatorGroup : public td::actor::Actor {
 | 
				
			||||||
  BlockIdExt min_masterchain_block_id_;
 | 
					  BlockIdExt min_masterchain_block_id_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::Ref<ValidatorSet> validator_set_;
 | 
					  td::Ref<ValidatorSet> validator_set_;
 | 
				
			||||||
 | 
					  std::vector<CollatorNodeDescr> collator_set_;
 | 
				
			||||||
  validatorsession::ValidatorSessionOptions config_;
 | 
					  validatorsession::ValidatorSessionOptions config_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::actor::ActorId<keyring::Keyring> keyring_;
 | 
					  td::actor::ActorId<keyring::Keyring> keyring_;
 | 
				
			||||||
| 
						 | 
					@ -120,6 +126,16 @@ class ValidatorGroup : public td::actor::Actor {
 | 
				
			||||||
  bool allow_unsafe_self_blocks_resync_;
 | 
					  bool allow_unsafe_self_blocks_resync_;
 | 
				
			||||||
  bool lite_mode_ = false;
 | 
					  bool lite_mode_ = false;
 | 
				
			||||||
  td::uint32 last_known_round_id_ = 0;
 | 
					  td::uint32 last_known_round_id_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  typedef std::tuple<td::Bits256, BlockIdExt, FileHash, FileHash> CacheKey;
 | 
				
			||||||
 | 
					  std::map<CacheKey, UnixTime> approved_candidates_cache_;
 | 
				
			||||||
 | 
					  td::uint32 approved_candidates_cache_round_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static CacheKey block_to_cache_key(const BlockCandidate& block) {
 | 
				
			||||||
 | 
					    return std::make_tuple(block.pubkey.as_bits256(), block.id, sha256_bits256(block.data), block.collated_file_hash);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace validator
 | 
					}  // namespace validator
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,6 +220,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
 | 
				
			||||||
  virtual void generate_block_candidate(BlockId block_id, td::Promise<BlockCandidate> promise) = 0;
 | 
					  virtual void generate_block_candidate(BlockId block_id, td::Promise<BlockCandidate> promise) = 0;
 | 
				
			||||||
  virtual void get_required_block_candidates(td::Promise<std::vector<BlockId>> promise) = 0;
 | 
					  virtual void get_required_block_candidates(td::Promise<std::vector<BlockId>> promise) = 0;
 | 
				
			||||||
  virtual void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
 | 
					  virtual void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace validator
 | 
					}  // namespace validator
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue