mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
emergency update
This commit is contained in:
parent
5d846e0aaf
commit
9f351fc29f
87 changed files with 2486 additions and 655 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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>());
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
84
adnl/adnl-received-mask.h
Normal 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
|
|
@ -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
97
adnl/adnl-tunnel.cpp
Normal 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
73
adnl/adnl-tunnel.h
Normal 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
|
12
adnl/adnl.h
12
adnl/adnl.h
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ")"
|
||||||
//
|
//
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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)))) ||
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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"};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
22
doc/tvm.tex
22
doc/tvm.tex
|
@ -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}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
@ -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.
|
@ -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;
|
||||||
|
|
|
@ -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); }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue