mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	Merge pull request #413 from ton-blockchain/temp-master
Update DNS resolver in liteclient and tonlib
This commit is contained in:
		
						commit
						eb86234a11
					
				
					 14 changed files with 278 additions and 237 deletions
				
			
		| 
						 | 
					@ -807,7 +807,7 @@ vmc_pushint$1111 value:int32 next:^VmCont = VmCont;
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  DNS RECORDS
 | 
					//  DNS RECORDS
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
_ (HashmapE 16 ^DNSRecord) = DNS_RecordSet;
 | 
					_ (HashmapE 256 DNSRecord) = DNS_RecordSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1);
 | 
					chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1);
 | 
				
			||||||
chunk_ref_empty$_ = TextChunkRef 0;
 | 
					chunk_ref_empty$_ = TextChunkRef 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,24 +146,27 @@ td::Result<DnsInterface::EntryData> DnsInterface::EntryData::from_cellslice(vm::
 | 
				
			||||||
  return td::Status::Error("Unknown entry data");
 | 
					  return td::Status::Error("Unknown entry data");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SmartContract::Args DnsInterface::resolve_args_raw(td::Slice encoded_name, td::int16 category) {
 | 
					SmartContract::Args DnsInterface::resolve_args_raw(td::Slice encoded_name, td::Bits256 category,
 | 
				
			||||||
 | 
					                                                   block::StdAddress address) {
 | 
				
			||||||
  SmartContract::Args res;
 | 
					  SmartContract::Args res;
 | 
				
			||||||
  res.set_method_id("dnsresolve");
 | 
					  res.set_method_id("dnsresolve");
 | 
				
			||||||
  res.set_stack(
 | 
					  res.set_stack(
 | 
				
			||||||
      {vm::load_cell_slice_ref(vm::CellBuilder().store_bytes(encoded_name).finalize()), td::make_refint(category)});
 | 
					      {vm::load_cell_slice_ref(vm::CellBuilder().store_bytes(encoded_name).finalize()),
 | 
				
			||||||
 | 
					       td::bits_to_refint(category.cbits(), 256, false)});
 | 
				
			||||||
 | 
					  res.set_address(std::move(address));
 | 
				
			||||||
  return res;
 | 
					  return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::Result<SmartContract::Args> DnsInterface::resolve_args(td::Slice name, td::int32 category_big) {
 | 
					td::Result<SmartContract::Args> DnsInterface::resolve_args(td::Slice name, td::Bits256 category,
 | 
				
			||||||
  TRY_RESULT(category, td::narrow_cast_safe<td::int16>(category_big));
 | 
					                                                           block::StdAddress address) {
 | 
				
			||||||
  if (name.size() > get_default_max_name_size()) {
 | 
					  if (name.size() > get_default_max_name_size()) {
 | 
				
			||||||
    return td::Status::Error("Name is too long");
 | 
					    return td::Status::Error("Name is too long");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto encoded_name = encode_name(name);
 | 
					  auto encoded_name = encode_name(name);
 | 
				
			||||||
  return resolve_args_raw(encoded_name, category);
 | 
					  return resolve_args_raw(encoded_name, category, std::move(address));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::Result<std::vector<DnsInterface::Entry>> DnsInterface::resolve(td::Slice name, td::int32 category) const {
 | 
					td::Result<std::vector<DnsInterface::Entry>> DnsInterface::resolve(td::Slice name, td::Bits256 category) const {
 | 
				
			||||||
  TRY_RESULT(raw_entries, resolve_raw(name, category));
 | 
					  TRY_RESULT(raw_entries, resolve_raw(name, category));
 | 
				
			||||||
  std::vector<Entry> entries;
 | 
					  std::vector<Entry> entries;
 | 
				
			||||||
  entries.reserve(raw_entries.size());
 | 
					  entries.reserve(raw_entries.size());
 | 
				
			||||||
| 
						 | 
					@ -171,10 +174,15 @@ td::Result<std::vector<DnsInterface::Entry>> DnsInterface::resolve(td::Slice nam
 | 
				
			||||||
    Entry entry;
 | 
					    Entry entry;
 | 
				
			||||||
    entry.name = std::move(raw_entry.name);
 | 
					    entry.name = std::move(raw_entry.name);
 | 
				
			||||||
    entry.category = raw_entry.category;
 | 
					    entry.category = raw_entry.category;
 | 
				
			||||||
    auto cs = vm::load_cell_slice(raw_entry.data);
 | 
					    entry.partially_resolved = raw_entry.partially_resolved;
 | 
				
			||||||
    TRY_RESULT(data, EntryData::from_cellslice(cs));
 | 
					    auto cs = *raw_entry.data;
 | 
				
			||||||
    entry.data = std::move(data);
 | 
					    auto data = EntryData::from_cellslice(cs);
 | 
				
			||||||
    entries.push_back(std::move(entry));
 | 
					    if (data.is_error()) {
 | 
				
			||||||
 | 
					      LOG(INFO) << "Failed to parse DNS entry: " << data.move_as_error();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      entry.data = data.move_as_ok();
 | 
				
			||||||
 | 
					      entries.push_back(std::move(entry));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return entries;
 | 
					  return entries;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -188,9 +196,9 @@ td::Result<std::vector<DnsInterface::Entry>> DnsInterface::resolve(td::Slice nam
 | 
				
			||||||
    Inline [Name] structure: [UInt<6b>:length] [Bytes<lengthB>:data]
 | 
					    Inline [Name] structure: [UInt<6b>:length] [Bytes<lengthB>:data]
 | 
				
			||||||
    Operations (continuation of message):
 | 
					    Operations (continuation of message):
 | 
				
			||||||
    00 Contract initialization message (only if seqno = 0) (x=-)
 | 
					    00 Contract initialization message (only if seqno = 0) (x=-)
 | 
				
			||||||
	31 TSet: replace ENTIRE DOMAIN TABLE with the provided tree root cell (x=-)
 | 
					    31 TSet: replace ENTIRE DOMAIN TABLE with the provided tree root cell (x=-)
 | 
				
			||||||
		[Cell<1r>:new_domains_table]
 | 
							[Cell<1r>:new_domains_table]
 | 
				
			||||||
	51 OSet: replace owner public key with a new one (x=-)
 | 
					    51 OSet: replace owner public key with a new one (x=-)
 | 
				
			||||||
		[UInt<256b>:new_public_key]
 | 
							[UInt<256b>:new_public_key]
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
// creation
 | 
					// creation
 | 
				
			||||||
| 
						 | 
					@ -233,37 +241,37 @@ td::Result<td::uint32> ManualDns::get_wallet_id_or_throw() const {
 | 
				
			||||||
  return static_cast<td::uint32>(vm::load_cell_slice(state_.data).fetch_ulong(32));
 | 
					  return static_cast<td::uint32>(vm::load_cell_slice(state_.data).fetch_ulong(32));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::Result<td::Ref<vm::Cell>> ManualDns::create_set_value_unsigned(td::int16 category, td::Slice name,
 | 
					td::Result<td::Ref<vm::Cell>> ManualDns::create_set_value_unsigned(td::Bits256 category, td::Slice name,
 | 
				
			||||||
                                                                   td::Ref<vm::Cell> data) const {
 | 
					                                                                   td::Ref<vm::Cell> data) const {
 | 
				
			||||||
  //11 VSet: set specified value to specified subdomain->category (x=2)
 | 
					  //11 VSet: set specified value to specified subdomain->category (x=2)
 | 
				
			||||||
  //[Int<16b>:category] [Name<?>:subdomain] [Cell<1r>:value]
 | 
					  //[Int<256b>:category] [Name<?>:subdomain] [Cell<1r>:value]
 | 
				
			||||||
  vm::CellBuilder cb;
 | 
					  vm::CellBuilder cb;
 | 
				
			||||||
  cb.store_long(11, 6);
 | 
					  cb.store_long(11, 6);
 | 
				
			||||||
  if (name.size() <= 58 - 2) {
 | 
					  if (name.size() <= 58 - 32) {
 | 
				
			||||||
    cb.store_long(category, 16);
 | 
					    cb.store_bytes(category.as_slice());
 | 
				
			||||||
    cb.store_long(0, 1);
 | 
					    cb.store_long(0, 1);
 | 
				
			||||||
    cb.store_long(name.size(), 6);
 | 
					    cb.store_long(name.size(), 6);
 | 
				
			||||||
    cb.store_bytes(name);
 | 
					    cb.store_bytes(name);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    cb.store_long(category, 16);
 | 
					    cb.store_bytes(category.as_slice());
 | 
				
			||||||
    cb.store_long(1, 1);
 | 
					    cb.store_long(1, 1);
 | 
				
			||||||
    cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
 | 
					    cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  cb.store_maybe_ref(std::move(data));
 | 
					  cb.store_maybe_ref(std::move(data));
 | 
				
			||||||
  return cb.finalize();
 | 
					  return cb.finalize();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
td::Result<td::Ref<vm::Cell>> ManualDns::create_delete_value_unsigned(td::int16 category, td::Slice name) const {
 | 
					td::Result<td::Ref<vm::Cell>> ManualDns::create_delete_value_unsigned(td::Bits256 category, td::Slice name) const {
 | 
				
			||||||
  //12 VDel: delete specified subdomain->category (x=2)
 | 
					  //12 VDel: delete specified subdomain->category (x=2)
 | 
				
			||||||
  //[Int<16b>:category] [Name<?>:subdomain]
 | 
					  //[Int<256b>:category] [Name<?>:subdomain]
 | 
				
			||||||
  vm::CellBuilder cb;
 | 
					  vm::CellBuilder cb;
 | 
				
			||||||
  cb.store_long(12, 6);
 | 
					  cb.store_long(12, 6);
 | 
				
			||||||
  if (name.size() <= 58 - 2) {
 | 
					  if (name.size() <= 58 - 32) {
 | 
				
			||||||
    cb.store_long(category, 16);
 | 
					    cb.store_bytes(category.as_slice());
 | 
				
			||||||
    cb.store_long(0, 1);
 | 
					    cb.store_long(0, 1);
 | 
				
			||||||
    cb.store_long(name.size(), 6);
 | 
					    cb.store_long(name.size(), 6);
 | 
				
			||||||
    cb.store_bytes(name);
 | 
					    cb.store_bytes(name);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    cb.store_long(category, 16);
 | 
					    cb.store_bytes(category.as_slice());
 | 
				
			||||||
    cb.store_long(1, 1);
 | 
					    cb.store_long(1, 1);
 | 
				
			||||||
    cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
 | 
					    cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -295,10 +303,9 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_set_all_unsigned(td::Span<Action
 | 
				
			||||||
    if (o_dict.not_null()) {
 | 
					    if (o_dict.not_null()) {
 | 
				
			||||||
      o_dict->prefetch_maybe_ref(dict_root);
 | 
					      o_dict->prefetch_maybe_ref(dict_root);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vm::Dictionary dict(dict_root, 16);
 | 
					    vm::Dictionary dict(dict_root, 256);
 | 
				
			||||||
    if (!action.data.value().is_null()) {
 | 
					    if (!action.data.value().is_null()) {
 | 
				
			||||||
      auto key = dict.integer_key(td::make_refint(action.category), 16);
 | 
					      dict.set_ref(action.category.bits(), 256, action.data.value());
 | 
				
			||||||
      dict.set_ref(key.bits(), 16, action.data.value());
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pdict.set(ptr, ptr_size, dict.get_root());
 | 
					    pdict.set(ptr, ptr_size, dict.get_root());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -340,14 +347,13 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_set_name_unsigned(td::Slice name
 | 
				
			||||||
    cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
 | 
					    cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  vm::Dictionary dict(16);
 | 
					  vm::Dictionary dict(256);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (auto& action : entries) {
 | 
					  for (auto& action : entries) {
 | 
				
			||||||
    if (action.data.value().is_null()) {
 | 
					    if (action.data.value().is_null()) {
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto key = dict.integer_key(td::make_refint(action.category), 16);
 | 
					    dict.set_ref(action.category.cbits(), 256, action.data.value());
 | 
				
			||||||
    dict.set_ref(key.bits(), 16, action.data.value());
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  cb.store_maybe_ref(dict.get_root_cell());
 | 
					  cb.store_maybe_ref(dict.get_root_cell());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -395,17 +401,16 @@ size_t ManualDns::get_max_name_size() const {
 | 
				
			||||||
  return get_default_max_name_size();
 | 
					  return get_default_max_name_size();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw(td::Slice name, td::int32 category_big) const {
 | 
					td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw(td::Slice name, td::Bits256 category) const {
 | 
				
			||||||
  return TRY_VM(resolve_raw_or_throw(name, category_big));
 | 
					  return TRY_VM(resolve_raw_or_throw(name, category));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw_or_throw(td::Slice name,
 | 
					td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw_or_throw(td::Slice name,
 | 
				
			||||||
                                                                             td::int32 category_big) const {
 | 
					                                                                             td::Bits256 category) const {
 | 
				
			||||||
  TRY_RESULT(category, td::narrow_cast_safe<td::int16>(category_big));
 | 
					 | 
				
			||||||
  if (name.size() > get_max_name_size()) {
 | 
					  if (name.size() > get_max_name_size()) {
 | 
				
			||||||
    return td::Status::Error("Name is too long");
 | 
					    return td::Status::Error("Name is too long");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto encoded_name = encode_name(name);
 | 
					  auto encoded_name = encode_name(name);
 | 
				
			||||||
  auto res = run_get_method(resolve_args_raw(encoded_name, category));
 | 
					  auto res = run_get_method(resolve_args_raw(encoded_name, category, address_));
 | 
				
			||||||
  if (!res.success) {
 | 
					  if (!res.success) {
 | 
				
			||||||
    return td::Status::Error("get method failed");
 | 
					    return td::Status::Error("get method failed");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -419,19 +424,22 @@ td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw_or_throw(td:
 | 
				
			||||||
    return td::Status::Error("Prefix size is not divisible by 8");
 | 
					    return td::Status::Error("Prefix size is not divisible by 8");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  prefix_size /= 8;
 | 
					  prefix_size /= 8;
 | 
				
			||||||
 | 
					  if (prefix_size == 0) {
 | 
				
			||||||
 | 
					    return vec;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (prefix_size < encoded_name.size()) {
 | 
					  if (prefix_size < encoded_name.size()) {
 | 
				
			||||||
    vec.push_back({decode_name(td::Slice(encoded_name).substr(0, prefix_size)), -1, data});
 | 
					    vec.push_back({decode_name(td::Slice(encoded_name).substr(0, prefix_size)), DNS_NEXT_RESOLVER_CATEGORY,
 | 
				
			||||||
 | 
					                   vm::load_cell_slice_ref(data), true});
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    if (category == 0) {
 | 
					    if (category.is_zero()) {
 | 
				
			||||||
      vm::Dictionary dict(std::move(data), 16);
 | 
					      vm::Dictionary dict(std::move(data), 256);
 | 
				
			||||||
      dict.check_for_each([&](auto cs, auto x, auto y) {
 | 
					      dict.check_for_each([&](auto cs, td::ConstBitPtr key, int n) {
 | 
				
			||||||
        td::BigInt256 cat;
 | 
					        CHECK(n == 256);
 | 
				
			||||||
        cat.import_bits(x, y, true);
 | 
					        vec.push_back({name.str(), td::Bits256(key), cs});
 | 
				
			||||||
        vec.push_back({name.str(), td::narrow_cast<td::int16>(cat.to_long()), cs->prefetch_ref()});
 | 
					 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      vec.push_back({name.str(), category, data});
 | 
					      vec.push_back({name.str(), category, vm::load_cell_slice_ref(data)});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -445,7 +453,7 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_update_query(CombinedActions<Act
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return create_set_all_unsigned(combined.actions.value());
 | 
					    return create_set_all_unsigned(combined.actions.value());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (combined.category == 0) {
 | 
					  if (combined.category.is_zero()) {
 | 
				
			||||||
    if (!combined.actions) {
 | 
					    if (!combined.actions) {
 | 
				
			||||||
      return create_delete_name_unsigned(encode_name(combined.name));
 | 
					      return create_delete_name_unsigned(encode_name(combined.name));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -488,9 +496,13 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_update_query(td::Ed25519::Privat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string DnsInterface::encode_name(td::Slice name) {
 | 
					std::string DnsInterface::encode_name(td::Slice name) {
 | 
				
			||||||
  std::string res;
 | 
					  std::string res;
 | 
				
			||||||
 | 
					  if (name.empty() || name == ".") {
 | 
				
			||||||
 | 
					    res += '\0';
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  while (!name.empty()) {
 | 
					  while (!name.empty()) {
 | 
				
			||||||
    auto pos = name.rfind('.');
 | 
					    auto pos = name.rfind('.');
 | 
				
			||||||
    if (pos == name.npos) {
 | 
					    if (pos == td::Slice::npos) {
 | 
				
			||||||
      res += name.str();
 | 
					      res += name.str();
 | 
				
			||||||
      name = td::Slice();
 | 
					      name = td::Slice();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					@ -504,20 +516,15 @@ std::string DnsInterface::encode_name(td::Slice name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string DnsInterface::decode_name(td::Slice name) {
 | 
					std::string DnsInterface::decode_name(td::Slice name) {
 | 
				
			||||||
  std::string res;
 | 
					  std::string res;
 | 
				
			||||||
  if (!name.empty() && name.back() == 0) {
 | 
					 | 
				
			||||||
    name.remove_suffix(1);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  while (!name.empty()) {
 | 
					  while (!name.empty()) {
 | 
				
			||||||
    auto pos = name.rfind('\0');
 | 
					    auto pos = name.rfind('\0');
 | 
				
			||||||
    if (!res.empty()) {
 | 
					    if (pos == td::Slice::npos) {
 | 
				
			||||||
      res += '.';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (pos == name.npos) {
 | 
					 | 
				
			||||||
      res += name.str();
 | 
					      res += name.str();
 | 
				
			||||||
      name = td::Slice();
 | 
					      name = td::Slice();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      res += name.substr(pos + 1).str();
 | 
					      res += name.substr(pos + 1).str();
 | 
				
			||||||
      name.truncate(pos);
 | 
					      name.truncate(pos);
 | 
				
			||||||
 | 
					      res += '.';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return res;
 | 
					  return res;
 | 
				
			||||||
| 
						 | 
					@ -570,17 +577,16 @@ td::Result<ManualDns::ActionExt> ManualDns::parse_line(td::Slice cmd) {
 | 
				
			||||||
  if (type == "set") {
 | 
					  if (type == "set") {
 | 
				
			||||||
    auto name = parser.read_word();
 | 
					    auto name = parser.read_word();
 | 
				
			||||||
    auto category_str = parser.read_word();
 | 
					    auto category_str = parser.read_word();
 | 
				
			||||||
    TRY_RESULT(category, td::to_integer_safe<td::int16>(category_str));
 | 
					 | 
				
			||||||
    TRY_RESULT(data, parse_data(parser.read_all()));
 | 
					    TRY_RESULT(data, parse_data(parser.read_all()));
 | 
				
			||||||
    return ManualDns::ActionExt{name.str(), category, std::move(data)};
 | 
					    return ManualDns::ActionExt{name.str(), td::sha256_bits256(td::as_slice(category_str)), std::move(data)};
 | 
				
			||||||
  } else if (type == "delete.name") {
 | 
					  } else if (type == "delete.name") {
 | 
				
			||||||
    auto name = parser.read_word();
 | 
					    auto name = parser.read_word();
 | 
				
			||||||
    if (name.empty()) {
 | 
					    if (name.empty()) {
 | 
				
			||||||
      return td::Status::Error("name is empty");
 | 
					      return td::Status::Error("name is empty");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ManualDns::ActionExt{name.str(), 0, {}};
 | 
					    return ManualDns::ActionExt{name.str(), td::Bits256::zero(), {}};
 | 
				
			||||||
  } else if (type == "delete.all") {
 | 
					  } else if (type == "delete.all") {
 | 
				
			||||||
    return ManualDns::ActionExt{"", 0, {}};
 | 
					    return ManualDns::ActionExt{"", td::Bits256::zero(), {}};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return td::Status::Error(PSLICE() << "Unknown command: " << type);
 | 
					  return td::Status::Error(PSLICE() << "Unknown command: " << type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,10 +26,14 @@
 | 
				
			||||||
#include "smc-envelope/SmartContract.h"
 | 
					#include "smc-envelope/SmartContract.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Ed25519.h"
 | 
					#include "Ed25519.h"
 | 
				
			||||||
 | 
					#include "common/checksum.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ton {
 | 
					namespace ton {
 | 
				
			||||||
 | 
					const td::Bits256 DNS_NEXT_RESOLVER_CATEGORY =
 | 
				
			||||||
 | 
					    td::sha256_bits256(td::Slice("dns_next_resolver", strlen("dns_next_resolver")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DnsInterface {
 | 
					class DnsInterface {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  struct EntryDataText {
 | 
					  struct EntryDataText {
 | 
				
			||||||
| 
						 | 
					@ -90,8 +94,9 @@ class DnsInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct Entry {
 | 
					  struct Entry {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category;
 | 
					    td::Bits256 category;
 | 
				
			||||||
    EntryData data;
 | 
					    EntryData data;
 | 
				
			||||||
 | 
					    bool partially_resolved = false;
 | 
				
			||||||
    auto key() const {
 | 
					    auto key() const {
 | 
				
			||||||
      return std::tie(name, category);
 | 
					      return std::tie(name, category);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -102,47 +107,48 @@ class DnsInterface {
 | 
				
			||||||
      return key() == other.key() && data == other.data;
 | 
					      return key() == other.key() && data == other.data;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Entry& entry) {
 | 
					    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Entry& entry) {
 | 
				
			||||||
      sb << entry.name << ":" << entry.category << ":" << entry.data;
 | 
					      sb << entry.name << ":" << entry.category.to_hex() << ":" << entry.data;
 | 
				
			||||||
      return sb;
 | 
					      return sb;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  struct RawEntry {
 | 
					  struct RawEntry {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category;
 | 
					    td::Bits256 category;
 | 
				
			||||||
    td::Ref<vm::Cell> data;
 | 
					    td::Ref<vm::CellSlice> data;
 | 
				
			||||||
 | 
					    bool partially_resolved = false;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct ActionExt {
 | 
					  struct ActionExt {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category;
 | 
					    td::Bits256 category;
 | 
				
			||||||
    td::optional<EntryData> data;
 | 
					    td::optional<EntryData> data;
 | 
				
			||||||
    static td::Result<ActionExt> parse(td::Slice);
 | 
					    static td::Result<ActionExt> parse(td::Slice);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct Action {
 | 
					  struct Action {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category;
 | 
					    td::Bits256 category;
 | 
				
			||||||
    td::optional<td::Ref<vm::Cell>> data;
 | 
					    td::optional<td::Ref<vm::Cell>> data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool does_create_category() const {
 | 
					    bool does_create_category() const {
 | 
				
			||||||
      CHECK(!name.empty());
 | 
					      CHECK(!name.empty());
 | 
				
			||||||
      CHECK(category != 0);
 | 
					      CHECK(!category.is_zero());
 | 
				
			||||||
      return static_cast<bool>(data);
 | 
					      return static_cast<bool>(data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bool does_change_empty() const {
 | 
					    bool does_change_empty() const {
 | 
				
			||||||
      CHECK(!name.empty());
 | 
					      CHECK(!name.empty());
 | 
				
			||||||
      CHECK(category != 0);
 | 
					      CHECK(!category.is_zero());
 | 
				
			||||||
      return static_cast<bool>(data) && data.value().not_null();
 | 
					      return static_cast<bool>(data) && data.value().not_null();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    void make_non_empty() {
 | 
					    void make_non_empty() {
 | 
				
			||||||
      CHECK(!name.empty());
 | 
					      CHECK(!name.empty());
 | 
				
			||||||
      CHECK(category != 0);
 | 
					      CHECK(!category.is_zero());
 | 
				
			||||||
      if (!data) {
 | 
					      if (!data) {
 | 
				
			||||||
        data = td::Ref<vm::Cell>();
 | 
					        data = td::Ref<vm::Cell>();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& action) {
 | 
					    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& action) {
 | 
				
			||||||
      sb << action.name << ":" << action.category << ":";
 | 
					      sb << action.name << ":" << action.category.to_hex() << ":";
 | 
				
			||||||
      if (action.data) {
 | 
					      if (action.data) {
 | 
				
			||||||
        if (action.data.value().is_null()) {
 | 
					        if (action.data.value().is_null()) {
 | 
				
			||||||
          sb << "<null>";
 | 
					          sb << "<null>";
 | 
				
			||||||
| 
						 | 
					@ -156,15 +162,14 @@ class DnsInterface {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual ~DnsInterface() {
 | 
					  virtual ~DnsInterface() = default;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  virtual size_t get_max_name_size() const = 0;
 | 
					  virtual size_t get_max_name_size() const = 0;
 | 
				
			||||||
  virtual td::Result<std::vector<RawEntry>> resolve_raw(td::Slice name, td::int32 category) const = 0;
 | 
					  virtual td::Result<std::vector<RawEntry>> resolve_raw(td::Slice name, td::Bits256 category) const = 0;
 | 
				
			||||||
  virtual td::Result<td::Ref<vm::Cell>> create_update_query(
 | 
					  virtual td::Result<td::Ref<vm::Cell>> create_update_query(
 | 
				
			||||||
      td::Ed25519::PrivateKey& pk, td::Span<Action> actions,
 | 
					      td::Ed25519::PrivateKey& pk, td::Span<Action> actions,
 | 
				
			||||||
      td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) const = 0;
 | 
					      td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::Result<std::vector<Entry>> resolve(td::Slice name, td::int32 category) const;
 | 
					  td::Result<std::vector<Entry>> resolve(td::Slice name, td::Bits256 category) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static std::string encode_name(td::Slice name);
 | 
					  static std::string encode_name(td::Slice name);
 | 
				
			||||||
  static std::string decode_name(td::Slice name);
 | 
					  static std::string decode_name(td::Slice name);
 | 
				
			||||||
| 
						 | 
					@ -172,13 +177,16 @@ class DnsInterface {
 | 
				
			||||||
  static size_t get_default_max_name_size() {
 | 
					  static size_t get_default_max_name_size() {
 | 
				
			||||||
    return 128;
 | 
					    return 128;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  static SmartContract::Args resolve_args_raw(td::Slice encoded_name, td::int16 category);
 | 
					  static SmartContract::Args resolve_args_raw(td::Slice encoded_name, td::Bits256 category,
 | 
				
			||||||
  static td::Result<SmartContract::Args> resolve_args(td::Slice name, td::int32 category);
 | 
					                                              block::StdAddress address = {});
 | 
				
			||||||
 | 
					  static td::Result<SmartContract::Args> resolve_args(td::Slice name, td::Bits256 category,
 | 
				
			||||||
 | 
					                                                      block::StdAddress address = {});
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
					class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  ManualDns(State state) : SmartContract(std::move(state)) {
 | 
					  ManualDns(State state, block::StdAddress address = {})
 | 
				
			||||||
 | 
					      : SmartContract(std::move(state)), address_(std::move(address)) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ManualDns* make_copy() const override {
 | 
					  ManualDns* make_copy() const override {
 | 
				
			||||||
| 
						 | 
					@ -186,8 +194,8 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // creation
 | 
					  // creation
 | 
				
			||||||
  static td::Ref<ManualDns> create(State state) {
 | 
					  static td::Ref<ManualDns> create(State state, block::StdAddress address = {}) {
 | 
				
			||||||
    return td::Ref<ManualDns>(true, std::move(state));
 | 
					    return td::Ref<ManualDns>(true, std::move(state), std::move(address));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  static td::Ref<ManualDns> create(td::Ref<vm::Cell> data = {}, int revision = 0);
 | 
					  static td::Ref<ManualDns> create(td::Ref<vm::Cell> data = {}, int revision = 0);
 | 
				
			||||||
  static td::Ref<ManualDns> create(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, int revision = 0);
 | 
					  static td::Ref<ManualDns> create(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, int revision = 0);
 | 
				
			||||||
| 
						 | 
					@ -208,9 +216,9 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
  td::Result<td::uint32> get_wallet_id() const;
 | 
					  td::Result<td::uint32> get_wallet_id() const;
 | 
				
			||||||
  td::Result<td::uint32> get_wallet_id_or_throw() const;
 | 
					  td::Result<td::uint32> get_wallet_id_or_throw() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_set_value_unsigned(td::int16 category, td::Slice name,
 | 
					  td::Result<td::Ref<vm::Cell>> create_set_value_unsigned(td::Bits256 category, td::Slice name,
 | 
				
			||||||
                                                          td::Ref<vm::Cell> data) const;
 | 
					                                                          td::Ref<vm::Cell> data) const;
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_delete_value_unsigned(td::int16 category, td::Slice name) const;
 | 
					  td::Result<td::Ref<vm::Cell>> create_delete_value_unsigned(td::Bits256 category, td::Slice name) const;
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_delete_all_unsigned() const;
 | 
					  td::Result<td::Ref<vm::Cell>> create_delete_all_unsigned() const;
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_set_all_unsigned(td::Span<Action> entries) const;
 | 
					  td::Result<td::Ref<vm::Cell>> create_set_all_unsigned(td::Span<Action> entries) const;
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_delete_name_unsigned(td::Slice name) const;
 | 
					  td::Result<td::Ref<vm::Cell>> create_delete_name_unsigned(td::Slice name) const;
 | 
				
			||||||
| 
						 | 
					@ -222,8 +230,8 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
  static td::Ref<vm::Cell> create_init_data_fast(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id);
 | 
					  static td::Ref<vm::Cell> create_init_data_fast(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  size_t get_max_name_size() const override;
 | 
					  size_t get_max_name_size() const override;
 | 
				
			||||||
  td::Result<std::vector<RawEntry>> resolve_raw(td::Slice name, td::int32 category_big) const override;
 | 
					  td::Result<std::vector<RawEntry>> resolve_raw(td::Slice name, td::Bits256 category) const override;
 | 
				
			||||||
  td::Result<std::vector<RawEntry>> resolve_raw_or_throw(td::Slice name, td::int32 category_big) const;
 | 
					  td::Result<std::vector<RawEntry>> resolve_raw_or_throw(td::Slice name, td::Bits256 category) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_init_query(
 | 
					  td::Result<td::Ref<vm::Cell>> create_init_query(
 | 
				
			||||||
      const td::Ed25519::PrivateKey& private_key,
 | 
					      const td::Ed25519::PrivateKey& private_key,
 | 
				
			||||||
| 
						 | 
					@ -235,10 +243,10 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
  template <class ActionT>
 | 
					  template <class ActionT>
 | 
				
			||||||
  struct CombinedActions {
 | 
					  struct CombinedActions {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category{0};
 | 
					    td::Bits256 category = td::Bits256::zero();
 | 
				
			||||||
    td::optional<std::vector<ActionT>> actions;
 | 
					    td::optional<std::vector<ActionT>> actions;
 | 
				
			||||||
    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const CombinedActions& action) {
 | 
					    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const CombinedActions& action) {
 | 
				
			||||||
      sb << action.name << ":" << action.category << ":";
 | 
					      sb << action.name << ":" << action.category.to_hex() << ":";
 | 
				
			||||||
      if (action.actions) {
 | 
					      if (action.actions) {
 | 
				
			||||||
        sb << "<data>" << action.actions.value().size();
 | 
					        sb << "<data>" << action.actions.value().size();
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
| 
						 | 
					@ -251,7 +259,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
  template <class ActionT = Action>
 | 
					  template <class ActionT = Action>
 | 
				
			||||||
  static std::vector<CombinedActions<ActionT>> combine_actions(td::Span<ActionT> actions) {
 | 
					  static std::vector<CombinedActions<ActionT>> combine_actions(td::Span<ActionT> actions) {
 | 
				
			||||||
    struct Info {
 | 
					    struct Info {
 | 
				
			||||||
      std::set<td::int16> known_category;
 | 
					      std::set<td::Bits256> known_category;
 | 
				
			||||||
      std::vector<ActionT> actions;
 | 
					      std::vector<ActionT> actions;
 | 
				
			||||||
      bool closed{false};
 | 
					      bool closed{false};
 | 
				
			||||||
      bool non_empty{false};
 | 
					      bool non_empty{false};
 | 
				
			||||||
| 
						 | 
					@ -278,7 +286,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
      if (info.closed) {
 | 
					      if (info.closed) {
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (action.category != 0 && action.does_create_category()) {
 | 
					      if (!action.category.is_zero() && action.does_create_category()) {
 | 
				
			||||||
        info.non_empty = true;
 | 
					        info.non_empty = true;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (!info.known_category.insert(action.category).second) {
 | 
					      if (!info.known_category.insert(action.category).second) {
 | 
				
			||||||
| 
						 | 
					@ -330,6 +338,8 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
 | 
				
			||||||
    return res;
 | 
					    return res;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  td::Result<td::Ref<vm::Cell>> create_update_query(CombinedActions<Action>& combined) const;
 | 
					  td::Result<td::Ref<vm::Cell>> create_update_query(CombinedActions<Action>& combined) const;
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  block::StdAddress address_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ton
 | 
					}  // namespace ton
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -810,7 +810,7 @@ class MapDns {
 | 
				
			||||||
  using ManualDns = ton::ManualDns;
 | 
					  using ManualDns = ton::ManualDns;
 | 
				
			||||||
  struct Entry {
 | 
					  struct Entry {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category{0};
 | 
					    td::Bits256 category = td::Bits256::zero();
 | 
				
			||||||
    std::string text;
 | 
					    std::string text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto key() const {
 | 
					    auto key() const {
 | 
				
			||||||
| 
						 | 
					@ -827,34 +827,34 @@ class MapDns {
 | 
				
			||||||
      return key() == other.key() && text == other.text;
 | 
					      return key() == other.key() && text == other.text;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Entry& entry) {
 | 
					    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Entry& entry) {
 | 
				
			||||||
      return sb << "[" << entry.name << ":" << entry.category << ":" << entry.text << "]";
 | 
					      return sb << "[" << entry.name << ":" << entry.category.to_hex() << ":" << entry.text << "]";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  struct Action {
 | 
					  struct Action {
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
    td::int16 category{0};
 | 
					    td::Bits256 category = td::Bits256::zero();
 | 
				
			||||||
    td::optional<std::string> text;
 | 
					    td::optional<std::string> text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool does_create_category() const {
 | 
					    bool does_create_category() const {
 | 
				
			||||||
      CHECK(!name.empty());
 | 
					      CHECK(!name.empty());
 | 
				
			||||||
      CHECK(category != 0);
 | 
					      CHECK(!category.is_zero());
 | 
				
			||||||
      return static_cast<bool>(text);
 | 
					      return static_cast<bool>(text);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bool does_change_empty() const {
 | 
					    bool does_change_empty() const {
 | 
				
			||||||
      CHECK(!name.empty());
 | 
					      CHECK(!name.empty());
 | 
				
			||||||
      CHECK(category != 0);
 | 
					      CHECK(!category.is_zero());
 | 
				
			||||||
      return static_cast<bool>(text) && !text.value().empty();
 | 
					      return static_cast<bool>(text) && !text.value().empty();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    void make_non_empty() {
 | 
					    void make_non_empty() {
 | 
				
			||||||
      CHECK(!name.empty());
 | 
					      CHECK(!name.empty());
 | 
				
			||||||
      CHECK(category != 0);
 | 
					      CHECK(!category.is_zero());
 | 
				
			||||||
      if (!text) {
 | 
					      if (!text) {
 | 
				
			||||||
        text = "";
 | 
					        text = "";
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& entry) {
 | 
					    friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& entry) {
 | 
				
			||||||
      return sb << "[" << entry.name << ":" << entry.category << ":" << (entry.text ? entry.text.value() : "<empty>")
 | 
					      return sb << "[" << entry.name << ":" << entry.category.to_hex() << ":"
 | 
				
			||||||
                << "]";
 | 
					                << (entry.text ? entry.text.value() : "<empty>") << "]";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  void update(td::Span<Action> actions) {
 | 
					  void update(td::Span<Action> actions) {
 | 
				
			||||||
| 
						 | 
					@ -868,7 +868,7 @@ class MapDns {
 | 
				
			||||||
    LOG(ERROR) << td::format::as_array(actions);
 | 
					    LOG(ERROR) << td::format::as_array(actions);
 | 
				
			||||||
    auto combined_actions = ton::ManualDns::combine_actions(actions);
 | 
					    auto combined_actions = ton::ManualDns::combine_actions(actions);
 | 
				
			||||||
    for (auto& c : combined_actions) {
 | 
					    for (auto& c : combined_actions) {
 | 
				
			||||||
      LOG(ERROR) << c.name << ":" << c.category;
 | 
					      LOG(ERROR) << c.name << ":" << c.category.to_hex();
 | 
				
			||||||
      if (c.actions) {
 | 
					      if (c.actions) {
 | 
				
			||||||
        LOG(ERROR) << td::format::as_array(c.actions.value());
 | 
					        LOG(ERROR) << td::format::as_array(c.actions.value());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -879,7 +879,7 @@ class MapDns {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Entry> resolve(td::Slice name, td::int16 category) {
 | 
					  std::vector<Entry> resolve(td::Slice name, td::Bits256 category) {
 | 
				
			||||||
    std::vector<Entry> res;
 | 
					    std::vector<Entry> res;
 | 
				
			||||||
    if (name.empty()) {
 | 
					    if (name.empty()) {
 | 
				
			||||||
      for (auto& a : entries_) {
 | 
					      for (auto& a : entries_) {
 | 
				
			||||||
| 
						 | 
					@ -891,7 +891,7 @@ class MapDns {
 | 
				
			||||||
      auto it = entries_.find(name);
 | 
					      auto it = entries_.find(name);
 | 
				
			||||||
      while (it == entries_.end()) {
 | 
					      while (it == entries_.end()) {
 | 
				
			||||||
        auto sz = name.find('.');
 | 
					        auto sz = name.find('.');
 | 
				
			||||||
        category = -1;
 | 
					        category = ton::DNS_NEXT_RESOLVER_CATEGORY;
 | 
				
			||||||
        if (sz != td::Slice::npos) {
 | 
					        if (sz != td::Slice::npos) {
 | 
				
			||||||
          name = name.substr(sz + 1);
 | 
					          name = name.substr(sz + 1);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -901,7 +901,7 @@ class MapDns {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (it != entries_.end()) {
 | 
					      if (it != entries_.end()) {
 | 
				
			||||||
        for (auto& b : it->second) {
 | 
					        for (auto& b : it->second) {
 | 
				
			||||||
          if (category == 0 || category == b.first) {
 | 
					          if (category.is_zero() || category == b.first) {
 | 
				
			||||||
            res.push_back({name.str(), b.first, b.second});
 | 
					            res.push_back({name.str(), b.first, b.second});
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -913,13 +913,13 @@ class MapDns {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  std::map<std::string, std::map<td::int16, std::string>, std::less<>> entries_;
 | 
					  std::map<std::string, std::map<td::Bits256, std::string>, std::less<>> entries_;
 | 
				
			||||||
  void do_update(const Action& action) {
 | 
					  void do_update(const Action& action) {
 | 
				
			||||||
    if (action.name.empty()) {
 | 
					    if (action.name.empty()) {
 | 
				
			||||||
      entries_.clear();
 | 
					      entries_.clear();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (action.category == 0) {
 | 
					    if (action.category.is_zero()) {
 | 
				
			||||||
      entries_.erase(action.name);
 | 
					      entries_.erase(action.name);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -946,7 +946,7 @@ class MapDns {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      for (auto& action : actions.actions.value()) {
 | 
					      for (auto& action : actions.actions.value()) {
 | 
				
			||||||
        CHECK(!action.name.empty());
 | 
					        CHECK(!action.name.empty());
 | 
				
			||||||
        CHECK(action.category != 0);
 | 
					        CHECK(!action.category.is_zero());
 | 
				
			||||||
        CHECK(action.text);
 | 
					        CHECK(action.text);
 | 
				
			||||||
        if (action.text.value().empty()) {
 | 
					        if (action.text.value().empty()) {
 | 
				
			||||||
          entries_[action.name];
 | 
					          entries_[action.name];
 | 
				
			||||||
| 
						 | 
					@ -956,7 +956,7 @@ class MapDns {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (actions.category == 0) {
 | 
					    if (!actions.category.is_zero()) {
 | 
				
			||||||
      entries_.erase(actions.name);
 | 
					      entries_.erase(actions.name);
 | 
				
			||||||
      LOG(ERROR) << "CLEAR " << actions.name;
 | 
					      LOG(ERROR) << "CLEAR " << actions.name;
 | 
				
			||||||
      if (!actions.actions) {
 | 
					      if (!actions.actions) {
 | 
				
			||||||
| 
						 | 
					@ -965,7 +965,7 @@ class MapDns {
 | 
				
			||||||
      entries_[actions.name];
 | 
					      entries_[actions.name];
 | 
				
			||||||
      for (auto& action : actions.actions.value()) {
 | 
					      for (auto& action : actions.actions.value()) {
 | 
				
			||||||
        CHECK(action.name == actions.name);
 | 
					        CHECK(action.name == actions.name);
 | 
				
			||||||
        CHECK(action.category != 0);
 | 
					        CHECK(!action.category.is_zero());
 | 
				
			||||||
        CHECK(action.text);
 | 
					        CHECK(action.text);
 | 
				
			||||||
        if (action.text.value().empty()) {
 | 
					        if (action.text.value().empty()) {
 | 
				
			||||||
          entries_[action.name];
 | 
					          entries_[action.name];
 | 
				
			||||||
| 
						 | 
					@ -979,7 +979,7 @@ class MapDns {
 | 
				
			||||||
    CHECK(actions.actions.value().size() == 1);
 | 
					    CHECK(actions.actions.value().size() == 1);
 | 
				
			||||||
    for (auto& action : actions.actions.value()) {
 | 
					    for (auto& action : actions.actions.value()) {
 | 
				
			||||||
      CHECK(action.name == actions.name);
 | 
					      CHECK(action.name == actions.name);
 | 
				
			||||||
      CHECK(action.category != 0);
 | 
					      CHECK(!action.category.is_zero());
 | 
				
			||||||
      if (action.text) {
 | 
					      if (action.text) {
 | 
				
			||||||
        if (action.text.value().empty()) {
 | 
					        if (action.text.value().empty()) {
 | 
				
			||||||
          entries_[action.name].erase(action.category);
 | 
					          entries_[action.name].erase(action.category);
 | 
				
			||||||
| 
						 | 
					@ -1036,8 +1036,8 @@ class CheckedDns {
 | 
				
			||||||
    return update(td::span_one(action));
 | 
					    return update(td::span_one(action));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Entry> resolve(td::Slice name, td::int16 category) {
 | 
					  std::vector<Entry> resolve(td::Slice name, td::Bits256 category) {
 | 
				
			||||||
    LOG(ERROR) << "RESOLVE: " << name << " " << category;
 | 
					    LOG(ERROR) << "RESOLVE: " << name << " " << category.to_hex();
 | 
				
			||||||
    auto res = map_dns_.resolve(name, category);
 | 
					    auto res = map_dns_.resolve(name, category);
 | 
				
			||||||
    LOG(ERROR) << td::format::as_array(res);
 | 
					    LOG(ERROR) << td::format::as_array(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1092,6 +1092,12 @@ class CheckedDns {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static td::Bits256 intToCat(int x) {
 | 
				
			||||||
 | 
					  td::Bits256 cat = td::Bits256::zero();
 | 
				
			||||||
 | 
					  cat.as_slice().copy_from(td::Slice((char*)&x, sizeof(x)));
 | 
				
			||||||
 | 
					  return cat;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void do_dns_test(CheckedDns&& dns) {
 | 
					void do_dns_test(CheckedDns&& dns) {
 | 
				
			||||||
  using Action = CheckedDns::Action;
 | 
					  using Action = CheckedDns::Action;
 | 
				
			||||||
  std::vector<Action> actions;
 | 
					  std::vector<Action> actions;
 | 
				
			||||||
| 
						 | 
					@ -1130,7 +1136,7 @@ void do_dns_test(CheckedDns&& dns) {
 | 
				
			||||||
    if (rnd.fast(0, 20) == 0) {
 | 
					    if (rnd.fast(0, 20) == 0) {
 | 
				
			||||||
      return action;
 | 
					      return action;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    action.category = td::narrow_cast<td::int16>(rnd.fast(1, 5));
 | 
					    action.category = intToCat(rnd.fast(1, 5));
 | 
				
			||||||
    if (rnd.fast(0, 4) == 0) {
 | 
					    if (rnd.fast(0, 4) == 0) {
 | 
				
			||||||
      return action;
 | 
					      return action;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1150,7 +1156,8 @@ void do_dns_test(CheckedDns&& dns) {
 | 
				
			||||||
      actions.clear();
 | 
					      actions.clear();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto name = gen_name();
 | 
					    auto name = gen_name();
 | 
				
			||||||
    dns.resolve(name, td::narrow_cast<td::int16>(rnd.fast(0, 5)));
 | 
					    auto category = td::Bits256::zero();
 | 
				
			||||||
 | 
					    dns.resolve(name, intToCat(rnd.fast(0, 5)));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1167,7 +1174,7 @@ TEST(Smartcont, DnsManual) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  CHECK(td::Slice("a\0b\0") == ManualDns::encode_name("b.a"));
 | 
					  CHECK(td::Slice("a\0b\0") == ManualDns::encode_name("b.a"));
 | 
				
			||||||
  CHECK(td::Slice("a\0b\0") == ManualDns::encode_name(".b.a"));
 | 
					  CHECK(td::Slice("a\0b\0") == ManualDns::encode_name(".b.a"));
 | 
				
			||||||
  ASSERT_EQ("b.a", ManualDns::decode_name("a\0b\0"));
 | 
					  ASSERT_EQ(".b.a", ManualDns::decode_name("a\0b\0"));
 | 
				
			||||||
  ASSERT_EQ("b.a", ManualDns::decode_name("a\0b"));
 | 
					  ASSERT_EQ("b.a", ManualDns::decode_name("a\0b"));
 | 
				
			||||||
  ASSERT_EQ("", ManualDns::decode_name(""));
 | 
					  ASSERT_EQ("", ManualDns::decode_name(""));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1184,8 +1191,8 @@ TEST(Smartcont, DnsManual) {
 | 
				
			||||||
  auto value = vm::CellBuilder().store_bytes("hello world").finalize();
 | 
					  auto value = vm::CellBuilder().store_bytes("hello world").finalize();
 | 
				
			||||||
  auto set_query =
 | 
					  auto set_query =
 | 
				
			||||||
      manual
 | 
					      manual
 | 
				
			||||||
          ->sign(key,
 | 
					          ->sign(key, manual->prepare(manual->create_set_value_unsigned(intToCat(1), "a\0b\0", value).move_as_ok(), 1)
 | 
				
			||||||
                 manual->prepare(manual->create_set_value_unsigned(1, "a\0b\0", value).move_as_ok(), 1).move_as_ok())
 | 
					                          .move_as_ok())
 | 
				
			||||||
          .move_as_ok();
 | 
					          .move_as_ok();
 | 
				
			||||||
  CHECK(manual.write().send_external_message(set_query).code == 0);
 | 
					  CHECK(manual.write().send_external_message(set_query).code == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1195,46 +1202,48 @@ TEST(Smartcont, DnsManual) {
 | 
				
			||||||
  CHECK(res.stack.write().pop_cell()->get_hash() == value->get_hash());
 | 
					  CHECK(res.stack.write().pop_cell()->get_hash() == value->get_hash());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  CheckedDns dns;
 | 
					  CheckedDns dns;
 | 
				
			||||||
  dns.update(CheckedDns::Action{"a.b.c", 1, "hello"});
 | 
					  dns.update(CheckedDns::Action{"a.b.c", intToCat(1), "hello"});
 | 
				
			||||||
  CHECK(dns.resolve("a.b.c", 1).at(0).text == "hello");
 | 
					  CHECK(dns.resolve("a.b.c", intToCat(1)).at(0).text == "hello");
 | 
				
			||||||
  dns.resolve("a", 1);
 | 
					  dns.resolve("a", intToCat(1));
 | 
				
			||||||
  dns.resolve("a.b", 1);
 | 
					  dns.resolve("a.b", intToCat(1));
 | 
				
			||||||
  CHECK(dns.resolve("a.b.c", 2).empty());
 | 
					  CHECK(dns.resolve("a.b.c", intToCat(2)).empty());
 | 
				
			||||||
  dns.update(CheckedDns::Action{"a.b.c", 2, "test"});
 | 
					  dns.update(CheckedDns::Action{"a.b.c", intToCat(2), "test"});
 | 
				
			||||||
  CHECK(dns.resolve("a.b.c", 2).at(0).text == "test");
 | 
					  CHECK(dns.resolve("a.b.c", intToCat(2)).at(0).text == "test");
 | 
				
			||||||
  dns.resolve("a.b.c", 1);
 | 
					  dns.resolve("a.b.c", intToCat(1));
 | 
				
			||||||
  dns.resolve("a.b.c", 2);
 | 
					  dns.resolve("a.b.c", intToCat(2));
 | 
				
			||||||
  LOG(ERROR) << "Test zero category";
 | 
					  LOG(ERROR) << "Test zero category";
 | 
				
			||||||
  dns.resolve("a.b.c", 0);
 | 
					  dns.resolve("a.b.c", intToCat(0));
 | 
				
			||||||
  dns.update(CheckedDns::Action{"", 0, ""});
 | 
					  dns.update(CheckedDns::Action{"", intToCat(0), ""});
 | 
				
			||||||
  CHECK(dns.resolve("a.b.c", 2).empty());
 | 
					  CHECK(dns.resolve("a.b.c", intToCat(2)).empty());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG(ERROR) << "Test multipe update";
 | 
					  LOG(ERROR) << "Test multipe update";
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    CheckedDns::Action e[4] = {CheckedDns::Action{"", 0, ""}, CheckedDns::Action{"a.b.c", 1, "hello"},
 | 
					    CheckedDns::Action e[4] = {
 | 
				
			||||||
                               CheckedDns::Action{"a.b.c", 2, "world"}, CheckedDns::Action{"x.y.z", 3, "abc"}};
 | 
					        CheckedDns::Action{"", intToCat(0), ""}, CheckedDns::Action{"a.b.c", intToCat(1), "hello"},
 | 
				
			||||||
 | 
					        CheckedDns::Action{"a.b.c", intToCat(2), "world"}, CheckedDns::Action{"x.y.z", intToCat(3), "abc"}};
 | 
				
			||||||
    dns.update(td::span(e, 4));
 | 
					    dns.update(td::span(e, 4));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  dns.resolve("a.b.c", 1);
 | 
					  dns.resolve("a.b.c", intToCat(1));
 | 
				
			||||||
  dns.resolve("a.b.c", 2);
 | 
					  dns.resolve("a.b.c", intToCat(2));
 | 
				
			||||||
  dns.resolve("x.y.z", 3);
 | 
					  dns.resolve("x.y.z", intToCat(3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  dns.update(td::span_one(CheckedDns::Action{"x.y.z", 0, ""}));
 | 
					  dns.update(td::span_one(CheckedDns::Action{"x.y.z", intToCat(0), ""}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  dns.resolve("a.b.c", 1);
 | 
					  dns.resolve("a.b.c", intToCat(1));
 | 
				
			||||||
  dns.resolve("a.b.c", 2);
 | 
					  dns.resolve("a.b.c", intToCat(2));
 | 
				
			||||||
  dns.resolve("x.y.z", 3);
 | 
					  dns.resolve("x.y.z", intToCat(3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    CheckedDns::Action e[3] = {CheckedDns::Action{"x.y.z", 0, ""}, CheckedDns::Action{"x.y.z", 1, "xxx"},
 | 
					    CheckedDns::Action e[3] = {CheckedDns::Action{"x.y.z", intToCat(0), ""},
 | 
				
			||||||
                               CheckedDns::Action{"x.y.z", 2, "yyy"}};
 | 
					                               CheckedDns::Action{"x.y.z", intToCat(1), "xxx"},
 | 
				
			||||||
 | 
					                               CheckedDns::Action{"x.y.z", intToCat(2), "yyy"}};
 | 
				
			||||||
    dns.update(td::span(e, 3));
 | 
					    dns.update(td::span(e, 3));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  dns.resolve("a.b.c", 1);
 | 
					  dns.resolve("a.b.c", intToCat(1));
 | 
				
			||||||
  dns.resolve("a.b.c", 2);
 | 
					  dns.resolve("a.b.c", intToCat(2));
 | 
				
			||||||
  dns.resolve("x.y.z", 1);
 | 
					  dns.resolve("x.y.z", intToCat(1));
 | 
				
			||||||
  dns.resolve("x.y.z", 2);
 | 
					  dns.resolve("x.y.z", intToCat(2));
 | 
				
			||||||
  dns.resolve("x.y.z", 3);
 | 
					  dns.resolve("x.y.z", intToCat(3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    auto actions_ext =
 | 
					    auto actions_ext =
 | 
				
			||||||
| 
						 | 
					@ -1250,8 +1259,8 @@ TEST(Smartcont, DnsManual) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dns.update(actions);
 | 
					    dns.update(actions);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  dns.resolve("one", 1);
 | 
					  dns.resolve("one", intToCat(1));
 | 
				
			||||||
  dns.resolve("two", 2);
 | 
					  dns.resolve("two", intToCat(2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: rethink semantic of creating an empty dictionary
 | 
					  // TODO: rethink semantic of creating an empty dictionary
 | 
				
			||||||
  do_dns_test(CheckedDns(true, true));
 | 
					  do_dns_test(CheckedDns(true, true));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,7 @@
 | 
				
			||||||
#include "openssl/rand.hpp"
 | 
					#include "openssl/rand.hpp"
 | 
				
			||||||
#include "crypto/vm/utils.h"
 | 
					#include "crypto/vm/utils.h"
 | 
				
			||||||
#include "crypto/common/util.h"
 | 
					#include "crypto/common/util.h"
 | 
				
			||||||
 | 
					#include "common/checksum.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if TD_DARWIN || TD_LINUX
 | 
					#if TD_DARWIN || TD_LINUX
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
| 
						 | 
					@ -1025,11 +1026,13 @@ bool TestNode::do_parse_line() {
 | 
				
			||||||
    workchain = ton::workchainInvalid;
 | 
					    workchain = ton::workchainInvalid;
 | 
				
			||||||
    bool step = (word.size() > 10);
 | 
					    bool step = (word.size() > 10);
 | 
				
			||||||
    std::string domain;
 | 
					    std::string domain;
 | 
				
			||||||
    int cat = 0;
 | 
					    std::string cat_str;
 | 
				
			||||||
    return (!step || parse_account_addr(workchain, addr)) && get_word_to(domain) &&
 | 
					    return (!step || parse_account_addr(workchain, addr)) && get_word_to(domain) &&
 | 
				
			||||||
           (parse_block_id_ext(domain, blkid) ? get_word_to(domain) : (blkid = mc_last_id_).is_valid()) &&
 | 
					           (parse_block_id_ext(domain, blkid) ? get_word_to(domain) : (blkid = mc_last_id_).is_valid()) &&
 | 
				
			||||||
           (seekeoln() || parse_int16(cat)) && seekeoln() &&
 | 
					           (seekeoln() || get_word_to(cat_str)) && seekeoln() &&
 | 
				
			||||||
           dns_resolve_start(workchain, addr, blkid, domain, cat, step);
 | 
					           dns_resolve_start(workchain, addr, blkid, domain,
 | 
				
			||||||
 | 
					                             cat_str.empty() ? td::Bits256::zero() : td::sha256_bits256(td::as_slice(cat_str)),
 | 
				
			||||||
 | 
					                             step ? 3 : 0);
 | 
				
			||||||
  } else if (word == "allshards" || word == "allshardssave") {
 | 
					  } else if (word == "allshards" || word == "allshardssave") {
 | 
				
			||||||
    std::string filename;
 | 
					    std::string filename;
 | 
				
			||||||
    return (word.size() <= 9 || get_word_to(filename)) &&
 | 
					    return (word.size() <= 9 || get_word_to(filename)) &&
 | 
				
			||||||
| 
						 | 
					@ -1599,37 +1602,42 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
					bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
				
			||||||
                                 std::string domain, int cat, int mode) {
 | 
					                                 std::string domain, td::Bits256 cat, int mode) {
 | 
				
			||||||
  if (domain.size() > 1023) {
 | 
					 | 
				
			||||||
    return set_error("domain name too long");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') {
 | 
					  if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') {
 | 
				
			||||||
    domain.erase(0, 1);
 | 
					    domain.erase(0, 1);
 | 
				
			||||||
    domain.pop_back();
 | 
					    domain.pop_back();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  std::vector<std::string> components;
 | 
					  std::vector<std::string> components;
 | 
				
			||||||
  std::size_t i, p = 0;
 | 
					  if (domain != ".") {
 | 
				
			||||||
  for (i = 0; i < domain.size(); i++) {
 | 
					    std::size_t i, p = 0;
 | 
				
			||||||
    if (!domain[i] || (unsigned char)domain[i] >= 0xfe || (unsigned char)domain[i] <= ' ') {
 | 
					    for (i = 0; i < domain.size(); i++) {
 | 
				
			||||||
      return set_error("invalid characters in a domain name");
 | 
					      if (!domain[i] || (unsigned char)domain[i] >= 0xfe || (unsigned char)domain[i] <= ' ') {
 | 
				
			||||||
    }
 | 
					        return set_error("invalid characters in a domain name");
 | 
				
			||||||
    if (domain[i] == '.') {
 | 
					 | 
				
			||||||
      if (i == p) {
 | 
					 | 
				
			||||||
        return set_error("domain name cannot have an empty component");
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      if (domain[i] == '.') {
 | 
				
			||||||
 | 
					        if (i == p) {
 | 
				
			||||||
 | 
					          return set_error("domain name cannot have an empty component");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        components.emplace_back(domain, p, i - p);
 | 
				
			||||||
 | 
					        p = i + 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (i > p) {
 | 
				
			||||||
      components.emplace_back(domain, p, i - p);
 | 
					      components.emplace_back(domain, p, i - p);
 | 
				
			||||||
      p = i + 1;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (i > p) {
 | 
					  std::string qdomain;
 | 
				
			||||||
    components.emplace_back(domain, p, i - p);
 | 
					  if (mode & 2) {
 | 
				
			||||||
 | 
					    qdomain += '\0';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  std::string qdomain, qdomain0;
 | 
					 | 
				
			||||||
  while (!components.empty()) {
 | 
					  while (!components.empty()) {
 | 
				
			||||||
    qdomain += components.back();
 | 
					    qdomain += components.back();
 | 
				
			||||||
    qdomain += '\0';
 | 
					    qdomain += '\0';
 | 
				
			||||||
    components.pop_back();
 | 
					    components.pop_back();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (qdomain.size() > 127) {
 | 
				
			||||||
 | 
					    return set_error("domain name too long");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(ready_ && !client_.empty())) {
 | 
					  if (!(ready_ && !client_.empty())) {
 | 
				
			||||||
    return set_error("server connection not ready");
 | 
					    return set_error("server connection not ready");
 | 
				
			||||||
| 
						 | 
					@ -1657,26 +1665,18 @@ bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
					bool TestNode::dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
				
			||||||
                                std::string domain, std::string qdomain, int cat, int mode) {
 | 
					                                std::string domain, std::string qdomain, td::Bits256 cat, int mode) {
 | 
				
			||||||
  LOG(INFO) << "dns_resolve for '" << domain << "' category=" << cat << " mode=" << mode
 | 
					  LOG(INFO) << "dns_resolve for '" << domain << "' category=" << cat << " mode=" << mode
 | 
				
			||||||
            << " starting from smart contract " << workchain << ":" << addr.to_hex() << " with respect to block "
 | 
					            << " starting from smart contract " << workchain << ":" << addr.to_hex() << " with respect to block "
 | 
				
			||||||
            << blkid.to_str();
 | 
					            << blkid.to_str();
 | 
				
			||||||
  std::string qdomain0;
 | 
					 | 
				
			||||||
  if (qdomain.size() <= 127) {
 | 
					 | 
				
			||||||
    qdomain0 = qdomain;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    qdomain0 = std::string{qdomain, 0, 127};
 | 
					 | 
				
			||||||
    qdomain[125] = '\xff';
 | 
					 | 
				
			||||||
    qdomain[126] = '\x0';
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  vm::CellBuilder cb;
 | 
					  vm::CellBuilder cb;
 | 
				
			||||||
  Ref<vm::Cell> cell;
 | 
					  Ref<vm::Cell> cell;
 | 
				
			||||||
  if (!(cb.store_bytes_bool(td::Slice(qdomain0)) && cb.finalize_to(cell))) {
 | 
					  if (!(cb.store_bytes_bool(td::Slice(qdomain)) && cb.finalize_to(cell))) {
 | 
				
			||||||
    return set_error("cannot store domain name into slice");
 | 
					    return set_error("cannot store domain name into slice");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  std::vector<vm::StackEntry> params;
 | 
					  std::vector<vm::StackEntry> params;
 | 
				
			||||||
  params.emplace_back(vm::load_cell_slice_ref(std::move(cell)));
 | 
					  params.emplace_back(vm::load_cell_slice_ref(cell));
 | 
				
			||||||
  params.emplace_back(td::make_refint(cat));
 | 
					  params.emplace_back(td::bits_to_refint(cat.cbits(), 256, false));
 | 
				
			||||||
  auto P = td::PromiseCreator::lambda([this, workchain, addr, blkid, domain, qdomain, cat,
 | 
					  auto P = td::PromiseCreator::lambda([this, workchain, addr, blkid, domain, qdomain, cat,
 | 
				
			||||||
                                       mode](td::Result<std::vector<vm::StackEntry>> R) {
 | 
					                                       mode](td::Result<std::vector<vm::StackEntry>> R) {
 | 
				
			||||||
    if (R.is_error()) {
 | 
					    if (R.is_error()) {
 | 
				
			||||||
| 
						 | 
					@ -1701,12 +1701,12 @@ bool TestNode::dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
				
			||||||
  return start_run_method(workchain, addr, blkid, "dnsresolve", std::move(params), 0x1f, std::move(P));
 | 
					  return start_run_method(workchain, addr, blkid, "dnsresolve", std::move(params), 0x1f, std::move(P));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TestNode::show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, bool raw_dump) {
 | 
					bool TestNode::show_dns_record(std::ostream& os, td::Bits256 cat, Ref<vm::CellSlice> value, bool raw_dump) {
 | 
				
			||||||
  if (raw_dump) {
 | 
					  if (raw_dump) {
 | 
				
			||||||
    bool ok = show_dns_record(os, cat, value, false);
 | 
					    bool ok = show_dns_record(os, cat, value, false);
 | 
				
			||||||
    if (!ok) {
 | 
					    if (!ok) {
 | 
				
			||||||
      os << "cannot parse dns record; raw value: ";
 | 
					      os << "cannot parse dns record; raw value: ";
 | 
				
			||||||
      vm::load_cell_slice(value).print_rec(print_limit_, os);
 | 
					      value->print_rec(print_limit_, os);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ok;
 | 
					    return ok;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -1715,11 +1715,11 @@ bool TestNode::show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, b
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // block::gen::t_DNSRecord.print_ref(print_limit_, os, value);
 | 
					  // block::gen::t_DNSRecord.print_ref(print_limit_, os, value);
 | 
				
			||||||
  if (!block::gen::t_DNSRecord.validate_ref(value)) {
 | 
					  if (!block::gen::t_DNSRecord.validate_csr(value)) {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  block::gen::t_DNSRecord.print_ref(print_limit_, os, value);
 | 
					  block::gen::t_DNSRecord.print(os, value, 0, print_limit_);
 | 
				
			||||||
  auto cs = vm::load_cell_slice(value);
 | 
					  auto cs = *value;
 | 
				
			||||||
  auto tag = block::gen::t_DNSRecord.get_tag(cs);
 | 
					  auto tag = block::gen::t_DNSRecord.get_tag(cs);
 | 
				
			||||||
  ton::WorkchainId wc;
 | 
					  ton::WorkchainId wc;
 | 
				
			||||||
  ton::StdSmcAddress addr;
 | 
					  ton::StdSmcAddress addr;
 | 
				
			||||||
| 
						 | 
					@ -1751,7 +1751,7 @@ bool TestNode::show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, b
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
					void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
				
			||||||
                                  std::string domain, std::string qdomain, int cat, int mode, int used_bits,
 | 
					                                  std::string domain, std::string qdomain, td::Bits256 cat, int mode, int used_bits,
 | 
				
			||||||
                                  Ref<vm::Cell> value) {
 | 
					                                  Ref<vm::Cell> value) {
 | 
				
			||||||
  if (used_bits <= 0) {
 | 
					  if (used_bits <= 0) {
 | 
				
			||||||
    td::TerminalIO::out() << "domain '" << domain << "' not found" << std::endl;
 | 
					    td::TerminalIO::out() << "domain '" << domain << "' not found" << std::endl;
 | 
				
			||||||
| 
						 | 
					@ -1761,12 +1761,12 @@ void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
    LOG(ERROR) << "too many bits used (" << used_bits << " out of " << qdomain.size() * 8 << ")";
 | 
					    LOG(ERROR) << "too many bits used (" << used_bits << " out of " << qdomain.size() * 8 << ")";
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  int pos = (used_bits >> 3);
 | 
					  size_t pos = used_bits >> 3;
 | 
				
			||||||
  if (qdomain[pos - 1]) {
 | 
					  bool end = pos == qdomain.size();
 | 
				
			||||||
 | 
					  if (!end && qdomain[pos - 1] && qdomain[pos]) {
 | 
				
			||||||
    LOG(ERROR) << "domain split not at a component boundary";
 | 
					    LOG(ERROR) << "domain split not at a component boundary";
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  bool end = ((std::size_t)pos == qdomain.size());
 | 
					 | 
				
			||||||
  if (!end) {
 | 
					  if (!end) {
 | 
				
			||||||
    LOG(INFO) << "partial information obtained";
 | 
					    LOG(INFO) << "partial information obtained";
 | 
				
			||||||
    if (value.is_null()) {
 | 
					    if (value.is_null()) {
 | 
				
			||||||
| 
						 | 
					@ -1778,7 +1778,7 @@ void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
    ton::StdSmcAddress nx_addr;
 | 
					    ton::StdSmcAddress nx_addr;
 | 
				
			||||||
    if (!(block::gen::t_DNSRecord.cell_unpack_dns_next_resolver(value, nx_address) &&
 | 
					    if (!(block::gen::t_DNSRecord.cell_unpack_dns_next_resolver(value, nx_address) &&
 | 
				
			||||||
          block::tlb::t_MsgAddressInt.extract_std_address(std::move(nx_address), nx_wc, nx_addr))) {
 | 
					          block::tlb::t_MsgAddressInt.extract_std_address(std::move(nx_address), nx_wc, nx_addr))) {
 | 
				
			||||||
      LOG(ERROR) << "cannot parse next resolver info for " << domain.substr(qdomain.size() - pos);
 | 
					      LOG(ERROR) << "cannot parse next resolver info for " << domain.substr(qdomain.size() - pos - 1);
 | 
				
			||||||
      std::ostringstream out;
 | 
					      std::ostringstream out;
 | 
				
			||||||
      vm::load_cell_slice(value).print_rec(print_limit_, out);
 | 
					      vm::load_cell_slice(value).print_rec(print_limit_, out);
 | 
				
			||||||
      td::TerminalIO::err() << out.str() << std::endl;
 | 
					      td::TerminalIO::err() << out.str() << std::endl;
 | 
				
			||||||
| 
						 | 
					@ -1792,37 +1792,41 @@ void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
				
			||||||
      LOG(ERROR) << "cannot send next dns query";
 | 
					      LOG(ERROR) << "cannot send next dns query";
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    LOG(INFO) << "recursive dns query to '" << domain.substr(qdomain.size() - pos) << "' sent";
 | 
					    LOG(INFO) << "recursive dns query to '" << domain.substr(qdomain.size() - pos - 1) << "' sent";
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto out = td::TerminalIO::out();
 | 
					  auto out = td::TerminalIO::out();
 | 
				
			||||||
  out << "Result for domain '" << domain << "' category " << cat << (cat ? "" : " (all categories)") << std::endl;
 | 
					  if (cat.is_zero()) {
 | 
				
			||||||
 | 
					    out << "Result for domain '" << domain << "' (all categories)" << std::endl;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    out << "Result for domain '" << domain << "' category " << cat << std::endl;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    if (value.not_null()) {
 | 
					    if (value.not_null()) {
 | 
				
			||||||
      std::ostringstream os0;
 | 
					      std::ostringstream os0;
 | 
				
			||||||
      vm::load_cell_slice(value).print_rec(print_limit_, os0);
 | 
					      vm::load_cell_slice(value).print_rec(print_limit_, os0);
 | 
				
			||||||
      out << "raw data: " << os0.str() << std::endl;
 | 
					      out << "raw data: " << os0.str() << std::endl;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!cat) {
 | 
					    if (cat.is_zero()) {
 | 
				
			||||||
      vm::Dictionary dict{value, 16};
 | 
					      vm::Dictionary dict{value, 256};
 | 
				
			||||||
      if (!dict.check_for_each([this, &out](Ref<vm::CellSlice> cs, td::ConstBitPtr key, int n) {
 | 
					      if (!dict.check_for_each([this, &out](Ref<vm::CellSlice> cs, td::ConstBitPtr key, int n) {
 | 
				
			||||||
            CHECK(n == 16);
 | 
					            CHECK(n == 256);
 | 
				
			||||||
            int x = (int)key.get_int(16);
 | 
					            td::Bits256 x{key};
 | 
				
			||||||
            if (cs.is_null() || cs->size_ext() != 0x10000) {
 | 
					            /*if (cs.is_null() || cs->size_ext() != 0x10000) {
 | 
				
			||||||
              out << "category #" << x << " : value is not a reference" << std::endl;
 | 
					              out << "category " << x << " : value is not a reference" << std::endl;
 | 
				
			||||||
              return false;
 | 
					              return true;
 | 
				
			||||||
            }
 | 
					            }*/
 | 
				
			||||||
            std::ostringstream os;
 | 
					            std::ostringstream os;
 | 
				
			||||||
            (void)show_dns_record(os, x, cs->prefetch_ref(), true);
 | 
					            (void)show_dns_record(os, x, cs, true);
 | 
				
			||||||
            out << "category #" << x << " : " << os.str() << std::endl;
 | 
					            out << "category " << x << " : " << os.str() << std::endl;
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
          })) {
 | 
					          })) {
 | 
				
			||||||
        out << "invalid dns record dictionary" << std::endl;
 | 
					        out << "invalid dns record dictionary" << std::endl;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      std::ostringstream os;
 | 
					      std::ostringstream os;
 | 
				
			||||||
      (void)show_dns_record(os, cat, value, true);
 | 
					      (void)show_dns_record(os, cat, value.is_null() ? Ref<vm::CellSlice>() : vm::load_cell_slice_ref(value), true);
 | 
				
			||||||
      out << "category #" << cat << " : " << os.str() << std::endl;
 | 
					      out << "category " << cat << " : " << os.str() << std::endl;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } catch (vm::VmError& err) {
 | 
					  } catch (vm::VmError& err) {
 | 
				
			||||||
    LOG(ERROR) << "vm error while traversing dns resolve result: " << err.get_msg();
 | 
					    LOG(ERROR) << "vm error while traversing dns resolve result: " << err.get_msg();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -213,13 +213,13 @@ class TestNode : public td::actor::Actor {
 | 
				
			||||||
  bool register_config_param1(Ref<vm::Cell> value);
 | 
					  bool register_config_param1(Ref<vm::Cell> value);
 | 
				
			||||||
  bool register_config_param4(Ref<vm::Cell> value);
 | 
					  bool register_config_param4(Ref<vm::Cell> value);
 | 
				
			||||||
  bool dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
 | 
					  bool dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
 | 
				
			||||||
                         int cat, int mode);
 | 
					                         td::Bits256 cat, int mode);
 | 
				
			||||||
  bool dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
 | 
					  bool dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
 | 
				
			||||||
                        std::string qdomain, int cat, int mode);
 | 
					                        std::string qdomain, td::Bits256 cat, int mode);
 | 
				
			||||||
  void dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
					  void dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
 | 
				
			||||||
                          std::string domain, std::string qdomain, int cat, int mode, int used_bits,
 | 
					                          std::string domain, std::string qdomain, td::Bits256 cat, int mode, int used_bits,
 | 
				
			||||||
                          Ref<vm::Cell> value);
 | 
					                          Ref<vm::Cell> value);
 | 
				
			||||||
  bool show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, bool raw_dump);
 | 
					  bool show_dns_record(std::ostream& os, td::Bits256 cat, Ref<vm::CellSlice> value, bool raw_dump);
 | 
				
			||||||
  bool get_all_shards(std::string filename = "", bool use_last = true, ton::BlockIdExt blkid = {});
 | 
					  bool get_all_shards(std::string filename = "", bool use_last = true, ton::BlockIdExt blkid = {});
 | 
				
			||||||
  void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data, std::string filename);
 | 
					  void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data, std::string filename);
 | 
				
			||||||
  bool parse_get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "",
 | 
					  bool parse_get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1073,7 +1073,8 @@ void TcpToRldpRequestSender::resolve() {
 | 
				
			||||||
    ton::dht::DhtKey dht_key{key.compute_short_id(), "http." + host_, 0};
 | 
					    ton::dht::DhtKey dht_key{key.compute_short_id(), "http." + host_, 0};
 | 
				
			||||||
    td::actor::send_closure(dht_, &ton::dht::Dht::get_value, std::move(dht_key), std::move(P));
 | 
					    td::actor::send_closure(dht_, &ton::dht::Dht::get_value, std::move(dht_key), std::move(P));
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    auto obj = tonlib_api::make_object<tonlib_api::dns_resolve>(nullptr, host_, 0, 16);
 | 
					    td::Bits256 category = td::sha256_bits256(td::Slice("site", 4));
 | 
				
			||||||
 | 
					    auto obj = tonlib_api::make_object<tonlib_api::dns_resolve>(nullptr, host_, category, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto P =
 | 
					    auto P =
 | 
				
			||||||
        td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<tonlib_api::object_ptr<tonlib_api::Object>> R) {
 | 
					        td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<tonlib_api::object_ptr<tonlib_api::Object>> R) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,11 +74,11 @@ int main() {
 | 
				
			||||||
  generate_cpp<td::TD_TL_writer_jni_cpp, td::TD_TL_writer_jni_h>(
 | 
					  generate_cpp<td::TD_TL_writer_jni_cpp, td::TD_TL_writer_jni_h>(
 | 
				
			||||||
      "auto/tl", "tonlib_api", "std::string", "std::string", "td::SecureString", "td::SecureString",
 | 
					      "auto/tl", "tonlib_api", "std::string", "std::string", "td::SecureString", "td::SecureString",
 | 
				
			||||||
      {"\"tl/tl_jni_object.h\"", "\"tl/tl_object_store.h\"", "\"td/utils/int_types.h\""},
 | 
					      {"\"tl/tl_jni_object.h\"", "\"tl/tl_object_store.h\"", "\"td/utils/int_types.h\""},
 | 
				
			||||||
      {"<string>", "\"td/utils/SharedSlice.h\""});
 | 
					      {"<string>", "\"td/utils/SharedSlice.h\"", "\"crypto/common/bitstring.h\""});
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  generate_cpp<>("auto/tl", "tonlib_api", "std::string", "std::string", "td::SecureString", "td::SecureString",
 | 
					  generate_cpp<>("auto/tl", "tonlib_api", "std::string", "std::string", "td::SecureString", "td::SecureString",
 | 
				
			||||||
                 {"\"tl/tl_object_parse.h\"", "\"tl/tl_object_store.h\"", "\"td/utils/int_types.h\""},
 | 
					                 {"\"tl/tl_object_parse.h\"", "\"tl/tl_object_store.h\"", "\"td/utils/int_types.h\""},
 | 
				
			||||||
                 {"<string>", "\"td/utils/SharedSlice.h\""});
 | 
					                 {"<string>", "\"td/utils/SharedSlice.h\"", "\"crypto/common/bitstring.h\""});
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  td::gen_json_converter(td::tl::read_tl_config_from_file("scheme/tonlib_api.tlo"), "auto/tl/tonlib_api_json",
 | 
					  td::gen_json_converter(td::tl::read_tl_config_from_file("scheme/tonlib_api.tlo"), "auto/tl/tonlib_api_json",
 | 
				
			||||||
                         "tonlib_api", td::tl::TL_writer::Mode::All);
 | 
					                         "tonlib_api", td::tl::TL_writer::Mode::All);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ string ? = String;
 | 
				
			||||||
int32 = Int32;
 | 
					int32 = Int32;
 | 
				
			||||||
int53 = Int53;
 | 
					int53 = Int53;
 | 
				
			||||||
int64 = Int64;
 | 
					int64 = Int64;
 | 
				
			||||||
 | 
					int256 8*[ int32 ] = Int256;
 | 
				
			||||||
bytes = Bytes;
 | 
					bytes = Bytes;
 | 
				
			||||||
secureString = SecureString;
 | 
					secureString = SecureString;
 | 
				
			||||||
secureBytes = SecureBytes;
 | 
					secureBytes = SecureBytes;
 | 
				
			||||||
| 
						 | 
					@ -117,11 +118,11 @@ dns.entryDataNextResolver resolver:AccountAddress = dns.EntryData;
 | 
				
			||||||
dns.entryDataSmcAddress smc_address:AccountAddress = dns.EntryData;
 | 
					dns.entryDataSmcAddress smc_address:AccountAddress = dns.EntryData;
 | 
				
			||||||
dns.entryDataAdnlAddress adnl_address:AdnlAddress = dns.EntryData;
 | 
					dns.entryDataAdnlAddress adnl_address:AdnlAddress = dns.EntryData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dns.entry name:string category:int32 entry:dns.EntryData = dns.Entry;
 | 
					dns.entry name:string category:int256 entry:dns.EntryData = dns.Entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dns.actionDeleteAll = dns.Action;
 | 
					dns.actionDeleteAll = dns.Action;
 | 
				
			||||||
// use category = 0 to delete all entries
 | 
					// use category = 0 to delete all entries
 | 
				
			||||||
dns.actionDelete name:string category:int32 = dns.Action;
 | 
					dns.actionDelete name:string category:int256 = dns.Action;
 | 
				
			||||||
dns.actionSet entry:dns.entry = dns.Action;
 | 
					dns.actionSet entry:dns.entry = dns.Action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dns.resolved entries:vector<dns.entry> = dns.Resolved;
 | 
					dns.resolved entries:vector<dns.entry> = dns.Resolved;
 | 
				
			||||||
| 
						 | 
					@ -283,7 +284,7 @@ smc.getData id:int53 = tvm.Cell;
 | 
				
			||||||
smc.getState id:int53 = tvm.Cell;
 | 
					smc.getState id:int53 = tvm.Cell;
 | 
				
			||||||
smc.runGetMethod id:int53 method:smc.MethodId stack:vector<tvm.StackEntry> = smc.RunResult;
 | 
					smc.runGetMethod id:int53 method:smc.MethodId stack:vector<tvm.StackEntry> = smc.RunResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dns.resolve account_address:accountAddress name:string category:int32 ttl:int32 = dns.Resolved;
 | 
					dns.resolve account_address:accountAddress name:string category:int256 ttl:int32 = dns.Resolved;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pchan.signPromise input_key:InputKey promise:pchan.promise = pchan.Promise;
 | 
					pchan.signPromise input_key:InputKey promise:pchan.promise = pchan.Promise;
 | 
				
			||||||
pchan.validatePromise public_key:bytes promise:pchan.promise = Ok;
 | 
					pchan.validatePromise public_key:bytes promise:pchan.promise = Ok;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -594,7 +594,8 @@ void dns_resolve(Client& client, const Wallet& dns, std::string name) {
 | 
				
			||||||
  using namespace ton::tonlib_api;
 | 
					  using namespace ton::tonlib_api;
 | 
				
			||||||
  auto address = dns.get_address();
 | 
					  auto address = dns.get_address();
 | 
				
			||||||
  auto resolved =
 | 
					  auto resolved =
 | 
				
			||||||
      sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 4)).move_as_ok();
 | 
					      sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(
 | 
				
			||||||
 | 
					                            std::move(address), name, td::sha256_bits256(td::Slice("cat", 3)), 4)).move_as_ok();
 | 
				
			||||||
  CHECK(resolved->entries_.size() == 1);
 | 
					  CHECK(resolved->entries_.size() == 1);
 | 
				
			||||||
  LOG(INFO) << to_string(resolved);
 | 
					  LOG(INFO) << to_string(resolved);
 | 
				
			||||||
  LOG(INFO) << "OK";
 | 
					  LOG(INFO) << "OK";
 | 
				
			||||||
| 
						 | 
					@ -747,13 +748,16 @@ void test_dns(Client& client, const Wallet& giver_wallet) {
 | 
				
			||||||
  std::vector<object_ptr<dns_Action>> actions;
 | 
					  std::vector<object_ptr<dns_Action>> actions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions.push_back(make_object<dns_actionSet>(
 | 
					  actions.push_back(make_object<dns_actionSet>(
 | 
				
			||||||
      make_object<dns_entry>("A", -1, make_object<dns_entryDataNextResolver>(A_B.get_address()))));
 | 
					      make_object<dns_entry>("A", ton::DNS_NEXT_RESOLVER_CATEGORY,
 | 
				
			||||||
 | 
					                             make_object<dns_entryDataNextResolver>(A_B.get_address()))));
 | 
				
			||||||
  auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok();
 | 
					  auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok();
 | 
				
			||||||
  actions.push_back(make_object<dns_actionSet>(
 | 
					  actions.push_back(make_object<dns_actionSet>(
 | 
				
			||||||
      make_object<dns_entry>("B", -1, make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
 | 
					      make_object<dns_entry>("B", ton::DNS_NEXT_RESOLVER_CATEGORY,
 | 
				
			||||||
 | 
					                             make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
 | 
				
			||||||
  auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok();
 | 
					  auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok();
 | 
				
			||||||
  actions.push_back(
 | 
					  actions.push_back(
 | 
				
			||||||
      make_object<dns_actionSet>(make_object<dns_entry>("C", 1, make_object<dns_entryDataText>("Hello dns"))));
 | 
					      make_object<dns_actionSet>(make_object<dns_entry>("C", td::sha256_bits256(td::Slice("cat", 3)),
 | 
				
			||||||
 | 
					                                                        make_object<dns_entryDataText>("Hello dns"))));
 | 
				
			||||||
  auto init_A_B_C = create_update_dns_query(client, A_B_C, std::move(actions)).move_as_ok();
 | 
					  auto init_A_B_C = create_update_dns_query(client, A_B_C, std::move(actions)).move_as_ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG(INFO) << "Send dns init queries";
 | 
					  LOG(INFO) << "Send dns init queries";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2623,11 +2623,10 @@ class GenericCreateSendGrams : public TonlibQueryActor {
 | 
				
			||||||
    return downcast_call2<R>(action,
 | 
					    return downcast_call2<R>(action,
 | 
				
			||||||
                             td::overloaded(
 | 
					                             td::overloaded(
 | 
				
			||||||
                                 [&](tonlib_api::dns_actionDeleteAll& del_all) -> R {
 | 
					                                 [&](tonlib_api::dns_actionDeleteAll& del_all) -> R {
 | 
				
			||||||
                                   return ton::ManualDns::Action{"", 0, {}};
 | 
					                                   return ton::ManualDns::Action{"", td::Bits256::zero(), {}};
 | 
				
			||||||
                                 },
 | 
					                                 },
 | 
				
			||||||
                                 [&](tonlib_api::dns_actionDelete& del) -> R {
 | 
					                                 [&](tonlib_api::dns_actionDelete& del) -> R {
 | 
				
			||||||
                                   TRY_RESULT(category, td::narrow_cast_safe<td::int16>(del.category_));
 | 
					                                   return ton::ManualDns::Action{del.name_, del.category_, {}};
 | 
				
			||||||
                                   return ton::ManualDns::Action{del.name_, category, {}};
 | 
					 | 
				
			||||||
                                 },
 | 
					                                 },
 | 
				
			||||||
                                 [&](tonlib_api::dns_actionSet& set) -> R {
 | 
					                                 [&](tonlib_api::dns_actionSet& set) -> R {
 | 
				
			||||||
                                   if (!set.entry_) {
 | 
					                                   if (!set.entry_) {
 | 
				
			||||||
| 
						 | 
					@ -2636,10 +2635,10 @@ class GenericCreateSendGrams : public TonlibQueryActor {
 | 
				
			||||||
                                   if (!set.entry_->entry_) {
 | 
					                                   if (!set.entry_->entry_) {
 | 
				
			||||||
                                     return TonlibError::EmptyField("entry.entry");
 | 
					                                     return TonlibError::EmptyField("entry.entry");
 | 
				
			||||||
                                   }
 | 
					                                   }
 | 
				
			||||||
                                   TRY_RESULT(category, td::narrow_cast_safe<td::int16>(set.entry_->category_));
 | 
					 | 
				
			||||||
                                   TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_));
 | 
					                                   TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_));
 | 
				
			||||||
                                   TRY_RESULT(data_cell, entry_data.as_cell());
 | 
					                                   TRY_RESULT(data_cell, entry_data.as_cell());
 | 
				
			||||||
                                   return ton::ManualDns::Action{set.entry_->name_, category, std::move(data_cell)};
 | 
					                                   return ton::ManualDns::Action{set.entry_->name_, set.entry_->category_,
 | 
				
			||||||
 | 
					                                                                 std::move(data_cell)};
 | 
				
			||||||
                                 }));
 | 
					                                 }));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3629,30 +3628,30 @@ td::Result<tonlib_api::object_ptr<tonlib_api::dns_EntryData>> to_tonlib_api(
 | 
				
			||||||
  return res;
 | 
					  return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl,
 | 
					void TonlibClient::finish_dns_resolve(std::string name, td::Bits256 category, td::int32 ttl,
 | 
				
			||||||
                                      td::optional<ton::BlockIdExt> block_id, DnsFinishData dns_finish_data,
 | 
					                                      td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
 | 
				
			||||||
 | 
					                                      DnsFinishData dns_finish_data,
 | 
				
			||||||
                                      td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
 | 
					                                      td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
 | 
				
			||||||
  block_id = dns_finish_data.block_id;
 | 
					  block_id = dns_finish_data.block_id;
 | 
				
			||||||
  // TODO: check if the smartcontract supports Dns interface
 | 
					  // TODO: check if the smartcontract supports Dns interface
 | 
				
			||||||
  // TODO: should we use some DnsInterface instead of ManualDns?
 | 
					  // TODO: should we use some DnsInterface instead of ManualDns?
 | 
				
			||||||
  auto dns = ton::ManualDns::create(dns_finish_data.smc_state);
 | 
					  auto dns = ton::ManualDns::create(dns_finish_data.smc_state, std::move(address));
 | 
				
			||||||
  TRY_RESULT_PROMISE(promise, entries, dns->resolve(name, category));
 | 
					  TRY_RESULT_PROMISE(promise, entries, dns->resolve(name, category));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (entries.size() == 1 && entries[0].category == -1 && entries[0].name != name && ttl > 0 &&
 | 
					  if (entries.size() == 1 && entries[0].partially_resolved && ttl > 0) {
 | 
				
			||||||
      entries[0].data.type == ton::ManualDns::EntryData::Type::NextResolver) {
 | 
					 | 
				
			||||||
    td::Slice got_name = entries[0].name;
 | 
					    td::Slice got_name = entries[0].name;
 | 
				
			||||||
    if (got_name.size() >= name.size()) {
 | 
					    if (got_name.size() > name.size()) {
 | 
				
			||||||
      TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is too long"));
 | 
					      TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is too long"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto dot_position = name.size() - got_name.size() - 1;
 | 
					    auto suffix_start = name.size() - got_name.size();
 | 
				
			||||||
    auto suffix = name.substr(dot_position + 1);
 | 
					    auto suffix = name.substr(suffix_start);
 | 
				
			||||||
    auto prefix = name.substr(0, dot_position);
 | 
					 | 
				
			||||||
    if (name[dot_position] != '.') {
 | 
					 | 
				
			||||||
      TRY_STATUS_PROMISE(promise, td::Status::Error("next resolver error: domain split not at a component boundary "));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (suffix != got_name) {
 | 
					    if (suffix != got_name) {
 | 
				
			||||||
      TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is not a suffix of the query"));
 | 
					      TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is not a suffix of the query"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    auto prefix = name.substr(0, suffix_start);
 | 
				
			||||||
 | 
					    if (!prefix.empty() && prefix.back() != '.' && suffix[0] != '.') {
 | 
				
			||||||
 | 
					      TRY_STATUS_PROMISE(promise, td::Status::Error("next resolver error: domain split not at a component boundary "));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto address = entries[0].data.data.get<ton::ManualDns::EntryDataNextResolver>().resolver;
 | 
					    auto address = entries[0].data.data.get<ton::ManualDns::EntryDataNextResolver>().resolver;
 | 
				
			||||||
    return do_dns_request(prefix, category, ttl - 1, std::move(block_id), address, std::move(promise));
 | 
					    return do_dns_request(prefix, category, ttl - 1, std::move(block_id), address, std::move(promise));
 | 
				
			||||||
| 
						 | 
					@ -3667,12 +3666,13 @@ void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::
 | 
				
			||||||
  promise.set_value(tonlib_api::make_object<tonlib_api::dns_resolved>(std::move(api_entries)));
 | 
					  promise.set_value(tonlib_api::make_object<tonlib_api::dns_resolved>(std::move(api_entries)));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TonlibClient::do_dns_request(std::string name, td::int32 category, td::int32 ttl,
 | 
					void TonlibClient::do_dns_request(std::string name, td::Bits256 category, td::int32 ttl,
 | 
				
			||||||
                                  td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
 | 
					                                  td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
 | 
				
			||||||
                                  td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
 | 
					                                  td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
 | 
				
			||||||
  auto block_id_copy = block_id.copy();
 | 
					  auto block_id_copy = block_id.copy();
 | 
				
			||||||
  td::Promise<DnsFinishData> new_promise =
 | 
					  td::Promise<DnsFinishData> new_promise =
 | 
				
			||||||
      promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id));
 | 
					      promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id),
 | 
				
			||||||
 | 
					                           address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (0) {
 | 
					  if (0) {
 | 
				
			||||||
    make_request(int_api::GetAccountState{address, std::move(block_id_copy), {}},
 | 
					    make_request(int_api::GetAccountState{address, std::move(block_id_copy), {}},
 | 
				
			||||||
| 
						 | 
					@ -3683,7 +3683,7 @@ void TonlibClient::do_dns_request(std::string name, td::int32 category, td::int3
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TRY_RESULT_PROMISE(promise, args, ton::DnsInterface::resolve_args(name, category));
 | 
					  TRY_RESULT_PROMISE(promise, args, ton::DnsInterface::resolve_args(name, category, address));
 | 
				
			||||||
  int_api::RemoteRunSmcMethod query;
 | 
					  int_api::RemoteRunSmcMethod query;
 | 
				
			||||||
  query.address = std::move(address);
 | 
					  query.address = std::move(address);
 | 
				
			||||||
  query.args = std::move(args);
 | 
					  query.args = std::move(args);
 | 
				
			||||||
| 
						 | 
					@ -3705,8 +3705,12 @@ td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
 | 
				
			||||||
                                      request.ttl_, std::move(block_id)));
 | 
					                                      request.ttl_, std::move(block_id)));
 | 
				
			||||||
    return td::Status::OK();
 | 
					    return td::Status::OK();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  std::string name = request.name_;
 | 
				
			||||||
 | 
					  if (name.empty() || name.back() != '.') {
 | 
				
			||||||
 | 
					    name += '.';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_));
 | 
					  TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_));
 | 
				
			||||||
  do_dns_request(request.name_, request.category_, request.ttl_, std::move(block_id), account_address,
 | 
					  do_dns_request(name, request.category_, request.ttl_, std::move(block_id), account_address,
 | 
				
			||||||
                 std::move(promise));
 | 
					                 std::move(promise));
 | 
				
			||||||
  return td::Status::OK();
 | 
					  return td::Status::OK();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,14 +325,15 @@ class TonlibClient : public td::actor::Actor {
 | 
				
			||||||
  void perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::SmartContract::Args args,
 | 
					  void perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::SmartContract::Args args,
 | 
				
			||||||
                             td::Promise<object_ptr<tonlib_api::smc_runResult>>&& promise);
 | 
					                             td::Promise<object_ptr<tonlib_api::smc_runResult>>&& promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
 | 
					  void do_dns_request(std::string name, td::Bits256 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
 | 
				
			||||||
                      block::StdAddress address, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
 | 
					                      block::StdAddress address, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
 | 
				
			||||||
  struct DnsFinishData {
 | 
					  struct DnsFinishData {
 | 
				
			||||||
    ton::BlockIdExt block_id;
 | 
					    ton::BlockIdExt block_id;
 | 
				
			||||||
    ton::SmartContract::State smc_state;
 | 
					    ton::SmartContract::State smc_state;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  void finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
 | 
					  void finish_dns_resolve(std::string name, td::Bits256 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
 | 
				
			||||||
                          DnsFinishData dns_finish_data, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
 | 
					                          block::StdAddress address, DnsFinishData dns_finish_data,
 | 
				
			||||||
 | 
					                          td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  td::Status do_request(int_api::GetAccountState request, td::Promise<td::unique_ptr<AccountState>>&&);
 | 
					  td::Status do_request(int_api::GetAccountState request, td::Promise<td::unique_ptr<AccountState>>&&);
 | 
				
			||||||
  td::Status do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&&);
 | 
					  td::Status do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&&);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1162,7 +1162,7 @@ class TonlibCli : public td::actor::Actor {
 | 
				
			||||||
    promise.set_error(td::Status::Error("Unknown command"));
 | 
					    promise.set_error(td::Status::Error("Unknown command"));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void do_dns_resolve(std::string name, td::int16 category, td::int32 ttl,
 | 
					  void do_dns_resolve(std::string name, td::Bits256 category, td::int32 ttl,
 | 
				
			||||||
                      tonlib_api::object_ptr<tonlib_api::dns_resolved> resolved, td::Promise<td::Unit> promise) {
 | 
					                      tonlib_api::object_ptr<tonlib_api::dns_resolved> resolved, td::Promise<td::Unit> promise) {
 | 
				
			||||||
    if (resolved->entries_.empty()) {
 | 
					    if (resolved->entries_.empty()) {
 | 
				
			||||||
      td::TerminalIO::out() << "No dns entries found\n";
 | 
					      td::TerminalIO::out() << "No dns entries found\n";
 | 
				
			||||||
| 
						 | 
					@ -1192,11 +1192,12 @@ class TonlibCli : public td::actor::Actor {
 | 
				
			||||||
    TRY_RESULT_PROMISE(promise, address, to_account_address(key_id, false));
 | 
					    TRY_RESULT_PROMISE(promise, address, to_account_address(key_id, false));
 | 
				
			||||||
    auto name = parser.read_word();
 | 
					    auto name = parser.read_word();
 | 
				
			||||||
    auto category_str = parser.read_word();
 | 
					    auto category_str = parser.read_word();
 | 
				
			||||||
    TRY_RESULT_PROMISE(promise, category, td::to_integer_safe<td::int16>(category_str));
 | 
					    td::Bits256 category = category_str.empty() ? td::Bits256::zero() : td::sha256_bits256(td::as_slice(category_str));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<tonlib_api::object_ptr<tonlib_api::dns_entry>> entries;
 | 
					    std::vector<tonlib_api::object_ptr<tonlib_api::dns_entry>> entries;
 | 
				
			||||||
    entries.push_back(make_object<tonlib_api::dns_entry>(
 | 
					    entries.push_back(make_object<tonlib_api::dns_entry>(
 | 
				
			||||||
        "", -1, make_object<tonlib_api::dns_entryDataNextResolver>(std::move(address.address))));
 | 
					        "", ton::DNS_NEXT_RESOLVER_CATEGORY,
 | 
				
			||||||
 | 
					        make_object<tonlib_api::dns_entryDataNextResolver>(std::move(address.address))));
 | 
				
			||||||
    do_dns_resolve(name.str(), category, 10, make_object<tonlib_api::dns_resolved>(std::move(entries)),
 | 
					    do_dns_resolve(name.str(), category, 10, make_object<tonlib_api::dns_resolved>(std::move(entries)),
 | 
				
			||||||
                   std::move(promise));
 | 
					                   std::move(promise));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -1217,8 +1218,8 @@ class TonlibCli : public td::actor::Actor {
 | 
				
			||||||
      if (action.name.empty()) {
 | 
					      if (action.name.empty()) {
 | 
				
			||||||
        actions.push_back(make_object<tonlib_api::dns_actionDeleteAll>());
 | 
					        actions.push_back(make_object<tonlib_api::dns_actionDeleteAll>());
 | 
				
			||||||
        td::TerminalIO::out() << "Delete all dns entries\n";
 | 
					        td::TerminalIO::out() << "Delete all dns entries\n";
 | 
				
			||||||
      } else if (action.category == 0) {
 | 
					      } else if (action.category.is_zero()) {
 | 
				
			||||||
        actions.push_back(make_object<tonlib_api::dns_actionDelete>(action.name, 0));
 | 
					        actions.push_back(make_object<tonlib_api::dns_actionDelete>(action.name, td::Bits256::zero()));
 | 
				
			||||||
        td::TerminalIO::out() << "Delete all dns enties with name: " << action.name << "\n";
 | 
					        td::TerminalIO::out() << "Delete all dns enties with name: " << action.name << "\n";
 | 
				
			||||||
      } else if (!action.data) {
 | 
					      } else if (!action.data) {
 | 
				
			||||||
        actions.push_back(make_object<tonlib_api::dns_actionDelete>(action.name, action.category));
 | 
					        actions.push_back(make_object<tonlib_api::dns_actionDelete>(action.name, action.category));
 | 
				
			||||||
| 
						 | 
					@ -1234,8 +1235,8 @@ class TonlibCli : public td::actor::Actor {
 | 
				
			||||||
        TRY_RESULT_PROMISE(promise, data, tonlib::to_tonlib_api(action.data.value()));
 | 
					        TRY_RESULT_PROMISE(promise, data, tonlib::to_tonlib_api(action.data.value()));
 | 
				
			||||||
        sb << action.data.value();
 | 
					        sb << action.data.value();
 | 
				
			||||||
        TRY_STATUS_PROMISE(promise, std::move(error));
 | 
					        TRY_STATUS_PROMISE(promise, std::move(error));
 | 
				
			||||||
        td::TerminalIO::out() << "Set dns entry: " << action.name << ":" << action.category << " " << sb.as_cslice()
 | 
					        td::TerminalIO::out() << "Set dns entry: " << action.name << ":" << action.category << " "
 | 
				
			||||||
                              << "\n";
 | 
					                              << sb.as_cslice() << "\n";
 | 
				
			||||||
        actions.push_back(make_object<tonlib_api::dns_actionSet>(
 | 
					        actions.push_back(make_object<tonlib_api::dns_actionSet>(
 | 
				
			||||||
            make_object<tonlib_api::dns_entry>(action.name, action.category, std::move(data))));
 | 
					            make_object<tonlib_api::dns_entry>(action.name, action.category, std::move(data))));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue