mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Update DNS resolver in liteclient and tonlib
This commit is contained in:
parent
7e3df93ca2
commit
7e207dc78f
14 changed files with 278 additions and 237 deletions
|
@ -146,24 +146,27 @@ 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());
|
||||
|
@ -171,10 +174,15 @@ td::Result<std::vector<DnsInterface::Entry>> 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<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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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)});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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::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);
|
||||
}
|
||||
|
|
|
@ -26,10 +26,14 @@
|
|||
#include "smc-envelope/SmartContract.h"
|
||||
|
||||
#include "Ed25519.h"
|
||||
#include "common/checksum.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
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<vm::Cell> data;
|
||||
td::Bits256 category;
|
||||
td::Ref<vm::CellSlice> data;
|
||||
bool partially_resolved = false;
|
||||
};
|
||||
|
||||
struct ActionExt {
|
||||
std::string name;
|
||||
td::int16 category;
|
||||
td::Bits256 category;
|
||||
td::optional<EntryData> data;
|
||||
static td::Result<ActionExt> parse(td::Slice);
|
||||
};
|
||||
|
||||
struct Action {
|
||||
std::string name;
|
||||
td::int16 category;
|
||||
td::Bits256 category;
|
||||
td::optional<td::Ref<vm::Cell>> data;
|
||||
|
||||
bool does_create_category() const {
|
||||
CHECK(!name.empty());
|
||||
CHECK(category != 0);
|
||||
CHECK(!category.is_zero());
|
||||
return static_cast<bool>(data);
|
||||
}
|
||||
bool does_change_empty() const {
|
||||
CHECK(!name.empty());
|
||||
CHECK(category != 0);
|
||||
CHECK(!category.is_zero());
|
||||
return static_cast<bool>(data) && data.value().not_null();
|
||||
}
|
||||
void make_non_empty() {
|
||||
CHECK(!name.empty());
|
||||
CHECK(category != 0);
|
||||
CHECK(!category.is_zero());
|
||||
if (!data) {
|
||||
data = td::Ref<vm::Cell>();
|
||||
}
|
||||
}
|
||||
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 << "<null>";
|
||||
|
@ -156,15 +162,14 @@ class DnsInterface {
|
|||
}
|
||||
};
|
||||
|
||||
virtual ~DnsInterface() {
|
||||
}
|
||||
virtual ~DnsInterface() = default;
|
||||
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(
|
||||
td::Ed25519::PrivateKey& pk, td::Span<Action> actions,
|
||||
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 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<SmartContract::Args> 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<SmartContract::Args> 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<ManualDns> create(State state) {
|
||||
return td::Ref<ManualDns>(true, std::move(state));
|
||||
static td::Ref<ManualDns> create(State state, block::StdAddress address = {}) {
|
||||
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(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_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::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_set_all_unsigned(td::Span<Action> entries) 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);
|
||||
|
||||
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_or_throw(td::Slice name, td::int32 category_big) const;
|
||||
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::Bits256 category) const;
|
||||
|
||||
td::Result<td::Ref<vm::Cell>> create_init_query(
|
||||
const td::Ed25519::PrivateKey& private_key,
|
||||
|
@ -235,10 +243,10 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
|
|||
template <class ActionT>
|
||||
struct CombinedActions {
|
||||
std::string name;
|
||||
td::int16 category{0};
|
||||
td::Bits256 category = td::Bits256::zero();
|
||||
td::optional<std::vector<ActionT>> 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 << "<data>" << action.actions.value().size();
|
||||
} else {
|
||||
|
@ -251,7 +259,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
|
|||
template <class ActionT = Action>
|
||||
static std::vector<CombinedActions<ActionT>> combine_actions(td::Span<ActionT> actions) {
|
||||
struct Info {
|
||||
std::set<td::int16> known_category;
|
||||
std::set<td::Bits256> known_category;
|
||||
std::vector<ActionT> 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<td::Ref<vm::Cell>> create_update_query(CombinedActions<Action>& combined) const;
|
||||
private:
|
||||
block::StdAddress address_;
|
||||
};
|
||||
|
||||
} // namespace ton
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue