mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	New liteserver config format
* Specify shards and seqno/utime/lt limits for liteservers in global config * Support in lite-client, tonlib, blockchain-explorer * Rework proxy-liteserver
This commit is contained in:
		
							parent
							
								
									38ab70c037
								
							
						
					
					
						commit
						007f1fb1d7
					
				
					 26 changed files with 1187 additions and 1130 deletions
				
			
		| 
						 | 
					@ -43,7 +43,6 @@
 | 
				
			||||||
#include "block/block-auto.h"
 | 
					#include "block/block-auto.h"
 | 
				
			||||||
#include "crypto/vm/utils.h"
 | 
					#include "crypto/vm/utils.h"
 | 
				
			||||||
#include "td/utils/crypto.h"
 | 
					#include "td/utils/crypto.h"
 | 
				
			||||||
#include "lite-client/QueryTraits.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "vm/boc.h"
 | 
					#include "vm/boc.h"
 | 
				
			||||||
#include "vm/cellops.h"
 | 
					#include "vm/cellops.h"
 | 
				
			||||||
| 
						 | 
					@ -212,7 +211,8 @@ void HttpQueryBlockData::finish_query() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryBlockData::start_up() {
 | 
					void HttpQueryBlockData::start_up() {
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_));
 | 
					  auto query = ton::serialize_tl_object(
 | 
				
			||||||
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
| 
						 | 
					@ -223,7 +223,7 @@ void HttpQueryBlockData::start_up() {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryBlockData::got_block_data(td::BufferSlice data) {
 | 
					void HttpQueryBlockData::got_block_data(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -274,7 +274,8 @@ void HttpQueryBlockView::finish_query() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryBlockView::start_up_query() {
 | 
					void HttpQueryBlockView::start_up_query() {
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_));
 | 
					  auto query = ton::serialize_tl_object(
 | 
				
			||||||
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
| 
						 | 
					@ -285,7 +286,7 @@ void HttpQueryBlockView::start_up_query() {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryBlockView::got_block_data(td::BufferSlice data) {
 | 
					void HttpQueryBlockView::got_block_data(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -321,10 +322,11 @@ void HttpQueryBlockInfo::start_up_query() {
 | 
				
			||||||
      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_block_header, R.move_as_ok());
 | 
					      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_block_header, R.move_as_ok());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto query =
 | 
					  auto query = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(block_id_), 0);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(block_id_), 0),
 | 
				
			||||||
 | 
					      true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
  pending_queries_ = 1;
 | 
					  pending_queries_ = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (block_id_.is_masterchain()) {
 | 
					  if (block_id_.is_masterchain()) {
 | 
				
			||||||
| 
						 | 
					@ -336,15 +338,16 @@ void HttpQueryBlockInfo::start_up_query() {
 | 
				
			||||||
        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_shard_info, R.move_as_ok());
 | 
					        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_shard_info, R.move_as_ok());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    auto query_2 =
 | 
					    auto query_2 = ton::serialize_tl_object(
 | 
				
			||||||
        ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_));
 | 
					        ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)),
 | 
				
			||||||
 | 
					        true);
 | 
				
			||||||
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                            ton::serialize_tl_object(query_2, true), liteclient::get_query_shard(*query_2),
 | 
					                            std::move(query_2), std::move(P_2));
 | 
				
			||||||
                            std::move(P_2));
 | 
					 | 
				
			||||||
    pending_queries_++;
 | 
					    pending_queries_++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
					  auto query_3 = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
				
			||||||
      ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false);
 | 
					                                              ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false),
 | 
				
			||||||
 | 
					                                          true);
 | 
				
			||||||
  auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					  auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
 | 
					      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
 | 
				
			||||||
| 
						 | 
					@ -353,8 +356,7 @@ void HttpQueryBlockInfo::start_up_query() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3),
 | 
					                          std::move(query_3), std::move(P_3));
 | 
				
			||||||
                          std::move(P_3));
 | 
					 | 
				
			||||||
  pending_queries_++;
 | 
					  pending_queries_++;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -407,9 +409,11 @@ void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (f->incomplete_ && transactions_.size() > 0) {
 | 
					  if (f->incomplete_ && transactions_.size() > 0) {
 | 
				
			||||||
    const auto &T = *transactions_.rbegin();
 | 
					    const auto &T = *transactions_.rbegin();
 | 
				
			||||||
    auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
					    auto query_3 = ton::serialize_tl_object(
 | 
				
			||||||
 | 
					        ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
				
			||||||
            ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
 | 
					            ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
 | 
				
			||||||
        ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false);
 | 
					            ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false),
 | 
				
			||||||
 | 
					        true);
 | 
				
			||||||
    auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					    auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
      if (R.is_error()) {
 | 
					      if (R.is_error()) {
 | 
				
			||||||
        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
 | 
					        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
 | 
				
			||||||
| 
						 | 
					@ -418,8 +422,7 @@ void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                            ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3),
 | 
					                            std::move(query_3), std::move(P_3));
 | 
				
			||||||
                            std::move(P_3));
 | 
					 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    if (!--pending_queries_) {
 | 
					    if (!--pending_queries_) {
 | 
				
			||||||
      finish_query();
 | 
					      finish_query();
 | 
				
			||||||
| 
						 | 
					@ -539,13 +542,14 @@ void HttpQueryBlockSearch::start_up_query() {
 | 
				
			||||||
      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_block_header, R.move_as_ok());
 | 
					      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_block_header, R.move_as_ok());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>(
 | 
					  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>(
 | 
				
			||||||
                                            mode_,
 | 
					                                            mode_,
 | 
				
			||||||
      ton::create_tl_lite_block_id_simple(
 | 
					                                            ton::create_tl_lite_block_id_simple(ton::BlockId{
 | 
				
			||||||
          ton::BlockId{account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}),
 | 
					                                                account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}),
 | 
				
			||||||
      lt_, utime_);
 | 
					                                            lt_, utime_),
 | 
				
			||||||
 | 
					                                        true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) {
 | 
					void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -567,16 +571,17 @@ void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) {
 | 
				
			||||||
        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_shard_info, R.move_as_ok());
 | 
					        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_shard_info, R.move_as_ok());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    auto query_2 =
 | 
					    auto query_2 = ton::serialize_tl_object(
 | 
				
			||||||
        ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_));
 | 
					        ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)),
 | 
				
			||||||
 | 
					        true);
 | 
				
			||||||
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                            ton::serialize_tl_object(query_2, true), liteclient::get_query_shard(*query_2),
 | 
					                            std::move(query_2), std::move(P_2));
 | 
				
			||||||
                            std::move(P_2));
 | 
					 | 
				
			||||||
    pending_queries_++;
 | 
					    pending_queries_++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
					  auto query_3 = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
				
			||||||
      ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false);
 | 
					                                              ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false),
 | 
				
			||||||
 | 
					                                          true);
 | 
				
			||||||
  auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					  auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, R.move_as_error_prefix("litequery failed: "));
 | 
					      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, R.move_as_error_prefix("litequery failed: "));
 | 
				
			||||||
