mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	updated liteserver
- new methods for liteserver/liteclient - added ADNL/DHT client-only work mode - fixed crash in ADNL
This commit is contained in:
		
							parent
							
								
									acf16718e6
								
							
						
					
					
						commit
						53ec9684bd
					
				
					 70 changed files with 816 additions and 322 deletions
				
			
		
							
								
								
									
										2
									
								
								GPLv2
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								GPLv2
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -23,5 +23,5 @@
 | 
			
		|||
    exception statement from your version. If you delete this exception statement 
 | 
			
		||||
    from all source files in the program, then also delete it here.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								LGPLv2
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								LGPLv2
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -14,5 +14,5 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,6 +155,16 @@ td::Result<AdnlAddressList> AdnlAddressList::create(const tl_object_ptr<ton_api:
 | 
			
		|||
  return A;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Status AdnlAddressList::add_udp_address(td::IPAddress addr) {
 | 
			
		||||
  if (addr.is_ipv4()) {
 | 
			
		||||
    auto r = td::make_ref<AdnlAddressUdp>(addr.get_ipv4(), static_cast<td::uint16>(addr.get_port()));
 | 
			
		||||
    addrs_.push_back(std::move(r));
 | 
			
		||||
    return td::Status::OK();
 | 
			
		||||
  } else {
 | 
			
		||||
    return td::Status::Error(ErrorCode::protoviolation, "only works with ipv4");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace adnl
 | 
			
		||||
 | 
			
		||||
}  // namespace ton
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,6 +88,7 @@ class AdnlAddressList {
 | 
			
		|||
  void add_addr(AdnlAddress addr) {
 | 
			
		||||
    addrs_.push_back(addr);
 | 
			
		||||
  }
 | 
			
		||||
  void update(td::IPAddress addr);
 | 
			
		||||
  bool public_only() const;
 | 
			
		||||
  td::uint32 size() const {
 | 
			
		||||
    return static_cast<td::uint32>(addrs_.size());
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +99,7 @@ class AdnlAddressList {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  static td::Result<AdnlAddressList> create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list);
 | 
			
		||||
  td::Status add_udp_address(td::IPAddress addr);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace adnl
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -111,13 +111,15 @@ void AdnlChannelImpl::send_message(td::uint32 priority, td::actor::ActorId<AdnlN
 | 
			
		|||
  td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_, priority, std::move(B));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AdnlChannelImpl::receive(td::BufferSlice data) {
 | 
			
		||||
void AdnlChannelImpl::receive(td::IPAddress addr, td::BufferSlice data) {
 | 
			
		||||
  auto P = td::PromiseCreator::lambda(
 | 
			
		||||
      [peer = peer_pair_, channel_id = channel_in_id_, id = print_id()](td::Result<AdnlPacket> R) {
 | 
			
		||||
      [peer = peer_pair_, channel_id = channel_in_id_, addr, id = print_id()](td::Result<AdnlPacket> R) {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          VLOG(ADNL_WARNING) << id << ": dropping IN message: can not decrypt: " << R.move_as_error();
 | 
			
		||||
        } else {
 | 
			
		||||
          td::actor::send_closure(peer, &AdnlPeerPair::receive_packet_from_channel, channel_id, R.move_as_ok());
 | 
			
		||||
          auto packet = R.move_as_ok();
 | 
			
		||||
          packet.set_remote_addr(addr);
 | 
			
		||||
          td::actor::send_closure(peer, &AdnlPeerPair::receive_packet_from_channel, channel_id, std::move(packet));
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ class AdnlChannel : public td::actor::Actor {
 | 
			
		|||
                                                             AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
 | 
			
		||||
                                                             AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
 | 
			
		||||
                                                             td::actor::ActorId<AdnlPeerPair> peer_pair);
 | 
			
		||||
  virtual void receive(td::BufferSlice data) = 0;
 | 
			
		||||
  virtual void receive(td::IPAddress addr, td::BufferSlice data) = 0;
 | 
			
		||||
  virtual void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn,
 | 
			
		||||
                            td::BufferSlice data) = 0;
 | 
			
		||||
  virtual ~AdnlChannel() = default;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ class AdnlChannelImpl : public AdnlChannel {
 | 
			
		|||
                  AdnlChannelIdShort in_id, AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
 | 
			
		||||
                  std::unique_ptr<Decryptor> decryptor);
 | 
			
		||||
  void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise);
 | 
			
		||||
  void receive(td::BufferSlice data) override;
 | 
			
		||||
  void receive(td::IPAddress addr, td::BufferSlice data) override;
 | 
			
		||||
  void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn, td::BufferSlice data) override;
 | 
			
		||||
 | 
			
		||||
  struct AdnlChannelPrintId {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,13 +40,15 @@ AdnlAddressList AdnlLocalId::get_addr_list() const {
 | 
			
		|||
  return addr_list_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AdnlLocalId::receive(td::BufferSlice data) {
 | 
			
		||||
void AdnlLocalId::receive(td::IPAddress addr, td::BufferSlice data) {
 | 
			
		||||
  auto P = td::PromiseCreator::lambda(
 | 
			
		||||
      [peer_table = peer_table_, dst = short_id_, id = print_id()](td::Result<AdnlPacket> R) {
 | 
			
		||||
      [peer_table = peer_table_, dst = short_id_, addr, id = print_id()](td::Result<AdnlPacket> R) {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          VLOG(ADNL_WARNING) << id << ": dropping IN message: cannot decrypt: " << R.move_as_error();
 | 
			
		||||
        } else {
 | 
			
		||||
          td::actor::send_closure(peer_table, &AdnlPeerTable::receive_decrypted_packet, dst, R.move_as_ok());
 | 
			
		||||
          auto packet = R.move_as_ok();
 | 
			
		||||
          packet.set_remote_addr(addr);
 | 
			
		||||
          td::actor::send_closure(peer_table, &AdnlPeerTable::receive_decrypted_packet, dst, std::move(packet));
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +119,7 @@ void AdnlLocalId::update_address_list(AdnlAddressList addr_list) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void AdnlLocalId::publish_address_list() {
 | 
			
		||||
  if (dht_node_.empty() || addr_list_.empty()) {
 | 
			
		||||
  if (dht_node_.empty() || addr_list_.empty() || addr_list_.size() == 0) {
 | 
			
		||||
    VLOG(ADNL_NOTICE) << this << ": skipping public addr list, because localid (or dht node) not fully initialized";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +180,8 @@ AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor
 | 
			
		|||
  id_ = std::move(id);
 | 
			
		||||
  short_id_ = id_.compute_short_id();
 | 
			
		||||
  addr_list_ = std::move(addr_list);
 | 
			
		||||
  if (addr_list_.addrs().size() > 0) {
 | 
			
		||||
  if (!addr_list_.empty()) {
 | 
			
		||||
    addr_list_.set_reinit_date(Adnl::adnl_start_time());
 | 
			
		||||
    addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
 | 
			
		||||
  }
 | 
			
		||||
  peer_table_ = peer_table;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ class AdnlLocalId : public td::actor::Actor {
 | 
			
		|||
  void decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise);
 | 
			
		||||
  void deliver(AdnlNodeIdShort src, td::BufferSlice data);
 | 
			
		||||
  void deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
 | 
			
		||||
  void receive(td::BufferSlice data);
 | 
			
		||||
  void receive(td::IPAddress addr, td::BufferSlice data);
 | 
			
		||||
 | 
			
		||||
  void subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback);
 | 
			
		||||
  void unsubscribe(std::string prefix);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
 | 
			
		|||
  }
 | 
			
		||||
  received_messages_++;
 | 
			
		||||
  if (received_messages_ % 64 == 0) {
 | 
			
		||||
    VLOG(ADNL_DEBUG) << this << ": received " << received_messages_ << "udp messages";
 | 
			
		||||
    VLOG(ADNL_DEBUG) << this << ": received " << received_messages_ << " udp messages";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,6 +132,9 @@ class AdnlPacket {
 | 
			
		|||
  auto signature() const {
 | 
			
		||||
    return signature_.clone();
 | 
			
		||||
  }
 | 
			
		||||
  auto remote_addr() const {
 | 
			
		||||
    return remote_addr_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void init_random();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +191,10 @@ class AdnlPacket {
 | 
			
		|||
    flags_ |= Flags::f_reinit_date;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void set_remote_addr(td::IPAddress addr) {
 | 
			
		||||
    remote_addr_ = addr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  td::BufferSlice rand1_;
 | 
			
		||||
  td::uint32 flags_{0};
 | 
			
		||||
| 
						 | 
				
			
			@ -204,6 +211,8 @@ class AdnlPacket {
 | 
			
		|||
  td::int32 dst_reinit_date_{0};
 | 
			
		||||
  td::BufferSlice signature_;
 | 
			
		||||
  td::BufferSlice rand2_;
 | 
			
		||||
 | 
			
		||||
  td::IPAddress remote_addr_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace adnl
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ td::actor::ActorOwn<Adnl> Adnl::create(std::string db, td::actor::ActorId<keyrin
 | 
			
		|||
  return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
 | 
			
		||||
void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data) {
 | 
			
		||||
  if (data.size() < 32) {
 | 
			
		||||
    VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			@ -60,14 +60,14 @@ void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
 | 
			
		|||
 | 
			
		||||
  auto it = local_ids_own_.find(dst);
 | 
			
		||||
  if (it != local_ids_own_.end()) {
 | 
			
		||||
    td::actor::send_closure(it->second, &AdnlLocalId::receive, std::move(data));
 | 
			
		||||
    td::actor::send_closure(it->second, &AdnlLocalId::receive, addr, std::move(data));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
 | 
			
		||||
  auto it2 = channels_.find(dst_chan_id);
 | 
			
		||||
  if (it2 != channels_.end()) {
 | 
			
		||||
    td::actor::send_closure(it2->second, &AdnlChannel::receive, std::move(data));
 | 
			
		||||
    td::actor::send_closure(it2->second, &AdnlChannel::receive, addr, std::move(data));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -237,7 +237,7 @@ void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkM
 | 
			
		|||
  class Cb : public AdnlNetworkManager::Callback {
 | 
			
		||||
   public:
 | 
			
		||||
    void receive_packet(td::IPAddress addr, td::BufferSlice data) override {
 | 
			
		||||
      td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, std::move(data));
 | 
			
		||||
      td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(data));
 | 
			
		||||
    }
 | 
			
		||||
    Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) {
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,7 +89,7 @@ class AdnlPeerTable : public Adnl {
 | 
			
		|||
 | 
			
		||||
  virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0;
 | 
			
		||||
 | 
			
		||||
  virtual void receive_packet(td::BufferSlice data) = 0;
 | 
			
		||||
  virtual void receive_packet(td::IPAddress addr, td::BufferSlice data) = 0;
 | 
			
		||||
  virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0;
 | 
			
		||||
  virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
 | 
			
		|||
  void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override;
 | 
			
		||||
  void add_static_nodes_from_config(AdnlNodesList nodes) override;
 | 
			
		||||
 | 
			
		||||
  void receive_packet(td::BufferSlice data) override;
 | 
			
		||||
  void receive_packet(td::IPAddress addr, td::BufferSlice data) override;
 | 
			
		||||
  void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override;
 | 
			
		||||
  void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) override;
 | 
			
		||||
  void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,7 +131,12 @@ void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
 | 
			
		|||
  }
 | 
			
		||||
  if (packet.dst_reinit_date() > 0 && packet.dst_reinit_date() < d) {
 | 
			
		||||
    if (!packet.addr_list().empty()) {
 | 
			
		||||
      update_addr_list(packet.addr_list());
 | 
			
		||||
      auto addr_list = packet.addr_list();
 | 
			
		||||
      if (packet.remote_addr().is_valid() && addr_list.size() == 0) {
 | 
			
		||||
        VLOG(ADNL_DEBUG) << "adding implicit address " << packet.remote_addr();
 | 
			
		||||
        addr_list.add_udp_address(packet.remote_addr());
 | 
			
		||||
      }
 | 
			
		||||
      update_addr_list(std::move(addr_list));
 | 
			
		||||
    }
 | 
			
		||||
    if (!packet.priority_addr_list().empty()) {
 | 
			
		||||
      update_addr_list(packet.priority_addr_list());
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +179,12 @@ void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  if (!packet.addr_list().empty()) {
 | 
			
		||||
    update_addr_list(packet.addr_list());
 | 
			
		||||
    auto addr_list = packet.addr_list();
 | 
			
		||||
    if (packet.remote_addr().is_valid() && addr_list.size() == 0) {
 | 
			
		||||
      VLOG(ADNL_DEBUG) << "adding implicit address " << packet.remote_addr();
 | 
			
		||||
      addr_list.add_udp_address(packet.remote_addr());
 | 
			
		||||
    }
 | 
			
		||||
    update_addr_list(std::move(addr_list));
 | 
			
		||||
  }
 | 
			
		||||
  if (!packet.priority_addr_list().empty()) {
 | 
			
		||||
    update_addr_list(packet.priority_addr_list());
 | 
			
		||||
| 
						 | 
				
			
			@ -642,7 +652,7 @@ void AdnlPeerPairImpl::update_addr_list(AdnlAddressList addr_list) {
 | 
			
		|||
  if (addr_list.empty()) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  CHECK(addr_list.size() > 0);
 | 
			
		||||
  //CHECK(addr_list.size() > 0);
 | 
			
		||||
 | 
			
		||||
  if (addr_list.reinit_date() > td::Clocks::system() + 60) {
 | 
			
		||||
    VLOG(ADNL_WARNING) << "dropping addr list with too new reinit date";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
    exception statement from your version. If you delete this exception statement
 | 
			
		||||
    from all source files in the program, then also delete it here.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "blockchain-explorer-http.hpp"
 | 
			
		||||
#include "block/block-db.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +36,8 @@
 | 
			
		|||
#include "block/mc-config.h"
 | 
			
		||||
#include "ton/ton-shard.h"
 | 
			
		||||
 | 
			
		||||
bool local_scripts{false};
 | 
			
		||||
 | 
			
		||||
HttpAnswer& HttpAnswer::operator<<(AddressCell addr_c) {
 | 
			
		||||
  ton::WorkchainId wc;
 | 
			
		||||
  ton::StdSmcAddress addr;
 | 
			
		||||
| 
						 | 
				
			
			@ -425,7 +427,7 @@ HttpAnswer& HttpAnswer::operator<<(AccountCell acc_c) {
 | 
			
		|||
 | 
			
		||||
HttpAnswer& HttpAnswer::operator<<(BlockHeaderCell head_c) {
 | 
			
		||||
  *this << "<div>";
 | 
			
		||||
  vm::CellSlice cs{vm::NoVm{}, head_c.root};
 | 
			
		||||
  vm::CellSlice cs{vm::NoVm(), head_c.root};
 | 
			
		||||
  auto block_id = head_c.block_id;
 | 
			
		||||
  try {
 | 
			
		||||
    auto virt_root = vm::MerkleProof::virtualize(head_c.root, 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -676,13 +678,17 @@ std::string HttpAnswer::header() {
 | 
			
		|||
           "maximum-scale=1.0, user-scalable=no\" />\n"
 | 
			
		||||
        << "<meta name=\"format-detection\" content=\"telephone=no\" />\n"
 | 
			
		||||
        << "<!-- Latest compiled and minified CSS -->\n"
 | 
			
		||||
        << "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">\n"
 | 
			
		||||
        << "<link rel=\"stylesheet\" href=\"" << (local_scripts ? "/" : "https://")
 | 
			
		||||
        << "maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">\n"
 | 
			
		||||
        << "<!-- jQuery library -->"
 | 
			
		||||
        << "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js\"></script>\n"
 | 
			
		||||
        << "<script src=\"" << (local_scripts ? "/" : "https://")
 | 
			
		||||
        << "ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js\"></script>\n"
 | 
			
		||||
        << "<!-- Popper JS -->\n"
 | 
			
		||||
        << "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js\"></script>\n"
 | 
			
		||||
        << "<script src=\"" << (local_scripts ? "/" : "https://")
 | 
			
		||||
        << "cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js\"></script>\n"
 | 
			
		||||
        << "<!-- Latest compiled JavaScript -->\n"
 | 
			
		||||
        << "<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js\"></script>\n"
 | 
			
		||||
        << "<script src=\"" << (local_scripts ? "/" : "https://")
 | 
			
		||||
        << "maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js\"></script>\n"
 | 
			
		||||
        << "</head><body>\n"
 | 
			
		||||
        << "<div class=\"container-fluid\">\n"
 | 
			
		||||
        << "<nav class=\"navbar navbar-expand px-0 mt-1 flex-wrap\">\n"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,8 @@
 | 
			
		|||
#include "td/utils/Random.h"
 | 
			
		||||
#include "block/block.h"
 | 
			
		||||
 | 
			
		||||
extern bool local_scripts;
 | 
			
		||||
 | 
			
		||||
class HttpAnswer {
 | 
			
		||||
 public:
 | 
			
		||||
  struct MessageCell {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -639,6 +639,10 @@ int main(int argc, char* argv[]) {
 | 
			
		|||
    td::actor::send_closure(x, &CoreActor::set_http_port, td::to_integer<td::uint32>(arg));
 | 
			
		||||
    return td::Status::OK();
 | 
			
		||||
  });
 | 
			
		||||
  p.add_option('L', "local-scripts", "use local copy of ajax/bootstrap/... JS", [&]() {
 | 
			
		||||
    local_scripts = true;
 | 
			
		||||
    return td::Status::OK();
 | 
			
		||||
  });
 | 
			
		||||
#if TD_DARWIN || TD_LINUX
 | 
			
		||||
  p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
 | 
			
		||||
    auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,8 @@
 | 
			
		|||
 | 
			
		||||
#define MAX_POST_SIZE (64 << 10)
 | 
			
		||||
 | 
			
		||||
extern bool local_scripts_;
 | 
			
		||||
 | 
			
		||||
class CoreActorInterface : public td::actor::Actor {
 | 
			
		||||
 public:
 | 
			
		||||
  struct RemoteNodeStatus {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "check-proof.h"
 | 
			
		||||
#include "block/block.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +219,17 @@ td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
td::Result<AccountState::Info> AccountState::validate(ton::BlockIdExt ref_blk, block::StdAddress addr) const {
 | 
			
		||||
  TRY_RESULT_PREFIX(root, vm::std_boc_deserialize(state.as_slice(), true), "cannot deserialize account state");
 | 
			
		||||
  TRY_RESULT_PREFIX(true_root, vm::std_boc_deserialize(state.as_slice(), true), "cannot deserialize account state");
 | 
			
		||||
  Ref<vm::Cell> root;
 | 
			
		||||
 | 
			
		||||
  if (is_virtualized && true_root.not_null()) {
 | 
			
		||||
    root = vm::MerkleProof::virtualize(true_root, 1);
 | 
			
		||||
    if (root.is_null()) {
 | 
			
		||||
      return td::Status::Error("account state proof is invalid");
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    root = true_root;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (blk != ref_blk && ref_blk.id.seqno != ~0U) {
 | 
			
		||||
    return td::Status::Error(PSLICE() << "obtained getAccountState() for a different reference block " << blk.to_str()
 | 
			
		||||
| 
						 | 
				
			
			@ -241,6 +251,7 @@ td::Result<AccountState::Info> AccountState::validate(ton::BlockIdExt ref_blk, b
 | 
			
		|||
  TRY_STATUS(block::check_account_proof(proof.as_slice(), shard_blk, addr, root, &res.last_trans_lt,
 | 
			
		||||
                                        &res.last_trans_hash, &res.gen_utime, &res.gen_lt));
 | 
			
		||||
  res.root = std::move(root);
 | 
			
		||||
  res.true_root = std::move(true_root);
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,10 +44,11 @@ struct AccountState {
 | 
			
		|||
  td::BufferSlice shard_proof;
 | 
			
		||||
  td::BufferSlice proof;
 | 
			
		||||
  td::BufferSlice state;
 | 
			
		||||
  bool is_virtualized{false};
 | 
			
		||||
 | 
			
		||||
  struct Info {
 | 
			
		||||
    td::Ref<vm::Cell> root;
 | 
			
		||||
    ton::LogicalTime last_trans_lt = 0;
 | 
			
		||||
    td::Ref<vm::Cell> root, true_root;
 | 
			
		||||
    ton::LogicalTime last_trans_lt{0};
 | 
			
		||||
    ton::Bits256 last_trans_hash;
 | 
			
		||||
    ton::LogicalTime gen_lt{0};
 | 
			
		||||
    td::uint32 gen_utime{0};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
    exception statement from your version. If you delete this exception statement 
 | 
			
		||||
    from all source files in the program, then also delete it here.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "mc-config.h"
 | 
			
		||||
#include "block/block.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -752,8 +752,8 @@ Ref<McShardDescr> McShardDescr::from_block(Ref<vm::Cell> block_root, Ref<vm::Cel
 | 
			
		|||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
  // TODO: use a suitable vm::MerkleUpdate method here
 | 
			
		||||
  vm::CellSlice cs(vm::NoVm(), rec.state_update);
 | 
			
		||||
  if (cs.special_type() != vm::Cell::SpecialType::MerkleUpdate) {
 | 
			
		||||
  vm::CellSlice cs(vm::NoVmSpec(), rec.state_update);
 | 
			
		||||
  if (!cs.is_valid() || cs.special_type() != vm::Cell::SpecialType::MerkleUpdate) {
 | 
			
		||||
    LOG(ERROR) << "state update in a block is not a Merkle update";
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -870,7 +870,7 @@ bool ShardConfig::get_shard_hash_raw_from(vm::Dictionary& dict, vm::CellSlice& c
 | 
			
		|||
  unsigned long long z = id.shard, m = std::numeric_limits<unsigned long long>::max();
 | 
			
		||||
  int len = id.pfx_len();
 | 
			
		||||
  while (true) {
 | 
			
		||||
    cs.load(vm::NoVmOrd{}, leaf ? root : std::move(root));
 | 
			
		||||
    cs.load(vm::NoVmOrd(), leaf ? root : std::move(root));
 | 
			
		||||
    int t = (int)cs.fetch_ulong(1);
 | 
			
		||||
    if (t < 0) {
 | 
			
		||||
      return false;  // throw DictError ?
 | 
			
		||||
| 
						 | 
				
			
			@ -1108,7 +1108,7 @@ std::vector<ton::BlockId> ShardConfig::get_shard_hash_ids(
 | 
			
		|||
            std::stack<std::pair<Ref<vm::Cell>, unsigned long long>> stack;
 | 
			
		||||
            stack.emplace(cs_ref->prefetch_ref(), ton::shardIdAll);
 | 
			
		||||
            while (!stack.empty()) {
 | 
			
		||||
              vm::CellSlice cs{vm::NoVm{}, std::move(stack.top().first)};
 | 
			
		||||
              vm::CellSlice cs{vm::NoVmOrd(), std::move(stack.top().first)};
 | 
			
		||||
              unsigned long long shard = stack.top().second;
 | 
			
		||||
              stack.pop();
 | 
			
		||||
              int t = (int)cs.fetch_ulong(1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -965,6 +965,11 @@ x{F4B5} @Defop SUBDICTRPGET
 | 
			
		|||
x{F4B6} @Defop SUBDICTIRPGET
 | 
			
		||||
x{F4B7} @Defop SUBDICTURPGET
 | 
			
		||||
 | 
			
		||||
x{F4BC} @Defop DICTIGETJMPZ
 | 
			
		||||
x{F4BD} @Defop DICTUGETJMPZ
 | 
			
		||||
x{F4BE} @Defop DICTIGETEXECZ
 | 
			
		||||
x{F4BF} @Defop DICTUGETEXECZ
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// blockchain-specific primitives
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1117,7 +1122,7 @@ variable @gvarcnt
 | 
			
		|||
  @procdict dup @ swap null!
 | 
			
		||||
} : }END
 | 
			
		||||
forget @proclist  forget @proccnt
 | 
			
		||||
{ }END <{ SETCP0 swap @procdictkeylen DICTPUSHCONST DICTIGETJMP 11 THROWARG }> } : }END>
 | 
			
		||||
{ }END <{ SETCP0 swap @procdictkeylen DICTPUSHCONST DICTIGETJMPZ 11 THROWARG }> } : }END>
 | 
			
		||||
{ }END> b> } : }END>c
 | 
			
		||||
{ }END>c <s } : }END>s
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "words.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1007,8 +1007,8 @@ void interpret_store_end(vm::Stack& stack, bool special) {
 | 
			
		|||
 | 
			
		||||
void interpret_from_cell(vm::Stack& stack) {
 | 
			
		||||
  auto cell = stack.pop_cell();
 | 
			
		||||
  Ref<vm::CellSlice> cs{true};
 | 
			
		||||
  if (!cs.unique_write().load(vm::NoVmOrd(), std::move(cell))) {
 | 
			
		||||
  Ref<vm::CellSlice> cs{true, vm::NoVmOrd(), std::move(cell)};
 | 
			
		||||
  if (!cs->is_valid()) {
 | 
			
		||||
    throw IntError{"deserializing a special cell as ordinary"};
 | 
			
		||||
  }
 | 
			
		||||
  stack.push(cs);
 | 
			
		||||
| 
						 | 
				
			
			@ -1117,7 +1117,10 @@ void interpret_fetch_ref(vm::Stack& stack, int mode) {
 | 
			
		|||
      stack.push(std::move(cs));
 | 
			
		||||
    }
 | 
			
		||||
    if (mode & 1) {
 | 
			
		||||
      Ref<vm::CellSlice> new_cs{true, vm::NoVm(), std::move(cell)};
 | 
			
		||||
      Ref<vm::CellSlice> new_cs{true, vm::NoVmOrd(), std::move(cell)};
 | 
			
		||||
      if (!new_cs->is_valid()) {
 | 
			
		||||
        throw IntError{"cannot load ordinary cell"};
 | 
			
		||||
      }
 | 
			
		||||
      stack.push(std::move(new_cs));
 | 
			
		||||
    } else {
 | 
			
		||||
      stack.push_cell(std::move(cell));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,3 +39,9 @@
 | 
			
		|||
int seqno() method_id {
 | 
			
		||||
  return get_data().begin_parse().preload_uint(32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var cs = get_data().begin_parse();
 | 
			
		||||
  cs~load_uint(64);
 | 
			
		||||
  return cs.preload_uint(256);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,3 +63,9 @@ int processed?(int query_id) method_id {
 | 
			
		|||
  (_, var found) = old_queries.udict_get?(64, query_id);
 | 
			
		||||
  return found ? true : - (query_id <= last_cleaned);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var cs = get_data().begin_parse();
 | 
			
		||||
  cs~load_uint(32 + 64);
 | 
			
		||||
  return cs.preload_uint(256);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,8 +15,8 @@ def? $2 { @' $2 } { "new-wallet" } cond constant file-base
 | 
			
		|||
 | 
			
		||||
// Create new advanced wallet; code adapted from `auto/wallet-code.fif`
 | 
			
		||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
 | 
			
		||||
   DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
 | 
			
		||||
     DROP c4 PUSHCTR CTOS 32 PLDU  // cnt
 | 
			
		||||
   DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
 | 
			
		||||
     1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL  // cnt or pubk
 | 
			
		||||
   }>
 | 
			
		||||
   INC 32 THROWIF	// fail unless recv_external
 | 
			
		||||
   9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU	//  signature in_msg msg_seqno valid_until cs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,8 @@ $3 "new-wallet" replace-if-null =: file-base
 | 
			
		|||
 | 
			
		||||
// Create new advanced wallet; code adapted from `auto/wallet3-code.fif`
 | 
			
		||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
 | 
			
		||||
   DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
 | 
			
		||||
     DROP c4 PUSHCTR CTOS 32 PLDU  // cnt
 | 
			
		||||
   DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
 | 
			
		||||
     1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL  // cnt or pubk
 | 
			
		||||
   }>
 | 
			
		||||
   INC 32 THROWIF	// fail unless recv_external
 | 
			
		||||
   9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU 	//  signature in_msg subwallet_id valid_until msg_seqno cs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,8 +15,8 @@ def? $2 { @' $2 } { "new-wallet" } cond constant file-base
 | 
			
		|||
 | 
			
		||||
// Create new simple wallet
 | 
			
		||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
 | 
			
		||||
   DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
 | 
			
		||||
     DROP c4 PUSHCTR CTOS 32 PLDU  // cnt
 | 
			
		||||
   DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
 | 
			
		||||
     1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL  // cnt or pubk
 | 
			
		||||
   }>
 | 
			
		||||
   INC 32 THROWIF  // fail unless recv_external
 | 
			
		||||
   512 INT LDSLICEX DUP 32 PLDU   // sign cs cnt
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,6 +62,12 @@ int seqno() method_id {
 | 
			
		|||
  return get_data().begin_parse().preload_uint(32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var cs = get_data().begin_parse();
 | 
			
		||||
  cs~load_uint(32);
 | 
			
		||||
  return cs.preload_uint(256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int balance() method_id {
 | 
			
		||||
  return restricted?() ? 0 : get_balance().first();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,12 @@ int seqno() method_id {
 | 
			
		|||
  return get_data().begin_parse().preload_uint(32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var cs = get_data().begin_parse();
 | 
			
		||||
  cs~load_uint(32);
 | 
			
		||||
  return cs.preload_uint(256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int balance() method_id {
 | 
			
		||||
  var ds = get_data().begin_parse().skip_bits(32 + 256);
 | 
			
		||||
  var rdict = ds~load_dict();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,11 @@ int seqno() method_id {
 | 
			
		|||
  return get_data().begin_parse().preload_uint(32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var (seqno, public_key) = load_state();
 | 
			
		||||
  return public_key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cell create_init_state(int public_key) method_id {
 | 
			
		||||
  return create_state(0, public_key);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,3 +29,9 @@
 | 
			
		|||
int seqno() method_id {
 | 
			
		||||
  return get_data().begin_parse().preload_uint(32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var cs = get_data().begin_parse();
 | 
			
		||||
  cs~load_uint(32);
 | 
			
		||||
  return cs.preload_uint(256);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,3 +33,9 @@
 | 
			
		|||
int seqno() method_id {
 | 
			
		||||
  return get_data().begin_parse().preload_uint(32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_public_key() method_id {
 | 
			
		||||
  var cs = get_data().begin_parse();
 | 
			
		||||
  cs~load_uint(64);
 | 
			
		||||
  return cs.preload_uint(256);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "vm/cells/CellBuilder.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -460,6 +460,16 @@ bool CellBuilder::append_cellslice_chk(Ref<CellSlice> cs_ref, unsigned size_ext)
 | 
			
		|||
  return cs_ref.not_null() && append_cellslice_chk(*cs_ref, size_ext);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CellSlice CellSlice::clone() const {
 | 
			
		||||
  CellBuilder cb;
 | 
			
		||||
  Ref<Cell> cell;
 | 
			
		||||
  if (cb.append_cellslice_bool(*this) && cb.finalize_to(cell)) {
 | 
			
		||||
    return CellSlice{NoVmOrd(), std::move(cell)};
 | 
			
		||||
  } else {
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CellBuilder::append_bitstring(const td::BitString& bs) {
 | 
			
		||||
  return store_bits_bool(bs.cbits(), bs.size());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -536,11 +546,11 @@ CellBuilder* CellBuilder::make_copy() const {
 | 
			
		|||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CellSlice CellBuilder::as_cellslice() const& {
 | 
			
		||||
CellSlice CellBuilder::as_cellslice() const & {
 | 
			
		||||
  return CellSlice{finalize_copy()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Ref<CellSlice> CellBuilder::as_cellslice_ref() const& {
 | 
			
		||||
Ref<CellSlice> CellBuilder::as_cellslice_ref() const & {
 | 
			
		||||
  return Ref<CellSlice>{true, finalize_copy()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -275,6 +275,7 @@ class CellSlice : public td::CntObject {
 | 
			
		|||
    offs = std::min(offs, size());
 | 
			
		||||
    return CellSlice{*this, size() - offs, size_refs(), offs, 0};
 | 
			
		||||
  }
 | 
			
		||||
  CellSlice clone() const;
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  void init_bits_refs();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "vm/dict.h"
 | 
			
		||||
#include "vm/cells.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +179,7 @@ bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) && {
 | 
			
		|||
  return cb.store_maybe_ref(std::move(root_cell));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) const& {
 | 
			
		||||
bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) const & {
 | 
			
		||||
  return is_valid() && cb.store_maybe_ref(root_cell);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2240,7 +2240,7 @@ Ref<CellSlice> AugmentedDictionary::extract_root() && {
 | 
			
		|||
  return std::move(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AugmentedDictionary::append_dict_to_bool(CellBuilder& cb) const& {
 | 
			
		||||
bool AugmentedDictionary::append_dict_to_bool(CellBuilder& cb) const & {
 | 
			
		||||
  if (!is_valid()) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -2535,7 +2535,7 @@ bool AugmentedDictionary::set(td::ConstBitPtr key, int key_len, const CellSlice&
 | 
			
		|||
  }
 | 
			
		||||
  auto res = dict_set(get_root_cell(), key, key_len, value, mode);
 | 
			
		||||
  if (res.second) {
 | 
			
		||||
    //vm::CellSlice cs{vm::NoVm{}, res.first};
 | 
			
		||||
    //vm::CellSlice cs{vm::NoVmOrd(), res.first};
 | 
			
		||||
    //std::cerr << "new augmented dictionary root is:\n";
 | 
			
		||||
    //cs.print_rec(std::cerr);
 | 
			
		||||
    set_root_cell(std::move(res.first));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "vm/log.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +210,7 @@ int exec_dict_get(VmState* st, unsigned args) {
 | 
			
		|||
  BitSlice key;
 | 
			
		||||
  unsigned char buffer[Dictionary::max_key_bytes];
 | 
			
		||||
  if (args & 4) {
 | 
			
		||||
    key = dict.integer_key(stack.pop_int(), n, !(args & 2), buffer, true);
 | 
			
		||||
    key = dict.integer_key(stack.pop_int_finite(), n, !(args & 2), buffer, true);
 | 
			
		||||
    if (!key.is_valid()) {
 | 
			
		||||
      stack.push_smallint(0);
 | 
			
		||||
      return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +250,7 @@ int exec_dict_get_optref(VmState* st, unsigned args) {
 | 
			
		|||
  BitSlice key;
 | 
			
		||||
  unsigned char buffer[Dictionary::max_key_bytes];
 | 
			
		||||
  if (args & 2) {
 | 
			
		||||
    key = dict.integer_key(stack.pop_int(), n, !(args & 1), buffer, true);
 | 
			
		||||
    key = dict.integer_key(stack.pop_int_finite(), n, !(args & 1), buffer, true);
 | 
			
		||||
    if (!key.is_valid()) {
 | 
			
		||||
      stack.push_null();
 | 
			
		||||
      return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -377,7 +377,7 @@ int exec_dict_delete(VmState* st, unsigned args) {
 | 
			
		|||
  BitSlice key;
 | 
			
		||||
  unsigned char buffer[Dictionary::max_key_bytes];
 | 
			
		||||
  if (args & 2) {
 | 
			
		||||
    key = dict.integer_key(stack.pop_int(), n, !(args & 1), buffer);
 | 
			
		||||
    key = dict.integer_key(stack.pop_int_finite(), n, !(args & 1), buffer);
 | 
			
		||||
    if (!key.is_valid()) {
 | 
			
		||||
      push_dict(stack, std::move(dict));
 | 
			
		||||
      stack.push_smallint(0);
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ int exec_dict_deleteget(VmState* st, unsigned args) {
 | 
			
		|||
  BitSlice key;
 | 
			
		||||
  unsigned char buffer[Dictionary::max_key_bytes];
 | 
			
		||||
  if (args & 4) {
 | 
			
		||||
    key = dict.integer_key(stack.pop_int(), n, !(args & 2), buffer);
 | 
			
		||||
    key = dict.integer_key(stack.pop_int_finite(), n, !(args & 2), buffer);
 | 
			
		||||
    if (!key.is_valid()) {
 | 
			
		||||
      push_dict(stack, std::move(dict));
 | 
			
		||||
      stack.push_smallint(0);
 | 
			
		||||
| 
						 | 
				
			
			@ -588,23 +588,29 @@ int exec_pfx_dict_delete(VmState* st) {
 | 
			
		|||
 | 
			
		||||
int exec_dict_get_exec(VmState* st, unsigned args) {
 | 
			
		||||
  Stack& stack = st->get_stack();
 | 
			
		||||
  VM_LOG(st) << "execute DICT" << (args & 1 ? 'U' : 'I') << "GET" << (args & 2 ? "EXEC\n" : "JMP\n");
 | 
			
		||||
  VM_LOG(st) << "execute DICT" << (args & 1 ? 'U' : 'I') << "GET" << (args & 2 ? "EXEC" : "JMP")
 | 
			
		||||
             << (args & 4 ? "Z" : "");
 | 
			
		||||
  stack.check_underflow(3);
 | 
			
		||||
  int n = stack.pop_smallint_range(Dictionary::max_key_bits);
 | 
			
		||||
  Dictionary dict{stack.pop_maybe_cell(), n};
 | 
			
		||||
  unsigned char buffer[Dictionary::max_key_bytes];
 | 
			
		||||
  dict.integer_key_simple(stack.pop_int(), n, !(args & 1), td::BitPtr{buffer});
 | 
			
		||||
  auto value = dict.lookup(td::BitPtr{buffer}, n);
 | 
			
		||||
  if (value.not_null()) {
 | 
			
		||||
    Ref<OrdCont> cont{true, std::move(value), st->get_cp()};
 | 
			
		||||
    return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont));
 | 
			
		||||
  } else {
 | 
			
		||||
    return 0;
 | 
			
		||||
  auto idx = stack.pop_int_finite();
 | 
			
		||||
  if (dict.integer_key_simple(idx, n, !(args & 1), td::BitPtr{buffer}, true)) {
 | 
			
		||||
    auto value = dict.lookup(td::BitPtr{buffer}, n);
 | 
			
		||||
    if (value.not_null()) {
 | 
			
		||||
      Ref<OrdCont> cont{true, std::move(value), st->get_cp()};
 | 
			
		||||
      return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // key not found or out of range
 | 
			
		||||
  if (args & 4) {
 | 
			
		||||
    stack.push_int(std::move(idx));
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string dump_dict_get_exec(CellSlice& cs, unsigned args) {
 | 
			
		||||
  return std::string{"DICT"} + (args & 1 ? 'U' : 'I') + "GET" + (args & 2 ? "EXEC" : "JMP");
 | 
			
		||||
  return std::string{"DICT"} + (args & 1 ? 'U' : 'I') + "GET" + (args & 2 ? "EXEC" : "JMP") + (args & 4 ? "Z" : "");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int exec_push_const_dict(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) {
 | 
			
		||||
| 
						 | 
				
			
			@ -720,7 +726,7 @@ int exec_subdict_get(VmState* st, unsigned args) {
 | 
			
		|||
  BitSlice key;
 | 
			
		||||
  unsigned char buffer[Dictionary::max_key_bytes];
 | 
			
		||||
  if (args & 2) {
 | 
			
		||||
    key = dict.integer_key(stack.pop_int(), k, !(args & 1), buffer, true);
 | 
			
		||||
    key = dict.integer_key(stack.pop_int_finite(), k, !(args & 1), buffer, true);
 | 
			
		||||
  } else {
 | 
			
		||||
    key = stack.pop_cellslice()->prefetch_bits(k);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -805,7 +811,8 @@ void register_dictionary_ops(OpcodeTable& cp0) {
 | 
			
		|||
                                      exec_const_pfx_dict_switch, compute_len_push_const_dict))
 | 
			
		||||
      .insert(OpcodeInstr::mkfixedrange(0xf4b1, 0xf4b4, 16, 3, std::bind(dump_subdictop2, _2, "GET"), exec_subdict_get))
 | 
			
		||||
      .insert(
 | 
			
		||||
          OpcodeInstr::mkfixedrange(0xf4b5, 0xf4b8, 16, 3, std::bind(dump_subdictop2, _2, "RPGET"), exec_subdict_get));
 | 
			
		||||
          OpcodeInstr::mkfixedrange(0xf4b5, 0xf4b8, 16, 3, std::bind(dump_subdictop2, _2, "RPGET"), exec_subdict_get))
 | 
			
		||||
      .insert(OpcodeInstr::mkfixed(0xf4bc >> 2, 14, 2, dump_dict_get_exec, exec_dict_get_exec));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace vm
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +33,12 @@ struct VmLog {
 | 
			
		|||
  td::LogOptions log_options{td::log_options};
 | 
			
		||||
  enum { DumpStack = 2 };
 | 
			
		||||
  int log_mask{1};
 | 
			
		||||
  static VmLog Null() {
 | 
			
		||||
    VmLog res;
 | 
			
		||||
    res.log_options.level = 0;
 | 
			
		||||
    res.log_mask = 0;
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class State>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "vm/stack.hpp"
 | 
			
		||||
#include "vm/continuation.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -824,7 +824,7 @@ bool StackEntry::deserialize(CellSlice& cs, int mode) {
 | 
			
		|||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
      } else if (n == 1) {
 | 
			
		||||
        return cs.have_refs() && t[0].deserialize(cs.fetch_ref(), mode);
 | 
			
		||||
        return cs.have_refs() && t[0].deserialize(cs.fetch_ref(), mode) && set(t_tuple, std::move(tuple));
 | 
			
		||||
      }
 | 
			
		||||
      return set(t_tuple, std::move(tuple));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -145,13 +145,13 @@ void DhtBucket::promote_node(size_t idx) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DhtBucket::check(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> dht,
 | 
			
		||||
void DhtBucket::check(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> dht,
 | 
			
		||||
                      adnl::AdnlNodeIdShort src) {
 | 
			
		||||
  size_t have_space = 0;
 | 
			
		||||
  for (size_t i = 0; i < active_nodes_.size(); i++) {
 | 
			
		||||
    auto &node = active_nodes_[i];
 | 
			
		||||
    if (node && td::Time::now_cached() - node->last_ping_at() > ping_timeout_) {
 | 
			
		||||
      node->send_ping(adnl, dht, src);
 | 
			
		||||
      node->send_ping(client_only, adnl, dht, src);
 | 
			
		||||
      if (node->ready_from() == 0) {
 | 
			
		||||
        demote_node(i);
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +163,7 @@ void DhtBucket::check(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<Dh
 | 
			
		|||
  for (size_t i = 0; i < backup_nodes_.size(); i++) {
 | 
			
		||||
    auto &node = backup_nodes_[i];
 | 
			
		||||
    if (node && td::Time::now_cached() - node->last_ping_at() > ping_timeout_) {
 | 
			
		||||
      node->send_ping(adnl, dht, src);
 | 
			
		||||
      node->send_ping(client_only, adnl, dht, src);
 | 
			
		||||
    }
 | 
			
		||||
    if (node && have_space > 0 && node->is_ready()) {
 | 
			
		||||
      promote_node(i);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,8 +39,8 @@ class DhtBucket {
 | 
			
		|||
 | 
			
		||||
  //std::map<td::UInt256, std::unique_ptr<DhtRemoteNode>> pending_nodes_;
 | 
			
		||||
  td::uint32 k_;
 | 
			
		||||
  bool check_one(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src,
 | 
			
		||||
                 const DhtMember::PrintId &print_id);
 | 
			
		||||
  //bool check_one(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src,
 | 
			
		||||
  //               const DhtMember::PrintId &print_id);
 | 
			
		||||
  void demote_node(size_t idx);
 | 
			
		||||
  void promote_node(size_t idx);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,8 @@ class DhtBucket {
 | 
			
		|||
  td::uint32 active_cnt();
 | 
			
		||||
  td::Status add_full_node(DhtKeyId id, DhtNode node, td::actor::ActorId<adnl::Adnl> adnl,
 | 
			
		||||
                           adnl::AdnlNodeIdShort self_id);
 | 
			
		||||
  void check(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src);
 | 
			
		||||
  void check(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
             adnl::AdnlNodeIdShort src);
 | 
			
		||||
  void receive_ping(DhtKeyId id, DhtNode result, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id);
 | 
			
		||||
  void get_nearest_nodes(DhtKeyId id, td::uint32 bit, DhtNodesList &vec, td::uint32 k);
 | 
			
		||||
  void dump(td::StringBuilder &sb) const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,6 +94,8 @@ class DhtMemberImpl : public DhtMember {
 | 
			
		|||
  td::actor::ActorId<keyring::Keyring> keyring_;
 | 
			
		||||
  td::actor::ActorId<adnl::Adnl> adnl_;
 | 
			
		||||
 | 
			
		||||
  bool client_only_{false};
 | 
			
		||||
 | 
			
		||||
  td::uint64 ping_queries_{0};
 | 
			
		||||
  td::uint64 find_node_queries_{0};
 | 
			
		||||
  td::uint64 find_value_queries_{0};
 | 
			
		||||
| 
						 | 
				
			
			@ -123,8 +125,8 @@ class DhtMemberImpl : public DhtMember {
 | 
			
		|||
 | 
			
		||||
 public:
 | 
			
		||||
  DhtMemberImpl(adnl::AdnlNodeIdShort id, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
 | 
			
		||||
                td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a = 3)
 | 
			
		||||
      : id_(id), key_{id_}, k_(k), a_(a), db_root_(db_root), keyring_(keyring), adnl_(adnl) {
 | 
			
		||||
                td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a = 3, bool client_only = false)
 | 
			
		||||
      : id_(id), key_{id_}, k_(k), a_(a), db_root_(db_root), keyring_(keyring), adnl_(adnl), client_only_(client_only) {
 | 
			
		||||
    for (size_t i = 0; i < 256; i++) {
 | 
			
		||||
      buckets_.emplace_back(k_);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,7 +96,12 @@ void DhtQuery::add_nodes(DhtNodesList list) {
 | 
			
		|||
 | 
			
		||||
void DhtQueryFindNodes::send_one_query(adnl::AdnlNodeIdShort id) {
 | 
			
		||||
  auto P = create_serialize_tl_object<ton_api::dht_findNode>(get_key().tl(), get_k());
 | 
			
		||||
  auto B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl());
 | 
			
		||||
  td::BufferSlice B;
 | 
			
		||||
  if (client_only_) {
 | 
			
		||||
    B = std::move(P);
 | 
			
		||||
  } else {
 | 
			
		||||
    B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result<td::BufferSlice> R) {
 | 
			
		||||
    td::actor::send_closure(SelfId, &DhtQueryFindNodes::on_result, std::move(R), dst);
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +134,12 @@ void DhtQueryFindNodes::finish(DhtNodesList list) {
 | 
			
		|||
 | 
			
		||||
void DhtQueryFindValue::send_one_query(adnl::AdnlNodeIdShort id) {
 | 
			
		||||
  auto P = create_serialize_tl_object<ton_api::dht_findValue>(get_key().tl(), get_k());
 | 
			
		||||
  auto B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl());
 | 
			
		||||
  td::BufferSlice B;
 | 
			
		||||
  if (client_only_) {
 | 
			
		||||
    B = std::move(P);
 | 
			
		||||
  } else {
 | 
			
		||||
    B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result<td::BufferSlice> R) {
 | 
			
		||||
    td::actor::send_closure(SelfId, &DhtQueryFindValue::on_result, std::move(R), dst);
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +196,7 @@ void DhtQueryFindValue::finish(DhtNodesList list) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
DhtQueryStore::DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src,
 | 
			
		||||
                             DhtNodesList list, td::uint32 k, td::uint32 a, DhtNode self,
 | 
			
		||||
                             DhtNodesList list, td::uint32 k, td::uint32 a, DhtNode self, bool client_only,
 | 
			
		||||
                             td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl,
 | 
			
		||||
                             td::Promise<td::Unit> promise)
 | 
			
		||||
    : print_id_(print_id)
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +205,8 @@ DhtQueryStore::DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, ad
 | 
			
		|||
    , promise_(std::move(promise))
 | 
			
		||||
    , value_(std::move(key_value))
 | 
			
		||||
    , list_(std::move(list))
 | 
			
		||||
    , self_(std::move(self)) {
 | 
			
		||||
    , self_(std::move(self))
 | 
			
		||||
    , client_only_(client_only) {
 | 
			
		||||
  node_ = node;
 | 
			
		||||
  adnl_ = adnl;
 | 
			
		||||
  src_ = src;
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +219,7 @@ void DhtQueryStore::start_up() {
 | 
			
		|||
 | 
			
		||||
  auto key = value_.key_id();
 | 
			
		||||
  auto A = td::actor::create_actor<DhtQueryFindNodes>("FindNodesQuery", key, print_id_, src_, std::move(list_), k_, a_,
 | 
			
		||||
                                                      self_.clone(), node_, adnl_, std::move(P));
 | 
			
		||||
                                                      self_.clone(), client_only_, node_, adnl_, std::move(P));
 | 
			
		||||
  A.release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,11 +41,21 @@ class DhtQuery : public td::actor::Actor {
 | 
			
		|||
 protected:
 | 
			
		||||
  DhtKeyId key_;
 | 
			
		||||
  DhtNode self_;
 | 
			
		||||
  bool client_only_;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  DhtQuery(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, td::uint32 k,
 | 
			
		||||
           td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl)
 | 
			
		||||
      : key_(key), self_(std::move(self)), print_id_(print_id), src_(src), k_(k), a_(a), node_(node), adnl_(adnl) {
 | 
			
		||||
           td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
           td::actor::ActorId<adnl::Adnl> adnl)
 | 
			
		||||
      : key_(key)
 | 
			
		||||
      , self_(std::move(self))
 | 
			
		||||
      , client_only_(client_only)
 | 
			
		||||
      , print_id_(print_id)
 | 
			
		||||
      , src_(src)
 | 
			
		||||
      , k_(k)
 | 
			
		||||
      , a_(a)
 | 
			
		||||
      , node_(node)
 | 
			
		||||
      , adnl_(adnl) {
 | 
			
		||||
    add_nodes(std::move(list));
 | 
			
		||||
  }
 | 
			
		||||
  DhtMember::PrintId print_id() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,9 +104,10 @@ class DhtQueryFindNodes : public DhtQuery {
 | 
			
		|||
 | 
			
		||||
 public:
 | 
			
		||||
  DhtQueryFindNodes(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list,
 | 
			
		||||
                    td::uint32 k, td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                    td::uint32 k, td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                    td::actor::ActorId<adnl::Adnl> adnl, td::Promise<DhtNodesList> promise)
 | 
			
		||||
      : DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), node, adnl), promise_(std::move(promise)) {
 | 
			
		||||
      : DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), client_only, node, adnl)
 | 
			
		||||
      , promise_(std::move(promise)) {
 | 
			
		||||
  }
 | 
			
		||||
  void send_one_query(adnl::AdnlNodeIdShort id) override;
 | 
			
		||||
  void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
 | 
			
		||||
| 
						 | 
				
			
			@ -112,9 +123,10 @@ class DhtQueryFindValue : public DhtQuery {
 | 
			
		|||
 | 
			
		||||
 public:
 | 
			
		||||
  DhtQueryFindValue(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list,
 | 
			
		||||
                    td::uint32 k, td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                    td::uint32 k, td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                    td::actor::ActorId<adnl::Adnl> adnl, td::Promise<DhtValue> promise)
 | 
			
		||||
      : DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), node, adnl), promise_(std::move(promise)) {
 | 
			
		||||
      : DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), client_only, node, adnl)
 | 
			
		||||
      , promise_(std::move(promise)) {
 | 
			
		||||
  }
 | 
			
		||||
  void send_one_query(adnl::AdnlNodeIdShort id) override;
 | 
			
		||||
  void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
 | 
			
		||||
| 
						 | 
				
			
			@ -139,10 +151,11 @@ class DhtQueryStore : public td::actor::Actor {
 | 
			
		|||
  td::uint32 remaining_;
 | 
			
		||||
  DhtNodesList list_;
 | 
			
		||||
  DhtNode self_;
 | 
			
		||||
  bool client_only_;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list,
 | 
			
		||||
                td::uint32 k, td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                td::uint32 k, td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                td::actor::ActorId<adnl::Adnl> adnl, td::Promise<td::Unit> promise);
 | 
			
		||||
  void send_stores(td::Result<DhtNodesList> res);
 | 
			
		||||
  void store_ready(td::Result<td::BufferSlice> res);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ td::Status DhtRemoteNode::update_value(DhtNode node, td::actor::ActorId<adnl::Ad
 | 
			
		|||
  return td::Status::OK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DhtRemoteNode::send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
void DhtRemoteNode::send_ping(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                              adnl::AdnlNodeIdShort src) {
 | 
			
		||||
  missed_pings_++;
 | 
			
		||||
  if (missed_pings_ > max_missed_pings_ && ready_from_ > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,37 +75,42 @@ void DhtRemoteNode::send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::Ac
 | 
			
		|||
 | 
			
		||||
  td::actor::send_closure(adnl, &adnl::Adnl::add_peer, src, node_.adnl_id(), node_.addr_list());
 | 
			
		||||
 | 
			
		||||
  auto P = td::PromiseCreator::lambda(
 | 
			
		||||
      [key = id_, id = node_.adnl_id().compute_short_id(), node, src, adnl](td::Result<DhtNode> R) mutable {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "[dht]: failed to get self node";
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        auto P = td::PromiseCreator::lambda([key, node, adnl](td::Result<td::BufferSlice> R) {
 | 
			
		||||
          if (R.is_error()) {
 | 
			
		||||
            VLOG(DHT_INFO) << "[dht]: received error for query to " << key << ": " << R.move_as_error();
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
          auto F = fetch_tl_object<ton_api::dht_node>(R.move_as_ok(), true);
 | 
			
		||||
  auto P = td::PromiseCreator::lambda([key = id_, id = node_.adnl_id().compute_short_id(), client_only, node, src,
 | 
			
		||||
                                       adnl](td::Result<DhtNode> R) mutable {
 | 
			
		||||
    if (R.is_error()) {
 | 
			
		||||
      LOG(ERROR) << "[dht]: failed to get self node";
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    auto P = td::PromiseCreator::lambda([key, node, adnl](td::Result<td::BufferSlice> R) {
 | 
			
		||||
      if (R.is_error()) {
 | 
			
		||||
        VLOG(DHT_INFO) << "[dht]: received error for query to " << key << ": " << R.move_as_error();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      auto F = fetch_tl_object<ton_api::dht_node>(R.move_as_ok(), true);
 | 
			
		||||
 | 
			
		||||
          if (F.is_ok()) {
 | 
			
		||||
            auto N = DhtNode::create(F.move_as_ok());
 | 
			
		||||
            if (N.is_ok()) {
 | 
			
		||||
              td::actor::send_closure(node, &DhtMember::receive_ping, key, N.move_as_ok());
 | 
			
		||||
            } else {
 | 
			
		||||
              VLOG(DHT_WARNING) << "[dht]: bad answer from " << key
 | 
			
		||||
                                << ": dropping bad getSignedAddressList() query answer: " << N.move_as_error();
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            VLOG(DHT_WARNING) << "[dht]: bad answer from " << key
 | 
			
		||||
                              << ": dropping invalid getSignedAddressList() query answer: " << F.move_as_error();
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
        auto Q = create_serialize_tl_object<ton_api::dht_getSignedAddressList>();
 | 
			
		||||
        auto B = create_serialize_tl_object_suffix<ton_api::dht_query>(Q.as_slice(), R.move_as_ok().tl());
 | 
			
		||||
        td::actor::send_closure(adnl, &adnl::Adnl::send_query, src, id, "dht ping", std::move(P),
 | 
			
		||||
                                td::Timestamp::in(10.0 + td::Random::fast(0, 100) * 0.1), std::move(B));
 | 
			
		||||
      });
 | 
			
		||||
      if (F.is_ok()) {
 | 
			
		||||
        auto N = DhtNode::create(F.move_as_ok());
 | 
			
		||||
        if (N.is_ok()) {
 | 
			
		||||
          td::actor::send_closure(node, &DhtMember::receive_ping, key, N.move_as_ok());
 | 
			
		||||
        } else {
 | 
			
		||||
          VLOG(DHT_WARNING) << "[dht]: bad answer from " << key
 | 
			
		||||
                            << ": dropping bad getSignedAddressList() query answer: " << N.move_as_error();
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        VLOG(DHT_WARNING) << "[dht]: bad answer from " << key
 | 
			
		||||
                          << ": dropping invalid getSignedAddressList() query answer: " << F.move_as_error();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    auto Q = create_serialize_tl_object<ton_api::dht_getSignedAddressList>();
 | 
			
		||||
    td::BufferSlice B;
 | 
			
		||||
    if (client_only) {
 | 
			
		||||
      B = std::move(Q);
 | 
			
		||||
    } else {
 | 
			
		||||
      B = create_serialize_tl_object_suffix<ton_api::dht_query>(Q.as_slice(), R.move_as_ok().tl());
 | 
			
		||||
    }
 | 
			
		||||
    td::actor::send_closure(adnl, &adnl::Adnl::send_query, src, id, "dht ping", std::move(P),
 | 
			
		||||
                            td::Timestamp::in(10.0 + td::Random::fast(0, 100) * 0.1), std::move(B));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  td::actor::send_closure(node, &DhtMember::get_self_node, std::move(P));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,8 @@ class DhtRemoteNode {
 | 
			
		|||
  double last_ping_at() const {
 | 
			
		||||
    return last_ping_at_;
 | 
			
		||||
  }
 | 
			
		||||
  void send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src);
 | 
			
		||||
  void send_ping(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
 | 
			
		||||
                 adnl::AdnlNodeIdShort src);
 | 
			
		||||
  td::Status receive_ping(DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id);
 | 
			
		||||
  td::Status update_value(DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										135
									
								
								dht/dht.cpp
									
										
									
									
									
								
							
							
						
						
									
										135
									
								
								dht/dht.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "dht.hpp"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,9 +44,10 @@ namespace dht {
 | 
			
		|||
 | 
			
		||||
td::actor::ActorOwn<DhtMember> DhtMember::create(adnl::AdnlNodeIdShort id, std::string db_root,
 | 
			
		||||
                                                 td::actor::ActorId<keyring::Keyring> keyring,
 | 
			
		||||
                                                 td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a) {
 | 
			
		||||
                                                 td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a,
 | 
			
		||||
                                                 bool client_only) {
 | 
			
		||||
  return td::actor::ActorOwn<DhtMember>(
 | 
			
		||||
      td::actor::create_actor<DhtMemberImpl>("dht", id, db_root, keyring, adnl, k, a));
 | 
			
		||||
      td::actor::create_actor<DhtMemberImpl>("dht", id, db_root, keyring, adnl, k, a, client_only));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Result<td::actor::ActorOwn<Dht>> Dht::create(adnl::AdnlNodeIdShort id, std::string db_root,
 | 
			
		||||
| 
						 | 
				
			
			@ -66,9 +67,24 @@ td::Result<td::actor::ActorOwn<Dht>> Dht::create(adnl::AdnlNodeIdShort id, std::
 | 
			
		|||
  return std::move(D);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Result<td::actor::ActorOwn<Dht>> Dht::create_client(adnl::AdnlNodeIdShort id, std::string db_root,
 | 
			
		||||
                                                        std::shared_ptr<DhtGlobalConfig> conf,
 | 
			
		||||
                                                        td::actor::ActorId<keyring::Keyring> keyring,
 | 
			
		||||
                                                        td::actor::ActorId<adnl::Adnl> adnl) {
 | 
			
		||||
  CHECK(conf->get_k() > 0);
 | 
			
		||||
  CHECK(conf->get_a() > 0);
 | 
			
		||||
 | 
			
		||||
  auto D = DhtMember::create(id, db_root, keyring, adnl, conf->get_k(), conf->get_a(), true);
 | 
			
		||||
  auto &nodes = conf->nodes();
 | 
			
		||||
 | 
			
		||||
  for (auto &node : nodes.list()) {
 | 
			
		||||
    auto key = node.get_key();
 | 
			
		||||
    td::actor::send_closure(D, &DhtMember::add_full_node, key, node.clone());
 | 
			
		||||
  }
 | 
			
		||||
  return std::move(D);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DhtMemberImpl::start_up() {
 | 
			
		||||
  std::shared_ptr<td::KeyValue> kv = std::make_shared<td::RocksDb>(
 | 
			
		||||
      td::RocksDb::open(PSTRING() << db_root_ << "/dht-" << td::base64url_encode(id_.as_slice())).move_as_ok());
 | 
			
		||||
  std::vector<td::int32> methods = {ton_api::dht_getSignedAddressList::ID,
 | 
			
		||||
                                    ton_api::dht_findNode::ID,
 | 
			
		||||
                                    ton_api::dht_findValue::ID,
 | 
			
		||||
| 
						 | 
				
			
			@ -82,26 +98,31 @@ void DhtMemberImpl::start_up() {
 | 
			
		|||
                            std::make_unique<Callback>(actor_id(this), id_));
 | 
			
		||||
  }
 | 
			
		||||
  alarm_timestamp() = td::Timestamp::in(1.0);
 | 
			
		||||
  for (td::uint32 bit = 0; bit < 256; bit++) {
 | 
			
		||||
    auto key = create_hash_tl_object<ton_api::dht_db_key_bucket>(bit);
 | 
			
		||||
    std::string value;
 | 
			
		||||
    auto R = kv->get(key.as_slice(), value);
 | 
			
		||||
    R.ensure();
 | 
			
		||||
    if (R.move_as_ok() == td::KeyValue::GetStatus::Ok) {
 | 
			
		||||
      auto V = fetch_tl_object<ton_api::dht_db_bucket>(td::BufferSlice{value}, true);
 | 
			
		||||
      V.ensure();
 | 
			
		||||
      auto nodes = std::move(V.move_as_ok()->nodes_);
 | 
			
		||||
      auto s = nodes->nodes_.size();
 | 
			
		||||
      DhtNodesList list{std::move(nodes)};
 | 
			
		||||
      CHECK(list.size() == s);
 | 
			
		||||
      auto &B = buckets_[bit];
 | 
			
		||||
      for (auto &node : list.list()) {
 | 
			
		||||
        auto key = node.get_key();
 | 
			
		||||
        B.add_full_node(key, std::move(node), adnl_, id_);
 | 
			
		||||
 | 
			
		||||
  if (!db_root_.empty()) {
 | 
			
		||||
    std::shared_ptr<td::KeyValue> kv = std::make_shared<td::RocksDb>(
 | 
			
		||||
        td::RocksDb::open(PSTRING() << db_root_ << "/dht-" << td::base64url_encode(id_.as_slice())).move_as_ok());
 | 
			
		||||
    for (td::uint32 bit = 0; bit < 256; bit++) {
 | 
			
		||||
      auto key = create_hash_tl_object<ton_api::dht_db_key_bucket>(bit);
 | 
			
		||||
      std::string value;
 | 
			
		||||
      auto R = kv->get(key.as_slice(), value);
 | 
			
		||||
      R.ensure();
 | 
			
		||||
      if (R.move_as_ok() == td::KeyValue::GetStatus::Ok) {
 | 
			
		||||
        auto V = fetch_tl_object<ton_api::dht_db_bucket>(td::BufferSlice{value}, true);
 | 
			
		||||
        V.ensure();
 | 
			
		||||
        auto nodes = std::move(V.move_as_ok()->nodes_);
 | 
			
		||||
        auto s = nodes->nodes_.size();
 | 
			
		||||
        DhtNodesList list{std::move(nodes)};
 | 
			
		||||
        CHECK(list.size() == s);
 | 
			
		||||
        auto &B = buckets_[bit];
 | 
			
		||||
        for (auto &node : list.list()) {
 | 
			
		||||
          auto key = node.get_key();
 | 
			
		||||
          B.add_full_node(key, std::move(node), adnl_, id_);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    db_ = DbType{std::move(kv)};
 | 
			
		||||
  }
 | 
			
		||||
  db_ = DbType{std::move(kv)};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DhtMemberImpl::tear_down() {
 | 
			
		||||
| 
						 | 
				
			
			@ -119,6 +140,9 @@ void DhtMemberImpl::tear_down() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void DhtMemberImpl::save_to_db() {
 | 
			
		||||
  if (db_root_.empty()) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  next_save_to_db_at_ = td::Timestamp::in(10.0);
 | 
			
		||||
  alarm_timestamp().relax(next_save_to_db_at_);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -277,6 +301,9 @@ void DhtMemberImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::dht_getSig
 | 
			
		|||
 | 
			
		||||
void DhtMemberImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
 | 
			
		||||
                                  td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  if (client_only_) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  {
 | 
			
		||||
    auto R = fetch_tl_prefix<ton_api::dht_query>(data, true);
 | 
			
		||||
    if (R.is_ok()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -358,11 +385,11 @@ void DhtMemberImpl::set_value(DhtValue value, td::Promise<td::Unit> promise) {
 | 
			
		|||
 | 
			
		||||
void DhtMemberImpl::get_value_in(DhtKeyId key, td::Promise<DhtValue> result) {
 | 
			
		||||
  auto P = td::PromiseCreator::lambda([key, promise = std::move(result), SelfId = actor_id(this), print_id = print_id(),
 | 
			
		||||
                                       adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_, a = a_,
 | 
			
		||||
                                       id = id_](td::Result<DhtNode> R) mutable {
 | 
			
		||||
                                       adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_, a = a_, id = id_,
 | 
			
		||||
                                       client_only = client_only_](td::Result<DhtNode> R) mutable {
 | 
			
		||||
    R.ensure();
 | 
			
		||||
    td::actor::create_actor<DhtQueryFindValue>("FindValueQuery", key, print_id, id, std::move(list), k, a,
 | 
			
		||||
                                               R.move_as_ok(), SelfId, adnl, std::move(promise))
 | 
			
		||||
                                               R.move_as_ok(), client_only, SelfId, adnl, std::move(promise))
 | 
			
		||||
        .release();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -374,7 +401,7 @@ void DhtMemberImpl::check() {
 | 
			
		|||
                 << " fvalue=" << find_value_queries_ << " store=" << store_queries_
 | 
			
		||||
                 << " addrlist=" << get_addr_list_queries_;
 | 
			
		||||
  for (auto &bucket : buckets_) {
 | 
			
		||||
    bucket.check(adnl_, actor_id(this), id_);
 | 
			
		||||
    bucket.check(client_only_, adnl_, actor_id(this), id_);
 | 
			
		||||
  }
 | 
			
		||||
  if (next_save_to_db_at_.is_in_past()) {
 | 
			
		||||
    save_to_db();
 | 
			
		||||
| 
						 | 
				
			
			@ -469,10 +496,10 @@ void DhtMemberImpl::check() {
 | 
			
		|||
    DhtKeyId key{x};
 | 
			
		||||
    auto P = td::PromiseCreator::lambda([key, promise = std::move(promise), SelfId = actor_id(this),
 | 
			
		||||
                                         print_id = print_id(), adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_,
 | 
			
		||||
                                         a = a_, id = id_](td::Result<DhtNode> R) mutable {
 | 
			
		||||
                                         a = a_, id = id_, client_only = client_only_](td::Result<DhtNode> R) mutable {
 | 
			
		||||
      R.ensure();
 | 
			
		||||
      td::actor::create_actor<DhtQueryFindNodes>("FindNodesQuery", key, print_id, id, std::move(list), k, a,
 | 
			
		||||
                                                 R.move_as_ok(), SelfId, adnl, std::move(promise))
 | 
			
		||||
                                                 R.move_as_ok(), client_only, SelfId, adnl, std::move(promise))
 | 
			
		||||
          .release();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -492,35 +519,39 @@ void DhtMemberImpl::send_store(DhtValue value, td::Promise<td::Unit> promise) {
 | 
			
		|||
  value.check().ensure();
 | 
			
		||||
  auto key_id = value.key_id();
 | 
			
		||||
 | 
			
		||||
  auto P = td::PromiseCreator::lambda([value = std::move(value), print_id = print_id(), id = id_,
 | 
			
		||||
                                       list = get_nearest_nodes(key_id, k_), k = k_, a = a_, SelfId = actor_id(this),
 | 
			
		||||
                                       adnl = adnl_, promise = std::move(promise)](td::Result<DhtNode> R) mutable {
 | 
			
		||||
    R.ensure();
 | 
			
		||||
    td::actor::create_actor<DhtQueryStore>("StoreQuery", std::move(value), print_id, id, std::move(list), k, a,
 | 
			
		||||
                                           R.move_as_ok(), SelfId, adnl, std::move(promise))
 | 
			
		||||
        .release();
 | 
			
		||||
  });
 | 
			
		||||
  auto P =
 | 
			
		||||
      td::PromiseCreator::lambda([value = std::move(value), print_id = print_id(), id = id_, client_only = client_only_,
 | 
			
		||||
                                  list = get_nearest_nodes(key_id, k_), k = k_, a = a_, SelfId = actor_id(this),
 | 
			
		||||
                                  adnl = adnl_, promise = std::move(promise)](td::Result<DhtNode> R) mutable {
 | 
			
		||||
        R.ensure();
 | 
			
		||||
        td::actor::create_actor<DhtQueryStore>("StoreQuery", std::move(value), print_id, id, std::move(list), k, a,
 | 
			
		||||
                                               R.move_as_ok(), client_only, SelfId, adnl, std::move(promise))
 | 
			
		||||
            .release();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
  get_self_node(std::move(P));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DhtMemberImpl::get_self_node(td::Promise<DhtNode> promise) {
 | 
			
		||||
  auto P = td::PromiseCreator::lambda([promise = std::move(promise), print_id = print_id(), id = id_,
 | 
			
		||||
                                       keyring = keyring_](td::Result<adnl::AdnlNode> R) mutable {
 | 
			
		||||
    R.ensure();
 | 
			
		||||
    auto node = R.move_as_ok();
 | 
			
		||||
    auto version = static_cast<td::int32>(td::Clocks::system());
 | 
			
		||||
    auto B = create_serialize_tl_object<ton_api::dht_node>(node.pub_id().tl(), node.addr_list().tl(), version,
 | 
			
		||||
                                                           td::BufferSlice());
 | 
			
		||||
    CHECK(node.addr_list().size() > 0);
 | 
			
		||||
    auto P = td::PromiseCreator::lambda(
 | 
			
		||||
        [promise = std::move(promise), node = std::move(node), version](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
          R.ensure();
 | 
			
		||||
          DhtNode n{node.pub_id(), node.addr_list(), version, R.move_as_ok()};
 | 
			
		||||
          promise.set_result(std::move(n));
 | 
			
		||||
        });
 | 
			
		||||
    td::actor::send_closure(keyring, &keyring::Keyring::sign_message, id.pubkey_hash(), std::move(B), std::move(P));
 | 
			
		||||
  });
 | 
			
		||||
  auto P =
 | 
			
		||||
      td::PromiseCreator::lambda([promise = std::move(promise), print_id = print_id(), id = id_, keyring = keyring_,
 | 
			
		||||
                                  client_only = client_only_](td::Result<adnl::AdnlNode> R) mutable {
 | 
			
		||||
        R.ensure();
 | 
			
		||||
        auto node = R.move_as_ok();
 | 
			
		||||
        auto version = static_cast<td::int32>(td::Clocks::system());
 | 
			
		||||
        auto B = create_serialize_tl_object<ton_api::dht_node>(node.pub_id().tl(), node.addr_list().tl(), version,
 | 
			
		||||
                                                               td::BufferSlice());
 | 
			
		||||
        if (!client_only) {
 | 
			
		||||
          CHECK(node.addr_list().size() > 0);
 | 
			
		||||
        }
 | 
			
		||||
        auto P = td::PromiseCreator::lambda(
 | 
			
		||||
            [promise = std::move(promise), node = std::move(node), version](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
              R.ensure();
 | 
			
		||||
              DhtNode n{node.pub_id(), node.addr_list(), version, R.move_as_ok()};
 | 
			
		||||
              promise.set_result(std::move(n));
 | 
			
		||||
            });
 | 
			
		||||
        td::actor::send_closure(keyring, &keyring::Keyring::sign_message, id.pubkey_hash(), std::move(B), std::move(P));
 | 
			
		||||
      });
 | 
			
		||||
  td::actor::send_closure(adnl_, &adnl::Adnl::get_self_node, id_, std::move(P));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,10 @@ class Dht : public td::actor::Actor {
 | 
			
		|||
                                                     std::shared_ptr<DhtGlobalConfig> conf,
 | 
			
		||||
                                                     td::actor::ActorId<keyring::Keyring> keyring,
 | 
			
		||||
                                                     td::actor::ActorId<adnl::Adnl> adnl);
 | 
			
		||||
  static td::Result<td::actor::ActorOwn<Dht>> create_client(adnl::AdnlNodeIdShort id, std::string db_root,
 | 
			
		||||
                                                            std::shared_ptr<DhtGlobalConfig> conf,
 | 
			
		||||
                                                            td::actor::ActorId<keyring::Keyring> keyring,
 | 
			
		||||
                                                            td::actor::ActorId<adnl::Adnl> adnl);
 | 
			
		||||
  static td::Result<std::shared_ptr<DhtGlobalConfig>> create_global_config(
 | 
			
		||||
      tl_object_ptr<ton_api::dht_config_global> conf);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,8 +85,8 @@ class DhtMember : public Dht {
 | 
			
		|||
 | 
			
		||||
  static td::actor::ActorOwn<DhtMember> create(adnl::AdnlNodeIdShort id, std::string db_root,
 | 
			
		||||
                                               td::actor::ActorId<keyring::Keyring> keyring,
 | 
			
		||||
                                               td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k = 10,
 | 
			
		||||
                                               td::uint32 a = 3);
 | 
			
		||||
                                               td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k = 10, td::uint32 a = 3,
 | 
			
		||||
                                               bool client_only = false);
 | 
			
		||||
 | 
			
		||||
  //virtual void update_addr_list(tl_object_ptr<ton_api::adnl_addressList> addr_list) = 0;
 | 
			
		||||
  //virtual void add_node(adnl::AdnlNodeIdShort id) = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2140,6 +2140,10 @@ These primitives are completely similar to their non-prefix code counterparts {\
 | 
			
		|||
\item {\tt F4AA} --- {\tt PFXDICTGETJMP} ($s$ $D$ $n$ -- $s'$ $s''$ or $s$), similar to {\tt PFXDICTGETQ}, but on success {\tt BLESS}es the value $x$ into a {\em Continuation\/} and transfers control to it as if by a {\tt JMPX}. On failure, returns $s$ unchanged and continues execution.
 | 
			
		||||
\item {\tt F4AB} --- {\tt PFXDICTGETEXEC} ($s$ $D$ $n$ -- $s'$ $s''$), similar to {\tt PFXDICTGETJMP}, but {\tt EXEC}utes the continuation found instead of jumping to it. On failure, throws a cell deserialization exception.
 | 
			
		||||
\item {\tt F4AE\_$n$} --- {\tt PFXDICTCONSTGETJMP $n$} or {\tt PFXDICTSWITCH $n$} ($s$ -- $s'$ $s''$ or $s$), combines {\tt DICTPUSHCONST $n$} for $0\leq n\leq 1023$ with {\tt PFXDICTGETJMP}.
 | 
			
		||||
\item {\tt F4BC} --- {\tt DICTIGETJMPZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTIGETJMP} that returns index $i$ on failure.
 | 
			
		||||
\item {\tt F4BD} --- {\tt DICTUGETJMPZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTUGETJMP} that returns index $i$ on failure.
 | 
			
		||||
\item {\tt F4BE} --- {\tt DICTIGETEXECZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTIGETEXEC} that returns index $i$ on failure.
 | 
			
		||||
\item {\tt F4BF} --- {\tt DICTUGETEXECZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTUGETEXEC} that returns index $i$ on failure.
 | 
			
		||||
\end{itemize}
 | 
			
		||||
 | 
			
		||||
\nxsubpoint\label{sp:prim.dict.get}\emb{{\sc SubDict} dictionary operations}
 | 
			
		||||
| 
						 | 
				
			
			@ -2150,6 +2154,7 @@ These primitives are completely similar to their non-prefix code counterparts {\
 | 
			
		|||
\item {\tt F4B5} --- {\tt SUBDICTRPGET} ($k$ $l$ $D$ $n$ -- $D'$), similar to {\tt SUBDICTGET}, but removes the common prefix $k$ from all keys of the new dictionary $D'$, which becomes of type $\HashmapE(n-l,X)$.
 | 
			
		||||
\item {\tt F4B6} --- {\tt SUBDICTIRPGET} ($x$ $l$ $D$ $n$ -- $D'$), variant of {\tt SUBDICTRPGET} with the prefix represented by a signed big-endian $l$-bit {\em Integer\/}~$x$, where necessarily $l\leq257$.
 | 
			
		||||
\item {\tt F4B7} --- {\tt SUBDICTURPGET} ($x$ $l$ $D$ $n$ -- $D'$), variant of {\tt SUBDICTRPGET} with the prefix represented by an unsigned big-endian $l$-bit {\em Integer\/}~$x$, where necessarily $l\leq256$.
 | 
			
		||||
\item {\tt F4BC}--{\tt F4BF} --- used by {\tt DICT\dots Z} primitives in \ptref{sp:prim.dict.get.spec}.
 | 
			
		||||
\end{itemize}
 | 
			
		||||
 | 
			
		||||
\mysubsection{Application-specific primitives}\label{p:prim.app}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "keyring.hpp"
 | 
			
		||||
#include "common/errorcode.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,9 @@ namespace ton {
 | 
			
		|||
namespace keyring {
 | 
			
		||||
 | 
			
		||||
void KeyringImpl::start_up() {
 | 
			
		||||
  td::mkdir(db_root_).ensure();
 | 
			
		||||
  if (db_root_.size() > 0) {
 | 
			
		||||
    td::mkdir(db_root_).ensure();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash key_hash) {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +39,10 @@ td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash k
 | 
			
		|||
    return it->second.get();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (db_root_.size() == 0) {
 | 
			
		||||
    return td::Status::Error(ErrorCode::notready, "key not in db");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto name = db_root_ + "/" + key_hash.bits256_value().to_hex();
 | 
			
		||||
 | 
			
		||||
  auto R = td::read_file(td::CSlice{name});
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +73,9 @@ void KeyringImpl::add_key(PrivateKey key, bool is_temp, td::Promise<td::Unit> pr
 | 
			
		|||
    promise.set_value(td::Unit());
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (db_root_.size() == 0) {
 | 
			
		||||
    CHECK(is_temp);
 | 
			
		||||
  }
 | 
			
		||||
  auto D = key.create_decryptor_async();
 | 
			
		||||
  D.ensure();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +112,9 @@ void KeyringImpl::add_key_short(PublicKeyHash key_hash, td::Promise<PublicKey> p
 | 
			
		|||
 | 
			
		||||
void KeyringImpl::del_key(PublicKeyHash key_hash, td::Promise<td::Unit> promise) {
 | 
			
		||||
  map_.erase(key_hash);
 | 
			
		||||
  if (db_root_.size() == 0) {
 | 
			
		||||
    return promise.set_value(td::Unit());
 | 
			
		||||
  }
 | 
			
		||||
  auto name = db_root_ + "/" + key_hash.bits256_value().to_hex();
 | 
			
		||||
  td::BufferSlice d{256};
 | 
			
		||||
  td::Random::secure_bytes(d.as_slice());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
    exception statement from your version. If you delete this exception statement 
 | 
			
		||||
    from all source files in the program, then also delete it here.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "lite-client.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -800,7 +800,7 @@ bool TestNode::show_help(std::string command) {
 | 
			
		|||
         "saveaccount[code|data] <filename> <addr> [<block-id-ext>]\tSaves into specified file the most recent state "
 | 
			
		||||
         "(StateInit) or just the code or data of specified account; <addr> is in "
 | 
			
		||||
         "[<workchain>:]<hex-or-base64-addr> format\n"
 | 
			
		||||
         "runmethod <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account <addr> "
 | 
			
		||||
         "runmethod[x] <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account <addr> "
 | 
			
		||||
         "with specified parameters\n"
 | 
			
		||||
         "allshards [<block-id-ext>]\tShows shard configuration from the most recent masterchain "
 | 
			
		||||
         "state or from masterchain state corresponding to <block-id-ext>\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -871,11 +871,11 @@ bool TestNode::do_parse_line() {
 | 
			
		|||
           (seekeoln()
 | 
			
		||||
                ? get_account_state(workchain, addr, mc_last_id_, filename, mode)
 | 
			
		||||
                : parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, filename, mode));
 | 
			
		||||
  } else if (word == "runmethod") {
 | 
			
		||||
  } else if (word == "runmethod" || word == "runmethodx") {
 | 
			
		||||
    std::string method;
 | 
			
		||||
    return parse_account_addr(workchain, addr) && get_word_to(method) &&
 | 
			
		||||
           (parse_block_id_ext(method, blkid) ? get_word_to(method) : (blkid = mc_last_id_).is_valid()) &&
 | 
			
		||||
           parse_run_method(workchain, addr, blkid, method);
 | 
			
		||||
           parse_run_method(workchain, addr, blkid, method, word.size() > 9);
 | 
			
		||||
  } else if (word == "allshards") {
 | 
			
		||||
    return eoln() ? get_all_shards() : (parse_block_id_ext(blkid) && seekeoln() && get_all_shards(false, blkid));
 | 
			
		||||
  } else if (word == "saveconfig") {
 | 
			
		||||
| 
						 | 
				
			
			@ -1015,8 +1015,16 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
			
		|||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::int64 TestNode::compute_method_id(std::string method) {
 | 
			
		||||
  td::int64 method_id;
 | 
			
		||||
  if (!convert_int64(method, method_id)) {
 | 
			
		||||
    method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000;
 | 
			
		||||
  }
 | 
			
		||||
  return method_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
 | 
			
		||||
                                std::string method_name) {
 | 
			
		||||
                                std::string method_name, bool ext_mode) {
 | 
			
		||||
  auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_));
 | 
			
		||||
  if (R.is_error()) {
 | 
			
		||||
    return set_error(R.move_as_error().to_string());
 | 
			
		||||
| 
						 | 
				
			
			@ -1030,28 +1038,69 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
			
		|||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  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_getAccountState>(
 | 
			
		||||
                                        ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
			
		||||
                                    true);
 | 
			
		||||
  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";
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [ Self = actor_id(this), workchain, addr, ref_blkid, method_name,
 | 
			
		||||
                      params = std::move(params) ](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(R.move_as_ok(), true);
 | 
			
		||||
        if (F.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot parse answer to liteServer.getAccountState";
 | 
			
		||||
        } else {
 | 
			
		||||
          auto f = F.move_as_ok();
 | 
			
		||||
          td::actor::send_closure_later(Self, &TestNode::run_smc_method, ref_blkid, ton::create_block_id(f->id_),
 | 
			
		||||
                                        ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
 | 
			
		||||
                                        std::move(f->proof_), std::move(f->state_), workchain, addr, method_name,
 | 
			
		||||
                                        std::move(params));
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
  int mode = (ext_mode ? 0x1f : 0);
 | 
			
		||||
  if (!mode) {
 | 
			
		||||
    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)),
 | 
			
		||||
                                      true);
 | 
			
		||||
    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";
 | 
			
		||||
    return envelope_send_query(
 | 
			
		||||
        std::move(b), [ Self = actor_id(this), workchain, addr, ref_blkid, method_name,
 | 
			
		||||
                        params = std::move(params) ](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
          if (R.is_error()) {
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
          auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(R.move_as_ok(), true);
 | 
			
		||||
          if (F.is_error()) {
 | 
			
		||||
            LOG(ERROR) << "cannot parse answer to liteServer.getAccountState";
 | 
			
		||||
          } else {
 | 
			
		||||
            auto f = F.move_as_ok();
 | 
			
		||||
            td::actor::send_closure_later(Self, &TestNode::run_smc_method, 0, ref_blkid, ton::create_block_id(f->id_),
 | 
			
		||||
                                          ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
 | 
			
		||||
                                          std::move(f->proof_), std::move(f->state_), workchain, addr, method_name,
 | 
			
		||||
                                          std::move(params), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(),
 | 
			
		||||
                                          -0x10000);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
  } else {
 | 
			
		||||
    td::int64 method_id = compute_method_id(method_name);
 | 
			
		||||
    // serialize parameters
 | 
			
		||||
    vm::CellBuilder cb;
 | 
			
		||||
    Ref<vm::Cell> cell;
 | 
			
		||||
    if (!(vm::Stack{params}.serialize(cb) && cb.finalize_to(cell))) {
 | 
			
		||||
      return set_error("cannot serialize stack with get-method parameters");
 | 
			
		||||
    }
 | 
			
		||||
    auto stk = vm::std_boc_serialize(std::move(cell));
 | 
			
		||||
    if (stk.is_error()) {
 | 
			
		||||
      return set_error("cannot serialize stack with get-method parameters : "s + stk.move_as_error().to_string());
 | 
			
		||||
    }
 | 
			
		||||
    auto b = ton::serialize_tl_object(
 | 
			
		||||
        ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>(mode, ton::create_tl_lite_block_id(ref_blkid),
 | 
			
		||||
                                                                      std::move(a), method_id, stk.move_as_ok()),
 | 
			
		||||
        true);
 | 
			
		||||
    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 "
 | 
			
		||||
              << params.size() << " parameters";
 | 
			
		||||
    return envelope_send_query(std::move(b), [
 | 
			
		||||
      Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params)
 | 
			
		||||
    ](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
      if (R.is_error()) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      auto F = ton::fetch_tl_object<ton::lite_api::liteServer_runMethodResult>(R.move_as_ok(), true);
 | 
			
		||||
      if (F.is_error()) {
 | 
			
		||||
        LOG(ERROR) << "cannot parse answer to liteServer.runSmcMethod";
 | 
			
		||||
      } else {
 | 
			
		||||
        auto f = F.move_as_ok();
 | 
			
		||||
        td::actor::send_closure_later(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_),
 | 
			
		||||
                                      std::move(f->proof_), std::move(f->state_proof_), workchain, addr, method_name,
 | 
			
		||||
                                      std::move(params), std::move(f->init_c7_), std::move(f->lib_extras_),
 | 
			
		||||
                                      std::move(f->result_), f->exit_code_);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workchain, ton::StdSmcAddress addr,
 | 
			
		||||
| 
						 | 
				
			
			@ -1212,87 +1261,147 @@ void TestNode::got_account_state(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, t
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
 | 
			
		||||
void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
 | 
			
		||||
                              td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
 | 
			
		||||
                              ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
 | 
			
		||||
                              std::vector<vm::StackEntry> params) {
 | 
			
		||||
  LOG(INFO) << "got account state for " << workchain << ":" << addr.to_hex() << " with respect to blocks "
 | 
			
		||||
            << blk.to_str() << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str());
 | 
			
		||||
  block::AccountState account_state;
 | 
			
		||||
  account_state.blk = blk;
 | 
			
		||||
  account_state.shard_blk = shard_blk;
 | 
			
		||||
  account_state.shard_proof = std::move(shard_proof);
 | 
			
		||||
  account_state.proof = std::move(proof);
 | 
			
		||||
  account_state.state = std::move(state);
 | 
			
		||||
  auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr));
 | 
			
		||||
  if (r_info.is_error()) {
 | 
			
		||||
    LOG(ERROR) << r_info.error().message();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
                              std::vector<vm::StackEntry> params, td::BufferSlice remote_c7,
 | 
			
		||||
                              td::BufferSlice remote_libs, td::BufferSlice remote_result, int remote_exit_code) {
 | 
			
		||||
  LOG(INFO) << "got (partial) account state with mode=" << mode << " for " << workchain << ":" << addr.to_hex()
 | 
			
		||||
            << " with respect to blocks " << blk.to_str()
 | 
			
		||||
            << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str());
 | 
			
		||||
  auto out = td::TerminalIO::out();
 | 
			
		||||
  auto info = r_info.move_as_ok();
 | 
			
		||||
  if (info.root.is_null()) {
 | 
			
		||||
    LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `" << method
 | 
			
		||||
               << "`)";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  block::gen::Account::Record_account acc;
 | 
			
		||||
  block::gen::AccountStorage::Record store;
 | 
			
		||||
  block::CurrencyCollection balance;
 | 
			
		||||
  if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) &&
 | 
			
		||||
        balance.validate_unpack(store.balance))) {
 | 
			
		||||
    LOG(ERROR) << "error unpacking account state";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  int tag = block::gen::t_AccountState.get_tag(*store.state);
 | 
			
		||||
  switch (tag) {
 | 
			
		||||
    case block::gen::AccountState::account_uninit:
 | 
			
		||||
      LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " not initialized yet (cannot run any methods)";
 | 
			
		||||
  try {
 | 
			
		||||
    block::AccountState account_state;
 | 
			
		||||
    account_state.blk = blk;
 | 
			
		||||
    account_state.shard_blk = shard_blk;
 | 
			
		||||
    account_state.shard_proof = std::move(shard_proof);
 | 
			
		||||
    account_state.proof = std::move(proof);
 | 
			
		||||
    LOG(DEBUG) << "serialized state is " << state.size() << " bytes";
 | 
			
		||||
    LOG(DEBUG) << "serialized remote c7 is " << remote_c7.size() << " bytes";
 | 
			
		||||
    account_state.state = std::move(state);
 | 
			
		||||
    account_state.is_virtualized = (mode > 0);
 | 
			
		||||
    auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr));
 | 
			
		||||
    if (r_info.is_error()) {
 | 
			
		||||
      LOG(ERROR) << r_info.error().message();
 | 
			
		||||
      return;
 | 
			
		||||
    case block::gen::AccountState::account_frozen:
 | 
			
		||||
      LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)";
 | 
			
		||||
    }
 | 
			
		||||
    auto out = td::TerminalIO::out();
 | 
			
		||||
    auto info = r_info.move_as_ok();
 | 
			
		||||
    if (info.root.is_null()) {
 | 
			
		||||
      LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `"
 | 
			
		||||
                 << method << "`)";
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
  CHECK(store.state.write().fetch_ulong(1) == 1);  // account_init$1 _:StateInit = AccountState;
 | 
			
		||||
  block::gen::StateInit::Record state_init;
 | 
			
		||||
  CHECK(tlb::csr_unpack(store.state, state_init));
 | 
			
		||||
  auto code = state_init.code->prefetch_ref();
 | 
			
		||||
  auto data = state_init.data->prefetch_ref();
 | 
			
		||||
  auto stack = td::make_ref<vm::Stack>(std::move(params));
 | 
			
		||||
  td::int64 method_id;
 | 
			
		||||
  if (!convert_int64(method, method_id)) {
 | 
			
		||||
    method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000;
 | 
			
		||||
  }
 | 
			
		||||
  stack.write().push_smallint(method_id);
 | 
			
		||||
  {
 | 
			
		||||
    std::ostringstream os;
 | 
			
		||||
    os << "arguments: ";
 | 
			
		||||
    stack->dump(os, 3);
 | 
			
		||||
    out << os.str();
 | 
			
		||||
  }
 | 
			
		||||
  long long gas_limit = vm::GasLimits::infty;
 | 
			
		||||
  // OstreamLogger ostream_logger(ctx.error_stream);
 | 
			
		||||
  // auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
 | 
			
		||||
  vm::GasLimits gas{gas_limit};
 | 
			
		||||
  LOG(DEBUG) << "creating VM";
 | 
			
		||||
  vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
 | 
			
		||||
  vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, acc.addr, balance));  // tuple with SmartContractInfo
 | 
			
		||||
  // vm.incr_stack_trace(1);    // enable stack dump after each step
 | 
			
		||||
  LOG(INFO) << "starting VM to run method `" << method << "` (" << method_id << ") of smart contract " << workchain
 | 
			
		||||
            << ":" << addr.to_hex();
 | 
			
		||||
  int exit_code = ~vm.run();
 | 
			
		||||
  LOG(DEBUG) << "VM terminated with exit code " << exit_code;
 | 
			
		||||
  if (exit_code != 0) {
 | 
			
		||||
    LOG(ERROR) << "VM terminated with error code " << exit_code;
 | 
			
		||||
    out << "result: error " << exit_code << std::endl;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  stack = vm.get_stack_ref();
 | 
			
		||||
  {
 | 
			
		||||
    std::ostringstream os;
 | 
			
		||||
    os << "result: ";
 | 
			
		||||
    stack->dump(os, 3);
 | 
			
		||||
    out << os.str();
 | 
			
		||||
    }
 | 
			
		||||
    if (false) {
 | 
			
		||||
      // DEBUG (dump state)
 | 
			
		||||
      std::ostringstream os;
 | 
			
		||||
      vm::CellSlice{vm::NoVm(), info.true_root}.print_rec(os);
 | 
			
		||||
      out << "dump of account state (proof): " << os.str() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    if (false && remote_c7.size()) {
 | 
			
		||||
      // DEBUG (dump remote_c7)
 | 
			
		||||
      auto r_c7 = vm::std_boc_deserialize(remote_c7).move_as_ok();
 | 
			
		||||
      std::ostringstream os;
 | 
			
		||||
      vm::StackEntry val;
 | 
			
		||||
      bool ok = val.deserialize(r_c7);
 | 
			
		||||
      val.dump(os);
 | 
			
		||||
      // os << std::endl;
 | 
			
		||||
      // block::gen::t_VmStackValue.print_ref(os, r_c7);
 | 
			
		||||
      // os << std::endl;
 | 
			
		||||
      // vm::CellSlice{vm::NoVmOrd(), r_c7}.print_rec(os);
 | 
			
		||||
      out << "remote_c7 (deserialized=" << ok << "): " << os.str() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    block::gen::Account::Record_account acc;
 | 
			
		||||
    block::gen::AccountStorage::Record store;
 | 
			
		||||
    block::CurrencyCollection balance;
 | 
			
		||||
    if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) &&
 | 
			
		||||
          balance.validate_unpack(store.balance))) {
 | 
			
		||||
      LOG(ERROR) << "error unpacking account state";
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    int tag = block::gen::t_AccountState.get_tag(*store.state);
 | 
			
		||||
    switch (tag) {
 | 
			
		||||
      case block::gen::AccountState::account_uninit:
 | 
			
		||||
        LOG(ERROR) << "account " << workchain << ":" << addr.to_hex()
 | 
			
		||||
                   << " not initialized yet (cannot run any methods)";
 | 
			
		||||
        return;
 | 
			
		||||
      case block::gen::AccountState::account_frozen:
 | 
			
		||||
        LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    CHECK(store.state.write().fetch_ulong(1) == 1);  // account_init$1 _:StateInit = AccountState;
 | 
			
		||||
    block::gen::StateInit::Record state_init;
 | 
			
		||||
    CHECK(tlb::csr_unpack(store.state, state_init));
 | 
			
		||||
    auto code = state_init.code->prefetch_ref();
 | 
			
		||||
    auto data = state_init.data->prefetch_ref();
 | 
			
		||||
    auto stack = td::make_ref<vm::Stack>(std::move(params));
 | 
			
		||||
    td::int64 method_id = compute_method_id(method);
 | 
			
		||||
    stack.write().push_smallint(method_id);
 | 
			
		||||
    {
 | 
			
		||||
      std::ostringstream os;
 | 
			
		||||
      os << "arguments: ";
 | 
			
		||||
      stack->dump(os, 3);
 | 
			
		||||
      out << os.str();
 | 
			
		||||
    }
 | 
			
		||||
    long long gas_limit = vm::GasLimits::infty;
 | 
			
		||||
    // OstreamLogger ostream_logger(ctx.error_stream);
 | 
			
		||||
    // auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
 | 
			
		||||
    vm::GasLimits gas{gas_limit};
 | 
			
		||||
    LOG(DEBUG) << "creating VM";
 | 
			
		||||
    vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
 | 
			
		||||
    vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()),
 | 
			
		||||
                                        balance));  // tuple with SmartContractInfo
 | 
			
		||||
    // vm.incr_stack_trace(1);    // enable stack dump after each step
 | 
			
		||||
    LOG(INFO) << "starting VM to run method `" << method << "` (" << method_id << ") of smart contract " << workchain
 | 
			
		||||
              << ":" << addr.to_hex();
 | 
			
		||||
    int exit_code = ~vm.run();
 | 
			
		||||
    LOG(DEBUG) << "VM terminated with exit code " << exit_code;
 | 
			
		||||
    if (mode > 0) {
 | 
			
		||||
      LOG(DEBUG) << "remote VM exit code is " << remote_exit_code;
 | 
			
		||||
    }
 | 
			
		||||
    if (exit_code != 0) {
 | 
			
		||||
      LOG(ERROR) << "VM terminated with error code " << exit_code;
 | 
			
		||||
      out << "result: error " << exit_code << std::endl;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    stack = vm.get_stack_ref();
 | 
			
		||||
    {
 | 
			
		||||
      std::ostringstream os;
 | 
			
		||||
      os << "result: ";
 | 
			
		||||
      stack->dump(os, 3);
 | 
			
		||||
      out << os.str();
 | 
			
		||||
    }
 | 
			
		||||
    if (mode & 4) {
 | 
			
		||||
      if (remote_result.empty()) {
 | 
			
		||||
        out << "remote result: <none>, exit code " << remote_exit_code;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto res = vm::std_boc_deserialize(std::move(remote_result));
 | 
			
		||||
        if (res.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot deserialize remote VM result boc: " << res.move_as_error();
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        auto cs = vm::load_cell_slice(res.move_as_ok());
 | 
			
		||||
        Ref<vm::Stack> remote_stack;
 | 
			
		||||
        if (!(vm::Stack::deserialize_to(cs, remote_stack, 0) && cs.empty_ext())) {
 | 
			
		||||
          LOG(ERROR) << "remote VM result boc cannot be deserialized as a VmStack";
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        std::ostringstream os;
 | 
			
		||||
        os << "remote result (not to be trusted): ";
 | 
			
		||||
        remote_stack->dump(os, 3);
 | 
			
		||||
        out << os.str();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (0) {  // DEBUG
 | 
			
		||||
      std::ostringstream os;
 | 
			
		||||
      LOG(DEBUG) << "dumping constructed proof";
 | 
			
		||||
      //vm::CellSlice{vm::NoVm(), pb.extract_proof()}.print_rec(os);
 | 
			
		||||
      out << "constructed state proof: " << os.str();
 | 
			
		||||
    }
 | 
			
		||||
  } catch (vm::VmVirtError& err) {
 | 
			
		||||
    out << "virtualization error while parsing runSmcMethod result: " << err.get_msg();
 | 
			
		||||
  } catch (vm::VmError& err) {
 | 
			
		||||
    out << "error while parsing runSmcMethod result: " << err.get_msg();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2062,7 +2171,7 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int
 | 
			
		|||
  }
 | 
			
		||||
  auto root = res.move_as_ok();
 | 
			
		||||
  std::ostringstream outp;
 | 
			
		||||
  vm::CellSlice cs{vm::NoVm{}, root};
 | 
			
		||||
  vm::CellSlice cs{vm::NoVm(), root};
 | 
			
		||||
  cs.print_rec(outp);
 | 
			
		||||
  td::TerminalIO::out() << outp.str();
 | 
			
		||||
  try {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
    exception statement from your version. If you delete this exception statement 
 | 
			
		||||
    from all source files in the program, then also delete it here.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "adnl/adnl-ext-client.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -117,11 +117,12 @@ class TestNode : public td::actor::Actor {
 | 
			
		|||
                         td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
 | 
			
		||||
                         ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string filename, int mode);
 | 
			
		||||
  bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
 | 
			
		||||
                        std::string method_name);
 | 
			
		||||
  void run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
 | 
			
		||||
                        std::string method_name, bool ext_mode);
 | 
			
		||||
  void run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
 | 
			
		||||
                      td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
 | 
			
		||||
                      ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
 | 
			
		||||
                      std::vector<vm::StackEntry> params);
 | 
			
		||||
                      std::vector<vm::StackEntry> params, td::BufferSlice remote_c7, td::BufferSlice remote_libs,
 | 
			
		||||
                      td::BufferSlice remote_result, int remote_exit_code);
 | 
			
		||||
  bool get_all_shards(bool use_last = true, ton::BlockIdExt blkid = {});
 | 
			
		||||
  void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data);
 | 
			
		||||
  bool get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "");
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +182,7 @@ class TestNode : public td::actor::Actor {
 | 
			
		|||
  static bool convert_uint32(td::Slice word, td::uint32& val);
 | 
			
		||||
  static bool convert_int32(td::Slice word, td::int32& val);
 | 
			
		||||
  static bool convert_shard_id(td::Slice str, ton::ShardIdFull& shard);
 | 
			
		||||
  static td::int64 compute_method_id(std::string method);
 | 
			
		||||
  bool parse_hash(ton::Bits256& hash);
 | 
			
		||||
  bool parse_lt(ton::LogicalTime& lt);
 | 
			
		||||
  bool parse_uint32(td::uint32& val);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,6 +84,12 @@ class BufferedFd : public BufferedFdBase<FdT> {
 | 
			
		|||
  ~BufferedFd();
 | 
			
		||||
 | 
			
		||||
  void close();
 | 
			
		||||
  size_t left_unread() {
 | 
			
		||||
    return input_reader_.size();
 | 
			
		||||
  }
 | 
			
		||||
  size_t left_unwritten() {
 | 
			
		||||
    return output_reader_.size();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Result<size_t> flush_read(size_t max_read = std::numeric_limits<size_t>::max()) TD_WARN_UNUSED_RESULT;
 | 
			
		||||
  Result<size_t> flush_write() TD_WARN_UNUSED_RESULT;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "td/utils/FileLog.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -128,4 +128,10 @@ void FileLog::do_rotate() {
 | 
			
		|||
  SET_VERBOSITY_LEVEL(current_verbosity_level);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result<td::unique_ptr<LogInterface>> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) {
 | 
			
		||||
  auto l = make_unique<FileLog>();
 | 
			
		||||
  TRY_STATUS(l->init(std::move(path), rotate_threshold, redirect_stderr));
 | 
			
		||||
  return std::move(l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace td
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +30,8 @@ class FileLog : public LogInterface {
 | 
			
		|||
  static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  static Result<td::unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD,
 | 
			
		||||
                                                     bool redirect_stderr = true);
 | 
			
		||||
  Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, bool redirect_stderr = true);
 | 
			
		||||
 | 
			
		||||
  Slice get_path() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,12 +44,12 @@ std::pair<T, T> split(T s, char delimiter = ' ') {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
vector<T> full_split(T s, char delimiter = ' ') {
 | 
			
		||||
vector<T> full_split(T s, char delimiter = ' ', size_t max_parts = std::numeric_limits<size_t>::max()) {
 | 
			
		||||
  vector<T> result;
 | 
			
		||||
  if (s.empty()) {
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  while (true) {
 | 
			
		||||
  while (result.size() + 1 < max_parts) {
 | 
			
		||||
    auto delimiter_pos = s.find(delimiter);
 | 
			
		||||
    if (delimiter_pos == string::npos) {
 | 
			
		||||
      result.push_back(std::move(s));
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +59,8 @@ vector<T> full_split(T s, char delimiter = ' ') {
 | 
			
		|||
      s = s.substr(delimiter_pos + 1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  result.push_back(std::move(s));
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
string implode(const vector<string> &v, char delimiter = ' ');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "td/utils/port/detail/Epoll.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +109,7 @@ void Epoll::run(int timeout_ms) {
 | 
			
		|||
#ifdef EPOLLRDHUP
 | 
			
		||||
    if (event->events & EPOLLRDHUP) {
 | 
			
		||||
      event->events &= ~EPOLLRDHUP;
 | 
			
		||||
      flags = flags | PollFlags::Close();
 | 
			
		||||
      //      flags |= Fd::Close;
 | 
			
		||||
      // TODO
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "td/utils/as.h"
 | 
			
		||||
#include "td/utils/base64.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -570,6 +570,10 @@ static void test_full_split(Slice str, vector<Slice> expected) {
 | 
			
		|||
  ASSERT_EQ(expected, td::full_split(str));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void test_full_split(Slice str, char c, size_t max_parts, vector<Slice> expected) {
 | 
			
		||||
  ASSERT_EQ(expected, td::full_split(str, c, max_parts));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Misc, full_split) {
 | 
			
		||||
  test_full_split("", {});
 | 
			
		||||
  test_full_split(" ", {"", ""});
 | 
			
		||||
| 
						 | 
				
			
			@ -585,6 +589,7 @@ TEST(Misc, full_split) {
 | 
			
		|||
  test_full_split(" abcdef ", {"", "abcdef", ""});
 | 
			
		||||
  test_full_split(" ab cd ef ", {"", "ab", "cd", "ef", ""});
 | 
			
		||||
  test_full_split("  ab  cd  ef  ", {"", "", "ab", "", "cd", "", "ef", "", ""});
 | 
			
		||||
  test_full_split("ab cd ef gh", ' ', 3, {"ab", "cd", "ef gh"});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Misc, StringBuilder) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ Test_Fift_testvm6_default dd6353c8f3f21cf62a4769ee1f3daaec46f43fd633ffb84c5d6535
 | 
			
		|||
Test_Fift_testvm7_default 77f54b6c8c9a728d262e912efcc347de7014a37d08793c3adeac8b96fe063342
 | 
			
		||||
Test_Fift_testvm8_default 17c9e2205ccecfd8549328b4a501d07dde0336899a7a496e747e1032ad5efff9
 | 
			
		||||
Test_Fift_testvm_default ee4cbfec76c050b6de7877cfc39817d594cd1e175b6265b76fb642e30b940437
 | 
			
		||||
Test_Fift_testvmprog_default 3aeebf868c0492f2bafe339505751449e9d258bf25ea5d956efe70c6fce408ed
 | 
			
		||||
Test_Fift_testvmprog_default a6d40d8a7bf0dd3b719c8b1023fef59e01ef094f732951cec4577556c6c68e64
 | 
			
		||||
Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb
 | 
			
		||||
Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d
 | 
			
		||||
Test_VM_assert_extract_minmax_key_default c352309c61bdf62ba7a0ba7280d303c88b0696fe7efa550c05feb2c662275297
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ liteServer.blockState id:tonNode.blockIdExt root_hash:int256 file_hash:int256 da
 | 
			
		|||
liteServer.blockHeader id:tonNode.blockIdExt mode:# header_proof:bytes = liteServer.BlockHeader;
 | 
			
		||||
liteServer.sendMsgStatus status:int = liteServer.SendMsgStatus;
 | 
			
		||||
liteServer.accountState id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state:bytes = liteServer.AccountState;
 | 
			
		||||
liteServer.runMethodResult mode:# id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state_proof:bytes init_c7:bytes lib_extras:bytes exit_code:int result:bytes = liteServer.RunMethodResult;
 | 
			
		||||
liteServer.runMethodResult mode:# id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:mode.0?bytes proof:mode.0?bytes state_proof:mode.1?bytes init_c7:mode.3?bytes lib_extras:mode.4?bytes exit_code:int result:mode.2?bytes = liteServer.RunMethodResult;
 | 
			
		||||
liteServer.shardInfo id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes shard_descr:bytes = liteServer.ShardInfo;
 | 
			
		||||
liteServer.allShardsInfo id:tonNode.blockIdExt proof:bytes data:bytes = liteServer.AllShardsInfo;
 | 
			
		||||
liteServer.transactionInfo id:tonNode.blockIdExt proof:bytes transaction:bytes = liteServer.TransactionInfo;
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +64,7 @@ liteServer.getState id:tonNode.blockIdExt = liteServer.BlockState;
 | 
			
		|||
liteServer.getBlockHeader id:tonNode.blockIdExt mode:# = liteServer.BlockHeader;
 | 
			
		||||
liteServer.sendMessage body:bytes = liteServer.SendMsgStatus;
 | 
			
		||||
liteServer.getAccountState id:tonNode.blockIdExt account:liteServer.accountId = liteServer.AccountState;
 | 
			
		||||
liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:int params:bytes = liteServer.RunMethodResult;
 | 
			
		||||
liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult;
 | 
			
		||||
liteServer.getShardInfo id:tonNode.blockIdExt workchain:int shard:long exact:Bool = liteServer.ShardInfo;
 | 
			
		||||
liteServer.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo;
 | 
			
		||||
liteServer.getOneTransaction id:tonNode.blockIdExt account:liteServer.accountId lt:long = liteServer.TransactionInfo;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -614,3 +614,25 @@ engine.validator.createElectionBid election_date:int election_addr:string wallet
 | 
			
		|||
engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus;
 | 
			
		||||
 | 
			
		||||
engine.validator.controlQuery data:bytes = Object;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
---types---
 | 
			
		||||
 | 
			
		||||
http.header name:string value:string = http.Header;
 | 
			
		||||
http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart;
 | 
			
		||||
http.response http_version:string status_code:int reason:string headers:(vector http.header) = http.Response;
 | 
			
		||||
 | 
			
		||||
---functions---
 | 
			
		||||
 | 
			
		||||
http.request id:int256 method:string url:string http_version:string headers:(vector http.header) = http.Response;
 | 
			
		||||
http.getNextPayloadPart id:int256 seqno:int max_chunk_size:int = http.PayloadPart;
 | 
			
		||||
 | 
			
		||||
---types---
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
http.server.dnsEntry domain:string addr:adnl.id.short = http.server.DnsEntry;
 | 
			
		||||
http.server.host domains:(vector string) ip:int port:int adnl_id:adnl.id.short = http.server.Host;
 | 
			
		||||
 | 
			
		||||
http.server.config dhs:(vector http.server.dnsEntry) local_hosts:(vector http.server.host) = http.server.Config;
 | 
			
		||||
 | 
			
		||||
---functions---
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -504,6 +504,13 @@ void ArchiveManager::load_package(PackageId id) {
 | 
			
		|||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string prefix = PSTRING() << db_root_ << id.path() << id.name();
 | 
			
		||||
  auto f = td::FileFd::open(prefix + ".pack", td::FileFd::Read);
 | 
			
		||||
  if (f.is_error()) {
 | 
			
		||||
    x->deleted_ = true;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FileDescription desc{id, false};
 | 
			
		||||
  if (!id.temp) {
 | 
			
		||||
    for (auto &e : x->firstblocks_) {
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +519,6 @@ void ArchiveManager::load_package(PackageId id) {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string prefix = PSTRING() << db_root_ << id.path() << id.name();
 | 
			
		||||
  desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.key, id.temp, prefix);
 | 
			
		||||
 | 
			
		||||
  get_file_map(id).emplace(id, std::move(desc));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@ class PackageReader : public td::actor::Actor {
 | 
			
		|||
  }
 | 
			
		||||
  void start_up() {
 | 
			
		||||
    promise_.set_result(package_->read(offset_));
 | 
			
		||||
    stop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,8 +46,14 @@ td::uint64 Package::append(std::string filename, td::Slice data, bool sync) {
 | 
			
		|||
  size += 8;
 | 
			
		||||
  CHECK(fd_.pwrite(filename, size).move_as_ok() == filename.size());
 | 
			
		||||
  size += filename.size();
 | 
			
		||||
  CHECK(fd_.pwrite(data, size).move_as_ok() == data.size());
 | 
			
		||||
  size += data.size();
 | 
			
		||||
  while (data.size() != 0) {
 | 
			
		||||
    auto R = fd_.pwrite(data, size);
 | 
			
		||||
    R.ensure();
 | 
			
		||||
    auto x = R.move_as_ok();
 | 
			
		||||
    CHECK(x > 0);
 | 
			
		||||
    size += x;
 | 
			
		||||
    data.remove_prefix(x);
 | 
			
		||||
  }
 | 
			
		||||
  if (sync) {
 | 
			
		||||
    fd_.sync().ensure();
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#include "liteserver.hpp"
 | 
			
		||||
#include "td/utils/Slice.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
#include "adnl/utils.hpp"
 | 
			
		||||
#include "ton/lite-tl.hpp"
 | 
			
		||||
#include "tl-utils/lite-utils.hpp"
 | 
			
		||||
#include "td/utils/Random.h"
 | 
			
		||||
#include "vm/boc.h"
 | 
			
		||||
#include "tl/tlblib.hpp"
 | 
			
		||||
#include "block/block.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +34,7 @@
 | 
			
		|||
#include "block/block-auto.h"
 | 
			
		||||
#include "vm/dict.h"
 | 
			
		||||
#include "vm/cells/MerkleProof.h"
 | 
			
		||||
#include "vm/continuation.h"
 | 
			
		||||
#include "shard.hpp"
 | 
			
		||||
#include "validator-set.hpp"
 | 
			
		||||
#include "signature-set.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -665,14 +667,14 @@ void LiteQuery::continue_getAccountState_0(Ref<ton::validator::MasterchainState>
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void LiteQuery::perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode,
 | 
			
		||||
                                     int method_id, td::BufferSlice params) {
 | 
			
		||||
                                     td::int64 method_id, td::BufferSlice params) {
 | 
			
		||||
  LOG(INFO) << "started a runSmcMethod(" << blkid.to_str() << ", " << workchain << ", " << addr.to_hex() << ", "
 | 
			
		||||
            << method_id << ", " << mode << ") liteserver query with " << params.size() << " parameter bytes";
 | 
			
		||||
  if (params.size() >= 65536) {
 | 
			
		||||
    fatal_error("more than 64k parameter bytes passed");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (mode & ~0xf) {
 | 
			
		||||
  if (mode & ~0x1f) {
 | 
			
		||||
    fatal_error("unsupported mode in runSmcMethod");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -984,7 +986,8 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
 | 
			
		|||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (mode_ & 0x10000) {
 | 
			
		||||
    finish_runSmcMethod(std::move(shard_proof), proof.move_as_ok(), std::move(acc_root));
 | 
			
		||||
    finish_runSmcMethod(std::move(shard_proof), proof.move_as_ok(), std::move(acc_root), sstate.gen_utime,
 | 
			
		||||
                        sstate.gen_lt);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  td::BufferSlice data;
 | 
			
		||||
| 
						 | 
				
			
			@ -1003,11 +1006,112 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
 | 
			
		|||
  finish_query(std::move(b));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root) {
 | 
			
		||||
// same as in lite-client/lite-client-common.cpp
 | 
			
		||||
static td::Ref<vm::Tuple> prepare_vm_c7(ton::UnixTime now, ton::LogicalTime lt, td::Ref<vm::CellSlice> my_addr,
 | 
			
		||||
                                        const block::CurrencyCollection& balance) {
 | 
			
		||||
  td::BitArray<256> rand_seed;
 | 
			
		||||
  td::RefInt256 rand_seed_int{true};
 | 
			
		||||
  td::Random::secure_bytes(rand_seed.as_slice());
 | 
			
		||||
  if (!rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false)) {
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
  auto tuple = vm::make_tuple_ref(td::make_refint(0x076ef1ea),  // [ magic:0x076ef1ea
 | 
			
		||||
                                  td::make_refint(0),           //   actions:Integer
 | 
			
		||||
                                  td::make_refint(0),           //   msgs_sent:Integer
 | 
			
		||||
                                  td::make_refint(now),         //   unixtime:Integer
 | 
			
		||||
                                  td::make_refint(lt),          //   block_lt:Integer
 | 
			
		||||
                                  td::make_refint(lt),          //   trans_lt:Integer
 | 
			
		||||
                                  std::move(rand_seed_int),     //   rand_seed:Integer
 | 
			
		||||
                                  balance.as_vm_tuple(),        //   balance_remaining:[Integer (Maybe Cell)]
 | 
			
		||||
                                  my_addr,                      //  myself:MsgAddressInt
 | 
			
		||||
                                  vm::StackEntry());            //  global_config:(Maybe Cell) ] = SmartContractInfo;
 | 
			
		||||
  LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
 | 
			
		||||
  return vm::make_tuple_ref(std::move(tuple));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root,
 | 
			
		||||
                                    UnixTime gen_utime, LogicalTime gen_lt) {
 | 
			
		||||
  LOG(INFO) << "completing runSmcMethod() query";
 | 
			
		||||
  // ... TODO ...
 | 
			
		||||
  fatal_error("runSmcMethod not implemented");
 | 
			
		||||
  return;
 | 
			
		||||
  int mode = mode_ & 0xffff;
 | 
			
		||||
  if (acc_root.is_null()) {
 | 
			
		||||
    // no such account
 | 
			
		||||
    LOG(INFO) << "runSmcMethod(" << acc_workchain_ << ":" << acc_addr_.to_hex()
 | 
			
		||||
              << ") query completed: account state is empty";
 | 
			
		||||
    auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
 | 
			
		||||
        mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
 | 
			
		||||
        std::move(state_proof), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(), -0x100, td::BufferSlice());
 | 
			
		||||
    finish_query(std::move(b));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  vm::MerkleProofBuilder pb{std::move(acc_root)};
 | 
			
		||||
  block::gen::Account::Record_account acc;
 | 
			
		||||
  block::gen::AccountStorage::Record store;
 | 
			
		||||
  block::CurrencyCollection balance;
 | 
			
		||||
  block::gen::StateInit::Record state_init;
 | 
			
		||||
  if (!(tlb::unpack_cell(pb.root(), acc) && tlb::csr_unpack(std::move(acc.storage), store) &&
 | 
			
		||||
        balance.validate_unpack(store.balance) && store.state->prefetch_ulong(1) == 1 &&
 | 
			
		||||
        store.state.write().advance(1) && tlb::csr_unpack(std::move(store.state), state_init))) {
 | 
			
		||||
    LOG(INFO) << "error unpacking account state, or account is frozen or uninitialized";
 | 
			
		||||
    auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
 | 
			
		||||
        mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
 | 
			
		||||
        std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), td::BufferSlice(),
 | 
			
		||||
        td::BufferSlice(), -0x100, td::BufferSlice());
 | 
			
		||||
    finish_query(std::move(b));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  auto code = state_init.code->prefetch_ref();
 | 
			
		||||
  auto data = state_init.data->prefetch_ref();
 | 
			
		||||
  long long gas_limit = client_method_gas_limit;
 | 
			
		||||
  LOG(DEBUG) << "creating VM with gas limit " << gas_limit;
 | 
			
		||||
  // **** INIT VM ****
 | 
			
		||||
  vm::GasLimits gas{gas_limit};
 | 
			
		||||
  vm::VmState vm{std::move(code), std::move(stack_), gas, 1, std::move(data), vm::VmLog::Null()};
 | 
			
		||||
  auto c7 = prepare_vm_c7(gen_utime, gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()), balance);
 | 
			
		||||
  vm.set_c7(c7);  // tuple with SmartContractInfo
 | 
			
		||||
  // vm.incr_stack_trace(1);    // enable stack dump after each step
 | 
			
		||||
  LOG(INFO) << "starting VM to run GET-method of smart contract " << acc_workchain_ << ":" << acc_addr_.to_hex();
 | 
			
		||||
  // **** RUN VM ****
 | 
			
		||||
  int exit_code = ~vm.run();
 | 
			
		||||
  LOG(DEBUG) << "VM terminated with exit code " << exit_code;
 | 
			
		||||
  stack_ = vm.get_stack_ref();
 | 
			
		||||
  LOG(INFO) << "runSmcMethod(" << acc_workchain_ << ":" << acc_addr_.to_hex() << ") query completed: exit code is "
 | 
			
		||||
            << exit_code;
 | 
			
		||||
  Ref<vm::Cell> cell;
 | 
			
		||||
  td::BufferSlice c7_info, result;
 | 
			
		||||
  if (mode & 8) {
 | 
			
		||||
    // serialize c7
 | 
			
		||||
    vm::CellBuilder cb;
 | 
			
		||||
    if (!(vm::StackEntry{std::move(c7)}.serialize(cb) && cb.finalize_to(cell))) {
 | 
			
		||||
      fatal_error("cannot serialize c7");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    auto res = vm::std_boc_serialize(std::move(cell));
 | 
			
		||||
    if (res.is_error()) {
 | 
			
		||||
      fatal_error("cannot serialize c7 : "s + res.move_as_error().to_string());
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    c7_info = res.move_as_ok();
 | 
			
		||||
  }
 | 
			
		||||
  // pre-serialize stack always (to visit all data cells referred from the result)
 | 
			
		||||
  vm::CellBuilder cb;
 | 
			
		||||
  if (!(stack_->serialize(cb) && cb.finalize_to(cell))) {
 | 
			
		||||
    fatal_error("cannot serialize resulting stack");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (mode & 4) {
 | 
			
		||||
    // serialize stack if required
 | 
			
		||||
    auto res = vm::std_boc_serialize(std::move(cell));
 | 
			
		||||
    if (res.is_error()) {
 | 
			
		||||
      fatal_error("cannot serialize resulting stack : "s + res.move_as_error().to_string());
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    result = res.move_as_ok();
 | 
			
		||||
  }
 | 
			
		||||
  auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
 | 
			
		||||
      mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
 | 
			
		||||
      std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), std::move(c7_info),
 | 
			
		||||
      td::BufferSlice(), exit_code, std::move(result));
 | 
			
		||||
  finish_query(std::move(b));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LiteQuery::continue_getOneTransaction() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    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/>.
 | 
			
		||||
 | 
			
		||||
    Copyright 2017-2019 Telegram Systems LLP
 | 
			
		||||
    Copyright 2017-2020 Telegram Systems LLP
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "ton/ton-types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -60,13 +60,14 @@ class LiteQuery : public td::actor::Actor {
 | 
			
		|||
 | 
			
		||||
 public:
 | 
			
		||||
  enum {
 | 
			
		||||
    default_timeout_msec = 4500,  // 4.5 seconds
 | 
			
		||||
    max_transaction_count = 16    // fetch at most 16 transactions in one query
 | 
			
		||||
    default_timeout_msec = 4500,      // 4.5 seconds
 | 
			
		||||
    max_transaction_count = 16,       // fetch at most 16 transactions in one query
 | 
			
		||||
    client_method_gas_limit = 100000  // gas limit for liteServer.runSmcMethod
 | 
			
		||||
  };
 | 
			
		||||
  enum {
 | 
			
		||||
    ls_version = 0x101,
 | 
			
		||||
    ls_capabilities = 3
 | 
			
		||||
  };  // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt
 | 
			
		||||
    ls_capabilities = 7
 | 
			
		||||
  };  // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt, +4 = runSmcMethod
 | 
			
		||||
  LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
 | 
			
		||||
            td::Promise<td::BufferSlice> promise);
 | 
			
		||||
  static void run_query(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
 | 
			
		||||
| 
						 | 
				
			
			@ -97,9 +98,10 @@ class LiteQuery : public td::actor::Actor {
 | 
			
		|||
  void continue_getAccountState_0(Ref<MasterchainState> mc_state, BlockIdExt blkid);
 | 
			
		||||
  void continue_getAccountState();
 | 
			
		||||
  void finish_getAccountState(td::BufferSlice shard_proof);
 | 
			
		||||
  void perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode, int method_id,
 | 
			
		||||
  void perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode, td::int64 method_id,
 | 
			
		||||
                            td::BufferSlice params);
 | 
			
		||||
  void finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root);
 | 
			
		||||
  void finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root,
 | 
			
		||||
                           UnixTime gen_utime, LogicalTime gen_lt);
 | 
			
		||||
  void perform_getOneTransaction(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, LogicalTime lt);
 | 
			
		||||
  void continue_getOneTransaction();
 | 
			
		||||
  void perform_getTransactions(WorkchainId workchain, StdSmcAddress addr, LogicalTime lt, Bits256 hash, unsigned count);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue