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

emergency update

This commit is contained in:
ton 2020-03-24 03:32:16 +04:00
parent 5d846e0aaf
commit 9f351fc29f
87 changed files with 2486 additions and 655 deletions

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once

View file

@ -19,6 +19,10 @@
#include "adnl-network-manager.hpp" #include "adnl-network-manager.hpp"
#include "adnl-peer-table.h" #include "adnl-peer-table.h"
#include "auto/tl/ton_api.hpp"
#include "td/utils/overloaded.h"
namespace ton { namespace ton {
namespace adnl { namespace adnl {
@ -27,25 +31,84 @@ td::actor::ActorOwn<AdnlNetworkManager> AdnlNetworkManager::create(td::uint16 po
return td::actor::create_actor<AdnlNetworkManagerImpl>("NetworkManager", port); return td::actor::create_actor<AdnlNetworkManagerImpl>("NetworkManager", port);
} }
void AdnlNetworkManagerImpl::add_listening_udp_port(td::uint16 port) { AdnlNetworkManagerImpl::OutDesc *AdnlNetworkManagerImpl::choose_out_iface(td::uint8 cat, td::uint32 priority) {
auto it = out_desc_.upper_bound(priority);
while (true) {
if (it == out_desc_.begin()) {
return nullptr;
}
it--;
auto &v = it->second;
for (auto &x : v) {
if (x.cat_mask.test(cat)) {
return &x;
}
}
}
}
size_t AdnlNetworkManagerImpl::add_listening_udp_port(td::uint16 port) {
auto it = port_2_socket_.find(port);
if (it != port_2_socket_.end()) {
return it->second;
}
class Callback : public td::UdpServer::Callback { class Callback : public td::UdpServer::Callback {
public: public:
Callback(td::actor::ActorShared<AdnlNetworkManagerImpl> manager) : manager_(std::move(manager)) { Callback(td::actor::ActorShared<AdnlNetworkManagerImpl> manager, size_t idx)
: manager_(std::move(manager)), idx_(idx) {
} }
private: private:
td::actor::ActorShared<AdnlNetworkManagerImpl> manager_; td::actor::ActorShared<AdnlNetworkManagerImpl> manager_;
size_t idx_;
void on_udp_message(td::UdpMessage udp_message) override { void on_udp_message(td::UdpMessage udp_message) override {
td::actor::send_closure_later(manager_, &AdnlNetworkManagerImpl::receive_udp_message, std::move(udp_message)); td::actor::send_closure_later(manager_, &AdnlNetworkManagerImpl::receive_udp_message, std::move(udp_message),
idx_);
} }
}; };
auto X = td::UdpServer::create("udp server", port, std::make_unique<Callback>(actor_shared(this))); auto idx = udp_sockets_.size();
auto X = td::UdpServer::create("udp server", port, std::make_unique<Callback>(actor_shared(this), idx));
X.ensure(); X.ensure();
udp_servers_.emplace(port, X.move_as_ok()); port_2_socket_[port] = idx;
udp_sockets_.push_back(UdpSocketDesc{port, X.move_as_ok()});
return idx;
} }
void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) { void AdnlNetworkManagerImpl::add_self_addr(td::IPAddress addr, AdnlCategoryMask cat_mask, td::uint32 priority) {
auto port = td::narrow_cast<td::uint16>(addr.get_port());
size_t idx = add_listening_udp_port(port);
add_in_addr(InDesc{port, nullptr, cat_mask}, idx);
auto d = OutDesc{port, td::IPAddress{}, nullptr, idx};
for (auto &it : out_desc_[priority]) {
if (it == d) {
it.cat_mask |= cat_mask;
return;
}
}
d.cat_mask = cat_mask;
out_desc_[priority].push_back(std::move(d));
}
void AdnlNetworkManagerImpl::add_proxy_addr(td::IPAddress addr, td::uint16 local_port, std::shared_ptr<AdnlProxy> proxy,
AdnlCategoryMask cat_mask, td::uint32 priority) {
size_t idx = add_listening_udp_port(local_port);
add_in_addr(InDesc{local_port, proxy, cat_mask}, idx);
auto d = OutDesc{local_port, addr, proxy, idx};
for (auto &it : out_desc_[priority]) {
if (it == d) {
it.cat_mask |= cat_mask;
return;
}
}
d.cat_mask = cat_mask;
proxy_register(d);
out_desc_[priority].push_back(std::move(d));
}
void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message, size_t idx) {
if (!callback_) { if (!callback_) {
LOG(ERROR) << this << ": dropping IN message [?->?]: peer table unitialized"; LOG(ERROR) << this << ": dropping IN message [?->?]: peer table unitialized";
return; return;
@ -54,6 +117,96 @@ void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
VLOG(ADNL_WARNING) << this << ": dropping ERROR message: " << message.error; VLOG(ADNL_WARNING) << this << ": dropping ERROR message: " << message.error;
return; return;
} }
if (message.data.size() < 32) {
VLOG(ADNL_WARNING) << this << ": received too small proxy packet of size " << message.data.size();
return;
}
if (message.data.size() >= get_mtu() + 128) {
VLOG(ADNL_NOTICE) << this << ": received huge packet of size " << message.data.size();
}
CHECK(idx < udp_sockets_.size());
auto &socket = udp_sockets_[idx];
AdnlCategoryMask cat_mask;
bool from_proxy = false;
if (socket.allow_proxy) {
td::Bits256 x;
x.as_slice().copy_from(message.data.as_slice().truncate(32));
auto it = proxy_addrs_.find(x);
if (it != proxy_addrs_.end()) {
from_proxy = true;
CHECK(it->second < in_desc_.size());
auto &proxy_iface = in_desc_[it->second];
CHECK(proxy_iface.is_proxy());
auto R = in_desc_[it->second].proxy->decrypt(std::move(message.data));
if (R.is_error()) {
VLOG(ADNL_WARNING) << this << ": failed to decrypt proxy mesage: " << R.move_as_error();
return;
}
auto packet = R.move_as_ok();
if (packet.flags & 1) {
message.address.init_host_port(td::IPAddress::ipv4_to_str(packet.ip), packet.port).ensure();
} else {
message.address = td::IPAddress{};
}
if ((packet.flags & 6) == 6) {
if (proxy_iface.received.packet_is_delivered(packet.adnl_start_time, packet.seqno)) {
VLOG(ADNL_WARNING) << this << ": dropping duplicate proxy packet";
return;
}
}
if (packet.flags & 8) {
if (packet.date < td::Clocks::system() - 60 || packet.date > td::Clocks::system() + 60) {
VLOG(ADNL_WARNING) << this << ": dropping proxy packet: bad time " << packet.date;
return;
}
}
if (!(packet.flags & (1 << 16))) {
VLOG(ADNL_WARNING) << this << ": dropping proxy packet: packet has outbound flag";
return;
}
if (packet.flags & (1 << 17)) {
auto F = fetch_tl_object<ton_api::adnl_ProxyControlPacket>(std::move(packet.data), true);
if (F.is_error()) {
VLOG(ADNL_WARNING) << this << ": dropping proxy packet: bad control packet";
return;
}
ton_api::downcast_call(*F.move_as_ok().get(),
td::overloaded(
[&](const ton_api::adnl_proxyControlPacketPing &f) {
auto &v = *proxy_iface.out_desc;
auto data =
create_serialize_tl_object<ton_api::adnl_proxyControlPacketPong>(f.id_);
AdnlProxy::Packet p;
p.flags = 6 | (1 << 17);
p.ip = 0;
p.port = 0;
p.data = std::move(data);
p.adnl_start_time = Adnl::adnl_start_time();
p.seqno = ++v.out_seqno;
auto enc = v.proxy->encrypt(std::move(p));
td::UdpMessage M;
M.address = v.proxy_addr;
M.data = std::move(enc);
td::actor::send_closure(socket.server, &td::UdpServer::send, std::move(M));
},
[&](const ton_api::adnl_proxyControlPacketPong &f) {},
[&](const ton_api::adnl_proxyControlPacketRegister &f) {}));
return;
}
message.data = std::move(packet.data);
cat_mask = in_desc_[it->second].cat_mask;
}
}
if (!from_proxy) {
if (socket.in_desc == std::numeric_limits<size_t>::max()) {
VLOG(ADNL_WARNING) << this << ": received bad packet to proxy-only listenung port";
return;
}
cat_mask = in_desc_[socket.in_desc].cat_mask;
}
if (message.data.size() >= get_mtu()) { if (message.data.size() >= get_mtu()) {
VLOG(ADNL_NOTICE) << this << ": received huge packet of size " << message.data.size(); VLOG(ADNL_NOTICE) << this << ": received huge packet of size " << message.data.size();
} }
@ -63,49 +216,81 @@ void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
} }
VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size(); VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size();
callback_->receive_packet(message.address, std::move(message.data)); callback_->receive_packet(message.address, cat_mask, std::move(message.data));
} }
void AdnlNetworkManagerImpl::send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, void AdnlNetworkManagerImpl::send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
td::uint32 priority, td::BufferSlice data) { td::uint32 priority, td::BufferSlice data) {
auto randseed = 1; // use DST? auto it = adnl_id_2_cat_.find(src_id);
while (priority > 0) { if (it == adnl_id_2_cat_.end()) {
if (out_desc_[priority].size() > 0) { VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: unknown src";
break;
}
priority--;
}
if (out_desc_[priority].size() == 0) {
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: no out desc";
return; return;
} }
auto &dv = out_desc_[priority]; auto out = choose_out_iface(it->second, priority);
auto &v = dv[randseed % dv.size()]; if (!out) {
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: no out rules";
return;
}
auto &v = *out;
auto &socket = udp_sockets_[v.socket_idx];
if (!v.is_proxy()) { if (!v.is_proxy()) {
auto it = udp_servers_.find(static_cast<td::uint16>(v.addr.get_port()));
CHECK(it != udp_servers_.end());
td::UdpMessage M; td::UdpMessage M;
M.address = dst_addr; M.address = dst_addr;
M.data = std::move(data); M.data = std::move(data);
CHECK(M.data.size() <= get_mtu()); CHECK(M.data.size() <= get_mtu());
td::actor::send_closure(it->second, &td::UdpServer::send, std::move(M)); td::actor::send_closure(socket.server, &td::UdpServer::send, std::move(M));
} else { } else {
auto it = udp_servers_.find(out_udp_port_); AdnlProxy::Packet p;
CHECK(it != udp_servers_.end()); p.flags = 7;
p.ip = dst_addr.get_ipv4();
p.port = static_cast<td::uint16>(dst_addr.get_port());
p.data = std::move(data);
p.adnl_start_time = Adnl::adnl_start_time();
p.seqno = ++v.out_seqno;
auto enc = v.proxy->encrypt( auto enc = v.proxy->encrypt(std::move(p));
AdnlProxy::Packet{dst_addr.get_ipv4(), static_cast<td::uint16>(dst_addr.get_port()), std::move(data)});
td::UdpMessage M; td::UdpMessage M;
M.address = v.addr; M.address = v.proxy_addr;
M.data = std::move(enc); M.data = std::move(enc);
td::actor::send_closure(it->second, &td::UdpServer::send, std::move(M)); td::actor::send_closure(socket.server, &td::UdpServer::send, std::move(M));
}
}
void AdnlNetworkManagerImpl::proxy_register(OutDesc &desc) {
auto data = create_serialize_tl_object<ton_api::adnl_proxyControlPacketRegister>(0, 0);
AdnlProxy::Packet p;
p.flags = 6 | (1 << 17);
p.ip = 0;
p.port = 0;
p.data = std::move(data);
p.adnl_start_time = Adnl::adnl_start_time();
p.seqno = ++desc.out_seqno;
auto enc = desc.proxy->encrypt(std::move(p));
td::UdpMessage M;
M.address = desc.proxy_addr;
M.data = std::move(enc);
auto &socket = udp_sockets_[desc.socket_idx];
td::actor::send_closure(socket.server, &td::UdpServer::send, std::move(M));
}
void AdnlNetworkManagerImpl::alarm() {
alarm_timestamp() = td::Timestamp::in(60.0);
for (auto &vec : out_desc_) {
for (auto &desc : vec.second) {
if (desc.is_proxy()) {
proxy_register(desc);
}
}
} }
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -26,6 +26,8 @@
#include "adnl-node-id.hpp" #include "adnl-node-id.hpp"
#include "adnl-proxy-types.h" #include "adnl-proxy-types.h"
#include <bitset>
namespace td { namespace td {
class UdpServer; class UdpServer;
} }
@ -36,6 +38,8 @@ namespace adnl {
class AdnlPeerTable; class AdnlPeerTable;
using AdnlCategoryMask = std::bitset<256>;
class AdnlNetworkConnection : public td::actor::Actor { class AdnlNetworkConnection : public td::actor::Actor {
public: public:
class Callback { class Callback {
@ -56,7 +60,7 @@ class AdnlNetworkManager : public td::actor::Actor {
public: public:
virtual ~Callback() = default; virtual ~Callback() = default;
//virtual void receive_packet(td::IPAddress addr, ConnHandle conn_handle, td::BufferSlice data) = 0; //virtual void receive_packet(td::IPAddress addr, ConnHandle conn_handle, td::BufferSlice data) = 0;
virtual void receive_packet(td::IPAddress addr, td::BufferSlice data) = 0; virtual void receive_packet(td::IPAddress addr, AdnlCategoryMask cat_mask, td::BufferSlice data) = 0;
}; };
static td::actor::ActorOwn<AdnlNetworkManager> create(td::uint16 out_port); static td::actor::ActorOwn<AdnlNetworkManager> create(td::uint16 out_port);
@ -64,14 +68,16 @@ class AdnlNetworkManager : public td::actor::Actor {
virtual void install_callback(std::unique_ptr<Callback> callback) = 0; virtual void install_callback(std::unique_ptr<Callback> callback) = 0;
virtual void add_self_addr(td::IPAddress addr, td::uint32 priority) = 0; virtual void add_self_addr(td::IPAddress addr, AdnlCategoryMask cat_mask, td::uint32 priority) = 0;
virtual void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) = 0; virtual void add_proxy_addr(td::IPAddress addr, td::uint16 local_port, std::shared_ptr<AdnlProxy> proxy,
AdnlCategoryMask cat_mask, td::uint32 priority) = 0;
virtual void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, virtual void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
td::uint32 priority, td::BufferSlice data) = 0; td::uint32 priority, td::BufferSlice data) = 0;
//virtual void send_tcp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, //virtual void send_tcp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
// td::uint32 priority, td::BufferSlice data) = 0; // td::uint32 priority, td::BufferSlice data) = 0;
//virtual void send_answer_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, //virtual void send_answer_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
// ConnHandle conn_handle, td::uint32 priority, td::BufferSlice data) = 0; // ConnHandle conn_handle, td::uint32 priority, td::BufferSlice data) = 0;
virtual void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) = 0;
static constexpr td::uint32 get_mtu() { static constexpr td::uint32 get_mtu() {
return 1440; return 1440;

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -25,6 +25,7 @@
#include "td/actor/PromiseFuture.h" #include "td/actor/PromiseFuture.h"
#include "adnl-network-manager.h" #include "adnl-network-manager.h"
#include "adnl-received-mask.h"
#include <map> #include <map>
@ -41,16 +42,61 @@ class AdnlPeerTable;
class AdnlNetworkManagerImpl : public AdnlNetworkManager { class AdnlNetworkManagerImpl : public AdnlNetworkManager {
public: public:
struct OutDesc { struct OutDesc {
td::IPAddress addr; td::uint16 port;
td::IPAddress proxy_addr;
std::shared_ptr<AdnlProxy> proxy; std::shared_ptr<AdnlProxy> proxy;
size_t socket_idx;
td::int64 out_seqno{0};
AdnlCategoryMask cat_mask{0};
bool is_proxy() const { bool is_proxy() const {
return proxy != nullptr; return proxy != nullptr;
} }
bool operator==(const OutDesc &with) const { bool operator==(const OutDesc &with) const {
return addr == with.addr && is_proxy() == with.is_proxy(); if (port != with.port) {
return false;
}
if (!is_proxy()) {
return !with.is_proxy();
}
if (!with.is_proxy()) {
return false;
}
return proxy_addr == with.proxy_addr && proxy->id() == with.proxy->id();
} }
}; };
struct InDesc {
td::uint16 port;
std::shared_ptr<AdnlProxy> proxy;
AdnlCategoryMask cat_mask;
AdnlReceivedMaskVersion received{};
OutDesc *out_desc = nullptr;
bool is_proxy() const {
return proxy != nullptr;
}
bool operator==(const InDesc &with) const {
if (port != with.port) {
return false;
}
if (!is_proxy()) {
return !with.is_proxy();
}
if (!with.is_proxy()) {
return false;
}
return proxy->id() == with.proxy->id();
}
};
struct UdpSocketDesc {
UdpSocketDesc(td::uint16 port, td::actor::ActorOwn<td::UdpServer> server) : port(port), server(std::move(server)) {
}
td::uint16 port;
td::actor::ActorOwn<td::UdpServer> server;
size_t in_desc{std::numeric_limits<size_t>::max()};
bool allow_proxy{false};
};
OutDesc *choose_out_iface(td::uint8 cat, td::uint32 priority);
AdnlNetworkManagerImpl(td::uint16 out_udp_port) : out_udp_port_(out_udp_port) { AdnlNetworkManagerImpl(td::uint16 out_udp_port) : out_udp_port_(out_udp_port) {
} }
@ -59,45 +105,60 @@ class AdnlNetworkManagerImpl : public AdnlNetworkManager {
callback_ = std::move(callback); callback_ = std::move(callback);
} }
void add_self_addr(td::IPAddress addr, td::uint32 priority) override { void alarm() override;
auto x = OutDesc{addr, nullptr}; void start_up() override {
auto &v = out_desc_[priority]; alarm_timestamp() = td::Timestamp::in(60.0);
for (auto &y : v) { }
if (x == y) {
void add_in_addr(InDesc desc, size_t socket_idx) {
for (size_t idx = 0; idx < in_desc_.size(); idx++) {
if (in_desc_[idx] == desc) {
in_desc_[idx].cat_mask |= desc.cat_mask;
return; return;
} }
} }
out_desc_[priority].push_back(std::move(x)); if (desc.is_proxy()) {
add_listening_udp_port(static_cast<td::uint16>(addr.get_port())); udp_sockets_[socket_idx].allow_proxy = true;
} proxy_addrs_[desc.proxy->id()] = in_desc_.size();
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override { } else {
auto x = OutDesc{addr, std::move(proxy)}; CHECK(udp_sockets_[socket_idx].in_desc == std::numeric_limits<size_t>::max());
auto &v = out_desc_[priority]; udp_sockets_[socket_idx].in_desc = in_desc_.size();
for (auto &y : v) {
if (x == y) {
return;
}
}
out_desc_[priority].push_back(std::move(x));
if (!udp_servers_.count(out_udp_port_)) {
add_listening_udp_port(out_udp_port_);
} }
in_desc_.push_back(std::move(desc));
} }
void add_self_addr(td::IPAddress addr, AdnlCategoryMask cat_mask, td::uint32 priority) override;
void add_proxy_addr(td::IPAddress addr, td::uint16 local_port, std::shared_ptr<AdnlProxy> proxy,
AdnlCategoryMask cat_mask, td::uint32 priority) override;
void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::uint32 priority, void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::uint32 priority,
td::BufferSlice data) override; td::BufferSlice data) override;
void add_listening_udp_port(td::uint16 port); void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) override {
void receive_udp_message(td::UdpMessage message); if (cat == 255) {
adnl_id_2_cat_.erase(id);
} else {
adnl_id_2_cat_[id] = cat;
}
}
size_t add_listening_udp_port(td::uint16 port);
void receive_udp_message(td::UdpMessage message, size_t idx);
void proxy_register(OutDesc &desc);
private: private:
std::unique_ptr<Callback> callback_; std::unique_ptr<Callback> callback_;
std::map<td::uint32, std::vector<OutDesc>> out_desc_; std::map<td::uint32, std::vector<OutDesc>> out_desc_;
std::vector<InDesc> in_desc_;
std::map<td::Bits256, size_t> proxy_addrs_;
td::uint64 received_messages_ = 0; td::uint64 received_messages_ = 0;
td::uint64 sent_messages_ = 0; td::uint64 sent_messages_ = 0;
std::map<td::uint16, td::actor::ActorOwn<td::UdpServer>> udp_servers_; std::vector<UdpSocketDesc> udp_sockets_;
std::map<td::uint16, size_t> port_2_socket_;
std::map<AdnlNodeIdShort, td::uint8> adnl_id_2_cat_;
td::uint16 out_udp_port_; td::uint16 out_udp_port_;
}; };

View file

@ -30,6 +30,7 @@
#include "utils.hpp" #include "utils.hpp"
#include "adnl-query.h" #include "adnl-query.h"
#include "adnl-ext-client.h" #include "adnl-ext-client.h"
#include "adnl-tunnel.h"
namespace ton { namespace ton {
@ -49,7 +50,7 @@ td::actor::ActorOwn<Adnl> Adnl::create(std::string db, td::actor::ActorId<keyrin
return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring)); return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring));
} }
void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data) { void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, AdnlCategoryMask cat_mask, td::BufferSlice data) {
if (data.size() < 32) { if (data.size() < 32) {
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size(); VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
return; return;
@ -60,14 +61,22 @@ void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data)
auto it = local_ids_.find(dst); auto it = local_ids_.find(dst);
if (it != local_ids_.end()) { if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::receive, addr, std::move(data)); if (!cat_mask.test(it->second.cat)) {
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->" << dst << "]: category mismatch";
return;
}
td::actor::send_closure(it->second.local_id, &AdnlLocalId::receive, addr, std::move(data));
return; return;
} }
AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()}; AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
auto it2 = channels_.find(dst_chan_id); auto it2 = channels_.find(dst_chan_id);
if (it2 != channels_.end()) { if (it2 != channels_.end()) {
td::actor::send_closure(it2->second, &AdnlChannel::receive, addr, std::move(data)); if (!cat_mask.test(it2->second.second)) {
VLOG(ADNL_WARNING) << this << ": dropping IN message to channel [?->" << dst << "]: category mismatch";
return;
}
td::actor::send_closure(it2->second.first, &AdnlChannel::receive, addr, std::move(data));
return; return;
} }
@ -109,7 +118,7 @@ void AdnlPeerTableImpl::receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket
<< "]: unknown dst (but how did we decrypt message?)"; << "]: unknown dst (but how did we decrypt message?)";
return; return;
} }
td::actor::send_closure(it->second, &AdnlPeer::receive_packet, dst, it2->second.second, it2->second.first.get(), td::actor::send_closure(it->second, &AdnlPeer::receive_packet, dst, it2->second.mode, it2->second.local_id.get(),
std::move(packet)); std::move(packet));
} }
@ -127,8 +136,8 @@ void AdnlPeerTableImpl::add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, Ad
} }
td::actor::send_closure(it->second, &AdnlPeer::update_id, std::move(id)); td::actor::send_closure(it->second, &AdnlPeer::update_id, std::move(id));
if (!addr_list.empty()) { if (!addr_list.empty()) {
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.second, td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.mode,
it2->second.first.get(), std::move(addr_list)); it2->second.local_id.get(), std::move(addr_list));
} }
} }
@ -152,7 +161,7 @@ void AdnlPeerTableImpl::send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst
return; return;
} }
td::actor::send_closure(it->second, &AdnlPeer::send_one_message, src, it2->second.second, it2->second.first.get(), td::actor::send_closure(it->second, &AdnlPeer::send_one_message, src, it2->second.mode, it2->second.local_id.get(),
OutboundAdnlMessage{std::move(message), flags}); OutboundAdnlMessage{std::move(message), flags});
} }
@ -185,23 +194,32 @@ void AdnlPeerTableImpl::send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std
return; return;
} }
td::actor::send_closure(it->second, &AdnlPeer::send_query, src, it2->second.second, it2->second.first.get(), name, td::actor::send_closure(it->second, &AdnlPeer::send_query, src, it2->second.mode, it2->second.local_id.get(), name,
std::move(promise), timeout, std::move(data), 0); std::move(promise), timeout, std::move(data), 0);
} }
void AdnlPeerTableImpl::add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode) { void AdnlPeerTableImpl::add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint8 cat, td::uint32 mode) {
auto a = id.compute_short_id(); auto a = id.compute_short_id();
VLOG(ADNL_INFO) << "adnl: adding local id " << a; VLOG(ADNL_INFO) << "adnl: adding local id " << a;
auto it = local_ids_.find(a); auto it = local_ids_.find(a);
if (it != local_ids_.end()) { if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::update_address_list, std::move(addr_list)); if (it->second.cat != cat) {
it->second.cat = cat;
if (!network_manager_.empty()) {
td::actor::send_closure(network_manager_, &AdnlNetworkManager::set_local_id_category, a, cat);
}
}
td::actor::send_closure(it->second.local_id, &AdnlLocalId::update_address_list, std::move(addr_list));
} else { } else {
local_ids_.emplace( local_ids_.emplace(
a, std::make_pair(td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list), mode, a, LocalIdInfo{td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list), mode,
actor_id(this), keyring_, dht_node_), actor_id(this), keyring_, dht_node_),
mode)); cat, mode});
if (!network_manager_.empty()) {
td::actor::send_closure(network_manager_, &AdnlNetworkManager::set_local_id_category, a, cat);
}
} }
} }
@ -215,14 +233,14 @@ void AdnlPeerTableImpl::subscribe(AdnlNodeIdShort dst, std::string prefix, std::
auto it = local_ids_.find(dst); auto it = local_ids_.find(dst);
LOG_CHECK(it != local_ids_.end()) << "dst=" << dst; LOG_CHECK(it != local_ids_.end()) << "dst=" << dst;
td::actor::send_closure(it->second.first, &AdnlLocalId::subscribe, prefix, std::move(callback)); td::actor::send_closure(it->second.local_id, &AdnlLocalId::subscribe, prefix, std::move(callback));
} }
void AdnlPeerTableImpl::unsubscribe(AdnlNodeIdShort dst, std::string prefix) { void AdnlPeerTableImpl::unsubscribe(AdnlNodeIdShort dst, std::string prefix) {
auto it = local_ids_.find(dst); auto it = local_ids_.find(dst);
if (it != local_ids_.end()) { if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::unsubscribe, prefix); td::actor::send_closure(it->second.local_id, &AdnlLocalId::unsubscribe, prefix);
} }
} }
@ -233,7 +251,7 @@ void AdnlPeerTableImpl::register_dht_node(td::actor::ActorId<dht::Dht> dht_node)
td::actor::send_closure(peer.second, &AdnlPeer::update_dht_node, dht_node_); td::actor::send_closure(peer.second, &AdnlPeer::update_dht_node, dht_node_);
} }
for (auto &local_id : local_ids_) { for (auto &local_id : local_ids_) {
td::actor::send_closure(local_id.second.first, &AdnlLocalId::update_dht_node, dht_node_); td::actor::send_closure(local_id.second.local_id, &AdnlLocalId::update_dht_node, dht_node_);
} }
} }
@ -242,8 +260,8 @@ void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkM
class Cb : public AdnlNetworkManager::Callback { class Cb : public AdnlNetworkManager::Callback {
public: public:
void receive_packet(td::IPAddress addr, td::BufferSlice data) override { void receive_packet(td::IPAddress addr, AdnlCategoryMask cat_mask, td::BufferSlice data) override {
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(data)); td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(cat_mask), std::move(data));
} }
Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) { Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) {
} }
@ -254,6 +272,10 @@ void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkM
auto cb = std::make_unique<Cb>(actor_id(this)); auto cb = std::make_unique<Cb>(actor_id(this));
td::actor::send_closure(network_manager_, &AdnlNetworkManager::install_callback, std::move(cb)); td::actor::send_closure(network_manager_, &AdnlNetworkManager::install_callback, std::move(cb));
for (auto &id : local_ids_) {
td::actor::send_closure(network_manager_, &AdnlNetworkManager::set_local_id_category, id.first, id.second.cat);
}
} }
void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) { void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) {
@ -262,7 +284,7 @@ void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddres
promise.set_error(td::Status::Error(ErrorCode::notready)); promise.set_error(td::Status::Error(ErrorCode::notready));
return; return;
} }
td::actor::send_closure(it->second.first, &AdnlLocalId::get_addr_list_async, std::move(promise)); td::actor::send_closure(it->second.local_id, &AdnlLocalId::get_addr_list_async, std::move(promise));
} }
void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) { void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) {
@ -271,11 +293,14 @@ void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode>
promise.set_error(td::Status::Error(ErrorCode::notready)); promise.set_error(td::Status::Error(ErrorCode::notready));
return; return;
} }
td::actor::send_closure(it->second.first, &AdnlLocalId::get_self_node, std::move(promise)); td::actor::send_closure(it->second.local_id, &AdnlLocalId::get_self_node, std::move(promise));
} }
void AdnlPeerTableImpl::register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) { void AdnlPeerTableImpl::register_channel(AdnlChannelIdShort id, AdnlNodeIdShort local_id,
auto success = channels_.emplace(id, channel).second; td::actor::ActorId<AdnlChannel> channel) {
auto it = local_ids_.find(local_id);
auto cat = (it != local_ids_.end()) ? it->second.cat : 255;
auto success = channels_.emplace(id, std::make_pair(channel, cat)).second;
CHECK(success); CHECK(success);
} }
@ -317,14 +342,14 @@ AdnlPeerTableImpl::AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<key
void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) { void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) {
auto it = local_ids_.find(dst); auto it = local_ids_.find(dst);
if (it != local_ids_.end()) { if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::deliver, src, std::move(data)); td::actor::send_closure(it->second.local_id, &AdnlLocalId::deliver, src, std::move(data));
} }
} }
void AdnlPeerTableImpl::deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data, void AdnlPeerTableImpl::deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) { td::Promise<td::BufferSlice> promise) {
auto it = local_ids_.find(dst); auto it = local_ids_.find(dst);
if (it != local_ids_.end()) { if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::deliver_query, src, std::move(data), std::move(promise)); td::actor::send_closure(it->second.local_id, &AdnlLocalId::deliver_query, src, std::move(data), std::move(promise));
} else { } else {
LOG(WARNING) << "deliver query: unknown dst " << dst; LOG(WARNING) << "deliver query: unknown dst " << dst;
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot deliver: unknown DST")); promise.set_error(td::Status::Error(ErrorCode::notready, "cannot deliver: unknown DST"));
@ -335,7 +360,7 @@ void AdnlPeerTableImpl::decrypt_message(AdnlNodeIdShort dst, td::BufferSlice dat
td::Promise<td::BufferSlice> promise) { td::Promise<td::BufferSlice> promise) {
auto it = local_ids_.find(dst); auto it = local_ids_.find(dst);
if (it != local_ids_.end()) { if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::decrypt_message, std::move(data), std::move(promise)); td::actor::send_closure(it->second.local_id, &AdnlLocalId::decrypt_message, std::move(data), std::move(promise));
} else { } else {
LOG(WARNING) << "decrypt message: unknown dst " << dst; LOG(WARNING) << "decrypt message: unknown dst " << dst;
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot decrypt: unknown DST")); promise.set_error(td::Status::Error(ErrorCode::notready, "cannot decrypt: unknown DST"));
@ -347,6 +372,10 @@ void AdnlPeerTableImpl::create_ext_server(std::vector<AdnlNodeIdShort> ids, std:
promise.set_value(AdnlExtServerCreator::create(actor_id(this), std::move(ids), std::move(ports))); promise.set_value(AdnlExtServerCreator::create(actor_id(this), std::move(ids), std::move(ports)));
} }
void AdnlPeerTableImpl::create_tunnel(AdnlNodeIdShort dst, td::uint32 size,
td::Promise<std::pair<td::actor::ActorOwn<AdnlTunnel>, AdnlAddress>> promise) {
}
} // namespace adnl } // namespace adnl
} // namespace ton } // namespace ton

View file

@ -89,11 +89,12 @@ class AdnlPeerTable : public Adnl {
virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0; virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0;
virtual void receive_packet(td::IPAddress addr, td::BufferSlice data) = 0; virtual void receive_packet(td::IPAddress addr, AdnlCategoryMask cat_mask, td::BufferSlice data) = 0;
virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0; virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0;
virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message, td::uint32 flags) = 0; virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message, td::uint32 flags) = 0;
virtual void register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) = 0; virtual void register_channel(AdnlChannelIdShort id, AdnlNodeIdShort local_id,
td::actor::ActorId<AdnlChannel> channel) = 0;
virtual void unregister_channel(AdnlChannelIdShort id) = 0; virtual void unregister_channel(AdnlChannelIdShort id) = 0;
virtual void add_static_node(AdnlNode node) = 0; virtual void add_static_node(AdnlNode node) = 0;

View file

@ -43,7 +43,7 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override; void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override;
void add_static_nodes_from_config(AdnlNodesList nodes) override; void add_static_nodes_from_config(AdnlNodesList nodes) override;
void receive_packet(td::IPAddress addr, td::BufferSlice data) override; void receive_packet(td::IPAddress addr, AdnlCategoryMask cat_mask, td::BufferSlice data) override;
void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override; void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override;
void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message, td::uint32 flags) override; void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message, td::uint32 flags) override;
void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override { void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override {
@ -64,7 +64,7 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
td::Timestamp timeout, td::BufferSlice data, td::uint64 max_answer_size) override { td::Timestamp timeout, td::BufferSlice data, td::uint64 max_answer_size) override {
send_query(src, dst, name, std::move(promise), timeout, std::move(data)); send_query(src, dst, name, std::move(promise), timeout, std::move(data));
} }
void add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode) override; void add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint8 cat, td::uint32 mode) override;
void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) override; void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) override;
void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) override; void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) override;
void unsubscribe(AdnlNodeIdShort dst, std::string prefix) override; void unsubscribe(AdnlNodeIdShort dst, std::string prefix) override;
@ -73,7 +73,8 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
void get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) override; void get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) override;
void get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) override; void get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) override;
void start_up() override; void start_up() override;
void register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) override; void register_channel(AdnlChannelIdShort id, AdnlNodeIdShort local_id,
td::actor::ActorId<AdnlChannel> channel) override;
void unregister_channel(AdnlChannelIdShort id) override; void unregister_channel(AdnlChannelIdShort id) override;
void write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node, void write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
@ -99,12 +100,20 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports, void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) override; td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) override;
void create_tunnel(AdnlNodeIdShort dst, td::uint32 size,
td::Promise<std::pair<td::actor::ActorOwn<AdnlTunnel>, AdnlAddress>> promise) override;
struct PrintId {}; struct PrintId {};
PrintId print_id() const { PrintId print_id() const {
return PrintId{}; return PrintId{};
} }
private: private:
struct LocalIdInfo {
td::actor::ActorOwn<AdnlLocalId> local_id;
td::uint8 cat;
td::uint32 mode;
};
td::actor::ActorId<keyring::Keyring> keyring_; td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<AdnlNetworkManager> network_manager_; td::actor::ActorId<AdnlNetworkManager> network_manager_;
@ -114,13 +123,14 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
void deliver_one_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message); void deliver_one_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message);
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeer>> peers_; std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeer>> peers_;
std::map<AdnlNodeIdShort, std::pair<td::actor::ActorOwn<AdnlLocalId>, td::uint32>> local_ids_; std::map<AdnlNodeIdShort, LocalIdInfo> local_ids_;
std::map<AdnlChannelIdShort, td::actor::ActorId<AdnlChannel>> channels_; std::map<AdnlChannelIdShort, std::pair<td::actor::ActorId<AdnlChannel>, td::uint8>> channels_;
td::actor::ActorOwn<AdnlDb> db_; td::actor::ActorOwn<AdnlDb> db_;
td::actor::ActorOwn<AdnlExtServer> ext_server_; td::actor::ActorOwn<AdnlExtServer> ext_server_;
AdnlNodeIdShort proxy_addr_;
//std::map<td::uint64, td::actor::ActorId<AdnlQuery>> out_queries_; //std::map<td::uint64, td::actor::ActorId<AdnlQuery>> out_queries_;
//td::uint64 last_query_id_ = 1; //td::uint64 last_query_id_ = 1;
}; };

View file

@ -482,7 +482,8 @@ void AdnlPeerPairImpl::create_channel(pubkeys::Ed25519 pub, td::uint32 date) {
channel_ = R.move_as_ok(); channel_ = R.move_as_ok();
channel_inited_ = true; channel_inited_ = true;
td::actor::send_closure_later(peer_table_, &AdnlPeerTable::register_channel, channel_in_id_, channel_.get()); td::actor::send_closure_later(peer_table_, &AdnlPeerTable::register_channel, channel_in_id_, local_id_,
channel_.get());
} else { } else {
VLOG(ADNL_WARNING) << this << ": failed to create channel: " << R.move_as_error(); VLOG(ADNL_WARNING) << this << ": failed to create channel: " << R.move_as_error();
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "td/actor/actor.h" #include "td/actor/actor.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
@ -170,7 +170,10 @@ int main(int argc, char *argv[]) {
network_manager = ton::adnl::AdnlNetworkManager::create(static_cast<td::uint16>(addr.get_port())); network_manager = ton::adnl::AdnlNetworkManager::create(static_cast<td::uint16>(addr.get_port()));
td::actor::send_closure(network_manager, &ton::adnl::AdnlNetworkManager::add_self_addr, addr, 0); ton::adnl::AdnlCategoryMask cat_mask;
cat_mask[0] = true;
td::actor::send_closure(network_manager, &ton::adnl::AdnlNetworkManager::add_self_addr, addr, std::move(cat_mask),
0);
auto tladdr = ton::create_tl_object<ton::ton_api::adnl_address_udp>(addr.get_ipv4(), addr.get_port()); auto tladdr = ton::create_tl_object<ton::ton_api::adnl_address_udp>(addr.get_ipv4(), addr.get_port());
auto addr_vec = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>(); auto addr_vec = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>();
@ -179,7 +182,8 @@ int main(int argc, char *argv[]) {
std::move(addr_vec), ton::adnl::Adnl::adnl_start_time(), ton::adnl::Adnl::adnl_start_time(), 0, 2000000000); std::move(addr_vec), ton::adnl::Adnl::adnl_start_time(), ton::adnl::Adnl::adnl_start_time(), 0, 2000000000);
auto addrlist = ton::adnl::AdnlAddressList::create(tladdrlist).move_as_ok(); auto addrlist = ton::adnl::AdnlAddressList::create(tladdrlist).move_as_ok();
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, std::move(addrlist)); td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, std::move(addrlist),
static_cast<td::uint8>(0));
td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}, td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{pub.compute_short_id()},
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::adnl_ping::ID), ton::adnl::Adnl::int_to_bytestring(ton::ton_api::adnl_ping::ID),
std::make_unique<ton::adnl::Callback>()); std::make_unique<ton::adnl::Callback>());

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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 "adnl-proxy-types.hpp" #include "adnl-proxy-types.hpp"
#include "tl-utils/tl-utils.hpp" #include "tl-utils/tl-utils.hpp"
@ -27,59 +27,84 @@ namespace ton {
namespace adnl { namespace adnl {
td::Result<AdnlProxy::Packet> AdnlProxyNone::decrypt(td::BufferSlice packet) const {
if (packet.size() < 32) {
return td::Status::Error(ErrorCode::protoviolation, "bad signature");
}
if (packet.as_slice().truncate(32) != id_.as_slice()) {
return td::Status::Error(ErrorCode::protoviolation, "bad proxy id");
}
Packet p{};
p.flags = 0;
p.ip = 0;
p.port = 0;
p.adnl_start_time = 0;
p.seqno = 0;
p.date = 0;
p.data = std::move(packet);
p.data.confirm_read(32);
return std::move(p);
}
td::BufferSlice AdnlProxyFast::encrypt(Packet packet) const { td::BufferSlice AdnlProxyFast::encrypt(Packet packet) const {
auto date = static_cast<td::uint32>(td::Clocks::system()); if (!packet.date) {
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>( packet.date = static_cast<td::int32>(td::Clocks::system());
packet.ip, packet.port, date, sha256_bits256(packet.data.as_slice()), shared_secret_); packet.flags |= 8;
}
auto obj = create_serialize_tl_object<ton_api::adnl_proxyToFast>(packet.ip, packet.port, date, signature); auto obj = create_tl_object<ton_api::adnl_proxyPacketHeader>(id_, packet.flags, packet.ip, packet.port,
td::BufferSlice res{32 + obj.size() + packet.data.size()}; packet.adnl_start_time, packet.seqno, packet.date,
auto S = res.as_slice(); td::sha256_bits256(packet.data.as_slice()));
S.copy_from(td::Bits256::zero().as_slice()); char data[64];
td::MutableSlice S{data, 64};
S.copy_from(get_tl_object_sha256(obj).as_slice());
S.remove_prefix(32); S.remove_prefix(32);
S.copy_from(obj.as_slice()); S.copy_from(shared_secret_.as_slice());
S.remove_prefix(obj.size());
S.copy_from(packet.data.as_slice());
return res; obj->signature_ = td::sha256_bits256(td::Slice(data, 64));
return serialize_tl_object(obj, false, std::move(packet.data));
} }
td::Result<AdnlProxy::Packet> AdnlProxyFast::decrypt(td::BufferSlice packet) const { td::Result<AdnlProxy::Packet> AdnlProxyFast::decrypt(td::BufferSlice packet) const {
if (packet.size() < 36) { TRY_RESULT(obj, fetch_tl_prefix<ton_api::adnl_proxyPacketHeader>(packet, false));
return td::Status::Error(ErrorCode::protoviolation, "too short packet"); if (obj->proxy_id_ != id_) {
return td::Status::Error(ErrorCode::protoviolation, "bad proxy id");
} }
td::Bits256 v; auto signature = std::move(obj->signature_);
v.as_slice().copy_from(packet.as_slice().truncate(32)); obj->signature_ = td::sha256_bits256(packet.as_slice());
if (!v.is_zero()) {
return td::Status::Error(ErrorCode::protoviolation, "non-zero DST");
}
packet.confirm_read(32);
TRY_RESULT(R, fetch_tl_prefix<ton_api::adnl_proxyToFast>(packet, true)); char data[64];
td::MutableSlice S{data, 64};
S.copy_from(get_tl_object_sha256(obj).as_slice());
S.remove_prefix(32);
S.copy_from(shared_secret_.as_slice());
if (R->date_ < td::Clocks::system() - 8) { if (td::sha256_bits256(td::Slice(data, 64)) != signature) {
return td::Status::Error(ErrorCode::protoviolation, "too old date");
}
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>(
R->ip_, R->port_, R->date_, sha256_bits256(packet.as_slice()), shared_secret_);
if (signature != R->signature_) {
return td::Status::Error(ErrorCode::protoviolation, "bad signature"); return td::Status::Error(ErrorCode::protoviolation, "bad signature");
} }
return Packet{static_cast<td::uint32>(R->ip_), static_cast<td::uint16>(R->port_), std::move(packet)}; Packet p;
p.flags = obj->flags_;
p.ip = (p.flags & 1) ? obj->ip_ : 0;
p.port = (p.flags & 1) ? static_cast<td::uint16>(obj->port_) : 0;
p.adnl_start_time = (p.flags & 2) ? obj->adnl_start_time_ : 0;
p.seqno = (p.flags & 4) ? obj->seqno_ : 0;
p.date = (p.flags & 8) ? obj->date_ : 0;
p.data = std::move(packet);
return std::move(p);
} }
td::Result<std::shared_ptr<AdnlProxy>> AdnlProxy::create(const ton_api::adnl_Proxy &proxy_type) { td::Result<std::shared_ptr<AdnlProxy>> AdnlProxy::create(const ton_api::adnl_Proxy &proxy_type) {
std::shared_ptr<AdnlProxy> R; std::shared_ptr<AdnlProxy> R;
ton_api::downcast_call( ton_api::downcast_call(
const_cast<ton_api::adnl_Proxy &>(proxy_type), const_cast<ton_api::adnl_Proxy &>(proxy_type),
td::overloaded([&](const ton_api::adnl_proxy_none &x) { R = std::make_shared<AdnlProxyNone>(); }, td::overloaded([&](const ton_api::adnl_proxy_none &x) { R = std::make_shared<AdnlProxyNone>(x.id_); },
[&](const ton_api::adnl_proxy_fast &x) { [&](const ton_api::adnl_proxy_fast &x) {
R = std::make_shared<AdnlProxyFast>(x.shared_secret_.as_slice()); R = std::make_shared<AdnlProxyFast>(x.id_, x.shared_secret_.as_slice());
})); }));
return R; return std::move(R);
} }
} // namespace adnl } // namespace adnl

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -28,14 +28,19 @@ namespace adnl {
class AdnlProxy { class AdnlProxy {
public: public:
struct Packet { struct Packet {
td::uint32 flags;
td::uint32 ip; td::uint32 ip;
td::uint16 port; td::uint16 port;
td::int32 adnl_start_time;
td::int64 seqno;
td::int32 date{0};
td::BufferSlice data; td::BufferSlice data;
}; };
virtual ~AdnlProxy() = default; virtual ~AdnlProxy() = default;
virtual td::BufferSlice encrypt(Packet packet) const = 0; virtual td::BufferSlice encrypt(Packet packet) const = 0;
virtual td::Result<Packet> decrypt(td::BufferSlice packet) const = 0; virtual td::Result<Packet> decrypt(td::BufferSlice packet) const = 0;
virtual tl_object_ptr<ton_api::adnl_Proxy> tl() const = 0; virtual tl_object_ptr<ton_api::adnl_Proxy> tl() const = 0;
virtual const td::Bits256 &id() const = 0;
static td::Result<std::shared_ptr<AdnlProxy>> create(const ton_api::adnl_Proxy &proxy_type); static td::Result<std::shared_ptr<AdnlProxy>> create(const ton_api::adnl_Proxy &proxy_type);
}; };

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -28,31 +28,42 @@ namespace adnl {
class AdnlProxyNone : public AdnlProxy { class AdnlProxyNone : public AdnlProxy {
public: public:
AdnlProxyNone() { AdnlProxyNone(td::Bits256 id) : id_(id) {
} }
td::BufferSlice encrypt(Packet packet) const override { td::BufferSlice encrypt(Packet packet) const override {
return std::move(packet.data); td::BufferSlice d{packet.data.size() + 32};
} d.as_slice().copy_from(id_.as_slice());
td::Result<Packet> decrypt(td::BufferSlice packet) const override { d.as_slice().remove_prefix(32).copy_from(packet.data.as_slice());
return Packet{0, 0, std::move(packet)}; return d;
} }
td::Result<Packet> decrypt(td::BufferSlice packet) const override;
tl_object_ptr<ton_api::adnl_Proxy> tl() const override { tl_object_ptr<ton_api::adnl_Proxy> tl() const override {
return create_tl_object<ton_api::adnl_proxy_none>(); return create_tl_object<ton_api::adnl_proxy_none>(id_);
} }
const td::Bits256 &id() const override {
return id_;
}
private:
td::Bits256 id_;
}; };
class AdnlProxyFast : public AdnlProxy { class AdnlProxyFast : public AdnlProxy {
public: public:
AdnlProxyFast(td::Slice shared_secret) AdnlProxyFast(td::Bits256 id, td::Slice shared_secret)
: shared_secret_(sha256_bits256(shared_secret)), shared_secret_raw_(shared_secret) { : id_(id), shared_secret_(sha256_bits256(shared_secret)), shared_secret_raw_(shared_secret) {
} }
td::BufferSlice encrypt(Packet packet) const override; td::BufferSlice encrypt(Packet packet) const override;
td::Result<Packet> decrypt(td::BufferSlice packet) const override; td::Result<Packet> decrypt(td::BufferSlice packet) const override;
tl_object_ptr<ton_api::adnl_Proxy> tl() const override { tl_object_ptr<ton_api::adnl_Proxy> tl() const override {
return create_tl_object<ton_api::adnl_proxy_fast>(shared_secret_raw_.clone_as_buffer_slice()); return create_tl_object<ton_api::adnl_proxy_fast>(id_, shared_secret_raw_.clone_as_buffer_slice());
}
const td::Bits256 &id() const override {
return id_;
} }
private: private:
td::Bits256 id_;
td::Bits256 shared_secret_; td::Bits256 shared_secret_;
td::SharedSlice shared_secret_raw_; td::SharedSlice shared_secret_raw_;
}; };

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "td/actor/actor.h" #include "td/actor/actor.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
@ -35,11 +35,13 @@
#include "td/utils/port/path.h" #include "td/utils/port/path.h"
#include "td/utils/port/user.h" #include "td/utils/port/user.h"
#include "td/utils/filesystem.h" #include "td/utils/filesystem.h"
#include "td/utils/overloaded.h"
#include "common/checksum.h" #include "common/checksum.h"
#include "common/errorcode.h" #include "common/errorcode.h"
#include "tl-utils/tl-utils.hpp" #include "tl-utils/tl-utils.hpp"
#include "auto/tl/ton_api_json.h" #include "auto/tl/ton_api_json.h"
#include "adnl-proxy-types.h" #include "adnl-proxy-types.h"
#include "adnl-received-mask.h"
#include <map> #include <map>
#if TD_DARWIN || TD_LINUX #if TD_DARWIN || TD_LINUX
@ -50,12 +52,19 @@ namespace ton {
namespace adnl { namespace adnl {
namespace {
td::int32 start_time() {
static td::int32 t = static_cast<td::int32>(td::Clocks::system());
return t;
}
} // namespace
class Receiver : public td::actor::Actor { class Receiver : public td::actor::Actor {
public: public:
void start_up() override; void start_up() override;
void receive_common(td::BufferSlice data); void receive_common(td::IPAddress addr, td::BufferSlice data);
void receive_from_client(td::BufferSlice data); void receive_from_client(td::IPAddress addr, td::BufferSlice data);
void receive_to_client(td::BufferSlice data); void receive_to_client(td::IPAddress addr, td::BufferSlice data);
Receiver(td::uint16 in_port, td::uint16 out_port, std::shared_ptr<AdnlProxy> proxy, td::IPAddress client_addr) Receiver(td::uint16 in_port, td::uint16 out_port, std::shared_ptr<AdnlProxy> proxy, td::IPAddress client_addr)
: in_port_(in_port), out_port_(out_port), proxy_(std::move(proxy)), addr_(client_addr) { : in_port_(in_port), out_port_(out_port), proxy_(std::move(proxy)), addr_(client_addr) {
@ -68,6 +77,10 @@ class Receiver : public td::actor::Actor {
td::IPAddress addr_; td::IPAddress addr_;
td::actor::ActorOwn<td::UdpServer> out_udp_server_; td::actor::ActorOwn<td::UdpServer> out_udp_server_;
td::actor::ActorOwn<td::UdpServer> in_udp_server_; td::actor::ActorOwn<td::UdpServer> in_udp_server_;
td::int32 client_start_time_{0};
td::uint64 out_seqno_{0};
AdnlReceivedMaskVersion received_;
}; };
void Receiver::start_up() { void Receiver::start_up() {
@ -81,15 +94,18 @@ void Receiver::start_up() {
const td::uint32 mode_; const td::uint32 mode_;
void on_udp_message(td::UdpMessage udp_message) override { void on_udp_message(td::UdpMessage udp_message) override {
if (udp_message.error.is_error()) { if (udp_message.error.is_error()) {
LOG(DEBUG) << udp_message.error; LOG(INFO) << "receifed udp message with error: " << udp_message.error;
return; return;
} }
if (mode_ == 0) { if (mode_ == 0) {
td::actor::send_closure_later(manager_, &Receiver::receive_common, std::move(udp_message.data)); td::actor::send_closure_later(manager_, &Receiver::receive_common, udp_message.address,
std::move(udp_message.data));
} else if (mode_ == 1) { } else if (mode_ == 1) {
td::actor::send_closure_later(manager_, &Receiver::receive_from_client, std::move(udp_message.data)); td::actor::send_closure_later(manager_, &Receiver::receive_from_client, udp_message.address,
std::move(udp_message.data));
} else { } else {
td::actor::send_closure_later(manager_, &Receiver::receive_to_client, std::move(udp_message.data)); td::actor::send_closure_later(manager_, &Receiver::receive_to_client, udp_message.address,
std::move(udp_message.data));
} }
} }
}; };
@ -108,46 +124,152 @@ void Receiver::start_up() {
} }
} }
void Receiver::receive_common(td::BufferSlice data) { void Receiver::receive_common(td::IPAddress addr, td::BufferSlice data) {
if (data.size() <= 32) { if (data.size() <= 32) {
LOG(INFO) << "dropping too short packet: size=" << data.size();
return; return;
} }
td::Bits256 id; if (proxy_->id().as_slice() == data.as_slice().truncate(32)) {
id.as_slice().copy_from(data.as_slice().truncate(32)); receive_from_client(addr, std::move(data));
if (id.is_zero()) {
receive_from_client(std::move(data));
} else { } else {
receive_to_client(std::move(data)); receive_to_client(addr, std::move(data));
} }
} }
void Receiver::receive_from_client(td::BufferSlice data) { void Receiver::receive_from_client(td::IPAddress addr, td::BufferSlice data) {
auto F = proxy_->decrypt(std::move(data)); auto F = proxy_->decrypt(std::move(data));
if (F.is_error()) { if (F.is_error()) {
LOG(INFO) << "proxy: failed to decrypt message from client: " << F.move_as_error();
return; return;
} }
auto f = F.move_as_ok(); auto f = F.move_as_ok();
if (f.flags & (1 << 16)) {
LOG(INFO) << "proxy: dropping message from client: flag 16 is set";
return;
}
if (f.date) {
if (f.date + 60.0 < td::Clocks::system() || f.date - 60.0 > td::Clocks::system()) {
LOG(INFO) << "proxy: dropping message from client: date mismatch";
return;
}
}
if ((f.flags & 6) == 6) {
if (received_.packet_is_delivered(f.adnl_start_time, f.seqno)) {
LOG(INFO) << "proxy: dropping message from client: duplicate packet (or old seqno/start_time)";
return;
}
received_.deliver_packet(f.adnl_start_time, f.seqno);
}
if (f.flags & (1 << 17)) {
auto F = fetch_tl_object<ton_api::adnl_ProxyControlPacket>(std::move(f.data), true);
if (F.is_error()) {
LOG(INFO) << this << ": dropping proxy packet: bad control packet: " << F.move_as_error();
return;
}
ton_api::downcast_call(*F.move_as_ok().get(),
td::overloaded(
[&](const ton_api::adnl_proxyControlPacketPing &f) {
auto data = create_serialize_tl_object<ton_api::adnl_proxyControlPacketPong>(f.id_);
AdnlProxy::Packet p;
p.flags = 6 | (1 << 16) | (1 << 17);
if (addr.is_valid() && addr.is_ipv4()) {
p.flags |= 1;
p.ip = addr.get_ipv4();
p.port = static_cast<td::uint16>(addr.get_port());
} else {
p.ip = 0;
p.port = 0;
}
p.data = std::move(data);
p.adnl_start_time = start_time();
p.seqno = out_seqno_;
p.data = std::move(data);
auto enc = proxy_->encrypt(std::move(p));
td::UdpMessage M;
M.address = addr;
M.data = std::move(enc);
td::actor::send_closure(
in_udp_server_.empty() ? out_udp_server_.get() : in_udp_server_.get(),
&td::UdpServer::send, std::move(M));
},
[&](const ton_api::adnl_proxyControlPacketPong &f) {},
[&](const ton_api::adnl_proxyControlPacketRegister &f) {
if (f.ip_ == 0 && f.port_ == 0) {
if (addr.is_valid() && addr.is_ipv4()) {
addr_ = addr;
}
} else {
td::IPAddress a;
auto S = a.init_host_port(td::IPAddress::ipv4_to_str(f.ip_), f.port_);
if (S.is_ok()) {
addr_ = a;
} else {
LOG(INFO) << "failed to init remote addr: " << S.move_as_error();
}
}
}));
return;
}
if (!(f.flags & 1)) {
LOG(INFO) << this << ": dropping proxy packet: no destination";
return;
}
td::IPAddress a; td::IPAddress a;
if (a.init_ipv4_port(td::IPAddress::ipv4_to_str(f.ip), f.port).is_error()) { if (a.init_ipv4_port(td::IPAddress::ipv4_to_str(f.ip), f.port).is_error()) {
LOG(INFO) << this << ": dropping proxy packet: invalid destination";
return;
}
if (!a.is_valid()) {
LOG(INFO) << this << ": dropping proxy packet: invalid destination";
return; return;
} }
td::UdpMessage M; td::UdpMessage M;
M.address = a; M.address = a;
M.data = std::move(f.data); M.data = std::move(f.data);
LOG(DEBUG) << this << ": proxying DOWN packet of length " << M.data.size() << " to " << a;
td::actor::send_closure(out_udp_server_.empty() ? in_udp_server_.get() : out_udp_server_.get(), &td::UdpServer::send, td::actor::send_closure(out_udp_server_.empty() ? in_udp_server_.get() : out_udp_server_.get(), &td::UdpServer::send,
std::move(M)); std::move(M));
} }
void Receiver::receive_to_client(td::BufferSlice data) { void Receiver::receive_to_client(td::IPAddress addr, td::BufferSlice data) {
LOG(DEBUG) << "proxying to " << addr_; LOG(DEBUG) << "proxying to " << addr_;
if (!addr_.is_valid() || !addr_.is_ipv4() || !addr_.get_ipv4()) {
LOG(INFO) << this << ": dropping external packet: client not inited";
return;
}
AdnlProxy::Packet p;
p.flags = (1 << 16);
if (addr.is_valid() && addr.is_ipv4()) {
p.flags |= 1;
p.ip = addr.get_ipv4();
p.port = static_cast<td::uint16>(addr.get_port());
} else {
p.ip = 0;
p.port = 0;
}
p.flags |= 2;
p.adnl_start_time = start_time();
p.flags |= 4;
p.seqno = ++out_seqno_;
p.data = std::move(data);
LOG(DEBUG) << this << ": proxying UP packet of length " << p.data.size() << " to " << addr_;
td::UdpMessage M; td::UdpMessage M;
M.address = addr_; M.address = addr_;
M.data = std::move(data); M.data = proxy_->encrypt(std::move(p));
td::actor::send_closure(in_udp_server_.empty() ? out_udp_server_.get() : in_udp_server_.get(), &td::UdpServer::send, td::actor::send_closure(in_udp_server_.empty() ? out_udp_server_.get() : in_udp_server_.get(), &td::UdpServer::send,
std::move(M)); std::move(M));
@ -204,7 +326,7 @@ int main(int argc, char *argv[]) {
}); });
p.add_option('l', "logname", "log to file", [&](td::Slice fname) { p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto F = std::make_unique<td::FileLog>(); auto F = std::make_unique<td::FileLog>();
TRY_STATUS(F->init(fname.str(), std::numeric_limits<td::uint64>::max(), true)); TRY_STATUS(F->init(fname.str(), std::numeric_limits<td::int64>::max(), true));
logger_ = std::move(F); logger_ = std::move(F);
td::log_interface = logger_.get(); td::log_interface = logger_.get();
return td::Status::OK(); return td::Status::OK();
@ -248,7 +370,9 @@ int main(int argc, char *argv[]) {
} }
TRY_RESULT(proxy, ton::adnl::AdnlProxy::create(*y->proxy_type_.get())); TRY_RESULT(proxy, ton::adnl::AdnlProxy::create(*y->proxy_type_.get()));
td::IPAddress a; td::IPAddress a;
a.init_ipv4_port(td::IPAddress::ipv4_to_str(y->dst_ip_), static_cast<td::uint16>(y->dst_port_)).ensure(); if (y->dst_ip_ || y->dst_port_) {
a.init_ipv4_port(td::IPAddress::ipv4_to_str(y->dst_ip_), static_cast<td::uint16>(y->dst_port_)).ensure();
}
scheduler.run_in_context([&] { scheduler.run_in_context([&] {
x.push_back(td::actor::create_actor<ton::adnl::Receiver>("adnl-proxy", in_port, out_port, std::move(proxy), a)); x.push_back(td::actor::create_actor<ton::adnl::Receiver>("adnl-proxy", in_port, out_port, std::move(proxy), a));

84
adnl/adnl-received-mask.h Normal file
View file

@ -0,0 +1,84 @@
#pragma once
#include "td/utils/int_types.h"
#include "td/utils/logging.h"
namespace ton {
namespace adnl {
class AdnlReceivedMask {
public:
void reset() {
seqno_ = 0;
mask_ = 0;
}
bool packet_is_delivered(td::int64 seqno) const {
if (seqno <= 0) {
return false;
}
if (seqno + 64 <= seqno_) {
return true;
}
if (seqno > seqno_) {
return false;
}
return mask_ & (1ull << (seqno_ - seqno));
}
void deliver_packet(td::int64 seqno) {
CHECK(!packet_is_delivered(seqno));
CHECK(seqno > 0);
if (seqno <= seqno_) {
mask_ |= (1ull << (seqno_ - seqno));
} else {
auto old = seqno_;
seqno_ = seqno;
if (seqno_ - old >= 64) {
mask_ = 1;
} else {
mask_ = mask_ << (seqno_ - old);
mask_ |= 1;
}
}
}
private:
td::int64 seqno_{0};
td::uint64 mask_{0};
};
class AdnlReceivedMaskVersion {
public:
bool packet_is_delivered(td::int32 utime, td::uint64 seqno) {
if (utime < utime_) {
return true;
} else if (utime == utime_) {
return mask_.packet_is_delivered(seqno);
} else {
return false;
}
}
void deliver_packet(td::int32 utime, td::uint64 seqno) {
CHECK(utime >= utime_);
if (utime == utime_) {
mask_.deliver_packet(seqno);
} else {
utime_ = utime;
mask_.reset();
mask_.deliver_packet(seqno);
}
}
void reset() {
mask_.reset();
utime_ = 0;
}
private:
AdnlReceivedMask mask_;
td::int32 utime_{0};
};
} // namespace adnl
} // namespace ton

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -34,9 +34,10 @@ class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
callback_ = std::move(callback); callback_ = std::move(callback);
} }
void add_self_addr(td::IPAddress addr, td::uint32 priority) override { void add_self_addr(td::IPAddress addr, AdnlCategoryMask cat_mask, td::uint32 priority) override {
} }
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override { void add_proxy_addr(td::IPAddress addr, td::uint16 local_port, std::shared_ptr<AdnlProxy> proxy,
AdnlCategoryMask cat_mask, td::uint32 priority) override {
} }
void send_udp_packet(ton::adnl::AdnlNodeIdShort src_id, ton::adnl::AdnlNodeIdShort dst_id, td::IPAddress dst_addr, void send_udp_packet(ton::adnl::AdnlNodeIdShort src_id, ton::adnl::AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
td::uint32 priority, td::BufferSlice data) override { td::uint32 priority, td::BufferSlice data) override {
@ -48,7 +49,9 @@ class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
return; return;
} }
CHECK(callback_); CHECK(callback_);
callback_->receive_packet(dst_addr, std::move(data)); AdnlCategoryMask m;
m[0] = true;
callback_->receive_packet(dst_addr, std::move(m), std::move(data));
} }
void add_node_id(AdnlNodeIdShort id, bool allow_send, bool allow_receive) { void add_node_id(AdnlNodeIdShort id, bool allow_send, bool allow_receive) {
@ -68,6 +71,8 @@ class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
CHECK(p >= 0 && p <= 1); CHECK(p >= 0 && p <= 1);
loss_probability_ = p; loss_probability_ = p;
} }
void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) override {
}
TestLoopbackNetworkManager() { TestLoopbackNetworkManager() {
} }

97
adnl/adnl-tunnel.cpp Normal file
View file

@ -0,0 +1,97 @@
#include "adnl-tunnel.h"
#include "adnl-peer-table.h"
namespace ton {
namespace adnl {
void AdnlInboundTunnelEndpoint::receive_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice datagram) {
receive_packet_cont(src, src_addr, std::move(datagram), 0);
}
void AdnlInboundTunnelEndpoint::receive_packet_cont(AdnlNodeIdShort src, td::IPAddress src_addr,
td::BufferSlice datagram, size_t idx) {
if (datagram.size() <= 32) {
VLOG(ADNL_INFO) << "dropping too short datagram";
return;
}
if (datagram.as_slice().truncate(32) != decrypt_via_[idx].as_slice()) {
VLOG(ADNL_INFO) << "invalid tunnel midpoint";
return;
}
datagram.confirm_read(32);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), src, src_addr, idx](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
VLOG(ADNL_INFO) << "dropping tunnel packet: failed to decrypt: " << R.move_as_error();
return;
} else {
td::actor::send_closure(SelfId, &AdnlInboundTunnelEndpoint::decrypted_packet, src, src_addr, R.move_as_ok(), idx);
}
});
td::actor::send_closure(keyring_, &keyring::Keyring::decrypt_message, decrypt_via_[idx], std::move(datagram),
std::move(P));
}
void AdnlInboundTunnelEndpoint::decrypted_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice data,
size_t idx) {
if (idx == decrypt_via_.size() - 1) {
td::actor::send_closure(adnl_, &AdnlPeerTable::receive_packet, src_addr, std::move(data));
return;
}
auto F = fetch_tl_object<ton_api::adnl_tunnelPacketContents>(std::move(data), true);
if (F.is_error()) {
VLOG(ADNL_INFO) << "dropping tunnel packet: failed to fetch: " << F.move_as_error();
return;
}
auto packet = F.move_as_ok();
td::IPAddress addr;
if (packet->flags_ & 1) {
addr.init_host_port(td::IPAddress::ipv4_to_str(packet->from_ip_), packet->from_port_).ignore();
}
if (packet->flags_ & 2) {
receive_packet_cont(src, addr, std::move(packet->message_), idx + 1);
}
}
void AdnlInboundTunnelMidpoint::start_up() {
encrypt_key_hash_ = encrypt_via_.compute_short_id();
auto R = encrypt_via_.create_encryptor();
if (R.is_error()) {
return;
}
encryptor_ = R.move_as_ok();
}
void AdnlInboundTunnelMidpoint::receive_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice datagram) {
if (!encryptor_) {
return;
}
auto obj = create_tl_object<ton_api::adnl_tunnelPacketContents>();
obj->flags_ = 2;
obj->message_ = std::move(datagram);
if (src_addr.is_valid() && src_addr.is_ipv4()) {
obj->flags_ |= 1;
obj->from_ip_ = src_addr.get_ipv4();
obj->from_port_ = src_addr.get_port();
}
auto packet = serialize_tl_object(std::move(obj), true);
auto dataR = encryptor_->encrypt(packet.as_slice());
if (dataR.is_error()) {
return;
}
auto data = dataR.move_as_ok();
td::BufferSlice enc{data.size() + 32};
auto S = enc.as_slice();
S.copy_from(encrypt_key_hash_.as_slice());
S.remove_prefix(32);
S.copy_from(data.as_slice());
td::actor::send_closure(adnl_, &Adnl::send_message_ex, proxy_as_, proxy_to_, std::move(enc),
Adnl::SendFlags::direct_only);
}
} // namespace adnl
} // namespace ton

73
adnl/adnl-tunnel.h Normal file
View file

@ -0,0 +1,73 @@
#pragma once
#include "adnl.h"
#include "adnl-peer-table.h"
#include "keys/encryptor.h"
#include <map>
namespace ton {
namespace adnl {
class AdnlInboundTunnelPoint : public AdnlTunnel {
public:
virtual ~AdnlInboundTunnelPoint() = default;
virtual void receive_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice datagram) = 0;
};
class AdnlInboundTunnelEndpoint : public AdnlInboundTunnelPoint {
public:
AdnlInboundTunnelEndpoint(PublicKeyHash pubkey_hash, std::vector<PublicKeyHash> decrypt_via, AdnlNodeIdShort proxy_to,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<AdnlPeerTable> adnl)
: pubkey_hash_(std::move(pubkey_hash))
, decrypt_via_(std::move(decrypt_via))
, proxy_to_(std::move(proxy_to))
, keyring_(std::move(keyring))
, adnl_(std::move(adnl)) {
}
void receive_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice datagram) override;
void receive_packet_cont(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice datagram, size_t idx);
void decrypted_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice data, size_t idx);
private:
PublicKeyHash pubkey_hash_;
std::vector<PublicKeyHash> decrypt_via_;
AdnlNodeIdShort proxy_to_;
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<AdnlPeerTable> adnl_;
};
class AdnlInboundTunnelMidpoint : public AdnlInboundTunnelPoint {
public:
AdnlInboundTunnelMidpoint(ton::PublicKey encrypt_via, AdnlNodeIdShort proxy_to, AdnlNodeIdShort proxy_as,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<AdnlPeerTable> adnl)
: encrypt_via_(std::move(encrypt_via)), proxy_to_(proxy_to), proxy_as_(proxy_as), keyring_(keyring), adnl_(adnl) {
}
void start_up() override;
void receive_packet(AdnlNodeIdShort src, td::IPAddress src_addr, td::BufferSlice datagram) override;
private:
ton::PublicKeyHash encrypt_key_hash_;
ton::PublicKey encrypt_via_;
std::unique_ptr<Encryptor> encryptor_;
AdnlNodeIdShort proxy_to_;
AdnlNodeIdShort proxy_as_;
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<AdnlPeerTable> adnl_;
};
class AdnlProxyNode : public td::actor::Actor {
public:
void receive_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data);
void receive_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise);
private:
std::map<PublicKeyHash, td::actor::ActorOwn<AdnlInboundTunnelMidpoint>> mid_;
};
} // namespace adnl
} // namespace ton

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -58,6 +58,8 @@ class AdnlSenderInterface : public td::actor::Actor {
td::uint64 max_answer_size) = 0; td::uint64 max_answer_size) = 0;
}; };
class AdnlTunnel : public td::actor::Actor {};
class Adnl : public AdnlSenderInterface { class Adnl : public AdnlSenderInterface {
public: public:
class Callback { class Callback {
@ -88,10 +90,10 @@ class Adnl : public AdnlSenderInterface {
virtual void add_static_nodes_from_config(AdnlNodesList nodes) = 0; virtual void add_static_nodes_from_config(AdnlNodesList nodes) = 0;
// adds local id. After that you can send/receive messages from/to this id // adds local id. After that you can send/receive messages from/to this id
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) { void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint8 cat) {
add_id_ex(std::move(id), std::move(addr_list), 0); add_id_ex(std::move(id), std::move(addr_list), cat, 0);
} }
virtual void add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode) = 0; virtual void add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint8 cat, td::uint32 mode) = 0;
virtual void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) = 0; virtual void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) = 0;
// subscribe to (some) messages(+queries) to this local id // subscribe to (some) messages(+queries) to this local id
@ -113,6 +115,8 @@ class Adnl : public AdnlSenderInterface {
virtual void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports, virtual void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) = 0; td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) = 0;
virtual void create_tunnel(AdnlNodeIdShort dst, td::uint32 size,
td::Promise<std::pair<td::actor::ActorOwn<AdnlTunnel>, AdnlAddress>> promise) = 0;
static td::actor::ActorOwn<Adnl> create(std::string db, td::actor::ActorId<keyring::Keyring> keyring); static td::actor::ActorOwn<Adnl> create(std::string db, td::actor::ActorId<keyring::Keyring> keyring);

View file

@ -391,7 +391,7 @@ endif()
add_executable(create-state block/create-state.cpp) add_executable(create-state block/create-state.cpp)
target_include_directories(create-state PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> target_include_directories(create-state PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>) $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block) target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block tonlib)
if (WINGETOPT_FOUND) if (WINGETOPT_FOUND)
target_link_libraries_system(create-state wingetopt) target_link_libraries_system(create-state wingetopt)
endif() endif()

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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 "crypto/Ed25519.h" #include "crypto/Ed25519.h"
@ -310,6 +310,10 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
return std::move(result); return std::move(result);
} }
int Ed25519::version() {
return OPENSSL_VERSION_NUMBER;
}
#else #else
Result<Ed25519::PrivateKey> Ed25519::generate_private_key() { Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
@ -387,6 +391,10 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
return std::move(shared_secret); return std::move(shared_secret);
} }
int Ed25519::version() {
return 0;
}
#endif #endif
} // namespace td } // namespace td

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -65,6 +65,8 @@ class Ed25519 {
static Result<PrivateKey> generate_private_key(); static Result<PrivateKey> generate_private_key();
static Result<SecureString> compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key); static Result<SecureString> compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key);
static int version();
}; };
} // namespace td } // namespace td

View file

@ -1633,15 +1633,19 @@ bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool c
bool config_params_present(vm::Dictionary& dict, Ref<vm::Cell> param_dict_root) { bool config_params_present(vm::Dictionary& dict, Ref<vm::Cell> param_dict_root) {
auto res = block::Config::unpack_param_dict(std::move(param_dict_root)); auto res = block::Config::unpack_param_dict(std::move(param_dict_root));
if (res.is_error()) { if (res.is_error()) {
LOG(ERROR)
<< "invalid mandatory parameters dictionary while checking existence of all mandatory configuration parameters";
return false; return false;
} }
for (int x : res.move_as_ok()) { for (int x : res.move_as_ok()) {
// LOG(DEBUG) << "checking whether mandatory configuration parameter #" << x << " exists";
if (!dict.int_key_exists(x)) { if (!dict.int_key_exists(x)) {
LOG(ERROR) << "configuration parameter #" << x LOG(ERROR) << "configuration parameter #" << x
<< " (declared as mandatory in configuration parameter #9) is missing"; << " (declared as mandatory in configuration parameter #9) is missing";
return false; return false;
} }
} }
// LOG(DEBUG) << "all mandatory configuration parameters present";
return true; return true;
} }

View file

@ -414,7 +414,7 @@ block_info#9bc7a987 version:uint32
after_split:(## 1) after_split:(## 1)
want_split:Bool want_merge:Bool want_split:Bool want_merge:Bool
key_block:Bool vert_seqno_incr:(## 1) key_block:Bool vert_seqno_incr:(## 1)
flags:(## 8) flags:(## 8) { flags <= 1 }
seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr } seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr }
{ prev_seq_no:# } { ~prev_seq_no + 1 = seq_no } { prev_seq_no:# } { ~prev_seq_no + 1 = seq_no }
shard:ShardIdent gen_utime:uint32 shard:ShardIdent gen_utime:uint32
@ -423,6 +423,7 @@ block_info#9bc7a987 version:uint32
gen_catchain_seqno:uint32 gen_catchain_seqno:uint32
min_ref_mc_seqno:uint32 min_ref_mc_seqno:uint32
prev_key_block_seqno:uint32 prev_key_block_seqno:uint32
gen_software:flags . 0?GlobalVersion
master_ref:not_master?^BlkMasterInfo master_ref:not_master?^BlkMasterInfo
prev_ref:^(BlkPrevInfo after_merge) prev_ref:^(BlkPrevInfo after_merge)
prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0) prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0)

View file

@ -55,6 +55,8 @@
#include "td/utils/port/path.h" #include "td/utils/port/path.h"
#include "td/utils/port/signals.h" #include "td/utils/port/signals.h"
#include "tonlib/keys/Mnemonic.h"
#include "block.h" #include "block.h"
#include "block-parse.h" #include "block-parse.h"
#include "block-auto.h" #include "block-auto.h"
@ -634,7 +636,25 @@ void interpret_sub_extra_currencies(vm::Stack& stack) {
stack.push_bool(ok); stack.push_bool(ok);
} }
void interpret_mnemonic_to_privkey(vm::Stack& stack, int mode) {
td::SecureString str{td::Slice{stack.pop_string()}};
auto res = tonlib::Mnemonic::create(std::move(str), td::SecureString());
if (res.is_error()) {
throw fift::IntError{res.move_as_error().to_string()};
}
auto privkey = res.move_as_ok().to_private_key();
td::SecureString key;
if (mode & 1) {
auto pub = privkey.get_public_key();
key = pub.move_as_ok().as_octet_string();
} else {
key = privkey.as_octet_string();
}
stack.push_bytes(key.as_slice());
}
void init_words_custom(fift::Dictionary& d) { void init_words_custom(fift::Dictionary& d) {
using namespace std::placeholders;
d.def_stack_word("verb@ ", interpret_get_verbosity); d.def_stack_word("verb@ ", interpret_get_verbosity);
d.def_stack_word("verb! ", interpret_set_verbosity); d.def_stack_word("verb! ", interpret_set_verbosity);
d.def_stack_word("wcid@ ", interpret_get_workchain); d.def_stack_word("wcid@ ", interpret_get_workchain);
@ -651,6 +671,8 @@ void init_words_custom(fift::Dictionary& d) {
d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr); d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr);
d.def_stack_word("CC+? ", interpret_add_extra_currencies); d.def_stack_word("CC+? ", interpret_add_extra_currencies);
d.def_stack_word("CC-? ", interpret_sub_extra_currencies); d.def_stack_word("CC-? ", interpret_sub_extra_currencies);
d.def_stack_word("mnemo>priv ", std::bind(interpret_mnemonic_to_privkey, _1, 0));
d.def_stack_word("mnemo>pub ", std::bind(interpret_mnemonic_to_privkey, _1, 1));
} }
tlb::TypenameLookup tlb_dict; tlb::TypenameLookup tlb_dict;
@ -738,7 +760,8 @@ void init_words_tlb(fift::Dictionary& d) {
d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str); d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str);
d.def_stack_word("tlb-skip ", interpret_tlb_skip); d.def_stack_word("tlb-skip ", interpret_tlb_skip);
d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip); d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip);
d.def_stack_word("ExtraCurrencyCollection", std::bind(interpret_tlb_type_const, _1, &block::tlb::t_ExtraCurrencyCollection)); d.def_stack_word("ExtraCurrencyCollection",
std::bind(interpret_tlb_type_const, _1, &block::tlb::t_ExtraCurrencyCollection));
} }
void usage(const char* progname) { void usage(const char* progname) {

View file

@ -1561,10 +1561,10 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
return skip_invalid ? 0 : 38; // not enough (extra) funds return skip_invalid ? 0 : 38; // not enough (extra) funds
} }
if (ap.remaining_balance.extra.not_null() || req.extra.not_null()) { if (ap.remaining_balance.extra.not_null() || req.extra.not_null()) {
LOG(WARNING) << "subtracting extra currencies: " LOG(DEBUG) << "subtracting extra currencies: "
<< block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus "
<< block::CurrencyCollection{0, req.extra}.to_str() << " equals " << block::CurrencyCollection{0, req.extra}.to_str() << " equals "
<< block::CurrencyCollection{0, new_extra}.to_str(); << block::CurrencyCollection{0, new_extra}.to_str();
} }
auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee); auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee);
@ -1730,11 +1730,17 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
} }
bounce_phase = std::make_unique<BouncePhase>(); bounce_phase = std::make_unique<BouncePhase>();
BouncePhase& bp = *bounce_phase; BouncePhase& bp = *bounce_phase;
block::gen::Message::Record msg;
block::gen::CommonMsgInfo::Record_int_msg_info info; block::gen::CommonMsgInfo::Record_int_msg_info info;
if (!tlb::unpack_cell_inexact(in_msg, info)) { auto cs = vm::load_cell_slice(in_msg);
if (!(tlb::unpack(cs, info) && gen::t_Maybe_Either_StateInit_Ref_StateInit.skip(cs) && cs.have(1) &&
cs.have_refs((int)cs.prefetch_ulong(1)))) {
bounce_phase.reset(); bounce_phase.reset();
return false; return false;
} }
if (cs.fetch_ulong(1)) {
cs = vm::load_cell_slice(cs.prefetch_ref());
}
info.ihr_disabled = true; info.ihr_disabled = true;
info.bounce = false; info.bounce = false;
info.bounced = true; info.bounced = true;
@ -1786,10 +1792,26 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
&& block::tlb::t_Grams.store_long(cb, bp.fwd_fees) // fwd_fee:Grams && block::tlb::t_Grams.store_long(cb, bp.fwd_fees) // fwd_fee:Grams
&& cb.store_long_bool(info.created_lt, 64) // created_lt:uint64 && cb.store_long_bool(info.created_lt, 64) // created_lt:uint64
&& cb.store_long_bool(info.created_at, 32) // created_at:uint32 && cb.store_long_bool(info.created_at, 32) // created_at:uint32
&& cb.store_long_bool(0, 2) // init:(Maybe ...) state:(Either ..) && cb.store_bool_bool(false)); // init:(Maybe ...)
&& cb.finalize_to(bp.out_msg)); if (cfg.bounce_msg_body) {
int body_bits = std::min((int)cs.size(), cfg.bounce_msg_body);
if (cb.remaining_bits() >= body_bits + 33u) {
CHECK(cb.store_bool_bool(false) // body:(Either X ^X) -> left X
&& cb.store_long_bool(-1, 32) // int = -1 ("message type")
&& cb.append_bitslice(cs.prefetch_bits(body_bits))); // truncated message body
} else {
vm::CellBuilder cb2;
CHECK(cb.store_bool_bool(true) // body:(Either X ^X) -> right ^X
&& cb2.store_long_bool(-1, 32) // int = -1 ("message type")
&& cb2.append_bitslice(cs.prefetch_bits(body_bits)) // truncated message body
&& cb.store_builder_ref_bool(std::move(cb2))); // ^X
}
} else {
CHECK(cb.store_bool_bool(false)); // body:(Either ..)
}
CHECK(cb.finalize_to(bp.out_msg));
if (verbosity > 2) { if (verbosity > 2) {
std::cerr << "generated bounced message: "; LOG(INFO) << "generated bounced message: ";
block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg); block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg);
} }
out_msgs.push_back(bp.out_msg); out_msgs.push_back(bp.out_msg);

View file

@ -139,6 +139,7 @@ struct ComputePhaseConfig {
struct ActionPhaseConfig { struct ActionPhaseConfig {
int max_actions{255}; int max_actions{255};
int bounce_msg_body{0}; // usually 0 or 256 bits
MsgPrices fwd_std; MsgPrices fwd_std;
MsgPrices fwd_mc; // from/to masterchain MsgPrices fwd_mc; // from/to masterchain
const WorkchainSet* workchains{nullptr}; const WorkchainSet* workchains{nullptr};

View file

@ -118,6 +118,24 @@ std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode)
return std::make_pair(std::move(quot), std::move(x)); return std::make_pair(std::move(quot), std::move(x));
} }
RefInt256 muldiv(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode) {
typename td::BigInt256::DoubleInt tmp{0};
tmp.add_mul(*x, *y);
RefInt256 quot{true};
tmp.mod_div(*z, quot.unique_write(), round_mode);
quot.write().normalize();
return quot;
}
std::pair<RefInt256, RefInt256> muldivmod(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode) {
typename td::BigInt256::DoubleInt tmp{0};
tmp.add_mul(*x, *y);
RefInt256 quot{true};
tmp.mod_div(*z, quot.unique_write(), round_mode);
quot.write().normalize();
return std::make_pair(std::move(quot), td::make_refint(tmp));
}
RefInt256 operator&(RefInt256 x, RefInt256 y) { RefInt256 operator&(RefInt256 x, RefInt256 y) {
x.write() &= *y; x.write() &= *y;
return x; return x;

View file

@ -45,6 +45,8 @@ extern RefInt256 operator%(RefInt256 x, RefInt256 y);
extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1); extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1);
extern RefInt256 mod(RefInt256 x, RefInt256 y, int round_mode = -1); extern RefInt256 mod(RefInt256 x, RefInt256 y, int round_mode = -1);
extern std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode = -1); extern std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode = -1);
extern RefInt256 muldiv(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode = -1);
extern std::pair<RefInt256, RefInt256> muldivmod(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode = -1);
extern RefInt256 operator-(RefInt256 x); extern RefInt256 operator-(RefInt256 x);
extern RefInt256 operator&(RefInt256 x, RefInt256 y); extern RefInt256 operator&(RefInt256 x, RefInt256 y);
extern RefInt256 operator|(RefInt256 x, RefInt256 y); extern RefInt256 operator|(RefInt256 x, RefInt256 y);

View file

@ -1,7 +1,7 @@
library TVM_Asm library TVM_Asm
// simple TVM Assembler // simple TVM Assembler
variable @atend variable @atend
'nop @atend ! { "not in asm context" abort } @atend !
{ `normal eq? not abort"must be terminated by }>" } : @normal? { `normal eq? not abort"must be terminated by }>" } : @normal?
{ @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend { @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend
{ @pushatend <b } : <{ { @pushatend <b } : <{
@ -12,10 +12,11 @@ variable @atend
{ @atend @ 2 { @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @| { @atend @ 2 { @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @|
{ @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{ { @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{
{ over brembits <= } : @havebits { over brembits <= } : @havebits
{ rot + -rot + swap } : pair+
{ rot >= -rot <= and } : 2x<= { rot >= -rot <= and } : 2x<=
{ 2 pick brembitrefs 1- 2x<= } : @havebitrefs { 2 pick brembitrefs 1- 2x<= } : @havebitrefs
{ @havebits not ' @| if } : @ensurebits { @havebits ' @| ifnot } : @ensurebits
{ @havebitrefs not ' @| if } : @ensurebitrefs { @havebitrefs ' @| ifnot } : @ensurebitrefs
{ rot over @ensurebits -rot u, } : @simpleuop { rot over @ensurebits -rot u, } : @simpleuop
{ tuck sbitrefs @ensurebitrefs swap s, } : @addop { tuck sbitrefs @ensurebitrefs swap s, } : @addop
{ tuck bbitrefs @ensurebitrefs swap b+ } : @addopb { tuck bbitrefs @ensurebitrefs swap b+ } : @addopb
@ -27,6 +28,7 @@ variable @atend
{ 1 { <b swap s, swap 4 u, @addopb } does create } : @Defop(4u) { 1 { <b swap s, swap 4 u, @addopb } does create } : @Defop(4u)
{ 1 { <b swap s, rot 4 u, swap 4 u, @addopb } does create } : @Defop(4u,4u) { 1 { <b swap s, rot 4 u, swap 4 u, @addopb } does create } : @Defop(4u,4u)
{ 1 { <b swap s, swap ref, @addopb } does create } : @Defop(ref) { 1 { <b swap s, swap ref, @addopb } does create } : @Defop(ref)
{ 1 { <b swap s, rot ref, swap ref, @addopb } does create } : @Defop(ref*2)
{ <b 0xef 8 u, swap 12 i, b> } : si() { <b 0xef 8 u, swap 12 i, b> } : si()
// x mi ma -- ? // x mi ma -- ?
{ rot tuck >= -rot <= and } : @range { rot tuck >= -rot <= and } : @range
@ -272,10 +274,27 @@ x{8A} @Defop(ref) PUSHREFCONT
} cond } cond
} cond } cond
} dup : PUSHSLICE : SLICE } dup : PUSHSLICE : SLICE
{ tuck bbitrefs swap 16 + dup 7 and 3 -roll swap @havebitrefs // ( b' -- ? )
not rot or { bbitrefs or 0= } : @cont-empty?
{ swap b> PUSHREFCONT } { bbits 7 and 0= } : @cont-aligned?
{ over bbitrefs 2dup 120 0 2x<= // ( b b' -- ? )
{ bbitrefs over 7 and { 2drop drop false } {
swap 16 + swap @havebitrefs nip
} cond
} : @cont-fits?
// ( b b' -- ? )
{ bbitrefs over 7 and { 2drop drop false } {
32 1 pair+ @havebitrefs nip
} cond
} : @cont-ref-fit?
// ( b b' b'' -- ? )
{ over @cont-aligned? over @cont-aligned? and not { 2drop drop false } {
bbitrefs rot bbitrefs pair+ swap 32 + swap @havebitrefs nip
} cond
} : @two-cont-fit?
{ 2dup @cont-fits? not
{ b> PUSHREFCONT }
{ swap over bbitrefs 2dup 120 0 2x<=
{ drop swap x{9} s, swap 3 >> 4 u, swap b+ } { drop swap x{9} s, swap 3 >> 4 u, swap b+ }
{ rot x{8F_} s, swap 2 u, swap 3 >> 7 u, swap b+ } cond { rot x{8F_} s, swap 2 u, swap 3 >> 7 u, swap b+ } cond
} cond } cond
@ -320,12 +339,16 @@ x{A985} @Defop MULDIVR
x{A98C} @Defop MULDIVMOD x{A98C} @Defop MULDIVMOD
x{A9A4} @Defop MULRSHIFT x{A9A4} @Defop MULRSHIFT
x{A9A5} @Defop MULRSHIFTR x{A9A5} @Defop MULRSHIFTR
x{A9A6} @Defop MULRSHIFTC
x{A9B4} @Defop(8u+1) MULRSHIFT# x{A9B4} @Defop(8u+1) MULRSHIFT#
x{A9B5} @Defop(8u+1) MULRSHIFTR# x{A9B5} @Defop(8u+1) MULRSHIFTR#
x{A9B6} @Defop(8u+1) MULRSHIFTC#
x{A9C4} @Defop LSHIFTDIV x{A9C4} @Defop LSHIFTDIV
x{A9C5} @Defop LSHIFTDIVR x{A9C5} @Defop LSHIFTDIVR
x{A9C6} @Defop LSHIFTDIVC
x{A9D4} @Defop(8u+1) LSHIFT#DIV x{A9D4} @Defop(8u+1) LSHIFT#DIV
x{A9D5} @Defop(8u+1) LSHIFT#DIVR x{A9D5} @Defop(8u+1) LSHIFT#DIVR
x{A9D6} @Defop(8u+1) LSHIFT#DIVC
x{AA} @Defop(8u+1) LSHIFT# x{AA} @Defop(8u+1) LSHIFT#
x{AB} @Defop(8u+1) RSHIFT# x{AB} @Defop(8u+1) RSHIFT#
x{AC} @Defop LSHIFT x{AC} @Defop LSHIFT
@ -628,46 +651,80 @@ x{DB3F} @Defop RETDATA
x{DC} @Defop IFRET x{DC} @Defop IFRET
x{DD} @Defop IFNOTRET x{DD} @Defop IFNOTRET
x{DE} @Defop IF x{DE} @Defop IF
{ }> PUSHCONT IF } : }>IF
x{DF} @Defop IFNOT x{DF} @Defop IFNOT
{ }> PUSHCONT IFNOT } : }>IFNOT
' IFNOTRET : IF: ' IFNOTRET : IF:
' IFRET : IFNOT: ' IFRET : IFNOT:
x{E0} @Defop IFJMP x{E0} @Defop IFJMP
{ }> PUSHCONT IFJMP } : }>IFJMP
{ { @normal? PUSHCONT IFJMP } @doafter<{ } : IFJMP:<{
x{E1} @Defop IFNOTJMP x{E1} @Defop IFNOTJMP
{ }> PUSHCONT IFNOTJMP } : }>IFNOTJMP
{ { @normal? PUSHCONT IFNOTJMP } @doafter<{ } : IFNOTJMP:<{
x{E2} @Defop IFELSE x{E2} @Defop IFELSE
{ `else @endblk } : }>ELSE<{
{ `else: @endblk } : }>ELSE:
{ PUSHCONT { @normal? PUSHCONT IFELSE } @doafter<{ } : @doifelse
{ 1 { swap @normal? -rot PUSHCONT swap PUSHCONT IFELSE } does @doafter<{ } : @doifnotelse
{
{ dup `else eq?
{ drop @doifelse }
{ dup `else: eq?
{ drop PUSHCONT IFJMP }
{ @normal? PUSHCONT IF
} cond
} cond
} @doafter<{
} : IF:<{
{
{ dup `else eq?
{ drop @doifnotelse }
{ dup `else: eq?
{ drop PUSHCONT IFNOTJMP }
{ @normal? PUSHCONT IFNOT
} cond
} cond
} @doafter<{
} : IFNOT:<{
x{E300} @Defop(ref) IFREF x{E300} @Defop(ref) IFREF
x{E301} @Defop(ref) IFNOTREF x{E301} @Defop(ref) IFNOTREF
x{E302} @Defop(ref) IFJMPREF x{E302} @Defop(ref) IFJMPREF
x{E303} @Defop(ref) IFNOTJMPREF x{E303} @Defop(ref) IFNOTJMPREF
x{E30D} @Defop(ref) IFREFELSE
x{E30E} @Defop(ref) IFELSEREF
x{E30F} @Defop(ref*2) IFREFELSEREF
{ 16 1 @havebitrefs nip } : @refop-fits?
// b b1 [e0 e1 e2] -- b'
{ -rot dup @cont-empty? { drop swap 0 } {
2dup @cont-fits? { rot 1 } {
over @refop-fits? { b> rot 2 } {
swap @| swap 2dup @cont-fits? { rot 1 } {
b> rot 2
} cond } cond } cond } cond
[] execute
} : @run-cont-op
{ triple 1 ' @run-cont-op does create } : @def-cont-op
{ } { PUSHCONT IF } { IFREF } @def-cont-op IF-cont
{ IFRET } { PUSHCONT IFJMP } { IFJMPREF } @def-cont-op IFJMP-cont
{ } { PUSHCONT IFNOT } { IFNOTREF } @def-cont-op IFNOT-cont
{ IFNOTRET } { PUSHCONT IFNOTJMP } { IFNOTJMPREF } @def-cont-op IFNOTJMP-cont
{ dup 2over rot } : 3dup
recursive IFELSE-cont2 {
dup @cont-empty? { drop IF-cont } {
over @cont-empty? { nip IFNOT-cont } {
3dup @two-cont-fit? { -rot PUSHCONT swap PUSHCONT IFELSE } {
3dup nip @cont-ref-fit? { rot swap PUSHCONT swap b> IFREFELSE } {
3dup drop @cont-ref-fit? { -rot PUSHCONT swap b> IFELSEREF } {
rot 32 2 @havebitrefs { rot b> rot b> IFREFELSEREF } {
@| -rot IFELSE-cont2
} cond } cond } cond } cond } cond } cond
} swap !
{ }> IF-cont } : }>IF
{ }> IFNOT-cont } : }>IFNOT
{ }> IFJMP-cont } : }>IFJMP
{ }> IFNOTJMP-cont } : }>IFNOTJMP
{ { @normal? IFJMP-cont } @doafter<{ } : IFJMP:<{
{ { @normal? IFNOTJMP-cont } @doafter<{ } : IFNOTJMP:<{
{ `else @endblk } : }>ELSE<{
{ `else: @endblk } : }>ELSE:
{ 1 { swap @normal? swap IFELSE-cont2 } does @doafter<{ } : @doifelse
{ 1 { swap @normal? IFELSE-cont2 } does @doafter<{ } : @doifnotelse
{
{ dup `else eq?
{ drop @doifelse }
{ dup `else: eq?
{ drop IFJMP-cont }
{ @normal? IF-cont
} cond
} cond
} @doafter<{
} : IF:<{
{
{ dup `else eq?
{ drop @doifnotelse }
{ dup `else: eq?
{ drop IFNOTJMP-cont }
{ @normal? IFNOT-cont
} cond
} cond
} @doafter<{
} : IFNOT:<{
x{E304} @Defop CONDSEL x{E304} @Defop CONDSEL
x{E305} @Defop CONDSELCHK x{E305} @Defop CONDSELCHK
x{E308} @Defop IFRETALT x{E308} @Defop IFRETALT
@ -676,18 +733,22 @@ x{E309} @Defop IFNOTRETALT
{ <b x{E3B_} swap 5 u, @addopb } : IFNBITJMP { <b x{E3B_} swap 5 u, @addopb } : IFNBITJMP
{ <b x{E3D_} swap 5 u, swap ref, @addopb } : IFBITJMPREF { <b x{E3D_} swap 5 u, swap ref, @addopb } : IFBITJMPREF
{ <b x{E3F_} swap 5 u, swap ref, @addopb } : IFNBITJMPREF { <b x{E3F_} swap 5 u, swap ref, @addopb } : IFNBITJMPREF
x{E4} @Defop REPEAT x{E4} @Defop REPEAT
{ }> PUSHCONT REPEAT } : }>REPEAT
{ { @normal? PUSHCONT REPEAT } @doafter<{ } : REPEAT:<{
x{E5} dup @Defop REPEATEND @Defop REPEAT: x{E5} dup @Defop REPEATEND @Defop REPEAT:
x{E6} @Defop UNTIL x{E6} @Defop UNTIL
{ }> PUSHCONT UNTIL } : }>UNTIL
{ { @normal? PUSHCONT UNTIL } @doafter<{ } : UNTIL:<{
x{E7} dup @Defop UNTILEND @Defop UNTIL: x{E7} dup @Defop UNTILEND @Defop UNTIL:
x{E8} @Defop WHILE x{E8} @Defop WHILE
x{E9} @Defop WHILEEND x{E9} @Defop WHILEEND
x{EA} @Defop AGAIN
x{EB} dup @Defop AGAINEND @Defop AGAIN:
{ `do @endblk } : }>DO<{ { `do @endblk } : }>DO<{
{ `do: @endblk } : }>DO: { `do: @endblk } : }>DO:
{ }> PUSHCONT REPEAT } : }>REPEAT
{ { @normal? PUSHCONT REPEAT } @doafter<{ } : REPEAT:<{
{ }> PUSHCONT UNTIL } : }>UNTIL
{ { @normal? PUSHCONT UNTIL } @doafter<{ } : UNTIL:<{
{ PUSHCONT { @normal? PUSHCONT WHILE } @doafter<{ } : @dowhile { PUSHCONT { @normal? PUSHCONT WHILE } @doafter<{ } : @dowhile
{ {
{ dup `do eq? { dup `do eq?
@ -696,10 +757,34 @@ x{E9} @Defop WHILEEND
} cond } cond
} @doafter<{ } @doafter<{
} : WHILE:<{ } : WHILE:<{
x{EA} @Defop AGAIN
{ }> PUSHCONT AGAIN } : }>AGAIN { }> PUSHCONT AGAIN } : }>AGAIN
{ { @normal? PUSHCONT AGAIN } @doafter<{ } : AGAIN:<{ { { @normal? PUSHCONT AGAIN } @doafter<{ } : AGAIN:<{
x{EB} dup @Defop AGAINEND @Defop AGAIN:
x{E314} @Defop REPEATBRK
x{E315} @Defop REPEATENDBRK
x{E316} @Defop UNTILBRK
x{E317} dup @Defop UNTILENDBRK @Defop UNTILBRK:
x{E318} @Defop WHILEBRK
x{E319} @Defop WHILEENDBRK
x{E31A} @Defop AGAINBRK
x{E31B} dup @Defop AGAINENDBRK @Defop AGAINBRK:
{ }> PUSHCONT REPEATBRK } : }>REPEATBRK
{ { @normal? PUSHCONT REPEATBRK } @doafter<{ } : REPEATBRK:<{
{ }> PUSHCONT UNTILBRK } : }>UNTILBRK
{ { @normal? PUSHCONT UNTILBRK } @doafter<{ } : UNTILBRK:<{
{ PUSHCONT { @normal? PUSHCONT WHILEBRK } @doafter<{ } : @dowhile
{
{ dup `do eq?
{ drop @dowhile }
{ `do: eq? not abort"`}>DO<{` expected" PUSHCONT WHILEENDBRK
} cond
} @doafter<{
} : WHILEBRK:<{
{ }> PUSHCONT AGAINBRK } : }>AGAINBRK
{ { @normal? PUSHCONT AGAINBRK } @doafter<{ } : AGAINBRK:<{
// //
// continuation stack manipulation and continuation creation // continuation stack manipulation and continuation creation
// //
@ -745,6 +830,8 @@ x{EDF6} @Defop THENRET
x{EDF7} @Defop THENRETALT x{EDF7} @Defop THENRETALT
x{EDF8} @Defop INVERT x{EDF8} @Defop INVERT
x{EDF9} @Defop BOOLEVAL x{EDF9} @Defop BOOLEVAL
x{EDFA} @Defop SAMEALT
x{EDFB} @Defop SAMEALTSAVE
// x{EE} is BLESSARGS // x{EE} is BLESSARGS
// //
// dictionary subroutine call/jump primitives // dictionary subroutine call/jump primitives

View file

@ -111,6 +111,42 @@ recursive list-map {
swap uncons -rot over execute -rot list-map cons swap uncons -rot over execute -rot list-map cons
} cond } cond
} swap ! } swap !
variable ctxdump variable curctx
// (a1 .. an) e -- executes e for a1, ..., an
{ ctxdump @ curctx @ ctxdump 2! curctx 2!
{ curctx 2@ over null? not } { swap uncons rot tuck curctx 2! execute }
while 2drop ctxdump 2@ curctx ! ctxdump !
} : list-foreach
forget ctxdump forget curctx
//
// Experimental implementation of `for` loops with index
//
variable loopdump variable curloop
{ curloop @ loopdump @ loopdump 2! } : push-loop-ctx
{ loopdump 2@ loopdump ! curloop ! } : pop-loop-ctx
// ilast i0 e -- executes e for i=i0,i0+1,...,ilast-1
{ -rot 2dup > {
push-loop-ctx {
triple dup curloop ! first execute curloop @ untriple 1+ 2dup <=
} until pop-loop-ctx
} if 2drop drop
} : for
// ilast i0 e -- same as 'for', but pushes current index i before executing e
{ -rot 2dup > {
push-loop-ctx {
triple dup curloop ! untriple nip swap execute curloop @ untriple 1+ 2dup <=
} until pop-loop-ctx
} if 2drop drop
} : for-i
// ( -- i ) Returns innermost loop index
{ curloop @ third } : i
// ( -- j ) Returns outer loop index
{ loopdump @ car third } : j
{ loopdump @ cadr third } : k
forget curloop forget loopdump
// //
// create Lisp-style lists using words "(" and ")" // create Lisp-style lists using words "(" and ")"
// //

View file

@ -177,28 +177,15 @@ void interpret_divmod(vm::Stack& stack, int round_mode) {
} }
void interpret_times_div(vm::Stack& stack, int round_mode) { void interpret_times_div(vm::Stack& stack, int round_mode) {
auto z = stack.pop_int(); auto z = stack.pop_int(), y = stack.pop_int(), x = stack.pop_int();
auto y = stack.pop_int(); stack.push_int(muldiv(std::move(x), std::move(y), std::move(z), round_mode));
auto x = stack.pop_int();
typename td::BigInt256::DoubleInt tmp{0};
tmp.add_mul(*x, *y);
auto q = td::make_refint();
tmp.mod_div(*z, q.unique_write(), round_mode);
q.unique_write().normalize();
stack.push_int(std::move(q));
} }
void interpret_times_divmod(vm::Stack& stack, int round_mode) { void interpret_times_divmod(vm::Stack& stack, int round_mode) {
auto z = stack.pop_int(); auto z = stack.pop_int(), y = stack.pop_int(), x = stack.pop_int();
auto y = stack.pop_int(); auto dm = muldivmod(std::move(x), std::move(y), std::move(z));
auto x = stack.pop_int(); stack.push_int(std::move(dm.first));
typename td::BigInt256::DoubleInt tmp{0}; stack.push_int(std::move(dm.second));
tmp.add_mul(*x, *y);
auto q = td::make_refint();
tmp.mod_div(*z, q.unique_write(), round_mode);
q.unique_write().normalize();
stack.push_int(std::move(q));
stack.push_int(td::make_refint(tmp));
} }
void interpret_times_mod(vm::Stack& stack, int round_mode) { void interpret_times_mod(vm::Stack& stack, int round_mode) {

View file

@ -427,9 +427,7 @@ AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("NEGATE", 1); return exec_op("NEGATE", 1);
} }
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) { AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) { if (x.is_int_const() && y.is_int_const()) {
r.set_const(x.int_const * y.int_const); r.set_const(x.int_const * y.int_const);
x.unused(); x.unused();
@ -492,6 +490,11 @@ AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("MUL", 2); return exec_op("MUL", 2);
} }
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
assert(res.size() == 1 && args.size() == 2);
return compile_mul_internal(res[0], args[0], args[1]);
}
AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args) { AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
assert(res.size() == 1 && args.size() == 2); assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1]; VarDescr &r = res[0], &x = args[0], &y = args[1];
@ -566,9 +569,7 @@ AsmOp compile_rshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, in
return exec_op(rshift, 2); return exec_op(rshift, 2);
} }
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) { AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, int round_mode) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) { if (x.is_int_const() && y.is_int_const()) {
r.set_const(div(x.int_const, y.int_const, round_mode)); r.set_const(div(x.int_const, y.int_const, round_mode));
x.unused(); x.unused();
@ -608,6 +609,11 @@ AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
return exec_op(op, 2); return exec_op(op, 2);
} }
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
assert(res.size() == 1 && args.size() == 2);
return compile_div_internal(res[0], args[0], args[1], round_mode);
}
AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) { AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
assert(res.size() == 1 && args.size() == 2); assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1]; VarDescr &r = res[0], &x = args[0], &y = args[1];
@ -648,6 +654,87 @@ AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
return exec_op(op, 2); return exec_op(op, 2);
} }
AsmOp compile_muldiv(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
assert(res.size() == 1 && args.size() == 3);
VarDescr &r = res[0], &x = args[0], &y = args[1], &z = args[2];
if (x.is_int_const() && y.is_int_const() && z.is_int_const()) {
r.set_const(muldiv(x.int_const, y.int_const, z.int_const, round_mode));
x.unused();
y.unused();
z.unused();
return push_const(r.int_const);
}
if (x.always_zero() || y.always_zero()) {
// dubious optimization for z=0...
x.unused();
y.unused();
z.unused();
r.set_const(td::make_refint(0));
return push_const(r.int_const);
}
char c = (round_mode < 0) ? 0 : (round_mode > 0 ? 'C' : 'R');
r.val = emulate_div(emulate_mul(x.val, y.val), z.val);
if (z.is_int_const()) {
if (*z.int_const == 0) {
x.unused();
y.unused();
z.unused();
r.set_const(div(z.int_const, z.int_const));
return push_const(r.int_const);
}
if (*z.int_const == 1) {
z.unused();
return compile_mul_internal(r, x, y);
}
}
if (y.is_int_const() && *y.int_const == 1) {
y.unused();
return compile_div_internal(r, x, z, round_mode);
}
if (x.is_int_const() && *x.int_const == 1) {
x.unused();
return compile_div_internal(r, y, z, round_mode);
}
if (z.is_int_const()) {
int k = is_pos_pow2(z.int_const);
if (k > 0) {
z.unused();
std::string op = "MULRSHIFT";
if (c) {
op += c;
}
return exec_arg_op(op + '#', k, 2);
}
}
if (y.is_int_const()) {
int k = is_pos_pow2(y.int_const);
if (k > 0) {
y.unused();
std::string op = "LSHIFT#DIV";
if (c) {
op += c;
}
return exec_arg_op(op, k, 2);
}
}
if (x.is_int_const()) {
int k = is_pos_pow2(x.int_const);
if (k > 0) {
x.unused();
std::string op = "LSHIFT#DIV";
if (c) {
op += c;
}
return exec_arg_op(op, k, 2);
}
}
std::string op = "MULDIV";
if (c) {
op += c;
}
return exec_op(op, 3);
}
int compute_compare(td::RefInt256 x, td::RefInt256 y, int mode) { int compute_compare(td::RefInt256 x, td::RefInt256 y, int mode) {
int s = td::cmp(x, y); int s = td::cmp(x, y);
if (mode == 7) { if (mode == 7) {
@ -933,8 +1020,9 @@ void define_builtins() {
define_builtin_func("^_&=_", arith_bin_op, AsmOp::Custom("AND", 2)); define_builtin_func("^_&=_", arith_bin_op, AsmOp::Custom("AND", 2));
define_builtin_func("^_|=_", arith_bin_op, AsmOp::Custom("OR", 2)); define_builtin_func("^_|=_", arith_bin_op, AsmOp::Custom("OR", 2));
define_builtin_func("^_^=_", arith_bin_op, AsmOp::Custom("XOR", 2)); define_builtin_func("^_^=_", arith_bin_op, AsmOp::Custom("XOR", 2));
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), AsmOp::Custom("MULDIVR", 3)); define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, -1));
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), AsmOp::Custom("MULDIV", 3)); define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 0));
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 1));
define_builtin_func("muldivmod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2)); define_builtin_func("muldivmod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2));
define_builtin_func("_==_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 2)); define_builtin_func("_==_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 2));
define_builtin_func("_!=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 5)); define_builtin_func("_!=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 5));