| 
						 | 
					@ -585,8 +590,7 @@ void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3),
 | 
					                          std::move(query_3), std::move(P_3));
 | 
				
			||||||
                          std::move(P_3));
 | 
					 | 
				
			||||||
  pending_queries_++;
 | 
					  pending_queries_++;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -626,9 +630,11 @@ void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (f->incomplete_ && transactions_.size() > 0) {
 | 
					  if (f->incomplete_ && transactions_.size() > 0) {
 | 
				
			||||||
    const auto &T = *transactions_.rbegin();
 | 
					    const auto &T = *transactions_.rbegin();
 | 
				
			||||||
    auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
					    auto query_3 = ton::serialize_tl_object(
 | 
				
			||||||
 | 
					        ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
				
			||||||
            ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
 | 
					            ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
 | 
				
			||||||
        ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false);
 | 
					            ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false),
 | 
				
			||||||
 | 
					        true);
 | 
				
			||||||
    auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					    auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
      if (R.is_error()) {
 | 
					      if (R.is_error()) {
 | 
				
			||||||
        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query,
 | 
					        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query,
 | 
				
			||||||
| 
						 | 
					@ -638,8 +644,7 @@ void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                            ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3),
 | 
					                            std::move(query_3), std::move(P_3));
 | 
				
			||||||
                            std::move(P_3));
 | 
					 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    if (!--pending_queries_) {
 | 
					    if (!--pending_queries_) {
 | 
				
			||||||
      finish_query();
 | 
					      finish_query();
 | 
				
			||||||
| 
						 | 
					@ -727,10 +732,11 @@ void HttpQueryViewAccount::start_up_query() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(ton::create_tl_lite_block_id(block_id_),
 | 
					  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
 | 
				
			||||||
                                                                                std::move(a));
 | 
					                                            ton::create_tl_lite_block_id(block_id_), std::move(a)),
 | 
				
			||||||
 | 
					                                        true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryViewAccount::got_account(td::BufferSlice data) {
 | 
					void HttpQueryViewAccount::got_account(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -823,9 +829,10 @@ void HttpQueryViewTransaction::start_up_query() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(1, std::move(a), lt_, hash_);
 | 
					  auto query = ton::serialize_tl_object(
 | 
				
			||||||
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(1, std::move(a), lt_, hash_), true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryViewTransaction::got_transaction(td::BufferSlice data) {
 | 
					void HttpQueryViewTransaction::got_transaction(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -913,10 +920,11 @@ void HttpQueryViewTransaction2::start_up_query() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
 | 
					  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
 | 
				
			||||||
      ton::create_tl_lite_block_id(block_id_), std::move(a), lt_);
 | 
					                                            ton::create_tl_lite_block_id(block_id_), std::move(a), lt_),
 | 
				
			||||||
 | 
					                                        true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryViewTransaction2::got_transaction(td::BufferSlice data) {
 | 
					void HttpQueryViewTransaction2::got_transaction(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -975,9 +983,9 @@ void HttpQueryViewLastBlock::start_up() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>();
 | 
					  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryViewLastBlock::got_result(td::BufferSlice data) {
 | 
					void HttpQueryViewLastBlock::got_result(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -1041,9 +1049,9 @@ void HttpQueryConfig::start_up() {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>();
 | 
					    auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
 | 
				
			||||||
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                            ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                            std::move(query), std::move(P));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1067,17 +1075,16 @@ void HttpQueryConfig::send_main_query() {
 | 
				
			||||||
      td::actor::send_closure(SelfId, &HttpQueryConfig::got_result, R.move_as_ok());
 | 
					      td::actor::send_closure(SelfId, &HttpQueryConfig::got_result, R.move_as_ok());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  if (params_.size() > 0) {
 | 
					 | 
				
			||||||
    auto query = ton::create_tl_object<ton::lite_api::liteServer_getConfigParams>(
 | 
					 | 
				
			||||||
        0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(params_));
 | 
					 | 
				
			||||||
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					 | 
				
			||||||
                            ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
  auto query =
 | 
					  auto query =
 | 
				
			||||||
        ton::create_tl_object<ton::lite_api::liteServer_getConfigAll>(0, ton::create_tl_lite_block_id(block_id_));
 | 
					      params_.size() > 0
 | 
				
			||||||
 | 
					          ? ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigParams>(
 | 
				
			||||||
 | 
					                                         0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(params_)),
 | 
				
			||||||
 | 
					                                     true)
 | 
				
			||||||
 | 
					          : ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigAll>(
 | 
				
			||||||
 | 
					                                         0, ton::create_tl_lite_block_id(block_id_)),
 | 
				
			||||||
 | 
					                                     true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                            ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryConfig::got_result(td::BufferSlice data) {
 | 
					void HttpQueryConfig::got_result(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -1219,9 +1226,10 @@ void HttpQuerySend::start_up() {
 | 
				
			||||||
      td::actor::send_closure(SelfId, &HttpQuerySend::got_result, R.move_as_ok());
 | 
					      td::actor::send_closure(SelfId, &HttpQuerySend::got_result, R.move_as_ok());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(std::move(data_));
 | 
					  auto query =
 | 
				
			||||||
 | 
					      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(std::move(data_)), true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQuerySend::got_result(td::BufferSlice data) {
 | 
					void HttpQuerySend::got_result(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					@ -1327,10 +1335,12 @@ void HttpQueryRunMethod::start_up_query() {
 | 
				
			||||||
    return abort_query(params_serialized.move_as_error_prefix("cannot serialize stack with get-method parameters : "));
 | 
					    return abort_query(params_serialized.move_as_error_prefix("cannot serialize stack with get-method parameters : "));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto query = ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>(
 | 
					  auto query = ton::serialize_tl_object(
 | 
				
			||||||
      0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok());
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>(
 | 
				
			||||||
 | 
					          0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()),
 | 
				
			||||||
 | 
					      true);
 | 
				
			||||||
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
					  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
 | 
				
			||||||
                          ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P));
 | 
					                          std::move(query), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HttpQueryRunMethod::got_result(td::BufferSlice data) {
 | 
					void HttpQueryRunMethod::got_result(td::BufferSlice data) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,8 +155,6 @@ class CoreActor : public CoreActorInterface {
 | 
				
			||||||
  td::int32 attempt_ = 0;
 | 
					  td::int32 attempt_ = 0;
 | 
				
			||||||
  td::int32 waiting_ = 0;
 | 
					  td::int32 waiting_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<bool> ready_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  //void run_queries();
 | 
					  //void run_queries();
 | 
				
			||||||
  void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
 | 
					  void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,12 +187,6 @@ class CoreActor : public CoreActorInterface {
 | 
				
			||||||
  static CoreActor* instance_;
 | 
					  static CoreActor* instance_;
 | 
				
			||||||
  td::actor::ActorId<CoreActor> self_id_;
 | 
					  td::actor::ActorId<CoreActor> self_id_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void conn_ready(td::uint32 idx) {
 | 
					 | 
				
			||||||
    ready_.at(idx) = true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  void conn_closed(td::uint32 idx) {
 | 
					 | 
				
			||||||
    ready_.at(idx) = false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  void set_global_config(std::string str) {
 | 
					  void set_global_config(std::string str) {
 | 
				
			||||||
    global_config_ = str;
 | 
					    global_config_ = str;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -219,7 +211,7 @@ class CoreActor : public CoreActorInterface {
 | 
				
			||||||
    hide_ips_ = value;
 | 
					    hide_ips_ = value;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) override;
 | 
					  void send_lite_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) override;
 | 
				
			||||||
  void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) override {
 | 
					  void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) override {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) override {
 | 
					  void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) override {
 | 
				
			||||||
| 
						 | 
					@ -439,50 +431,24 @@ class CoreActor : public CoreActorInterface {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void run() {
 | 
					  void run() {
 | 
				
			||||||
    std::vector<liteclient::ExtClient::LiteServer> servers;
 | 
					    std::vector<liteclient::LiteServerConfig> servers;
 | 
				
			||||||
    if (remote_public_key_.empty()) {
 | 
					    if (remote_public_key_.empty()) {
 | 
				
			||||||
      auto G = td::read_file(global_config_).move_as_ok();
 | 
					      auto G = td::read_file(global_config_).move_as_ok();
 | 
				
			||||||
      auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
 | 
					      auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
 | 
				
			||||||
      ton::ton_api::liteclient_config_global gc;
 | 
					      ton::ton_api::liteclient_config_global gc;
 | 
				
			||||||
      ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
 | 
					      ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
 | 
				
			||||||
 | 
					      auto r_servers = liteclient::LiteServerConfig::parse_global_config(gc);
 | 
				
			||||||
      size_t size = gc.liteservers_.size() + gc.liteservers_v2_.size();
 | 
					      r_servers.ensure();
 | 
				
			||||||
      CHECK(size > 0);
 | 
					      servers = r_servers.move_as_ok();
 | 
				
			||||||
      ready_.resize(size, false);
 | 
					      for (const auto& serv : servers) {
 | 
				
			||||||
 | 
					        addrs_.push_back(serv.addr);
 | 
				
			||||||
      for (auto& s : gc.liteservers_) {
 | 
					 | 
				
			||||||
        td::IPAddress addr;
 | 
					 | 
				
			||||||
        addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure();
 | 
					 | 
				
			||||||
        addrs_.push_back(addr);
 | 
					 | 
				
			||||||
        liteclient::ExtClient::LiteServer serv;
 | 
					 | 
				
			||||||
        serv.address = addr;
 | 
					 | 
				
			||||||
        serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok();
 | 
					 | 
				
			||||||
        servers.push_back(std::move(serv));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      for (auto& s : gc.liteservers_v2_) {
 | 
					 | 
				
			||||||
        td::IPAddress addr;
 | 
					 | 
				
			||||||
        addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure();
 | 
					 | 
				
			||||||
        addrs_.push_back(addr);
 | 
					 | 
				
			||||||
        liteclient::ExtClient::LiteServer serv;
 | 
					 | 
				
			||||||
        serv.address = addr;
 | 
					 | 
				
			||||||
        serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok();
 | 
					 | 
				
			||||||
        serv.is_full = false;
 | 
					 | 
				
			||||||
        for (auto& shard : s->shards_) {
 | 
					 | 
				
			||||||
          serv.shards.emplace_back(shard->workchain_, (ton::ShardId)shard->shard_);
 | 
					 | 
				
			||||||
          CHECK(serv.shards.back().is_valid_ext());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        servers.push_back(std::move(serv));
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      if (!remote_addr_.is_valid()) {
 | 
					      if (!remote_addr_.is_valid()) {
 | 
				
			||||||
        LOG(FATAL) << "remote addr not set";
 | 
					        LOG(FATAL) << "remote addr not set";
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      ready_.resize(1, false);
 | 
					 | 
				
			||||||
      addrs_.push_back(remote_addr_);
 | 
					      addrs_.push_back(remote_addr_);
 | 
				
			||||||
      liteclient::ExtClient::LiteServer serv;
 | 
					      servers.push_back(liteclient::LiteServerConfig{ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_});
 | 
				
			||||||
      serv.address = remote_addr_;
 | 
					 | 
				
			||||||
      serv.adnl_id = ton::adnl::AdnlNodeIdFull{remote_public_key_};
 | 
					 | 
				
			||||||
      servers.push_back(std::move(serv));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    client_ = liteclient::ExtClient::create(std::move(servers), make_callback());
 | 
					    client_ = liteclient::ExtClient::create(std::move(servers), make_callback());
 | 
				
			||||||
    daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast<td::uint16>(http_port_), nullptr, nullptr,
 | 
					    daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast<td::uint16>(http_port_), nullptr, nullptr,
 | 
				
			||||||
| 
						 | 
					@ -545,7 +511,7 @@ void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result<td::Buf
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}*/
 | 
					}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoreActor::send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) {
 | 
					void CoreActor::send_lite_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
  auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					  auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      promise.set_error(R.move_as_error());
 | 
					      promise.set_error(R.move_as_error());
 | 
				
			||||||
| 
						 | 
					@ -563,7 +529,7 @@ void CoreActor::send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, t
 | 
				
			||||||
    promise.set_value(std::move(B));
 | 
					    promise.set_value(std::move(B));
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query));
 | 
					  auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query));
 | 
				
			||||||
  td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", serialize_tl_object(q, true), shard,
 | 
					  td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", serialize_tl_object(q, true),
 | 
				
			||||||
                          td::Timestamp::in(10.0), std::move(P));
 | 
					                          td::Timestamp::in(10.0), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,7 @@ class CoreActorInterface : public td::actor::Actor {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  virtual ~CoreActorInterface() = default;
 | 
					  virtual ~CoreActorInterface() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual void send_lite_query(td::BufferSlice data, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) = 0;
 | 
					  virtual void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
 | 
				
			||||||
  virtual void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) = 0;
 | 
					  virtual void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) = 0;
 | 
				
			||||||
  virtual void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) = 0;
 | 
					  virtual void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,9 @@
 | 
				
			||||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
 | 
					cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h ext-client.cpp ext-client.h QueryTraits.h)
 | 
					add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h ext-client.cpp ext-client.h
 | 
				
			||||||
target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block)
 | 
					  query-utils.hpp query-utils.cpp)
 | 
				
			||||||
 | 
					target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto
 | 
				
			||||||
 | 
					  ton_block)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_executable(lite-client lite-client.cpp lite-client.h ext-client.h ext-client.cpp)
 | 
					add_executable(lite-client lite-client.cpp lite-client.h ext-client.h ext-client.cpp)
 | 
				
			||||||
target_link_libraries(lite-client tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block
 | 
					target_link_libraries(lite-client tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,229 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
    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 "ton/ton-types.h"
 | 
					 | 
				
			||||||
#include "auto/tl/lite_api.h"
 | 
					 | 
				
			||||||
#include "auto/tl/lite_api.hpp"
 | 
					 | 
				
			||||||
#include "vm/boc.h"
 | 
					 | 
				
			||||||
#include "vm/cellslice.h"
 | 
					 | 
				
			||||||
#include "block/block-auto.h"
 | 
					 | 
				
			||||||
#include "block/block-parse.h"
 | 
					 | 
				
			||||||
#include "auto/tl/lite_api.hpp"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace liteclient {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Query>
 | 
					 | 
				
			||||||
struct QueryTraits {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const Query& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getMasterchainInfo> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfo& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getMasterchainInfoExt> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfoExt& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getTime> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTime& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getVersion> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getVersion& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getBlock> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlock& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getState> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getState& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getBlockHeader> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockHeader& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_sendMessage> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_sendMessage& q) {
 | 
					 | 
				
			||||||
    auto shard = [&]() -> td::Result<ton::ShardIdFull> {
 | 
					 | 
				
			||||||
      vm::BagOfCells boc;
 | 
					 | 
				
			||||||
      TRY_STATUS(boc.deserialize(q.body_.as_slice()));
 | 
					 | 
				
			||||||
      if (boc.get_root_count() != 1) {
 | 
					 | 
				
			||||||
        return td::Status::Error("external message is not a valid bag of cells");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
 | 
					 | 
				
			||||||
      if (!tlb::unpack_cell_inexact(boc.get_root_cell(), info)) {
 | 
					 | 
				
			||||||
        return td::Status::Error("cannot unpack external message header");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      auto dest_prefix = block::tlb::t_MsgAddressInt.get_prefix(info.dest);
 | 
					 | 
				
			||||||
      if (!dest_prefix.is_valid()) {
 | 
					 | 
				
			||||||
        return td::Status::Error("destination of an inbound external message is an invalid blockchain address");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return dest_prefix.as_leaf_shard();
 | 
					 | 
				
			||||||
    }();
 | 
					 | 
				
			||||||
    if (shard.is_error()) {
 | 
					 | 
				
			||||||
      LOG(DEBUG) << "Failed to get shard from query liteServer.sendMessage: " << shard.move_as_error();
 | 
					 | 
				
			||||||
      return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return shard.move_as_ok();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getAccountState> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAccountState& q) {
 | 
					 | 
				
			||||||
    return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getAccountStatePrunned> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAccountStatePrunned& q) {
 | 
					 | 
				
			||||||
    return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_runSmcMethod> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_runSmcMethod& q) {
 | 
					 | 
				
			||||||
    return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getShardInfo> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardInfo& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getAllShardsInfo> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAllShardsInfo& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getOneTransaction> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getOneTransaction& q) {
 | 
					 | 
				
			||||||
    return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getTransactions> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTransactions& q) {
 | 
					 | 
				
			||||||
    return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_lookupBlock> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_lookupBlock& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_listBlockTransactions> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactions& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_listBlockTransactionsExt> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactionsExt& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getBlockProof> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockProof& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getConfigAll> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigAll& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getConfigParams> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigParams& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getValidatorStats> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getValidatorStats& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getLibraries> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getLibraries& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct QueryTraits<ton::lite_api::liteServer_getShardBlockProof> {
 | 
					 | 
				
			||||||
  static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardBlockProof& q) {
 | 
					 | 
				
			||||||
    return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<typename Query>
 | 
					 | 
				
			||||||
inline ton::ShardIdFull get_query_shard(const Query& q) {
 | 
					 | 
				
			||||||
  return QueryTraits<Query>::get_shard(q);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace tonlib
 | 
					 | 
				
			||||||
| 
						 | 
					@ -17,35 +17,31 @@
 | 
				
			||||||
#include "ext-client.h"
 | 
					#include "ext-client.h"
 | 
				
			||||||
#include "td/utils/Random.h"
 | 
					#include "td/utils/Random.h"
 | 
				
			||||||
#include "ton/ton-shard.h"
 | 
					#include "ton/ton-shard.h"
 | 
				
			||||||
#include <map>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace liteclient {
 | 
					namespace liteclient {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ExtClientImpl : public ExtClient {
 | 
					class ExtClientImpl : public ExtClient {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  ExtClientImpl(std::vector<LiteServer> servers, td::unique_ptr<ExtClient::Callback> callback)
 | 
					  ExtClientImpl(std::vector<LiteServerConfig> liteservers, td::unique_ptr<Callback> callback)
 | 
				
			||||||
      : callback_(std::move(callback)) {
 | 
					      : callback_(std::move(callback)) {
 | 
				
			||||||
    CHECK(!servers.empty());
 | 
					    CHECK(!liteservers.empty());
 | 
				
			||||||
    servers_.resize(servers.size());
 | 
					    servers_.resize(liteservers.size());
 | 
				
			||||||
    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
					    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
				
			||||||
      servers_[i].s = std::move(servers[i]);
 | 
					      servers_[i].config = std::move(liteservers[i]);
 | 
				
			||||||
      if (!servers_[i].s.is_full) {
 | 
					      servers_[i].idx = i;
 | 
				
			||||||
        for (auto shard : servers_[i].s.shards) {
 | 
					 | 
				
			||||||
          CHECK(shard.is_valid_ext());
 | 
					 | 
				
			||||||
          max_server_shard_depth_ = std::max(max_server_shard_depth_, shard.pfx_len());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void start_up() override {
 | 
					  void start_up() override {
 | 
				
			||||||
 | 
					    LOG(INFO) << "Started ext client, " << servers_.size() << " liteservers";
 | 
				
			||||||
    td::Random::Fast rnd;
 | 
					    td::Random::Fast rnd;
 | 
				
			||||||
    td::random_shuffle(td::as_mutable_span(servers_), rnd);
 | 
					    td::random_shuffle(td::as_mutable_span(servers_), rnd);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
					  void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
 | 
				
			||||||
                  td::Promise<td::BufferSlice> promise) override {
 | 
					                  td::Promise<td::BufferSlice> promise) override {
 | 
				
			||||||
    TRY_RESULT_PROMISE(promise, server_idx, before_query(shard));
 | 
					    QueryInfo query_info = get_query_info(data);
 | 
				
			||||||
 | 
					    TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info));
 | 
				
			||||||
    auto& server = servers_[server_idx];
 | 
					    auto& server = servers_[server_idx];
 | 
				
			||||||
    CHECK(!server.client.empty());
 | 
					    CHECK(!server.client.empty());
 | 
				
			||||||
    alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
 | 
					    alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
 | 
				
			||||||
| 
						 | 
					@ -53,56 +49,43 @@ class ExtClientImpl : public ExtClient {
 | 
				
			||||||
                                      promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					                                      promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
      if (R.is_error() &&
 | 
					      if (R.is_error() &&
 | 
				
			||||||
          (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
 | 
					          (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
 | 
				
			||||||
        td::actor::send_closure(SelfId, &ExtClientImpl::set_server_bad, server_idx);
 | 
					        td::actor::send_closure(SelfId, &ExtClientImpl::on_server_error, server_idx);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      promise.set_result(std::move(R));
 | 
					      promise.set_result(std::move(R));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    LOG(DEBUG) << "Sending query " << query_info.to_str() << " to server #" << server.idx << " ("
 | 
				
			||||||
 | 
					               << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")";
 | 
				
			||||||
    send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
 | 
					    send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
 | 
				
			||||||
                 std::move(P));
 | 
					                 std::move(P));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void force_change_liteserver() override {
 | 
					  void reset_servers() override {
 | 
				
			||||||
    if (servers_.size() == 1) {
 | 
					    LOG(INFO) << "Force resetting all liteservers";
 | 
				
			||||||
      return;
 | 
					    for (Server& server : servers_) {
 | 
				
			||||||
    }
 | 
					      server.alive = false;
 | 
				
			||||||
    auto it = shard_to_server_.find(ton::ShardIdFull(ton::masterchainId));
 | 
					      server.timeout = {};
 | 
				
			||||||
    if (it != shard_to_server_.end()) {
 | 
					      server.ignore_until = {};
 | 
				
			||||||
      set_server_bad(it->second);
 | 
					      server.client.reset();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  td::Result<size_t> before_query(ton::ShardIdFull shard) {
 | 
					  td::Result<size_t> select_server(const QueryInfo& query_info) {
 | 
				
			||||||
    if (!shard.is_valid_ext()) {
 | 
					    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
				
			||||||
      return td::Status::Error("Invalid shard");
 | 
					      if (servers_[i].alive && servers_[i].config.accepts_query(query_info)) {
 | 
				
			||||||
 | 
					        return i;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    if (is_closing_) {
 | 
					 | 
				
			||||||
      return td::Status::Error("Client is closing");
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (shard.pfx_len() > max_server_shard_depth_) {
 | 
					 | 
				
			||||||
      shard = shard_prefix(shard, max_server_shard_depth_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    auto it = shard_to_server_.find(shard);
 | 
					 | 
				
			||||||
    if (it != shard_to_server_.end()) {
 | 
					 | 
				
			||||||
      size_t server_idx = it->second;
 | 
					 | 
				
			||||||
      if (!servers_[server_idx].client.empty()) {
 | 
					 | 
				
			||||||
        return server_idx;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      shard_to_server_.erase(it);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    size_t server_idx = servers_.size();
 | 
					    size_t server_idx = servers_.size();
 | 
				
			||||||
    int cnt = 0;
 | 
					    int cnt = 0;
 | 
				
			||||||
    int best_priority = -1;
 | 
					    int best_priority = -1;
 | 
				
			||||||
    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
					    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
				
			||||||
      Server& server = servers_[i];
 | 
					      Server& server = servers_[i];
 | 
				
			||||||
      if (!server.supports(shard)) {
 | 
					      if (!server.config.accepts_query(query_info)) {
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      int priority = 0;
 | 
					      int priority = 0;
 | 
				
			||||||
      priority += (server.client.empty() ? 0 : 100);
 | 
					 | 
				
			||||||
      priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10);
 | 
					      priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10);
 | 
				
			||||||
      priority += (server.s.is_full ? 1 : 0);
 | 
					 | 
				
			||||||
      if (priority < best_priority) {
 | 
					      if (priority < best_priority) {
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -116,100 +99,76 @@ class ExtClientImpl : public ExtClient {
 | 
				
			||||||
      ++cnt;
 | 
					      ++cnt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (server_idx == servers_.size()) {
 | 
					    if (server_idx == servers_.size()) {
 | 
				
			||||||
      return td::Status::Error(PSTRING() << "No liteserver for shard " << shard.to_str());
 | 
					      return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Server& server = servers_[server_idx];
 | 
					    Server& server = servers_[server_idx];
 | 
				
			||||||
 | 
					    server.alive = true;
 | 
				
			||||||
 | 
					    server.ignore_until = {};
 | 
				
			||||||
 | 
					    alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
 | 
				
			||||||
    if (!server.client.empty()) {
 | 
					    if (!server.client.empty()) {
 | 
				
			||||||
      return server_idx;
 | 
					      return server_idx;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
					    class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
				
			||||||
     public:
 | 
					     public:
 | 
				
			||||||
      explicit Callback(td::actor::ActorShared<ExtClientImpl> parent, size_t idx)
 | 
					      explicit Callback(td::actor::ActorId<ExtClientImpl> parent, size_t idx) : parent_(std::move(parent)), idx_(idx) {
 | 
				
			||||||
          : parent_(std::move(parent)), idx_(idx) {
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      void on_ready() override {
 | 
					      void on_ready() override {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      void on_stop_ready() override {
 | 
					      void on_stop_ready() override {
 | 
				
			||||||
        td::actor::send_closure(parent_, &ExtClientImpl::set_server_bad, idx_);
 | 
					        td::actor::send_closure(parent_, &ExtClientImpl::on_server_error, idx_);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     private:
 | 
					     private:
 | 
				
			||||||
      td::actor::ActorShared<ExtClientImpl> parent_;
 | 
					      td::actor::ActorId<ExtClientImpl> parent_;
 | 
				
			||||||
      size_t idx_;
 | 
					      size_t idx_;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    ref_cnt_++;
 | 
					    LOG(INFO) << "Connecting to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str() << ":"
 | 
				
			||||||
    if (shard.is_masterchain()) {
 | 
					              << server.config.addr.get_port() << ") for query " << query_info.to_str();
 | 
				
			||||||
      LOG(INFO) << "Connecting to liteserver " << server.s.address << " for masterchain";
 | 
					    server.client = ton::adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr,
 | 
				
			||||||
    } else {
 | 
					                                                     std::make_unique<Callback>(actor_id(this), server_idx));
 | 
				
			||||||
      LOG(INFO) << "Connecting to liteserver " << server.s.address << " for shard " << shard.to_str();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    server.client = ton::adnl::AdnlExtClient::create(
 | 
					 | 
				
			||||||
        server.s.adnl_id, server.s.address, std::make_unique<Callback>(td::actor::actor_shared(this), server_idx));
 | 
					 | 
				
			||||||
    alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
 | 
					 | 
				
			||||||
    return server_idx;
 | 
					    return server_idx;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct Server {
 | 
					  struct Server {
 | 
				
			||||||
    LiteServer s;
 | 
					    LiteServerConfig config;
 | 
				
			||||||
 | 
					    size_t idx = 0;
 | 
				
			||||||
    td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
 | 
					    td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
 | 
				
			||||||
 | 
					    bool alive = false;
 | 
				
			||||||
    td::Timestamp timeout = td::Timestamp::never();
 | 
					    td::Timestamp timeout = td::Timestamp::never();
 | 
				
			||||||
    td::Timestamp ignore_until = td::Timestamp::never();
 | 
					    td::Timestamp ignore_until = td::Timestamp::never();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool supports(const ton::ShardIdFull& shard) const {
 | 
					 | 
				
			||||||
      return s.is_full || shard.is_masterchain() ||
 | 
					 | 
				
			||||||
             std::any_of(s.shards.begin(), s.shards.end(),
 | 
					 | 
				
			||||||
                         [&](const ton::ShardIdFull s_shard) { return ton::shard_intersects(shard, s_shard); });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  std::vector<Server> servers_;
 | 
					  std::vector<Server> servers_;
 | 
				
			||||||
  std::map<ton::ShardIdFull, size_t> shard_to_server_;
 | 
					 | 
				
			||||||
  int max_server_shard_depth_ = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::unique_ptr<ExtClient::Callback> callback_;
 | 
					  td::unique_ptr<Callback> callback_;
 | 
				
			||||||
  static constexpr double MAX_NO_QUERIES_TIMEOUT = 100;
 | 
					  static constexpr double MAX_NO_QUERIES_TIMEOUT = 100.0;
 | 
				
			||||||
 | 
					  static constexpr double BAD_SERVER_TIMEOUT = 30.0;
 | 
				
			||||||
  bool is_closing_{false};
 | 
					 | 
				
			||||||
  td::uint32 ref_cnt_{1};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void alarm() override {
 | 
					  void alarm() override {
 | 
				
			||||||
    for (Server& server : servers_) {
 | 
					    for (Server& server : servers_) {
 | 
				
			||||||
      if (server.timeout && server.timeout.is_in_past()) {
 | 
					      if (server.timeout && server.timeout.is_in_past()) {
 | 
				
			||||||
 | 
					        LOG(INFO) << "Closing connection to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str()
 | 
				
			||||||
 | 
					                  << ":" << server.config.addr.get_port() << ")";
 | 
				
			||||||
        server.client.reset();
 | 
					        server.client.reset();
 | 
				
			||||||
 | 
					        server.alive = false;
 | 
				
			||||||
 | 
					        server.ignore_until = {};
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void set_server_bad(size_t idx) {
 | 
					
 | 
				
			||||||
    servers_[idx].client.reset();
 | 
					  void on_server_error(size_t idx) {
 | 
				
			||||||
    servers_[idx].timeout = td::Timestamp::never();
 | 
					    servers_[idx].alive = false;
 | 
				
			||||||
    servers_[idx].ignore_until = td::Timestamp::in(60.0);
 | 
					    servers_[idx].ignore_until = td::Timestamp::in(BAD_SERVER_TIMEOUT);
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  void hangup_shared() override {
 | 
					 | 
				
			||||||
    ref_cnt_--;
 | 
					 | 
				
			||||||
    try_stop();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  void hangup() override {
 | 
					 | 
				
			||||||
    is_closing_ = true;
 | 
					 | 
				
			||||||
    ref_cnt_--;
 | 
					 | 
				
			||||||
    for (Server& server : servers_) {
 | 
					 | 
				
			||||||
      server.client.reset();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    try_stop();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  void try_stop() {
 | 
					 | 
				
			||||||
    if (is_closing_ && ref_cnt_ == 0) {
 | 
					 | 
				
			||||||
      stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::actor::ActorOwn<ExtClient> ExtClient::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
 | 
					td::actor::ActorOwn<ExtClient> ExtClient::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
 | 
				
			||||||
                                                 td::unique_ptr<Callback> callback) {
 | 
					                                                 td::unique_ptr<Callback> callback) {
 | 
				
			||||||
  return create({LiteServer{dst, dst_addr, true, {}}}, std::move(callback));
 | 
					  return create({LiteServerConfig{dst, dst_addr}}, std::move(callback));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServer> servers,
 | 
					td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServerConfig> liteservers,
 | 
				
			||||||
                                                 td::unique_ptr<Callback> callback) {
 | 
					                                                 td::unique_ptr<Callback> callback) {
 | 
				
			||||||
  return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(servers), std::move(callback));
 | 
					  return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(liteservers), std::move(callback));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}  // namespace liteclient
 | 
					}  // namespace liteclient
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,29 +18,24 @@
 | 
				
			||||||
#include "td/actor/actor.h"
 | 
					#include "td/actor/actor.h"
 | 
				
			||||||
#include "ton/ton-types.h"
 | 
					#include "ton/ton-types.h"
 | 
				
			||||||
#include "adnl/adnl-ext-client.h"
 | 
					#include "adnl/adnl-ext-client.h"
 | 
				
			||||||
 | 
					#include "query-utils.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace liteclient {
 | 
					namespace liteclient {
 | 
				
			||||||
class ExtClient : public td::actor::Actor {
 | 
					class ExtClient : public td::actor::Actor {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  struct LiteServer {
 | 
					 | 
				
			||||||
    ton::adnl::AdnlNodeIdFull adnl_id;
 | 
					 | 
				
			||||||
    td::IPAddress address;
 | 
					 | 
				
			||||||
    bool is_full = true;
 | 
					 | 
				
			||||||
    std::vector<ton::ShardIdFull> shards;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  class Callback {
 | 
					  class Callback {
 | 
				
			||||||
   public:
 | 
					   public:
 | 
				
			||||||
    virtual ~Callback() {
 | 
					    virtual ~Callback() = default;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
					  virtual void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
 | 
				
			||||||
                          td::Promise<td::BufferSlice> promise) = 0;
 | 
					                          td::Promise<td::BufferSlice> promise) = 0;
 | 
				
			||||||
  virtual void force_change_liteserver() = 0;
 | 
					  virtual void reset_servers() {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static td::actor::ActorOwn<ExtClient> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
 | 
					  static td::actor::ActorOwn<ExtClient> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
 | 
				
			||||||
                                               td::unique_ptr<Callback> callback);
 | 
					                                               td::unique_ptr<Callback> callback);
 | 
				
			||||||
  static td::actor::ActorOwn<ExtClient> create(std::vector<LiteServer> servers, td::unique_ptr<Callback> callback);
 | 
					  static td::actor::ActorOwn<ExtClient> create(std::vector<LiteServerConfig> liteservers,
 | 
				
			||||||
 | 
					                                               td::unique_ptr<Callback> callback);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}  // namespace liteclient
 | 
					}  // namespace liteclient
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,12 +67,6 @@ using td::Ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int verbosity;
 | 
					int verbosity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::LiteServer::supports(ton::ShardIdFull shard) const {
 | 
					 | 
				
			||||||
  return is_full || shard.is_masterchain() ||
 | 
					 | 
				
			||||||
         std::any_of(shards.begin(), shards.end(),
 | 
					 | 
				
			||||||
                     [&](const ton::ShardIdFull& our_shard) { return ton::shard_intersects(shard, our_shard); });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void TestNode::run() {
 | 
					void TestNode::run() {
 | 
				
			||||||
  class Cb : public td::TerminalIO::Callback {
 | 
					  class Cb : public td::TerminalIO::Callback {
 | 
				
			||||||
   public:
 | 
					   public:
 | 
				
			||||||
| 
						 | 
					@ -88,22 +82,19 @@ void TestNode::run() {
 | 
				
			||||||
  io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique<Cb>(actor_id(this)));
 | 
					  io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique<Cb>(actor_id(this)));
 | 
				
			||||||
  td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
 | 
					  td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<liteclient::LiteServerConfig> servers;
 | 
				
			||||||
  if (!single_remote_public_key_.empty()) {  // Use single provided liteserver
 | 
					  if (!single_remote_public_key_.empty()) {  // Use single provided liteserver
 | 
				
			||||||
    LiteServer s;
 | 
					    servers.push_back(
 | 
				
			||||||
    s.addr = single_remote_addr_;
 | 
					        liteclient::LiteServerConfig{ton::adnl::AdnlNodeIdFull{single_remote_public_key_}, single_remote_addr_});
 | 
				
			||||||
    s.public_key = single_remote_public_key_;
 | 
					    td::TerminalIO::out() << "using liteserver " << single_remote_addr_ << "\n";
 | 
				
			||||||
    single_liteserver_idx_ = 0;
 | 
					  } else {
 | 
				
			||||||
    td::TerminalIO::out() << "using liteserver " << s.addr << "\n";
 | 
					 | 
				
			||||||
    servers_.push_back(std::move(s));
 | 
					 | 
				
			||||||
    run_init_queries();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto G = td::read_file(global_config_).move_as_ok();
 | 
					    auto G = td::read_file(global_config_).move_as_ok();
 | 
				
			||||||
    auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
 | 
					    auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
 | 
				
			||||||
    ton::ton_api::liteclient_config_global gc;
 | 
					    ton::ton_api::liteclient_config_global gc;
 | 
				
			||||||
    ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
 | 
					    ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
 | 
				
			||||||
  CHECK(gc.liteservers_.size() + gc.liteservers_v2_.size() > 0);
 | 
					    auto r_servers = liteclient::LiteServerConfig::parse_global_config(gc);
 | 
				
			||||||
 | 
					    r_servers.ensure();
 | 
				
			||||||
 | 
					    servers = r_servers.move_as_ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (gc.validator_ && gc.validator_->zero_state_) {
 | 
					    if (gc.validator_ && gc.validator_->zero_state_) {
 | 
				
			||||||
      zstate_id_.workchain = gc.validator_->zero_state_->workchain_;
 | 
					      zstate_id_.workchain = gc.validator_->zero_state_->workchain_;
 | 
				
			||||||
| 
						 | 
					@ -114,29 +105,16 @@ void TestNode::run() {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (auto& server : gc.liteservers_) {
 | 
					 | 
				
			||||||
    LiteServer s;
 | 
					 | 
				
			||||||
    s.addr.init_host_port(td::IPAddress::ipv4_to_str(server->ip_), server->port_).ensure();
 | 
					 | 
				
			||||||
    s.public_key = ton::PublicKey{server->id_};
 | 
					 | 
				
			||||||
    servers_.push_back(std::move(s));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  for (auto& server : gc.liteservers_v2_) {
 | 
					 | 
				
			||||||
    LiteServer s;
 | 
					 | 
				
			||||||
    s.addr.init_host_port(td::IPAddress::ipv4_to_str(server->ip_), server->port_).ensure();
 | 
					 | 
				
			||||||
    s.public_key = ton::PublicKey{server->id_};
 | 
					 | 
				
			||||||
    s.is_full = false;
 | 
					 | 
				
			||||||
    for (const auto& shard : server->shards_) {
 | 
					 | 
				
			||||||
      s.shards.emplace_back(shard->workchain_, shard->shard_);
 | 
					 | 
				
			||||||
      CHECK(s.shards.back().is_valid_ext());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    servers_.push_back(std::move(s));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (single_liteserver_idx_ != -1) {  // Use single liteserver from config
 | 
					    if (single_liteserver_idx_ != -1) {  // Use single liteserver from config
 | 
				
			||||||
    CHECK(single_liteserver_idx_ >= 0 && (size_t)single_liteserver_idx_ < gc.liteservers_.size());
 | 
					      CHECK(single_liteserver_idx_ >= 0 && (size_t)single_liteserver_idx_ < servers.size());
 | 
				
			||||||
    td::TerminalIO::out() << "using liteserver " << single_liteserver_idx_ << " with addr "
 | 
					      td::TerminalIO::out() << "using liteserver #" << single_liteserver_idx_ << " with addr "
 | 
				
			||||||
                          << servers_[single_liteserver_idx_].addr << "\n";
 | 
					                            << servers[single_liteserver_idx_].addr << "\n";
 | 
				
			||||||
 | 
					      servers = {servers[single_liteserver_idx_]};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  CHECK(!servers.empty());
 | 
				
			||||||
 | 
					  client_ = liteclient::ExtClient::create(std::move(servers), nullptr);
 | 
				
			||||||
 | 
					  ready_ = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run_init_queries();
 | 
					  run_init_queries();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -183,142 +161,23 @@ void TestNode::after_got_result(bool ok) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::envelope_send_query_to_any(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
					bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
  return envelope_send_query_to_shard(ton::ShardIdFull(ton::masterchainId), std::move(query), std::move(promise));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool TestNode::envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query,
 | 
					 | 
				
			||||||
                                              td::Promise<td::BufferSlice> promise) {
 | 
					 | 
				
			||||||
  return envelope_send_query_to_shard(prefix.as_leaf_shard(), std::move(query), std::move(promise));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool TestNode::envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query,
 | 
					 | 
				
			||||||
                                            td::Promise<td::BufferSlice> promise) {
 | 
					 | 
				
			||||||
  if (single_liteserver_idx_ >= 0) {
 | 
					 | 
				
			||||||
    return envelope_send_query_to_server(single_liteserver_idx_, std::move(query), std::move(promise));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (shard.is_masterchain() && mc_server_idx_ != -1) {
 | 
					 | 
				
			||||||
    return envelope_send_query_to_server(mc_server_idx_, std::move(query), std::move(promise));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  auto it = shard_server_idx_cached_.find(shard);
 | 
					 | 
				
			||||||
  if (it != shard_server_idx_cached_.end()) {
 | 
					 | 
				
			||||||
    return envelope_send_query_to_server(it->second, std::move(query), std::move(promise));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  int server_idx = -1;
 | 
					 | 
				
			||||||
  int random_idx = -1;
 | 
					 | 
				
			||||||
  int cnt = 0;
 | 
					 | 
				
			||||||
  bool selected_full = false;
 | 
					 | 
				
			||||||
  for (int i = 0; i < (int)servers_.size(); ++i) {
 | 
					 | 
				
			||||||
    const LiteServer& server = servers_[i];
 | 
					 | 
				
			||||||
    if (!server.supports(shard)) {
 | 
					 | 
				
			||||||
      continue;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (server.is_full && !selected_full) {
 | 
					 | 
				
			||||||
      selected_full = true;
 | 
					 | 
				
			||||||
      server_idx = -1;
 | 
					 | 
				
			||||||
      cnt = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!server.is_full && selected_full) {
 | 
					 | 
				
			||||||
      continue;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!server.client.empty()) {
 | 
					 | 
				
			||||||
      server_idx = i;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (td::Random::fast(0, cnt) == 0) {
 | 
					 | 
				
			||||||
      random_idx = i;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ++cnt;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (server_idx == -1) {
 | 
					 | 
				
			||||||
    server_idx = random_idx;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (server_idx == -1) {
 | 
					 | 
				
			||||||
  running_queries_++;
 | 
					  running_queries_++;
 | 
				
			||||||
    got_result(td::Status::Error(PSTRING() << "failed to select a suitable server for " << shard.to_str()),
 | 
					  if (!ready_ || client_.empty()) {
 | 
				
			||||||
               std::move(promise));
 | 
					    got_result(td::Status::Error("failed to send query to server: not ready"), std::move(promise));
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  shard_server_idx_cached_[shard] = server_idx;
 | 
					 | 
				
			||||||
  if (shard.is_masterchain()) {
 | 
					 | 
				
			||||||
    mc_server_idx_ = server_idx;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return envelope_send_query_to_server(server_idx, std::move(query), std::move(promise));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool TestNode::envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query,
 | 
					 | 
				
			||||||
                                             td::Promise<td::BufferSlice> promise) {
 | 
					 | 
				
			||||||
  running_queries_++;
 | 
					 | 
				
			||||||
  LiteServer& server = servers_.at(server_idx);
 | 
					 | 
				
			||||||
  if (server.client.empty()) {
 | 
					 | 
				
			||||||
    start_client(server_idx);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  CHECK(!server.client.empty());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  auto P = td::PromiseCreator::lambda(
 | 
					  auto P = td::PromiseCreator::lambda(
 | 
				
			||||||
      [SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					      [SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
        td::actor::send_closure(SelfId, &TestNode::got_result, std::move(R), std::move(promise));
 | 
					        td::actor::send_closure(SelfId, &TestNode::got_result, std::move(R), std::move(promise));
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
  td::BufferSlice b =
 | 
					  td::BufferSlice b =
 | 
				
			||||||
      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query)), true);
 | 
					      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query)), true);
 | 
				
			||||||
  if (server.client_ready) {
 | 
					  td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", std::move(b), td::Timestamp::in(10.0),
 | 
				
			||||||
    td::actor::send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
 | 
					                          std::move(P));
 | 
				
			||||||
                            td::Timestamp::in(10.0), std::move(P));
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    server.wait_client_ready.push_back(
 | 
					 | 
				
			||||||
        [client = server.client.get(), b = std::move(b), P = std::move(P)](td::Result<td::Unit> R) mutable {
 | 
					 | 
				
			||||||
          if (R.is_ok()) {
 | 
					 | 
				
			||||||
            td::actor::send_closure(client, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
 | 
					 | 
				
			||||||
                                    td::Timestamp::in(10.0), std::move(P));
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            P.set_error(R.move_as_error_prefix("failed to connect: "));
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TestNode::start_client(int server_idx) {
 | 
					 | 
				
			||||||
  LiteServer& server = servers_[server_idx];
 | 
					 | 
				
			||||||
  CHECK(server.client.empty());
 | 
					 | 
				
			||||||
  class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
					 | 
				
			||||||
   public:
 | 
					 | 
				
			||||||
    void on_ready() override {
 | 
					 | 
				
			||||||
      td::actor::send_closure(id_, &TestNode::conn_ready, server_idx_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    void on_stop_ready() override {
 | 
					 | 
				
			||||||
      td::actor::send_closure(id_, &TestNode::conn_closed, server_idx_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    Callback(td::actor::ActorId<TestNode> id, int server_idx) : id_(std::move(id)), server_idx_(server_idx) {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   private:
 | 
					 | 
				
			||||||
    td::actor::ActorId<TestNode> id_;
 | 
					 | 
				
			||||||
    int server_idx_;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  server.client_ready = false;
 | 
					 | 
				
			||||||
  server.wait_client_ready.clear();
 | 
					 | 
				
			||||||
  LOG(INFO) << "Connecting to " << server.addr << " (liteserver #" << server_idx << ")";
 | 
					 | 
				
			||||||
  server.client = ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{server.public_key}, server.addr,
 | 
					 | 
				
			||||||
                                                   std::make_unique<Callback>(actor_id(this), server_idx));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void TestNode::conn_ready(int server_idx) {
 | 
					 | 
				
			||||||
  LiteServer& server = servers_[server_idx];
 | 
					 | 
				
			||||||
  LOG(INFO) << "Connection to " << server.addr << " (liteserver #" << server_idx << ") is ready";
 | 
					 | 
				
			||||||
  server.client_ready = true;
 | 
					 | 
				
			||||||
  for (auto& p : server.wait_client_ready) {
 | 
					 | 
				
			||||||
    p.set_result(td::Unit());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  server.wait_client_ready.clear();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void TestNode::conn_closed(int server_idx) {
 | 
					 | 
				
			||||||
  LiteServer& server = servers_[server_idx];
 | 
					 | 
				
			||||||
  LOG(INFO) << "Connection to " << server.addr << " (liteserver #" << server_idx << ") closed";
 | 
					 | 
				
			||||||
  server.client_ready = false;
 | 
					 | 
				
			||||||
  server.wait_client_ready.clear();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
td::Promise<td::Unit> TestNode::trivial_promise() {
 | 
					td::Promise<td::Unit> TestNode::trivial_promise() {
 | 
				
			||||||
  return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result<td::Unit> res) {
 | 
					  return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result<td::Unit> res) {
 | 
				
			||||||
    if (res.is_error()) {
 | 
					    if (res.is_error()) {
 | 
				
			||||||
| 
						 | 
					@ -433,7 +292,7 @@ bool TestNode::dump_cached_cell(td::Slice hash_pfx, td::Slice type_name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_server_time() {
 | 
					bool TestNode::get_server_time() {
 | 
				
			||||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getTime>(), true);
 | 
					  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getTime>(), true);
 | 
				
			||||||
  return envelope_send_query_to_any(std::move(b), [&, Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
					  return envelope_send_query(std::move(b), [&, Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
    if (res.is_error()) {
 | 
					    if (res.is_error()) {
 | 
				
			||||||
      LOG(ERROR) << "cannot get server time";
 | 
					      LOG(ERROR) << "cannot get server time";
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					@ -453,7 +312,7 @@ bool TestNode::get_server_time() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_server_version(int mode) {
 | 
					bool TestNode::get_server_version(int mode) {
 | 
				
			||||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getVersion>(), true);
 | 
					  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getVersion>(), true);
 | 
				
			||||||
  return envelope_send_query_to_any(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) {
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) {
 | 
				
			||||||
    td::actor::send_closure_later(Self, &TestNode::got_server_version, std::move(res), mode);
 | 
					    td::actor::send_closure_later(Self, &TestNode::got_server_version, std::move(res), mode);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -501,7 +360,7 @@ bool TestNode::get_server_mc_block_id() {
 | 
				
			||||||
  int mode = (mc_server_capabilities_ & 2) ? 0 : -1;
 | 
					  int mode = (mc_server_capabilities_ & 2) ? 0 : -1;
 | 
				
			||||||
  if (mode < 0) {
 | 
					  if (mode < 0) {
 | 
				
			||||||
    auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
 | 
					    auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
 | 
				
			||||||
    return envelope_send_query_to_any(std::move(b), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
					    return envelope_send_query(std::move(b), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
      if (res.is_error()) {
 | 
					      if (res.is_error()) {
 | 
				
			||||||
        LOG(ERROR) << "cannot get masterchain info from server";
 | 
					        LOG(ERROR) << "cannot get masterchain info from server";
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
| 
						 | 
					@ -521,8 +380,7 @@ bool TestNode::get_server_mc_block_id() {
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    auto b =
 | 
					    auto b =
 | 
				
			||||||
        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfoExt>(mode), true);
 | 
					        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfoExt>(mode), true);
 | 
				
			||||||
    return envelope_send_query_to_any(
 | 
					    return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
        std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) -> void {
 | 
					 | 
				
			||||||
      if (res.is_error()) {
 | 
					      if (res.is_error()) {
 | 
				
			||||||
        LOG(ERROR) << "cannot get extended masterchain info from server";
 | 
					        LOG(ERROR) << "cannot get extended masterchain info from server";
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
| 
						 | 
					@ -594,8 +452,7 @@ void TestNode::got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateI
 | 
				
			||||||
bool TestNode::request_block(ton::BlockIdExt blkid) {
 | 
					bool TestNode::request_block(ton::BlockIdExt blkid) {
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(blkid)), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(blkid)), true);
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
					 | 
				
			||||||
    if (res.is_error()) {
 | 
					    if (res.is_error()) {
 | 
				
			||||||
      LOG(ERROR) << "cannot obtain block " << blkid.to_str() << " from server";
 | 
					      LOG(ERROR) << "cannot obtain block " << blkid.to_str() << " from server";
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					@ -620,8 +477,7 @@ bool TestNode::request_block(ton::BlockIdExt blkid) {
 | 
				
			||||||
bool TestNode::request_state(ton::BlockIdExt blkid) {
 | 
					bool TestNode::request_state(ton::BlockIdExt blkid) {
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getState>(ton::create_tl_lite_block_id(blkid)), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getState>(ton::create_tl_lite_block_id(blkid)), true);
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
					 | 
				
			||||||
    if (res.is_error()) {
 | 
					    if (res.is_error()) {
 | 
				
			||||||
      LOG(ERROR) << "cannot obtain state " << blkid.to_str() << " from server";
 | 
					      LOG(ERROR) << "cannot obtain state " << blkid.to_str() << " from server";
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					@ -1280,18 +1136,8 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) {
 | 
				
			||||||
    LOG(ERROR) << "failed to read file `" << filename << "`: " << err.to_string();
 | 
					    LOG(ERROR) << "failed to read file `" << filename << "`: " << err.to_string();
 | 
				
			||||||
    return err;
 | 
					    return err;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (ready_ && !client_.empty()) {
 | 
				
			||||||
    LOG(ERROR) << "sending query from file " << filename;
 | 
					    LOG(ERROR) << "sending query from file " << filename;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  TRY_RESULT_PREFIX(root, vm::std_boc_deserialize(F.ok().as_slice()), "invalid boc: ");
 | 
					 | 
				
			||||||
  block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
 | 
					 | 
				
			||||||
  if (!tlb::unpack_cell_inexact(root, info)) {
 | 
					 | 
				
			||||||
    return td::Status::Error("failed to unpack external message header");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  auto dest_prefix = block::tlb::MsgAddressInt::get_prefix(info.dest);
 | 
					 | 
				
			||||||
  if (!dest_prefix.is_valid()) {
 | 
					 | 
				
			||||||
    return td::Status::Error("destination of the message is invalid");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> R) {
 | 
					    auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
      if (R.is_error()) {
 | 
					      if (R.is_error()) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
| 
						 | 
					@ -1304,10 +1150,13 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) {
 | 
				
			||||||
        LOG(INFO) << "external message status is " << status;
 | 
					        LOG(INFO) << "external message status is " << status;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(F.move_as_ok()), true);
 | 
					    auto b =
 | 
				
			||||||
  return envelope_send_query_to_account(dest_prefix, std::move(b), std::move(P))
 | 
					        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(F.move_as_ok()), true);
 | 
				
			||||||
             ? td::Status::OK()
 | 
					    return envelope_send_query(std::move(b), std::move(P)) ? td::Status::OK()
 | 
				
			||||||
                                                           : td::Status::Error("cannot send query to server");
 | 
					                                                           : td::Status::Error("cannot send query to server");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return td::Status::Error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
 | 
					bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
 | 
				
			||||||
| 
						 | 
					@ -1315,6 +1164,9 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
  if (!ref_blkid.is_valid()) {
 | 
					  if (!ref_blkid.is_valid()) {
 | 
				
			||||||
    return set_error("must obtain last block information before making other queries");
 | 
					    return set_error("must obtain last block information before making other queries");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (addr_ext) {
 | 
					  if (addr_ext) {
 | 
				
			||||||
    return get_special_smc_addr(
 | 
					    return get_special_smc_addr(
 | 
				
			||||||
        addr_ext, [this, ref_blkid, filename, mode, prunned](td::Result<ton::StdSmcAddress> res) {
 | 
					        addr_ext, [this, ref_blkid, filename, mode, prunned](td::Result<ton::StdSmcAddress> res) {
 | 
				
			||||||
| 
						 | 
					@ -1336,12 +1188,10 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
                                     ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
					                                     ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
				
			||||||
                                 true);
 | 
					                                 true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
					 | 
				
			||||||
  LOG(INFO) << "requesting " << (prunned ? "prunned " : "") << "account state for " << workchain << ":" << addr.to_hex()
 | 
					  LOG(INFO) << "requesting " << (prunned ? "prunned " : "") << "account state for " << workchain << ":" << addr.to_hex()
 | 
				
			||||||
            << " with respect to " << ref_blkid.to_str() << " with savefile `" << filename << "` and mode " << mode;
 | 
					            << " with respect to " << ref_blkid.to_str() << " with savefile `" << filename << "` and mode " << mode;
 | 
				
			||||||
  return envelope_send_query_to_account(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode,
 | 
				
			||||||
      account_prefix, std::move(b),
 | 
					                                            prunned](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
      [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode, prunned](td::Result<td::BufferSlice> R) {
 | 
					 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1421,17 +1271,18 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
				
			||||||
  if (!ref_blkid.is_valid()) {
 | 
					  if (!ref_blkid.is_valid()) {
 | 
				
			||||||
    return set_error("must obtain last block information before making other queries");
 | 
					    return set_error("must obtain last block information before making other queries");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
				
			||||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
					 | 
				
			||||||
  if (!mode) {
 | 
					  if (!mode) {
 | 
				
			||||||
    auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
 | 
					    auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
 | 
				
			||||||
                                          ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
					                                          ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
				
			||||||
                                      true);
 | 
					                                      true);
 | 
				
			||||||
    LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to "
 | 
					    LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to "
 | 
				
			||||||
              << ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters";
 | 
					              << ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters";
 | 
				
			||||||
    return envelope_send_query_to_account(
 | 
					    return envelope_send_query(
 | 
				
			||||||
        account_prefix, std::move(b),
 | 
					        std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, method_name, params = std::move(params),
 | 
				
			||||||
        [Self = actor_id(this), workchain, addr, ref_blkid, method_name, params = std::move(params),
 | 
					 | 
				
			||||||
                       promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					                       promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
          if (R.is_error()) {
 | 
					          if (R.is_error()) {
 | 
				
			||||||
            promise.set_error(R.move_as_error());
 | 
					            promise.set_error(R.move_as_error());
 | 
				
			||||||
| 
						 | 
					@ -1472,9 +1323,8 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
				
			||||||
    LOG(INFO) << "requesting remote get-method execution for " << workchain << ":" << addr.to_hex()
 | 
					    LOG(INFO) << "requesting remote get-method execution for " << workchain << ":" << addr.to_hex()
 | 
				
			||||||
              << " with respect to " << ref_blkid.to_str() << " to run method " << method_name << " with "
 | 
					              << " with respect to " << ref_blkid.to_str() << " to run method " << method_name << " with "
 | 
				
			||||||
              << params.size() << " parameters";
 | 
					              << params.size() << " parameters";
 | 
				
			||||||
    return envelope_send_query_to_account(
 | 
					    return envelope_send_query(std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode,
 | 
				
			||||||
        account_prefix, std::move(b),
 | 
					                                              params = std::move(params),
 | 
				
			||||||
        [Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params),
 | 
					 | 
				
			||||||
                                              promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					                                              promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
      if (R.is_error()) {
 | 
					      if (R.is_error()) {
 | 
				
			||||||
        promise.set_error(R.move_as_error());
 | 
					        promise.set_error(R.move_as_error());
 | 
				
			||||||
| 
						 | 
					@ -1486,11 +1336,11 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
				
			||||||
        promise.set_error(td::Status::Error("cannot parse answer to liteServer.runSmcMethod"));
 | 
					        promise.set_error(td::Status::Error("cannot parse answer to liteServer.runSmcMethod"));
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        auto f = F.move_as_ok();
 | 
					        auto f = F.move_as_ok();
 | 
				
			||||||
            td::actor::send_closure_later(
 | 
					        td::actor::send_closure_later(Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_),
 | 
				
			||||||
                Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_),
 | 
					                                      ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
 | 
				
			||||||
                ton::create_block_id(f->shardblk_), std::move(f->shard_proof_), std::move(f->proof_),
 | 
					                                      std::move(f->proof_), std::move(f->state_proof_), workchain, addr, method_name,
 | 
				
			||||||
                std::move(f->state_proof_), workchain, addr, method_name, std::move(params), std::move(f->init_c7_),
 | 
					                                      std::move(params), std::move(f->init_c7_), std::move(f->lib_extras_),
 | 
				
			||||||
                std::move(f->lib_extras_), std::move(f->result_), f->exit_code_, std::move(promise));
 | 
					                                      std::move(f->result_), f->exit_code_, std::move(promise));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -1722,8 +1572,8 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add
 | 
				
			||||||
  params.emplace_back(td::make_refint(bits));
 | 
					  params.emplace_back(td::make_refint(bits));
 | 
				
			||||||
  params.emplace_back(td::make_refint(refs));
 | 
					  params.emplace_back(td::make_refint(refs));
 | 
				
			||||||
  params.emplace_back(td::make_refint(expires_in));
 | 
					  params.emplace_back(td::make_refint(expires_in));
 | 
				
			||||||
  auto P =
 | 
					  auto P = td::PromiseCreator::lambda(
 | 
				
			||||||
      td::PromiseCreator::lambda([expires_in, bits, refs, chash, filename](td::Result<std::vector<vm::StackEntry>> R) {
 | 
					      [this, expires_in, bits, refs, chash, filename](td::Result<std::vector<vm::StackEntry>> R) {
 | 
				
			||||||
        if (R.is_error()) {
 | 
					        if (R.is_error()) {
 | 
				
			||||||
          LOG(ERROR) << R.move_as_error();
 | 
					          LOG(ERROR) << R.move_as_error();
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
| 
						 | 
					@ -1748,9 +1598,8 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_msg_queue_sizes() {
 | 
					bool TestNode::get_msg_queue_sizes() {
 | 
				
			||||||
  // TODO: rework for separated liteservers
 | 
					 | 
				
			||||||
  auto q = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOutMsgQueueSizes>(0, 0, 0), true);
 | 
					  auto q = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOutMsgQueueSizes>(0, 0, 0), true);
 | 
				
			||||||
  return envelope_send_query_to_any(std::move(q), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
					  return envelope_send_query(std::move(q), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
    if (res.is_error()) {
 | 
					    if (res.is_error()) {
 | 
				
			||||||
      LOG(ERROR) << "liteServer.getOutMsgQueueSizes error: " << res.move_as_error();
 | 
					      LOG(ERROR) << "liteServer.getOutMsgQueueSizes error: " << res.move_as_error();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					@ -1810,6 +1659,10 @@ bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
    return set_error("domain name too long");
 | 
					    return set_error("domain name too long");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (workchain == ton::workchainInvalid) {
 | 
					  if (workchain == ton::workchainInvalid) {
 | 
				
			||||||
    if (dns_root_queried_) {
 | 
					    if (dns_root_queried_) {
 | 
				
			||||||
      workchain = ton::masterchainId;
 | 
					      workchain = ton::masterchainId;
 | 
				
			||||||
| 
						 | 
					@ -2018,16 +1871,17 @@ bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workc
 | 
				
			||||||
  if (!ton::shard_contains(blkid.shard_full(), ton::extract_addr_prefix(workchain, addr))) {
 | 
					  if (!ton::shard_contains(blkid.shard_full(), ton::extract_addr_prefix(workchain, addr))) {
 | 
				
			||||||
    return set_error("the shard of this block cannot contain this account");
 | 
					    return set_error("the shard of this block cannot contain this account");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
				
			||||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
 | 
					  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
 | 
				
			||||||
                                        ton::create_tl_lite_block_id(blkid), std::move(a), lt),
 | 
					                                        ton::create_tl_lite_block_id(blkid), std::move(a), lt),
 | 
				
			||||||
                                    true);
 | 
					                                    true);
 | 
				
			||||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
					 | 
				
			||||||
  LOG(INFO) << "requesting transaction " << lt << " of " << workchain << ":" << addr.to_hex() << " from block "
 | 
					  LOG(INFO) << "requesting transaction " << lt << " of " << workchain << ":" << addr.to_hex() << " from block "
 | 
				
			||||||
            << blkid.to_str();
 | 
					            << blkid.to_str();
 | 
				
			||||||
  return envelope_send_query_to_account(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      account_prefix, std::move(b),
 | 
					      std::move(b), [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result<td::BufferSlice> R) -> void {
 | 
				
			||||||
      [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result<td::BufferSlice> R) -> void {
 | 
					 | 
				
			||||||
        if (R.is_error()) {
 | 
					        if (R.is_error()) {
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -2044,15 +1898,16 @@ bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_last_transactions(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::LogicalTime lt,
 | 
					bool TestNode::get_last_transactions(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::LogicalTime lt,
 | 
				
			||||||
                                     ton::Bits256 hash, unsigned count, bool dump) {
 | 
					                                     ton::Bits256 hash, unsigned count, bool dump) {
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(count, std::move(a), lt, hash), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(count, std::move(a), lt, hash), true);
 | 
				
			||||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
					 | 
				
			||||||
  LOG(INFO) << "requesting " << count << " last transactions from " << lt << ":" << hash.to_hex() << " of " << workchain
 | 
					  LOG(INFO) << "requesting " << count << " last transactions from " << lt << ":" << hash.to_hex() << " of " << workchain
 | 
				
			||||||
            << ":" << addr.to_hex();
 | 
					            << ":" << addr.to_hex();
 | 
				
			||||||
  return envelope_send_query_to_account(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      account_prefix, std::move(b),
 | 
					      std::move(b), [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
      [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result<td::BufferSlice> R) {
 | 
					 | 
				
			||||||
        if (R.is_error()) {
 | 
					        if (R.is_error()) {
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -2420,10 +2275,10 @@ void TestNode::got_one_transaction(ton::BlockIdExt req_blkid, ton::BlockIdExt bl
 | 
				
			||||||
                 << " but received data has " << root->get_hash().bits().to_hex(256);
 | 
					                 << " but received data has " << root->get_hash().bits().to_hex(256);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } catch (vm::VmError& err) {
 | 
					  } catch (vm::VmError err) {
 | 
				
			||||||
    LOG(ERROR) << "error while traversing block transaction proof : " << err.get_msg();
 | 
					    LOG(ERROR) << "error while traversing block transaction proof : " << err.get_msg();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  } catch (vm::VmVirtError& err) {
 | 
					  } catch (vm::VmVirtError err) {
 | 
				
			||||||
    LOG(ERROR) << "virtualization error while traversing block transaction proof : " << err.get_msg();
 | 
					    LOG(ERROR) << "virtualization error while traversing block transaction proof : " << err.get_msg();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -2602,14 +2457,16 @@ void TestNode::got_last_transactions(std::vector<ton::BlockIdExt> blkids, td::Bu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_block_transactions(ton::BlockIdExt blkid, int mode, unsigned count, ton::Bits256 acc_addr,
 | 
					bool TestNode::get_block_transactions(ton::BlockIdExt blkid, int mode, unsigned count, ton::Bits256 acc_addr,
 | 
				
			||||||
                                      ton::LogicalTime lt) {
 | 
					                                      ton::LogicalTime lt) {
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(acc_addr, lt);
 | 
					  auto a = ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(acc_addr, lt);
 | 
				
			||||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
					  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
				
			||||||
                                        ton::create_tl_lite_block_id(blkid), mode, count, std::move(a), false, false),
 | 
					                                        ton::create_tl_lite_block_id(blkid), mode, count, std::move(a), false, false),
 | 
				
			||||||
                                    true);
 | 
					                                    true);
 | 
				
			||||||
  LOG(INFO) << "requesting " << count << " transactions from block " << blkid.to_str() << " starting from account "
 | 
					  LOG(INFO) << "requesting " << count << " transactions from block " << blkid.to_str() << " starting from account "
 | 
				
			||||||
            << acc_addr.to_hex() << " lt " << lt;
 | 
					            << acc_addr.to_hex() << " lt " << lt;
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> R) {
 | 
				
			||||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> R) {
 | 
					 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -2651,11 +2508,13 @@ bool TestNode::get_all_shards(std::string filename, bool use_last, ton::BlockIdE
 | 
				
			||||||
  if (!blkid.is_masterchain()) {
 | 
					  if (!blkid.is_masterchain()) {
 | 
				
			||||||
    return set_error("only masterchain blocks contain shard configuration");
 | 
					    return set_error("only masterchain blocks contain shard configuration");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(blkid)), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(blkid)), true);
 | 
				
			||||||
  LOG(INFO) << "requesting recent shard configuration";
 | 
					  LOG(INFO) << "requesting recent shard configuration";
 | 
				
			||||||
  return envelope_send_query_to_any(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), filename](td::Result<td::BufferSlice> R) -> void {
 | 
				
			||||||
      std::move(b), [Self = actor_id(this), filename](td::Result<td::BufferSlice> R) -> void {
 | 
					 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -2664,8 +2523,8 @@ bool TestNode::get_all_shards(std::string filename, bool use_last, ton::BlockIdE
 | 
				
			||||||
      LOG(ERROR) << "cannot parse answer to liteServer.getAllShardsInfo";
 | 
					      LOG(ERROR) << "cannot parse answer to liteServer.getAllShardsInfo";
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      auto f = F.move_as_ok();
 | 
					      auto f = F.move_as_ok();
 | 
				
			||||||
          td::actor::send_closure_later(Self, &TestNode::got_all_shards, ton::create_block_id(f->id_),
 | 
					      td::actor::send_closure_later(Self, &TestNode::got_all_shards, ton::create_block_id(f->id_), std::move(f->proof_),
 | 
				
			||||||
                                        std::move(f->proof_), std::move(f->data_), filename);
 | 
					                                    std::move(f->data_), filename);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2731,6 +2590,9 @@ bool TestNode::parse_get_config_params(ton::BlockIdExt blkid, int mode, std::str
 | 
				
			||||||
      params.push_back(x);
 | 
					      params.push_back(x);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (!blkid.is_masterchain_ext()) {
 | 
					  if (!blkid.is_masterchain_ext()) {
 | 
				
			||||||
    return set_error("only masterchain blocks contain configuration");
 | 
					    return set_error("only masterchain blocks contain configuration");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -2749,6 +2611,10 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, td::Promise<std::unique_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_config_params_ext(ton::BlockIdExt blkid, td::Promise<ConfigInfo> promise, int mode,
 | 
					bool TestNode::get_config_params_ext(ton::BlockIdExt blkid, td::Promise<ConfigInfo> promise, int mode,
 | 
				
			||||||
                                     std::string filename, std::vector<int> params) {
 | 
					                                     std::string filename, std::vector<int> params) {
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error("server connection not ready"));
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (!blkid.is_masterchain_ext()) {
 | 
					  if (!blkid.is_masterchain_ext()) {
 | 
				
			||||||
    promise.set_error(td::Status::Error("masterchain reference block expected"));
 | 
					    promise.set_error(td::Status::Error("masterchain reference block expected"));
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
| 
						 | 
					@ -2766,8 +2632,7 @@ bool TestNode::get_config_params_ext(ton::BlockIdExt blkid, td::Promise<ConfigIn
 | 
				
			||||||
                                                      true);
 | 
					                                                      true);
 | 
				
			||||||
  LOG(INFO) << "requesting " << params.size() << " configuration parameters with respect to masterchain block "
 | 
					  LOG(INFO) << "requesting " << params.size() << " configuration parameters with respect to masterchain block "
 | 
				
			||||||
            << blkid.to_str();
 | 
					            << blkid.to_str();
 | 
				
			||||||
  return envelope_send_query_to_any(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), mode, filename, blkid, params = std::move(params),
 | 
				
			||||||
      std::move(b), [Self = actor_id(this), mode, filename, blkid, params = std::move(params),
 | 
					 | 
				
			||||||
                                            promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					                                            promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
    td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, mode, filename, std::move(params),
 | 
					    td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, mode, filename, std::move(params),
 | 
				
			||||||
                                  std::move(R), std::move(promise));
 | 
					                                  std::move(R), std::move(promise));
 | 
				
			||||||
| 
						 | 
					@ -2959,8 +2824,8 @@ bool TestNode::get_block(ton::BlockIdExt blkid, bool dump) {
 | 
				
			||||||
  LOG(INFO) << "got block download request for " << blkid.to_str();
 | 
					  LOG(INFO) << "got block download request for " << blkid.to_str();
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(blkid)), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(blkid)), true);
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
					      std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
        if (res.is_error()) {
 | 
					        if (res.is_error()) {
 | 
				
			||||||
          LOG(ERROR) << "cannot obtain block " << blkid.to_str()
 | 
					          LOG(ERROR) << "cannot obtain block " << blkid.to_str()
 | 
				
			||||||
                     << " from server : " << res.move_as_error().to_string();
 | 
					                     << " from server : " << res.move_as_error().to_string();
 | 
				
			||||||
| 
						 | 
					@ -2988,8 +2853,8 @@ bool TestNode::get_state(ton::BlockIdExt blkid, bool dump) {
 | 
				
			||||||
  LOG(INFO) << "got state download request for " << blkid.to_str();
 | 
					  LOG(INFO) << "got state download request for " << blkid.to_str();
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getState>(ton::create_tl_lite_block_id(blkid)), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getState>(ton::create_tl_lite_block_id(blkid)), true);
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
					      std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
				
			||||||
        if (res.is_error()) {
 | 
					        if (res.is_error()) {
 | 
				
			||||||
          LOG(ERROR) << "cannot obtain state " << blkid.to_str()
 | 
					          LOG(ERROR) << "cannot obtain state " << blkid.to_str()
 | 
				
			||||||
                     << " from server : " << res.move_as_error().to_string();
 | 
					                     << " from server : " << res.move_as_error().to_string();
 | 
				
			||||||
| 
						 | 
					@ -3126,7 +2991,7 @@ void TestNode::got_state(ton::BlockIdExt blkid, ton::RootHash root_hash, ton::Fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_show_block_header(ton::BlockIdExt blkid, int mode) {
 | 
					bool TestNode::get_show_block_header(ton::BlockIdExt blkid, int mode) {
 | 
				
			||||||
  return get_block_header(blkid, mode, [this](td::Result<BlockHdrInfo> R) {
 | 
					  return get_block_header(blkid, mode, [this, blkid](td::Result<BlockHdrInfo> R) {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
      LOG(ERROR) << "unable to fetch block header: " << R.move_as_error();
 | 
					      LOG(ERROR) << "unable to fetch block header: " << R.move_as_error();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					@ -3141,9 +3006,8 @@ bool TestNode::get_block_header(ton::BlockIdExt blkid, int mode, td::Promise<Tes
 | 
				
			||||||
  LOG(INFO) << "got block header request for " << blkid.to_str() << " with mode " << mode;
 | 
					  LOG(INFO) << "got block header request for " << blkid.to_str() << " with mode " << mode;
 | 
				
			||||||
  auto b = ton::serialize_tl_object(
 | 
					  auto b = ton::serialize_tl_object(
 | 
				
			||||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(blkid), mode), true);
 | 
					      ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(blkid), mode), true);
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      blkid.shard_full(), std::move(b),
 | 
					      std::move(b), [this, blkid, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
				
			||||||
      [this, blkid, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
					 | 
				
			||||||
        TRY_RESULT_PROMISE_PREFIX(promise, res, std::move(R),
 | 
					        TRY_RESULT_PROMISE_PREFIX(promise, res, std::move(R),
 | 
				
			||||||
                                  PSLICE() << "cannot obtain block header for " << blkid.to_str() << " from server :");
 | 
					                                  PSLICE() << "cannot obtain block header for " << blkid.to_str() << " from server :");
 | 
				
			||||||
        got_block_header_raw(std::move(res), std::move(promise), blkid);
 | 
					        got_block_header_raw(std::move(res), std::move(promise), blkid);
 | 
				
			||||||
| 
						 | 
					@ -3169,9 +3033,8 @@ bool TestNode::lookup_block(ton::ShardIdFull shard, int mode, td::uint64 arg,
 | 
				
			||||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>(
 | 
					  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>(
 | 
				
			||||||
                                        mode, ton::create_tl_lite_block_id_simple(id), arg, (td::uint32)arg),
 | 
					                                        mode, ton::create_tl_lite_block_id_simple(id), arg, (td::uint32)arg),
 | 
				
			||||||
                                    true);
 | 
					                                    true);
 | 
				
			||||||
  return envelope_send_query_to_shard(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      shard, std::move(b),
 | 
					      std::move(b), [this, id, mode, arg, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
				
			||||||
      [this, id, mode, arg, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
					 | 
				
			||||||
        TRY_RESULT_PROMISE_PREFIX(promise, res, std::move(R),
 | 
					        TRY_RESULT_PROMISE_PREFIX(promise, res, std::move(R),
 | 
				
			||||||
                                  PSLICE() << "cannot look up block header for " << id.to_str() << " with mode " << mode
 | 
					                                  PSLICE() << "cannot look up block header for " << id.to_str() << " with mode " << mode
 | 
				
			||||||
                                           << " and argument " << arg << " from server :");
 | 
					                                           << " and argument " << arg << " from server :");
 | 
				
			||||||
| 
						 | 
					@ -3285,9 +3148,9 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    show_block_header(blkid, std::move(virt_root), mode);
 | 
					    show_block_header(blkid, std::move(virt_root), mode);
 | 
				
			||||||
  } catch (vm::VmError& err) {
 | 
					  } catch (vm::VmError err) {
 | 
				
			||||||
    LOG(ERROR) << "error processing header for " << blkid.to_str() << " : " << err.get_msg();
 | 
					    LOG(ERROR) << "error processing header for " << blkid.to_str() << " : " << err.get_msg();
 | 
				
			||||||
  } catch (vm::VmVirtError& err) {
 | 
					  } catch (vm::VmVirtError err) {
 | 
				
			||||||
    LOG(ERROR) << "error processing header for " << blkid.to_str() << " : " << err.get_msg();
 | 
					    LOG(ERROR) << "error processing header for " << blkid.to_str() << " : " << err.get_msg();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  show_new_blkids();
 | 
					  show_new_blkids();
 | 
				
			||||||
| 
						 | 
					@ -3316,8 +3179,7 @@ bool TestNode::get_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod
 | 
				
			||||||
      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getBlockProof>(
 | 
					      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getBlockProof>(
 | 
				
			||||||
                                   mode & 0xfff, ton::create_tl_lite_block_id(from), ton::create_tl_lite_block_id(to)),
 | 
					                                   mode & 0xfff, ton::create_tl_lite_block_id(from), ton::create_tl_lite_block_id(to)),
 | 
				
			||||||
                               true);
 | 
					                               true);
 | 
				
			||||||
  return envelope_send_query_to_any(
 | 
					  return envelope_send_query(std::move(b), [Self = actor_id(this), from, to, mode](td::Result<td::BufferSlice> res) {
 | 
				
			||||||
      std::move(b), [Self = actor_id(this), from, to, mode](td::Result<td::BufferSlice> res) {
 | 
					 | 
				
			||||||
    if (res.is_error()) {
 | 
					    if (res.is_error()) {
 | 
				
			||||||
      LOG(ERROR) << "cannot obtain block proof for " << ((mode & 1) ? to.to_str() : "last masterchain block")
 | 
					      LOG(ERROR) << "cannot obtain block proof for " << ((mode & 1) ? to.to_str() : "last masterchain block")
 | 
				
			||||||
                 << " starting from " << from.to_str() << " from server : " << res.move_as_error().to_string();
 | 
					                 << " starting from " << from.to_str() << " from server : " << res.move_as_error().to_string();
 | 
				
			||||||
| 
						 | 
					@ -3378,6 +3240,9 @@ void TestNode::got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after,
 | 
					bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after,
 | 
				
			||||||
                                 ton::UnixTime min_utime) {
 | 
					                                 ton::UnixTime min_utime) {
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (!blkid.is_masterchain_ext()) {
 | 
					  if (!blkid.is_masterchain_ext()) {
 | 
				
			||||||
    return set_error("only masterchain blocks contain block creator statistics");
 | 
					    return set_error("only masterchain blocks contain block creator statistics");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -3388,7 +3253,7 @@ bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_c
 | 
				
			||||||
  auto& os = *osp;
 | 
					  auto& os = *osp;
 | 
				
			||||||
  return get_creator_stats(
 | 
					  return get_creator_stats(
 | 
				
			||||||
      blkid, mode, req_count, start_after, min_utime,
 | 
					      blkid, mode, req_count, start_after, min_utime,
 | 
				
			||||||
      [&os](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
					      [min_utime, &os](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
				
			||||||
                       const block::DiscountedCounter& shard_cnt) -> bool {
 | 
					                       const block::DiscountedCounter& shard_cnt) -> bool {
 | 
				
			||||||
        os << key.to_hex() << " mc_cnt:" << mc_cnt << " shard_cnt:" << shard_cnt << std::endl;
 | 
					        os << key.to_hex() << " mc_cnt:" << mc_cnt << " shard_cnt:" << shard_cnt << std::endl;
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
| 
						 | 
					@ -3418,6 +3283,10 @@ bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_c
 | 
				
			||||||
bool TestNode::get_creator_stats(ton::BlockIdExt blkid, unsigned req_count, ton::UnixTime min_utime,
 | 
					bool TestNode::get_creator_stats(ton::BlockIdExt blkid, unsigned req_count, ton::UnixTime min_utime,
 | 
				
			||||||
                                 TestNode::creator_stats_func_t func, std::unique_ptr<TestNode::CreatorStatsRes> state,
 | 
					                                 TestNode::creator_stats_func_t func, std::unique_ptr<TestNode::CreatorStatsRes> state,
 | 
				
			||||||
                                 td::Promise<std::unique_ptr<TestNode::CreatorStatsRes>> promise) {
 | 
					                                 td::Promise<std::unique_ptr<TestNode::CreatorStatsRes>> promise) {
 | 
				
			||||||
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
 | 
					    promise.set_error(td::Status::Error("server connection not ready"));
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (!state) {
 | 
					  if (!state) {
 | 
				
			||||||
    promise.set_error(td::Status::Error("null CreatorStatsRes"));
 | 
					    promise.set_error(td::Status::Error("null CreatorStatsRes"));
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
| 
						 | 
					@ -3436,7 +3305,7 @@ bool TestNode::get_creator_stats(ton::BlockIdExt blkid, unsigned req_count, ton:
 | 
				
			||||||
  LOG(INFO) << "requesting up to " << req_count << " block creator stats records with respect to masterchain block "
 | 
					  LOG(INFO) << "requesting up to " << req_count << " block creator stats records with respect to masterchain block "
 | 
				
			||||||
            << blkid.to_str() << " starting from validator public key " << state->last_key.to_hex() << " created after "
 | 
					            << blkid.to_str() << " starting from validator public key " << state->last_key.to_hex() << " created after "
 | 
				
			||||||
            << min_utime << " (mode=" << state->mode << ")";
 | 
					            << min_utime << " (mode=" << state->mode << ")";
 | 
				
			||||||
  return envelope_send_query_to_any(
 | 
					  return envelope_send_query(
 | 
				
			||||||
      std::move(b), [this, blkid, req_count, state = std::move(state), min_utime, func = std::move(func),
 | 
					      std::move(b), [this, blkid, req_count, state = std::move(state), min_utime, func = std::move(func),
 | 
				
			||||||
                     promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
					                     promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
        TRY_RESULT_PROMISE(promise, res, std::move(R));
 | 
					        TRY_RESULT_PROMISE(promise, res, std::move(R));
 | 
				
			||||||
| 
						 | 
					@ -3653,7 +3522,7 @@ bool TestNode::load_creator_stats(std::unique_ptr<TestNode::ValidatorLoadInfo> l
 | 
				
			||||||
  ton::UnixTime min_utime = info.valid_since - 1000;
 | 
					  ton::UnixTime min_utime = info.valid_since - 1000;
 | 
				
			||||||
  return get_creator_stats(
 | 
					  return get_creator_stats(
 | 
				
			||||||
      info.blk_id, 1000, min_utime,
 | 
					      info.blk_id, 1000, min_utime,
 | 
				
			||||||
      [&info](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
					      [min_utime, &info](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
				
			||||||
                         const block::DiscountedCounter& shard_cnt) -> bool {
 | 
					                         const block::DiscountedCounter& shard_cnt) -> bool {
 | 
				
			||||||
        info.store_record(key, mc_cnt, shard_cnt);
 | 
					        info.store_record(key, mc_cnt, shard_cnt);
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
| 
						 | 
					@ -3879,9 +3748,8 @@ bool compute_punishment_default(int interval, bool severe, td::RefInt256& fine,
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned& fine_part,
 | 
					bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned& fine_part, Ref<vm::Cell> punishment_params) {
 | 
				
			||||||
                        Ref<vm::Cell> punishment_params) {
 | 
					  if(punishment_params.is_null()) {
 | 
				
			||||||
  if (punishment_params.is_null()) {
 | 
					 | 
				
			||||||
    return compute_punishment_default(interval, severe, fine, fine_part);
 | 
					    return compute_punishment_default(interval, severe, fine, fine_part);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  block::gen::MisbehaviourPunishmentConfig::Record rec;
 | 
					  block::gen::MisbehaviourPunishmentConfig::Record rec;
 | 
				
			||||||
| 
						 | 
					@ -3889,7 +3757,7 @@ bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (interval <= rec.unpunishable_interval) {
 | 
					  if(interval <= rec.unpunishable_interval) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3897,31 +3765,24 @@ bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned
 | 
				
			||||||
  fine_part = rec.default_proportional_fine;
 | 
					  fine_part = rec.default_proportional_fine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (severe) {
 | 
					  if (severe) {
 | 
				
			||||||
    fine = fine * rec.severity_flat_mult;
 | 
					    fine = fine * rec.severity_flat_mult; fine >>= 8;
 | 
				
			||||||
    fine >>= 8;
 | 
					    fine_part = fine_part * rec.severity_proportional_mult; fine_part >>= 8;
 | 
				
			||||||
    fine_part = fine_part * rec.severity_proportional_mult;
 | 
					 | 
				
			||||||
    fine_part >>= 8;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (interval >= rec.long_interval) {
 | 
					  if (interval >= rec.long_interval) {
 | 
				
			||||||
    fine = fine * rec.long_flat_mult;
 | 
					    fine = fine * rec.long_flat_mult; fine >>= 8;
 | 
				
			||||||
    fine >>= 8;
 | 
					    fine_part = fine_part * rec.long_proportional_mult; fine_part >>= 8;
 | 
				
			||||||
    fine_part = fine_part * rec.long_proportional_mult;
 | 
					 | 
				
			||||||
    fine_part >>= 8;
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (interval >= rec.medium_interval) {
 | 
					  if (interval >= rec.medium_interval) {
 | 
				
			||||||
    fine = fine * rec.medium_flat_mult;
 | 
					    fine = fine * rec.medium_flat_mult; fine >>= 8;
 | 
				
			||||||
    fine >>= 8;
 | 
					    fine_part = fine_part * rec.medium_proportional_mult; fine_part >>= 8;
 | 
				
			||||||
    fine_part = fine_part * rec.medium_proportional_mult;
 | 
					 | 
				
			||||||
    fine_part >>= 8;
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool check_punishment(int interval, bool severe, td::RefInt256 fine, unsigned fine_part,
 | 
					bool check_punishment(int interval, bool severe, td::RefInt256 fine, unsigned fine_part, Ref<vm::Cell> punishment_params) {
 | 
				
			||||||
                      Ref<vm::Cell> punishment_params) {
 | 
					 | 
				
			||||||
  td::RefInt256 computed_fine;
 | 
					  td::RefInt256 computed_fine;
 | 
				
			||||||
  unsigned computed_fine_part;
 | 
					  unsigned computed_fine_part;
 | 
				
			||||||
  return compute_punishment(interval, severe, computed_fine, computed_fine_part, punishment_params) &&
 | 
					  return compute_punishment(interval, severe, computed_fine, computed_fine_part, punishment_params) &&
 | 
				
			||||||
| 
						 | 
					@ -4056,7 +3917,7 @@ td::Result<Ref<vm::Cell>> TestNode::ValidatorLoadInfo::build_proof(int idx, td::
 | 
				
			||||||
    block::gen::ValidatorDescr::Record_validator_addr rec2;
 | 
					    block::gen::ValidatorDescr::Record_validator_addr rec2;
 | 
				
			||||||
    if (tlb::csr_unpack(entry, rec1)) {
 | 
					    if (tlb::csr_unpack(entry, rec1)) {
 | 
				
			||||||
      pk = std::move(rec1.public_key);
 | 
					      pk = std::move(rec1.public_key);
 | 
				
			||||||
    } else if (tlb::csr_unpack(entry, rec2)) {
 | 
					    } else if (tlb::csr_unpack(std::move(entry), rec2)) {
 | 
				
			||||||
      pk = std::move(rec2.public_key);
 | 
					      pk = std::move(rec2.public_key);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      return td::Status::Error("cannot unpack ValidatorDescr");
 | 
					      return td::Status::Error("cannot unpack ValidatorDescr");
 | 
				
			||||||
| 
						 | 
					@ -4272,8 +4133,7 @@ td::Status TestNode::continue_check_validator_load_proof(std::unique_ptr<Validat
 | 
				
			||||||
    if (suggested_fine.is_null()) {
 | 
					    if (suggested_fine.is_null()) {
 | 
				
			||||||
      return td::Status::Error("cannot parse suggested fine");
 | 
					      return td::Status::Error("cannot parse suggested fine");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!check_punishment(interval, severe, suggested_fine, rec.suggested_fine_part,
 | 
					    if (!check_punishment(interval, severe, suggested_fine, rec.suggested_fine_part, info2->config->get_config_param(40))) {
 | 
				
			||||||
                          info2->config->get_config_param(40))) {
 | 
					 | 
				
			||||||
      LOG(ERROR) << "proposed punishment (fine " << td::dec_string(suggested_fine)
 | 
					      LOG(ERROR) << "proposed punishment (fine " << td::dec_string(suggested_fine)
 | 
				
			||||||
                 << ", fine_part=" << (double)rec.suggested_fine_part / (1LL << 32) << " is too harsh";
 | 
					                 << ", fine_part=" << (double)rec.suggested_fine_part / (1LL << 32) << " is too harsh";
 | 
				
			||||||
      show_vote(root->get_hash().bits(), false);
 | 
					      show_vote(root->get_hash().bits(), false);
 | 
				
			||||||
| 
						 | 
					@ -4422,8 +4282,7 @@ int main(int argc, char* argv[]) {
 | 
				
			||||||
    return (verbosity >= 0 && verbosity <= 9) ? td::Status::OK() : td::Status::Error("verbosity must be 0..9");
 | 
					    return (verbosity >= 0 && verbosity <= 9) ? td::Status::OK() : td::Status::Error("verbosity must be 0..9");
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  p.add_option('V', "version", "shows lite-client build information", [&]() {
 | 
					  p.add_option('V', "version", "shows lite-client build information", [&]() {
 | 
				
			||||||
    std::cout << "lite-client build information: [ Commit: " << GitMetadata::CommitSHA1()
 | 
					    std::cout << "lite-client build information: [ Commit: " << GitMetadata::CommitSHA1() << ", Date: " << GitMetadata::CommitDate() << "]\n";
 | 
				
			||||||
              << ", Date: " << GitMetadata::CommitDate() << "]\n";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::exit(0);
 | 
					    std::exit(0);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
					    Copyright 2017-2020 Telegram Systems LLP
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include "ext-client.h"
 | 
				
			||||||
#include "adnl/adnl-ext-client.h"
 | 
					#include "adnl/adnl-ext-client.h"
 | 
				
			||||||
#include "tl-utils/tl-utils.hpp"
 | 
					#include "tl-utils/tl-utils.hpp"
 | 
				
			||||||
#include "ton/ton-types.h"
 | 
					#include "ton/ton-types.h"
 | 
				
			||||||
| 
						 | 
					@ -46,35 +47,19 @@ class TestNode : public td::actor::Actor {
 | 
				
			||||||
    min_ls_version = 0x101,
 | 
					    min_ls_version = 0x101,
 | 
				
			||||||
    min_ls_capabilities = 1
 | 
					    min_ls_capabilities = 1
 | 
				
			||||||
  };  // server version >= 1.1, capabilities at least +1 = build proof chains
 | 
					  };  // server version >= 1.1, capabilities at least +1 = build proof chains
 | 
				
			||||||
 | 
					  td::actor::ActorOwn<liteclient::ExtClient> client_;
 | 
				
			||||||
  td::actor::ActorOwn<td::TerminalIO> io_;
 | 
					  td::actor::ActorOwn<td::TerminalIO> io_;
 | 
				
			||||||
 | 
					  bool ready_ = false;
 | 
				
			||||||
  struct LiteServer {
 | 
					 | 
				
			||||||
    td::IPAddress addr;
 | 
					 | 
				
			||||||
    ton::PublicKey public_key;
 | 
					 | 
				
			||||||
    bool is_full = true;
 | 
					 | 
				
			||||||
    std::vector<ton::ShardIdFull> shards;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
 | 
					 | 
				
			||||||
    bool client_ready = false;
 | 
					 | 
				
			||||||
    std::vector<td::Promise<td::Unit>> wait_client_ready;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool supports(ton::ShardIdFull shard) const;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  std::vector<LiteServer> servers_;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::int32 single_liteserver_idx_ = -1;
 | 
					  td::int32 single_liteserver_idx_ = -1;
 | 
				
			||||||
  td::IPAddress single_remote_addr_;
 | 
					  td::IPAddress single_remote_addr_;
 | 
				
			||||||
  ton::PublicKey single_remote_public_key_;
 | 
					  ton::PublicKey single_remote_public_key_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::map<ton::ShardIdFull, td::int32> shard_server_idx_cached_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool readline_enabled_ = true;
 | 
					  bool readline_enabled_ = true;
 | 
				
			||||||
  int print_limit_ = 1024;
 | 
					  int print_limit_ = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string db_root_;
 | 
					  std::string db_root_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // mc_server is the server for queries to masterchain
 | 
					 | 
				
			||||||
  int mc_server_idx_ = -1;
 | 
					 | 
				
			||||||
  int mc_server_time_ = 0;
 | 
					  int mc_server_time_ = 0;
 | 
				
			||||||
  int mc_server_time_got_at_ = 0;
 | 
					  int mc_server_time_got_at_ = 0;
 | 
				
			||||||
  int mc_server_version_ = 0;
 | 
					  int mc_server_version_ = 0;
 | 
				
			||||||
| 
						 | 
					@ -443,18 +428,7 @@ class TestNode : public td::actor::Actor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void got_result(td::Result<td::BufferSlice> R, td::Promise<td::BufferSlice> promise);
 | 
					  void got_result(td::Result<td::BufferSlice> R, td::Promise<td::BufferSlice> promise);
 | 
				
			||||||
  void after_got_result(bool ok);
 | 
					  void after_got_result(bool ok);
 | 
				
			||||||
  bool envelope_send_query_to_any(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
 | 
					  bool envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
 | 
				
			||||||
  bool envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query,
 | 
					 | 
				
			||||||
                                    td::Promise<td::BufferSlice> promise);
 | 
					 | 
				
			||||||
  bool envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query,
 | 
					 | 
				
			||||||
                                      td::Promise<td::BufferSlice> promise);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void start_client(int server_idx);
 | 
					 | 
				
			||||||
  void conn_ready(int server_idx);
 | 
					 | 
				
			||||||
  void conn_closed(int server_idx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void parse_line(td::BufferSlice data);
 | 
					  void parse_line(td::BufferSlice data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TestNode() = default;
 | 
					  TestNode() = default;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										394
									
								
								lite-client/query-utils.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								lite-client/query-utils.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,394 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    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 "query-utils.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "block-parse.h"
 | 
				
			||||||
 | 
					#include "td/utils/overloaded.h"
 | 
				
			||||||
 | 
					#include "tl-utils/common-utils.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "block/block-auto.h"
 | 
				
			||||||
 | 
					#include "auto/tl/lite_api.hpp"
 | 
				
			||||||
 | 
					#include "overlay/overlay-broadcast.hpp"
 | 
				
			||||||
 | 
					#include "tl-utils/lite-utils.hpp"
 | 
				
			||||||
 | 
					#include "ton/lite-tl.hpp"
 | 
				
			||||||
 | 
					#include "ton/ton-shard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ton/ton-tl.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace liteclient {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace ton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string QueryInfo::to_str() const {
 | 
				
			||||||
 | 
					  td::StringBuilder sb;
 | 
				
			||||||
 | 
					  sb << "[ " << lite_query_name_by_id(query_id) << " " << shard_id.to_str();
 | 
				
			||||||
 | 
					  switch (type) {
 | 
				
			||||||
 | 
					    case t_simple:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case t_seqno:
 | 
				
			||||||
 | 
					      sb << " seqno=" << value;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case t_utime:
 | 
				
			||||||
 | 
					      sb << " utime=" << value;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case t_lt:
 | 
				
			||||||
 | 
					      sb << " lt=" << value;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case t_mc_seqno:
 | 
				
			||||||
 | 
					      sb << " mc_seqno=" << value;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  sb << " ]";
 | 
				
			||||||
 | 
					  return sb.as_cslice().str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QueryInfo get_query_info(td::Slice data) {
 | 
				
			||||||
 | 
					  auto F = fetch_tl_object<lite_api::liteServer_query>(data, true);
 | 
				
			||||||
 | 
					  if (F.is_ok()) {
 | 
				
			||||||
 | 
					    data = F.ok()->data_;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true).ignore();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true).ignore();
 | 
				
			||||||
 | 
					  auto Q = fetch_tl_object<lite_api::Function>(data, true);
 | 
				
			||||||
 | 
					  if (Q.is_error()) {
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return get_query_info(*Q.ok());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QueryInfo get_query_info(const lite_api::Function& f) {
 | 
				
			||||||
 | 
					  QueryInfo info;
 | 
				
			||||||
 | 
					  info.query_id = f.get_id();
 | 
				
			||||||
 | 
					  auto from_block_id = [&](const tl_object_ptr<lite_api::tonNode_blockIdExt>& id) {
 | 
				
			||||||
 | 
					    BlockIdExt block_id = create_block_id(id);
 | 
				
			||||||
 | 
					    info.shard_id = block_id.shard_full();
 | 
				
			||||||
 | 
					    info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					    info.value = block_id.seqno();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  downcast_call(
 | 
				
			||||||
 | 
					      const_cast<lite_api::Function&>(f),
 | 
				
			||||||
 | 
					      td::overloaded([&](const lite_api::liteServer_getTime& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getVersion& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getMasterchainInfo& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getMasterchainInfoExt& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getBlock& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getBlockHeader& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getState& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getAccountState& q) {
 | 
				
			||||||
 | 
					                       BlockIdExt block_id = create_block_id(q.id_);
 | 
				
			||||||
 | 
					                       AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_);
 | 
				
			||||||
 | 
					                       info.shard_id = acc_id_prefix.as_leaf_shard();
 | 
				
			||||||
 | 
					                       // See LiteQuery::perform_getAccountState
 | 
				
			||||||
 | 
					                       if (block_id.id.workchain != masterchainId) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno();
 | 
				
			||||||
 | 
					                       } else if (block_id.id.seqno != ~0U) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_mc_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno();
 | 
				
			||||||
 | 
					                       } else {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_simple;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getAccountStatePrunned& q) {
 | 
				
			||||||
 | 
					                       BlockIdExt block_id = create_block_id(q.id_);
 | 
				
			||||||
 | 
					                       AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_);
 | 
				
			||||||
 | 
					                       info.shard_id = acc_id_prefix.as_leaf_shard();
 | 
				
			||||||
 | 
					                       // See LiteQuery::perform_getAccountState
 | 
				
			||||||
 | 
					                       if (block_id.id.workchain != masterchainId) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno();
 | 
				
			||||||
 | 
					                       } else if (block_id.id.seqno != ~0U) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_mc_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno();
 | 
				
			||||||
 | 
					                       } else {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_simple;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getOneTransaction& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getTransactions& q) {
 | 
				
			||||||
 | 
					                       AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_);
 | 
				
			||||||
 | 
					                       info.shard_id = acc_id_prefix.as_leaf_shard();
 | 
				
			||||||
 | 
					                       info.type = QueryInfo::t_lt;
 | 
				
			||||||
 | 
					                       info.value = q.lt_;
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_sendMessage& q) {
 | 
				
			||||||
 | 
					                       info.type = QueryInfo::t_simple;
 | 
				
			||||||
 | 
					                       auto r_root = vm::std_boc_deserialize(q.body_);
 | 
				
			||||||
 | 
					                       if (r_root.is_error()) {
 | 
				
			||||||
 | 
					                         return;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                       block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
 | 
				
			||||||
 | 
					                       if (!tlb::unpack_cell_inexact(r_root.ok(), msg_info)) {
 | 
				
			||||||
 | 
					                         return;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                       auto dest_prefix = block::tlb::MsgAddressInt::get_prefix(msg_info.dest);
 | 
				
			||||||
 | 
					                       if (!dest_prefix.is_valid()) {
 | 
				
			||||||
 | 
					                         return;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                       info.shard_id = dest_prefix.as_leaf_shard();
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getShardInfo& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getAllShardsInfo& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_lookupBlock& q) {
 | 
				
			||||||
 | 
					                       BlockId block_id = create_block_id_simple(q.id_);
 | 
				
			||||||
 | 
					                       info.shard_id = block_id.shard_full();
 | 
				
			||||||
 | 
					                       // See LiteQuery::perform_lookupBlock
 | 
				
			||||||
 | 
					                       if (q.mode_ & 1) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno;
 | 
				
			||||||
 | 
					                       } else if (q.mode_ == 2) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_lt;
 | 
				
			||||||
 | 
					                         info.value = q.lt_;
 | 
				
			||||||
 | 
					                       } else if (q.mode_ == 4) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_utime;
 | 
				
			||||||
 | 
					                         info.value = q.utime_;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_lookupBlockWithProof& q) {
 | 
				
			||||||
 | 
					                       BlockId block_id = create_block_id_simple(q.id_);
 | 
				
			||||||
 | 
					                       info.shard_id = block_id.shard_full();
 | 
				
			||||||
 | 
					                       // See LiteQuery::perform_lookupBlockWithProof
 | 
				
			||||||
 | 
					                       if (q.mode_ & 1) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno;
 | 
				
			||||||
 | 
					                       } else if (q.mode_ == 2) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_lt;
 | 
				
			||||||
 | 
					                         info.value = q.lt_;
 | 
				
			||||||
 | 
					                       } else if (q.mode_ == 4) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_utime;
 | 
				
			||||||
 | 
					                         info.value = q.utime_;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_listBlockTransactions& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_listBlockTransactionsExt& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getConfigParams& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getConfigAll& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getBlockProof& q) {
 | 
				
			||||||
 | 
					                       info.shard_id = ShardIdFull{masterchainId};
 | 
				
			||||||
 | 
					                       BlockIdExt from = create_block_id(q.known_block_);
 | 
				
			||||||
 | 
					                       BlockIdExt to = create_block_id(q.target_block_);
 | 
				
			||||||
 | 
					                       // See LiteQuery::perform_getBlockProof
 | 
				
			||||||
 | 
					                       if ((q.mode_ & 1) && (q.mode_ & 0x1000)) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					                         info.value = std::max(from.seqno(), to.seqno());
 | 
				
			||||||
 | 
					                       } else {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_simple;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getValidatorStats& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_runSmcMethod& q) {
 | 
				
			||||||
 | 
					                       BlockIdExt block_id = create_block_id(q.id_);
 | 
				
			||||||
 | 
					                       AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_);
 | 
				
			||||||
 | 
					                       info.shard_id = acc_id_prefix.as_leaf_shard();
 | 
				
			||||||
 | 
					                       // See LiteQuery::perform_getAccountState
 | 
				
			||||||
 | 
					                       if (block_id.id.workchain != masterchainId) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno();
 | 
				
			||||||
 | 
					                       } else if (block_id.id.seqno != ~0U) {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_mc_seqno;
 | 
				
			||||||
 | 
					                         info.value = block_id.seqno();
 | 
				
			||||||
 | 
					                       } else {
 | 
				
			||||||
 | 
					                         info.type = QueryInfo::t_simple;
 | 
				
			||||||
 | 
					                       }
 | 
				
			||||||
 | 
					                     },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getLibraries& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getLibrariesWithProof& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getShardBlockProof& q) { from_block_id(q.id_); },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_nonfinal_getCandidate& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_nonfinal_getValidatorGroups& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const lite_api::liteServer_getOutMsgQueueSizes& q) { /* t_simple */ },
 | 
				
			||||||
 | 
					                     [&](const auto&) { /* t_simple */ }));
 | 
				
			||||||
 | 
					  if (info.shard_id.workchain == masterchainId) {
 | 
				
			||||||
 | 
					    info.shard_id.shard = shardIdAll;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!info.shard_id.is_valid_ext()) {
 | 
				
			||||||
 | 
					    info.shard_id = ShardIdFull{masterchainId};
 | 
				
			||||||
 | 
					    info.type = QueryInfo::t_simple;
 | 
				
			||||||
 | 
					    info.value = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return info;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LiteServerConfig::accepts_query(const QueryInfo& query_info) const {
 | 
				
			||||||
 | 
					  if (is_full) {
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (const Slice& s : slices) {
 | 
				
			||||||
 | 
					    if (s.accepts_query(query_info)) {
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LiteServerConfig::Slice::accepts_query(const QueryInfo& query_info) const {
 | 
				
			||||||
 | 
					  if (unlimited) {
 | 
				
			||||||
 | 
					    for (const ShardInfo& shard : shards_from) {
 | 
				
			||||||
 | 
					      if (shard_intersects(shard.shard_id, query_info.shard_id)) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!shards_from.empty()) {
 | 
				
			||||||
 | 
					    bool from_ok = false;
 | 
				
			||||||
 | 
					    DCHECK(shards_from[0].shard_id.is_masterchain());
 | 
				
			||||||
 | 
					    for (const ShardInfo& shard : shards_from) {
 | 
				
			||||||
 | 
					      if (shard_intersects(shard.shard_id, query_info.shard_id)) {
 | 
				
			||||||
 | 
					        switch (query_info.type) {
 | 
				
			||||||
 | 
					          case QueryInfo::t_simple:
 | 
				
			||||||
 | 
					            from_ok = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_seqno:
 | 
				
			||||||
 | 
					            from_ok = shard.seqno <= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_utime:
 | 
				
			||||||
 | 
					            from_ok = shard.utime <= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_lt:
 | 
				
			||||||
 | 
					            from_ok = shard.lt <= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_mc_seqno:
 | 
				
			||||||
 | 
					            from_ok = shards_from[0].seqno <= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (from_ok) {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!from_ok) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!shards_to.empty()) {
 | 
				
			||||||
 | 
					    bool to_ok = false;
 | 
				
			||||||
 | 
					    DCHECK(shards_to[0].shard_id.is_masterchain());
 | 
				
			||||||
 | 
					    for (const ShardInfo& shard : shards_to) {
 | 
				
			||||||
 | 
					      if (shard_intersects(shard.shard_id, query_info.shard_id)) {
 | 
				
			||||||
 | 
					        switch (query_info.type) {
 | 
				
			||||||
 | 
					          case QueryInfo::t_simple:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_seqno:
 | 
				
			||||||
 | 
					            to_ok = shard.seqno >= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_utime:
 | 
				
			||||||
 | 
					            to_ok = shard.utime >= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_lt:
 | 
				
			||||||
 | 
					            to_ok = shard.lt >= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case QueryInfo::t_mc_seqno:
 | 
				
			||||||
 | 
					            to_ok = shards_from[0].seqno >= query_info.value;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (to_ok) {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!to_ok) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td::Result<std::vector<LiteServerConfig>> LiteServerConfig::parse_global_config(
 | 
				
			||||||
 | 
					    const ton_api::liteclient_config_global& config) {
 | 
				
			||||||
 | 
					  std::vector<LiteServerConfig> servers;
 | 
				
			||||||
 | 
					  for (const auto& f : config.liteservers_) {
 | 
				
			||||||
 | 
					    LiteServerConfig server;
 | 
				
			||||||
 | 
					    TRY_STATUS(server.addr.init_host_port(td::IPAddress::ipv4_to_str(f->ip_), f->port_));
 | 
				
			||||||
 | 
					    server.adnl_id = adnl::AdnlNodeIdFull{PublicKey{f->id_}};
 | 
				
			||||||
 | 
					    server.is_full = true;
 | 
				
			||||||
 | 
					    servers.push_back(std::move(server));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (const auto& f : config.liteservers_v2_) {
 | 
				
			||||||
 | 
					    LiteServerConfig server;
 | 
				
			||||||
 | 
					    TRY_STATUS(server.addr.init_host_port(td::IPAddress::ipv4_to_str(f->ip_), f->port_));
 | 
				
			||||||
 | 
					    server.adnl_id = adnl::AdnlNodeIdFull{PublicKey{f->id_}};
 | 
				
			||||||
 | 
					    server.is_full = false;
 | 
				
			||||||
 | 
					    for (const auto& slice_obj : f->slices_) {
 | 
				
			||||||
 | 
					      Slice slice;
 | 
				
			||||||
 | 
					      td::Status S = td::Status::OK();
 | 
				
			||||||
 | 
					      downcast_call(*slice_obj,
 | 
				
			||||||
 | 
					                    td::overloaded(
 | 
				
			||||||
 | 
					                        [&](const ton_api::liteserver_descV2_sliceSimple& s) {
 | 
				
			||||||
 | 
					                          slice.unlimited = true;
 | 
				
			||||||
 | 
					                          slice.shards_from.push_back({ShardIdFull{masterchainId}, 0, 0, 0});
 | 
				
			||||||
 | 
					                          for (const auto& shard_obj : s.shards_) {
 | 
				
			||||||
 | 
					                            ShardIdFull shard_id = create_shard_id(shard_obj);
 | 
				
			||||||
 | 
					                            if (!shard_id.is_valid_ext()) {
 | 
				
			||||||
 | 
					                              S = td::Status::Error(PSTRING() << "invalid shard id " << shard_id.to_str());
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (!shard_id.is_masterchain()) {
 | 
				
			||||||
 | 
					                              slice.shards_from.push_back({shard_id, 0, 0, 0});
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        [&](const ton_api::liteserver_descV2_sliceTimed& s) {
 | 
				
			||||||
 | 
					                          auto parse_shards =
 | 
				
			||||||
 | 
					                              [](const std::vector<tl_object_ptr<ton_api::liteserver_descV2_shardInfo>>& shard_objs,
 | 
				
			||||||
 | 
					                                 std::vector<ShardInfo>& shards) -> td::Status {
 | 
				
			||||||
 | 
					                            if (shard_objs.empty()) {
 | 
				
			||||||
 | 
					                              return td::Status::OK();
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            size_t i = 0;
 | 
				
			||||||
 | 
					                            int mc_idx = -1;
 | 
				
			||||||
 | 
					                            for (const auto& shard_obj : shard_objs) {
 | 
				
			||||||
 | 
					                              ShardIdFull shard_id = create_shard_id(shard_obj->shard_id_);
 | 
				
			||||||
 | 
					                              if (!shard_id.is_valid_ext()) {
 | 
				
			||||||
 | 
					                                return td::Status::Error(PSTRING() << "invalid shard id " << shard_id.to_str());
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                              if (shard_id.is_masterchain()) {
 | 
				
			||||||
 | 
					                                shard_id = ShardIdFull{masterchainId};
 | 
				
			||||||
 | 
					                                if (mc_idx != -1) {
 | 
				
			||||||
 | 
					                                  return td::Status::Error("duplicate masterchain shard in sliceTimed");
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                mc_idx = (int)i;
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                              shards.push_back({shard_id, (BlockSeqno)shard_obj->seqno_, (UnixTime)shard_obj->utime_,
 | 
				
			||||||
 | 
					                                                (LogicalTime)shard_obj->lt_});
 | 
				
			||||||
 | 
					                              ++i;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (mc_idx == -1) {
 | 
				
			||||||
 | 
					                              return td::Status::Error("no masterchain shard in sliceTimed");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            std::swap(shards[0], shards[mc_idx]);
 | 
				
			||||||
 | 
					                            return td::Status::OK();
 | 
				
			||||||
 | 
					                          };
 | 
				
			||||||
 | 
					                          S = parse_shards(s.shards_from_, slice.shards_from);
 | 
				
			||||||
 | 
					                          if (S.is_ok()) {
 | 
				
			||||||
 | 
					                            S = parse_shards(s.shards_to_, slice.shards_to);
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                          if (S.is_ok() && slice.shards_from.empty() && slice.shards_to.empty()) {
 | 
				
			||||||
 | 
					                            S = td::Status::Error("shards_from and shards_to are both empty");
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                        }));
 | 
				
			||||||
 | 
					      TRY_STATUS(std::move(S));
 | 
				
			||||||
 | 
					      server.slices.push_back(slice);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    servers.push_back(std::move(server));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return servers;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace liteclient
 | 
				
			||||||
							
								
								
									
										89
									
								
								lite-client/query-utils.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								lite-client/query-utils.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    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 "ton/ton-types.h"
 | 
				
			||||||
 | 
					#include "auto/tl/lite_api.h"
 | 
				
			||||||
 | 
					#include "td/utils/port/IPAddress.h"
 | 
				
			||||||
 | 
					#include "adnl/adnl-node-id.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace liteclient {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QueryInfo {
 | 
				
			||||||
 | 
					  enum Type { t_simple, t_seqno, t_utime, t_lt, t_mc_seqno };
 | 
				
			||||||
 | 
					  int query_id = 0;
 | 
				
			||||||
 | 
					  ton::ShardIdFull shard_id{ton::masterchainId};
 | 
				
			||||||
 | 
					  Type type = t_simple;
 | 
				
			||||||
 | 
					  td::uint64 value = 0;
 | 
				
			||||||
 | 
					  /* Query types and examples:
 | 
				
			||||||
 | 
					   * t_simple - query to the recent blocks in a shard, or general info. value = 0.
 | 
				
			||||||
 | 
					   *   getTime, getMasterchainInfo (shard_id = masterchain)
 | 
				
			||||||
 | 
					   *   sendMessage
 | 
				
			||||||
 | 
					   *   getAccountState, runSmcMethod - when no block is given
 | 
				
			||||||
 | 
					   * t_seqno - query to block with seqno in a shard. value = seqno.
 | 
				
			||||||
 | 
					   *   lookupBlock by seqno
 | 
				
			||||||
 | 
					   *   getBlock, getBlockHeader
 | 
				
			||||||
 | 
					   *   getAccountState, runSmcMethod  - when shard block is given
 | 
				
			||||||
 | 
					   * t_utime - query to a block with given unixtime in a shard. value = utime.
 | 
				
			||||||
 | 
					   *   lookupBlock by utime
 | 
				
			||||||
 | 
					   * t_lt - query to a block with given lt in a shard. value = lt.
 | 
				
			||||||
 | 
					   *   lookupBlock by lt
 | 
				
			||||||
 | 
					   *   getTransactions
 | 
				
			||||||
 | 
					   * t_mc_seqno - query to a block in a shard, masterchain seqno is given. value = mc_seqno.
 | 
				
			||||||
 | 
					   *   getAccountState, runSmcMethod - when mc block is given
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string to_str() const;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QueryInfo get_query_info(td::Slice data);
 | 
				
			||||||
 | 
					QueryInfo get_query_info(const ton::lite_api::Function& f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LiteServerConfig {
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  struct ShardInfo {
 | 
				
			||||||
 | 
					    ton::ShardIdFull shard_id;
 | 
				
			||||||
 | 
					    ton::BlockSeqno seqno;
 | 
				
			||||||
 | 
					    ton::UnixTime utime;
 | 
				
			||||||
 | 
					    ton::LogicalTime lt;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct Slice {
 | 
				
			||||||
 | 
					    std::vector<ShardInfo> shards_from, shards_to;
 | 
				
			||||||
 | 
					    bool unlimited = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool accepts_query(const QueryInfo& query_info) const;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool is_full = false;
 | 
				
			||||||
 | 
					  std::vector<Slice> slices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  ton::adnl::AdnlNodeIdFull adnl_id;
 | 
				
			||||||
 | 
					  td::IPAddress addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LiteServerConfig() = default;
 | 
				
			||||||
 | 
					  LiteServerConfig(ton::adnl::AdnlNodeIdFull adnl_id, td::IPAddress addr)
 | 
				
			||||||
 | 
					      : is_full(true), adnl_id(adnl_id), addr(addr) {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool accepts_query(const QueryInfo& query_info) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static td::Result<std::vector<LiteServerConfig>> parse_global_config(
 | 
				
			||||||
 | 
					      const ton::ton_api::liteclient_config_global& config);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace liteclient
 | 
				
			||||||
| 
						 | 
					@ -148,6 +148,39 @@ td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>>
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					td::Result<tl_object_ptr<std::enable_if_t<std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data,
 | 
				
			||||||
 | 
					                                                                                                bool boxed) {
 | 
				
			||||||
 | 
					  td::TlParser p(data);
 | 
				
			||||||
 | 
					  tl_object_ptr<T> R;
 | 
				
			||||||
 | 
					  if (boxed) {
 | 
				
			||||||
 | 
					    R = TlFetchBoxed<TlFetchObject<T>, T::ID>::parse(p);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    R = move_tl_object_as<T>(T::fetch(p));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (p.get_status().is_ok()) {
 | 
				
			||||||
 | 
					    data.remove_prefix(data.size() - p.get_left_len());
 | 
				
			||||||
 | 
					    return std::move(R);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return p.get_status();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data,
 | 
				
			||||||
 | 
					                                                                                                 bool boxed) {
 | 
				
			||||||
 | 
					  CHECK(boxed);
 | 
				
			||||||
 | 
					  td::TlParser p(data);
 | 
				
			||||||
 | 
					  tl_object_ptr<T> R;
 | 
				
			||||||
 | 
					  R = move_tl_object_as<T>(T::fetch(p));
 | 
				
			||||||
 | 
					  if (p.get_status().is_ok()) {
 | 
				
			||||||
 | 
					    data.remove_prefix(data.size() - p.get_left_len());
 | 
				
			||||||
 | 
					    return std::move(R);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return p.get_status();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class T>
 | 
					template <class T>
 | 
				
			||||||
[[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) {
 | 
					[[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) {
 | 
				
			||||||
  auto B = serialize_tl_object(obj, true);
 | 
					  auto B = serialize_tl_object(obj, true);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -588,8 +588,12 @@ dummyworkchain0.config.global zero_state_hash:int256 = dummyworkchain0.config.Gl
 | 
				
			||||||
validator.config.global zero_state:tonNode.blockIdExt init_block:tonNode.blockIdExt hardforks:(vector tonNode.blockIdExt) = validator.config.Global;
 | 
					validator.config.global zero_state:tonNode.blockIdExt init_block:tonNode.blockIdExt hardforks:(vector tonNode.blockIdExt) = validator.config.Global;
 | 
				
			||||||
config.global adnl:adnl.config.global dht:dht.config.Global validator:validator.config.global = config.Global;
 | 
					config.global adnl:adnl.config.global dht:dht.config.Global validator:validator.config.global = config.Global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					liteserver.descV2.sliceSimple shards:(vector tonNode.shardId) = liteserver.descV2.Slice;
 | 
				
			||||||
 | 
					liteserver.descV2.shardInfo shard_id:tonNode.shardId seqno:int utime:int lt:long = liteserver.descV2.ShardInfo;
 | 
				
			||||||
 | 
					liteserver.descV2.sliceTimed shards_from:(vector liteserver.descV2.shardInfo) shards_to:(vector liteserver.descV2.shardInfo) = liteserver.descV2.Slice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
liteserver.desc id:PublicKey ip:int port:int = liteserver.Desc;
 | 
					liteserver.desc id:PublicKey ip:int port:int = liteserver.Desc;
 | 
				
			||||||
liteserver.descV2 id:PublicKey ip:int port:int shards:(vector tonNode.shardId) = liteserver.DescV2;
 | 
					liteserver.descV2 id:PublicKey ip:int port:int slices:(vector liteserver.descV2.Slice) = liteserver.DescV2;
 | 
				
			||||||
liteclient.config.global liteservers:(vector liteserver.desc) liteservers_v2:(vector liteserver.descV2) validator:validator.config.global = liteclient.config.Global;
 | 
					liteclient.config.global liteservers:(vector liteserver.desc) liteservers_v2:(vector liteserver.descV2) validator:validator.config.global = liteclient.config.Global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
engine.adnl id:int256 category:int = engine.Adnl;
 | 
					engine.adnl id:int256 category:int = engine.Adnl;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -190,7 +190,7 @@ smc.libraryQueryExt.one hash:int256 = smc.LibraryQueryExt;
 | 
				
			||||||
smc.libraryQueryExt.scanBoc boc:bytes max_libs:int32 = smc.LibraryQueryExt;
 | 
					smc.libraryQueryExt.scanBoc boc:bytes max_libs:int32 = smc.LibraryQueryExt;
 | 
				
			||||||
smc.libraryResultExt dict_boc:bytes libs_ok:(vector int256) libs_not_found:(vector int256) = smc.LibraryResultExt;
 | 
					smc.libraryResultExt dict_boc:bytes libs_ok:(vector int256) libs_not_found:(vector int256) = smc.LibraryResultExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
updateSendLiteServerQuery id:int64 data:bytes workchain:int32 shard:int64 = Update;
 | 
					updateSendLiteServerQuery id:int64 data:bytes = Update;
 | 
				
			||||||
updateSyncState sync_state:SyncState = Update;
 | 
					updateSyncState sync_state:SyncState = Update;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//@class LogStream @description Describes a stream to which tonlib internal log is written
 | 
					//@class LogStream @description Describes a stream to which tonlib internal log is written
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
#include "Config.h"
 | 
					#include "Config.h"
 | 
				
			||||||
#include "adnl/adnl-node-id.hpp"
 | 
					#include "adnl/adnl-node-id.hpp"
 | 
				
			||||||
#include "td/utils/JsonBuilder.h"
 | 
					#include "td/utils/JsonBuilder.h"
 | 
				
			||||||
 | 
					#include "auto/tl/ton_api_json.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace tonlib {
 | 
					namespace tonlib {
 | 
				
			||||||
td::Result<ton::BlockIdExt> parse_block_id_ext(td::JsonObject &obj) {
 | 
					td::Result<ton::BlockIdExt> parse_block_id_ext(td::JsonObject &obj) {
 | 
				
			||||||
| 
						 | 
					@ -65,67 +66,11 @@ td::Result<Config> Config::parse(std::string str) {
 | 
				
			||||||
  if (json.type() != td::JsonValue::Type::Object) {
 | 
					  if (json.type() != td::JsonValue::Type::Object) {
 | 
				
			||||||
    return td::Status::Error("Invalid config (1)");
 | 
					    return td::Status::Error("Invalid config (1)");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  td::JsonArray empty_array;
 | 
					 | 
				
			||||||
  TRY_RESULT(lite_servers_obj,
 | 
					 | 
				
			||||||
             td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, true));
 | 
					 | 
				
			||||||
  auto &lite_servers =
 | 
					 | 
				
			||||||
      lite_servers_obj.type() == td::JsonValue::Type::Array ? lite_servers_obj.get_array() : empty_array;
 | 
					 | 
				
			||||||
  TRY_RESULT(lite_servers_v2_obj,
 | 
					 | 
				
			||||||
             td::get_json_object_field(json.get_object(), "liteservers_v2", td::JsonValue::Type::Array, true));
 | 
					 | 
				
			||||||
  auto &lite_servers_v2 =
 | 
					 | 
				
			||||||
      lite_servers_v2_obj.type() == td::JsonValue::Type::Array ? lite_servers_v2_obj.get_array() : empty_array;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  auto parse_desc = [&](td::JsonValue &value) -> td::Result<Config::LiteServer> {
 | 
					 | 
				
			||||||
    if (value.type() != td::JsonValue::Type::Object) {
 | 
					 | 
				
			||||||
      return td::Status::Error("Invalid config (2)");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    auto &object = value.get_object();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    TRY_RESULT(ip, td::get_json_object_long_field(object, "ip", false));
 | 
					 | 
				
			||||||
    TRY_RESULT(port, td::get_json_object_int_field(object, "port", false));
 | 
					 | 
				
			||||||
    Config::LiteServer server;
 | 
					 | 
				
			||||||
    TRY_STATUS(server.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast<td::int32>(ip)), port));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false));
 | 
					 | 
				
			||||||
    auto &id = id_obj.get_object();
 | 
					 | 
				
			||||||
    TRY_RESULT(id_type, td::get_json_object_string_field(id, "@type", false));
 | 
					 | 
				
			||||||
    if (id_type != "pub.ed25519") {
 | 
					 | 
				
			||||||
      return td::Status::Error("Invalid config (3)");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    TRY_RESULT(key_base64, td::get_json_object_string_field(id, "key", false));
 | 
					 | 
				
			||||||
    TRY_RESULT(key, td::base64_decode(key_base64));
 | 
					 | 
				
			||||||
    if (key.size() != 32) {
 | 
					 | 
				
			||||||
      return td::Status::Error("Invalid config (4)");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    server.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
 | 
					 | 
				
			||||||
    return server;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Config res;
 | 
					  Config res;
 | 
				
			||||||
  for (auto &value : lite_servers) {
 | 
					  ton::ton_api::liteclient_config_global conf;
 | 
				
			||||||
    TRY_RESULT(server, parse_desc(value));
 | 
					  TRY_STATUS(ton::ton_api::from_json(conf, json.get_object()));
 | 
				
			||||||
    res.lite_servers.push_back(std::move(server));
 | 
					  TRY_RESULT_ASSIGN(res.lite_servers, liteclient::LiteServerConfig::parse_global_config(conf));
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  for (auto &value : lite_servers_v2) {
 | 
					 | 
				
			||||||
    TRY_RESULT(server, parse_desc(value));
 | 
					 | 
				
			||||||
    server.is_full = false;
 | 
					 | 
				
			||||||
    TRY_RESULT(shards_obj, td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false));
 | 
					 | 
				
			||||||
    for (auto &shard : shards_obj.get_array()) {
 | 
					 | 
				
			||||||
      if (shard.type() != td::JsonValue::Type::Object) {
 | 
					 | 
				
			||||||
        return td::Status::Error("Invalid config (5)");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      auto &shard_obj = shard.get_object();
 | 
					 | 
				
			||||||
      TRY_RESULT(workchain, td::get_json_object_int_field(shard_obj, "workchain", false));
 | 
					 | 
				
			||||||
      TRY_RESULT(shard_id, td::get_json_object_long_field(shard_obj, "shard", false));
 | 
					 | 
				
			||||||
      if (shard_id == 0) {
 | 
					 | 
				
			||||||
        return td::Status::Error("Invalid config (6)");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      server.shards.emplace_back(workchain, shard_id);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res.lite_servers.push_back(std::move(server));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TRY_RESULT(validator_obj,
 | 
					  TRY_RESULT(validator_obj,
 | 
				
			||||||
             td::get_json_object_field(json.get_object(), "validator", td::JsonValue::Type::Object, false));
 | 
					             td::get_json_object_field(json.get_object(), "validator", td::JsonValue::Type::Object, false));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,11 +24,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace tonlib {
 | 
					namespace tonlib {
 | 
				
			||||||
struct Config {
 | 
					struct Config {
 | 
				
			||||||
  using LiteServer = liteclient::ExtClient::LiteServer;
 | 
					 | 
				
			||||||
  ton::BlockIdExt zero_state_id;
 | 
					  ton::BlockIdExt zero_state_id;
 | 
				
			||||||
  ton::BlockIdExt init_block_id;
 | 
					  ton::BlockIdExt init_block_id;
 | 
				
			||||||
  std::vector<ton::BlockIdExt> hardforks;
 | 
					  std::vector<ton::BlockIdExt> hardforks;
 | 
				
			||||||
  std::vector<LiteServer> lite_servers;
 | 
					  std::vector<liteclient::LiteServerConfig> lite_servers;
 | 
				
			||||||
  std::string name;
 | 
					  std::string name;
 | 
				
			||||||
  static td::Result<Config> parse(std::string str);
 | 
					  static td::Result<Config> parse(std::string str);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
 | 
				
			||||||
  td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
 | 
					  td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) {
 | 
					void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
  auto query_id = queries_.create(std::move(promise));
 | 
					  auto query_id = queries_.create(std::move(promise));
 | 
				
			||||||
  td::Promise<td::BufferSlice> P = [query_id, self = this,
 | 
					  td::Promise<td::BufferSlice> P = [query_id, self = this,
 | 
				
			||||||
                                    actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) {
 | 
					                                    actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) {
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,6 @@ void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td
 | 
				
			||||||
    return P.set_error(TonlibError::NoLiteServers());
 | 
					    return P.set_error(TonlibError::NoLiteServers());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::send_query, "query", std::move(query),
 | 
					  td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::send_query, "query", std::move(query),
 | 
				
			||||||
                          shard, td::Timestamp::in(10.0), std::move(P));
 | 
					                          td::Timestamp::in(10.0), std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}  // namespace tonlib
 | 
					}  // namespace tonlib
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,6 @@
 | 
				
			||||||
#include "lite-client/ext-client.h"
 | 
					#include "lite-client/ext-client.h"
 | 
				
			||||||
#include "TonlibError.h"
 | 
					#include "TonlibError.h"
 | 
				
			||||||
#include "utils.h"
 | 
					#include "utils.h"
 | 
				
			||||||
#include "lite-client/QueryTraits.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace tonlib {
 | 
					namespace tonlib {
 | 
				
			||||||
class LastBlock;
 | 
					class LastBlock;
 | 
				
			||||||
| 
						 | 
					@ -65,7 +64,6 @@ class ExtClient {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <class QueryT>
 | 
					  template <class QueryT>
 | 
				
			||||||
  void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise, td::int32 seq_no = -1) {
 | 
					  void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise, td::int32 seq_no = -1) {
 | 
				
			||||||
    ton::ShardIdFull shard = liteclient::QueryTraits<QueryT>::get_shard(query);
 | 
					 | 
				
			||||||
    auto raw_query = ton::serialize_tl_object(&query, true);
 | 
					    auto raw_query = ton::serialize_tl_object(&query, true);
 | 
				
			||||||
    td::uint32 tag = td::Random::fast_uint32();
 | 
					    td::uint32 tag = td::Random::fast_uint32();
 | 
				
			||||||
    VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query);
 | 
					    VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query);
 | 
				
			||||||
| 
						 | 
					@ -79,7 +77,7 @@ class ExtClient {
 | 
				
			||||||
        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
 | 
					        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    send_raw_query(
 | 
					    send_raw_query(
 | 
				
			||||||
        std::move(liteserver_query), shard, [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable {
 | 
					        std::move(liteserver_query), [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
          auto res = [&]() -> td::Result<typename QueryT::ReturnType> {
 | 
					          auto res = [&]() -> td::Result<typename QueryT::ReturnType> {
 | 
				
			||||||
            TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork());
 | 
					            TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork());
 | 
				
			||||||
            auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
 | 
					            auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
 | 
				
			||||||
| 
						 | 
					@ -99,7 +97,7 @@ class ExtClient {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void force_change_liteserver() {
 | 
					  void force_change_liteserver() {
 | 
				
			||||||
    if (!client_.adnl_ext_client_.empty()) {
 | 
					    if (!client_.adnl_ext_client_.empty()) {
 | 
				
			||||||
      td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::force_change_liteserver);
 | 
					      td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::reset_servers);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,6 +107,6 @@ class ExtClient {
 | 
				
			||||||
  td::Container<td::Promise<LastBlockState>> last_block_queries_;
 | 
					  td::Container<td::Promise<LastBlockState>> last_block_queries_;
 | 
				
			||||||
  td::Container<td::Promise<LastConfigState>> last_config_queries_;
 | 
					  td::Container<td::Promise<LastConfigState>> last_config_queries_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise);
 | 
					  void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}  // namespace tonlib
 | 
					}  // namespace tonlib
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,14 +28,11 @@ class ExtClientOutboundImpl : public ExtClientOutbound {
 | 
				
			||||||
  ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
 | 
					  ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
					  void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
 | 
				
			||||||
                  td::Promise<td::BufferSlice> promise) override {
 | 
					                  td::Promise<td::BufferSlice> promise) override {
 | 
				
			||||||
    auto query_id = next_query_id_++;
 | 
					    auto query_id = next_query_id_++;
 | 
				
			||||||
    queries_[query_id] = std::move(promise);
 | 
					    queries_[query_id] = std::move(promise);
 | 
				
			||||||
    callback_->request(query_id, data.as_slice().str(), shard);
 | 
					    callback_->request(query_id, data.as_slice().str());
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void force_change_liteserver() override {
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
 | 
					  void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,8 @@ class ExtClientOutbound : public liteclient::ExtClient {
 | 
				
			||||||
   public:
 | 
					   public:
 | 
				
			||||||
    virtual ~Callback() {
 | 
					    virtual ~Callback() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    virtual void request(td::int64 id, std::string data, ton::ShardIdFull shard) = 0;
 | 
					    virtual void request(td::int64 id, std::string data) = 0;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					 | 
				
			||||||
  virtual void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) = 0;
 | 
					  virtual void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) = 0;
 | 
				
			||||||
  static td::actor::ActorOwn<ExtClientOutbound> create(td::unique_ptr<Callback> callback);
 | 
					  static td::actor::ActorOwn<ExtClientOutbound> create(td::unique_ptr<Callback> callback);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2078,9 +2078,8 @@ ExtClientRef TonlibClient::get_client_ref() {
 | 
				
			||||||
  return ref;
 | 
					  return ref;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TonlibClient::proxy_request(td::int64 query_id, std::string data, ton::ShardIdFull shard) {
 | 
					void TonlibClient::proxy_request(td::int64 query_id, std::string data) {
 | 
				
			||||||
  on_update(
 | 
					  on_update(tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data));
 | 
				
			||||||
      tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data, shard.workchain, shard.shard));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TonlibClient::init_ext_client() {
 | 
					void TonlibClient::init_ext_client() {
 | 
				
			||||||
| 
						 | 
					@ -2091,9 +2090,9 @@ void TonlibClient::init_ext_client() {
 | 
				
			||||||
          : parent_(std::move(parent)), config_generation_(config_generation) {
 | 
					          : parent_(std::move(parent)), config_generation_(config_generation) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      void request(td::int64 id, std::string data, ton::ShardIdFull shard) override {
 | 
					      void request(td::int64 id, std::string data) override {
 | 
				
			||||||
        send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), std::move(data),
 | 
					        send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff),
 | 
				
			||||||
                     shard);
 | 
					                     std::move(data));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     private:
 | 
					     private:
 | 
				
			||||||
| 
						 | 
					@ -2106,17 +2105,8 @@ void TonlibClient::init_ext_client() {
 | 
				
			||||||
    ext_client_outbound_ = client.get();
 | 
					    ext_client_outbound_ = client.get();
 | 
				
			||||||
    raw_client_ = std::move(client);
 | 
					    raw_client_ = std::move(client);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    class Callback : public liteclient::ExtClient::Callback {
 | 
					 | 
				
			||||||
     public:
 | 
					 | 
				
			||||||
      explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     private:
 | 
					 | 
				
			||||||
      td::actor::ActorShared<> parent_;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    ext_client_outbound_ = {};
 | 
					    ext_client_outbound_ = {};
 | 
				
			||||||
    ref_cnt_++;
 | 
					    raw_client_ = liteclient::ExtClient::create(config_.lite_servers, nullptr);
 | 
				
			||||||
    raw_client_ = liteclient::ExtClient::create(config_.lite_servers, td::make_unique<Callback>(td::actor::actor_shared()));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4491,8 +4481,8 @@ void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& v
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  for (unsigned int i = 0; i < loaded_cell.data_cell->get_refs_cnt(); i++) {
 | 
					  for (unsigned int i=0; i<loaded_cell.data_cell->get_refs_cnt(); i++) {
 | 
				
			||||||
    deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1);
 | 
					    deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1, max_libs);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -401,7 +401,7 @@ class TonlibClient : public td::actor::Actor {
 | 
				
			||||||
  td::Status do_request(const tonlib_api::getConfigAll& request,
 | 
					  td::Status do_request(const tonlib_api::getConfigAll& request,
 | 
				
			||||||
                        td::Promise<object_ptr<tonlib_api::configInfo>>&& promise);
 | 
					                        td::Promise<object_ptr<tonlib_api::configInfo>>&& promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void proxy_request(td::int64 query_id, std::string data, ton::ShardIdFull shard);
 | 
					  void proxy_request(td::int64 query_id, std::string data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void load_libs_from_disk();
 | 
					  void load_libs_from_disk();
 | 
				
			||||||
  void store_libs_to_disk();
 | 
					  void store_libs_to_disk();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1541,7 +1541,7 @@ class TonlibCli : public td::actor::Actor {
 | 
				
			||||||
          CHECK(!raw_client_.empty());
 | 
					          CHECK(!raw_client_.empty());
 | 
				
			||||||
          snd_bytes_ += update->data_.size();
 | 
					          snd_bytes_ += update->data_.size();
 | 
				
			||||||
          send_closure(raw_client_, &liteclient::ExtClient::send_query, "query", td::BufferSlice(update->data_),
 | 
					          send_closure(raw_client_, &liteclient::ExtClient::send_query, "query", td::BufferSlice(update->data_),
 | 
				
			||||||
                       ton::ShardIdFull(update->workchain_, update->shard_), td::Timestamp::in(5),
 | 
					                       td::Timestamp::in(5),
 | 
				
			||||||
                       [actor_id = actor_id(this), id = update->id_](td::Result<td::BufferSlice> res) {
 | 
					                       [actor_id = actor_id(this), id = update->id_](td::Result<td::BufferSlice> res) {
 | 
				
			||||||
                         send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res));
 | 
					                         send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res));
 | 
				
			||||||
                       });
 | 
					                       });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,50 +29,71 @@
 | 
				
			||||||
#include "td/utils/OptionParser.h"
 | 
					#include "td/utils/OptionParser.h"
 | 
				
			||||||
#include "td/utils/port/path.h"
 | 
					#include "td/utils/port/path.h"
 | 
				
			||||||
#include "td/utils/port/signals.h"
 | 
					#include "td/utils/port/signals.h"
 | 
				
			||||||
#include "td/utils/port/user.h"
 | 
					 | 
				
			||||||
#include "td/utils/port/IPAddress.h"
 | 
					#include "td/utils/port/IPAddress.h"
 | 
				
			||||||
#include "td/utils/Random.h"
 | 
					#include "td/utils/Random.h"
 | 
				
			||||||
#include "td/utils/FileLog.h"
 | 
					#include "td/utils/FileLog.h"
 | 
				
			||||||
#include "git.h"
 | 
					#include "git.h"
 | 
				
			||||||
#include "auto/tl/ton_api.h"
 | 
					#include "auto/tl/ton_api.h"
 | 
				
			||||||
#include "auto/tl/lite_api.h"
 | 
					#include "auto/tl/lite_api.h"
 | 
				
			||||||
#include "auto/tl/lite_api.hpp"
 | 
					 | 
				
			||||||
#include "tl-utils/lite-utils.hpp"
 | 
					#include "tl-utils/lite-utils.hpp"
 | 
				
			||||||
#include "ton/lite-tl.hpp"
 | 
					 | 
				
			||||||
#include "auto/tl/ton_api_json.h"
 | 
					#include "auto/tl/ton_api_json.h"
 | 
				
			||||||
#include "adnl/adnl.h"
 | 
					#include "adnl/adnl.h"
 | 
				
			||||||
#include "lite-client/QueryTraits.h"
 | 
					 | 
				
			||||||
#include "lite-client/ext-client.h"
 | 
					#include "lite-client/ext-client.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if TD_DARWIN || TD_LINUX
 | 
					#if TD_DARWIN || TD_LINUX
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace ton;
 | 
					using namespace ton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProxyLiteserver : public td::actor::Actor {
 | 
					class ProxyLiteserver : public td::actor::Actor {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  ProxyLiteserver(std::string global_config, std::string db_root, td::uint16 port)
 | 
					  ProxyLiteserver(std::string global_config, std::string db_root, td::uint16 port, PublicKeyHash public_key_hash)
 | 
				
			||||||
      : global_config_(std::move(global_config)), db_root_(std::move(db_root)), port_(port) {
 | 
					      : global_config_(std::move(global_config))
 | 
				
			||||||
 | 
					      , db_root_(std::move(db_root))
 | 
				
			||||||
 | 
					      , port_(port)
 | 
				
			||||||
 | 
					      , public_key_hash_(public_key_hash) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void start_up() override {
 | 
					  void start_up() override {
 | 
				
			||||||
    LOG_CHECK(db_root_ != "") << "db root is not set";
 | 
					    LOG_CHECK(!db_root_.empty()) << "db root is not set";
 | 
				
			||||||
    td::mkdir(db_root_).ensure();
 | 
					    td::mkdir(db_root_).ensure();
 | 
				
			||||||
    db_root_ = td::realpath(db_root_).move_as_ok();
 | 
					    db_root_ = td::realpath(db_root_).move_as_ok();
 | 
				
			||||||
    keyring_ = keyring::Keyring::create(db_root_ + "/keyring");
 | 
					    keyring_ = keyring::Keyring::create(db_root_ + "/keyring");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (public_key_hash_.is_zero()) {
 | 
				
			||||||
 | 
					      id_ = {};
 | 
				
			||||||
 | 
					      run();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      td::actor::send_closure(keyring_, &keyring::Keyring::get_public_key, public_key_hash_,
 | 
				
			||||||
 | 
					                              [SelfId = actor_id(this)](td::Result<PublicKey> R) mutable {
 | 
				
			||||||
 | 
					                                if (R.is_error()) {
 | 
				
			||||||
 | 
					                                  LOG(FATAL) << "Failed to load public key: " << R.move_as_error();
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                td::actor::send_closure(SelfId, &ProxyLiteserver::got_public_key, R.move_as_ok());
 | 
				
			||||||
 | 
					                              });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void got_public_key(PublicKey pub) {
 | 
				
			||||||
 | 
					    id_ = adnl::AdnlNodeIdFull{pub};
 | 
				
			||||||
 | 
					    run();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void run() {
 | 
				
			||||||
    td::Status S = prepare_local_config();
 | 
					    td::Status S = prepare_local_config();
 | 
				
			||||||
    if (S.is_error()) {
 | 
					    if (S.is_error()) {
 | 
				
			||||||
      LOG(FATAL) << "Local config error: " << S;
 | 
					      LOG(FATAL) << "Local config error: " << S;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    S = create_ext_client();
 | 
					    S = parse_global_config();
 | 
				
			||||||
    if (S.is_error()) {
 | 
					    if (S.is_error()) {
 | 
				
			||||||
      LOG(FATAL) << S;
 | 
					      LOG(FATAL) << S;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    run_clients();
 | 
				
			||||||
    create_ext_server();
 | 
					    create_ext_server();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,73 +103,123 @@ class ProxyLiteserver : public td::actor::Actor {
 | 
				
			||||||
      auto conf_data = r_conf_data.move_as_ok();
 | 
					      auto conf_data = r_conf_data.move_as_ok();
 | 
				
			||||||
      TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: ");
 | 
					      TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: ");
 | 
				
			||||||
      TRY_STATUS_PREFIX(ton_api::from_json(*config_, conf_json.get_object()), "json does not fit TL scheme: ");
 | 
					      TRY_STATUS_PREFIX(ton_api::from_json(*config_, conf_json.get_object()), "json does not fit TL scheme: ");
 | 
				
			||||||
      TRY_RESULT_PREFIX_ASSIGN(port_, td::narrow_cast_safe<td::uint16>(config_->port_), "invalid port: ");
 | 
					      TRY_RESULT_PREFIX(cfg_port, td::narrow_cast_safe<td::uint16>(config_->port_), "invalid port: ");
 | 
				
			||||||
      TRY_RESULT_PREFIX_ASSIGN(id_, adnl::AdnlNodeIdFull::create(config_->id_), "invalid id: ");
 | 
					      TRY_RESULT_PREFIX(cfg_id, adnl::AdnlNodeIdFull::create(config_->id_), "invalid id: ");
 | 
				
			||||||
 | 
					      bool rewrite_config = false;
 | 
				
			||||||
 | 
					      if (port_ == 0) {
 | 
				
			||||||
 | 
					        port_ = cfg_port;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        rewrite_config |= (port_ != cfg_port);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (id_.empty()) {
 | 
				
			||||||
 | 
					        id_ = std::move(cfg_id);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        rewrite_config |= (id_ != cfg_id);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!rewrite_config) {
 | 
				
			||||||
 | 
					        return td::Status::OK();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      LOG(WARNING) << "First launch, creating local config";
 | 
					      LOG(WARNING) << "First launch, creating local config";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (port_ == 0) {
 | 
					    if (port_ == 0) {
 | 
				
			||||||
      return td::Status::Error("port is not set");
 | 
					      return td::Status::Error("port is not set");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    config_->port_ = port_;
 | 
					    config_->port_ = port_;
 | 
				
			||||||
 | 
					    if (id_.empty()) {
 | 
				
			||||||
      auto pk = PrivateKey{privkeys::Ed25519::random()};
 | 
					      auto pk = PrivateKey{privkeys::Ed25519::random()};
 | 
				
			||||||
      id_ = adnl::AdnlNodeIdFull{pk.compute_public_key()};
 | 
					      id_ = adnl::AdnlNodeIdFull{pk.compute_public_key()};
 | 
				
			||||||
      config_->id_ = id_.tl();
 | 
					 | 
				
			||||||
      td::actor::send_closure(keyring_, &keyring::Keyring::add_key, std::move(pk), false, [](td::Result<td::Unit> R) {
 | 
					      td::actor::send_closure(keyring_, &keyring::Keyring::add_key, std::move(pk), false, [](td::Result<td::Unit> R) {
 | 
				
			||||||
        if (R.is_error()) {
 | 
					        if (R.is_error()) {
 | 
				
			||||||
          LOG(FATAL) << "Failed to store private key";
 | 
					          LOG(FATAL) << "Failed to store private key";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    config_->id_ = id_.tl();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto s = td::json_encode<std::string>(td::ToJson(*config_), true);
 | 
					    auto s = td::json_encode<std::string>(td::ToJson(*config_), true);
 | 
				
			||||||
    TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: ");
 | 
					    TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: ");
 | 
				
			||||||
    }
 | 
					    LOG(WARNING) << "Writing config.json";
 | 
				
			||||||
    return td::Status::OK();
 | 
					    return td::Status::OK();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::Status create_ext_client() {
 | 
					  td::Status parse_global_config() {
 | 
				
			||||||
    std::vector<liteclient::ExtClient::LiteServer> servers;
 | 
					 | 
				
			||||||
    TRY_RESULT_PREFIX(global_config_data, td::read_file(global_config_), "Failed to read global config: ");
 | 
					    TRY_RESULT_PREFIX(global_config_data, td::read_file(global_config_), "Failed to read global config: ");
 | 
				
			||||||
    TRY_RESULT_PREFIX(global_config_json, td::json_decode(global_config_data.as_slice()),
 | 
					    TRY_RESULT_PREFIX(global_config_json, td::json_decode(global_config_data.as_slice()),
 | 
				
			||||||
                      "Failed to parse global config: ");
 | 
					                      "Failed to parse global config: ");
 | 
				
			||||||
    ton::ton_api::liteclient_config_global gc;
 | 
					    ton_api::liteclient_config_global gc;
 | 
				
			||||||
    ton::ton_api::from_json(gc, global_config_json.get_object()).ensure();
 | 
					    TRY_STATUS_PREFIX(ton_api::from_json(gc, global_config_json.get_object()), "Failed to parse global config: ");
 | 
				
			||||||
 | 
					    TRY_RESULT_PREFIX(servers, liteclient::LiteServerConfig::parse_global_config(gc),
 | 
				
			||||||
    size_t size = gc.liteservers_.size() + gc.liteservers_v2_.size();
 | 
					                      "Falied to parse liteservers in global config: ");
 | 
				
			||||||
    if (size == 0) {
 | 
					    if (servers.empty()) {
 | 
				
			||||||
      return td::Status::Error("No liteservers in global config");
 | 
					      return td::Status::Error("No liteservers in global config");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    for (auto& s : servers) {
 | 
				
			||||||
    for (auto& s : gc.liteservers_) {
 | 
					      servers_.emplace_back();
 | 
				
			||||||
      td::IPAddress addr;
 | 
					      servers_.back().config = std::move(s);
 | 
				
			||||||
      addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure();
 | 
					 | 
				
			||||||
      liteclient::ExtClient::LiteServer serv;
 | 
					 | 
				
			||||||
      serv.address = addr;
 | 
					 | 
				
			||||||
      serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok();
 | 
					 | 
				
			||||||
      servers.push_back(std::move(serv));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    for (auto& s : gc.liteservers_v2_) {
 | 
					 | 
				
			||||||
      td::IPAddress addr;
 | 
					 | 
				
			||||||
      addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure();
 | 
					 | 
				
			||||||
      liteclient::ExtClient::LiteServer serv;
 | 
					 | 
				
			||||||
      serv.address = addr;
 | 
					 | 
				
			||||||
      serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok();
 | 
					 | 
				
			||||||
      serv.is_full = false;
 | 
					 | 
				
			||||||
      for (auto& shard : s->shards_) {
 | 
					 | 
				
			||||||
        serv.shards.emplace_back(shard->workchain_, (ton::ShardId)shard->shard_);
 | 
					 | 
				
			||||||
        CHECK(serv.shards.back().is_valid_ext());
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      servers.push_back(std::move(serv));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class Callback : public liteclient::ExtClient::Callback {};
 | 
					 | 
				
			||||||
    ext_client_ = liteclient::ExtClient::create(std::move(servers), td::make_unique<Callback>());
 | 
					 | 
				
			||||||
    return td::Status::OK();
 | 
					    return td::Status::OK();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void run_clients() {
 | 
				
			||||||
 | 
					    class Callback : public adnl::AdnlExtClient::Callback {
 | 
				
			||||||
 | 
					     public:
 | 
				
			||||||
 | 
					      explicit Callback(td::actor::ActorId<ProxyLiteserver> id, size_t idx) : id_(std::move(id)), idx_(idx) {
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void on_ready() override {
 | 
				
			||||||
 | 
					        td::actor::send_closure(id_, &ProxyLiteserver::on_client_status, idx_, true);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void on_stop_ready() override {
 | 
				
			||||||
 | 
					        td::actor::send_closure(id_, &ProxyLiteserver::on_client_status, idx_, false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     private:
 | 
				
			||||||
 | 
					      td::actor::ActorId<ProxyLiteserver> id_;
 | 
				
			||||||
 | 
					      size_t idx_;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
				
			||||||
 | 
					      Server& server = servers_[i];
 | 
				
			||||||
 | 
					      server.client = adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr,
 | 
				
			||||||
 | 
					                                                  std::make_unique<Callback>(actor_id(this), i));
 | 
				
			||||||
 | 
					      server.alive = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void on_client_status(size_t idx, bool ready) {
 | 
				
			||||||
 | 
					    Server& server = servers_[idx];
 | 
				
			||||||
 | 
					    if (server.alive == ready) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    server.alive = ready;
 | 
				
			||||||
 | 
					    LOG(WARNING) << (ready ? "Connected to" : "Disconnected from") << " server #" << idx << " ("
 | 
				
			||||||
 | 
					                 << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void create_ext_server() {
 | 
					  void create_ext_server() {
 | 
				
			||||||
    adnl_ = adnl::Adnl::create("", keyring_.get());
 | 
					    adnl_ = adnl::Adnl::create("", keyring_.get());
 | 
				
			||||||
    td::actor::send_closure(adnl_, &adnl::Adnl::add_id, id_, ton::adnl::AdnlAddressList{}, (td::uint8)255);
 | 
					    td::actor::send_closure(adnl_, &adnl::Adnl::add_id, id_, adnl::AdnlAddressList{}, (td::uint8)255);
 | 
				
			||||||
    td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server,
 | 
					
 | 
				
			||||||
                            std::vector<adnl::AdnlNodeIdShort>{id_.compute_short_id()}, std::vector<td::uint16>{port_},
 | 
					    class AdnlCallback : public adnl::Adnl::Callback {
 | 
				
			||||||
 | 
					     public:
 | 
				
			||||||
 | 
					      explicit AdnlCallback(td::actor::ActorId<ProxyLiteserver> id) : id_(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_, &ProxyLiteserver::receive_query, std::move(data), std::move(promise));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     private:
 | 
				
			||||||
 | 
					      td::actor::ActorId<ProxyLiteserver> id_;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, id_.compute_short_id(),
 | 
				
			||||||
 | 
					                            adnl::Adnl::int_to_bytestring(lite_api::liteServer_query::ID),
 | 
				
			||||||
 | 
					                            std::make_unique<AdnlCallback>(actor_id(this)));
 | 
				
			||||||
 | 
					    td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server, std::vector{id_.compute_short_id()},
 | 
				
			||||||
 | 
					                            std::vector{port_},
 | 
				
			||||||
                            [SelfId = actor_id(this)](td::Result<td::actor::ActorOwn<adnl::AdnlExtServer>> R) {
 | 
					                            [SelfId = actor_id(this)](td::Result<td::actor::ActorOwn<adnl::AdnlExtServer>> R) {
 | 
				
			||||||
                              R.ensure();
 | 
					                              R.ensure();
 | 
				
			||||||
                              td::actor::send_closure(SelfId, &ProxyLiteserver::created_ext_server, R.move_as_ok());
 | 
					                              td::actor::send_closure(SelfId, &ProxyLiteserver::created_ext_server, R.move_as_ok());
 | 
				
			||||||
| 
						 | 
					@ -158,93 +229,72 @@ class ProxyLiteserver : public td::actor::Actor {
 | 
				
			||||||
  void created_ext_server(td::actor::ActorOwn<adnl::AdnlExtServer> s) {
 | 
					  void created_ext_server(td::actor::ActorOwn<adnl::AdnlExtServer> s) {
 | 
				
			||||||
    ext_server_ = std::move(s);
 | 
					    ext_server_ = std::move(s);
 | 
				
			||||||
    LOG(WARNING) << "Started proxy liteserver on port " << port_;
 | 
					    LOG(WARNING) << "Started proxy liteserver on port " << port_;
 | 
				
			||||||
 | 
					    alarm();
 | 
				
			||||||
    class AdnlCallback : public adnl::Adnl::Callback {
 | 
					 | 
				
			||||||
     public:
 | 
					 | 
				
			||||||
      AdnlCallback(td::actor::ActorId<liteclient::ExtClient> client) : client_(client) {
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override {
 | 
					  td::Result<size_t> select_server(const liteclient::QueryInfo& query_info) {
 | 
				
			||||||
 | 
					    size_t best_idx = servers_.size();
 | 
				
			||||||
 | 
					    int cnt = 0;
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
				
			||||||
 | 
					      Server& server = servers_[i];
 | 
				
			||||||
 | 
					      if (!server.alive || !server.config.accepts_query(query_info)) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data,
 | 
					      ++cnt;
 | 
				
			||||||
                         td::Promise<td::BufferSlice> promise) override {
 | 
					      if (td::Random::fast(1, cnt) == 1) {
 | 
				
			||||||
        td::actor::create_actor<QueryWorker>("worker", client_, std::move(data), std::move(promise)).release();
 | 
					        best_idx = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (best_idx == servers_.size()) {
 | 
				
			||||||
 | 
					      return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return best_idx;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     private:
 | 
					  void receive_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
 | 
				
			||||||
      td::actor::ActorId<liteclient::ExtClient> client_;
 | 
					    liteclient::QueryInfo query_info = liteclient::get_query_info(data);
 | 
				
			||||||
    };
 | 
					    ++ls_stats_[query_info.query_id];
 | 
				
			||||||
    td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, id_.compute_short_id(),
 | 
					    promise = [promise = std::move(promise), query_info, timer = td::Timer()](td::Result<td::BufferSlice> R) mutable {
 | 
				
			||||||
                            adnl::Adnl::int_to_bytestring(lite_api::liteServer_query::ID),
 | 
					      if (R.is_ok()) {
 | 
				
			||||||
                            std::make_unique<AdnlCallback>(ext_client_.get()));
 | 
					        LOG(INFO) << "Query " << query_info.to_str() << ": OK, time=" << timer.elapsed()
 | 
				
			||||||
  }
 | 
					                  << ", response_size=" << R.ok().size();
 | 
				
			||||||
 | 
					        promise.set_value(R.move_as_ok());
 | 
				
			||||||
  class QueryWorker : public td::actor::Actor {
 | 
					 | 
				
			||||||
   public:
 | 
					 | 
				
			||||||
    QueryWorker(td::actor::ActorId<liteclient::ExtClient> client, td::BufferSlice data,
 | 
					 | 
				
			||||||
                td::Promise<td::BufferSlice> promise)
 | 
					 | 
				
			||||||
        : client_(std::move(client)), data_(std::move(data)), promise_(std::move(promise)) {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void start_up() override {
 | 
					 | 
				
			||||||
      auto data = data_.clone();
 | 
					 | 
				
			||||||
      auto F = fetch_tl_object<lite_api::liteServer_query>(data, true);
 | 
					 | 
				
			||||||
      if (F.is_ok()) {
 | 
					 | 
				
			||||||
        data = std::move(F.move_as_ok()->data_);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        auto G = fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true);
 | 
					 | 
				
			||||||
        if (G.is_error()) {
 | 
					 | 
				
			||||||
          fatal_error(G.move_as_error());
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      }
 | 
					      LOG(INFO) << "Query " << query_info.to_str() << ": " << R.error();
 | 
				
			||||||
      fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true).ignore();
 | 
					      promise.set_value(create_serialize_tl_object<lite_api::liteServer_error>(
 | 
				
			||||||
      auto F2 = fetch_tl_object<ton::lite_api::Function>(std::move(data), true);
 | 
					          R.error().code(), "Gateway error: " + R.error().message().str()));
 | 
				
			||||||
      if (F2.is_error()) {
 | 
					 | 
				
			||||||
        fatal_error(F2.move_as_error());
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      auto query = F2.move_as_ok();
 | 
					 | 
				
			||||||
      lite_api::downcast_call(*query, [&](auto& obj) { shard_ = liteclient::get_query_shard(obj); });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      LOG(INFO) << "Got query: shard=" << shard_.to_str() << " size=" << data_.size();
 | 
					 | 
				
			||||||
      td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "q", std::move(data_), shard_,
 | 
					 | 
				
			||||||
                              td::Timestamp::in(8.0), [SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
 | 
					 | 
				
			||||||
                                td::actor::send_closure(SelfId, &QueryWorker::got_result, std::move(R));
 | 
					 | 
				
			||||||
                              });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void got_result(td::Result<td::BufferSlice> R) {
 | 
					 | 
				
			||||||
      if (R.is_error()) {
 | 
					 | 
				
			||||||
        LOG(INFO) << "Query to shard=" << shard_.to_str() << ": " << R.error();
 | 
					 | 
				
			||||||
        promise_.set_value(create_serialize_tl_object<lite_api::liteServer_error>(
 | 
					 | 
				
			||||||
            R.error().code(), "gateway error: " + R.error().message().str()));
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        td::BufferSlice response = R.move_as_ok();
 | 
					 | 
				
			||||||
        LOG(INFO) << "Query to shard=" << shard_.to_str() << ": OK, size=" << response.size()
 | 
					 | 
				
			||||||
                  << " time=" << timer_.elapsed();
 | 
					 | 
				
			||||||
        promise_.set_value(std::move(response));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void fatal_error(td::Status S) {
 | 
					 | 
				
			||||||
      promise_.set_error(std::move(S));
 | 
					 | 
				
			||||||
      stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   private:
 | 
					 | 
				
			||||||
    td::actor::ActorId<liteclient::ExtClient> client_;
 | 
					 | 
				
			||||||
    td::BufferSlice data_;
 | 
					 | 
				
			||||||
    td::Promise<td::BufferSlice> promise_;
 | 
					 | 
				
			||||||
    td::Timer timer_ = {};
 | 
					 | 
				
			||||||
    ShardIdFull shard_;
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Server& server = servers_[server_idx];
 | 
				
			||||||
 | 
					    LOG(INFO) << "Sending query " << query_info.to_str() << ", size=" << data.size() << ", to server #" << server_idx
 | 
				
			||||||
 | 
					              << " (" << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")";
 | 
				
			||||||
 | 
					    td::actor::send_closure(server.client, &adnl::AdnlExtClient::send_query, "q", std::move(data),
 | 
				
			||||||
 | 
					                            td::Timestamp::in(8.0), std::move(promise));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void alarm() override {
 | 
				
			||||||
 | 
					    alarm_timestamp() = td::Timestamp::in(60.0);
 | 
				
			||||||
 | 
					    if (!ls_stats_.empty()) {
 | 
				
			||||||
 | 
					      td::StringBuilder sb;
 | 
				
			||||||
 | 
					      sb << "Liteserver stats (1 minute):";
 | 
				
			||||||
 | 
					      td::uint32 total = 0;
 | 
				
			||||||
 | 
					      for (const auto& p : ls_stats_) {
 | 
				
			||||||
 | 
					        sb << " " << lite_query_name_by_id(p.first) << ":" << p.second;
 | 
				
			||||||
 | 
					        total += p.second;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      sb << " TOTAL:" << total;
 | 
				
			||||||
 | 
					      LOG(WARNING) << sb.as_cslice();
 | 
				
			||||||
 | 
					      ls_stats_.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  std::string global_config_;
 | 
					  std::string global_config_;
 | 
				
			||||||
  std::string db_root_;
 | 
					  std::string db_root_;
 | 
				
			||||||
  td::uint16 port_;
 | 
					  td::uint16 port_;
 | 
				
			||||||
 | 
					  PublicKeyHash public_key_hash_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  tl_object_ptr<ton_api::proxyLiteserver_config> config_ = create_tl_object<ton_api::proxyLiteserver_config>();
 | 
					  tl_object_ptr<ton_api::proxyLiteserver_config> config_ = create_tl_object<ton_api::proxyLiteserver_config>();
 | 
				
			||||||
  adnl::AdnlNodeIdFull id_;
 | 
					  adnl::AdnlNodeIdFull id_;
 | 
				
			||||||
| 
						 | 
					@ -252,7 +302,15 @@ class ProxyLiteserver : public td::actor::Actor {
 | 
				
			||||||
  td::actor::ActorOwn<keyring::Keyring> keyring_;
 | 
					  td::actor::ActorOwn<keyring::Keyring> keyring_;
 | 
				
			||||||
  td::actor::ActorOwn<adnl::Adnl> adnl_;
 | 
					  td::actor::ActorOwn<adnl::Adnl> adnl_;
 | 
				
			||||||
  td::actor::ActorOwn<adnl::AdnlExtServer> ext_server_;
 | 
					  td::actor::ActorOwn<adnl::AdnlExtServer> ext_server_;
 | 
				
			||||||
  td::actor::ActorOwn<liteclient::ExtClient> ext_client_;
 | 
					
 | 
				
			||||||
 | 
					  struct Server {
 | 
				
			||||||
 | 
					    liteclient::LiteServerConfig config;
 | 
				
			||||||
 | 
					    td::actor::ActorOwn<adnl::AdnlExtClient> client;
 | 
				
			||||||
 | 
					    bool alive = false;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  std::vector<Server> servers_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::map<int, td::uint32> ls_stats_;  // lite_api ID -> count, 0 for unknown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string config_file() const {
 | 
					  std::string config_file() const {
 | 
				
			||||||
    return db_root_ + "/config.json";
 | 
					    return db_root_ + "/config.json";
 | 
				
			||||||
| 
						 | 
					@ -270,6 +328,7 @@ int main(int argc, char* argv[]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string global_config, db_root;
 | 
					  std::string global_config, db_root;
 | 
				
			||||||
  td::uint16 port = 0;
 | 
					  td::uint16 port = 0;
 | 
				
			||||||
 | 
					  PublicKeyHash public_key_hash = PublicKeyHash::zero();
 | 
				
			||||||
  td::uint32 threads = 4;
 | 
					  td::uint32 threads = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::OptionParser p;
 | 
					  td::OptionParser p;
 | 
				
			||||||
| 
						 | 
					@ -290,15 +349,27 @@ int main(int argc, char* argv[]) {
 | 
				
			||||||
    std::cout << sb.as_cslice().c_str();
 | 
					    std::cout << sb.as_cslice().c_str();
 | 
				
			||||||
    std::exit(2);
 | 
					    std::exit(2);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  p.add_checked_option('p', "port", "liteserver port (use only on first launch)", [&](td::Slice arg) -> td::Status {
 | 
					  p.add_checked_option('p', "port", "liteserver port (required only on first launch)",
 | 
				
			||||||
 | 
					                       [&](td::Slice arg) -> td::Status {
 | 
				
			||||||
                         TRY_RESULT_ASSIGN(port, td::to_integer_safe<td::uint16>(arg));
 | 
					                         TRY_RESULT_ASSIGN(port, td::to_integer_safe<td::uint16>(arg));
 | 
				
			||||||
                         return td::Status::OK();
 | 
					                         return td::Status::OK();
 | 
				
			||||||
                       });
 | 
					                       });
 | 
				
			||||||
 | 
					  p.add_checked_option(
 | 
				
			||||||
 | 
					      'A', "adnl-id",
 | 
				
			||||||
 | 
					      "liteserver public key hash in hex (optional). The corresponding private key is required in <db>/keyring/",
 | 
				
			||||||
 | 
					      [&](td::Slice arg) -> td::Status {
 | 
				
			||||||
 | 
					        td::Bits256 value;
 | 
				
			||||||
 | 
					        if (value.from_hex(arg) != 256) {
 | 
				
			||||||
 | 
					          return td::Status::Error("invalid adnl-id");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public_key_hash = PublicKeyHash{value};
 | 
				
			||||||
 | 
					        return td::Status::OK();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
  p.add_option('C', "global-config", "global TON configuration file",
 | 
					  p.add_option('C', "global-config", "global TON configuration file",
 | 
				
			||||||
               [&](td::Slice arg) { global_config = arg.str(); });
 | 
					               [&](td::Slice arg) { global_config = arg.str(); });
 | 
				
			||||||
  p.add_option('D', "db", "db root", [&](td::Slice arg) { db_root = arg.str(); });
 | 
					  p.add_option('D', "db", "db root", [&](td::Slice arg) { db_root = arg.str(); });
 | 
				
			||||||
  p.add_option('d', "daemonize", "set SIGHUP", [&]() {
 | 
					  p.add_option('d', "daemonize", "set SIGHUP", [&]() {
 | 
				
			||||||
    td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
 | 
					    td::set_signal_handler(td::SignalType::HangUp, [](int) {
 | 
				
			||||||
#if TD_DARWIN || TD_LINUX
 | 
					#if TD_DARWIN || TD_LINUX
 | 
				
			||||||
      close(0);
 | 
					      close(0);
 | 
				
			||||||
      setsid();
 | 
					      setsid();
 | 
				
			||||||
| 
						 | 
					@ -318,8 +389,10 @@ int main(int argc, char* argv[]) {
 | 
				
			||||||
  p.run(argc, argv).ensure();
 | 
					  p.run(argc, argv).ensure();
 | 
				
			||||||
  td::actor::Scheduler scheduler({threads});
 | 
					  td::actor::Scheduler scheduler({threads});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  scheduler.run_in_context(
 | 
					  scheduler.run_in_context([&] {
 | 
				
			||||||
      [&] { td::actor::create_actor<ProxyLiteserver>("proxy-liteserver", global_config, db_root, port).release(); });
 | 
					    td::actor::create_actor<ProxyLiteserver>("proxy-liteserver", global_config, db_root, port, public_key_hash)
 | 
				
			||||||
 | 
					        .release();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
  while (scheduler.run(1)) {
 | 
					  while (scheduler.run(1)) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue