From 7e207dc78f8e757cf3e9357a0cdeb51986ff4794 Mon Sep 17 00:00:00 2001 From: SpyCheese Date: Wed, 29 Jun 2022 12:30:19 +0300 Subject: [PATCH] Update DNS resolver in liteclient and tonlib --- crypto/block/block.tlb | 2 +- crypto/smc-envelope/ManualDns.cpp | 114 +++++++++++++------------- crypto/smc-envelope/ManualDns.h | 64 ++++++++------- crypto/test/test-smartcont.cpp | 119 +++++++++++++++------------- lite-client/lite-client.cpp | 114 +++++++++++++------------- lite-client/lite-client.h | 8 +- rldp-http-proxy/rldp-http-proxy.cpp | 3 +- tl/generate/generate_common.cpp | 4 +- tl/generate/scheme/tonlib_api.tl | 7 +- tl/generate/scheme/tonlib_api.tlo | Bin 28288 -> 28428 bytes tonlib/test/online.cpp | 12 ++- tonlib/tonlib/TonlibClient.cpp | 46 ++++++----- tonlib/tonlib/TonlibClient.h | 7 +- tonlib/tonlib/tonlib-cli.cpp | 15 ++-- 14 files changed, 278 insertions(+), 237 deletions(-) diff --git a/crypto/block/block.tlb b/crypto/block/block.tlb index b970d9196..46b29cf23 100644 --- a/crypto/block/block.tlb +++ b/crypto/block/block.tlb @@ -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; diff --git a/crypto/smc-envelope/ManualDns.cpp b/crypto/smc-envelope/ManualDns.cpp index 00f1becb8..8f5097c05 100644 --- a/crypto/smc-envelope/ManualDns.cpp +++ b/crypto/smc-envelope/ManualDns.cpp @@ -146,24 +146,27 @@ td::Result 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 DnsInterface::resolve_args(td::Slice name, td::int32 category_big) { - TRY_RESULT(category, td::narrow_cast_safe(category_big)); +td::Result 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> DnsInterface::resolve(td::Slice name, td::int32 category) const { +td::Result> DnsInterface::resolve(td::Slice name, td::Bits256 category) const { TRY_RESULT(raw_entries, resolve_raw(name, category)); std::vector entries; entries.reserve(raw_entries.size()); @@ -171,10 +174,15 @@ td::Result> DnsInterface::resolve(td::Slice nam 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; } @@ -188,9 +196,9 @@ td::Result> DnsInterface::resolve(td::Slice nam Inline [Name] structure: [UInt<6b>:length] [Bytes: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 @@ -233,37 +241,37 @@ td::Result ManualDns::get_wallet_id_or_throw() const { return static_cast(vm::load_cell_slice(state_.data).fetch_ulong(32)); } -td::Result> ManualDns::create_set_value_unsigned(td::int16 category, td::Slice name, +td::Result> ManualDns::create_set_value_unsigned(td::Bits256 category, td::Slice name, td::Ref 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> ManualDns::create_delete_value_unsigned(td::int16 category, td::Slice name) const { +td::Result> 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()); } @@ -295,10 +303,9 @@ td::Result> ManualDns::create_set_all_unsigned(td::Spanprefetch_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()); } @@ -340,14 +347,13 @@ td::Result> 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()); @@ -395,17 +401,16 @@ size_t ManualDns::get_max_name_size() const { return get_default_max_name_size(); } -td::Result> ManualDns::resolve_raw(td::Slice name, td::int32 category_big) const { - return TRY_VM(resolve_raw_or_throw(name, category_big)); +td::Result> ManualDns::resolve_raw(td::Slice name, td::Bits256 category) const { + return TRY_VM(resolve_raw_or_throw(name, category)); } td::Result> ManualDns::resolve_raw_or_throw(td::Slice name, - td::int32 category_big) const { - TRY_RESULT(category, td::narrow_cast_safe(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"); } @@ -419,19 +424,22 @@ td::Result> 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(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)}); } } @@ -445,7 +453,7 @@ td::Result> ManualDns::create_update_query(CombinedActions> 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 { @@ -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; @@ -570,17 +577,16 @@ td::Result 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(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); } diff --git a/crypto/smc-envelope/ManualDns.h b/crypto/smc-envelope/ManualDns.h index fbf12e74c..545c32795 100644 --- a/crypto/smc-envelope/ManualDns.h +++ b/crypto/smc-envelope/ManualDns.h @@ -26,10 +26,14 @@ #include "smc-envelope/SmartContract.h" #include "Ed25519.h" +#include "common/checksum.h" #include namespace ton { +const td::Bits256 DNS_NEXT_RESOLVER_CATEGORY = + td::sha256_bits256(td::Slice("dns_next_resolver", strlen("dns_next_resolver"))); + class DnsInterface { public: struct EntryDataText { @@ -90,8 +94,9 @@ class DnsInterface { struct Entry { std::string name; - td::int16 category; + td::Bits256 category; EntryData data; + bool partially_resolved = false; auto key() const { return std::tie(name, category); } @@ -102,47 +107,48 @@ class DnsInterface { return key() == other.key() && data == other.data; } 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; } }; struct RawEntry { std::string name; - td::int16 category; - td::Ref data; + td::Bits256 category; + td::Ref data; + bool partially_resolved = false; }; struct ActionExt { std::string name; - td::int16 category; + td::Bits256 category; td::optional data; static td::Result parse(td::Slice); }; struct Action { std::string name; - td::int16 category; + td::Bits256 category; td::optional> data; bool does_create_category() const { CHECK(!name.empty()); - CHECK(category != 0); + CHECK(!category.is_zero()); return static_cast(data); } bool does_change_empty() const { CHECK(!name.empty()); - CHECK(category != 0); + CHECK(!category.is_zero()); return static_cast(data) && data.value().not_null(); } void make_non_empty() { CHECK(!name.empty()); - CHECK(category != 0); + CHECK(!category.is_zero()); if (!data) { data = td::Ref(); } } 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.value().is_null()) { sb << ""; @@ -156,15 +162,14 @@ class DnsInterface { } }; - virtual ~DnsInterface() { - } + virtual ~DnsInterface() = default; virtual size_t get_max_name_size() const = 0; - virtual td::Result> resolve_raw(td::Slice name, td::int32 category) const = 0; + virtual td::Result> resolve_raw(td::Slice name, td::Bits256 category) const = 0; virtual td::Result> create_update_query( td::Ed25519::PrivateKey& pk, td::Span actions, td::uint32 valid_until = std::numeric_limits::max()) const = 0; - td::Result> resolve(td::Slice name, td::int32 category) const; + td::Result> resolve(td::Slice name, td::Bits256 category) const; static std::string encode_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() { return 128; } - static SmartContract::Args resolve_args_raw(td::Slice encoded_name, td::int16 category); - static td::Result resolve_args(td::Slice name, td::int32 category); + static SmartContract::Args resolve_args_raw(td::Slice encoded_name, td::Bits256 category, + block::StdAddress address = {}); + static td::Result resolve_args(td::Slice name, td::Bits256 category, + block::StdAddress address = {}); }; class ManualDns : public ton::SmartContract, public DnsInterface { 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 { @@ -186,8 +194,8 @@ class ManualDns : public ton::SmartContract, public DnsInterface { } // creation - static td::Ref create(State state) { - return td::Ref(true, std::move(state)); + static td::Ref create(State state, block::StdAddress address = {}) { + return td::Ref(true, std::move(state), std::move(address)); } static td::Ref create(td::Ref data = {}, int revision = 0); static td::Ref 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 get_wallet_id() const; td::Result get_wallet_id_or_throw() const; - td::Result> create_set_value_unsigned(td::int16 category, td::Slice name, + td::Result> create_set_value_unsigned(td::Bits256 category, td::Slice name, td::Ref data) const; - td::Result> create_delete_value_unsigned(td::int16 category, td::Slice name) const; + td::Result> create_delete_value_unsigned(td::Bits256 category, td::Slice name) const; td::Result> create_delete_all_unsigned() const; td::Result> create_set_all_unsigned(td::Span entries) const; td::Result> create_delete_name_unsigned(td::Slice name) const; @@ -222,8 +230,8 @@ class ManualDns : public ton::SmartContract, public DnsInterface { static td::Ref create_init_data_fast(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id); size_t get_max_name_size() const override; - td::Result> resolve_raw(td::Slice name, td::int32 category_big) const override; - td::Result> resolve_raw_or_throw(td::Slice name, td::int32 category_big) const; + td::Result> resolve_raw(td::Slice name, td::Bits256 category) const override; + td::Result> resolve_raw_or_throw(td::Slice name, td::Bits256 category) const; td::Result> create_init_query( const td::Ed25519::PrivateKey& private_key, @@ -235,10 +243,10 @@ class ManualDns : public ton::SmartContract, public DnsInterface { template struct CombinedActions { std::string name; - td::int16 category{0}; + td::Bits256 category = td::Bits256::zero(); td::optional> actions; 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) { sb << "" << action.actions.value().size(); } else { @@ -251,7 +259,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface { template static std::vector> combine_actions(td::Span actions) { struct Info { - std::set known_category; + std::set known_category; std::vector actions; bool closed{false}; bool non_empty{false}; @@ -278,7 +286,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface { if (info.closed) { continue; } - if (action.category != 0 && action.does_create_category()) { + if (!action.category.is_zero() && action.does_create_category()) { info.non_empty = true; } if (!info.known_category.insert(action.category).second) { @@ -330,6 +338,8 @@ class ManualDns : public ton::SmartContract, public DnsInterface { return res; } td::Result> create_update_query(CombinedActions& combined) const; + private: + block::StdAddress address_; }; } // namespace ton diff --git a/crypto/test/test-smartcont.cpp b/crypto/test/test-smartcont.cpp index 370a36e85..673bb7586 100644 --- a/crypto/test/test-smartcont.cpp +++ b/crypto/test/test-smartcont.cpp @@ -810,7 +810,7 @@ class MapDns { using ManualDns = ton::ManualDns; struct Entry { std::string name; - td::int16 category{0}; + td::Bits256 category = td::Bits256::zero(); std::string text; auto key() const { @@ -827,34 +827,34 @@ class MapDns { return key() == other.key() && text == other.text; } 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 { std::string name; - td::int16 category{0}; + td::Bits256 category = td::Bits256::zero(); td::optional text; bool does_create_category() const { CHECK(!name.empty()); - CHECK(category != 0); + CHECK(!category.is_zero()); return static_cast(text); } bool does_change_empty() const { CHECK(!name.empty()); - CHECK(category != 0); + CHECK(!category.is_zero()); return static_cast(text) && !text.value().empty(); } void make_non_empty() { CHECK(!name.empty()); - CHECK(category != 0); + CHECK(!category.is_zero()); if (!text) { text = ""; } } friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& entry) { - return sb << "[" << entry.name << ":" << entry.category << ":" << (entry.text ? entry.text.value() : "") - << "]"; + return sb << "[" << entry.name << ":" << entry.category.to_hex() << ":" + << (entry.text ? entry.text.value() : "") << "]"; } }; void update(td::Span actions) { @@ -868,7 +868,7 @@ class MapDns { LOG(ERROR) << td::format::as_array(actions); auto combined_actions = ton::ManualDns::combine_actions(actions); for (auto& c : combined_actions) { - LOG(ERROR) << c.name << ":" << c.category; + LOG(ERROR) << c.name << ":" << c.category.to_hex(); if (c.actions) { LOG(ERROR) << td::format::as_array(c.actions.value()); } @@ -879,7 +879,7 @@ class MapDns { } } - std::vector resolve(td::Slice name, td::int16 category) { + std::vector resolve(td::Slice name, td::Bits256 category) { std::vector res; if (name.empty()) { for (auto& a : entries_) { @@ -891,7 +891,7 @@ class MapDns { auto it = entries_.find(name); while (it == entries_.end()) { auto sz = name.find('.'); - category = -1; + category = ton::DNS_NEXT_RESOLVER_CATEGORY; if (sz != td::Slice::npos) { name = name.substr(sz + 1); } else { @@ -901,7 +901,7 @@ class MapDns { } if (it != entries_.end()) { 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}); } } @@ -913,13 +913,13 @@ class MapDns { } private: - std::map, std::less<>> entries_; + std::map, std::less<>> entries_; void do_update(const Action& action) { if (action.name.empty()) { entries_.clear(); return; } - if (action.category == 0) { + if (action.category.is_zero()) { entries_.erase(action.name); return; } @@ -946,7 +946,7 @@ class MapDns { } for (auto& action : actions.actions.value()) { CHECK(!action.name.empty()); - CHECK(action.category != 0); + CHECK(!action.category.is_zero()); CHECK(action.text); if (action.text.value().empty()) { entries_[action.name]; @@ -956,7 +956,7 @@ class MapDns { } return; } - if (actions.category == 0) { + if (!actions.category.is_zero()) { entries_.erase(actions.name); LOG(ERROR) << "CLEAR " << actions.name; if (!actions.actions) { @@ -965,7 +965,7 @@ class MapDns { entries_[actions.name]; for (auto& action : actions.actions.value()) { CHECK(action.name == actions.name); - CHECK(action.category != 0); + CHECK(!action.category.is_zero()); CHECK(action.text); if (action.text.value().empty()) { entries_[action.name]; @@ -979,7 +979,7 @@ class MapDns { CHECK(actions.actions.value().size() == 1); for (auto& action : actions.actions.value()) { CHECK(action.name == actions.name); - CHECK(action.category != 0); + CHECK(!action.category.is_zero()); if (action.text) { if (action.text.value().empty()) { entries_[action.name].erase(action.category); @@ -1036,8 +1036,8 @@ class CheckedDns { return update(td::span_one(action)); } - std::vector resolve(td::Slice name, td::int16 category) { - LOG(ERROR) << "RESOLVE: " << name << " " << category; + std::vector resolve(td::Slice name, td::Bits256 category) { + LOG(ERROR) << "RESOLVE: " << name << " " << category.to_hex(); auto res = map_dns_.resolve(name, category); 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) { using Action = CheckedDns::Action; std::vector actions; @@ -1130,7 +1136,7 @@ void do_dns_test(CheckedDns&& dns) { if (rnd.fast(0, 20) == 0) { return action; } - action.category = td::narrow_cast(rnd.fast(1, 5)); + action.category = intToCat(rnd.fast(1, 5)); if (rnd.fast(0, 4) == 0) { return action; } @@ -1150,7 +1156,8 @@ void do_dns_test(CheckedDns&& dns) { actions.clear(); } auto name = gen_name(); - dns.resolve(name, td::narrow_cast(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")); - 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("", ManualDns::decode_name("")); @@ -1184,8 +1191,8 @@ TEST(Smartcont, DnsManual) { auto value = vm::CellBuilder().store_bytes("hello world").finalize(); auto set_query = manual - ->sign(key, - manual->prepare(manual->create_set_value_unsigned(1, "a\0b\0", value).move_as_ok(), 1).move_as_ok()) + ->sign(key, manual->prepare(manual->create_set_value_unsigned(intToCat(1), "a\0b\0", value).move_as_ok(), 1) + .move_as_ok()) .move_as_ok(); 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()); CheckedDns dns; - dns.update(CheckedDns::Action{"a.b.c", 1, "hello"}); - CHECK(dns.resolve("a.b.c", 1).at(0).text == "hello"); - dns.resolve("a", 1); - dns.resolve("a.b", 1); - CHECK(dns.resolve("a.b.c", 2).empty()); - dns.update(CheckedDns::Action{"a.b.c", 2, "test"}); - CHECK(dns.resolve("a.b.c", 2).at(0).text == "test"); - dns.resolve("a.b.c", 1); - dns.resolve("a.b.c", 2); + dns.update(CheckedDns::Action{"a.b.c", intToCat(1), "hello"}); + CHECK(dns.resolve("a.b.c", intToCat(1)).at(0).text == "hello"); + dns.resolve("a", intToCat(1)); + dns.resolve("a.b", intToCat(1)); + CHECK(dns.resolve("a.b.c", intToCat(2)).empty()); + dns.update(CheckedDns::Action{"a.b.c", intToCat(2), "test"}); + CHECK(dns.resolve("a.b.c", intToCat(2)).at(0).text == "test"); + dns.resolve("a.b.c", intToCat(1)); + dns.resolve("a.b.c", intToCat(2)); LOG(ERROR) << "Test zero category"; - dns.resolve("a.b.c", 0); - dns.update(CheckedDns::Action{"", 0, ""}); - CHECK(dns.resolve("a.b.c", 2).empty()); + dns.resolve("a.b.c", intToCat(0)); + dns.update(CheckedDns::Action{"", intToCat(0), ""}); + CHECK(dns.resolve("a.b.c", intToCat(2)).empty()); LOG(ERROR) << "Test multipe update"; { - CheckedDns::Action e[4] = {CheckedDns::Action{"", 0, ""}, CheckedDns::Action{"a.b.c", 1, "hello"}, - CheckedDns::Action{"a.b.c", 2, "world"}, CheckedDns::Action{"x.y.z", 3, "abc"}}; + CheckedDns::Action e[4] = { + 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.resolve("a.b.c", 1); - dns.resolve("a.b.c", 2); - dns.resolve("x.y.z", 3); + dns.resolve("a.b.c", intToCat(1)); + dns.resolve("a.b.c", intToCat(2)); + 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", 2); - dns.resolve("x.y.z", 3); + dns.resolve("a.b.c", intToCat(1)); + dns.resolve("a.b.c", intToCat(2)); + 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{"x.y.z", 2, "yyy"}}; + CheckedDns::Action e[3] = {CheckedDns::Action{"x.y.z", intToCat(0), ""}, + CheckedDns::Action{"x.y.z", intToCat(1), "xxx"}, + CheckedDns::Action{"x.y.z", intToCat(2), "yyy"}}; dns.update(td::span(e, 3)); } - dns.resolve("a.b.c", 1); - dns.resolve("a.b.c", 2); - dns.resolve("x.y.z", 1); - dns.resolve("x.y.z", 2); - dns.resolve("x.y.z", 3); + dns.resolve("a.b.c", intToCat(1)); + dns.resolve("a.b.c", intToCat(2)); + dns.resolve("x.y.z", intToCat(1)); + dns.resolve("x.y.z", intToCat(2)); + dns.resolve("x.y.z", intToCat(3)); { auto actions_ext = @@ -1250,8 +1259,8 @@ TEST(Smartcont, DnsManual) { dns.update(actions); } - dns.resolve("one", 1); - dns.resolve("two", 2); + dns.resolve("one", intToCat(1)); + dns.resolve("two", intToCat(2)); // TODO: rethink semantic of creating an empty dictionary do_dns_test(CheckedDns(true, true)); diff --git a/lite-client/lite-client.cpp b/lite-client/lite-client.cpp index f472af217..aad3ae6e3 100644 --- a/lite-client/lite-client.cpp +++ b/lite-client/lite-client.cpp @@ -62,6 +62,7 @@ #include "openssl/rand.hpp" #include "crypto/vm/utils.h" #include "crypto/common/util.h" +#include "common/checksum.h" #if TD_DARWIN || TD_LINUX #include @@ -1025,11 +1026,13 @@ bool TestNode::do_parse_line() { workchain = ton::workchainInvalid; bool step = (word.size() > 10); std::string domain; - int cat = 0; + std::string cat_str; 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()) && - (seekeoln() || parse_int16(cat)) && seekeoln() && - dns_resolve_start(workchain, addr, blkid, domain, cat, step); + (seekeoln() || get_word_to(cat_str)) && seekeoln() && + 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") { std::string 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, - std::string domain, int cat, int mode) { - if (domain.size() > 1023) { - return set_error("domain name too long"); - } + std::string domain, td::Bits256 cat, int mode) { if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') { domain.erase(0, 1); domain.pop_back(); } std::vector components; - std::size_t i, p = 0; - for (i = 0; i < domain.size(); i++) { - 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 != ".") { + std::size_t i, p = 0; + for (i = 0; i < domain.size(); i++) { + 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"); + } + components.emplace_back(domain, p, i - p); + p = i + 1; } + } + if (i > p) { components.emplace_back(domain, p, i - p); - p = i + 1; } } - if (i > p) { - components.emplace_back(domain, p, i - p); + std::string qdomain; + if (mode & 2) { + qdomain += '\0'; } - std::string qdomain, qdomain0; while (!components.empty()) { qdomain += components.back(); qdomain += '\0'; components.pop_back(); } + if (qdomain.size() > 127) { + return set_error("domain name too long"); + } if (!(ready_ && !client_.empty())) { 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, - 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 << " starting from smart contract " << workchain << ":" << addr.to_hex() << " with respect to block " << 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; Ref 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"); } std::vector params; - params.emplace_back(vm::load_cell_slice_ref(std::move(cell))); - params.emplace_back(td::make_refint(cat)); + params.emplace_back(vm::load_cell_slice_ref(cell)); + params.emplace_back(td::bits_to_refint(cat.cbits(), 256, false)); auto P = td::PromiseCreator::lambda([this, workchain, addr, blkid, domain, qdomain, cat, mode](td::Result> R) { 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)); } -bool TestNode::show_dns_record(std::ostream& os, int cat, Ref value, bool raw_dump) { +bool TestNode::show_dns_record(std::ostream& os, td::Bits256 cat, Ref value, bool raw_dump) { if (raw_dump) { bool ok = show_dns_record(os, cat, value, false); if (!ok) { 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; } @@ -1715,11 +1715,11 @@ bool TestNode::show_dns_record(std::ostream& os, int cat, Ref value, b return true; } // 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; } - block::gen::t_DNSRecord.print_ref(print_limit_, os, value); - auto cs = vm::load_cell_slice(value); + block::gen::t_DNSRecord.print(os, value, 0, print_limit_); + auto cs = *value; auto tag = block::gen::t_DNSRecord.get_tag(cs); ton::WorkchainId wc; ton::StdSmcAddress addr; @@ -1751,7 +1751,7 @@ bool TestNode::show_dns_record(std::ostream& os, int cat, Ref value, b } 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 value) { if (used_bits <= 0) { 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 << ")"; return; } - int pos = (used_bits >> 3); - if (qdomain[pos - 1]) { + size_t pos = used_bits >> 3; + bool end = pos == qdomain.size(); + if (!end && qdomain[pos - 1] && qdomain[pos]) { LOG(ERROR) << "domain split not at a component boundary"; return; } - bool end = ((std::size_t)pos == qdomain.size()); if (!end) { LOG(INFO) << "partial information obtained"; if (value.is_null()) { @@ -1778,7 +1778,7 @@ void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress ton::StdSmcAddress nx_addr; 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))) { - 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; vm::load_cell_slice(value).print_rec(print_limit_, out); 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"; 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; } 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 { if (value.not_null()) { std::ostringstream os0; vm::load_cell_slice(value).print_rec(print_limit_, os0); out << "raw data: " << os0.str() << std::endl; } - if (!cat) { - vm::Dictionary dict{value, 16}; + if (cat.is_zero()) { + vm::Dictionary dict{value, 256}; if (!dict.check_for_each([this, &out](Ref cs, td::ConstBitPtr key, int n) { - CHECK(n == 16); - int x = (int)key.get_int(16); - if (cs.is_null() || cs->size_ext() != 0x10000) { - out << "category #" << x << " : value is not a reference" << std::endl; - return false; - } + CHECK(n == 256); + td::Bits256 x{key}; + /*if (cs.is_null() || cs->size_ext() != 0x10000) { + out << "category " << x << " : value is not a reference" << std::endl; + return true; + }*/ std::ostringstream os; - (void)show_dns_record(os, x, cs->prefetch_ref(), true); - out << "category #" << x << " : " << os.str() << std::endl; + (void)show_dns_record(os, x, cs, true); + out << "category " << x << " : " << os.str() << std::endl; return true; })) { out << "invalid dns record dictionary" << std::endl; } } else { std::ostringstream os; - (void)show_dns_record(os, cat, value, true); - out << "category #" << cat << " : " << os.str() << std::endl; + (void)show_dns_record(os, cat, value.is_null() ? Ref() : vm::load_cell_slice_ref(value), true); + out << "category " << cat << " : " << os.str() << std::endl; } } catch (vm::VmError& err) { LOG(ERROR) << "vm error while traversing dns resolve result: " << err.get_msg(); diff --git a/lite-client/lite-client.h b/lite-client/lite-client.h index 00d8bd075..e62e801ce 100644 --- a/lite-client/lite-client.h +++ b/lite-client/lite-client.h @@ -213,13 +213,13 @@ class TestNode : public td::actor::Actor { bool register_config_param1(Ref value); bool register_config_param4(Ref value); 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, - 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, - 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 value); - bool show_dns_record(std::ostream& os, int cat, Ref value, bool raw_dump); + bool show_dns_record(std::ostream& os, td::Bits256 cat, Ref value, bool raw_dump); 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); bool parse_get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "", diff --git a/rldp-http-proxy/rldp-http-proxy.cpp b/rldp-http-proxy/rldp-http-proxy.cpp index 59533c50f..fb5ae4c1b 100644 --- a/rldp-http-proxy/rldp-http-proxy.cpp +++ b/rldp-http-proxy/rldp-http-proxy.cpp @@ -1073,7 +1073,8 @@ void TcpToRldpRequestSender::resolve() { 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)); } else { - auto obj = tonlib_api::make_object(nullptr, host_, 0, 16); + td::Bits256 category = td::sha256_bits256(td::Slice("site", 4)); + auto obj = tonlib_api::make_object(nullptr, host_, category, 16); auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { diff --git a/tl/generate/generate_common.cpp b/tl/generate/generate_common.cpp index c824f0f4a..0068ccbd4 100644 --- a/tl/generate/generate_common.cpp +++ b/tl/generate/generate_common.cpp @@ -74,11 +74,11 @@ int main() { generate_cpp( "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\""}, - {"", "\"td/utils/SharedSlice.h\""}); + {"", "\"td/utils/SharedSlice.h\"", "\"crypto/common/bitstring.h\""}); #else 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\""}, - {"", "\"td/utils/SharedSlice.h\""}); + {"", "\"td/utils/SharedSlice.h\"", "\"crypto/common/bitstring.h\""}); #endif 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); diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index d5f97cce8..7ba6b6a90 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -4,6 +4,7 @@ string ? = String; int32 = Int32; int53 = Int53; int64 = Int64; +int256 8*[ int32 ] = Int256; bytes = Bytes; secureString = SecureString; secureBytes = SecureBytes; @@ -117,11 +118,11 @@ dns.entryDataNextResolver resolver:AccountAddress = dns.EntryData; dns.entryDataSmcAddress smc_address:AccountAddress = 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; // 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.resolved entries:vector = dns.Resolved; @@ -283,7 +284,7 @@ smc.getData id:int53 = tvm.Cell; smc.getState id:int53 = tvm.Cell; smc.runGetMethod id:int53 method:smc.MethodId stack:vector = 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.validatePromise public_key:bytes promise:pchan.promise = Ok; diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index 05c56ac08283bea94ca484f2c04acf3d2ac1d224..d99b35f3c4e65fe121791b649c41a7a4c09a29a1 100644 GIT binary patch delta 382 zcmZp;%h+>|k@wMTeJchih}g(`o0;3DXW?8n&%6>NQ?tqTOp=>lFkfJ1;fb4cb@Co| z6_#c0(sG-hu=lVrHf}EDTg?WR*{mR1!ea^6m>2TP#9R!KN%(yDY6%$y`?jn$q zSFD$qT#}ie=aQO}T9OJ>0MpAf`C+KF1jtN~Eg*nw(&Rh(3Sfs%GLW$a`3RdLh&BcW zkaZw6oFMB`^Gb>;85lr(kQ13f)_|Qpd4_=jByi3ccrbxklWoEjHd`2HD6yDLJ(e|j NNoWPclL}!85&&#vcRK(8 delta 281 zcmeCV$JlU}k@wMTeJchi2;azin|U)2%LQhZ{nHlipZtJbg=NPoy-AxnIC|I^8#Yhn zTg}D_l3|$qQB;0&if9PWW(B1Uybd6-o5zHFK;{%Vv*~cywjBhkgBpBQjw|NTb`w2; zl)PfS#N?99{5+S`oYaz3pghQr{;VgjIkP KZ{86WA^`x$&towF diff --git a/tonlib/test/online.cpp b/tonlib/test/online.cpp index 3b6a554c1..52f517200 100644 --- a/tonlib/test/online.cpp +++ b/tonlib/test/online.cpp @@ -594,7 +594,8 @@ void dns_resolve(Client& client, const Wallet& dns, std::string name) { using namespace ton::tonlib_api; auto address = dns.get_address(); 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); LOG(INFO) << to_string(resolved); LOG(INFO) << "OK"; @@ -747,13 +748,16 @@ void test_dns(Client& client, const Wallet& giver_wallet) { std::vector> actions; actions.push_back(make_object( - make_object("A", -1, make_object(A_B.get_address())))); + make_object("A", ton::DNS_NEXT_RESOLVER_CATEGORY, + make_object(A_B.get_address())))); auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok(); actions.push_back(make_object( - make_object("B", -1, make_object(A_B_C.get_address())))); + make_object("B", ton::DNS_NEXT_RESOLVER_CATEGORY, + make_object(A_B_C.get_address())))); auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok(); actions.push_back( - make_object(make_object("C", 1, make_object("Hello dns")))); + make_object(make_object("C", td::sha256_bits256(td::Slice("cat", 3)), + make_object("Hello dns")))); 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"; diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 26881fc16..6a31720c8 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -2623,11 +2623,10 @@ class GenericCreateSendGrams : public TonlibQueryActor { return downcast_call2(action, td::overloaded( [&](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 { - TRY_RESULT(category, td::narrow_cast_safe(del.category_)); - return ton::ManualDns::Action{del.name_, category, {}}; + return ton::ManualDns::Action{del.name_, del.category_, {}}; }, [&](tonlib_api::dns_actionSet& set) -> R { if (!set.entry_) { @@ -2636,10 +2635,10 @@ class GenericCreateSendGrams : public TonlibQueryActor { if (!set.entry_->entry_) { return TonlibError::EmptyField("entry.entry"); } - TRY_RESULT(category, td::narrow_cast_safe(set.entry_->category_)); TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_)); 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> to_tonlib_api( return res; } -void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, - td::optional block_id, DnsFinishData dns_finish_data, +void TonlibClient::finish_dns_resolve(std::string name, td::Bits256 category, td::int32 ttl, + td::optional block_id, block::StdAddress address, + DnsFinishData dns_finish_data, td::Promise>&& promise) { block_id = dns_finish_data.block_id; // TODO: check if the smartcontract supports Dns interface // 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)); - if (entries.size() == 1 && entries[0].category == -1 && entries[0].name != name && ttl > 0 && - entries[0].data.type == ton::ManualDns::EntryData::Type::NextResolver) { + if (entries.size() == 1 && entries[0].partially_resolved && ttl > 0) { 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")); } - auto dot_position = name.size() - got_name.size() - 1; - auto suffix = name.substr(dot_position + 1); - 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 ")); - } + auto suffix_start = name.size() - got_name.size(); + auto suffix = name.substr(suffix_start); if (suffix != got_name) { 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().resolver; 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(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 block_id, block::StdAddress address, td::Promise>&& promise) { auto block_id_copy = block_id.copy(); td::Promise 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) { 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; } - 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; query.address = std::move(address); 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))); 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_)); - 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)); return td::Status::OK(); } diff --git a/tonlib/tonlib/TonlibClient.h b/tonlib/tonlib/TonlibClient.h index 716133e46..1d2bb38a2 100644 --- a/tonlib/tonlib/TonlibClient.h +++ b/tonlib/tonlib/TonlibClient.h @@ -325,14 +325,15 @@ class TonlibClient : public td::actor::Actor { void perform_smc_execution(td::Ref smc, ton::SmartContract::Args args, td::Promise>&& promise); - void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional block_id, + void do_dns_request(std::string name, td::Bits256 category, td::int32 ttl, td::optional block_id, block::StdAddress address, td::Promise>&& promise); struct DnsFinishData { ton::BlockIdExt block_id; ton::SmartContract::State smc_state; }; - void finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, td::optional block_id, - DnsFinishData dns_finish_data, td::Promise>&& promise); + void finish_dns_resolve(std::string name, td::Bits256 category, td::int32 ttl, td::optional block_id, + block::StdAddress address, DnsFinishData dns_finish_data, + td::Promise>&& promise); td::Status do_request(int_api::GetAccountState request, td::Promise>&&); td::Status do_request(int_api::GetPrivateKey request, td::Promise&&); diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index 6b758fca5..be550454d 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -1162,7 +1162,7 @@ class TonlibCli : public td::actor::Actor { 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 resolved, td::Promise promise) { if (resolved->entries_.empty()) { 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)); auto name = parser.read_word(); auto category_str = parser.read_word(); - TRY_RESULT_PROMISE(promise, category, td::to_integer_safe(category_str)); + td::Bits256 category = category_str.empty() ? td::Bits256::zero() : td::sha256_bits256(td::as_slice(category_str)); std::vector> entries; entries.push_back(make_object( - "", -1, make_object(std::move(address.address)))); + "", ton::DNS_NEXT_RESOLVER_CATEGORY, + make_object(std::move(address.address)))); do_dns_resolve(name.str(), category, 10, make_object(std::move(entries)), std::move(promise)); } @@ -1217,8 +1218,8 @@ class TonlibCli : public td::actor::Actor { if (action.name.empty()) { actions.push_back(make_object()); td::TerminalIO::out() << "Delete all dns entries\n"; - } else if (action.category == 0) { - actions.push_back(make_object(action.name, 0)); + } else if (action.category.is_zero()) { + actions.push_back(make_object(action.name, td::Bits256::zero())); td::TerminalIO::out() << "Delete all dns enties with name: " << action.name << "\n"; } else if (!action.data) { actions.push_back(make_object(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())); sb << action.data.value(); TRY_STATUS_PROMISE(promise, std::move(error)); - td::TerminalIO::out() << "Set dns entry: " << action.name << ":" << action.category << " " << sb.as_cslice() - << "\n"; + td::TerminalIO::out() << "Set dns entry: " << action.name << ":" << action.category << " " + << sb.as_cslice() << "\n"; actions.push_back(make_object( make_object(action.name, action.category, std::move(data)))); }