View file

@ -575,9 +575,9 @@ bool Optimizer::find_at_least(int pb) {
(is_push_rotrev(&i) && rewrite(AsmOp::Push(i), AsmOp::Custom("-ROT"))) || (is_push_rotrev(&i) && rewrite(AsmOp::Push(i), AsmOp::Custom("-ROT"))) ||
(is_push_xchg(&i, &j, &k) && rewrite(AsmOp::Push(i), AsmOp::Xchg(j, k))) || (is_push_xchg(&i, &j, &k) && rewrite(AsmOp::Push(i), AsmOp::Xchg(j, k))) ||
(is_reverse(&i, &j) && rewrite(AsmOp::BlkReverse(i, j))) || (is_reverse(&i, &j) && rewrite(AsmOp::BlkReverse(i, j))) ||
(is_blkdrop2(&i, &j) && rewrite(AsmOp::BlkDrop2(i, j))) ||
(is_nip_seq(&i, &j) && rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) || (is_nip_seq(&i, &j) && rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
(is_pop_blkdrop(&i, &k) && rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) || (is_pop_blkdrop(&i, &k) && rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
(is_blkdrop2(&i, &j) && rewrite(AsmOp::BlkDrop2(i, j))) ||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14 (is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2)) ? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
: rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) || : rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||

View file

@ -23,6 +23,25 @@
.end_cell()); .end_cell());
} }
;; [min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price]
_ parse_vote_config(cell c) inline {
var cs = c.begin_parse();
throw_unless(44, cs~load_uint(8) == 0x36);
var res = [cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(32), cs~load_uint(32), cs~load_uint(32), cs~load_uint(32)];
cs.end_parse();
return res;
}
;; cfg_vote_setup#91 normal_params:^ConfigProposalSetup critical_params:^ConfigProposalSetup = ConfigVotingSetup;
_ get_vote_config(int critical?) inline_ref {
var cs = config_param(11).begin_parse();
throw_unless(44, cs~load_uint(8) == 0x91);
if (critical?) {
cs~load_ref();
}
return parse_vote_config(cs.preload_ref());
}
(int, int) check_validator_set(cell vset) { (int, int) check_validator_set(cell vset) {
var cs = vset.begin_parse(); var cs = vset.begin_parse();
throw_unless(9, cs~load_uint(8) == 0x12); ;; validators_ext#12 only throw_unless(9, cs~load_uint(8) == 0x12); ;; validators_ext#12 only
@ -46,53 +65,14 @@
.end_cell(), mode); .end_cell(), mode);
} }
() send_confirmation(addr, query_id, ans_tag) impure { () send_confirmation(addr, query_id, ans_tag) impure inline {
return send_answer(addr, query_id, ans_tag, 64); return send_answer(addr, query_id, ans_tag, 64);
} }
() send_error(addr, query_id, ans_tag) impure { () send_error(addr, query_id, ans_tag) impure inline {
return send_answer(addr, query_id, ans_tag, 64); return send_answer(addr, query_id, ans_tag, 64);
} }
() recv_internal(cell in_msg_cell, slice in_msg) impure {
var cs = in_msg_cell.begin_parse();
var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
var s_addr = cs~load_msg_addr();
(int src_wc, int src_addr) = s_addr.parse_std_addr();
if ((src_wc + 1) | (flags & 1) | in_msg.slice_empty?()) {
;; source not in masterchain, or a bounced message, or a simple transfer
return ();
}
int tag = in_msg~load_uint(32);
int query_id = in_msg~load_uint(64);
if (tag == 0x4e565354) {
;; set next validator set
var vset = in_msg~load_ref();
in_msg.end_parse();
var elector_param = config_param(1);
var elector_addr = cell_null?(elector_param) ? -1 : elector_param.begin_parse().preload_uint(256);
var ok = false;
if (src_addr == elector_addr) {
;; message from elector smart contract
;; set next validator set
(var t_since, var t_until) = check_validator_set(vset);
var t = now();
ok = (t_since > t) & (t_until > t_since);
}
if (ok) {
set_conf_param(36, vset);
;; send confirmation
return send_confirmation(s_addr, query_id, 0xee764f4b);
} else {
return send_error(s_addr, query_id, 0xee764f6f);
}
}
;; if tag is non-zero and its higher bit is zero, throw an exception (the message is an unsupported query)
;; to bounce message back to sender
throw_unless(37, (tag == 0) | (tag & (1 << 31)));
;; do nothing for other internal messages
}
;; forward a message to elector smart contract to make it upgrade its code ;; forward a message to elector smart contract to make it upgrade its code
() change_elector_code(slice cs) impure { () change_elector_code(slice cs) impure {
var dest_addr = config_param(1).begin_parse().preload_uint(256); var dest_addr = config_param(1).begin_parse().preload_uint(256);
@ -114,7 +94,7 @@
_ perform_action(cfg_dict, public_key, action, cs) { _ perform_action(cfg_dict, public_key, action, cs) {
if (action == 0x43665021) { if (action == 0x43665021) {
;; change one configuration parameter ;; change one configuration parameter
var param_index = cs~load_uint(32); var param_index = cs~load_int(32);
var param_value = cs~load_ref(); var param_value = cs~load_ref();
cs.end_parse(); cs.end_parse();
cfg_dict~idict_set_ref(32, param_index, param_value); cfg_dict~idict_set_ref(32, param_index, param_value);
@ -143,11 +123,8 @@ _ perform_action(cfg_dict, public_key, action, cs) {
} }
} }
(slice, int) get_validator_descr(int idx) inline_ref { (cell, int, slice) get_current_vset() inline_ref {
var vset = config_param(34); var vset = config_param(34);
if (vset.null?()) {
return (null(), 0);
}
var cs = begin_parse(vset); var cs = begin_parse(vset);
;; validators_ext#12 utime_since:uint32 utime_until:uint32 ;; validators_ext#12 utime_since:uint32 utime_until:uint32
;; total:(## 16) main:(## 16) { main <= total } { main >= 1 } ;; total:(## 16) main:(## 16) { main <= total } { main >= 1 }
@ -155,6 +132,11 @@ _ perform_action(cfg_dict, public_key, action, cs) {
throw_unless(40, cs~load_uint(8) == 0x12); throw_unless(40, cs~load_uint(8) == 0x12);
cs~skip_bits(32 + 32 + 16 + 16); cs~skip_bits(32 + 32 + 16 + 16);
int total_weight = cs~load_uint(64); int total_weight = cs~load_uint(64);
return (vset, total_weight, cs);
}
(slice, int) get_validator_descr(int idx) inline_ref {
var (vset, total_weight, cs) = get_current_vset();
var dict = begin_cell().store_slice(cs).end_cell(); var dict = begin_cell().store_slice(cs).end_cell();
var (value, _) = dict.udict_get?(16, idx); var (value, _) = dict.udict_get?(16, idx);
return (value, total_weight); return (value, total_weight);
@ -169,6 +151,40 @@ _ perform_action(cfg_dict, public_key, action, cs) {
return (cs~load_uint(256), cs~load_uint(64)); return (cs~load_uint(256), cs~load_uint(64));
} }
;; cfg_proposal#f3 param_id:int32 param_value:(Maybe ^Cell) if_hash_equal:(Maybe uint256)
;; c -> (param-id param-cell maybe-hash)
(int, cell, int) parse_config_proposal(cell c) inline_ref {
var cs = c.begin_parse();
throw_unless(44, cs~load_int(8) == 0xf3 - 0x100);
var (id, val, hash) = (cs~load_int(32), cs~load_maybe_ref(), cs~load_int(1));
if (hash) {
hash = cs~load_uint(256);
} else {
hash = -1;
}
cs.end_parse();
return (id, val, hash);
}
;; cfg_proposal_status#ce expires:uint32 proposal:^ConfigProposal is_critical:Bool
;; voters:(HashmapE 16 True) remaining_weight:int64 validator_set_id:uint256
;; rounds_remaining:uint8 wins:uint8 losses:uint8 = ConfigProposalStatus;
(int, cell, int, cell, int, int, slice) unpack_proposal_status(slice cs) inline_ref {
throw_unless(44, cs~load_int(8) == 0xce - 0x100);
return (cs~load_uint(32), cs~load_ref(), cs~load_int(1), cs~load_dict(), cs~load_int(64), cs~load_uint(256), cs);
}
builder begin_pack_proposal_status(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id) inline {
return begin_cell()
.store_int(0xce - 0x100, 8)
.store_uint(expires, 32)
.store_ref(proposal)
.store_int(critical?, 1)
.store_dict(voters)
.store_int(weight_remaining, 64)
.store_uint(vset_id, 256);
}
(cell, int, int, slice) new_proposal(cs) inline { (cell, int, int, slice) new_proposal(cs) inline {
return (null(), 0, 0, cs); return (null(), 0, 0, cs);
} }
@ -216,6 +232,141 @@ builder pack_proposal(cell voters, int sum_weight, int vset_id, slice body) inli
} }
} }
int register_voting_proposal(slice cs, int msg_value) inline_ref {
var (expire_at, proposal, critical?) = (cs~load_uint(32), cs~load_ref(), cs~load_int(1));
if (expire_at >> 30) {
expire_at -= now();
}
var (param_id, param_val, hash) = parse_config_proposal(proposal);
if (hash >= 0) {
cell cur_val = config_param(param_id);
int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val);
if (cur_hash != hash) {
hash = -0xe2646356; ;; bad current value
}
} else {
var m_params = config_param(9);
var (_, found?) = m_params.idict_get?(32, param_id);
if (found?) {
hash = -0xcd506e6c; ;; cannot set mandatory parameter to null
}
}
if (param_val.cell_depth() >= 256) {
hash = -0xc2616456; ;; bad value
}
if (hash < -1) {
return hash; ;; return error if any
}
ifnot (critical?) {
var crit_params = config_param(10);
var (_, found?) = crit_params.idict_get?(32, param_id);
if (found?) {
hash = -0xc3726954; ;; trying to set a critical parameter without critical flag
}
}
if (hash < -1) {
return hash;
}
;; obtain vote proposal configuration
var vote_cfg = get_vote_config(critical?);
var [min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price] = vote_cfg;
if (expire_at < min_store_sec) {
return -0xc5787069; ;; expired
}
expire_at = min(expire_at, max_store_sec);
;; compute price
var (_, bits, refs) = compute_data_size(param_val, 1024);
var pps = bit_price * (bits + 1024) + cell_price * (refs + 2);
var price = pps * expire_at;
expire_at += now();
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
int phash = proposal.cell_hash();
var (pstatus, found?) = vote_dict.udict_get?(256, phash);
if (found?) {
;; proposal already exists; we can only extend it
var (expires, r_proposal, r_critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
if (r_critical? != critical?) {
return -0xc3726955; ;; cannot upgrade critical parameter to non-critical...
}
if (expires >= expire_at) {
return -0xc16c7245; ;; proposal already exists
}
;; recompute price
price = pps * (expire_at - expires + 16384);
if (msg_value - price < (1 << 30)) {
return -0xf0617924; ;; need more money
}
;; update expiration time
vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expire_at, r_proposal, r_critical?, voters, weight_remaining, vset_id).store_slice(rest));
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
return price;
}
if (msg_value - price < (1 << 30)) {
return -0xf0617924; ;; need more money
}
;; obtain current validator set data
var (vset, total_weight, _) = get_current_vset();
int weight_remaining = muldiv(total_weight, 2, 3) + 1;
;; create new proposal
vote_dict~udict_set_builder(256, phash,
begin_pack_proposal_status(expire_at, proposal, critical?, null(), weight_remaining, vset.cell_hash())
.store_uint(max_tot_rounds, 8).store_uint(0, 16));
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
return price;
}
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
var cs = in_msg_cell.begin_parse();
var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
var s_addr = cs~load_msg_addr();
(int src_wc, int src_addr) = s_addr.parse_std_addr();
if ((src_wc + 1) | (flags & 1) | in_msg.slice_empty?()) {
;; source not in masterchain, or a bounced message, or a simple transfer
return ();
}
int tag = in_msg~load_uint(32);
int query_id = in_msg~load_uint(64);
if (tag == 0x4e565354) {
;; set next validator set
var vset = in_msg~load_ref();
in_msg.end_parse();
var elector_param = config_param(1);
var elector_addr = cell_null?(elector_param) ? -1 : elector_param.begin_parse().preload_uint(256);
var ok = false;
if (src_addr == elector_addr) {
;; message from elector smart contract
;; set next validator set
(var t_since, var t_until) = check_validator_set(vset);
var t = now();
ok = (t_since > t) & (t_until > t_since);
}
if (ok) {
set_conf_param(36, vset);
;; send confirmation
return send_confirmation(s_addr, query_id, 0xee764f4b);
} else {
return send_error(s_addr, query_id, 0xee764f6f);
}
}
if (tag == 0x6e565052) {
;; new voting proposal
var price = register_voting_proposal(cs, msg_value);
int mode = 64;
int ans_tag = - price;
if (price >= 0) {
;; ok, debit price
raw_reserve(price, 4);
ans_tag = 0xee565052;
mode = 128;
}
return send_answer(s_addr, query_id, ans_tag, mode);
}
;; if tag is non-zero and its higher bit is zero, throw an exception (the message is an unsupported query)
;; to bounce message back to sender
throw_unless(37, (tag == 0) | (tag & (1 << 31)));
;; do nothing for other internal messages
}
() recv_external(slice in_msg) impure { () recv_external(slice in_msg) impure {
var signature = in_msg~load_bits(512); var signature = in_msg~load_bits(512);
var cs = in_msg; var cs = in_msg;

View file

@ -201,8 +201,8 @@ smc1_addr config.minter_smc!
1000000000000 -17 of-cc 666666666666 239 of-cc cc+ config.to_mint! 1000000000000 -17 of-cc 666666666666 239 of-cc cc+ config.to_mint!
( 9 10 18 20 21 22 23 24 25 28 34 ) config.mandatory_params! ( 0 1 9 10 12 14 15 16 17 18 20 21 22 23 24 25 28 34 ) config.mandatory_params!
( -1000 -1001 9 10 32 34 36 ) config.critical_params! ( -1000 -1001 0 1 9 10 12 14 15 16 17 32 34 36 ) config.critical_params!
// [ min_tot_rounds max_tot_rounds min_wins max_losses min_store_sec max_store_sec bit_price cell_price ] // [ min_tot_rounds max_tot_rounds min_wins max_losses min_store_sec max_store_sec bit_price cell_price ]
// first for ordinary proposals, then for critical proposals // first for ordinary proposals, then for critical proposals

View file

@ -66,6 +66,13 @@ _ unpack_owner_info(slice cs) inline_ref {
return (root_i, 0, 0, in_msg); return (root_i, 0, 0, in_msg);
} }
(cell, ()) dec_flood(cell owner_infos, int creator_i) {
(slice owner_info, var found?) = owner_infos.udict_get?(8, creator_i);
(int public_key, int flood) = unpack_owner_info(owner_info);
owner_infos~udict_set_builder(8, creator_i, pack_owner_info(public_key, flood - 1));
return (owner_infos, ());
}
() try_init() impure inline_ref { () try_init() impure inline_ref {
;; first query without signatures is always accepted ;; first query without signatures is always accepted
(int wallet_id, int n, int k, int last_cleaned, cell owner_infos, cell pending_queries) = unpack_state(); (int wallet_id, int n, int k, int last_cleaned, cell owner_infos, cell pending_queries) = unpack_state();
@ -82,10 +89,7 @@ _ unpack_owner_info(slice cs) inline_ref {
send_raw_message(msg~load_ref(), mode); send_raw_message(msg~load_ref(), mode);
} }
pending_queries~udict_set_builder(64, query_id, begin_cell().store_int(0, 1)); pending_queries~udict_set_builder(64, query_id, begin_cell().store_int(0, 1));
owner_infos~dec_flood(creator_i);
(slice owner_info, var found?) = owner_infos.udict_get?(8, creator_i);
(int public_key, int flood) = unpack_owner_info(owner_info);
owner_infos~udict_set_builder(8, creator_i, pack_owner_info(public_key, flood - 1));
} else { } else {
pending_queries~udict_set_builder(64, query_id, begin_cell() pending_queries~udict_set_builder(64, query_id, begin_cell()
.store_uint(1, 1) .store_uint(1, 1)
@ -123,8 +127,8 @@ _ unpack_owner_info(slice cs) inline_ref {
last_cleaned -= last_cleaned == 0; last_cleaned -= last_cleaned == 0;
(slice owner_info, var found?) = owner_infos.udict_get?(8, root_i); (slice owner_info, var found?) = owner_infos.udict_get?(8, root_i);
(int public_key, int flood) = unpack_owner_info(owner_info);
throw_unless(31, found?); throw_unless(31, found?);
(int public_key, int flood) = unpack_owner_info(owner_info);
throw_unless(32, check_signature(root_hash, root_signature, public_key)); throw_unless(32, check_signature(root_hash, root_signature, public_key));
cell signatures = in_msg~load_dict(); cell signatures = in_msg~load_dict();
@ -154,11 +158,12 @@ _ unpack_owner_info(slice cs) inline_ref {
cnt_bits |= mask; cnt_bits |= mask;
cnt += 1; cnt += 1;
throw_if(41, ~ found? & (cnt < k) & (bound + ((60 * 60) << 32) > query_id));
set_gas_limit(100000); set_gas_limit(100000);
ifnot (found?) { ifnot (found?) {
owner_infos~udict_set_builder(8, root_i, pack_owner_info(public_key, flood)); owner_infos~udict_set_builder(8, root_i, pack_owner_info(public_key, flood));
throw_if(41, (cnt < k) & (bound + ((60 * 60) << 32) > query_id));
} }
(pending_queries, owner_infos) = update_pending_queries(pending_queries, owner_infos, msg, query_id, creator_i, cnt, cnt_bits, n, k); (pending_queries, owner_infos) = update_pending_queries(pending_queries, owner_infos, msg, query_id, creator_i, cnt, cnt_bits, n, k);
@ -178,12 +183,15 @@ _ unpack_owner_info(slice cs) inline_ref {
bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago
int old_last_cleaned = last_cleaned; int old_last_cleaned = last_cleaned;
do { do {
var (pending_queries', i, _, f) = pending_queries.udict_delete_get_min(64); var (pending_queries', i, query, f) = pending_queries.udict_delete_get_min(64);
f~touch(); f~touch();
if (f) { if (f) {
f = (i < bound); f = (i < bound);
} }
if (f) { if (f) {
if (query~load_int(1)) {
owner_infos~dec_flood(query~load_uint(8));
}
pending_queries = pending_queries'; pending_queries = pending_queries';
last_cleaned = i; last_cleaned = i;
need_save = -1; need_save = -1;

View file

@ -64,6 +64,8 @@ cont bless(slice s) impure asm "BLESS";
int min(int x, int y) asm "MIN"; int min(int x, int y) asm "MIN";
int max(int x, int y) asm "MAX"; int max(int x, int y) asm "MAX";
(int, int) minmax(int x, int y) asm "MINMAX";
int abs(int x) asm "ABS";
slice begin_parse(cell c) asm "CTOS"; slice begin_parse(cell c) asm "CTOS";
() end_parse(slice s) impure asm "ENDS"; () end_parse(slice s) impure asm "ENDS";

View file

@ -44,7 +44,7 @@ td::Ref<vm::Stack> prepare_vm_stack(td::Ref<vm::CellSlice> body) {
return stack_ref; return stack_ref;
} }
td::Ref<vm::Tuple> prepare_vm_c7() { td::Ref<vm::Tuple> prepare_vm_c7(td::uint32 now) {
// TODO: fix initialization of c7 // TODO: fix initialization of c7
td::BitArray<256> rand_seed; td::BitArray<256> rand_seed;
rand_seed.as_slice().fill(0); rand_seed.as_slice().fill(0);
@ -54,7 +54,7 @@ td::Ref<vm::Tuple> prepare_vm_c7() {
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
td::make_refint(0), // actions:Integer td::make_refint(0), // actions:Integer
td::make_refint(0), // msgs_sent:Integer td::make_refint(0), // msgs_sent:Integer
td::make_refint(0), // unixtime:Integer td::make_refint(now), // unixtime:Integer
td::make_refint(0), // block_lt:Integer td::make_refint(0), // block_lt:Integer
td::make_refint(0), // trans_lt:Integer td::make_refint(0), // trans_lt:Integer
std::move(rand_seed_int), // rand_seed:Integer std::move(rand_seed_int), // rand_seed:Integer
@ -166,8 +166,12 @@ td::Ref<vm::Cell> SmartContract::get_init_state() const {
} }
SmartContract::Answer SmartContract::run_method(Args args) { SmartContract::Answer SmartContract::run_method(Args args) {
td::uint32 now = 0;
if (args.now) {
now = args.now.unwrap();
}
if (!args.c7) { if (!args.c7) {
args.c7 = prepare_vm_c7(); args.c7 = prepare_vm_c7(now);
} }
if (!args.limits) { if (!args.limits) {
args.limits = vm::GasLimits{(long long)0, (long long)1000000, (long long)10000}; args.limits = vm::GasLimits{(long long)0, (long long)1000000, (long long)10000};
@ -182,8 +186,12 @@ SmartContract::Answer SmartContract::run_method(Args args) {
} }
SmartContract::Answer SmartContract::run_get_method(Args args) const { SmartContract::Answer SmartContract::run_get_method(Args args) const {
td::uint32 now = 0;
if (args.now) {
now = args.now.unwrap();
}
if (!args.c7) { if (!args.c7) {
args.c7 = prepare_vm_c7(); args.c7 = prepare_vm_c7(now);
} }
if (!args.limits) { if (!args.limits) {
args.limits = vm::GasLimits{1000000}; args.limits = vm::GasLimits{1000000};

View file

@ -55,6 +55,7 @@ class SmartContract : public td::CntObject {
td::optional<vm::GasLimits> limits; td::optional<vm::GasLimits> limits;
td::optional<td::Ref<vm::Tuple>> c7; td::optional<td::Ref<vm::Tuple>> c7;
td::optional<td::Ref<vm::Stack>> stack; td::optional<td::Ref<vm::Stack>> stack;
td::optional<td::int32> now;
bool ignore_chksig{false}; bool ignore_chksig{false};
Args() { Args() {
@ -62,6 +63,10 @@ class SmartContract : public td::CntObject {
Args(std::initializer_list<vm::StackEntry> stack) Args(std::initializer_list<vm::StackEntry> stack)
: stack(td::Ref<vm::Stack>(true, std::vector<vm::StackEntry>(std::move(stack)))) { : stack(td::Ref<vm::Stack>(true, std::vector<vm::StackEntry>(std::move(stack)))) {
} }
Args&& set_now(int now) {
this->now = now;
return std::move(*this);
}
Args&& set_method_id(td::Slice method_name) { Args&& set_method_id(td::Slice method_name) {
unsigned crc = td::crc16(method_name); unsigned crc = td::crc16(method_name);
return set_method_id((crc & 0xffff) | 0x10000); return set_method_id((crc & 0xffff) | 0x10000);

View file

@ -583,16 +583,58 @@ TEST(Smartcon, Multisig) {
wallet_id, td::transform(keys, [](auto& key) { return key.get_public_key().ok().as_octet_string(); }), k); wallet_id, td::transform(keys, [](auto& key) { return key.get_public_key().ok().as_octet_string(); }), k);
auto ms = ton::MultisigWallet::create(init_state); auto ms = ton::MultisigWallet::create(init_state);
td::uint64 query_id = 123 | ((100 * 60ull) << 32); td::uint32 now = 0;
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize()); auto args = [&now]() -> ton::SmartContract::Args { return ton::SmartContract::Args().set_now(now); };
// first empty query (init)
CHECK(ms.write().send_external_message(vm::CellBuilder().finalize()).code == 0);
// first empty query
CHECK(ms.write().send_external_message(vm::CellBuilder().finalize()).code > 0);
// first empty query (init)
CHECK(ms.write().send_external_message(vm::CellBuilder().finalize(), args()).code == 0);
// first empty query
CHECK(ms.write().send_external_message(vm::CellBuilder().finalize(), args()).code > 0);
{
td::uint64 query_id = 123 | ((now + 10 * 60ull) << 32);
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize());
auto query = qb.create(0, keys[0]);
auto res = ms.write().send_external_message(query, args());
CHECK(!res.accepted);
CHECK(res.code == 41);
}
{
for (int i = 1; i <= 11; i++) {
td::uint64 query_id = i | ((now + 100 * 60ull) << 32);
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize());
auto query = qb.create(5, keys[5]);
auto res = ms.write().send_external_message(query, args());
if (i <= 10) {
CHECK(res.accepted);
} else {
CHECK(!res.accepted);
}
}
now += 100 * 60 + 100;
{
td::uint64 query_id = 200 | ((now + 100 * 60ull) << 32);
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize());
auto query = qb.create(6, keys[6]);
auto res = ms.write().send_external_message(query, args());
CHECK(res.accepted);
}
{
td::uint64 query_id = 300 | ((now + 100 * 60ull) << 32);
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize());
auto query = qb.create(5, keys[5]);
auto res = ms.write().send_external_message(query, args());
CHECK(res.accepted);
}
}
td::uint64 query_id = 123 | ((now + 100 * 60ull) << 32);
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize());
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
auto query = qb.create(i, keys[i]); auto query = qb.create(i, keys[i]);
auto ans = ms.write().send_external_message(query); auto ans = ms.write().send_external_message(query, args());
LOG(INFO) << "CODE: " << ans.code; LOG(INFO) << "CODE: " << ans.code;
LOG(INFO) << "GAS: " << ans.gas_used; LOG(INFO) << "GAS: " << ans.gas_used;
} }
@ -602,12 +644,12 @@ TEST(Smartcon, Multisig) {
auto query = qb.create(49, keys[49]); auto query = qb.create(49, keys[49]);
CHECK(ms->get_n_k() == std::make_pair(n, k)); CHECK(ms->get_n_k() == std::make_pair(n, k));
auto ans = ms.write().send_external_message(query); auto ans = ms.write().send_external_message(query, args());
LOG(INFO) << "CODE: " << ans.code; LOG(INFO) << "CODE: " << ans.code;
LOG(INFO) << "GAS: " << ans.gas_used; LOG(INFO) << "GAS: " << ans.gas_used;
CHECK(ans.success); CHECK(ans.success);
ASSERT_EQ(0, ms->processed(query_id)); ASSERT_EQ(0, ms->processed(query_id));
CHECK(ms.write().send_external_message(query).code > 0); CHECK(ms.write().send_external_message(query, args()).code > 0);
ASSERT_EQ(0, ms->processed(query_id)); ASSERT_EQ(0, ms->processed(query_id));
{ {
@ -618,7 +660,7 @@ TEST(Smartcon, Multisig) {
query = qb.create(99, keys[99]); query = qb.create(99, keys[99]);
} }
ans = ms.write().send_external_message(query); ans = ms.write().send_external_message(query, args());
LOG(INFO) << "CODE: " << ans.code; LOG(INFO) << "CODE: " << ans.code;
LOG(INFO) << "GAS: " << ans.gas_used; LOG(INFO) << "GAS: " << ans.gas_used;
ASSERT_EQ(-1, ms->processed(query_id)); ASSERT_EQ(-1, ms->processed(query_id));

View file

@ -789,7 +789,7 @@ void register_shift_logic_ops(OpcodeTable& cp0) {
int exec_minmax(VmState* st, int mode) { int exec_minmax(VmState* st, int mode) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute MINMAXOP " << mode; VM_LOG(st) << "execute " << (mode & 1 ? "Q" : "") << (mode & 2 ? "MIN" : "") << (mode & 4 ? "MAX" : "");
stack.check_underflow(2); stack.check_underflow(2);
auto x = stack.pop_int(); auto x = stack.pop_int();
auto y = stack.pop_int(); auto y = stack.pop_int();
@ -811,7 +811,7 @@ int exec_minmax(VmState* st, int mode) {
int exec_abs(VmState* st, bool quiet) { int exec_abs(VmState* st, bool quiet) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute ABS"; VM_LOG(st) << "execute " << (quiet ? "QABS" : "ABS");
stack.check_underflow(1); stack.check_underflow(1);
auto x = stack.pop_int(); auto x = stack.pop_int();
if (x->is_valid() && x->sgn() < 0) { if (x->is_valid() && x->sgn() < 0) {

View file

@ -58,14 +58,27 @@ std::string dump_push_ref(CellSlice& cs, unsigned args, int pfx_bits, std::strin
return ""; return "";
} }
cs.advance(pfx_bits); cs.advance(pfx_bits);
cs.advance_refs(1); auto cell = cs.fetch_ref();
return name; return name + " (" + cell->get_hash().to_hex() + ")";
} }
int compute_len_push_ref(const CellSlice& cs, unsigned args, int pfx_bits) { int compute_len_push_ref(const CellSlice& cs, unsigned args, int pfx_bits) {
return cs.have_refs(1) ? (0x10000 + pfx_bits) : 0; return cs.have_refs(1) ? (0x10000 + pfx_bits) : 0;
} }
std::string dump_push_ref2(CellSlice& cs, unsigned args, int pfx_bits, std::string name) {
if (!cs.have_refs(2)) {
return "";
}
cs.advance(pfx_bits);
auto cell1 = cs.fetch_ref(), cell2 = cs.fetch_ref();
return name + " (" + cell1->get_hash().to_hex() + ") (" + cell2->get_hash().to_hex() + ")";
}
int compute_len_push_ref2(const CellSlice& cs, unsigned args, int pfx_bits) {
return cs.have_refs(2) ? (0x20000 + pfx_bits) : 0;
}
int exec_push_slice_common(VmState* st, CellSlice& cs, unsigned data_bits, unsigned refs, int pfx_bits) { int exec_push_slice_common(VmState* st, CellSlice& cs, unsigned data_bits, unsigned refs, int pfx_bits) {
if (!cs.have(pfx_bits + data_bits)) { if (!cs.have(pfx_bits + data_bits)) {
throw VmError{Excno::inv_opcode, "not enough data bits for a PUSHSLICE instruction"}; throw VmError{Excno::inv_opcode, "not enough data bits for a PUSHSLICE instruction"};

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
#include "vm/cellslice.h" #include "vm/cellslice.h"
@ -28,4 +28,7 @@ void register_cell_ops(OpcodeTable &cp0);
std::string dump_push_ref(CellSlice &cs, unsigned args, int pfx_bits, std::string name); std::string dump_push_ref(CellSlice &cs, unsigned args, int pfx_bits, std::string name);
int compute_len_push_ref(const CellSlice &cs, unsigned args, int pfx_bits); int compute_len_push_ref(const CellSlice &cs, unsigned args, int pfx_bits);
std::string dump_push_ref2(CellSlice &cs, unsigned args, int pfx_bits, std::string name);
int compute_len_push_ref2(const CellSlice &cs, unsigned args, int pfx_bits);
} // namespace vm } // namespace vm

View file

@ -26,10 +26,12 @@
#include "vm/excno.hpp" #include "vm/excno.hpp"
#include "vm/vm.h" #include "vm/vm.h"
using namespace std::literals::string_literals;
namespace vm { namespace vm {
int exec_execute(VmState* st) { int exec_execute(VmState* st) {
VM_LOG(st) << "execute EXECUTE\n"; VM_LOG(st) << "execute EXECUTE";
auto cont = st->get_stack().pop_cont(); auto cont = st->get_stack().pop_cont();
return st->call(std::move(cont)); return st->call(std::move(cont));
} }
@ -150,12 +152,58 @@ int exec_callcc_varargs(VmState* st) {
int exec_do_with_ref(VmState* st, CellSlice& cs, int pfx_bits, const std::function<int(VmState*, Ref<OrdCont>)>& func, int exec_do_with_ref(VmState* st, CellSlice& cs, int pfx_bits, const std::function<int(VmState*, Ref<OrdCont>)>& func,
const char* name) { const char* name) {
if (!cs.have_refs(1)) { if (!cs.have_refs(1)) {
throw VmError{Excno::inv_opcode, "no references left for a CALLREF instruction"}; throw VmError{Excno::inv_opcode, "no references left for a "s + name + " instruction"};
} }
cs.advance(pfx_bits); cs.advance(pfx_bits);
auto cell = cs.fetch_ref(); auto cell = cs.fetch_ref();
VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")"; VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")";
return func(st, Ref<OrdCont>{true, load_cell_slice_ref(std::move(cell)), st->get_cp()}); return func(st, st->ref_to_cont(std::move(cell)));
}
int exec_do_with_cell(VmState* st, CellSlice& cs, int pfx_bits, const std::function<int(VmState*, Ref<Cell>)>& func,
const char* name) {
if (!cs.have_refs(1)) {
throw VmError{Excno::inv_opcode, "no references left for a "s + name + " instruction"};
}
cs.advance(pfx_bits);
auto cell = cs.fetch_ref();
VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")";
return func(st, std::move(cell));
}
int exec_ifelse_ref(VmState* st, CellSlice& cs, int pfx_bits, bool mode) {
const char* name = mode ? "IFREFELSE" : "IFELSEREF";
if (!cs.have_refs(1)) {
throw VmError{Excno::inv_opcode, "no references left for a "s + name + " instruction"};
}
cs.advance(pfx_bits);
auto cell = cs.fetch_ref();
Stack& stack = st->get_stack();
VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")";
stack.check_underflow(2);
auto cont = stack.pop_cont();
if (stack.pop_bool() == mode) {
cont = st->ref_to_cont(std::move(cell));
} else {
cell.clear();
}
return st->call(std::move(cont));
}
int exec_ifref_elseref(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) {
if (!cs.have_refs(2)) {
throw VmError{Excno::inv_opcode, "no references left for a IFREFELSEREF instruction"};
}
cs.advance(pfx_bits);
auto cell1 = cs.fetch_ref(), cell2 = cs.fetch_ref();
Stack& stack = st->get_stack();
VM_LOG(st) << "execute IFREFELSEREF (" << cell1->get_hash().to_hex() << ") (" << cell2->get_hash().to_hex() << ")";
if (!stack.pop_bool()) {
cell1 = std::move(cell2);
} else {
cell2.clear();
}
return st->call(st->ref_to_cont(std::move(cell1)));
} }
int exec_ret_data(VmState* st) { int exec_ret_data(VmState* st) {
@ -349,7 +397,7 @@ int exec_if_bit_jmpref(VmState* st, CellSlice& cs, unsigned args, int pfx_bits)
bool val = x->get_bit(bit); bool val = x->get_bit(bit);
stack.push_int(std::move(x)); stack.push_int(std::move(x));
if (val ^ negate) { if (val ^ negate) {
return st->jump(Ref<OrdCont>{true, load_cell_slice_ref(std::move(cell)), st->get_cp()}); return st->jump(st->ref_to_cont(std::move(cell)));
} }
return 0; return 0;
} }
@ -365,66 +413,72 @@ std::string dump_if_bit_jmpref(CellSlice& cs, unsigned args, int pfx_bits) {
return os.str(); return os.str();
} }
int exec_repeat(VmState* st) { int exec_repeat(VmState* st, bool brk) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute REPEAT\n"; VM_LOG(st) << "execute REPEAT" << (brk ? "BRK" : "");
stack.check_underflow(2); stack.check_underflow(2);
auto cont = stack.pop_cont(); auto cont = stack.pop_cont();
int c = stack.pop_smallint_range(0x7fffffff, 0x80000000); int c = stack.pop_smallint_range(0x7fffffff, 0x80000000);
if (c <= 0) { if (c <= 0) {
return 0; return 0;
} }
return st->repeat(std::move(cont), st->extract_cc(1), c); return st->repeat(std::move(cont), st->c1_envelope_if(brk, st->extract_cc(1)), c);
} }
int exec_repeat_end(VmState* st) { int exec_repeat_end(VmState* st, bool brk) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute REPEATEND\n"; VM_LOG(st) << "execute REPEATEND" << (brk ? "BRK" : "");
stack.check_underflow(1); stack.check_underflow(1);
int c = stack.pop_smallint_range(0x7fffffff, 0x80000000); int c = stack.pop_smallint_range(0x7fffffff, 0x80000000);
if (c <= 0) { if (c <= 0) {
return st->ret(); return st->ret();
} }
auto cont = st->extract_cc(0); auto cont = st->extract_cc(0);
return st->repeat(std::move(cont), st->get_c0(), c); return st->repeat(std::move(cont), st->c1_envelope_if(brk, st->get_c0()), c);
} }
int exec_until(VmState* st) { int exec_until(VmState* st, bool brk) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute UNTIL\n"; VM_LOG(st) << "execute UNTIL" << (brk ? "BRK" : "");
auto cont = stack.pop_cont(); auto cont = stack.pop_cont();
return st->until(std::move(cont), st->extract_cc(1)); return st->until(std::move(cont), st->c1_envelope_if(brk, st->extract_cc(1)));
} }
int exec_until_end(VmState* st) { int exec_until_end(VmState* st, bool brk) {
VM_LOG(st) << "execute UNTILEND\n"; VM_LOG(st) << "execute UNTILEND" << (brk ? "BRK" : "");
auto cont = st->extract_cc(0); auto cont = st->extract_cc(0);
return st->until(std::move(cont), st->get_c0()); return st->until(std::move(cont), st->c1_envelope_if(brk, st->get_c0()));
} }
int exec_while(VmState* st) { int exec_while(VmState* st, bool brk) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute WHILE\n"; VM_LOG(st) << "execute WHILE" << (brk ? "BRK" : "");
stack.check_underflow(2); stack.check_underflow(2);
auto body = stack.pop_cont(); auto body = stack.pop_cont();
auto cond = stack.pop_cont(); auto cond = stack.pop_cont();
return st->loop_while(std::move(cond), std::move(body), st->extract_cc(1)); return st->loop_while(std::move(cond), std::move(body), st->c1_envelope_if(brk, st->extract_cc(1)));
} }
int exec_while_end(VmState* st) { int exec_while_end(VmState* st, bool brk) {
VM_LOG(st) << "execute WHILEEND\n"; VM_LOG(st) << "execute WHILEEND" << (brk ? "BRK" : "");
auto cond = st->get_stack().pop_cont(); auto cond = st->get_stack().pop_cont();
auto body = st->extract_cc(0); auto body = st->extract_cc(0);
return st->loop_while(std::move(cond), std::move(body), st->get_c0()); return st->loop_while(std::move(cond), std::move(body), st->c1_envelope_if(brk, st->get_c0()));
} }
int exec_again(VmState* st) { int exec_again(VmState* st, bool brk) {
VM_LOG(st) << "execute AGAIN\n"; VM_LOG(st) << "execute AGAIN" << (brk ? "BRK" : "");
if (brk) {
st->set_c1(st->extract_cc(3));
}
return st->again(st->get_stack().pop_cont()); return st->again(st->get_stack().pop_cont());
} }
int exec_again_end(VmState* st) { int exec_again_end(VmState* st, bool brk) {
VM_LOG(st) << "execute AGAINEND\n"; VM_LOG(st) << "execute AGAINEND" << (brk ? "BRK" : "");
if (brk) {
st->c1_save_set();
}
return st->again(st->extract_cc(0)); return st->again(st->extract_cc(0));
} }
@ -437,44 +491,70 @@ void register_continuation_cond_loop_ops(OpcodeTable& cp0) {
.insert(OpcodeInstr::mksimple(0xe0, 8, "IFJMP", exec_if_jmp)) .insert(OpcodeInstr::mksimple(0xe0, 8, "IFJMP", exec_if_jmp))
.insert(OpcodeInstr::mksimple(0xe1, 8, "IFNOTJMP", exec_ifnot_jmp)) .insert(OpcodeInstr::mksimple(0xe1, 8, "IFNOTJMP", exec_ifnot_jmp))
.insert(OpcodeInstr::mksimple(0xe2, 8, "IFELSE", exec_if_else)) .insert(OpcodeInstr::mksimple(0xe2, 8, "IFELSE", exec_if_else))
.insert(OpcodeInstr::mkext( .insert(OpcodeInstr::mkext(0xe300, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREF"),
0xe300, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREF"), std::bind(exec_do_with_cell, _1, _2, _4,
std::bind(exec_do_with_ref, _1, _2, _4, [](auto st, auto cell) {
[](auto st, auto cont) { return st->get_stack().pop_bool() ? st->call(std::move(cont)) : 0; }, return st->get_stack().pop_bool()
"IFREF"), ? st->call(st->ref_to_cont(std::move(cell)))
compute_len_push_ref)) : 0;
.insert(OpcodeInstr::mkext( },
0xe301, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTREF"), "IFREF"),
std::bind(exec_do_with_ref, _1, _2, _4, compute_len_push_ref))
[](auto st, auto cont) { return st->get_stack().pop_bool() ? 0 : st->call(std::move(cont)); }, .insert(OpcodeInstr::mkext(0xe301, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTREF"),
"IFNOTREF"), std::bind(exec_do_with_cell, _1, _2, _4,
compute_len_push_ref)) [](auto st, auto cell) {
.insert(OpcodeInstr::mkext( return st->get_stack().pop_bool()
0xe302, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFJMPREF"), ? 0
std::bind(exec_do_with_ref, _1, _2, _4, : st->call(st->ref_to_cont(std::move(cell)));
[](auto st, auto cont) { return st->get_stack().pop_bool() ? st->jump(std::move(cont)) : 0; }, },
"IFJMPREF"), "IFNOTREF"),
compute_len_push_ref)) compute_len_push_ref))
.insert(OpcodeInstr::mkext( .insert(OpcodeInstr::mkext(0xe302, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFJMPREF"),
0xe303, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTJMPREF"), std::bind(exec_do_with_cell, _1, _2, _4,
std::bind(exec_do_with_ref, _1, _2, _4, [](auto st, auto cell) {
[](auto st, auto cont) { return st->get_stack().pop_bool() ? 0 : st->jump(std::move(cont)); }, return st->get_stack().pop_bool()
"IFNOTJMPREF"), ? st->jump(st->ref_to_cont(std::move(cell)))
compute_len_push_ref)) : 0;
},
"IFJMPREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe303, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTJMPREF"),
std::bind(exec_do_with_cell, _1, _2, _4,
[](auto st, auto cell) {
return st->get_stack().pop_bool()
? 0
: st->jump(st->ref_to_cont(std::move(cell)));
},
"IFNOTJMPREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mksimple(0xe304, 16, "CONDSEL", exec_condsel)) .insert(OpcodeInstr::mksimple(0xe304, 16, "CONDSEL", exec_condsel))
.insert(OpcodeInstr::mksimple(0xe305, 16, "CONDSELCHK", exec_condsel_chk)) .insert(OpcodeInstr::mksimple(0xe305, 16, "CONDSELCHK", exec_condsel_chk))
.insert(OpcodeInstr::mksimple(0xe308, 16, "IFRETALT", exec_ifretalt)) .insert(OpcodeInstr::mksimple(0xe308, 16, "IFRETALT", exec_ifretalt))
.insert(OpcodeInstr::mksimple(0xe309, 16, "IFNOTRETALT", exec_ifnotretalt)) .insert(OpcodeInstr::mksimple(0xe309, 16, "IFNOTRETALT", exec_ifnotretalt))
.insert(OpcodeInstr::mkext(0xe30d, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREFELSE"),
std::bind(exec_ifelse_ref, _1, _2, _4, true), compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe30e, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFELSEREF"),
std::bind(exec_ifelse_ref, _1, _2, _4, false), compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe30f, 16, 0, std::bind(dump_push_ref2, _1, _2, _3, "IFREFELSEREF"),
exec_ifref_elseref, compute_len_push_ref2))
.insert(OpcodeInstr::mkfixed(0xe380 >> 6, 10, 6, dump_if_bit_jmp, exec_if_bit_jmp)) .insert(OpcodeInstr::mkfixed(0xe380 >> 6, 10, 6, dump_if_bit_jmp, exec_if_bit_jmp))
.insert(OpcodeInstr::mkext(0xe3c0 >> 6, 10, 6, dump_if_bit_jmpref, exec_if_bit_jmpref, compute_len_push_ref)) .insert(OpcodeInstr::mkext(0xe3c0 >> 6, 10, 6, dump_if_bit_jmpref, exec_if_bit_jmpref, compute_len_push_ref))
.insert(OpcodeInstr::mksimple(0xe4, 8, "REPEAT", exec_repeat)) .insert(OpcodeInstr::mksimple(0xe4, 8, "REPEAT", std::bind(exec_repeat, _1, false)))
.insert(OpcodeInstr::mksimple(0xe5, 8, "REPEATEND", exec_repeat_end)) .insert(OpcodeInstr::mksimple(0xe5, 8, "REPEATEND", std::bind(exec_repeat_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xe6, 8, "UNTIL", exec_until)) .insert(OpcodeInstr::mksimple(0xe6, 8, "UNTIL", std::bind(exec_until, _1, false)))
.insert(OpcodeInstr::mksimple(0xe7, 8, "UNTILEND", exec_until_end)) .insert(OpcodeInstr::mksimple(0xe7, 8, "UNTILEND", std::bind(exec_until_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xe8, 8, "WHILE", exec_while)) .insert(OpcodeInstr::mksimple(0xe8, 8, "WHILE", std::bind(exec_while, _1, false)))
.insert(OpcodeInstr::mksimple(0xe9, 8, "WHILEEND", exec_while_end)) .insert(OpcodeInstr::mksimple(0xe9, 8, "WHILEEND", std::bind(exec_while_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xea, 8, "AGAIN", exec_again)) .insert(OpcodeInstr::mksimple(0xea, 8, "AGAIN", std::bind(exec_again, _1, false)))
.insert(OpcodeInstr::mksimple(0xeb, 8, "AGAINEND", exec_again_end)); .insert(OpcodeInstr::mksimple(0xeb, 8, "AGAINEND", std::bind(exec_again_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xe314, 16, "REPEATBRK", std::bind(exec_repeat, _1, true)))
.insert(OpcodeInstr::mksimple(0xe315, 16, "REPEATENDBRK", std::bind(exec_repeat_end, _1, true)))
.insert(OpcodeInstr::mksimple(0xe316, 16, "UNTILBRK", std::bind(exec_until, _1, true)))
.insert(OpcodeInstr::mksimple(0xe317, 16, "UNTILENDBRK", std::bind(exec_until_end, _1, true)))
.insert(OpcodeInstr::mksimple(0xe318, 16, "WHILEBRK", std::bind(exec_while, _1, true)))
.insert(OpcodeInstr::mksimple(0xe319, 16, "WHILEENDBRK", std::bind(exec_while_end, _1, true)))
.insert(OpcodeInstr::mksimple(0xe31a, 16, "AGAINBRK", std::bind(exec_again, _1, true)))
.insert(OpcodeInstr::mksimple(0xe31b, 16, "AGAINENDBRK", std::bind(exec_again_end, _1, true)));
} }
int exec_setcontargs_common(VmState* st, int copy, int more) { int exec_setcontargs_common(VmState* st, int copy, int more) {
@ -706,6 +786,17 @@ int exec_save_ctr(VmState* st, unsigned args) {
return 0; return 0;
} }
int exec_samealt(VmState* st, bool save) {
VM_LOG(st) << "execute SAMEALT" << (save ? "SAVE" : "");
auto c0 = st->get_c0();
if (save) {
force_cregs(c0)->define_c1(st->get_c1());
st->set_c0(c0);
}
st->set_c1(std::move(c0));
return 0;
}
int exec_savealt_ctr(VmState* st, unsigned args) { int exec_savealt_ctr(VmState* st, unsigned args) {
unsigned idx = args & 15; unsigned idx = args & 15;
VM_LOG(st) << "execute SAVEALTCTR c" << idx; VM_LOG(st) << "execute SAVEALTCTR c" << idx;
@ -883,6 +974,8 @@ void register_continuation_change_ops(OpcodeTable& cp0) {
.insert(OpcodeInstr::mksimple(0xedf7, 16, "THENRETALT", exec_thenret_alt)) .insert(OpcodeInstr::mksimple(0xedf7, 16, "THENRETALT", exec_thenret_alt))
.insert(OpcodeInstr::mksimple(0xedf8, 16, "INVERT", exec_invert)) .insert(OpcodeInstr::mksimple(0xedf8, 16, "INVERT", exec_invert))
.insert(OpcodeInstr::mksimple(0xedf9, 16, "BOOLEVAL", exec_booleval)) .insert(OpcodeInstr::mksimple(0xedf9, 16, "BOOLEVAL", exec_booleval))
.insert(OpcodeInstr::mksimple(0xedfa, 16, "SAMEALT", std::bind(exec_samealt, _1, false)))
.insert(OpcodeInstr::mksimple(0xedfb, 16, "SAMEALTSAVE", std::bind(exec_samealt, _1, true)))
.insert(OpcodeInstr::mkfixed(0xee, 8, 8, std::bind(dump_setcontargs, _1, _2, "BLESSARGS"), exec_bless_args)); .insert(OpcodeInstr::mkfixed(0xee, 8, 8, std::bind(dump_setcontargs, _1, _2, "BLESSARGS"), exec_bless_args));
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -45,6 +45,7 @@ const char* get_exception_msg(Excno exc_no);
class VmError { class VmError {
Excno exc_no; Excno exc_no;
bool msg_alloc = false;
const char* msg; const char* msg;
long long arg; long long arg;
@ -55,6 +56,18 @@ class VmError {
} }
VmError(Excno _excno, const char* _msg, long long _arg) : exc_no(_excno), msg(_msg), arg(_arg) { VmError(Excno _excno, const char* _msg, long long _arg) : exc_no(_excno), msg(_msg), arg(_arg) {
} }
VmError(Excno _excno, std::string _msg, long long _arg = 0) : exc_no(_excno), msg_alloc(true), arg(_arg) {
msg_alloc = true;
char* p = (char*)malloc(_msg.size() + 1);
memcpy(p, _msg.data(), _msg.size());
p[_msg.size()] = 0;
msg = p;
}
~VmError() {
if (msg_alloc) {
free(const_cast<char*>(msg));
}
}
int get_errno() const { int get_errno() const {
return static_cast<int>(exc_no); return static_cast<int>(exc_no);
} }

View file

@ -333,6 +333,22 @@ int VmState::ret_alt(int ret_args) {
return jump(std::move(cont), ret_args); return jump(std::move(cont), ret_args);
} }
Ref<Continuation> VmState::c1_envelope(Ref<Continuation> cont, bool save) {
if (save) {
force_cregs(cont)->define_c1(cr.c[1]);
force_cregs(cont)->define_c0(cr.c[0]);
}
set_c1(cont);
return cont;
}
void VmState::c1_save_set(bool save) {
if (save) {
force_cregs(cr.c[0])->define_c1(cr.c[1]);
}
set_c1(cr.c[0]);
}
Ref<OrdCont> VmState::extract_cc(int save_cr, int stack_copy, int cc_args) { Ref<OrdCont> VmState::extract_cc(int save_cr, int stack_copy, int cc_args) {
Ref<Stack> new_stk; Ref<Stack> new_stk;
if (stack_copy < 0 || stack_copy == stack->depth()) { if (stack_copy < 0 || stack_copy == stack->depth()) {

View file

@ -297,6 +297,11 @@ class VmState final : public VmStateInterface {
int throw_exception(int excno, StackEntry&& arg); int throw_exception(int excno, StackEntry&& arg);
int throw_exception(int excno); int throw_exception(int excno);
Ref<OrdCont> extract_cc(int save_cr = 1, int stack_copy = -1, int cc_args = -1); Ref<OrdCont> extract_cc(int save_cr = 1, int stack_copy = -1, int cc_args = -1);
Ref<Continuation> c1_envelope(Ref<Continuation> cont, bool save = true);
Ref<Continuation> c1_envelope_if(bool cond, Ref<Continuation> cont, bool save = true) {
return cond ? c1_envelope(std::move(cont), save) : std::move(cont);
}
void c1_save_set(bool save = true);
void fatal(void) const { void fatal(void) const {
throw VmFatal{}; throw VmFatal{};
} }
@ -313,6 +318,9 @@ class VmState final : public VmStateInterface {
bool get_chksig_always_succeed() const { bool get_chksig_always_succeed() const {
return chksig_always_succeed; return chksig_always_succeed;
} }
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
}
private: private:
void init_cregs(bool same_c3 = false, bool push_0 = true); void init_cregs(bool same_c3 = false, bool push_0 = true);

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "dht-server.hpp" #include "dht-server.hpp"
@ -70,8 +70,12 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
[&](const ton::ton_api::engine_addr &obj) { [&](const ton::ton_api::engine_addr &obj) {
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast<td::uint16>(obj.port_)).ensure(); in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast<td::uint16>(obj.port_)).ensure();
out_ip = in_ip; out_ip = in_ip;
categories = obj.categories_; for (auto &cat : obj.categories_) {
priority_categories = obj.priority_categories_; categories.push_back(td::narrow_cast<td::uint8>(cat));
}
for (auto &cat : obj.priority_categories_) {
priority_categories.push_back(td::narrow_cast<td::uint8>(cat));
}
}, },
[&](const ton::ton_api::engine_addrProxy &obj) { [&](const ton::ton_api::engine_addrProxy &obj) {
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.in_ip_), static_cast<td::uint16>(obj.in_port_)) in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.in_ip_), static_cast<td::uint16>(obj.in_port_))
@ -82,15 +86,19 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
auto R = ton::adnl::AdnlProxy::create(*obj.proxy_type_.get()); auto R = ton::adnl::AdnlProxy::create(*obj.proxy_type_.get());
R.ensure(); R.ensure();
proxy = R.move_as_ok(); proxy = R.move_as_ok();
categories = obj.categories_; for (auto &cat : obj.categories_) {
priority_categories = obj.priority_categories_; categories.push_back(td::narrow_cast<td::uint8>(cat));
}
for (auto &cat : obj.priority_categories_) {
priority_categories.push_back(td::narrow_cast<td::uint8>(cat));
}
} }
})); }));
config_add_network_addr(in_ip, out_ip, std::move(proxy), categories, priority_categories).ensure(); config_add_network_addr(in_ip, out_ip, std::move(proxy), categories, priority_categories).ensure();
} }
for (auto &adnl : config.adnl_) { for (auto &adnl : config.adnl_) {
config_add_adnl_addr(ton::PublicKeyHash{adnl->id_}, adnl->category_).ensure(); config_add_adnl_addr(ton::PublicKeyHash{adnl->id_}, td::narrow_cast<td::uint8>(adnl->category_)).ensure();
} }
for (auto &dht : config.dht_) { for (auto &dht : config.dht_) {
config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure(); config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure();
@ -448,7 +456,7 @@ void DhtServer::load_empty_local_config(td::Promise<td::Unit> promise) {
ig.add_promise(std::move(ret_promise)); ig.add_promise(std::move(ret_promise));
for (auto &addr : addrs_) { for (auto &addr : addrs_) {
config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int32>{0, 1, 2, 3}, std::vector<td::int32>{}) config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int8>{0, 1, 2, 3}, std::vector<td::int8>{})
.ensure(); .ensure();
} }
@ -501,7 +509,7 @@ void DhtServer::load_local_config(td::Promise<td::Unit> promise) {
ig.add_promise(std::move(ret_promise)); ig.add_promise(std::move(ret_promise));
for (auto &addr : addrs_) { for (auto &addr : addrs_) {
config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int32>{0, 1, 2, 3}, std::vector<td::int32>{}) config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int8>{0, 1, 2, 3}, std::vector<td::int8>{})
.ensure(); .ensure();
} }
@ -656,12 +664,20 @@ void DhtServer::start_adnl() {
} }
void DhtServer::add_addr(const Config::Addr &addr, const Config::AddrCats &cats) { void DhtServer::add_addr(const Config::Addr &addr, const Config::AddrCats &cats) {
ton::adnl::AdnlCategoryMask cat_mask;
for (auto cat : cats.cats) {
cat_mask[cat] = true;
}
for (auto cat : cats.priority_cats) {
cat_mask[cat] = true;
}
if (!cats.proxy) { if (!cats.proxy) {
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr.addr, td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr.addr,
cats.cats.size() ? 0 : 1); std::move(cat_mask), cats.cats.size() ? 0 : 1);
} else { } else {
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, addr.addr, td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, cats.in_addr,
cats.proxy, cats.cats.size() ? 0 : 1); static_cast<td::uint16>(addr.addr.get_port()), cats.proxy, std::move(cat_mask),
cats.cats.size() ? 0 : 1);
} }
td::uint32 ts = static_cast<td::uint32>(td::Clocks::system()); td::uint32 ts = static_cast<td::uint32>(td::Clocks::system());
@ -687,7 +703,7 @@ void DhtServer::add_addr(const Config::Addr &addr, const Config::AddrCats &cats)
void DhtServer::add_adnl(ton::PublicKeyHash id, AdnlCategory cat) { void DhtServer::add_adnl(ton::PublicKeyHash id, AdnlCategory cat) {
CHECK(addr_lists_[cat].size() > 0); CHECK(addr_lists_[cat].size() > 0);
CHECK(keys_.count(id) > 0); CHECK(keys_.count(id) > 0);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, addr_lists_[cat]); td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, addr_lists_[cat], cat);
} }
void DhtServer::started_adnl() { void DhtServer::started_adnl() {
@ -738,7 +754,7 @@ void DhtServer::start_control_interface() {
for (auto &s : config_.controls) { for (auto &s : config_.controls) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[s.second.key]}, td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[s.second.key]},
ton::adnl::AdnlAddressList{}); ton::adnl::AdnlAddressList{}, static_cast<td::uint8>(255));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{s.second.key}, td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{s.second.key},
std::string(""), std::make_unique<Callback>(actor_id(this))); std::string(""), std::make_unique<Callback>(actor_id(this)));
@ -785,7 +801,7 @@ void DhtServer::add_adnl_node(ton::PublicKey key, AdnlCategory cat, td::Promise<
} }
if (!adnl_.empty()) { if (!adnl_.empty()) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{key}, addr_lists_[cat]); td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{key}, addr_lists_[cat], cat);
} }
write_config(std::move(promise)); write_config(std::move(promise));
@ -970,23 +986,25 @@ void DhtServer::run_control_query(ton::ton_api::engine_validator_addAdnlId &quer
return; return;
} }
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), cat = query.category_, TRY_RESULT_PROMISE(promise, cat, td::narrow_cast_safe<td::uint8>(query.category_));
promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
if (R.is_error()) { auto P = td::PromiseCreator::lambda(
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: "))); [SelfId = actor_id(this), cat, promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
return; if (R.is_error()) {
} promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
auto pub = R.move_as_ok(); return;
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable { }
if (R.is_error()) { auto pub = R.move_as_ok();
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: "))); auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
} else { if (R.is_error()) {
promise.set_value( promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true)); } else {
} promise.set_value(
}); ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
td::actor::send_closure(SelfId, &DhtServer::add_adnl_node, pub, cat, std::move(P)); }
}); });
td::actor::send_closure(SelfId, &DhtServer::add_adnl_node, pub, cat, std::move(P));
});
td::actor::send_closure(keyring_, &ton::keyring::Keyring::get_public_key, ton::PublicKeyHash{query.key_hash_}, td::actor::send_closure(keyring_, &ton::keyring::Keyring::get_public_key, ton::PublicKeyHash{query.key_hash_},
std::move(P)); std::move(P));

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "adnl/adnl.h" #include "adnl/adnl.h"
#include "dht/dht.h" #include "dht/dht.h"
@ -40,7 +40,7 @@
enum DhtServerPermissions : td::uint32 { vep_default = 1, vep_modify = 2, vep_unsafe = 4 }; enum DhtServerPermissions : td::uint32 { vep_default = 1, vep_modify = 2, vep_unsafe = 4 };
using AdnlCategory = td::int32; using AdnlCategory = td::int8;
struct Config { struct Config {
struct Addr { struct Addr {
@ -177,7 +177,7 @@ class DhtServer : public td::actor::Actor {
void alarm() override; void alarm() override;
void run(); void run();
void add_adnl_node(ton::PublicKey pub, td::int32 cat, td::Promise<td::Unit> promise); void add_adnl_node(ton::PublicKey pub, AdnlCategory cat, td::Promise<td::Unit> promise);
void add_dht_node(ton::PublicKeyHash pub, td::Promise<td::Unit> promise); void add_dht_node(ton::PublicKeyHash pub, td::Promise<td::Unit> promise);
void add_control_interface(ton::PublicKeyHash id, td::int32 port, td::Promise<td::Unit> promise); void add_control_interface(ton::PublicKeyHash id, td::int32 port, td::Promise<td::Unit> promise);
void add_control_process(ton::PublicKeyHash id, td::int32 port, ton::PublicKeyHash pub, td::int32 permissions, void add_control_process(ton::PublicKeyHash id, td::int32 port, ton::PublicKeyHash pub, td::int32 permissions,
@ -214,4 +214,3 @@ class DhtServer : public td::actor::Actor {
void process_control_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data, void process_control_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise); td::Promise<td::BufferSlice> promise);
}; };

View file

@ -1843,7 +1843,7 @@ All these primitives first check whether there is enough space in the Builder, a
\item {\tt E0} --- {\tt IFJMP} ($f$ $c$ -- ), jumps to $c$ (similarly to {\tt JMPX}), but only if $f$ is non-zero. \item {\tt E0} --- {\tt IFJMP} ($f$ $c$ -- ), jumps to $c$ (similarly to {\tt JMPX}), but only if $f$ is non-zero.
\item {\tt E1} --- {\tt IFNOTJMP} ($f$ $c$ -- ), jumps to $c$ (similarly to {\tt JMPX}), but only if $f$ is zero. \item {\tt E1} --- {\tt IFNOTJMP} ($f$ $c$ -- ), jumps to $c$ (similarly to {\tt JMPX}), but only if $f$ is zero.
\item {\tt E2} --- {\tt IFELSE} ($f$ $c$ $c'$ -- ), if integer $f$ is non-zero, executes $c$, otherwise executes $c'$. Equivalent to {\tt CONDSELCHK}; {\tt EXECUTE}. \item {\tt E2} --- {\tt IFELSE} ($f$ $c$ $c'$ -- ), if integer $f$ is non-zero, executes $c$, otherwise executes $c'$. Equivalent to {\tt CONDSELCHK}; {\tt EXECUTE}.
\item {\tt E300} --- {\tt IFREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IF}. \item {\tt E300} --- {\tt IFREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IF}, with the optimization that the cell reference is not actually loaded into a {\em Slice} and then converted into an ordinary {\em Continuation\/} if $f=0$. Similar remarks apply to the next three primitives.
\item {\tt E301} --- {\tt IFNOTREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFNOT}. \item {\tt E301} --- {\tt IFNOTREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFNOT}.
\item {\tt E302} --- {\tt IFJMPREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFJMP}. \item {\tt E302} --- {\tt IFJMPREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFJMP}.
\item {\tt E303} --- {\tt IFNOTJMPREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFNOTJMP}. \item {\tt E303} --- {\tt IFNOTJMPREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFNOTJMP}.
@ -1851,14 +1851,18 @@ All these primitives first check whether there is enough space in the Builder, a
\item {\tt E305} --- {\tt CONDSELCHK} ($f$ $x$ $y$ -- $x$ or $y$), same as {\tt CONDSEL}, but first checks whether $x$ and $y$ have the same type. \item {\tt E305} --- {\tt CONDSELCHK} ($f$ $x$ $y$ -- $x$ or $y$), same as {\tt CONDSEL}, but first checks whether $x$ and $y$ have the same type.
\item {\tt E308} --- {\tt IFRETALT} ($f$ --), performs {\tt RETALT} if integer $f\neq0$. \item {\tt E308} --- {\tt IFRETALT} ($f$ --), performs {\tt RETALT} if integer $f\neq0$.
\item {\tt E309} --- {\tt IFNOTRETALT} ($f$ --), performs {\tt RETALT} if integer $f=0$. \item {\tt E309} --- {\tt IFNOTRETALT} ($f$ --), performs {\tt RETALT} if integer $f=0$.
\item {\tt E30D} --- {\tt IFREFELSE} ($f$ $c$ --), equivalent to {\tt PUSHREFCONT}; {\tt SWAP}; {\tt IFELSE}, with the optimization that the cell reference is not actually loaded into a {\em Slice} and then converted into an ordinary {\em Continuation\/} if $f=0$. Similar remarks apply to the next two primitives: {\em Cell\/}s are converted into {\em Continuation\/}s only when necessary.
\item {\tt E30E} --- {\tt IFELSEREF} ($f$ $c$ --), equivalent to {\tt PUSHREFCONT}; {\tt IFELSE}.
\item {\tt E30F} --- {\tt IFREFELSEREF} ($f$ --), equivalent to {\tt PUSHREFCONT}; {\tt PUSHREFCONT}; {\tt IFELSE}.
\item {\tt E310}--{\tt E31F} --- reserved for loops with break operators, cf.~\ptref{sp:prim.loop} below.
\item {\tt E39\_$n$} --- {\tt IFBITJMP $n$} ($x$ $c$ -- $x$), checks whether bit $0\leq n\leq 31$ is set in integer $x$, and if so, performs {\tt JMPX} to continuation~$c$. Value $x$ is left in the stack. \item {\tt E39\_$n$} --- {\tt IFBITJMP $n$} ($x$ $c$ -- $x$), checks whether bit $0\leq n\leq 31$ is set in integer $x$, and if so, performs {\tt JMPX} to continuation~$c$. Value $x$ is left in the stack.
\item {\tt E3B\_$n$} --- {\tt IFNBITJMP $n$} ($x$ $c$ -- $x$), jumps to $c$ if bit $0\leq n\leq 31$ is not set in integer~$x$. \item {\tt E3B\_$n$} --- {\tt IFNBITJMP $n$} ($x$ $c$ -- $x$), jumps to $c$ if bit $0\leq n\leq 31$ is not set in integer~$x$.
\item {\tt E3D\_$n$} --- {\tt IFBITJMPREF $n$} ($x$ -- $x$), performs a {\tt JMPREF} if bit $0\leq n\leq 31$ is set in integer~$x$. \item {\tt E3D\_$n$} --- {\tt IFBITJMPREF $n$} ($x$ -- $x$), performs a {\tt JMPREF} if bit $0\leq n\leq 31$ is set in integer~$x$.
\item {\tt E3F\_$n$} --- {\tt IFNBITJMPREF $n$} ($x$ -- $x$), performs a {\tt JMPREF} if bit $0\leq n\leq 31$ is not set in integer~$x$. \item {\tt E3F\_$n$} --- {\tt IFNBITJMPREF $n$} ($x$ -- $x$), performs a {\tt JMPREF} if bit $0\leq n\leq 31$ is not set in integer~$x$.
\end{itemize} \end{itemize}
\nxsubpoint\emb{Control flow primitives: loops} \nxsubpoint\emb{Control flow primitives: loops}\label{sp:prim.loop}
Most of the loop primitives listed below are implemented with the aid of extraordinary continuations, such as {\tt ec\_until} (cf.~\ptref{sp:extraord.cont}), with the loop body and the original current continuation {\tt cc} stored as the arguments to this extraordinary continuation. Typically a suitable extraordinary continuation is constructed, and then saved into the loop body continuation savelist as {\tt c0}; after that, the modified loop body continuation is loaded into {\tt cc} and executed in the usual fashion. Most of the loop primitives listed below are implemented with the aid of extraordinary continuations, such as {\tt ec\_until} (cf.~\ptref{sp:extraord.cont}), with the loop body and the original current continuation {\tt cc} stored as the arguments to this extraordinary continuation. Typically a suitable extraordinary continuation is constructed, and then saved into the loop body continuation savelist as {\tt c0}; after that, the modified loop body continuation is loaded into {\tt cc} and executed in the usual fashion. All of these loop primitives have {\tt *BRK} versions, adapted for breaking out of a loop; they additionally set {\tt c1} to the original current continuation (or original {\tt c0} for {\tt *ENDBRK} versions), and save the old {\tt c1} into the savelist of the original current continuation (or of the original {\tt c0} for {\tt *ENDBRK} versions).
\begin{itemize} \begin{itemize}
\item {\tt E4} --- {\tt REPEAT} ($n$ $c$ -- ), executes continuation $c$ $n$ times, if integer $n$ is non-negative. If $n\geq2^{31}$ or $n<-2^{31}$, generates a range check exception. Notice that a {\tt RET} inside the code of $c$ works as a {\tt continue}, not as a {\tt break}. One should use either alternative (experimental) loops or alternative {\tt RETALT} (along with a {\tt SETEXITALT} before the loop) to {\tt break} out of a loop. \item {\tt E4} --- {\tt REPEAT} ($n$ $c$ -- ), executes continuation $c$ $n$ times, if integer $n$ is non-negative. If $n\geq2^{31}$ or $n<-2^{31}$, generates a range check exception. Notice that a {\tt RET} inside the code of $c$ works as a {\tt continue}, not as a {\tt break}. One should use either alternative (experimental) loops or alternative {\tt RETALT} (along with a {\tt SETEXITALT} before the loop) to {\tt break} out of a loop.
\item {\tt E5} --- {\tt REPEATEND} ($n$ -- ), similar to {\tt REPEAT}, but it is applied to the current continuation {\tt cc}. \item {\tt E5} --- {\tt REPEATEND} ($n$ -- ), similar to {\tt REPEAT}, but it is applied to the current continuation {\tt cc}.
@ -1868,6 +1872,14 @@ Most of the loop primitives listed below are implemented with the aid of extraor
\item {\tt E9} --- {\tt WHILEEND} ($c'$ -- ), similar to {\tt WHILE}, but uses the current continuation {\tt cc} as the loop body. \item {\tt E9} --- {\tt WHILEEND} ($c'$ -- ), similar to {\tt WHILE}, but uses the current continuation {\tt cc} as the loop body.
\item {\tt EA} --- {\tt AGAIN} ($c$ -- ), similar to {\tt REPEAT}, but executes $c$ infinitely many times. A {\tt RET} only begins a new iteration of the infinite loop, which can be exited only by an exception, or a {\tt RETALT} (or an explicit {\tt JMPX}). \item {\tt EA} --- {\tt AGAIN} ($c$ -- ), similar to {\tt REPEAT}, but executes $c$ infinitely many times. A {\tt RET} only begins a new iteration of the infinite loop, which can be exited only by an exception, or a {\tt RETALT} (or an explicit {\tt JMPX}).
\item {\tt EB} --- {\tt AGAINEND} ( -- ), similar to {\tt AGAIN}, but performed with respect to the current continuation {\tt cc}. \item {\tt EB} --- {\tt AGAINEND} ( -- ), similar to {\tt AGAIN}, but performed with respect to the current continuation {\tt cc}.
\item {\tt E314} --- {\tt REPEATBRK} ($n$ $c$ -- ), similar to {\tt REPEAT}, but also sets {\tt c1} to the original {\tt cc} after saving the old value of {\tt c1} into the savelist of the original {\tt cc}. In this way {\tt RETALT} could be used to break out of the loop body.
\item {\tt E315} --- {\tt REPEATENDBRK} ($n$ -- ), similar to {\tt REPEATEND}, but also sets {\tt c1} to the original {\tt c0} after saving the old value of {\tt c1} into the savelist of the original {\tt c0}. Equivalent to {\tt SAMEALTSAVE}; {\tt REPEATEND}.
\item {\tt E316} --- {\tt UNTILBRK} ($c$ -- ), similar to {\tt UNTIL}, but also modifies {\tt c1} in the same way as {\tt REPEATBRK}.
\item {\tt E317} --- {\tt UNTILENDBRK} ( -- ), equivalent to {\tt SAMEALTSAVE}; {\tt UNTILEND}.
\item {\tt E318} --- {\tt WHILEBRK} ($c'$ $c$ -- ), similar to {\tt WHILE}, but also modifies {\tt c1} in the same way as {\tt REPEATBRK}.
\item {\tt E319} --- {\tt WHILEENDBRK} ($c$ -- ), equivalent to {\tt SAMEALTSAVE}; {\tt WHILEEND}.
\item {\tt E31A} --- {\tt AGAINBRK} ($c$ -- ), similar to {\tt AGAIN}, but also modifies {\tt c1} in the same way as {\tt REPEATBRK}.
\item {\tt E31B} --- {\tt AGAINENDBRK} ( -- ), equivalent to {\tt SAMEALTSAVE}; {\tt AGAINEND}.
\end{itemize} \end{itemize}
\nxsubpoint\label{sp:cont.stk.manip}\emb{Manipulating the stack of continuations} \nxsubpoint\label{sp:cont.stk.manip}\emb{Manipulating the stack of continuations}
@ -1914,7 +1926,9 @@ Most of the loop primitives listed below are implemented with the aid of extraor
\item {\tt EDF6} --- {\tt THENRET} ($c$ -- $c'$), computes $c':=c\circ_0{\tt c0}$ \item {\tt EDF6} --- {\tt THENRET} ($c$ -- $c'$), computes $c':=c\circ_0{\tt c0}$
\item {\tt EDF7} --- {\tt THENRETALT} ($c$ -- $c'$), computes $c':=c\circ_0{\tt c1}$ \item {\tt EDF7} --- {\tt THENRETALT} ($c$ -- $c'$), computes $c':=c\circ_0{\tt c1}$
\item {\tt EDF8} --- {\tt INVERT} ( -- ), interchanges {\tt c0} and {\tt c1}. \item {\tt EDF8} --- {\tt INVERT} ( -- ), interchanges {\tt c0} and {\tt c1}.
\item {\tt EDF9} --- {\tt BOOLEVAL} ($c$ -- $?$), performs ${\tt cc}\leftarrow \bigl(c\circ_0(({\tt PUSH}\,-1)\circ_0{\tt cc})\bigr)\circ_1(({\tt PUSH}\,0)\circ_0{\tt cc})$. If $c$ represents a boolean circuit, the net effect is to evaluate it and push either $-1$ or $0$ into the stack before continuing. \item {\tt EDF9} --- {\tt BOOLEVAL} ($c$ -- $?$), performs ${\tt cc}\leftarrow \bigl(c\circ_0(({\tt PUSH}\,-1)\circ_0{\tt cc})\bigr)\circ_1(({\tt PUSH}\,0)\circ_0{\tt cc})$. If $c$ represents a boolean circuit, the net effect is to evaluate it and push either $-1$ or $0$ into the stack before continuing.
\item {\tt EDFA} --- {\tt SAMEALT} ( -- ), sets $c_1:=c_0$. Equivalent to {\tt PUSH c0}; {\tt POP c1}.
\item {\tt EDFB} --- {\tt SAMEALTSAVE} ( -- ), sets $c_1:=c_0$, but first saves the old value of $c_1$ into the savelist of $c_0$. Equivalent to {\tt SAVE c1}; {\tt SAMEALT}.
\item {\tt EE$rn$} --- {\tt BLESSARGS $r,n$} ($x_1$\dots$x_r$ $s$ -- $c$), described in~\ptref{sp:cont.stk.manip}. \item {\tt EE$rn$} --- {\tt BLESSARGS $r,n$} ($x_1$\dots$x_r$ $s$ -- $c$), described in~\ptref{sp:cont.stk.manip}.
\end{itemize} \end{itemize}

View file

@ -69,7 +69,7 @@ class TonTest {
val giverInputKey = TonApi.InputKeyRegular(giverKey, "local password".toByteArray()) val giverInputKey = TonApi.InputKeyRegular(giverKey, "local password".toByteArray())
val giverAddress = client.send(TonApi.GetAccountAddress(TonApi.WalletV3InitialAccountState(giverKey.publicKey, info.configInfo.defaultWalletId), 1)) as TonApi.AccountAddress; val giverAddress = client.send(TonApi.GetAccountAddress(TonApi.WalletV3InitialAccountState(giverKey.publicKey, info.configInfo.defaultWalletId), 1)) as TonApi.AccountAddress;
val queryInfo = client.send(TonApi.CreateQuery(giverInputKey, giverAddress, 60, TonApi.ActionMsg(arrayOf(TonApi.MsgMessage(walletAddress, 6660000000, TonApi.MsgDataText("Helo") )), true))) as TonApi.QueryInfo; val queryInfo = client.send(TonApi.CreateQuery(giverInputKey, giverAddress, 60, TonApi.ActionMsg(arrayOf(TonApi.MsgMessage(walletAddress, inputKey.key.publicKey, 6660000000, TonApi.MsgDataDecryptedText("Helo".toByteArray()) )), true))) as TonApi.QueryInfo;
client.send(TonApi.QuerySend(queryInfo.id)) as TonApi.Ok; client.send(TonApi.QuerySend(queryInfo.id)) as TonApi.Ok;
while ((client.send(TonApi.GetAccountState(walletAddress)) as TonApi.FullAccountState).balance <= 0L) { while ((client.send(TonApi.GetAccountState(walletAddress)) as TonApi.FullAccountState).balance <= 0L) {

View file

@ -102,7 +102,7 @@ public class TonTestJava {
TonApi.AccountAddress giverAddress = (TonApi.AccountAddress)client.send(new TonApi.GetAccountAddress(new TonApi.WalletV3InitialAccountState(giverKey.publicKey, info.configInfo.defaultWalletId), 1)); TonApi.AccountAddress giverAddress = (TonApi.AccountAddress)client.send(new TonApi.GetAccountAddress(new TonApi.WalletV3InitialAccountState(giverKey.publicKey, info.configInfo.defaultWalletId), 1));
appendLog("sending grams..."); appendLog("sending grams...");
TonApi.QueryInfo queryInfo = (TonApi.QueryInfo)client.send(new TonApi.CreateQuery(giverInputKey, giverAddress, 60, new TonApi.ActionMsg(new TonApi.MsgMessage[]{new TonApi.MsgMessage(walletAddress, 6660000000L, new TonApi.MsgDataText("Helo") )}, true))); TonApi.QueryInfo queryInfo = (TonApi.QueryInfo)client.send(new TonApi.CreateQuery(giverInputKey, giverAddress, 60, new TonApi.ActionMsg(new TonApi.MsgMessage[]{new TonApi.MsgMessage(walletAddress, "", 6660000000L, new TonApi.MsgDataText("Hello".getBytes()) )}, true)));
result = client.send(new TonApi.QuerySend(queryInfo.id)); result = client.send(new TonApi.QuerySend(queryInfo.id));
if (!(result instanceof TonApi.Ok)) { if (!(result instanceof TonApi.Ok)) {
appendLog("failed to send grams"); appendLog("failed to send grams");

View file

@ -777,12 +777,16 @@ class RldpHttpProxy : public td::actor::Actor {
ton::adnl::AdnlNetworkManager::create(is_client_ ? client_port_ : static_cast<td::uint16>(addr_.get_port())); ton::adnl::AdnlNetworkManager::create(is_client_ ? client_port_ : static_cast<td::uint16>(addr_.get_port()));
adnl_ = ton::adnl::Adnl::create(is_client_ ? std::string("") : (db_root_), keyring_.get()); adnl_ = ton::adnl::Adnl::create(is_client_ ? std::string("") : (db_root_), keyring_.get());
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_network_manager, adnl_network_manager_.get()); td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_network_manager, adnl_network_manager_.get());
ton::adnl::AdnlCategoryMask cat_mask;
cat_mask[0] = true;
if (is_client_) { if (is_client_) {
td::IPAddress addr; td::IPAddress addr;
addr.init_host_port("127.0.0.1", client_port_).ensure(); addr.init_host_port("127.0.0.1", client_port_).ensure();
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr, 0); td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr,
std::move(cat_mask), 0);
} else { } else {
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr_, 0); td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr_,
std::move(cat_mask), 0);
} }
ton::adnl::AdnlAddressList addr_list; ton::adnl::AdnlAddressList addr_list;
@ -798,7 +802,8 @@ class RldpHttpProxy : public td::actor::Actor {
auto pub = pk.compute_public_key(); auto pub = pk.compute_public_key();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {}); td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
local_id_ = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}; local_id_ = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()};
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list); td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list,
static_cast<td::uint8>(0));
if (server_ids_.size() == 0 && !is_client_) { if (server_ids_.size() == 0 && !is_client_) {
server_ids_.insert(local_id_); server_ids_.insert(local_id_);
@ -809,10 +814,12 @@ class RldpHttpProxy : public td::actor::Actor {
auto pub = pk.compute_public_key(); auto pub = pk.compute_public_key();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {}); td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
dht_id_ = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}; dht_id_ = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()};
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list); td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list,
static_cast<td::uint8>(0));
} }
for (auto &serv_id : server_ids_) { for (auto &serv_id : server_ids_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, server_ids_full_[serv_id], addr_list); td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, server_ids_full_[serv_id], addr_list,
static_cast<td::uint8>(0));
} }
} }
{ {

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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 "td/db/RocksDb.h" #include "td/db/RocksDb.h"
@ -162,30 +162,32 @@ Result<size_t> RocksDb::count(Slice prefix) {
} }
Status RocksDb::begin_transaction() { Status RocksDb::begin_transaction() {
write_batch_ = std::make_unique<rocksdb::WriteBatch>(); //write_batch_ = std::make_unique<rocksdb::WriteBatch>();
//transaction_.reset(db_->BeginTransaction({}, {})); rocksdb::WriteOptions options;
options.sync = true;
transaction_.reset(db_->BeginTransaction(options, {}));
return Status::OK(); return Status::OK();
} }
Status RocksDb::commit_transaction() { Status RocksDb::commit_transaction() {
CHECK(write_batch_); //CHECK(write_batch_);
auto write_batch = std::move(write_batch_); //auto write_batch = std::move(write_batch_);
rocksdb::WriteOptions options; //rocksdb::WriteOptions options;
options.sync = true; //options.sync = true;
TRY_STATUS(from_rocksdb(db_->Write(options, write_batch.get()))); //TRY_STATUS(from_rocksdb(db_->Write(options, write_batch.get())));
return Status::OK(); //return Status::OK();
//CHECK(transaction_); CHECK(transaction_);
//auto res = from_rocksdb(transaction_->Commit()); auto res = from_rocksdb(transaction_->Commit());
//transaction_.reset(); transaction_.reset();
//return res; return res;
} }
Status RocksDb::abort_transaction() { Status RocksDb::abort_transaction() {
CHECK(write_batch_); //CHECK(write_batch_);
write_batch_.reset(); //write_batch_.reset();
//CHECK(transaction_); CHECK(transaction_);
//transaction_.reset(); transaction_.reset();
return Status::OK(); return Status::OK();
} }

View file

@ -32,7 +32,11 @@ TEST(KeyValue, simple) {
td::RocksDb::destroy(db_name).ignore(); td::RocksDb::destroy(db_name).ignore();
std::unique_ptr<td::KeyValue> kv = std::make_unique<td::RocksDb>(td::RocksDb::open(db_name.str()).move_as_ok()); std::unique_ptr<td::KeyValue> kv = std::make_unique<td::RocksDb>(td::RocksDb::open(db_name.str()).move_as_ok());
auto set_value = [&](td::Slice key, td::Slice value) { kv->set(key, value); }; auto set_value = [&](td::Slice key, td::Slice value) {
kv->begin_transaction();
kv->set(key, value);
kv->commit_transaction();
};
auto ensure_value = [&](td::Slice key, td::Slice value) { auto ensure_value = [&](td::Slice key, td::Slice value) {
std::string kv_value; std::string kv_value;
auto status = kv->get(key, kv_value).move_as_ok(); auto status = kv->get(key, kv_value).move_as_ok();

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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 "td/utils/crypto.h" #include "td/utils/crypto.h"
@ -299,16 +299,16 @@ void aes_cbc_decrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlic
aes_cbc_xcrypt(aes_key, aes_iv, from, to, false); aes_cbc_xcrypt(aes_key, aes_iv, from, to, false);
} }
AesCbcState::AesCbcState(Slice key256, Slice iv128) : key_(key256), iv_(iv128) { AesCbcState::AesCbcState(Slice key256, Slice iv128) : raw_{td::SecureString(key256), td::SecureString(iv128)} {
CHECK(key_.size() == 32); CHECK(raw_.key.size() == 32);
CHECK(iv_.size() == 16); CHECK(raw_.iv.size() == 16);
} }
void AesCbcState::encrypt(Slice from, MutableSlice to) { void AesCbcState::encrypt(Slice from, MutableSlice to) {
::td::aes_cbc_encrypt(key_.as_slice(), iv_.as_mutable_slice(), from, to); ::td::aes_cbc_encrypt(raw_.key.as_slice(), raw_.iv.as_mutable_slice(), from, to);
} }
void AesCbcState::decrypt(Slice from, MutableSlice to) { void AesCbcState::decrypt(Slice from, MutableSlice to) {
::td::aes_cbc_decrypt(key_.as_slice(), iv_.as_mutable_slice(), from, to); ::td::aes_cbc_decrypt(raw_.key.as_slice(), raw_.iv.as_mutable_slice(), from, to);
} }
class AesCtrState::Impl { class AesCtrState::Impl {

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -65,10 +65,17 @@ class AesCbcState {
void encrypt(Slice from, MutableSlice to); void encrypt(Slice from, MutableSlice to);
void decrypt(Slice from, MutableSlice to); void decrypt(Slice from, MutableSlice to);
struct Raw {
SecureString key;
SecureString iv;
};
const Raw &raw() const {
return raw_;
}
private: private:
SecureString key_; Raw raw_;
SecureString iv_;
}; };
void sha1(Slice data, unsigned char output[20]); void sha1(Slice data, unsigned char output[20]);

View file

@ -29,6 +29,8 @@
#include "adnl/adnl.h" #include "adnl/adnl.h"
#include "adnl/adnl-test-loopback-implementation.h" #include "adnl/adnl-test-loopback-implementation.h"
#include "keys/encryptor.h"
#include "td/utils/port/signals.h" #include "td/utils/port/signals.h"
#include "td/utils/port/path.h" #include "td/utils/port/path.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
@ -81,8 +83,10 @@ int main() {
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list(); auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr); td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub2}, addr); static_cast<td::uint8>(0));
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub2}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, src, ton::adnl::AdnlNodeIdFull{pub2}, addr); td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, src, ton::adnl::AdnlNodeIdFull{pub2}, addr);
@ -91,30 +95,85 @@ int main() {
}); });
{ {
auto a = ton::adnl::Adnl::adnl_start_time(); td::Bits256 proxy_id;
std::this_thread::sleep_for(std::chrono::milliseconds(10000)); td::Random::secure_bytes(proxy_id.as_slice());
CHECK(a == ton::adnl::Adnl::adnl_start_time()); auto obj = ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(proxy_id, td::BufferSlice{"1234"});
}
{
auto obj = ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(td::BufferSlice{"1234"});
auto R = ton::adnl::AdnlProxy::create(*obj.get()); auto R = ton::adnl::AdnlProxy::create(*obj.get());
R.ensure(); R.ensure();
auto P = R.move_as_ok(); auto P = R.move_as_ok();
td::BufferSlice z{64}; td::BufferSlice z{64};
td::Random::secure_bytes(z.as_slice()); td::Random::secure_bytes(z.as_slice());
auto packet = P->encrypt(ton::adnl::AdnlProxy::Packet{2, 3, z.clone()}); auto packet = P->encrypt(ton::adnl::AdnlProxy::Packet{15, 2, 3, 4, 5, 6, z.clone()});
td::Bits256 x;
x.as_slice().copy_from(packet.as_slice().truncate(32));
CHECK(x.is_zero());
auto packet2R = P->decrypt(std::move(packet)); auto packet2R = P->decrypt(std::move(packet));
packet2R.ensure(); packet2R.ensure();
auto packet2 = packet2R.move_as_ok(); auto packet2 = packet2R.move_as_ok();
CHECK(packet2.flags == 15);
CHECK(packet2.ip == 2); CHECK(packet2.ip == 2);
CHECK(packet2.port == 3); CHECK(packet2.port == 3);
CHECK(packet2.adnl_start_time == 4);
CHECK(packet2.seqno == 5);
CHECK(packet2.date == 6);
CHECK(packet2.data.as_slice() == z.as_slice()); CHECK(packet2.data.as_slice() == z.as_slice());
} }
{
auto f = td::Clocks::system();
for (int i = 0; i < 10000; i++) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
auto dec = pk.create_decryptor().move_as_ok();
auto enc = pub.create_encryptor().move_as_ok();
td::BufferSlice data{1024};
td::Random::secure_bytes(data.as_slice());
auto enc_data = enc->encrypt(data.as_slice()).move_as_ok();
auto dec_data = dec->decrypt(enc_data.as_slice()).move_as_ok();
CHECK(data.as_slice() == dec_data.as_slice());
}
LOG(ERROR) << "Encrypted 10000 of 1KiB packets. Time=" << (td::Clocks::system() - f);
f = td::Clocks::system();
{
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
auto dec = pk.create_decryptor().move_as_ok();
auto enc = pub.create_encryptor().move_as_ok();
for (int i = 0; i < 10000; i++) {
td::BufferSlice data{1024};
td::Random::secure_bytes(data.as_slice());
auto enc_data = enc->encrypt(data.as_slice()).move_as_ok();
auto dec_data = dec->decrypt(enc_data.as_slice()).move_as_ok();
CHECK(data.as_slice() == dec_data.as_slice());
}
}
LOG(ERROR) << "Encrypted 10000 of 1KiB packets with one key. Time=" << (td::Clocks::system() - f);
f = td::Clocks::system();
for (int i = 0; i < 10000; i++) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
auto dec = pk.create_decryptor().move_as_ok();
auto enc = pub.create_encryptor().move_as_ok();
td::BufferSlice data{1024};
td::Random::secure_bytes(data.as_slice());
auto enc_data = enc->encrypt(data.as_slice()).move_as_ok();
auto dec_data = dec->decrypt(enc_data.as_slice()).move_as_ok();
CHECK(data.as_slice() == dec_data.as_slice());
}
LOG(ERROR) << "Signed 10000 of 1KiB packets. Time=" << (td::Clocks::system() - f);
f = td::Clocks::system();
{
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
auto dec = pk.create_decryptor().move_as_ok();
auto enc = pub.create_encryptor().move_as_ok();
for (int i = 0; i < 10000; i++) {
td::BufferSlice data{1024};
td::Random::secure_bytes(data.as_slice());
auto signature = dec->sign(data.as_slice()).move_as_ok();
enc->check_signature(data.as_slice(), signature.as_slice()).ensure();
}
}
LOG(ERROR) << "Signed 10000 of 1KiB packets with one key. Time=" << (td::Clocks::system() - f);
}
auto send_packet = [&](td::uint32 i) { auto send_packet = [&](td::uint32 i) {
td::BufferSlice d{i}; td::BufferSlice d{i};
d.as_slice()[0] = '1'; d.as_slice()[0] = '1';
@ -159,6 +218,7 @@ int main() {
td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, dst, "1", std::make_unique<Callback>(remaining)); td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, dst, "1", std::make_unique<Callback>(remaining));
}); });
LOG(ERROR) << "Ed25519 version is " << td::Ed25519::version();
LOG(ERROR) << "testing delivering of all packets"; LOG(ERROR) << "testing delivering of all packets";
auto f = td::Clocks::system(); auto f = td::Clocks::system();
@ -324,6 +384,12 @@ int main() {
} }
LOG(ERROR) << "successfully tested ignoring"; LOG(ERROR) << "successfully tested ignoring";
if (true) {
auto a = ton::adnl::Adnl::adnl_start_time();
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
CHECK(a == ton::adnl::Adnl::adnl_start_time());
}
td::rmrf(db_root_).ensure(); td::rmrf(db_root_).ensure();
std::_Exit(0); std::_Exit(0);
return 0; return 0;

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "adnl/adnl.h" #include "adnl/adnl.h"
#include "adnl/utils.hpp" #include "adnl/utils.hpp"
@ -250,7 +250,8 @@ int main(int argc, char *argv[]) {
n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1}; n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1};
n.adnl_id = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()}; n.adnl_id = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {}); td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr); td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, n.adnl_id, true, td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, n.adnl_id, true,
true); true);

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "adnl/adnl-network-manager.h" #include "adnl/adnl-network-manager.h"
#include "adnl/adnl-test-loopback-implementation.h" #include "adnl/adnl-test-loopback-implementation.h"
@ -87,7 +87,8 @@ int main() {
dht_config = dht_configR.move_as_ok(); dht_config = dht_configR.move_as_ok();
} }
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {}); td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr); td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, src, true, true); td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, src, true, true);
dht.push_back(ton::dht::Dht::create(src, db_root_, dht_config, keyring.get(), adnl.get()).move_as_ok()); dht.push_back(ton::dht::Dht::create(src, db_root_, dht_config, keyring.get(), adnl.get()).move_as_ok());

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "adnl/adnl-network-manager.h" #include "adnl/adnl-network-manager.h"
#include "adnl/adnl-test-loopback-implementation.h" #include "adnl/adnl-test-loopback-implementation.h"
@ -75,8 +75,10 @@ int main() {
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list(); auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr); td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub2}, addr); static_cast<td::uint8>(0));
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub2}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(rldp, &ton::rldp::Rldp::add_id, src); td::actor::send_closure(rldp, &ton::rldp::Rldp::add_id, src);
td::actor::send_closure(rldp, &ton::rldp::Rldp::add_id, dst); td::actor::send_closure(rldp, &ton::rldp::Rldp::add_id, dst);

