1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Merge branch 'master' into testnet

This commit is contained in:
EmelyanenkoK 2022-08-04 17:45:31 +03:00
commit 5101b404a4
23 changed files with 488 additions and 399 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -786,7 +786,9 @@ struct ModArray {
}
ModArray& operator/=(const ModArray& other) {
assert(try_divide(other) && "division by zero?");
if (!try_divide(other)) {
assert(false); // division by zero?
}
return *this;
}
@ -1051,7 +1053,9 @@ void init_invm() {
for (int i = 0; i < mod_cnt; i++) {
assert(mod[i] > 0 && mod[i] <= (1 << 30));
for (int j = 0; j < i; j++) {
assert(gcdx(mod[i], mod[j], invm[i][j], invm[j][i]) == 1);
if (gcdx(mod[i], mod[j], invm[i][j], invm[j][i]) != 1) {
assert(false);
}
if (invm[i][j] < 0) {
invm[i][j] += mod[j];
}

View file

@ -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<std::string> text;
bool does_create_category() const {
CHECK(!name.empty());
CHECK(category != 0);
CHECK(!category.is_zero());
return static_cast<bool>(text);
}
bool does_change_empty() const {
CHECK(!name.empty());
CHECK(category != 0);
CHECK(!category.is_zero());
return static_cast<bool>(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() : "<empty>")
<< "]";
return sb << "[" << entry.name << ":" << entry.category.to_hex() << ":"
<< (entry.text ? entry.text.value() : "<empty>") << "]";
}
};
void update(td::Span<Action> 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<Entry> resolve(td::Slice name, td::int16 category) {
std::vector<Entry> resolve(td::Slice name, td::Bits256 category) {
std::vector<Entry> 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::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) {
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<Entry> resolve(td::Slice name, td::int16 category) {
LOG(ERROR) << "RESOLVE: " << name << " " << category;
std::vector<Entry> 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<Action> actions;
@ -1130,7 +1136,7 @@ void do_dns_test(CheckedDns&& dns) {
if (rnd.fast(0, 20) == 0) {
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) {
return action;
}
@ -1150,7 +1156,8 @@ void do_dns_test(CheckedDns&& dns) {
actions.clear();
}
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"));
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));

View file

@ -320,7 +320,7 @@ class Stack : public td::CntObject {
Stack(const Stack& old_stack, unsigned copy_elem, unsigned skip_top);
Stack(Stack&& old_stack, unsigned copy_elem, unsigned skip_top);
td::CntObject* make_copy() const override {
std::cerr << "copy stack at " << (const void*)this << " (" << depth() << " entries)\n";
//std::cerr << "copy stack at " << (const void*)this << " (" << depth() << " entries)\n";
return new Stack{stack};
}
void push_from_stack(const Stack& old_stack, unsigned copy_elem, unsigned skip_top = 0);