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

updated tonlib

- updated tonlib
- updated validator
- updated documentation
- first version of http over rldp proxy
This commit is contained in:
ton 2020-02-06 21:56:46 +04:00
parent 53ec9684bd
commit 77842f9b63
128 changed files with 10555 additions and 2285 deletions

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "vm/dict.h"
#include "common/bigint.hpp"
@ -28,6 +28,7 @@
#include "fift/utils.h"
#include "smc-envelope/GenericAccount.h"
#include "smc-envelope/ManualDns.h"
#include "smc-envelope/MultisigWallet.h"
#include "smc-envelope/SmartContract.h"
#include "smc-envelope/SmartContractCode.h"
@ -36,6 +37,7 @@
#include "smc-envelope/Wallet.h"
#include "smc-envelope/WalletV3.h"
#include "smc-envelope/HighloadWallet.h"
#include "smc-envelope/HighloadWalletV2.h"
#include "td/utils/base64.h"
#include "td/utils/crypto.h"
@ -47,6 +49,7 @@
#include "td/utils/PathView.h"
#include "td/utils/filesystem.h"
#include "td/utils/port/path.h"
#include "td/utils/Variant.h"
#include <bitset>
#include <set>
@ -63,8 +66,8 @@ std::string load_source(std::string name) {
td::Ref<vm::Cell> get_test_wallet_source() {
std::string code = R"ABCD(
SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk
}>
INC 32 THROWIF // fail unless recv_external
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt
@ -91,8 +94,8 @@ INC NEWC 32 STU 256 STU ENDC c4 POPCTR
td::Ref<vm::Cell> get_wallet_source() {
std::string code = R"ABCD(
SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk
}>
INC 32 THROWIF // fail unless recv_external
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs
@ -119,8 +122,8 @@ SETCP0 DUP IFNOTRET // return if recv_internal
td::Ref<vm::Cell> get_wallet_v3_source() {
std::string code = R"ABCD(
SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk
}>
INC 32 THROWIF // fail unless recv_external
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs
@ -176,8 +179,15 @@ TEST(Tonlib, TestWallet) {
"321", "-C", "TEST"})
.move_as_ok();
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
ton::TestWallet::Gift gift;
gift.destination = dest;
gift.message = "TEST";
gift.gramms = 321000000000ll;
ton::TestWallet wallet(priv_key.get_public_key().move_as_ok(), 123);
ASSERT_EQ(123u, wallet.get_seqno().ok());
CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string());
auto gift_message = ton::GenericAccount::create_ext_message(
address, {}, ton::TestWallet::make_a_gift_message(priv_key, 123, 321000000000ll, "TEST", dest));
address, {}, wallet.make_a_gift_message(priv_key, 0, {gift}).move_as_ok());
LOG(ERROR) << "-------";
vm::load_cell_slice(gift_message).print_rec(std::cerr);
LOG(ERROR) << "-------";
@ -224,13 +234,20 @@ TEST(Tonlib, Wallet) {
};
fift_output.source_lookup.set_os_time(std::make_unique<ZeroOsTime>());
auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
fift_output =
fift::mem_run_fift(std::move(fift_output.source_lookup),
{"aba", "new-wallet", "-C", "TESTv2", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "123", "321"})
.move_as_ok();
fift_output = fift::mem_run_fift(std::move(fift_output.source_lookup),
{"aba", "new-wallet", "-C", "TESTv2",
"Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "123", "321"})
.move_as_ok();
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
ton::TestWallet::Gift gift;
gift.destination = dest;
gift.message = "TESTv2";
gift.gramms = 321000000000ll;
ton::Wallet wallet(priv_key.get_public_key().move_as_ok(), 123);
ASSERT_EQ(123u, wallet.get_seqno().ok());
CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string());
auto gift_message = ton::GenericAccount::create_ext_message(
address, {}, ton::Wallet::make_a_gift_message(priv_key, 123, 60, 321000000000ll, "TESTv2", dest));
address, {}, wallet.make_a_gift_message(priv_key, 60, {gift}).move_as_ok());
LOG(ERROR) << "-------";
vm::load_cell_slice(gift_message).print_rec(std::cerr);
LOG(ERROR) << "-------";
@ -251,7 +268,8 @@ TEST(Tonlib, WalletV3) {
td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}};
auto pub_key = priv_key.get_public_key().move_as_ok();
auto init_state = ton::WalletV3::get_init_state(pub_key, 239);
auto init_message = ton::WalletV3::get_init_message(priv_key, 239);
auto init_message =
ton::WalletV3(priv_key.get_public_key().move_as_ok(), 239).get_init_message(priv_key).move_as_ok();
auto address = ton::GenericAccount::get_address(0, init_state);
CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));
@ -273,13 +291,24 @@ TEST(Tonlib, WalletV3) {
};
fift_output.source_lookup.set_os_time(std::make_unique<ZeroOsTime>());
auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
fift_output =
fift::mem_run_fift(std::move(fift_output.source_lookup),
{"aba", "new-wallet", "-C", "TESTv3", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "239", "123", "321"})
.move_as_ok();
fift_output = fift::mem_run_fift(std::move(fift_output.source_lookup),
{"aba", "new-wallet", "-C", "TESTv3",
"Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "239", "123", "321"})
.move_as_ok();
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
ton::WalletV3::Gift gift;
gift.destination = dest;
gift.message = "TESTv3";
gift.gramms = 321000000000ll;
ton::WalletV3 wallet(priv_key.get_public_key().move_as_ok(), 239, 123);
ASSERT_EQ(239u, wallet.get_wallet_id().ok());
ASSERT_EQ(123u, wallet.get_seqno().ok());
CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string());
auto gift_message = ton::GenericAccount::create_ext_message(
address, {}, ton::WalletV3::make_a_gift_message(priv_key, 239, 123, 60, 321000000000ll, "TESTv3", dest));
address, {}, wallet.make_a_gift_message(priv_key, 60, {gift}).move_as_ok());
LOG(ERROR) << "-------";
vm::load_cell_slice(gift_message).print_rec(std::cerr);
LOG(ERROR) << "-------";
@ -304,6 +333,11 @@ TEST(Tonlib, HighloadWallet) {
auto init_message = ton::HighloadWallet::get_init_message(priv_key, 239);
auto address = ton::GenericAccount::get_address(0, init_state);
ton::HighloadWallet wallet({ton::HighloadWallet::get_init_code(), ton::HighloadWallet::get_init_data(pub_key, 239)});
ASSERT_EQ(239u, wallet.get_wallet_id().ok());
ASSERT_EQ(0u, wallet.get_seqno().ok());
CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string());
CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));
td::Ref<vm::Cell> res = ton::GenericAccount::create_ext_message(address, init_state, init_message);
@ -354,6 +388,80 @@ TEST(Tonlib, HighloadWallet) {
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == gift_message->get_hash());
}
TEST(Tonlib, HighloadWalletV2) {
auto source_lookup = fift::create_mem_source_lookup(load_source("smartcont/new-highload-wallet-v2.fif")).move_as_ok();
source_lookup
.write_file("/auto/highload-wallet-v2-code.fif", load_source("smartcont/auto/highload-wallet-v2-code.fif"))
.ensure();
class ZeroOsTime : public fift::OsTime {
public:
td::uint32 now() override {
return 0;
}
};
source_lookup.set_os_time(std::make_unique<ZeroOsTime>());
auto fift_output = fift::mem_run_fift(std::move(source_lookup), {"aba", "0", "239"}).move_as_ok();
LOG(ERROR) << fift_output.output;
auto new_wallet_pk = fift_output.source_lookup.read_file("new-wallet.pk").move_as_ok().data;
auto new_wallet_query = fift_output.source_lookup.read_file("new-wallet239-query.boc").move_as_ok().data;
auto new_wallet_addr = fift_output.source_lookup.read_file("new-wallet239.addr").move_as_ok().data;
td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}};
auto pub_key = priv_key.get_public_key().move_as_ok();
auto init_state = ton::HighloadWalletV2::get_init_state(pub_key, 239, 0);
auto init_message = ton::HighloadWalletV2::get_init_message(priv_key, 239, 65535);
auto address = ton::GenericAccount::get_address(0, init_state);
ton::HighloadWalletV2 wallet(
{ton::HighloadWalletV2::get_init_code(0), ton::HighloadWalletV2::get_init_data(pub_key, 239)});
ASSERT_EQ(239u, wallet.get_wallet_id().ok());
CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string());
CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));
td::Ref<vm::Cell> res = ton::GenericAccount::create_ext_message(address, init_state, init_message);
LOG(ERROR) << "---smc-envelope----";
vm::load_cell_slice(res).print_rec(std::cerr);
LOG(ERROR) << "---fift scripts----";
vm::load_cell_slice(vm::std_boc_deserialize(new_wallet_query).move_as_ok()).print_rec(std::cerr);
CHECK(vm::std_boc_deserialize(new_wallet_query).move_as_ok()->get_hash() == res->get_hash());
fift_output.source_lookup.write_file("/main.fif", load_source("smartcont/highload-wallet-v2.fif")).ensure();
std::string order;
std::vector<ton::HighloadWalletV2::Gift> gifts;
auto add_order = [&](td::Slice dest_str, td::int64 gramms) {
auto g = td::to_string(gramms);
if (g.size() < 10) {
g = std::string(10 - g.size(), '0') + g;
}
order += PSTRING() << "SEND " << dest_str << " " << g.substr(0, g.size() - 9) << "." << g.substr(g.size() - 9)
<< "\n";
ton::HighloadWalletV2::Gift gift;
gift.destination = block::StdAddress::parse(dest_str).move_as_ok();
gift.gramms = gramms;
gifts.push_back(gift);
};
std::string dest_str = "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX";
add_order(dest_str, 0);
add_order(dest_str, 321000000000ll);
add_order(dest_str, 321ll);
fift_output.source_lookup.write_file("/order", order).ensure();
fift_output.source_lookup.set_os_time(std::make_unique<ZeroOsTime>());
fift_output =
fift::mem_run_fift(std::move(fift_output.source_lookup), {"aba", "new-wallet", "239", "order"}).move_as_ok();
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
auto gift_message = ton::GenericAccount::create_ext_message(
address, {}, ton::HighloadWalletV2::make_a_gift_message(priv_key, 239, 60, gifts));
LOG(ERROR) << "---smc-envelope----";
vm::load_cell_slice(gift_message).print_rec(std::cerr);
LOG(ERROR) << "---fift scripts----";
vm::load_cell_slice(vm::std_boc_deserialize(wallet_query).move_as_ok()).print_rec(std::cerr);
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == gift_message->get_hash());
}
TEST(Tonlib, TestGiver) {
auto address =
block::StdAddress::parse("-1:60c04141c6a7b96d68615e7a91d265ad0f3a9a922e9ae9c901d4fa83f5d3c0d0").move_as_ok();
@ -365,9 +473,13 @@ TEST(Tonlib, TestGiver) {
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
auto res = ton::GenericAccount::create_ext_message(
ton::TestGiver::address(), {},
ton::TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, "GIFT", address));
ton::TestGiver::Gift gift;
gift.gramms = 1000000000ll * 6666 / 1000;
gift.message = "GIFT";
gift.destination = address;
td::Ed25519::PrivateKey key{td::SecureString()};
auto res = ton::GenericAccount::create_ext_message(ton::TestGiver::address(), {},
ton::TestGiver().make_a_gift_message(key, 0, {gift}).move_as_ok());
vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr);
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash());
}
@ -670,3 +782,457 @@ TEST(Smartcont, MultisigStress) {
LOG(INFO) << "Final code size: " << ms->code_size();
LOG(INFO) << "Final data size: " << ms->data_size();
}
class MapDns {
public:
using ManualDns = ton::ManualDns;
struct Entry {
std::string name;
td::int16 category{0};
std::string text;
auto key() const {
return std::tie(name, category);
}
bool operator<(const Entry& other) const {
return key() < other.key();
}
bool operator==(const ton::DnsInterface::Entry& other) const {
return key() == other.key() && other.data.type == ManualDns::EntryData::Type::Text &&
other.data.data.get<ManualDns::EntryDataText>().text == text;
}
bool operator==(const Entry& other) const {
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 << "]";
}
};
struct Action {
std::string name;
td::int16 category{0};
td::optional<std::string> text;
bool does_create_category() const {
CHECK(!name.empty());
CHECK(category != 0);
return static_cast<bool>(text);
}
bool does_change_empty() const {
CHECK(!name.empty());
CHECK(category != 0);
return static_cast<bool>(text) && !text.value().empty();
}
void make_non_empty() {
CHECK(!name.empty());
CHECK(category != 0);
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>")
<< "]";
}
};
void update(td::Span<Action> actions) {
for (auto& action : actions) {
do_update(action);
}
}
using CombinedActions = ton::ManualDns::CombinedActions<Action>;
void update_combined(td::Span<Action> actions) {
LOG(ERROR) << "BEGIN";
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;
if (c.actions) {
LOG(ERROR) << td::format::as_array(c.actions.value());
}
}
LOG(ERROR) << "END";
for (auto& combined_action : combined_actions) {
do_update(combined_action);
}
}
std::vector<Entry> resolve(td::Slice name, td::int16 category) {
std::vector<Entry> res;
if (name.empty()) {
for (auto& a : entries_) {
for (auto& b : a.second) {
res.push_back({a.first, b.first, b.second});
}
}
} else {
auto it = entries_.find(name);
while (it == entries_.end()) {
auto sz = name.find('.');
category = -1;
if (sz != td::Slice::npos) {
name = name.substr(sz + 1);
} else {
break;
}
it = entries_.find(name);
}
if (it != entries_.end()) {
for (auto& b : it->second) {
if (category == 0 || category == b.first) {
res.push_back({name.str(), b.first, b.second});
}
}
}
}
std::sort(res.begin(), res.end());
return res;
}
private:
std::map<std::string, std::map<td::int16, std::string>, std::less<>> entries_;
void do_update(const Action& action) {
if (action.name.empty()) {
entries_.clear();
return;
}
if (action.category == 0) {
entries_.erase(action.name);
return;
}
if (action.text) {
if (action.text.value().empty()) {
entries_[action.name].erase(action.category);
} else {
entries_[action.name][action.category] = action.text.value();
}
} else {
auto it = entries_.find(action.name);
if (it != entries_.end()) {
it->second.erase(action.category);
}
}
}
void do_update(const CombinedActions& actions) {
if (actions.name.empty()) {
entries_.clear();
LOG(ERROR) << "CLEAR";
if (!actions.actions) {
return;
}
for (auto& action : actions.actions.value()) {
CHECK(!action.name.empty());
CHECK(action.category != 0);
CHECK(action.text);
if (action.text.value().empty()) {
entries_[action.name];
} else {
entries_[action.name][action.category] = action.text.value();
}
}
return;
}
if (actions.category == 0) {
entries_.erase(actions.name);
LOG(ERROR) << "CLEAR " << actions.name;
if (!actions.actions) {
return;
}
entries_[actions.name];
for (auto& action : actions.actions.value()) {
CHECK(action.name == actions.name);
CHECK(action.category != 0);
CHECK(action.text);
if (action.text.value().empty()) {
entries_[action.name];
} else {
entries_[action.name][action.category] = action.text.value();
}
}
return;
}
CHECK(actions.actions);
CHECK(actions.actions.value().size() == 1);
for (auto& action : actions.actions.value()) {
CHECK(action.name == actions.name);
CHECK(action.category != 0);
if (action.text) {
if (action.text.value().empty()) {
entries_[action.name].erase(action.category);
} else {
entries_[action.name][action.category] = action.text.value();
}
} else {
auto it = entries_.find(action.name);
if (it != entries_.end()) {
it->second.erase(action.category);
}
}
}
}
};
class CheckedDns {
public:
explicit CheckedDns(bool check_smc = true, bool check_combine = true) {
if (check_smc) {
key_ = td::Ed25519::generate_private_key().move_as_ok();
dns_ = ManualDns::create(ManualDns::create_init_data_fast(key_.value().get_public_key().move_as_ok(), 123));
}
if (check_combine) {
combined_map_dns_ = MapDns();
}
}
using Action = MapDns::Action;
using Entry = MapDns::Entry;
void update(td::Span<Action> entries) {
if (dns_.not_null()) {
auto smc_actions = td::transform(entries, [](auto& entry) {
ton::DnsInterface::Action action;
action.name = entry.name;
action.category = entry.category;
if (entry.text) {
if (entry.text.value().empty()) {
action.data = td::Ref<vm::Cell>();
} else {
action.data = ManualDns::EntryData::text(entry.text.value()).as_cell().move_as_ok();
}
}
return action;
});
auto query = dns_->create_update_query(key_.value(), smc_actions).move_as_ok();
CHECK(dns_.write().send_external_message(std::move(query)).code == 0);
}
map_dns_.update(entries);
if (combined_map_dns_) {
combined_map_dns_.value().update_combined(entries);
}
}
void update(const Action& action) {
return update(td::Span<Action>(&action, 1));
}
std::vector<Entry> resolve(td::Slice name, td::int16 category) {
LOG(ERROR) << "RESOLVE: " << name << " " << category;
auto res = map_dns_.resolve(name, category);
LOG(ERROR) << td::format::as_array(res);
if (dns_.not_null()) {
auto other_res = dns_->resolve(name, category).move_as_ok();
std::sort(other_res.begin(), other_res.end());
if (res.size() != other_res.size()) {
LOG(ERROR) << td::format::as_array(res);
LOG(FATAL) << td::format::as_array(other_res);
}
for (size_t i = 0; i < res.size(); i++) {
if (!(res[i] == other_res[i])) {
LOG(ERROR) << td::format::as_array(res);
LOG(FATAL) << td::format::as_array(other_res);
}
}
}
if (combined_map_dns_) {
auto other_res = combined_map_dns_.value().resolve(name, category);
std::sort(other_res.begin(), other_res.end());
if (res.size() != other_res.size()) {
LOG(ERROR) << td::format::as_array(res);
LOG(FATAL) << td::format::as_array(other_res);
}
for (size_t i = 0; i < res.size(); i++) {
if (!(res[i] == other_res[i])) {
LOG(ERROR) << td::format::as_array(res);
LOG(FATAL) << td::format::as_array(other_res);
}
}
}
return res;
}
private:
using ManualDns = ton::ManualDns;
td::optional<td::Ed25519::PrivateKey> key_;
td::Ref<ManualDns> dns_;
MapDns map_dns_;
td::optional<MapDns> combined_map_dns_;
void do_update_smc(const Action& entry) {
LOG(ERROR) << td::format::escaped(ManualDns::encode_name(entry.name));
ton::DnsInterface::Action action;
action.name = entry.name;
action.category = entry.category;
action.data = ManualDns::EntryData::text(entry.text.value()).as_cell().move_as_ok();
}
};
void do_dns_test(CheckedDns&& dns) {
using Action = CheckedDns::Action;
std::vector<Action> actions;
td::Random::Xorshift128plus rnd(123);
auto gen_name = [&] {
auto cnt = rnd.fast(1, 2);
std::string res;
for (int i = 0; i < cnt; i++) {
if (i != 0) {
res += '.';
}
auto len = rnd.fast(1, 1);
for (int j = 0; j < len; j++) {
res += static_cast<char>(rnd.fast('a', 'b'));
}
}
return res;
};
auto gen_text = [&] {
std::string res;
int len = 5;
for (int j = 0; j < len; j++) {
res += static_cast<char>(rnd.fast('a', 'b'));
}
return res;
};
auto gen_action = [&] {
Action action;
if (rnd.fast(0, 1000) == 0) {
return action;
}
action.name = gen_name();
if (rnd.fast(0, 20) == 0) {
return action;
}
action.category = td::narrow_cast<td::int16>(rnd.fast(1, 5));
if (rnd.fast(0, 4) == 0) {
return action;
}
if (rnd.fast(0, 4) == 0) {
action.text = "";
return action;
}
action.text = gen_text();
return action;
};
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
for (int i = 0; i < 100000; i++) {
actions.push_back(gen_action());
if (rnd.fast(0, 10) == 0) {
dns.update(actions);
actions.clear();
}
dns.resolve(gen_name(), td::narrow_cast<td::int16>(rnd.fast(0, 5)));
}
};
TEST(Smartcont, DnsManual) {
using ManualDns = ton::ManualDns;
auto test_entry_data = [](auto&& entry_data) {
auto cell = entry_data.as_cell().move_as_ok();
auto cs = vm::load_cell_slice(cell);
auto new_entry_data = ManualDns::EntryData::from_cellslice(cs).move_as_ok();
ASSERT_EQ(entry_data, new_entry_data);
};
test_entry_data(ManualDns::EntryData::text("abcd"));
test_entry_data(ManualDns::EntryData::adnl_address(ton::Bits256{}));
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"));
ASSERT_EQ("", ManualDns::decode_name(""));
auto key = td::Ed25519::generate_private_key().move_as_ok();
auto manual = ManualDns::create(ManualDns::create_init_data_fast(key.get_public_key().move_as_ok(), 123));
CHECK(manual->get_wallet_id().move_as_ok() == 123);
auto init_query = manual->create_init_query(key).move_as_ok();
LOG(ERROR) << "A";
CHECK(manual.write().send_external_message(init_query).code == 0);
LOG(ERROR) << "B";
CHECK(manual.write().send_external_message(init_query).code != 0);
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())
.move_as_ok();
CHECK(manual.write().send_external_message(set_query).code == 0);
auto res = manual->run_get_method(
"dnsresolve", {vm::load_cell_slice_ref(vm::CellBuilder().store_bytes("a\0b\0").finalize()), td::make_refint(1)});
CHECK(res.code == 0);
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);
LOG(ERROR) << "Test zero category";
dns.resolve("a.b.c", 0);
dns.update(CheckedDns::Action{"", 0, ""});
CHECK(dns.resolve("a.b.c", 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"}};
dns.update(td::Span<CheckedDns::Action>(e, 4));
}
dns.resolve("a.b.c", 1);
dns.resolve("a.b.c", 2);
dns.resolve("x.y.z", 3);
{
CheckedDns::Action e[1] = {CheckedDns::Action{"x.y.z", 0, ""}};
dns.update(td::Span<CheckedDns::Action>(e, 1));
}
dns.resolve("a.b.c", 1);
dns.resolve("a.b.c", 2);
dns.resolve("x.y.z", 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"}};
dns.update(td::Span<CheckedDns::Action>(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);
{
auto actions_ext =
ton::ManualDns::parse("delete.name one\nset one 1 TEXT:one\ndelete.name two\nset two 2 TEXT:two").move_as_ok();
auto actions = td::transform(actions_ext, [](auto& action) {
td::optional<std::string> data;
if (action.data) {
data = action.data.value().data.template get<ton::ManualDns::EntryDataText>().text;
}
return CheckedDns::Action{action.name, action.category, std::move(data)};
});
dns.update(actions);
}
dns.resolve("one", 1);
dns.resolve("two", 2);
// TODO: rethink semantic of creating an empty dictionary
do_dns_test(CheckedDns(true, true));
}