View file

@ -58,8 +58,8 @@ adnl.id.short id:int256 = adnl.id.Short;
adnl.proxyToFastHash ip:int port:int date:int data_hash:int256 shared_secret:int256 = adnl.ProxyTo; adnl.proxyToFastHash ip:int port:int date:int data_hash:int256 shared_secret:int256 = adnl.ProxyTo;
adnl.proxyToFast ip:int port:int date:int signature:int256 = adnl.ProxyToSign; adnl.proxyToFast ip:int port:int date:int signature:int256 = adnl.ProxyToSign;
adnl.proxy.none = adnl.Proxy; adnl.proxy.none id:int256 = adnl.Proxy;
adnl.proxy.fast shared_secret:bytes = adnl.Proxy; adnl.proxy.fast id:int256 shared_secret:bytes = adnl.Proxy;
adnl.address.udp ip:int port:int = adnl.Address; adnl.address.udp ip:int port:int = adnl.Address;
@ -109,6 +109,23 @@ adnl.tunnelPacketContents
= adnl.TunnelPacketContents; = adnl.TunnelPacketContents;
// flag 16 - packet is outbound
// flag 17 - control packet
adnl.proxyPacketHeader
proxy_id:int256
flags:#
ip:flags.0?int
port:flags.0?int
adnl_start_time:flags.1?int
seqno:flags.2?long
date:flags.3?int
signature:int256 = adnl.ProxyPacketHeader;
adnl.proxyControlPacketPing id:int256 = adnl.ProxyControlPacket;
adnl.proxyControlPacketPong id:int256 = adnl.ProxyControlPacket;
adnl.proxyControlPacketRegister ip:int port:int = adnl.ProxyControlPacket;
adnl.message.createChannel key:int256 date:int = adnl.Message; adnl.message.createChannel key:int256 date:int = adnl.Message;
adnl.message.confirmChannel key:int256 peer_key:int256 date:int = adnl.Message; adnl.message.confirmChannel key:int256 peer_key:int256 date:int = adnl.Message;

