Skip to content

Commit

Permalink
Merge pull request #413 from ton-blockchain/temp-master
Browse files Browse the repository at this point in the history
Update DNS resolver in liteclient and tonlib
  • Loading branch information
tolya-yanot authored Jun 29, 2022
2 parents 7e3df93 + 7e207dc commit eb86234
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 237 deletions.
2 changes: 1 addition & 1 deletion crypto/block/block.tlb
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ vmc_pushint$1111 value:int32 next:^VmCont = VmCont;
//
// DNS RECORDS
//
_ (HashmapE 16 ^DNSRecord) = DNS_RecordSet;
_ (HashmapE 256 DNSRecord) = DNS_RecordSet;

chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1);
chunk_ref_empty$_ = TextChunkRef 0;
Expand Down
114 changes: 60 additions & 54 deletions crypto/smc-envelope/ManualDns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,35 +146,43 @@ td::Result<DnsInterface::EntryData> DnsInterface::EntryData::from_cellslice(vm::
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;
res.set_method_id("dnsresolve");
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;
}

td::Result<SmartContract::Args> DnsInterface::resolve_args(td::Slice name, td::int32 category_big) {
TRY_RESULT(category, td::narrow_cast_safe<td::int16>(category_big));
td::Result<SmartContract::Args> DnsInterface::resolve_args(td::Slice name, td::Bits256 category,
block::StdAddress address) {
if (name.size() > get_default_max_name_size()) {
return td::Status::Error("Name is too long");
}
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));
std::vector<Entry> entries;
entries.reserve(raw_entries.size());
for (auto& raw_entry : raw_entries) {
Entry entry;
entry.name = std::move(raw_entry.name);
entry.category = raw_entry.category;
auto cs = vm::load_cell_slice(raw_entry.data);
TRY_RESULT(data, EntryData::from_cellslice(cs));
entry.data = std::move(data);
entries.push_back(std::move(entry));
entry.partially_resolved = raw_entry.partially_resolved;
auto cs = *raw_entry.data;
auto data = EntryData::from_cellslice(cs);
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;
}
Expand All @@ -188,9 +196,9 @@ td::Result<std::vector<DnsInterface::Entry>> DnsInterface::resolve(td::Slice nam
Inline [Name] structure: [UInt<6b>:length] [Bytes<lengthB>:data]
Operations (continuation of message):
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]
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]
*/
// creation
Expand Down Expand Up @@ -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));
}

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 {
//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;
cb.store_long(11, 6);
if (name.size() <= 58 - 2) {
cb.store_long(category, 16);
if (name.size() <= 58 - 32) {
cb.store_bytes(category.as_slice());
cb.store_long(0, 1);
cb.store_long(name.size(), 6);
cb.store_bytes(name);
} else {
cb.store_long(category, 16);
cb.store_bytes(category.as_slice());
cb.store_long(1, 1);
cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
}
cb.store_maybe_ref(std::move(data));
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)
//[Int<16b>:category] [Name<?>:subdomain]
//[Int<256b>:category] [Name<?>:subdomain]
vm::CellBuilder cb;
cb.store_long(12, 6);
if (name.size() <= 58 - 2) {
cb.store_long(category, 16);
if (name.size() <= 58 - 32) {
cb.store_bytes(category.as_slice());
cb.store_long(0, 1);
cb.store_long(name.size(), 6);
cb.store_bytes(name);
} else {
cb.store_long(category, 16);
cb.store_bytes(category.as_slice());
cb.store_long(1, 1);
cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
}
Expand Down Expand Up @@ -295,10 +303,9 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_set_all_unsigned(td::Span<Action
if (o_dict.not_null()) {
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()) {
auto key = dict.integer_key(td::make_refint(action.category), 16);
dict.set_ref(key.bits(), 16, action.data.value());
dict.set_ref(action.category.bits(), 256, action.data.value());
}
pdict.set(ptr, ptr_size, dict.get_root());
}
Expand Down Expand Up @@ -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());
}

vm::Dictionary dict(16);
vm::Dictionary dict(256);

for (auto& action : entries) {
if (action.data.value().is_null()) {
continue;
}
auto key = dict.integer_key(td::make_refint(action.category), 16);
dict.set_ref(key.bits(), 16, action.data.value());
dict.set_ref(action.category.cbits(), 256, action.data.value());
}
cb.store_maybe_ref(dict.get_root_cell());

Expand Down Expand Up @@ -395,17 +401,16 @@ size_t ManualDns::get_max_name_size() const {
return get_default_max_name_size();
}

td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw(td::Slice name, td::int32 category_big) const {
return TRY_VM(resolve_raw_or_throw(name, category_big));
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));
}
td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw_or_throw(td::Slice name,
td::int32 category_big) const {
TRY_RESULT(category, td::narrow_cast_safe<td::int16>(category_big));
td::Bits256 category) const {
if (name.size() > get_max_name_size()) {
return td::Status::Error("Name is too long");
}
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) {
return td::Status::Error("get method failed");
}
Expand All @@ -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");
}
prefix_size /= 8;
if (prefix_size == 0) {
return vec;
}
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 {
if (category == 0) {
vm::Dictionary dict(std::move(data), 16);
dict.check_for_each([&](auto cs, auto x, auto y) {
td::BigInt256 cat;
cat.import_bits(x, y, true);
vec.push_back({name.str(), td::narrow_cast<td::int16>(cat.to_long()), cs->prefetch_ref()});
if (category.is_zero()) {
vm::Dictionary dict(std::move(data), 256);
dict.check_for_each([&](auto cs, td::ConstBitPtr key, int n) {
CHECK(n == 256);
vec.push_back({name.str(), td::Bits256(key), cs});
return true;
});
} else {
vec.push_back({name.str(), category, data});
vec.push_back({name.str(), category, vm::load_cell_slice_ref(data)});
}
}

Expand All @@ -445,7 +453,7 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_update_query(CombinedActions<Act
}
return create_set_all_unsigned(combined.actions.value());
}
if (combined.category == 0) {
if (combined.category.is_zero()) {
if (!combined.actions) {
return create_delete_name_unsigned(encode_name(combined.name));
}
Expand Down Expand Up @@ -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 res;
if (name.empty() || name == ".") {
res += '\0';
return res;
}
while (!name.empty()) {
auto pos = name.rfind('.');
if (pos == name.npos) {
if (pos == td::Slice::npos) {
res += name.str();
name = td::Slice();
} else {
Expand All @@ -504,20 +516,15 @@ std::string DnsInterface::encode_name(td::Slice name) {

std::string DnsInterface::decode_name(td::Slice name) {
std::string res;
if (!name.empty() && name.back() == 0) {
name.remove_suffix(1);
}
while (!name.empty()) {
auto pos = name.rfind('\0');
if (!res.empty()) {
res += '.';
}
if (pos == name.npos) {
if (pos == td::Slice::npos) {
res += name.str();
name = td::Slice();
} else {
res += name.substr(pos + 1).str();
name.truncate(pos);
res += '.';
}
}
return res;
Expand Down Expand Up @@ -570,17 +577,16 @@ td::Result<ManualDns::ActionExt> ManualDns::parse_line(td::Slice cmd) {
if (type == "set") {
auto name = 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()));
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") {
auto name = parser.read_word();
if (name.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") {
return ManualDns::ActionExt{"", 0, {}};
return ManualDns::ActionExt{"", td::Bits256::zero(), {}};
}
return td::Status::Error(PSLICE() << "Unknown command: " << type);
}
Expand Down
Loading

0 comments on commit eb86234

Please sign in to comment.