Binary file not shown.

View file

@ -51,7 +51,7 @@ ton.blockId workchain:int32 shard:int64 seqno:int32 = internal.BlockId;
ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt; ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt;
raw.fullAccountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId block_id:ton.blockIdExt frozen_hash:bytes sync_utime:int53 = raw.FullAccountState; raw.fullAccountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId block_id:ton.blockIdExt frozen_hash:bytes sync_utime:int53 = raw.FullAccountState;
raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes msg_data:msg.Data = raw.Message; raw.message source:accountAddress destination:accountAddress value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes msg_data:msg.Data = raw.Message;
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction; raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions; raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
@ -88,7 +88,11 @@ msg.dataText text:bytes = msg.Data;
msg.dataDecryptedText text:bytes = msg.Data; msg.dataDecryptedText text:bytes = msg.Data;
msg.dataEncryptedText text:bytes = msg.Data; msg.dataEncryptedText text:bytes = msg.Data;
msg.dataArray elements:vector<msg.Data> = msg.DataArray; msg.dataEncrypted source:accountAddress data:msg.Data = msg.DataEncrypted;
msg.dataDecrypted proof:bytes data:msg.Data = msg.DataDecrypted;
msg.dataEncryptedArray elements:vector<msg.dataEncrypted> = msg.DataEncryptedArray;
msg.dataDecryptedArray elements:vector<msg.dataDecrypted> = msg.DataDecryptedArray;
msg.message destination:accountAddress public_key:string amount:int64 data:msg.Data = msg.Message; msg.message destination:accountAddress public_key:string amount:int64 data:msg.Data = msg.Message;
@ -216,7 +220,8 @@ guessAccountRevision initial_account_state:InitialAccountState = AccountRevision
getAccountState account_address:accountAddress = FullAccountState; getAccountState account_address:accountAddress = FullAccountState;
createQuery private_key:InputKey address:accountAddress timeout:int32 action:Action = query.Info; createQuery private_key:InputKey address:accountAddress timeout:int32 action:Action = query.Info;
msg.decrypt input_key:InputKey data:msg.dataArray = msg.DataArray; msg.decrypt input_key:InputKey data:msg.dataEncryptedArray = msg.DataDecryptedArray;
msg.decryptWithProof proof:bytes data:msg.dataEncrypted = msg.Data;
query.send id:int53 = Ok; query.send id:int53 = Ok;
query.forget id:int53 = Ok; query.forget id:int53 = Ok;

Binary file not shown.

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. 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
*/ */
#pragma once #pragma once
@ -56,7 +56,13 @@ constexpr unsigned min_split_merge_interval = 30; // split/merge interval must
constexpr unsigned max_split_merge_delay = constexpr unsigned max_split_merge_delay =
1000; // end of split/merge interval must be at most 1000 seconds in the future 1000; // end of split/merge interval must be at most 1000 seconds in the future
enum GlobalCapabilities { capIhrEnabled = 1, capCreateStatsEnabled = 2 }; enum GlobalCapabilities {
capIhrEnabled = 1,
capCreateStatsEnabled = 2,
capBounceMsgBody = 4,
capReportVersion = 8,
capSplitMergeTransactions = 16
};
inline int shard_pfx_len(ShardId shard) { inline int shard_pfx_len(ShardId shard) {
return shard ? 63 - td::count_trailing_zeroes_non_zero64(shard) : 0; return shard ? 63 - td::count_trailing_zeroes_non_zero64(shard) : 0;

View file

@ -155,6 +155,13 @@ TEST(Tonlib, InitClose) {
} }
} }
td::Slice to_data(const td::SecureString &str) {
return str.as_slice();
}
td::Slice to_data(const tonlib::SimpleEncryptionV2::Decrypted &str) {
return str.data.as_slice();
}
template <class Encryption> template <class Encryption>
void test_encryption() { void test_encryption() {
std::string secret = "secret"; std::string secret = "secret";
@ -164,7 +171,7 @@ void test_encryption() {
auto encrypted_data = Encryption::encrypt_data(data, secret); auto encrypted_data = Encryption::encrypt_data(data, secret);
LOG(ERROR) << encrypted_data.size(); LOG(ERROR) << encrypted_data.size();
auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok(); auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok();
CHECK(data == decrypted_data); CHECK(data == to_data(decrypted_data));
Encryption::decrypt_data(encrypted_data, wrong_secret).ensure_error(); Encryption::decrypt_data(encrypted_data, wrong_secret).ensure_error();
Encryption::decrypt_data("", secret).ensure_error(); Encryption::decrypt_data("", secret).ensure_error();
Encryption::decrypt_data(std::string(32, 'a'), secret).ensure_error(); Encryption::decrypt_data(std::string(32, 'a'), secret).ensure_error();
@ -177,7 +184,7 @@ void test_encryption() {
auto data = td::rand_string('a', 'z', static_cast<int>(i)); auto data = td::rand_string('a', 'z', static_cast<int>(i));
auto encrypted_data = Encryption::encrypt_data(data, secret); auto encrypted_data = Encryption::encrypt_data(data, secret);
auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok(); auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok();
CHECK(data == decrypted_data); CHECK(data == to_data(decrypted_data));
} }
} }
TEST(Tonlib, SimpleEncryption) { TEST(Tonlib, SimpleEncryption) {
@ -199,24 +206,33 @@ TEST(Tonlib, SimpleEncryptionAsym) {
auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok(); auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok();
LOG(ERROR) << encrypted_data.size(); LOG(ERROR) << encrypted_data.size();
auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok(); auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok();
CHECK(data == decrypted_data); CHECK(data == decrypted_data.data);
auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok(); auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok();
CHECK(data == decrypted_data2); CHECK(data == decrypted_data2.data);
CHECK(decrypted_data.proof == decrypted_data2.proof);
auto decrypted_data3 =
SimpleEncryptionV2::decrypt_data_with_proof(encrypted_data, decrypted_data.proof).move_as_ok();
CHECK(data == decrypted_data3);
SimpleEncryptionV2::decrypt_data(encrypted_data, wrong_private_key).ensure_error(); SimpleEncryptionV2::decrypt_data(encrypted_data, wrong_private_key).ensure_error();
SimpleEncryptionV2::decrypt_data("", private_key).ensure_error(); SimpleEncryptionV2::decrypt_data("", private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(32, 'a'), private_key).ensure_error(); SimpleEncryptionV2::decrypt_data(std::string(32, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(33, 'a'), private_key).ensure_error(); SimpleEncryptionV2::decrypt_data(std::string(33, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(64, 'a'), private_key).ensure_error(); SimpleEncryptionV2::decrypt_data(std::string(64, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(128, 'a'), private_key).ensure_error(); SimpleEncryptionV2::decrypt_data(std::string(128, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data_with_proof(encrypted_data, decrypted_data.proof, "bad salt").ensure_error();
} }
for (size_t i = 0; i < 255; i++) { for (size_t i = 0; i < 255; i++) {
auto data = td::rand_string('a', 'z', static_cast<int>(i)); auto data = td::rand_string('a', 'z', static_cast<int>(i));
auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok(); auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok();
auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok(); auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok();
CHECK(data == decrypted_data); CHECK(data == decrypted_data.data);
auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok(); auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok();
CHECK(data == decrypted_data2); CHECK(data == decrypted_data2.data);
} }
} }
@ -518,19 +534,30 @@ TEST(Tonlib, KeysApi) {
auto other_public_key = td::Ed25519::generate_private_key().move_as_ok().get_public_key().move_as_ok(); auto other_public_key = td::Ed25519::generate_private_key().move_as_ok().get_public_key().move_as_ok();
std::string text = "hello world"; std::string text = "hello world";
std::vector<tonlib_api::object_ptr<tonlib_api::msg_Data>> elements; std::vector<tonlib_api::object_ptr<tonlib_api::msg_dataEncrypted>> elements;
elements.push_back(make_object<tonlib_api::msg_dataEncryptedText>( td::Slice addr = "Ef9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX";
SimpleEncryptionV2::encrypt_data(text, other_public_key, pkey).move_as_ok().as_slice().str())); auto encrypted = SimpleEncryptionV2::encrypt_data(text, other_public_key, pkey, addr).move_as_ok().as_slice().str();
elements.push_back(make_object<tonlib_api::msg_dataEncrypted>(
make_object<tonlib_api::accountAddress>(addr.str()), make_object<tonlib_api::msg_dataEncryptedText>(encrypted)));
auto decrypted = auto decrypted =
sync_send(client, make_object<tonlib_api::msg_decrypt>( sync_send(client, make_object<tonlib_api::msg_decrypt>(
make_object<tonlib_api::inputKeyRegular>( make_object<tonlib_api::inputKeyRegular>(
make_object<tonlib_api::key>(key->public_key_, raw_imported_key->secret_.copy()), make_object<tonlib_api::key>(key->public_key_, raw_imported_key->secret_.copy()),
new_local_password.copy()), new_local_password.copy()),
make_object<tonlib_api::msg_dataArray>(std::move(elements)))) make_object<tonlib_api::msg_dataEncryptedArray>(std::move(elements))))
.move_as_ok(); .move_as_ok();
downcast_call(*decrypted->elements_[0], auto proof = decrypted->elements_[0]->proof_;
downcast_call(*decrypted->elements_[0]->data_,
td::overloaded([](auto &) { UNREACHABLE(); },
[&](tonlib_api::msg_dataDecryptedText &decrypted) { CHECK(decrypted.text_ == text); }));
auto decrypted2 = sync_send(client, make_object<tonlib_api::msg_decryptWithProof>(
proof, make_object<tonlib_api::msg_dataEncrypted>(
make_object<tonlib_api::accountAddress>(addr.str()),
make_object<tonlib_api::msg_dataEncryptedText>(encrypted))))
.move_as_ok();
downcast_call(*decrypted2,
td::overloaded([](auto &) { UNREACHABLE(); }, td::overloaded([](auto &) { UNREACHABLE(); },
[&](tonlib_api::msg_dataDecryptedText &decrypted) { CHECK(decrypted.text_ == text); })); [&](tonlib_api::msg_dataDecryptedText &decrypted) { CHECK(decrypted.text_ == text); }));
} }

View file

@ -392,9 +392,9 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
if (transfer_all) { if (transfer_all) {
ASSERT_EQ(amount - first_fee, txn->in_msg_->value_); ASSERT_EQ(amount - first_fee, txn->in_msg_->value_);
} else { } else {
ASSERT_EQ(new_src_state.address, txn->in_msg_->source_); ASSERT_EQ(new_src_state.address, txn->in_msg_->source_->account_address_);
} }
ASSERT_EQ(new_src_state.address, txn->in_msg_->source_); ASSERT_EQ(new_src_state.address, txn->in_msg_->source_->account_address_);
if (!encrypt) { if (!encrypt) {
ASSERT_EQ(message, read_text(*txn->in_msg_->msg_data_)); ASSERT_EQ(message, read_text(*txn->in_msg_->msg_data_));
} }

View file

@ -1368,6 +1368,7 @@ bool TonlibClient::is_static_request(td::int32 id) {
case tonlib_api::encrypt::ID: case tonlib_api::encrypt::ID:
case tonlib_api::decrypt::ID: case tonlib_api::decrypt::ID:
case tonlib_api::kdf::ID: case tonlib_api::kdf::ID:
case tonlib_api::msg_decryptWithProof::ID:
return true; return true;
default: default:
return false; return false;
@ -1841,38 +1842,41 @@ struct ToRawTransactions {
auto body_cell = vm::CellBuilder().append_cellslice(*body).finalize(); auto body_cell = vm::CellBuilder().append_cellslice(*body).finalize();
auto body_hash = body_cell->get_hash().as_slice().str(); auto body_hash = body_cell->get_hash().as_slice().str();
tonlib_api::object_ptr<tonlib_api::msg_Data> data; auto get_data = [body = std::move(body), body_cell, this](td::Slice salt) mutable {
if (body->size() >= 32 && static_cast<td::uint32>(body->prefetch_long(32)) <= 1) { tonlib_api::object_ptr<tonlib_api::msg_Data> data;
auto type = body.write().fetch_long(32); if (body->size() >= 32 && static_cast<td::uint32>(body->prefetch_long(32)) <= 1) {
td::Status status; auto type = body.write().fetch_long(32);
td::Status status;
auto r_body_message = vm::CellString::load(body.write()); auto r_body_message = vm::CellString::load(body.write());
LOG_IF(WARNING, r_body_message.is_error()) << "Failed to parse a message: " << r_body_message.error(); LOG_IF(WARNING, r_body_message.is_error()) << "Failed to parse a message: " << r_body_message.error();
if (r_body_message.is_ok()) { if (r_body_message.is_ok()) {
if (type == 0) { if (type == 0) {
data = tonlib_api::make_object<tonlib_api::msg_dataText>(r_body_message.move_as_ok()); data = tonlib_api::make_object<tonlib_api::msg_dataText>(r_body_message.move_as_ok());
} else {
LOG(ERROR) << "TRY DECRYPT";
auto encrypted_message = r_body_message.move_as_ok();
auto r_decrypted_message = [&]() -> td::Result<std::string> {
if (!private_key_) {
return TonlibError::EmptyField("private_key");
}
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(encrypted_message, private_key_.value()));
return decrypted.as_slice().str();
}();
if (r_decrypted_message.is_ok()) {
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(r_decrypted_message.move_as_ok());
} else { } else {
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(encrypted_message); LOG(ERROR) << "TRY DECRYPT";
auto encrypted_message = r_body_message.move_as_ok();
auto r_decrypted_message = [&]() -> td::Result<std::string> {
if (!private_key_) {
return TonlibError::EmptyField("private_key");
}
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(encrypted_message, private_key_.value(), salt));
return decrypted.data.as_slice().str();
}();
if (r_decrypted_message.is_ok()) {
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(r_decrypted_message.move_as_ok());
} else {
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(encrypted_message);
}
} }
} }
} }
} if (!data) {
if (!data) { data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)));
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell))); }
} return data;
};
auto tag = block::gen::CommonMsgInfo().get_tag(*message.info); auto tag = block::gen::CommonMsgInfo().get_tag(*message.info);
if (tag < 0) { if (tag < 0) {
@ -1892,9 +1896,10 @@ struct ToRawTransactions {
TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee)); TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee));
auto created_lt = static_cast<td::int64>(msg_info.created_lt); auto created_lt = static_cast<td::int64>(msg_info.created_lt);
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance, fwd_fee, return tonlib_api::make_object<tonlib_api::raw_message>(
ihr_fee, created_lt, std::move(body_hash), tonlib_api::make_object<tonlib_api::accountAddress>(src),
std::move(data)); tonlib_api::make_object<tonlib_api::accountAddress>(std::move(dest)), balance, fwd_fee, ihr_fee, created_lt,
std::move(body_hash), get_data(src));
} }
case block::gen::CommonMsgInfo::ext_in_msg_info: { case block::gen::CommonMsgInfo::ext_in_msg_info: {
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
@ -1902,8 +1907,10 @@ struct ToRawTransactions {
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info"); return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
} }
TRY_RESULT(dest, to_std_address(msg_info.dest)); TRY_RESULT(dest, to_std_address(msg_info.dest));
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0, 0, 0, 0, std::move(body_hash), return tonlib_api::make_object<tonlib_api::raw_message>(
std::move(data)); tonlib_api::make_object<tonlib_api::accountAddress>(),
tonlib_api::make_object<tonlib_api::accountAddress>(std::move(dest)), 0, 0, 0, 0, std::move(body_hash),
get_data(""));
} }
case block::gen::CommonMsgInfo::ext_out_msg_info: { case block::gen::CommonMsgInfo::ext_out_msg_info: {
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info; block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
@ -1911,8 +1918,9 @@ struct ToRawTransactions {
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info"); return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
} }
TRY_RESULT(src, to_std_address(msg_info.src)); TRY_RESULT(src, to_std_address(msg_info.src));
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, std::move(body_hash), return tonlib_api::make_object<tonlib_api::raw_message>(
std::move(data)); tonlib_api::make_object<tonlib_api::accountAddress>(src),
tonlib_api::make_object<tonlib_api::accountAddress>(), 0, 0, 0, 0, std::move(body_hash), get_data(src));
} }
} }
@ -2493,8 +2501,13 @@ class GenericCreateSendGrams : public TonlibQueryActor {
return TonlibError::MessageEncryption("Get public key (in destination)"); return TonlibError::MessageEncryption("Get public key (in destination)");
} }
auto addr = source_->get_address();
addr.bounceable = true;
addr.testnet = false;
TRY_RESULT_PREFIX(encrypted_message, TRY_RESULT_PREFIX(encrypted_message,
SimpleEncryptionV2::encrypt_data(action.message, o_public_key.unwrap(), private_key_.value()), SimpleEncryptionV2::encrypt_data(action.message, o_public_key.unwrap(), private_key_.value(),
addr.rserialize(true)),
TonlibError::Internal()); TonlibError::Internal());
gift.message = encrypted_message.as_slice().str(); gift.message = encrypted_message.as_slice().str();
gift.is_encrypted = true; gift.is_encrypted = true;
@ -2569,7 +2582,7 @@ td::Status TonlibClient::do_request(tonlib_api::createQuery& request,
} }
td::Status TonlibClient::do_request(tonlib_api::msg_decrypt& request, td::Status TonlibClient::do_request(tonlib_api::msg_decrypt& request,
td::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise) { td::Promise<object_ptr<tonlib_api::msg_dataDecryptedArray>>&& promise) {
if (!request.input_key_) { if (!request.input_key_) {
return TonlibError::EmptyField("input_key"); return TonlibError::EmptyField("input_key");
} }
@ -2577,27 +2590,44 @@ td::Status TonlibClient::do_request(tonlib_api::msg_decrypt& request,
return TonlibError::EmptyField("data"); return TonlibError::EmptyField("data");
} }
TRY_RESULT(input_key, from_tonlib(*request.input_key_)); TRY_RESULT(input_key, from_tonlib(*request.input_key_));
using ReturnType = tonlib_api::object_ptr<tonlib_api::msg_dataDecrypted>;
make_request( make_request(
int_api::GetPrivateKey{std::move(input_key)}, int_api::GetPrivateKey{std::move(input_key)},
promise.wrap([elements = std::move(request.data_)](auto key) mutable { promise.wrap([elements = std::move(request.data_)](auto key) mutable {
auto private_key = td::Ed25519::PrivateKey(std::move(key.private_key)); auto private_key = td::Ed25519::PrivateKey(std::move(key.private_key));
elements->elements_ = td::transform(std::move(elements->elements_), [&private_key](auto msg) { auto new_elements = td::transform(std::move(elements->elements_), [&private_key](auto msg) -> ReturnType {
auto res = tonlib_api::make_object<tonlib_api::msg_dataDecrypted>();
if (!msg) { if (!msg) {
return std::move(msg); return res;
}
if (!msg->data_) {
return res;
}
res->data_ = std::move(msg->data_);
if (!msg->source_) {
return res;
}
auto r_account_address = get_account_address(msg->source_->account_address_);
if (r_account_address.is_error()) {
return res;
} }
using ReturnType = tonlib_api::object_ptr<tonlib_api::msg_Data>;
return downcast_call2<ReturnType>( return downcast_call2<ReturnType>(
*msg, td::overloaded([&msg](auto&) { return std::move(msg); }, *res->data_,
[&msg, &private_key](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType { td::overloaded(
auto r_decrypted = SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key); [&res](auto&) { return std::move(res); },
if (r_decrypted.is_error()) { [&res, &private_key, &msg](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType {
return std::move(msg); auto r_decrypted =
} SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key, msg->source_->account_address_);
return tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>( if (r_decrypted.is_error()) {
r_decrypted.move_as_ok().as_slice().str()); return std::move(res);
})); }
auto decrypted = r_decrypted.move_as_ok();
return tonlib_api::make_object<tonlib_api::msg_dataDecrypted>(
decrypted.proof.as_slice().str(),
tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(decrypted.data.as_slice().str()));
}));
}); });
return std::move(elements); return tonlib_api::make_object<tonlib_api::msg_dataDecryptedArray>(std::move(new_elements));
})); }));
return td::Status::OK(); return td::Status::OK();
} }
@ -3251,6 +3281,32 @@ tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const
SimpleEncryption::kdf(request.password_, request.salt_, request.iterations_)); SimpleEncryption::kdf(request.password_, request.salt_, request.iterations_));
} }
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
const tonlib_api::msg_decryptWithProof& request) {
if (!request.data_) {
return status_to_tonlib_api(TonlibError::EmptyField("data"));
}
if (!request.data_->data_) {
TonlibError::EmptyField("data.data");
}
if (!request.data_->source_) {
TonlibError::EmptyField("data.source");
}
using ReturnType = tonlib_api::object_ptr<tonlib_api::msg_Data>;
return downcast_call2<ReturnType>(
*request.data_->data_,
td::overloaded([&request](auto&) { return std::move(request.data_->data_); },
[&request](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType {
auto r_decrypted = SimpleEncryptionV2::decrypt_data_with_proof(
encrypted.text_, request.proof_, request.data_->source_->account_address_);
if (r_decrypted.is_error()) {
return std::move(request.data_->data_);
}
auto decrypted = r_decrypted.move_as_ok();
return tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(decrypted.as_slice().str());
}));
}
td::Status TonlibClient::do_request(int_api::GetAccountState request, td::Status TonlibClient::do_request(int_api::GetAccountState request,
td::Promise<td::unique_ptr<AccountState>>&& promise) { td::Promise<td::unique_ptr<AccountState>>&& promise) {
auto actor_id = actor_id_++; auto actor_id = actor_id_++;
@ -3399,4 +3455,9 @@ td::Status TonlibClient::do_request(const tonlib_api::kdf& request, P&&) {
UNREACHABLE(); UNREACHABLE();
return TonlibError::Internal(); return TonlibError::Internal();
} }
template <class P>
td::Status TonlibClient::do_request(const tonlib_api::msg_decryptWithProof& request, P&&) {
UNREACHABLE();
return TonlibError::Internal();
}
} // namespace tonlib } // namespace tonlib

View file

@ -160,6 +160,8 @@ class TonlibClient : public td::actor::Actor {
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::decrypt& request); static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::decrypt& request);
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::kdf& request); static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::kdf& request);
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::msg_decryptWithProof& request);
template <class P> template <class P>
td::Status do_request(const tonlib_api::runTests& request, P&&); td::Status do_request(const tonlib_api::runTests& request, P&&);
template <class P> template <class P>
@ -194,6 +196,8 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(const tonlib_api::decrypt& request, P&&); td::Status do_request(const tonlib_api::decrypt& request, P&&);
template <class P> template <class P>
td::Status do_request(const tonlib_api::kdf& request, P&&); td::Status do_request(const tonlib_api::kdf& request, P&&);
template <class P>
td::Status do_request(const tonlib_api::msg_decryptWithProof& request, P&&);
void make_any_request(tonlib_api::Function& function, QueryContext query_context, void make_any_request(tonlib_api::Function& function, QueryContext query_context,
td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>&& promise); td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>&& promise);
@ -281,7 +285,8 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(tonlib_api::createQuery& request, td::Promise<object_ptr<tonlib_api::query_info>>&& promise); td::Status do_request(tonlib_api::createQuery& request, td::Promise<object_ptr<tonlib_api::query_info>>&& promise);
td::Status do_request(tonlib_api::msg_decrypt& request, td::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise); td::Status do_request(tonlib_api::msg_decrypt& request,
td::Promise<object_ptr<tonlib_api::msg_dataDecryptedArray>>&& promise);
td::int64 next_smc_id_{0}; td::int64 next_smc_id_{0};
std::map<td::int64, td::unique_ptr<AccountState>> smcs_; std::map<td::int64, td::unique_ptr<AccountState>> smcs_;

View file

@ -23,7 +23,7 @@
namespace tonlib { namespace tonlib {
td::AesCbcState SimpleEncryption::calc_aes_cbc_state_hash(td::Slice hash) { td::AesCbcState SimpleEncryption::calc_aes_cbc_state_hash(td::Slice hash) {
CHECK(hash.size() == 64); CHECK(hash.size() >= 48);
td::SecureString key(32); td::SecureString key(32);
key.as_mutable_slice().copy_from(hash.substr(0, 32)); key.as_mutable_slice().copy_from(hash.substr(0, 32));
td::SecureString iv(16); td::SecureString iv(16);
@ -34,7 +34,7 @@ td::AesCbcState SimpleEncryption::calc_aes_cbc_state_hash(td::Slice hash) {
td::AesCbcState SimpleEncryption::calc_aes_cbc_state_sha512(td::Slice seed) { td::AesCbcState SimpleEncryption::calc_aes_cbc_state_sha512(td::Slice seed) {
td::SecureString hash(64); td::SecureString hash(64);
sha512(seed, hash.as_mutable_slice()); sha512(seed, hash.as_mutable_slice());
return calc_aes_cbc_state_hash(hash.as_slice()); return calc_aes_cbc_state_hash(hash.as_slice().substr(0, 48));
} }
td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size, td::int64 min_padding) { td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size, td::int64 min_padding) {
@ -106,10 +106,10 @@ td::Result<td::SecureString> SimpleEncryption::decrypt_data(td::Slice encrypted_
return td::SecureString(decrypted_data.as_slice().substr(prefix_size)); return td::SecureString(decrypted_data.as_slice().substr(prefix_size));
} }
td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data, td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PublicKey &public_key) { td::Slice salt) {
TRY_RESULT(tmp_private_key, td::Ed25519::generate_private_key()); TRY_RESULT(tmp_private_key, td::Ed25519::generate_private_key());
return encrypt_data(data, public_key, tmp_private_key); return encrypt_data(data, public_key, tmp_private_key, salt);
} }
namespace { namespace {
@ -124,9 +124,10 @@ td::SecureString secure_xor(td::Slice a, td::Slice b) {
} // namespace } // namespace
td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key, td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PrivateKey &private_key) { const td::Ed25519::PrivateKey &private_key,
td::Slice salt) {
TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(public_key, private_key)); TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(public_key, private_key));
auto encrypted = encrypt_data(data, shared_secret.as_slice()); auto encrypted = encrypt_data(data, shared_secret.as_slice(), salt);
TRY_RESULT(tmp_public_key, private_key.get_public_key()); TRY_RESULT(tmp_public_key, private_key.get_public_key());
td::SecureString prefixed_encrypted(tmp_public_key.LENGTH + encrypted.size()); td::SecureString prefixed_encrypted(tmp_public_key.LENGTH + encrypted.size());
prefixed_encrypted.as_mutable_slice().copy_from(tmp_public_key.as_octet_string()); prefixed_encrypted.as_mutable_slice().copy_from(tmp_public_key.as_octet_string());
@ -136,8 +137,9 @@ td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data, co
return std::move(prefixed_encrypted); return std::move(prefixed_encrypted);
} }
td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice data, td::Result<SimpleEncryptionV2::Decrypted> SimpleEncryptionV2::decrypt_data(td::Slice data,
const td::Ed25519::PrivateKey &private_key) { const td::Ed25519::PrivateKey &private_key,
td::Slice salt) {
if (data.size() < td::Ed25519::PublicKey::LENGTH) { if (data.size() < td::Ed25519::PublicKey::LENGTH) {
return td::Status::Error("Failed to decrypte: data is too small"); return td::Status::Error("Failed to decrypte: data is too small");
} }
@ -145,17 +147,19 @@ td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice data,
auto tmp_public_key = auto tmp_public_key =
td::Ed25519::PublicKey(secure_xor(data.substr(0, td::Ed25519::PublicKey::LENGTH), public_key.as_octet_string())); td::Ed25519::PublicKey(secure_xor(data.substr(0, td::Ed25519::PublicKey::LENGTH), public_key.as_octet_string()));
TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(tmp_public_key, private_key)); TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(tmp_public_key, private_key));
TRY_RESULT(decrypted, decrypt_data(data.substr(td::Ed25519::PublicKey::LENGTH), shared_secret.as_slice())); TRY_RESULT(decrypted, decrypt_data(data.substr(td::Ed25519::PublicKey::LENGTH), shared_secret.as_slice(), salt));
return std::move(decrypted); return std::move(decrypted);
} }
td::SecureString SimpleEncryptionV2::encrypt_data(td::Slice data, td::Slice secret) {
td::SecureString SimpleEncryptionV2::encrypt_data(td::Slice data, td::Slice secret, td::Slice salt) {
auto prefix = SimpleEncryption::gen_random_prefix(data.size(), 16); auto prefix = SimpleEncryption::gen_random_prefix(data.size(), 16);
td::SecureString combined(prefix.size() + data.size()); td::SecureString combined(prefix.size() + data.size());
combined.as_mutable_slice().copy_from(prefix); combined.as_mutable_slice().copy_from(prefix);
combined.as_mutable_slice().substr(prefix.size()).copy_from(data); combined.as_mutable_slice().substr(prefix.size()).copy_from(data);
return encrypt_data_with_prefix(combined.as_slice(), secret); return encrypt_data_with_prefix(combined.as_slice(), secret, salt);
} }
td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice encrypted_data, td::Slice secret) {
td::Result<std::pair<td::Slice, td::Slice>> unpack_encrypted_data(td::Slice encrypted_data) {
if (encrypted_data.size() < 17) { if (encrypted_data.size() < 17) {
return td::Status::Error("Failed to decrypt: data is too small"); return td::Status::Error("Failed to decrypt: data is too small");
} }
@ -163,13 +167,18 @@ td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice encrypte
return td::Status::Error("Failed to decrypt: data size is not divisible by 16"); return td::Status::Error("Failed to decrypt: data size is not divisible by 16");
} }
auto msg_key = encrypted_data.substr(0, 16); auto msg_key = encrypted_data.substr(0, 16);
encrypted_data = encrypted_data.substr(16); auto data = encrypted_data.substr(16);
return std::make_pair(msg_key, data);
}
auto cbc_state = SimpleEncryption::calc_aes_cbc_state_hash(SimpleEncryption::combine_secrets(secret, msg_key)); td::Result<td::SecureString> SimpleEncryptionV2::do_decrypt(td::Slice cbc_state_secret, td::Slice msg_key,
td::Slice encrypted_data, td::Slice salt) {
auto cbc_state = SimpleEncryption::calc_aes_cbc_state_hash(cbc_state_secret);
td::SecureString decrypted_data(encrypted_data.size(), 0); td::SecureString decrypted_data(encrypted_data.size(), 0);
auto iv_copy = cbc_state.raw().key.copy();
cbc_state.decrypt(encrypted_data, decrypted_data.as_mutable_slice()); cbc_state.decrypt(encrypted_data, decrypted_data.as_mutable_slice());
auto data_hash = SimpleEncryption::combine_secrets(decrypted_data, secret); auto data_hash = SimpleEncryption::combine_secrets(salt, decrypted_data);
auto got_msg_key = data_hash.as_slice().substr(0, 16); auto got_msg_key = data_hash.as_slice().substr(0, 16);
// check hash // check hash
if (msg_key != got_msg_key) { if (msg_key != got_msg_key) {
@ -183,9 +192,35 @@ td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice encrypte
return td::SecureString(decrypted_data.as_slice().substr(prefix_size)); return td::SecureString(decrypted_data.as_slice().substr(prefix_size));
} }
td::SecureString SimpleEncryptionV2::encrypt_data_with_prefix(td::Slice data, td::Slice secret) {
td::Result<SimpleEncryptionV2::Decrypted> SimpleEncryptionV2::decrypt_data(td::Slice encrypted_data, td::Slice secret,
td::Slice salt) {
TRY_RESULT(p, unpack_encrypted_data(encrypted_data));
auto msg_key = p.first;
auto data = p.second;
auto cbc_state_secret = td::SecureString(SimpleEncryption::combine_secrets(secret, msg_key).as_slice().substr(0, 48));
TRY_RESULT(res, do_decrypt(cbc_state_secret.as_slice(), msg_key, data, salt));
return Decrypted{std::move(cbc_state_secret), std::move(res)};
}
td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data_with_proof(td::Slice encrypted_data, td::Slice proof,
td::Slice salt) {
if (encrypted_data.size() < td::Ed25519::PublicKey::LENGTH) {
return td::Status::Error("Failed to decrypte: data is too small");
}
if (proof.size() != 48) {
return td::Status::Error("Invalid proof size");
}
encrypted_data = encrypted_data.substr(td::Ed25519::PublicKey::LENGTH);
TRY_RESULT(p, unpack_encrypted_data(encrypted_data));
auto msg_key = p.first;
auto data = p.second;
return do_decrypt(proof, msg_key, data, salt);
}
td::SecureString SimpleEncryptionV2::encrypt_data_with_prefix(td::Slice data, td::Slice secret, td::Slice salt) {
CHECK(data.size() % 16 == 0); CHECK(data.size() % 16 == 0);
auto data_hash = SimpleEncryption::combine_secrets(data, secret); auto data_hash = SimpleEncryption::combine_secrets(salt, data);
auto msg_key = data_hash.as_slice().substr(0, 16); auto msg_key = data_hash.as_slice().substr(0, 16);
td::SecureString res_buf(data.size() + 16, 0); td::SecureString res_buf(data.size() + 16, 0);

View file

@ -43,14 +43,27 @@ class SimpleEncryption {
class SimpleEncryptionV2 { class SimpleEncryptionV2 {
public: public:
static td::Result<td::SecureString> encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key);
static td::Result<td::SecureString> decrypt_data(td::Slice data, const td::Ed25519::PrivateKey &private_key);
static td::Result<td::SecureString> encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key, static td::Result<td::SecureString> encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PrivateKey &private_key); td::Slice salt = {});
static td::SecureString encrypt_data(td::Slice data, td::Slice secret); struct Decrypted {
static td::Result<td::SecureString> decrypt_data(td::Slice encrypted_data, td::Slice secret); td::SecureString proof;
td::SecureString data;
};
static td::Result<Decrypted> decrypt_data(td::Slice data, const td::Ed25519::PrivateKey &private_key,
td::Slice sallt = {});
static td::Result<td::SecureString> encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PrivateKey &private_key, td::Slice salt = {});
static td::Result<td::SecureString> decrypt_data_with_proof(td::Slice encrypted_data, td::Slice proof,
td::Slice salt = {});
static td::SecureString encrypt_data(td::Slice data, td::Slice secret, td::Slice salt = {});
static td::Result<Decrypted> decrypt_data(td::Slice encrypted_data, td::Slice secret, td::Slice salt = {});
private: private:
static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret); static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret, td::Slice salt = {});
static td::Result<td::SecureString> do_decrypt(td::Slice cbc_state_secret, td::Slice msg_key,
td::Slice encrypted_data, td::Slice salt);
}; };
} // namespace tonlib } // namespace tonlib

View file

@ -1384,10 +1384,10 @@ class TonlibCli : public td::actor::Actor {
sb << "-" << Grams{td::uint64(-balance)}; sb << "-" << Grams{td::uint64(-balance)};
} }
sb << " Fee: " << Grams{td::uint64(t->fee_)}; sb << " Fee: " << Grams{td::uint64(t->fee_)};
if (t->in_msg_->source_.empty()) { if (!t->in_msg_->source_->account_address_.empty()) {
sb << " External "; sb << " External ";
} else { } else {
sb << " From " << t->in_msg_->source_; sb << " From " << t->in_msg_->source_->account_address_;
} }
auto print_msg_data = [](td::StringBuilder& sb, auto print_msg_data = [](td::StringBuilder& sb,
tonlib_api::object_ptr<tonlib_api::msg_Data>& msg_data) { tonlib_api::object_ptr<tonlib_api::msg_Data>& msg_data) {
@ -1406,10 +1406,10 @@ class TonlibCli : public td::actor::Actor {
print_msg_data(sb, t->in_msg_->msg_data_); print_msg_data(sb, t->in_msg_->msg_data_);
for (auto& ot : t->out_msgs_) { for (auto& ot : t->out_msgs_) {
sb << "\n\t"; sb << "\n\t";
if (ot->destination_.empty()) { if (ot->destination_->account_address_.empty()) {
sb << " External "; sb << " External ";
} else { } else {
sb << " To " << ot->destination_; sb << " To " << ot->destination_->account_address_;
} }
sb << " " << Grams{td::uint64(ot->value_)}; sb << " " << Grams{td::uint64(ot->value_)};
print_msg_data(sb, ot->msg_data_); print_msg_data(sb, ot->msg_data_);

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "validator-engine-console-query.h" #include "validator-engine-console-query.h"
#include "validator-engine-console.h" #include "validator-engine-console.h"
@ -609,6 +609,7 @@ td::Status AddNetworkAddressQuery::receive(td::BufferSlice data) {
td::Status AddNetworkProxyAddressQuery::run() { td::Status AddNetworkProxyAddressQuery::run() {
TRY_RESULT_ASSIGN(in_addr_, tokenizer_.get_token<td::IPAddress>()); TRY_RESULT_ASSIGN(in_addr_, tokenizer_.get_token<td::IPAddress>());
TRY_RESULT_ASSIGN(out_addr_, tokenizer_.get_token<td::IPAddress>()); TRY_RESULT_ASSIGN(out_addr_, tokenizer_.get_token<td::IPAddress>());
TRY_RESULT_ASSIGN(id_, tokenizer_.get_token<td::Bits256>());
TRY_RESULT_ASSIGN(shared_secret_, tokenizer_.get_token<td::BufferSlice>()); TRY_RESULT_ASSIGN(shared_secret_, tokenizer_.get_token<td::BufferSlice>());
TRY_RESULT_ASSIGN(cats_, tokenizer_.get_token_vector<td::int32>()); TRY_RESULT_ASSIGN(cats_, tokenizer_.get_token_vector<td::int32>());
TRY_RESULT_ASSIGN(prio_cats_, tokenizer_.get_token_vector<td::int32>()); TRY_RESULT_ASSIGN(prio_cats_, tokenizer_.get_token_vector<td::int32>());
@ -619,7 +620,7 @@ td::Status AddNetworkProxyAddressQuery::run() {
td::Status AddNetworkProxyAddressQuery::send() { td::Status AddNetworkProxyAddressQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addProxy>( auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addProxy>(
static_cast<td::int32>(in_addr_.get_ipv4()), in_addr_.get_port(), static_cast<td::int32>(out_addr_.get_ipv4()), static_cast<td::int32>(in_addr_.get_ipv4()), in_addr_.get_port(), static_cast<td::int32>(out_addr_.get_ipv4()),
out_addr_.get_port(), ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(std::move(shared_secret_)), out_addr_.get_port(), ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(id_, std::move(shared_secret_)),
std::move(cats_), std::move(prio_cats_)); std::move(cats_), std::move(prio_cats_));
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise()); td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK(); return td::Status::OK();

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -104,6 +104,19 @@ inline td::Result<ton::PublicKeyHash> Tokenizer::get_token() {
} }
} }
template <>
inline td::Result<td::Bits256> Tokenizer::get_token() {
TRY_RESULT(S, get_raw_token());
TRY_RESULT(F, td::hex_decode(S));
if (F.size() == 32) {
td::Bits256 v;
v.as_slice().copy_from(F);
return v;
} else {
return td::Status::Error("cannot parse keyhash: bad length");
}
}
template <> template <>
inline td::Result<td::IPAddress> Tokenizer::get_token() { inline td::Result<td::IPAddress> Tokenizer::get_token() {
TRY_RESULT(S, get_raw_token()); TRY_RESULT(S, get_raw_token());
@ -782,7 +795,7 @@ class AddNetworkProxyAddressQuery : public Query {
return "addproxyaddr"; return "addproxyaddr";
} }
static std::string get_help() { static std::string get_help() {
return "addproxyaddr <inip> <outid> <secret> {cats...} {priocats...}\tadds ip address to address list"; return "addproxyaddr <inip> <outip> <id> <secret> {cats...} {priocats...}\tadds ip address to address list";
} }
std::string name() const override { std::string name() const override {
return get_name(); return get_name();
@ -791,6 +804,7 @@ class AddNetworkProxyAddressQuery : public Query {
private: private:
td::IPAddress in_addr_; td::IPAddress in_addr_;
td::IPAddress out_addr_; td::IPAddress out_addr_;
td::Bits256 id_;
td::BufferSlice shared_secret_; td::BufferSlice shared_secret_;
std::vector<td::int32> cats_; std::vector<td::int32> cats_;
std::vector<td::int32> prio_cats_; std::vector<td::int32> prio_cats_;

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "validator-engine.hpp" #include "validator-engine.hpp"
@ -86,8 +86,12 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
[&](const ton::ton_api::engine_addr &obj) { [&](const ton::ton_api::engine_addr &obj) {
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast<td::uint16>(obj.port_)).ensure(); in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast<td::uint16>(obj.port_)).ensure();
out_ip = in_ip; out_ip = in_ip;
categories = obj.categories_; for (auto cat : obj.categories_) {
priority_categories = obj.priority_categories_; categories.push_back(td::narrow_cast<td::uint8>(cat));
}
for (auto cat : obj.priority_categories_) {
priority_categories.push_back(td::narrow_cast<td::uint8>(cat));
}
}, },
[&](const ton::ton_api::engine_addrProxy &obj) { [&](const ton::ton_api::engine_addrProxy &obj) {
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.in_ip_), static_cast<td::uint16>(obj.in_port_)) in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.in_ip_), static_cast<td::uint16>(obj.in_port_))
@ -98,15 +102,19 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
auto R = ton::adnl::AdnlProxy::create(*obj.proxy_type_.get()); auto R = ton::adnl::AdnlProxy::create(*obj.proxy_type_.get());
R.ensure(); R.ensure();
proxy = R.move_as_ok(); proxy = R.move_as_ok();
categories = obj.categories_; for (auto cat : obj.categories_) {
priority_categories = obj.priority_categories_; categories.push_back(td::narrow_cast<td::uint8>(cat));
}
for (auto cat : obj.priority_categories_) {
priority_categories.push_back(td::narrow_cast<td::uint8>(cat));
}
} }
})); }));
config_add_network_addr(in_ip, out_ip, std::move(proxy), categories, priority_categories).ensure(); config_add_network_addr(in_ip, out_ip, std::move(proxy), categories, priority_categories).ensure();
} }
for (auto &adnl : config.adnl_) { for (auto &adnl : config.adnl_) {
config_add_adnl_addr(ton::PublicKeyHash{adnl->id_}, adnl->category_).ensure(); config_add_adnl_addr(ton::PublicKeyHash{adnl->id_}, td::narrow_cast<td::uint8>(adnl->category_)).ensure();
} }
for (auto &dht : config.dht_) { for (auto &dht : config.dht_) {
config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure(); config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure();
@ -1094,7 +1102,9 @@ void ValidatorEngine::load_empty_local_config(td::Promise<td::Unit> promise) {
ig.add_promise(std::move(ret_promise)); ig.add_promise(std::move(ret_promise));
for (auto &addr : addrs_) { for (auto &addr : addrs_) {
config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int32>{0, 1, 2, 3}, std::vector<td::int32>{}) config_
.config_add_network_addr(addr, addr, nullptr, std::vector<AdnlCategory>{0, 1, 2, 3},
std::vector<AdnlCategory>{})
.ensure(); .ensure();
} }
@ -1156,7 +1166,9 @@ void ValidatorEngine::load_local_config(td::Promise<td::Unit> promise) {
ig.add_promise(std::move(ret_promise)); ig.add_promise(std::move(ret_promise));
for (auto &addr : addrs_) { for (auto &addr : addrs_) {
config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int32>{0, 1, 2, 3}, std::vector<td::int32>{}) config_
.config_add_network_addr(addr, addr, nullptr, std::vector<AdnlCategory>{0, 1, 2, 3},
std::vector<AdnlCategory>{})
.ensure(); .ensure();
} }
@ -1378,18 +1390,25 @@ void ValidatorEngine::start_adnl() {
} }
void ValidatorEngine::add_addr(const Config::Addr &addr, const Config::AddrCats &cats) { void ValidatorEngine::add_addr(const Config::Addr &addr, const Config::AddrCats &cats) {
ton::adnl::AdnlCategoryMask cat_mask;
for (auto cat : cats.cats) {
cat_mask[cat] = true;
}
for (auto cat : cats.priority_cats) {
cat_mask[cat] = true;
}
if (!cats.proxy) { if (!cats.proxy) {
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr.addr, td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr.addr,
cats.cats.size() ? 0 : 1); std::move(cat_mask), cats.cats.size() ? 0 : 1);
} else { } else {
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, addr.addr, td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, cats.in_addr,
cats.proxy, cats.cats.size() ? 0 : 1); static_cast<td::uint16>(addr.addr.get_port()), cats.proxy, std::move(cat_mask),
cats.cats.size() ? 0 : 1);
} }
td::uint32 ts = static_cast<td::uint32>(td::Clocks::system()); td::uint32 ts = static_cast<td::uint32>(td::Clocks::system());
for (auto cat : cats.cats) { for (auto cat : cats.cats) {
CHECK(cat >= 0);
ton::adnl::AdnlAddress x = ton::adnl::AdnlAddressImpl::create( ton::adnl::AdnlAddress x = ton::adnl::AdnlAddressImpl::create(
ton::create_tl_object<ton::ton_api::adnl_address_udp>(cats.in_addr.get_ipv4(), cats.in_addr.get_port())); ton::create_tl_object<ton::ton_api::adnl_address_udp>(cats.in_addr.get_ipv4(), cats.in_addr.get_port()));
addr_lists_[cat].add_addr(std::move(x)); addr_lists_[cat].add_addr(std::move(x));
@ -1397,7 +1416,6 @@ void ValidatorEngine::add_addr(const Config::Addr &addr, const Config::AddrCats
addr_lists_[cat].set_reinit_date(ton::adnl::Adnl::adnl_start_time()); addr_lists_[cat].set_reinit_date(ton::adnl::Adnl::adnl_start_time());
} }
for (auto cat : cats.priority_cats) { for (auto cat : cats.priority_cats) {
CHECK(cat >= 0);
ton::adnl::AdnlAddress x = ton::adnl::AdnlAddressImpl::create( ton::adnl::AdnlAddress x = ton::adnl::AdnlAddressImpl::create(
ton::create_tl_object<ton::ton_api::adnl_address_udp>(cats.in_addr.get_ipv4(), cats.in_addr.get_port())); ton::create_tl_object<ton::ton_api::adnl_address_udp>(cats.in_addr.get_ipv4(), cats.in_addr.get_port()));
prio_addr_lists_[cat].add_addr(std::move(x)); prio_addr_lists_[cat].add_addr(std::move(x));
@ -1408,7 +1426,7 @@ void ValidatorEngine::add_addr(const Config::Addr &addr, const Config::AddrCats
void ValidatorEngine::add_adnl(ton::PublicKeyHash id, AdnlCategory cat) { void ValidatorEngine::add_adnl(ton::PublicKeyHash id, AdnlCategory cat) {
CHECK(keys_.count(id) > 0); CHECK(keys_.count(id) > 0);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, addr_lists_[cat]); td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, addr_lists_[cat], cat);
} }
void ValidatorEngine::started_adnl() { void ValidatorEngine::started_adnl() {
@ -1526,7 +1544,7 @@ void ValidatorEngine::started_full_node() {
void ValidatorEngine::add_lite_server(ton::PublicKeyHash id, td::uint16 port) { void ValidatorEngine::add_lite_server(ton::PublicKeyHash id, td::uint16 port) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]},
ton::adnl::AdnlAddressList{}); ton::adnl::AdnlAddressList{}, static_cast<td::uint8>(255));
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_id, td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_id,
ton::adnl::AdnlNodeIdShort{id}); ton::adnl::AdnlNodeIdShort{id});
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_port, port); td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_port, port);
@ -1565,7 +1583,7 @@ void ValidatorEngine::add_control_interface(ton::PublicKeyHash id, td::uint16 po
}; };
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]},
ton::adnl::AdnlAddressList{}); ton::adnl::AdnlAddressList{}, static_cast<td::uint8>(255));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{id}, std::string(""), td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{id}, std::string(""),
std::make_unique<Callback>(actor_id(this), port)); std::make_unique<Callback>(actor_id(this), port));
td::actor::send_closure(control_ext_server_, &ton::adnl::AdnlExtServer::add_local_id, ton::adnl::AdnlNodeIdShort{id}); td::actor::send_closure(control_ext_server_, &ton::adnl::AdnlExtServer::add_local_id, ton::adnl::AdnlNodeIdShort{id});
@ -1621,7 +1639,7 @@ void ValidatorEngine::started() {
} }
void ValidatorEngine::try_add_adnl_node(ton::PublicKeyHash key, AdnlCategory cat, td::Promise<td::Unit> promise) { void ValidatorEngine::try_add_adnl_node(ton::PublicKeyHash key, AdnlCategory cat, td::Promise<td::Unit> promise) {
if (cat < 0 || static_cast<td::uint32>(cat) > max_cat()) { if (cat > max_cat()) {
promise.set_error(td::Status::Error(ton::ErrorCode::protoviolation, "bad category value")); promise.set_error(td::Status::Error(ton::ErrorCode::protoviolation, "bad category value"));
return; return;
} }
@ -2136,23 +2154,24 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addAdnlId
} }
auto id = ton::PublicKeyHash{query.key_hash_}; auto id = ton::PublicKeyHash{query.key_hash_};
TRY_RESULT_PROMISE(promise, cat, td::narrow_cast_safe<td::uint8>(query.category_));
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id, cat = query.category_, auto P = td::PromiseCreator::lambda(
promise = std::move(promise)](td::Result<td::Unit> R) mutable { [SelfId = actor_id(this), id, cat, promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) { if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: "))); promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
return; return;
} }
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable { auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) { if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: "))); promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
} else { } else {
promise.set_value( promise.set_value(
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true)); ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
} }
}); });
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_adnl_node, id, cat, std::move(P)); td::actor::send_closure(SelfId, &ValidatorEngine::try_add_adnl_node, id, cat, std::move(P));
}); });
check_key(id, std::move(P)); check_key(id, std::move(P));
} }
@ -2538,7 +2557,17 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addListen
} }
}); });
try_add_listening_port(query.ip_, query.port_, query.categories_, query.priority_categories_, std::move(P)); std::vector<td::uint8> cats;
for (auto cat : query.categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
cats.push_back(c);
}
std::vector<td::uint8> prio_cats;
for (auto cat : query.priority_categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
prio_cats.push_back(c);
}
try_add_listening_port(query.ip_, query.port_, std::move(cats), std::move(prio_cats), std::move(P));
} }
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delListeningPort &query, td::BufferSlice data, void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delListeningPort &query, td::BufferSlice data,
@ -2561,7 +2590,17 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delListen
} }
}); });
try_del_listening_port(query.ip_, query.port_, query.categories_, query.priority_categories_, std::move(P)); std::vector<td::uint8> cats;
for (auto cat : query.categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
cats.push_back(c);
}
std::vector<td::uint8> prio_cats;
for (auto cat : query.priority_categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
prio_cats.push_back(c);
}
try_del_listening_port(query.ip_, query.port_, std::move(cats), std::move(prio_cats), std::move(P));
} }
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addProxy &query, td::BufferSlice data, void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addProxy &query, td::BufferSlice data,
@ -2590,8 +2629,18 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addProxy
} }
}); });
try_add_proxy(query.in_ip_, query.in_port_, query.out_ip_, query.out_port_, R.move_as_ok(), query.categories_, std::vector<td::uint8> cats;
query.priority_categories_, std::move(P)); for (auto cat : query.categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
cats.push_back(c);
}
std::vector<td::uint8> prio_cats;
for (auto cat : query.priority_categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
prio_cats.push_back(c);
}
try_add_proxy(query.in_ip_, query.in_port_, query.out_ip_, query.out_port_, R.move_as_ok(), std::move(cats),
std::move(prio_cats), std::move(P));
} }
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delProxy &query, td::BufferSlice data, void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delProxy &query, td::BufferSlice data,
@ -2614,7 +2663,18 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delProxy
} }
}); });
try_del_proxy(query.out_ip_, query.out_port_, query.categories_, query.priority_categories_, std::move(P)); std::vector<td::uint8> cats;
for (auto cat : query.categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
cats.push_back(c);
}
std::vector<td::uint8> prio_cats;
for (auto cat : query.priority_categories_) {
TRY_RESULT_PROMISE(promise, c, td::narrow_cast_safe<td::uint8>(cat));
prio_cats.push_back(c);
}
try_del_proxy(query.out_ip_, query.out_port_, std::move(cats), std::move(prio_cats), std::move(P));
} }
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getConfig &query, td::BufferSlice data, void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getConfig &query, td::BufferSlice data,

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -43,7 +43,7 @@
enum ValidatorEnginePermissions : td::uint32 { vep_default = 1, vep_modify = 2, vep_unsafe = 4 }; enum ValidatorEnginePermissions : td::uint32 { vep_default = 1, vep_modify = 2, vep_unsafe = 4 };
using AdnlCategory = td::int32; using AdnlCategory = td::uint8;
struct Config { struct Config {
struct Addr { struct Addr {
@ -201,8 +201,8 @@ class ValidatorEngine : public td::actor::Actor {
bool started_ = false; bool started_ = false;
public: public:
static constexpr td::uint32 max_cat() { static constexpr td::uint8 max_cat() {
return 256; return 250;
} }
void set_local_config(std::string str); void set_local_config(std::string str);
@ -286,7 +286,7 @@ class ValidatorEngine : public td::actor::Actor {
void alarm() override; void alarm() override;
void run(); void run();
void try_add_adnl_node(ton::PublicKeyHash pub, td::int32 cat, td::Promise<td::Unit> promise); void try_add_adnl_node(ton::PublicKeyHash pub, AdnlCategory cat, td::Promise<td::Unit> promise);
void try_add_dht_node(ton::PublicKeyHash pub, td::Promise<td::Unit> promise); void try_add_dht_node(ton::PublicKeyHash pub, td::Promise<td::Unit> promise);
void try_add_validator_permanent_key(ton::PublicKeyHash key_hash, td::uint32 election_date, td::uint32 ttl, void try_add_validator_permanent_key(ton::PublicKeyHash key_hash, td::uint32 election_date, td::uint32 ttl,
td::Promise<td::Unit> promise); td::Promise<td::Unit> promise);
@ -385,4 +385,3 @@ class ValidatorEngine : public td::actor::Actor {
void process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, void process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data, td::Promise<td::BufferSlice> promise); td::BufferSlice data, td::Promise<td::BufferSlice> promise);
}; };

View file

@ -79,8 +79,8 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
} }
if (handle_->is_applied()) { if (handle_->is_applied()) {
auto P = td::PromiseCreator::lambda( auto P =
[ SelfId = actor_id(this), seqno = handle_->id().id.seqno ](td::Result<BlockIdExt> R) { td::PromiseCreator::lambda([SelfId = actor_id(this), seqno = handle_->id().id.seqno](td::Result<BlockIdExt> R) {
R.ensure(); R.ensure();
auto h = R.move_as_ok(); auto h = R.move_as_ok();
if (h.id.seqno < seqno) { if (h.id.seqno < seqno) {
@ -119,15 +119,14 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, block_, std::move(P)); td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, block_, std::move(P));
} else { } else {
auto P = auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle = handle_](td::Result<td::Ref<BlockData>> R) {
td::PromiseCreator::lambda([ SelfId = actor_id(this), handle = handle_ ](td::Result<td::Ref<BlockData>> R) { CHECK(handle->received());
CHECK(handle->received()); if (R.is_error()) {
if (R.is_error()) { td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error()); } else {
} else { td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data); }
} });
});
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, apply_block_priority(), timeout_, td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, apply_block_priority(), timeout_,
std::move(P)); std::move(P));
@ -136,19 +135,25 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
void ApplyBlock::written_block_data() { void ApplyBlock::written_block_data() {
VLOG(VALIDATOR_DEBUG) << "apply block: written block data for " << id_; VLOG(VALIDATOR_DEBUG) << "apply block: written block data for " << id_;
if (handle_->id().is_masterchain() && !handle_->inited_proof()) { if (!handle_->id().seqno()) {
abort_query(td::Status::Error(ErrorCode::notready, "proof is absent")); CHECK(handle_->inited_split_after());
return; CHECK(handle_->inited_state_root_hash());
CHECK(handle_->inited_logical_time());
} else {
if (handle_->id().is_masterchain() && !handle_->inited_proof()) {
abort_query(td::Status::Error(ErrorCode::notready, "proof is absent"));
return;
}
if (!handle_->id().is_masterchain() && !handle_->inited_proof_link()) {
abort_query(td::Status::Error(ErrorCode::notready, "proof link is absent"));
return;
}
CHECK(handle_->inited_merge_before());
CHECK(handle_->inited_split_after());
CHECK(handle_->inited_prev());
CHECK(handle_->inited_state_root_hash());
CHECK(handle_->inited_logical_time());
} }
if (!handle_->id().is_masterchain() && !handle_->inited_proof_link()) {
abort_query(td::Status::Error(ErrorCode::notready, "proof link is absent"));
return;
}
CHECK(handle_->inited_merge_before());
CHECK(handle_->inited_split_after());
CHECK(handle_->inited_prev());
CHECK(handle_->inited_state_root_hash());
CHECK(handle_->inited_logical_time());
if (handle_->is_applied() && handle_->processed()) { if (handle_->is_applied() && handle_->processed()) {
finish_query(); finish_query();
} else { } else {

View file

@ -39,6 +39,9 @@ namespace validator {
using td::Ref; using td::Ref;
class Collator final : public td::actor::Actor { class Collator final : public td::actor::Actor {
static constexpr int supported_version = 1;
static constexpr long long supported_capabilities =
ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion;
using LtCellRef = block::LtCellRef; using LtCellRef = block::LtCellRef;
using NewOutMsg = block::NewOutMsg; using NewOutMsg = block::NewOutMsg;
const ShardIdFull shard; const ShardIdFull shard;
@ -137,6 +140,7 @@ class Collator final : public td::actor::Actor {
bool shard_conf_adjusted_{false}; bool shard_conf_adjusted_{false};
bool ihr_enabled_{false}; bool ihr_enabled_{false};
bool create_stats_enabled_{false}; bool create_stats_enabled_{false};
bool report_version_{false};
td::uint64 overload_history_{0}, underload_history_{0}; td::uint64 overload_history_{0}, underload_history_{0};
td::uint64 block_size_estimate_{}; td::uint64 block_size_estimate_{};
Ref<block::WorkchainInfo> wc_info_; Ref<block::WorkchainInfo> wc_info_;
@ -286,6 +290,7 @@ class Collator final : public td::actor::Actor {
bool store_master_ref(vm::CellBuilder& cb); bool store_master_ref(vm::CellBuilder& cb);
bool store_prev_blk_ref(vm::CellBuilder& cb, bool after_merge); bool store_prev_blk_ref(vm::CellBuilder& cb, bool after_merge);
bool store_zero_state_ref(vm::CellBuilder& cb); bool store_zero_state_ref(vm::CellBuilder& cb);
bool store_version(vm::CellBuilder& cb) const;
bool create_block_info(Ref<vm::Cell>& block_info); bool create_block_info(Ref<vm::Cell>& block_info);
bool check_value_flow(); bool check_value_flow();
bool create_block_extra(Ref<vm::Cell>& block_extra); bool create_block_extra(Ref<vm::Cell>& block_extra);

View file

@ -510,6 +510,7 @@ bool Collator::unpack_last_mc_state() {
global_id_ = config_->get_global_blockchain_id(); global_id_ = config_->get_global_blockchain_id();
ihr_enabled_ = config_->ihr_enabled(); ihr_enabled_ = config_->ihr_enabled();
create_stats_enabled_ = config_->create_stats_enabled(); create_stats_enabled_ = config_->create_stats_enabled();
report_version_ = config_->has_capability(ton::capReportVersion);
shard_conf_ = std::make_unique<block::ShardConfig>(*config_); shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_); prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
if (prev_key_block_exists_) { if (prev_key_block_exists_) {
@ -529,6 +530,16 @@ bool Collator::unpack_last_mc_state() {
<< ", " << block_limits_->bytes.hard() << "]"; << ", " << block_limits_->bytes.hard() << "]";
LOG(DEBUG) << "block limits: gas [" << block_limits_->gas.underload() << ", " << block_limits_->gas.soft() << ", " LOG(DEBUG) << "block limits: gas [" << block_limits_->gas.underload() << ", " << block_limits_->gas.soft() << ", "
<< block_limits_->gas.hard() << "]"; << block_limits_->gas.hard() << "]";
if (config_->has_capabilities() && (config_->get_capabilities() & ~supported_capabilities)) {
LOG(ERROR) << "block generation capabilities " << config_->get_capabilities()
<< " have been enabled in global configuration, but we support only " << supported_capabilities
<< " (upgrade validator software?)";
}
if (config_->get_global_version() > supported_version) {
LOG(ERROR) << "block version " << config_->get_global_version()
<< " have been enabled in global configuration, but we support only " << supported_version
<< " (upgrade validator software?)";
}
// TODO: extract start_lt and end_lt from prev_mc_block as well // TODO: extract start_lt and end_lt from prev_mc_block as well
// std::cerr << " block::gen::ShardState::print_ref(mc_state_root) = "; // std::cerr << " block::gen::ShardState::print_ref(mc_state_root) = ";
// block::gen::t_ShardState.print_ref(std::cerr, mc_state_root, 2); // block::gen::t_ShardState.print_ref(std::cerr, mc_state_root, 2);
@ -1502,6 +1513,7 @@ bool Collator::fetch_config_params() {
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor, block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
(unsigned)rec.first_frac, (unsigned)rec.next_frac}; (unsigned)rec.first_frac, (unsigned)rec.next_frac};
action_phase_cfg_.workchains = &config_->get_workchain_list(); action_phase_cfg_.workchains = &config_->get_workchain_list();
action_phase_cfg_.bounce_msg_body = (config_->has_capability(ton::capBounceMsgBody) ? 256 : 0);
} }
{ {
// fetch block_grams_created // fetch block_grams_created
@ -3571,7 +3583,7 @@ bool Collator::create_block_info(Ref<vm::Cell>& block_info) {
&& cb.store_bool_bool(want_split_) // want_split:Bool && cb.store_bool_bool(want_split_) // want_split:Bool
&& cb.store_bool_bool(want_merge_) // want_merge:Bool && cb.store_bool_bool(want_merge_) // want_merge:Bool
&& cb.store_bool_bool(is_key_block_) // key_block:Bool && cb.store_bool_bool(is_key_block_) // key_block:Bool
&& cb.store_long_bool(0, 9) // vert_seqno_incr:(## 1) flags:(## 8) && cb.store_long_bool((int)report_version_, 9) // vert_seqno_incr:(## 1) flags:(## 8)
&& cb.store_long_bool(new_block_seqno, 32) // seq_no:# && cb.store_long_bool(new_block_seqno, 32) // seq_no:#
&& cb.store_long_bool(vert_seqno_, 32) // vert_seq_no:# && cb.store_long_bool(vert_seqno_, 32) // vert_seq_no:#
&& block::ShardId{shard}.serialize(cb) // shard:ShardIdent && block::ShardId{shard}.serialize(cb) // shard:ShardIdent
@ -3582,6 +3594,7 @@ bool Collator::create_block_info(Ref<vm::Cell>& block_info) {
&& cb.store_long_bool(cc_seqno, 32) // gen_catchain_seqno:uint32 && cb.store_long_bool(cc_seqno, 32) // gen_catchain_seqno:uint32
&& cb.store_long_bool(min_ref_mc_seqno_, 32) // min_ref_mc_seqno:uint32 && cb.store_long_bool(min_ref_mc_seqno_, 32) // min_ref_mc_seqno:uint32
&& cb.store_long_bool(prev_key_block_seqno_, 32) // prev_key_block_seqno:uint32 && cb.store_long_bool(prev_key_block_seqno_, 32) // prev_key_block_seqno:uint32
&& (!report_version_ || store_version(cb)) // gen_software:flags . 0?GlobalVersion
&& (mc || (store_master_ref(cb2) // master_ref:not_master? && (mc || (store_master_ref(cb2) // master_ref:not_master?
&& cb.store_builder_ref_bool(std::move(cb2)))) // .. ^BlkMasterInfo && cb.store_builder_ref_bool(std::move(cb2)))) // .. ^BlkMasterInfo
&& store_prev_blk_ref(cb2, after_merge_) // prev_ref:.. && store_prev_blk_ref(cb2, after_merge_) // prev_ref:..
@ -3589,6 +3602,10 @@ bool Collator::create_block_info(Ref<vm::Cell>& block_info) {
&& cb.finalize_to(block_info); && cb.finalize_to(block_info);
} }
bool Collator::store_version(vm::CellBuilder& cb) const {
return block::gen::t_GlobalVersion.pack_capabilities(cb, supported_version, supported_capabilities);
}
bool Collator::store_zero_state_ref(vm::CellBuilder& cb) { bool Collator::store_zero_state_ref(vm::CellBuilder& cb) {
CHECK(prev_state_root_.not_null()); CHECK(prev_state_root_.not_null());
RootHash root_hash = prev_state_root_->get_hash().bits(); RootHash root_hash = prev_state_root_->get_hash().bits();

View file

@ -679,6 +679,17 @@ bool ValidateQuery::try_unpack_mc_state() {
config_->set_block_id_ext(mc_blkid_); config_->set_block_id_ext(mc_blkid_);
ihr_enabled_ = config_->ihr_enabled(); ihr_enabled_ = config_->ihr_enabled();
create_stats_enabled_ = config_->create_stats_enabled(); create_stats_enabled_ = config_->create_stats_enabled();
if (config_->has_capabilities() && (config_->get_capabilities() & ~supported_capabilities)) {
LOG(ERROR) << "block generation capabilities " << config_->get_capabilities()
<< " have been enabled in global configuration, but we support only " << supported_capabilities
<< " (upgrade validator software?)";
}
if (config_->get_global_version() > supported_version) {
LOG(ERROR) << "block version " << config_->get_global_version()
<< " have been enabled in global configuration, but we support only " << supported_version
<< " (upgrade validator software?)";
}
old_shard_conf_ = std::make_unique<block::ShardConfig>(*config_); old_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
if (!is_masterchain()) { if (!is_masterchain()) {
new_shard_conf_ = std::make_unique<block::ShardConfig>(*config_); new_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
@ -772,6 +783,7 @@ bool ValidateQuery::fetch_config_params() {
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor, block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
(unsigned)rec.first_frac, (unsigned)rec.next_frac}; (unsigned)rec.first_frac, (unsigned)rec.next_frac};
action_phase_cfg_.workchains = &config_->get_workchain_list(); action_phase_cfg_.workchains = &config_->get_workchain_list();
action_phase_cfg_.bounce_msg_body = (config_->has_capability(ton::capBounceMsgBody) ? 256 : 0);
} }
{ {
// fetch block_grams_created // fetch block_grams_created
@ -4832,7 +4844,7 @@ bool ValidateQuery::check_config_update(Ref<vm::CellSlice> old_conf_params, Ref<
} }
if (!block::valid_config_data(ocfg_root, old_cfg_addr, true, true, old_mparams_)) { if (!block::valid_config_data(ocfg_root, old_cfg_addr, true, true, old_mparams_)) {
return reject_query("configuration extracted from (old) configuration smart contract "s + old_cfg_addr.to_hex() + return reject_query("configuration extracted from (old) configuration smart contract "s + old_cfg_addr.to_hex() +
" failed to pass per-parameted validity checks, or one of mandatory parameters is missing"); " failed to pass per-parameter validity checks, or one of mandatory parameters is missing");
} }
if (block::important_config_parameters_changed(new_cfg_root, old_cfg_root)) { if (block::important_config_parameters_changed(new_cfg_root, old_cfg_root)) {
// same as the check in Collator::create_mc_state_extra() // same as the check in Collator::create_mc_state_extra()

View file

@ -107,6 +107,10 @@ inline ErrorCtxSet ErrorCtx::set_guard(std::vector<std::string> str_list) {
*/ */
class ValidateQuery : public td::actor::Actor { class ValidateQuery : public td::actor::Actor {
static constexpr int supported_version = 1;
static constexpr long long supported_capabilities =
ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion;
public: public:
ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev, ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,

View file

@ -382,7 +382,6 @@ void ArchiveImporter::finish_query() {
if (promise_) { if (promise_) {
promise_.set_value( promise_.set_value(
std::vector<BlockSeqno>{state_->get_seqno(), std::min<BlockSeqno>(state_->get_seqno(), shard_client_seqno_)}); std::vector<BlockSeqno>{state_->get_seqno(), std::min<BlockSeqno>(state_->get_seqno(), shard_client_seqno_)});
td::unlink(path_).ensure();
} }
stop(); stop();
} }

View file

@ -1393,6 +1393,39 @@ void ValidatorManagerImpl::start_up() {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::started, R.move_as_ok()); td::actor::send_closure(SelfId, &ValidatorManagerImpl::started, R.move_as_ok());
}); });
auto to_import_dir = db_root_ + "/import";
auto S = td::WalkPath::run(to_import_dir, [&](td::CSlice cfname, td::WalkPath::Type t) -> void {
auto fname = td::Slice(cfname);
if (t == td::WalkPath::Type::NotDir) {
auto d = fname.rfind('/');
if (d != td::Slice::npos) {
fname = fname.substr(d + 1);
}
if (fname.size() <= 13) {
return;
}
if (fname.substr(fname.size() - 5) != ".pack") {
return;
}
fname = fname.substr(0, fname.size() - 5);
if (fname.substr(0, 8) != "archive.") {
return;
}
fname = fname.substr(8);
auto v = td::to_integer_safe<BlockSeqno>(fname);
if (v.is_error()) {
return;
}
auto pos = v.move_as_ok();
LOG(INFO) << "found archive slice '" << cfname << "' for position " << pos;
to_import_[pos] = std::make_pair(cfname.str(), true);
}
});
if (S.is_error()) {
LOG(INFO) << "failed to load blocks from import dir: " << S;
}
validator_manager_init(opts_, actor_id(this), db_.get(), std::move(P)); validator_manager_init(opts_, actor_id(this), db_.get(), std::move(P));
check_waiters_at_ = td::Timestamp::in(1.0); check_waiters_at_ = td::Timestamp::in(1.0);
@ -1475,23 +1508,35 @@ void ValidatorManagerImpl::download_next_archive() {
finish_prestart_sync(); finish_prestart_sync();
return; return;
} }
auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno());
auto it = to_import_.upper_bound(seqno);
if (it != to_import_.begin()) {
it--;
if (it->second.second) {
it->second.second = false;
downloaded_archive_slice(it->second.first, false);
return;
}
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::string> R) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::string> R) {
if (R.is_error()) { if (R.is_error()) {
LOG(INFO) << "failed to download archive slice: " << R.error(); LOG(INFO) << "failed to download archive slice: " << R.error();
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); }, delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
td::Timestamp::in(2.0)); td::Timestamp::in(2.0));
} else { } else {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::downloaded_archive_slice, R.move_as_ok()); td::actor::send_closure(SelfId, &ValidatorManagerImpl::downloaded_archive_slice, R.move_as_ok(), true);
} }
}); });
auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno());
callback_->download_archive(seqno + 1, db_root_ + "/tmp/", td::Timestamp::in(3600.0), std::move(P)); callback_->download_archive(seqno + 1, db_root_ + "/tmp/", td::Timestamp::in(3600.0), std::move(P));
} }
void ValidatorManagerImpl::downloaded_archive_slice(std::string name) { void ValidatorManagerImpl::downloaded_archive_slice(std::string name, bool is_tmp) {
LOG(INFO) << "downloaded archive slice: " << name; LOG(INFO) << "downloaded archive slice: " << name;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::vector<BlockSeqno>> R) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), name, is_tmp](td::Result<std::vector<BlockSeqno>> R) {
if (is_tmp) {
td::unlink(name).ensure();
}
if (R.is_error()) { if (R.is_error()) {
LOG(INFO) << "failed to check downloaded archive slice: " << R.error(); LOG(INFO) << "failed to check downloaded archive slice: " << R.error();
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); }, delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
@ -1539,6 +1584,8 @@ void ValidatorManagerImpl::checked_archive_slice(std::vector<BlockSeqno> seqno)
} }
void ValidatorManagerImpl::finish_prestart_sync() { void ValidatorManagerImpl::finish_prestart_sync() {
to_import_.clear();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure(); R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerImpl::completed_prestart_sync); td::actor::send_closure(SelfId, &ValidatorManagerImpl::completed_prestart_sync);
@ -1665,6 +1712,16 @@ void ValidatorManagerImpl::update_shards() {
if (!validator_id.is_zero()) { if (!validator_id.is_zero()) {
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash); auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
// DIRTY. But we don't want to create hardfork now
// TODO! DELETE IT LATER
if (last_masterchain_seqno_ >= 2904932 && val_set->get_catchain_seqno() == 44896) {
if (opts_->zero_block_id().file_hash.to_hex() ==
"5E994FCF4D425C0A6CE6A792594B7173205F740A39CD56F537DEFD28B48A0F6E") {
val_group_id[0] = !val_group_id[0];
}
}
VLOG(VALIDATOR_DEBUG) << "validating group " << val_group_id; VLOG(VALIDATOR_DEBUG) << "validating group " << val_group_id;
auto it = validator_groups_.find(val_group_id); auto it = validator_groups_.find(val_group_id);
if (it != validator_groups_.end()) { if (it != validator_groups_.end()) {

View file

@ -264,7 +264,7 @@ class ValidatorManagerImpl : public ValidatorManager {
bool out_of_sync(); bool out_of_sync();
void prestart_sync(); void prestart_sync();
void download_next_archive(); void download_next_archive();
void downloaded_archive_slice(std::string name); void downloaded_archive_slice(std::string name, bool is_tmp);
void checked_archive_slice(std::vector<BlockSeqno> seqno); void checked_archive_slice(std::vector<BlockSeqno> seqno);
void finish_prestart_sync(); void finish_prestart_sync();
void completed_prestart_sync(); void completed_prestart_sync();
@ -556,6 +556,8 @@ class ValidatorManagerImpl : public ValidatorManager {
td::actor::ActorOwn<AsyncStateSerializer> serializer_; td::actor::ActorOwn<AsyncStateSerializer> serializer_;
std::map<BlockSeqno, std::pair<std::string, bool>> to_import_;
private: private:
std::unique_ptr<Callback> callback_; std::unique_ptr<Callback> callback_;
td::actor::ActorOwn<Db> db_; td::actor::ActorOwn<Db> db_;