mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +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
|
||||
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
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
#include "adnl-network-manager.hpp"
|
||||
#include "adnl-peer-table.h"
|
||||
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
@ -27,25 +31,84 @@ td::actor::ActorOwn<AdnlNetworkManager> AdnlNetworkManager::create(td::uint16 po
|
|||
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 {
|
||||
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:
|
||||
td::actor::ActorShared<AdnlNetworkManagerImpl> manager_;
|
||||
size_t idx_;
|
||||
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();
|
||||
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_) {
|
||||
LOG(ERROR) << this << ": dropping IN message [?->?]: peer table unitialized";
|
||||
return;
|
||||
|
@ -54,6 +117,96 @@ void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
|
|||
VLOG(ADNL_WARNING) << this << ": dropping ERROR message: " << message.error;
|
||||
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()) {
|
||||
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();
|
||||
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,
|
||||
td::uint32 priority, td::BufferSlice data) {
|
||||
auto randseed = 1; // use DST?
|
||||
while (priority > 0) {
|
||||
if (out_desc_[priority].size() > 0) {
|
||||
break;
|
||||
}
|
||||
priority--;
|
||||
}
|
||||
if (out_desc_[priority].size() == 0) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: no out desc";
|
||||
auto it = adnl_id_2_cat_.find(src_id);
|
||||
if (it == adnl_id_2_cat_.end()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: unknown src";
|
||||
return;
|
||||
}
|
||||
|
||||
auto &dv = out_desc_[priority];
|
||||
auto &v = dv[randseed % dv.size()];
|
||||
auto out = choose_out_iface(it->second, priority);
|
||||
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()) {
|
||||
auto it = udp_servers_.find(static_cast<td::uint16>(v.addr.get_port()));
|
||||
CHECK(it != udp_servers_.end());
|
||||
|
||||
td::UdpMessage M;
|
||||
M.address = dst_addr;
|
||||
M.data = std::move(data);
|
||||
|
||||
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 {
|
||||
auto it = udp_servers_.find(out_udp_port_);
|
||||
CHECK(it != udp_servers_.end());
|
||||
AdnlProxy::Packet p;
|
||||
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(
|
||||
AdnlProxy::Packet{dst_addr.get_ipv4(), static_cast<td::uint16>(dst_addr.get_port()), std::move(data)});
|
||||
auto enc = v.proxy->encrypt(std::move(p));
|
||||
|
||||
td::UdpMessage M;
|
||||
M.address = v.addr;
|
||||
M.address = v.proxy_addr;
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
|||
#include "adnl-node-id.hpp"
|
||||
#include "adnl-proxy-types.h"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
namespace td {
|
||||
class UdpServer;
|
||||
}
|
||||
|
@ -36,6 +38,8 @@ namespace adnl {
|
|||
|
||||
class AdnlPeerTable;
|
||||
|
||||
using AdnlCategoryMask = std::bitset<256>;
|
||||
|
||||
class AdnlNetworkConnection : public td::actor::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
|
@ -56,7 +60,7 @@ class AdnlNetworkManager : public td::actor::Actor {
|
|||
public:
|
||||
virtual ~Callback() = default;
|
||||
//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);
|
||||
|
||||
|
@ -64,14 +68,16 @@ class AdnlNetworkManager : public td::actor::Actor {
|
|||
|
||||
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_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, 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, 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,
|
||||
td::uint32 priority, td::BufferSlice data) = 0;
|
||||
//virtual void send_tcp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
|
||||
// td::uint32 priority, td::BufferSlice data) = 0;
|
||||
//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;
|
||||
virtual void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) = 0;
|
||||
|
||||
static constexpr td::uint32 get_mtu() {
|
||||
return 1440;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "adnl-network-manager.h"
|
||||
#include "adnl-received-mask.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
|
@ -41,16 +42,61 @@ class AdnlPeerTable;
|
|||
class AdnlNetworkManagerImpl : public AdnlNetworkManager {
|
||||
public:
|
||||
struct OutDesc {
|
||||
td::IPAddress addr;
|
||||
td::uint16 port;
|
||||
td::IPAddress proxy_addr;
|
||||
std::shared_ptr<AdnlProxy> proxy;
|
||||
size_t socket_idx;
|
||||
td::int64 out_seqno{0};
|
||||
AdnlCategoryMask cat_mask{0};
|
||||
|
||||
bool is_proxy() const {
|
||||
return proxy != nullptr;
|
||||
}
|
||||
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) {
|
||||
}
|
||||
|
@ -59,45 +105,60 @@ class AdnlNetworkManagerImpl : public AdnlNetworkManager {
|
|||
callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void add_self_addr(td::IPAddress addr, td::uint32 priority) override {
|
||||
auto x = OutDesc{addr, nullptr};
|
||||
auto &v = out_desc_[priority];
|
||||
for (auto &y : v) {
|
||||
if (x == y) {
|
||||
void alarm() override;
|
||||
void start_up() override {
|
||||
alarm_timestamp() = td::Timestamp::in(60.0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
out_desc_[priority].push_back(std::move(x));
|
||||
add_listening_udp_port(static_cast<td::uint16>(addr.get_port()));
|
||||
}
|
||||
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override {
|
||||
auto x = OutDesc{addr, std::move(proxy)};
|
||||
auto &v = out_desc_[priority];
|
||||
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_);
|
||||
if (desc.is_proxy()) {
|
||||
udp_sockets_[socket_idx].allow_proxy = true;
|
||||
proxy_addrs_[desc.proxy->id()] = in_desc_.size();
|
||||
} else {
|
||||
CHECK(udp_sockets_[socket_idx].in_desc == std::numeric_limits<size_t>::max());
|
||||
udp_sockets_[socket_idx].in_desc = in_desc_.size();
|
||||
}
|
||||
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,
|
||||
td::BufferSlice data) override;
|
||||
|
||||
void add_listening_udp_port(td::uint16 port);
|
||||
void receive_udp_message(td::UdpMessage message);
|
||||
void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) override {
|
||||
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:
|
||||
std::unique_ptr<Callback> callback_;
|
||||
|
||||
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 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_;
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "utils.hpp"
|
||||
#include "adnl-query.h"
|
||||
#include "adnl-ext-client.h"
|
||||
#include "adnl-tunnel.h"
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
|
||||
return;
|
||||
|
@ -60,14 +61,22 @@ void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data)
|
|||
|
||||
auto it = local_ids_.find(dst);
|
||||
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;
|
||||
}
|
||||
|
||||
AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
|
||||
auto it2 = channels_.find(dst_chan_id);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -109,7 +118,7 @@ void AdnlPeerTableImpl::receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket
|
|||
<< "]: unknown dst (but how did we decrypt message?)";
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
if (!addr_list.empty()) {
|
||||
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.second,
|
||||
it2->second.first.get(), std::move(addr_list));
|
||||
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.mode,
|
||||
it2->second.local_id.get(), std::move(addr_list));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +161,7 @@ void AdnlPeerTableImpl::send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst
|
|||
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});
|
||||
}
|
||||
|
||||
|
@ -185,23 +194,32 @@ void AdnlPeerTableImpl::send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std
|
|||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
VLOG(ADNL_INFO) << "adnl: adding local id " << a;
|
||||
|
||||
auto it = local_ids_.find(a);
|
||||
|
||||
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 {
|
||||
local_ids_.emplace(
|
||||
a, std::make_pair(td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list), mode,
|
||||
actor_id(this), keyring_, dht_node_),
|
||||
mode));
|
||||
a, LocalIdInfo{td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list), mode,
|
||||
actor_id(this), keyring_, dht_node_),
|
||||
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);
|
||||
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) {
|
||||
auto it = local_ids_.find(dst);
|
||||
|
||||
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_);
|
||||
}
|
||||
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 {
|
||||
public:
|
||||
void receive_packet(td::IPAddress addr, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(data));
|
||||
void receive_packet(td::IPAddress addr, AdnlCategoryMask cat_mask, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(cat_mask), std::move(data));
|
||||
}
|
||||
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));
|
||||
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) {
|
||||
|
@ -262,7 +284,7 @@ void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddres
|
|||
promise.set_error(td::Status::Error(ErrorCode::notready));
|
||||
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) {
|
||||
|
@ -271,11 +293,14 @@ void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode>
|
|||
promise.set_error(td::Status::Error(ErrorCode::notready));
|
||||
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) {
|
||||
auto success = channels_.emplace(id, channel).second;
|
||||
void AdnlPeerTableImpl::register_channel(AdnlChannelIdShort id, AdnlNodeIdShort local_id,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -317,14 +342,14 @@ AdnlPeerTableImpl::AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<key
|
|||
void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) {
|
||||
auto it = local_ids_.find(dst);
|
||||
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,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto it = local_ids_.find(dst);
|
||||
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 {
|
||||
LOG(WARNING) << "deliver query: unknown dst " << 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) {
|
||||
auto it = local_ids_.find(dst);
|
||||
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 {
|
||||
LOG(WARNING) << "decrypt message: unknown dst " << 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)));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::create_tunnel(AdnlNodeIdShort dst, td::uint32 size,
|
||||
td::Promise<std::pair<td::actor::ActorOwn<AdnlTunnel>, AdnlAddress>> promise) {
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // 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 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 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 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_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 send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message, td::uint32 flags) 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 {
|
||||
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 subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) 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_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) 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 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,
|
||||
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 {};
|
||||
PrintId print_id() const {
|
||||
return PrintId{};
|
||||
}
|
||||
|
||||
private:
|
||||
struct LocalIdInfo {
|
||||
td::actor::ActorOwn<AdnlLocalId> local_id;
|
||||
td::uint8 cat;
|
||||
td::uint32 mode;
|
||||
};
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager_;
|
||||
|
@ -114,13 +123,14 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
|
|||
void deliver_one_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message);
|
||||
|
||||
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeer>> peers_;
|
||||
std::map<AdnlNodeIdShort, std::pair<td::actor::ActorOwn<AdnlLocalId>, td::uint32>> local_ids_;
|
||||
std::map<AdnlChannelIdShort, td::actor::ActorId<AdnlChannel>> channels_;
|
||||
std::map<AdnlNodeIdShort, LocalIdInfo> local_ids_;
|
||||
std::map<AdnlChannelIdShort, std::pair<td::actor::ActorId<AdnlChannel>, td::uint8>> channels_;
|
||||
|
||||
td::actor::ActorOwn<AdnlDb> db_;
|
||||
|
||||
td::actor::ActorOwn<AdnlExtServer> ext_server_;
|
||||
|
||||
AdnlNodeIdShort proxy_addr_;
|
||||
//std::map<td::uint64, td::actor::ActorId<AdnlQuery>> out_queries_;
|
||||
//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_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 {
|
||||
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
|
||||
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
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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/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()));
|
||||
|
||||
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 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);
|
||||
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()},
|
||||
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::adnl_ping::ID),
|
||||
std::make_unique<ton::adnl::Callback>());
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-proxy-types.hpp"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
|
@ -27,59 +27,84 @@ namespace ton {
|
|||
|
||||
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 {
|
||||
auto date = static_cast<td::uint32>(td::Clocks::system());
|
||||
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>(
|
||||
packet.ip, packet.port, date, sha256_bits256(packet.data.as_slice()), shared_secret_);
|
||||
|
||||
auto obj = create_serialize_tl_object<ton_api::adnl_proxyToFast>(packet.ip, packet.port, date, signature);
|
||||
td::BufferSlice res{32 + obj.size() + packet.data.size()};
|
||||
auto S = res.as_slice();
|
||||
S.copy_from(td::Bits256::zero().as_slice());
|
||||
if (!packet.date) {
|
||||
packet.date = static_cast<td::int32>(td::Clocks::system());
|
||||
packet.flags |= 8;
|
||||
}
|
||||
auto obj = create_tl_object<ton_api::adnl_proxyPacketHeader>(id_, packet.flags, packet.ip, packet.port,
|
||||
packet.adnl_start_time, packet.seqno, packet.date,
|
||||
td::sha256_bits256(packet.data.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.copy_from(obj.as_slice());
|
||||
S.remove_prefix(obj.size());
|
||||
S.copy_from(packet.data.as_slice());
|
||||
S.copy_from(shared_secret_.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 {
|
||||
if (packet.size() < 36) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too short packet");
|
||||
TRY_RESULT(obj, fetch_tl_prefix<ton_api::adnl_proxyPacketHeader>(packet, false));
|
||||
if (obj->proxy_id_ != id_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad proxy id");
|
||||
}
|
||||
|
||||
td::Bits256 v;
|
||||
v.as_slice().copy_from(packet.as_slice().truncate(32));
|
||||
if (!v.is_zero()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "non-zero DST");
|
||||
}
|
||||
packet.confirm_read(32);
|
||||
auto signature = std::move(obj->signature_);
|
||||
obj->signature_ = td::sha256_bits256(packet.as_slice());
|
||||
|
||||
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) {
|
||||
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_) {
|
||||
if (td::sha256_bits256(td::Slice(data, 64)) != 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) {
|
||||
std::shared_ptr<AdnlProxy> R;
|
||||
ton_api::downcast_call(
|
||||
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) {
|
||||
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
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -28,14 +28,19 @@ namespace adnl {
|
|||
class AdnlProxy {
|
||||
public:
|
||||
struct Packet {
|
||||
td::uint32 flags;
|
||||
td::uint32 ip;
|
||||
td::uint16 port;
|
||||
td::int32 adnl_start_time;
|
||||
td::int64 seqno;
|
||||
td::int32 date{0};
|
||||
td::BufferSlice data;
|
||||
};
|
||||
virtual ~AdnlProxy() = default;
|
||||
virtual td::BufferSlice encrypt(Packet 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 const td::Bits256 &id() const = 0;
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -28,31 +28,42 @@ namespace adnl {
|
|||
|
||||
class AdnlProxyNone : public AdnlProxy {
|
||||
public:
|
||||
AdnlProxyNone() {
|
||||
AdnlProxyNone(td::Bits256 id) : id_(id) {
|
||||
}
|
||||
td::BufferSlice encrypt(Packet packet) const override {
|
||||
return std::move(packet.data);
|
||||
}
|
||||
td::Result<Packet> decrypt(td::BufferSlice packet) const override {
|
||||
return Packet{0, 0, std::move(packet)};
|
||||
td::BufferSlice d{packet.data.size() + 32};
|
||||
d.as_slice().copy_from(id_.as_slice());
|
||||
d.as_slice().remove_prefix(32).copy_from(packet.data.as_slice());
|
||||
return d;
|
||||
}
|
||||
td::Result<Packet> decrypt(td::BufferSlice packet) 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 {
|
||||
public:
|
||||
AdnlProxyFast(td::Slice shared_secret)
|
||||
: shared_secret_(sha256_bits256(shared_secret)), shared_secret_raw_(shared_secret) {
|
||||
AdnlProxyFast(td::Bits256 id, td::Slice shared_secret)
|
||||
: id_(id), shared_secret_(sha256_bits256(shared_secret)), shared_secret_raw_(shared_secret) {
|
||||
}
|
||||
td::BufferSlice encrypt(Packet packet) const override;
|
||||
td::Result<Packet> decrypt(td::BufferSlice packet) 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:
|
||||
td::Bits256 id_;
|
||||
td::Bits256 shared_secret_;
|
||||
td::SharedSlice shared_secret_raw_;
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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/utils/buffer.h"
|
||||
|
@ -35,11 +35,13 @@
|
|||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/port/user.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "common/checksum.h"
|
||||
#include "common/errorcode.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "adnl-proxy-types.h"
|
||||
#include "adnl-received-mask.h"
|
||||
#include <map>
|
||||
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
|
@ -50,12 +52,19 @@ namespace ton {
|
|||
|
||||
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 {
|
||||
public:
|
||||
void start_up() override;
|
||||
void receive_common(td::BufferSlice data);
|
||||
void receive_from_client(td::BufferSlice data);
|
||||
void receive_to_client(td::BufferSlice data);
|
||||
void receive_common(td::IPAddress addr, td::BufferSlice data);
|
||||
void receive_from_client(td::IPAddress addr, 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)
|
||||
: 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::actor::ActorOwn<td::UdpServer> out_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() {
|
||||
|
@ -81,15 +94,18 @@ void Receiver::start_up() {
|
|||
const td::uint32 mode_;
|
||||
void on_udp_message(td::UdpMessage udp_message) override {
|
||||
if (udp_message.error.is_error()) {
|
||||
LOG(DEBUG) << udp_message.error;
|
||||
LOG(INFO) << "receifed udp message with error: " << udp_message.error;
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
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) {
|
||||
LOG(INFO) << "dropping too short packet: size=" << data.size();
|
||||
return;
|
||||
}
|
||||
|
||||
td::Bits256 id;
|
||||
id.as_slice().copy_from(data.as_slice().truncate(32));
|
||||
|
||||
if (id.is_zero()) {
|
||||
receive_from_client(std::move(data));
|
||||
if (proxy_->id().as_slice() == data.as_slice().truncate(32)) {
|
||||
receive_from_client(addr, std::move(data));
|
||||
} 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));
|
||||
if (F.is_error()) {
|
||||
LOG(INFO) << "proxy: failed to decrypt message from client: " << F.move_as_error();
|
||||
return;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
td::UdpMessage M;
|
||||
M.address = a;
|
||||
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,
|
||||
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_;
|
||||
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;
|
||||
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,
|
||||
std::move(M));
|
||||
|
@ -204,7 +326,7 @@ int main(int argc, char *argv[]) {
|
|||
});
|
||||
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
|
||||
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);
|
||||
td::log_interface = logger_.get();
|
||||
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()));
|
||||
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([&] {
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -34,9 +34,10 @@ class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
|
|||
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,
|
||||
td::uint32 priority, td::BufferSlice data) override {
|
||||
|
@ -48,7 +49,9 @@ class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
|
|||
return;
|
||||
}
|
||||
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) {
|
||||
|
@ -68,6 +71,8 @@ class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
|
|||
CHECK(p >= 0 && p <= 1);
|
||||
loss_probability_ = p;
|
||||
}
|
||||
void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) override {
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -58,6 +58,8 @@ class AdnlSenderInterface : public td::actor::Actor {
|
|||
td::uint64 max_answer_size) = 0;
|
||||
};
|
||||
|
||||
class AdnlTunnel : public td::actor::Actor {};
|
||||
|
||||
class Adnl : public AdnlSenderInterface {
|
||||
public:
|
||||
class Callback {
|
||||
|
@ -88,10 +90,10 @@ class Adnl : public AdnlSenderInterface {
|
|||
virtual void add_static_nodes_from_config(AdnlNodesList nodes) = 0;
|
||||
|
||||
// adds local id. After that you can send/receive messages from/to this id
|
||||
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) {
|
||||
add_id_ex(std::move(id), std::move(addr_list), 0);
|
||||
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint8 cat) {
|
||||
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;
|
||||
|
||||
// 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,
|
||||
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);
|
||||
|
||||
|
|
|
@ -391,7 +391,7 @@ endif()
|
|||
add_executable(create-state block/create-state.cpp)
|
||||
target_include_directories(create-state PUBLIC $<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)
|
||||
target_link_libraries_system(create-state wingetopt)
|
||||
endif()
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "crypto/Ed25519.h"
|
||||
|
||||
|
@ -310,6 +310,10 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
|
|||
return std::move(result);
|
||||
}
|
||||
|
||||
int Ed25519::version() {
|
||||
return OPENSSL_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int Ed25519::version() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -65,6 +65,8 @@ class Ed25519 {
|
|||
static Result<PrivateKey> generate_private_key();
|
||||
|
||||
static Result<SecureString> compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key);
|
||||
|
||||
static int version();
|
||||
};
|
||||
|
||||
} // 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) {
|
||||
auto res = block::Config::unpack_param_dict(std::move(param_dict_root));
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR)
|
||||
<< "invalid mandatory parameters dictionary while checking existence of all mandatory configuration parameters";
|
||||
return false;
|
||||
}
|
||||
for (int x : res.move_as_ok()) {
|
||||
// LOG(DEBUG) << "checking whether mandatory configuration parameter #" << x << " exists";
|
||||
if (!dict.int_key_exists(x)) {
|
||||
LOG(ERROR) << "configuration parameter #" << x
|
||||
<< " (declared as mandatory in configuration parameter #9) is missing";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// LOG(DEBUG) << "all mandatory configuration parameters present";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -414,7 +414,7 @@ block_info#9bc7a987 version:uint32
|
|||
after_split:(## 1)
|
||||
want_split:Bool want_merge:Bool
|
||||
key_block:Bool vert_seqno_incr:(## 1)
|
||||
flags:(## 8)
|
||||
flags:(## 8) { flags <= 1 }
|
||||
seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr }
|
||||
{ prev_seq_no:# } { ~prev_seq_no + 1 = seq_no }
|
||||
shard:ShardIdent gen_utime:uint32
|
||||
|
@ -423,6 +423,7 @@ block_info#9bc7a987 version:uint32
|
|||
gen_catchain_seqno:uint32
|
||||
min_ref_mc_seqno:uint32
|
||||
prev_key_block_seqno:uint32
|
||||
gen_software:flags . 0?GlobalVersion
|
||||
master_ref:not_master?^BlkMasterInfo
|
||||
prev_ref:^(BlkPrevInfo after_merge)
|
||||
prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0)
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/port/signals.h"
|
||||
|
||||
#include "tonlib/keys/Mnemonic.h"
|
||||
|
||||
#include "block.h"
|
||||
#include "block-parse.h"
|
||||
#include "block-auto.h"
|
||||
|
@ -634,7 +636,25 @@ void interpret_sub_extra_currencies(vm::Stack& stack) {
|
|||
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) {
|
||||
using namespace std::placeholders;
|
||||
d.def_stack_word("verb@ ", interpret_get_verbosity);
|
||||
d.def_stack_word("verb! ", interpret_set_verbosity);
|
||||
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("CC+? ", interpret_add_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;
|
||||
|
@ -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-skip ", interpret_tlb_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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
if (ap.remaining_balance.extra.not_null() || req.extra.not_null()) {
|
||||
LOG(WARNING) << "subtracting extra currencies: "
|
||||
<< block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus "
|
||||
<< block::CurrencyCollection{0, req.extra}.to_str() << " equals "
|
||||
<< block::CurrencyCollection{0, new_extra}.to_str();
|
||||
LOG(DEBUG) << "subtracting extra currencies: "
|
||||
<< block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus "
|
||||
<< block::CurrencyCollection{0, req.extra}.to_str() << " equals "
|
||||
<< block::CurrencyCollection{0, new_extra}.to_str();
|
||||
}
|
||||
|
||||
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>();
|
||||
BouncePhase& bp = *bounce_phase;
|
||||
block::gen::Message::Record msg;
|
||||
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();
|
||||
return false;
|
||||
}
|
||||
if (cs.fetch_ulong(1)) {
|
||||
cs = vm::load_cell_slice(cs.prefetch_ref());
|
||||
}
|
||||
info.ihr_disabled = true;
|
||||
info.bounce = false;
|
||||
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
|
||||
&& 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(0, 2) // init:(Maybe ...) state:(Either ..)
|
||||
&& cb.finalize_to(bp.out_msg));
|
||||
&& cb.store_bool_bool(false)); // init:(Maybe ...)
|
||||
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) {
|
||||
std::cerr << "generated bounced message: ";
|
||||
LOG(INFO) << "generated bounced message: ";
|
||||
block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg);
|
||||
}
|
||||
out_msgs.push_back(bp.out_msg);
|
||||
|
|
|
@ -139,6 +139,7 @@ struct ComputePhaseConfig {
|
|||
|
||||
struct ActionPhaseConfig {
|
||||
int max_actions{255};
|
||||
int bounce_msg_body{0}; // usually 0 or 256 bits
|
||||
MsgPrices fwd_std;
|
||||
MsgPrices fwd_mc; // from/to masterchain
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
x.write() &= *y;
|
||||
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 mod(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, RefInt256 y);
|
||||
extern RefInt256 operator|(RefInt256 x, RefInt256 y);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
library TVM_Asm
|
||||
// simple TVM Assembler
|
||||
variable @atend
|
||||
'nop @atend !
|
||||
{ "not in asm context" abort } @atend !
|
||||
{ `normal eq? not abort"must be terminated by }>" } : @normal?
|
||||
{ @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend
|
||||
{ @pushatend <b } : <{
|
||||
|
@ -12,10 +12,11 @@ variable @atend
|
|||
{ @atend @ 2 { @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @|
|
||||
{ @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{
|
||||
{ over brembits <= } : @havebits
|
||||
{ rot + -rot + swap } : pair+
|
||||
{ rot >= -rot <= and } : 2x<=
|
||||
{ 2 pick brembitrefs 1- 2x<= } : @havebitrefs
|
||||
{ @havebits not ' @| if } : @ensurebits
|
||||
{ @havebitrefs not ' @| if } : @ensurebitrefs
|
||||
{ @havebits ' @| ifnot } : @ensurebits
|
||||
{ @havebitrefs ' @| ifnot } : @ensurebitrefs
|
||||
{ rot over @ensurebits -rot u, } : @simpleuop
|
||||
{ tuck sbitrefs @ensurebitrefs swap s, } : @addop
|
||||
{ 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, 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, rot ref, swap ref, @addopb } does create } : @Defop(ref*2)
|
||||
{ <b 0xef 8 u, swap 12 i, b> } : si()
|
||||
// x mi ma -- ?
|
||||
{ rot tuck >= -rot <= and } : @range
|
||||
|
@ -272,10 +274,27 @@ x{8A} @Defop(ref) PUSHREFCONT
|
|||
} cond
|
||||
} cond
|
||||
} dup : PUSHSLICE : SLICE
|
||||
{ tuck bbitrefs swap 16 + dup 7 and 3 -roll swap @havebitrefs
|
||||
not rot or
|
||||
{ swap b> PUSHREFCONT }
|
||||
{ over bbitrefs 2dup 120 0 2x<=
|
||||
// ( b' -- ? )
|
||||
{ bbitrefs or 0= } : @cont-empty?
|
||||
{ bbits 7 and 0= } : @cont-aligned?
|
||||
// ( 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+ }
|
||||
{ rot x{8F_} s, swap 2 u, swap 3 >> 7 u, swap b+ } cond
|
||||
} cond
|
||||
|
@ -320,12 +339,16 @@ x{A985} @Defop MULDIVR
|
|||
x{A98C} @Defop MULDIVMOD
|
||||
x{A9A4} @Defop MULRSHIFT
|
||||
x{A9A5} @Defop MULRSHIFTR
|
||||
x{A9A6} @Defop MULRSHIFTC
|
||||
x{A9B4} @Defop(8u+1) MULRSHIFT#
|
||||
x{A9B5} @Defop(8u+1) MULRSHIFTR#
|
||||
x{A9B6} @Defop(8u+1) MULRSHIFTC#
|
||||
x{A9C4} @Defop LSHIFTDIV
|
||||
x{A9C5} @Defop LSHIFTDIVR
|
||||
x{A9C6} @Defop LSHIFTDIVC
|
||||
x{A9D4} @Defop(8u+1) LSHIFT#DIV
|
||||
x{A9D5} @Defop(8u+1) LSHIFT#DIVR
|
||||
x{A9D6} @Defop(8u+1) LSHIFT#DIVC
|
||||
x{AA} @Defop(8u+1) LSHIFT#
|
||||
x{AB} @Defop(8u+1) RSHIFT#
|
||||
x{AC} @Defop LSHIFT
|
||||
|
@ -628,46 +651,80 @@ x{DB3F} @Defop RETDATA
|
|||
x{DC} @Defop IFRET
|
||||
x{DD} @Defop IFNOTRET
|
||||
x{DE} @Defop IF
|
||||
{ }> PUSHCONT IF } : }>IF
|
||||
x{DF} @Defop IFNOT
|
||||
{ }> PUSHCONT IFNOT } : }>IFNOT
|
||||
' IFNOTRET : IF:
|
||||
' IFRET : IFNOT:
|
||||
x{E0} @Defop IFJMP
|
||||
{ }> PUSHCONT IFJMP } : }>IFJMP
|
||||
{ { @normal? PUSHCONT IFJMP } @doafter<{ } : IFJMP:<{
|
||||
x{E1} @Defop IFNOTJMP
|
||||
{ }> PUSHCONT IFNOTJMP } : }>IFNOTJMP
|
||||
{ { @normal? PUSHCONT IFNOTJMP } @doafter<{ } : IFNOTJMP:<{
|
||||
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{E301} @Defop(ref) IFNOTREF
|
||||
x{E302} @Defop(ref) IFJMPREF
|
||||
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{E305} @Defop CONDSELCHK
|
||||
x{E308} @Defop IFRETALT
|
||||
|
@ -676,18 +733,22 @@ x{E309} @Defop IFNOTRETALT
|
|||
{ <b x{E3B_} swap 5 u, @addopb } : IFNBITJMP
|
||||
{ <b x{E3D_} swap 5 u, swap ref, @addopb } : IFBITJMPREF
|
||||
{ <b x{E3F_} swap 5 u, swap ref, @addopb } : IFNBITJMPREF
|
||||
|
||||
x{E4} @Defop REPEAT
|
||||
{ }> PUSHCONT REPEAT } : }>REPEAT
|
||||
{ { @normal? PUSHCONT REPEAT } @doafter<{ } : REPEAT:<{
|
||||
x{E5} dup @Defop REPEATEND @Defop REPEAT:
|
||||
x{E6} @Defop UNTIL
|
||||
{ }> PUSHCONT UNTIL } : }>UNTIL
|
||||
{ { @normal? PUSHCONT UNTIL } @doafter<{ } : UNTIL:<{
|
||||
x{E7} dup @Defop UNTILEND @Defop UNTIL:
|
||||
x{E8} @Defop WHILE
|
||||
x{E9} @Defop WHILEEND
|
||||
x{EA} @Defop AGAIN
|
||||
x{EB} dup @Defop AGAINEND @Defop AGAIN:
|
||||
|
||||
{ `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
|
||||
{
|
||||
{ dup `do eq?
|
||||
|
@ -696,10 +757,34 @@ x{E9} @Defop WHILEEND
|
|||
} cond
|
||||
} @doafter<{
|
||||
} : WHILE:<{
|
||||
x{EA} @Defop AGAIN
|
||||
{ }> PUSHCONT AGAIN } : }>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
|
||||
//
|
||||
|
@ -745,6 +830,8 @@ x{EDF6} @Defop THENRET
|
|||
x{EDF7} @Defop THENRETALT
|
||||
x{EDF8} @Defop INVERT
|
||||
x{EDF9} @Defop BOOLEVAL
|
||||
x{EDFA} @Defop SAMEALT
|
||||
x{EDFB} @Defop SAMEALTSAVE
|
||||
// x{EE} is BLESSARGS
|
||||
//
|
||||
// dictionary subroutine call/jump primitives
|
||||
|
|
|
@ -111,6 +111,42 @@ recursive list-map {
|
|||
swap uncons -rot over execute -rot list-map cons
|
||||
} cond
|
||||
} 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 ")"
|
||||
//
|
||||
|
|
|
@ -177,28 +177,15 @@ void interpret_divmod(vm::Stack& stack, int round_mode) {
|
|||
}
|
||||
|
||||
void interpret_times_div(vm::Stack& stack, int round_mode) {
|
||||
auto z = stack.pop_int();
|
||||
auto y = stack.pop_int();
|
||||
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));
|
||||
auto z = stack.pop_int(), y = stack.pop_int(), x = stack.pop_int();
|
||||
stack.push_int(muldiv(std::move(x), std::move(y), std::move(z), round_mode));
|
||||
}
|
||||
|
||||
void interpret_times_divmod(vm::Stack& stack, int round_mode) {
|
||||
auto z = stack.pop_int();
|
||||
auto y = stack.pop_int();
|
||||
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));
|
||||
stack.push_int(td::make_refint(tmp));
|
||||
auto z = stack.pop_int(), y = stack.pop_int(), x = stack.pop_int();
|
||||
auto dm = muldivmod(std::move(x), std::move(y), std::move(z));
|
||||
stack.push_int(std::move(dm.first));
|
||||
stack.push_int(std::move(dm.second));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(x.int_const * y.int_const);
|
||||
x.unused();
|
||||
|
@ -492,6 +490,11 @@ AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
|||
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) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
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);
|
||||
}
|
||||
|
||||
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, int round_mode) {
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(div(x.int_const, y.int_const, round_mode));
|
||||
x.unused();
|
||||
|
@ -608,6 +609,11 @@ AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
|
|||
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) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
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);
|
||||
}
|
||||
|
||||
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 s = td::cmp(x, y);
|
||||
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("OR", 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), AsmOp::Custom("MULDIV", 3));
|
||||
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, -1));
|
||||
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("_==_", 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));
|
||||
|
|
|
@ -575,9 +575,9 @@ bool Optimizer::find_at_least(int pb) {
|
|||
(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_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_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
|
||||
? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
|
||||
: rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
|
||||
|
|
|
@ -23,6 +23,25 @@
|
|||
.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) {
|
||||
var cs = vset.begin_parse();
|
||||
throw_unless(9, cs~load_uint(8) == 0x12); ;; validators_ext#12 only
|
||||
|
@ -46,53 +65,14 @@
|
|||
.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);
|
||||
}
|
||||
|
||||
() 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);
|
||||
}
|
||||
|
||||
() 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
|
||||
() change_elector_code(slice cs) impure {
|
||||
var dest_addr = config_param(1).begin_parse().preload_uint(256);
|
||||
|
@ -114,7 +94,7 @@
|
|||
_ perform_action(cfg_dict, public_key, action, cs) {
|
||||
if (action == 0x43665021) {
|
||||
;; change one configuration parameter
|
||||
var param_index = cs~load_uint(32);
|
||||
var param_index = cs~load_int(32);
|
||||
var param_value = cs~load_ref();
|
||||
cs.end_parse();
|
||||
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);
|
||||
if (vset.null?()) {
|
||||
return (null(), 0);
|
||||
}
|
||||
var cs = begin_parse(vset);
|
||||
;; validators_ext#12 utime_since:uint32 utime_until:uint32
|
||||
;; 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);
|
||||
cs~skip_bits(32 + 32 + 16 + 16);
|
||||
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 (value, _) = dict.udict_get?(16, idx);
|
||||
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));
|
||||
}
|
||||
|
||||
;; 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 {
|
||||
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 {
|
||||
var signature = in_msg~load_bits(512);
|
||||
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!
|
||||
|
||||
( 9 10 18 20 21 22 23 24 25 28 34 ) config.mandatory_params!
|
||||
( -1000 -1001 9 10 32 34 36 ) config.critical_params!
|
||||
( 0 1 9 10 12 14 15 16 17 18 20 21 22 23 24 25 28 34 ) config.mandatory_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 ]
|
||||
// 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);
|
||||
}
|
||||
|
||||
(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 {
|
||||
;; 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();
|
||||
|
@ -82,10 +89,7 @@ _ unpack_owner_info(slice cs) inline_ref {
|
|||
send_raw_message(msg~load_ref(), mode);
|
||||
}
|
||||
pending_queries~udict_set_builder(64, query_id, begin_cell().store_int(0, 1));
|
||||
|
||||
(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));
|
||||
owner_infos~dec_flood(creator_i);
|
||||
} else {
|
||||
pending_queries~udict_set_builder(64, query_id, begin_cell()
|
||||
.store_uint(1, 1)
|
||||
|
@ -123,8 +127,8 @@ _ unpack_owner_info(slice cs) inline_ref {
|
|||
last_cleaned -= last_cleaned == 0;
|
||||
|
||||
(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?);
|
||||
(int public_key, int flood) = unpack_owner_info(owner_info);
|
||||
throw_unless(32, check_signature(root_hash, root_signature, public_key));
|
||||
|
||||
cell signatures = in_msg~load_dict();
|
||||
|
@ -154,11 +158,12 @@ _ unpack_owner_info(slice cs) inline_ref {
|
|||
cnt_bits |= mask;
|
||||
cnt += 1;
|
||||
|
||||
throw_if(41, ~ found? & (cnt < k) & (bound + ((60 * 60) << 32) > query_id));
|
||||
|
||||
set_gas_limit(100000);
|
||||
|
||||
ifnot (found?) {
|
||||
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);
|
||||
|
@ -178,12 +183,15 @@ _ unpack_owner_info(slice cs) inline_ref {
|
|||
bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago
|
||||
int old_last_cleaned = last_cleaned;
|
||||
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();
|
||||
if (f) {
|
||||
f = (i < bound);
|
||||
}
|
||||
if (f) {
|
||||
if (query~load_int(1)) {
|
||||
owner_infos~dec_flood(query~load_uint(8));
|
||||
}
|
||||
pending_queries = pending_queries';
|
||||
last_cleaned = i;
|
||||
need_save = -1;
|
||||
|
|
|
@ -64,6 +64,8 @@ cont bless(slice s) impure asm "BLESS";
|
|||
|
||||
int min(int x, int y) asm "MIN";
|
||||
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";
|
||||
() 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;
|
||||
}
|
||||
|
||||
td::Ref<vm::Tuple> prepare_vm_c7() {
|
||||
td::Ref<vm::Tuple> prepare_vm_c7(td::uint32 now) {
|
||||
// TODO: fix initialization of c7
|
||||
td::BitArray<256> rand_seed;
|
||||
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(0), // actions: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), // trans_lt: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) {
|
||||
td::uint32 now = 0;
|
||||
if (args.now) {
|
||||
now = args.now.unwrap();
|
||||
}
|
||||
if (!args.c7) {
|
||||
args.c7 = prepare_vm_c7();
|
||||
args.c7 = prepare_vm_c7(now);
|
||||
}
|
||||
if (!args.limits) {
|
||||
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 {
|
||||
td::uint32 now = 0;
|
||||
if (args.now) {
|
||||
now = args.now.unwrap();
|
||||
}
|
||||
if (!args.c7) {
|
||||
args.c7 = prepare_vm_c7();
|
||||
args.c7 = prepare_vm_c7(now);
|
||||
}
|
||||
if (!args.limits) {
|
||||
args.limits = vm::GasLimits{1000000};
|
||||
|
|
|
@ -55,6 +55,7 @@ class SmartContract : public td::CntObject {
|
|||
td::optional<vm::GasLimits> limits;
|
||||
td::optional<td::Ref<vm::Tuple>> c7;
|
||||
td::optional<td::Ref<vm::Stack>> stack;
|
||||
td::optional<td::int32> now;
|
||||
bool ignore_chksig{false};
|
||||
|
||||
Args() {
|
||||
|
@ -62,6 +63,10 @@ class SmartContract : public td::CntObject {
|
|||
Args(std::initializer_list<vm::StackEntry> 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) {
|
||||
unsigned crc = td::crc16(method_name);
|
||||
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);
|
||||
auto ms = ton::MultisigWallet::create(init_state);
|
||||
|
||||
td::uint64 query_id = 123 | ((100 * 60ull) << 32);
|
||||
ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize());
|
||||
// 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);
|
||||
td::uint32 now = 0;
|
||||
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(), 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++) {
|
||||
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) << "GAS: " << ans.gas_used;
|
||||
}
|
||||
|
@ -602,12 +644,12 @@ TEST(Smartcon, Multisig) {
|
|||
auto query = qb.create(49, keys[49]);
|
||||
|
||||
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) << "GAS: " << ans.gas_used;
|
||||
CHECK(ans.success);
|
||||
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));
|
||||
|
||||
{
|
||||
|
@ -618,7 +660,7 @@ TEST(Smartcon, Multisig) {
|
|||
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) << "GAS: " << ans.gas_used;
|
||||
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) {
|
||||
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);
|
||||
auto x = 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) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute ABS";
|
||||
VM_LOG(st) << "execute " << (quiet ? "QABS" : "ABS");
|
||||
stack.check_underflow(1);
|
||||
auto x = stack.pop_int();
|
||||
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 "";
|
||||
}
|
||||
cs.advance(pfx_bits);
|
||||
cs.advance_refs(1);
|
||||
return name;
|
||||
auto cell = cs.fetch_ref();
|
||||
return name + " (" + cell->get_hash().to_hex() + ")";
|
||||
}
|
||||
|
||||
int compute_len_push_ref(const CellSlice& cs, unsigned args, int pfx_bits) {
|
||||
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) {
|
||||
if (!cs.have(pfx_bits + data_bits)) {
|
||||
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
|
||||
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
|
||||
#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);
|
||||
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
|
||||
|
|
|
@ -26,10 +26,12 @@
|
|||
#include "vm/excno.hpp"
|
||||
#include "vm/vm.h"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
namespace vm {
|
||||
|
||||
int exec_execute(VmState* st) {
|
||||
VM_LOG(st) << "execute EXECUTE\n";
|
||||
VM_LOG(st) << "execute EXECUTE";
|
||||
auto cont = st->get_stack().pop_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,
|
||||
const char* name) {
|
||||
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);
|
||||
auto cell = cs.fetch_ref();
|
||||
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) {
|
||||
|
@ -349,7 +397,7 @@ int exec_if_bit_jmpref(VmState* st, CellSlice& cs, unsigned args, int pfx_bits)
|
|||
bool val = x->get_bit(bit);
|
||||
stack.push_int(std::move(x));
|
||||
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;
|
||||
}
|
||||
|
@ -365,66 +413,72 @@ std::string dump_if_bit_jmpref(CellSlice& cs, unsigned args, int pfx_bits) {
|
|||
return os.str();
|
||||
}
|
||||
|
||||
int exec_repeat(VmState* st) {
|
||||
int exec_repeat(VmState* st, bool brk) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute REPEAT\n";
|
||||
VM_LOG(st) << "execute REPEAT" << (brk ? "BRK" : "");
|
||||
stack.check_underflow(2);
|
||||
auto cont = stack.pop_cont();
|
||||
int c = stack.pop_smallint_range(0x7fffffff, 0x80000000);
|
||||
if (c <= 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();
|
||||
VM_LOG(st) << "execute REPEATEND\n";
|
||||
VM_LOG(st) << "execute REPEATEND" << (brk ? "BRK" : "");
|
||||
stack.check_underflow(1);
|
||||
int c = stack.pop_smallint_range(0x7fffffff, 0x80000000);
|
||||
if (c <= 0) {
|
||||
return st->ret();
|
||||
}
|
||||
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();
|
||||
VM_LOG(st) << "execute UNTIL\n";
|
||||
VM_LOG(st) << "execute UNTIL" << (brk ? "BRK" : "");
|
||||
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) {
|
||||
VM_LOG(st) << "execute UNTILEND\n";
|
||||
int exec_until_end(VmState* st, bool brk) {
|
||||
VM_LOG(st) << "execute UNTILEND" << (brk ? "BRK" : "");
|
||||
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();
|
||||
VM_LOG(st) << "execute WHILE\n";
|
||||
VM_LOG(st) << "execute WHILE" << (brk ? "BRK" : "");
|
||||
stack.check_underflow(2);
|
||||
auto body = 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) {
|
||||
VM_LOG(st) << "execute WHILEEND\n";
|
||||
int exec_while_end(VmState* st, bool brk) {
|
||||
VM_LOG(st) << "execute WHILEEND" << (brk ? "BRK" : "");
|
||||
auto cond = st->get_stack().pop_cont();
|
||||
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) {
|
||||
VM_LOG(st) << "execute AGAIN\n";
|
||||
int exec_again(VmState* st, bool brk) {
|
||||
VM_LOG(st) << "execute AGAIN" << (brk ? "BRK" : "");
|
||||
if (brk) {
|
||||
st->set_c1(st->extract_cc(3));
|
||||
}
|
||||
return st->again(st->get_stack().pop_cont());
|
||||
}
|
||||
|
||||
int exec_again_end(VmState* st) {
|
||||
VM_LOG(st) << "execute AGAINEND\n";
|
||||
int exec_again_end(VmState* st, bool brk) {
|
||||
VM_LOG(st) << "execute AGAINEND" << (brk ? "BRK" : "");
|
||||
if (brk) {
|
||||
st->c1_save_set();
|
||||
}
|
||||
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(0xe1, 8, "IFNOTJMP", exec_ifnot_jmp))
|
||||
.insert(OpcodeInstr::mksimple(0xe2, 8, "IFELSE", exec_if_else))
|
||||
.insert(OpcodeInstr::mkext(
|
||||
0xe300, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREF"),
|
||||
std::bind(exec_do_with_ref, _1, _2, _4,
|
||||
[](auto st, auto cont) { return st->get_stack().pop_bool() ? st->call(std::move(cont)) : 0; },
|
||||
"IFREF"),
|
||||
compute_len_push_ref))
|
||||
.insert(OpcodeInstr::mkext(
|
||||
0xe301, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTREF"),
|
||||
std::bind(exec_do_with_ref, _1, _2, _4,
|
||||
[](auto st, auto cont) { return st->get_stack().pop_bool() ? 0 : st->call(std::move(cont)); },
|
||||
"IFNOTREF"),
|
||||
compute_len_push_ref))
|
||||
.insert(OpcodeInstr::mkext(
|
||||
0xe302, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFJMPREF"),
|
||||
std::bind(exec_do_with_ref, _1, _2, _4,
|
||||
[](auto st, auto cont) { return st->get_stack().pop_bool() ? st->jump(std::move(cont)) : 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_ref, _1, _2, _4,
|
||||
[](auto st, auto cont) { return st->get_stack().pop_bool() ? 0 : st->jump(std::move(cont)); },
|
||||
"IFNOTJMPREF"),
|
||||
compute_len_push_ref))
|
||||
.insert(OpcodeInstr::mkext(0xe300, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREF"),
|
||||
std::bind(exec_do_with_cell, _1, _2, _4,
|
||||
[](auto st, auto cell) {
|
||||
return st->get_stack().pop_bool()
|
||||
? st->call(st->ref_to_cont(std::move(cell)))
|
||||
: 0;
|
||||
},
|
||||
"IFREF"),
|
||||
compute_len_push_ref))
|
||||
.insert(OpcodeInstr::mkext(0xe301, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTREF"),
|
||||
std::bind(exec_do_with_cell, _1, _2, _4,
|
||||
[](auto st, auto cell) {
|
||||
return st->get_stack().pop_bool()
|
||||
? 0
|
||||
: st->call(st->ref_to_cont(std::move(cell)));
|
||||
},
|
||||
"IFNOTREF"),
|
||||
compute_len_push_ref))
|
||||
.insert(OpcodeInstr::mkext(0xe302, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFJMPREF"),
|
||||
std::bind(exec_do_with_cell, _1, _2, _4,
|
||||
[](auto st, auto cell) {
|
||||
return st->get_stack().pop_bool()
|
||||
? st->jump(st->ref_to_cont(std::move(cell)))
|
||||
: 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(0xe305, 16, "CONDSELCHK", exec_condsel_chk))
|
||||
.insert(OpcodeInstr::mksimple(0xe308, 16, "IFRETALT", exec_ifretalt))
|
||||
.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::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(0xe5, 8, "REPEATEND", exec_repeat_end))
|
||||
.insert(OpcodeInstr::mksimple(0xe6, 8, "UNTIL", exec_until))
|
||||
.insert(OpcodeInstr::mksimple(0xe7, 8, "UNTILEND", exec_until_end))
|
||||
.insert(OpcodeInstr::mksimple(0xe8, 8, "WHILE", exec_while))
|
||||
.insert(OpcodeInstr::mksimple(0xe9, 8, "WHILEEND", exec_while_end))
|
||||
.insert(OpcodeInstr::mksimple(0xea, 8, "AGAIN", exec_again))
|
||||
.insert(OpcodeInstr::mksimple(0xeb, 8, "AGAINEND", exec_again_end));
|
||||
.insert(OpcodeInstr::mksimple(0xe4, 8, "REPEAT", std::bind(exec_repeat, _1, false)))
|
||||
.insert(OpcodeInstr::mksimple(0xe5, 8, "REPEATEND", std::bind(exec_repeat_end, _1, false)))
|
||||
.insert(OpcodeInstr::mksimple(0xe6, 8, "UNTIL", std::bind(exec_until, _1, false)))
|
||||
.insert(OpcodeInstr::mksimple(0xe7, 8, "UNTILEND", std::bind(exec_until_end, _1, false)))
|
||||
.insert(OpcodeInstr::mksimple(0xe8, 8, "WHILE", std::bind(exec_while, _1, false)))
|
||||
.insert(OpcodeInstr::mksimple(0xe9, 8, "WHILEEND", std::bind(exec_while_end, _1, false)))
|
||||
.insert(OpcodeInstr::mksimple(0xea, 8, "AGAIN", std::bind(exec_again, _1, false)))
|
||||
.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) {
|
||||
|
@ -706,6 +786,17 @@ int exec_save_ctr(VmState* st, unsigned args) {
|
|||
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) {
|
||||
unsigned idx = args & 15;
|
||||
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(0xedf8, 16, "INVERT", exec_invert))
|
||||
.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));
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -45,6 +45,7 @@ const char* get_exception_msg(Excno exc_no);
|
|||
|
||||
class VmError {
|
||||
Excno exc_no;
|
||||
bool msg_alloc = false;
|
||||
const char* msg;
|
||||
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, 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 {
|
||||
return static_cast<int>(exc_no);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,22 @@ int VmState::ret_alt(int 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<Stack> new_stk;
|
||||
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);
|
||||
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 {
|
||||
throw VmFatal{};
|
||||
}
|
||||
|
@ -313,6 +318,9 @@ class VmState final : public VmStateInterface {
|
|||
bool get_chksig_always_succeed() const {
|
||||
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:
|
||||
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
|
||||
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"
|
||||
|
||||
|
@ -70,8 +70,12 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
|
|||
[&](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();
|
||||
out_ip = in_ip;
|
||||
categories = obj.categories_;
|
||||
priority_categories = obj.priority_categories_;
|
||||
for (auto &cat : obj.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) {
|
||||
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());
|
||||
R.ensure();
|
||||
proxy = R.move_as_ok();
|
||||
categories = obj.categories_;
|
||||
priority_categories = obj.priority_categories_;
|
||||
for (auto &cat : obj.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();
|
||||
}
|
||||
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_) {
|
||||
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));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -501,7 +509,7 @@ void DhtServer::load_local_config(td::Promise<td::Unit> promise) {
|
|||
ig.add_promise(std::move(ret_promise));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -656,12 +664,20 @@ void DhtServer::start_adnl() {
|
|||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, addr.addr,
|
||||
cats.proxy, cats.cats.size() ? 0 : 1);
|
||||
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, cats.in_addr,
|
||||
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());
|
||||
|
@ -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) {
|
||||
CHECK(addr_lists_[cat].size() > 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() {
|
||||
|
@ -738,7 +754,7 @@ void DhtServer::start_control_interface() {
|
|||
|
||||
for (auto &s : config_.controls) {
|
||||
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},
|
||||
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()) {
|
||||
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));
|
||||
|
@ -970,23 +986,25 @@ void DhtServer::run_control_query(ton::ton_api::engine_validator_addAdnlId &quer
|
|||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), cat = query.category_,
|
||||
promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
||||
return;
|
||||
}
|
||||
auto pub = R.move_as_ok();
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
|
||||
} 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));
|
||||
});
|
||||
TRY_RESULT_PROMISE(promise, cat, td::narrow_cast_safe<td::uint8>(query.category_));
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), cat, promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
||||
return;
|
||||
}
|
||||
auto pub = R.move_as_ok();
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
|
||||
} 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(keyring_, &ton::keyring::Keyring::get_public_key, ton::PublicKeyHash{query.key_hash_},
|
||||
std::move(P));
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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 "dht/dht.h"
|
||||
|
@ -40,7 +40,7 @@
|
|||
|
||||
enum DhtServerPermissions : td::uint32 { vep_default = 1, vep_modify = 2, vep_unsafe = 4 };
|
||||
|
||||
using AdnlCategory = td::int32;
|
||||
using AdnlCategory = td::int8;
|
||||
|
||||
struct Config {
|
||||
struct Addr {
|
||||
|
@ -177,7 +177,7 @@ class DhtServer : public td::actor::Actor {
|
|||
void alarm() override;
|
||||
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_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,
|
||||
|
@ -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,
|
||||
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 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 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 E302} --- {\tt IFJMPREF} ($f$ -- ), equivalent to {\tt PUSHREFCONT}; {\tt IFJMP}.
|
||||
\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 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 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 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 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}
|
||||
|
||||
\nxsubpoint\emb{Control flow primitives: loops}
|
||||
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.
|
||||
\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. 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}
|
||||
\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}.
|
||||
|
@ -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 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 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}
|
||||
|
||||
\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 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 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}.
|
||||
\end{itemize}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class TonTest {
|
|||
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 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;
|
||||
|
||||
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));
|
||||
|
||||
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));
|
||||
if (!(result instanceof TonApi.Ok)) {
|
||||
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()));
|
||||
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());
|
||||
ton::adnl::AdnlCategoryMask cat_mask;
|
||||
cat_mask[0] = true;
|
||||
if (is_client_) {
|
||||
td::IPAddress addr;
|
||||
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 {
|
||||
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;
|
||||
|
@ -798,7 +802,8 @@ class RldpHttpProxy : public td::actor::Actor {
|
|||
auto pub = pk.compute_public_key();
|
||||
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()};
|
||||
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_) {
|
||||
server_ids_.insert(local_id_);
|
||||
|
@ -809,10 +814,12 @@ class RldpHttpProxy : public td::actor::Actor {
|
|||
auto pub = pk.compute_public_key();
|
||||
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()};
|
||||
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_) {
|
||||
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
|
||||
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"
|
||||
|
||||
|
@ -162,30 +162,32 @@ Result<size_t> RocksDb::count(Slice prefix) {
|
|||
}
|
||||
|
||||
Status RocksDb::begin_transaction() {
|
||||
write_batch_ = std::make_unique<rocksdb::WriteBatch>();
|
||||
//transaction_.reset(db_->BeginTransaction({}, {}));
|
||||
//write_batch_ = std::make_unique<rocksdb::WriteBatch>();
|
||||
rocksdb::WriteOptions options;
|
||||
options.sync = true;
|
||||
transaction_.reset(db_->BeginTransaction(options, {}));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDb::commit_transaction() {
|
||||
CHECK(write_batch_);
|
||||
auto write_batch = std::move(write_batch_);
|
||||
rocksdb::WriteOptions options;
|
||||
options.sync = true;
|
||||
TRY_STATUS(from_rocksdb(db_->Write(options, write_batch.get())));
|
||||
return Status::OK();
|
||||
//CHECK(write_batch_);
|
||||
//auto write_batch = std::move(write_batch_);
|
||||
//rocksdb::WriteOptions options;
|
||||
//options.sync = true;
|
||||
//TRY_STATUS(from_rocksdb(db_->Write(options, write_batch.get())));
|
||||
//return Status::OK();
|
||||
|
||||
//CHECK(transaction_);
|
||||
//auto res = from_rocksdb(transaction_->Commit());
|
||||
//transaction_.reset();
|
||||
//return res;
|
||||
CHECK(transaction_);
|
||||
auto res = from_rocksdb(transaction_->Commit());
|
||||
transaction_.reset();
|
||||
return res;
|
||||
}
|
||||
|
||||
Status RocksDb::abort_transaction() {
|
||||
CHECK(write_batch_);
|
||||
write_batch_.reset();
|
||||
//CHECK(transaction_);
|
||||
//transaction_.reset();
|
||||
//CHECK(write_batch_);
|
||||
//write_batch_.reset();
|
||||
CHECK(transaction_);
|
||||
transaction_.reset();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,11 @@ TEST(KeyValue, simple) {
|
|||
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());
|
||||
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) {
|
||||
std::string kv_value;
|
||||
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
|
||||
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"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
AesCbcState::AesCbcState(Slice key256, Slice iv128) : key_(key256), iv_(iv128) {
|
||||
CHECK(key_.size() == 32);
|
||||
CHECK(iv_.size() == 16);
|
||||
AesCbcState::AesCbcState(Slice key256, Slice iv128) : raw_{td::SecureString(key256), td::SecureString(iv128)} {
|
||||
CHECK(raw_.key.size() == 32);
|
||||
CHECK(raw_.iv.size() == 16);
|
||||
}
|
||||
|
||||
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) {
|
||||
::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 {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -65,10 +65,17 @@ class AesCbcState {
|
|||
|
||||
void encrypt(Slice from, MutableSlice to);
|
||||
void decrypt(Slice from, MutableSlice to);
|
||||
struct Raw {
|
||||
SecureString key;
|
||||
SecureString iv;
|
||||
};
|
||||
|
||||
const Raw &raw() const {
|
||||
return raw_;
|
||||
}
|
||||
|
||||
private:
|
||||
SecureString key_;
|
||||
SecureString iv_;
|
||||
Raw raw_;
|
||||
};
|
||||
|
||||
void sha1(Slice data, unsigned char output[20]);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "adnl/adnl.h"
|
||||
#include "adnl/adnl-test-loopback-implementation.h"
|
||||
|
||||
#include "keys/encryptor.h"
|
||||
|
||||
#include "td/utils/port/signals.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
@ -81,8 +83,10 @@ int main() {
|
|||
|
||||
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{pub2}, 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(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);
|
||||
|
||||
|
@ -91,30 +95,85 @@ int main() {
|
|||
});
|
||||
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
{
|
||||
auto obj = ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(td::BufferSlice{"1234"});
|
||||
td::Bits256 proxy_id;
|
||||
td::Random::secure_bytes(proxy_id.as_slice());
|
||||
auto obj = ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(proxy_id, td::BufferSlice{"1234"});
|
||||
auto R = ton::adnl::AdnlProxy::create(*obj.get());
|
||||
R.ensure();
|
||||
auto P = R.move_as_ok();
|
||||
td::BufferSlice z{64};
|
||||
td::Random::secure_bytes(z.as_slice());
|
||||
auto packet = P->encrypt(ton::adnl::AdnlProxy::Packet{2, 3, z.clone()});
|
||||
td::Bits256 x;
|
||||
x.as_slice().copy_from(packet.as_slice().truncate(32));
|
||||
CHECK(x.is_zero());
|
||||
auto packet = P->encrypt(ton::adnl::AdnlProxy::Packet{15, 2, 3, 4, 5, 6, z.clone()});
|
||||
auto packet2R = P->decrypt(std::move(packet));
|
||||
packet2R.ensure();
|
||||
auto packet2 = packet2R.move_as_ok();
|
||||
CHECK(packet2.flags == 15);
|
||||
CHECK(packet2.ip == 2);
|
||||
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());
|
||||
}
|
||||
|
||||
{
|
||||
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) {
|
||||
td::BufferSlice d{i};
|
||||
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));
|
||||
});
|
||||
|
||||
LOG(ERROR) << "Ed25519 version is " << td::Ed25519::version();
|
||||
LOG(ERROR) << "testing delivering of all packets";
|
||||
|
||||
auto f = td::Clocks::system();
|
||||
|
@ -324,6 +384,12 @@ int main() {
|
|||
}
|
||||
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();
|
||||
std::_Exit(0);
|
||||
return 0;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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/utils.hpp"
|
||||
|
@ -250,7 +250,8 @@ int main(int argc, char *argv[]) {
|
|||
n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1};
|
||||
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(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,
|
||||
true);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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-test-loopback-implementation.h"
|
||||
|
@ -87,7 +87,8 @@ int main() {
|
|||
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(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);
|
||||
|
||||
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
|
||||
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-test-loopback-implementation.h"
|
||||
|
@ -75,8 +75,10 @@ int main() {
|
|||
|
||||
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{pub2}, 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(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, 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.proxyToFast ip:int port:int date:int signature:int256 = adnl.ProxyToSign;
|
||||
|
||||
adnl.proxy.none = adnl.Proxy;
|
||||
adnl.proxy.fast shared_secret:bytes = adnl.Proxy;
|
||||
adnl.proxy.none id:int256 = adnl.Proxy;
|
||||
adnl.proxy.fast id:int256 shared_secret:bytes = adnl.Proxy;
|
||||
|
||||
|
||||
adnl.address.udp ip:int port:int = adnl.Address;
|
||||
|
@ -109,6 +109,23 @@ 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.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;
|
||||
|
||||
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.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.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;
|
||||
|
||||
|
@ -216,7 +220,8 @@ guessAccountRevision initial_account_state:InitialAccountState = AccountRevision
|
|||
getAccountState account_address:accountAddress = FullAccountState;
|
||||
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.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
|
||||
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
|
||||
|
||||
|
@ -56,7 +56,13 @@ constexpr unsigned min_split_merge_interval = 30; // split/merge interval must
|
|||
constexpr unsigned max_split_merge_delay =
|
||||
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) {
|
||||
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>
|
||||
void test_encryption() {
|
||||
std::string secret = "secret";
|
||||
|
@ -164,7 +171,7 @@ void test_encryption() {
|
|||
auto encrypted_data = Encryption::encrypt_data(data, secret);
|
||||
LOG(ERROR) << encrypted_data.size();
|
||||
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("", 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 encrypted_data = Encryption::encrypt_data(data, secret);
|
||||
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) {
|
||||
|
@ -199,24 +206,33 @@ TEST(Tonlib, SimpleEncryptionAsym) {
|
|||
auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok();
|
||||
LOG(ERROR) << encrypted_data.size();
|
||||
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();
|
||||
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("", 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(64, '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++) {
|
||||
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 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();
|
||||
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();
|
||||
std::string text = "hello world";
|
||||
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_Data>> elements;
|
||||
elements.push_back(make_object<tonlib_api::msg_dataEncryptedText>(
|
||||
SimpleEncryptionV2::encrypt_data(text, other_public_key, pkey).move_as_ok().as_slice().str()));
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_dataEncrypted>> elements;
|
||||
td::Slice addr = "Ef9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX";
|
||||
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 =
|
||||
sync_send(client, make_object<tonlib_api::msg_decrypt>(
|
||||
make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(key->public_key_, raw_imported_key->secret_.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();
|
||||
|
||||
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(); },
|
||||
[&](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) {
|
||||
ASSERT_EQ(amount - first_fee, txn->in_msg_->value_);
|
||||
} 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) {
|
||||
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::decrypt::ID:
|
||||
case tonlib_api::kdf::ID:
|
||||
case tonlib_api::msg_decryptWithProof::ID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -1841,38 +1842,41 @@ struct ToRawTransactions {
|
|||
auto body_cell = vm::CellBuilder().append_cellslice(*body).finalize();
|
||||
auto body_hash = body_cell->get_hash().as_slice().str();
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (body->size() >= 32 && static_cast<td::uint32>(body->prefetch_long(32)) <= 1) {
|
||||
auto type = body.write().fetch_long(32);
|
||||
td::Status status;
|
||||
auto get_data = [body = std::move(body), body_cell, this](td::Slice salt) mutable {
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (body->size() >= 32 && static_cast<td::uint32>(body->prefetch_long(32)) <= 1) {
|
||||
auto type = body.write().fetch_long(32);
|
||||
td::Status status;
|
||||
|
||||
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();
|
||||
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();
|
||||
|
||||
if (r_body_message.is_ok()) {
|
||||
if (type == 0) {
|
||||
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());
|
||||
if (r_body_message.is_ok()) {
|
||||
if (type == 0) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(r_body_message.move_as_ok());
|
||||
} 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) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)));
|
||||
}
|
||||
if (!data) {
|
||||
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);
|
||||
if (tag < 0) {
|
||||
|
@ -1892,9 +1896,10 @@ struct ToRawTransactions {
|
|||
TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee));
|
||||
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,
|
||||
ihr_fee, created_lt, std::move(body_hash),
|
||||
std::move(data));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(src),
|
||||
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: {
|
||||
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");
|
||||
}
|
||||
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),
|
||||
std::move(data));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(
|
||||
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: {
|
||||
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");
|
||||
}
|
||||
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),
|
||||
std::move(data));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(
|
||||
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)");
|
||||
}
|
||||
|
||||
auto addr = source_->get_address();
|
||||
addr.bounceable = true;
|
||||
addr.testnet = false;
|
||||
|
||||
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());
|
||||
gift.message = encrypted_message.as_slice().str();
|
||||
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::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise) {
|
||||
td::Promise<object_ptr<tonlib_api::msg_dataDecryptedArray>>&& promise) {
|
||||
if (!request.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");
|
||||
}
|
||||
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
|
||||
using ReturnType = tonlib_api::object_ptr<tonlib_api::msg_dataDecrypted>;
|
||||
make_request(
|
||||
int_api::GetPrivateKey{std::move(input_key)},
|
||||
promise.wrap([elements = std::move(request.data_)](auto key) mutable {
|
||||
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) {
|
||||
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>(
|
||||
*msg, td::overloaded([&msg](auto&) { return std::move(msg); },
|
||||
[&msg, &private_key](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType {
|
||||
auto r_decrypted = SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key);
|
||||
if (r_decrypted.is_error()) {
|
||||
return std::move(msg);
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(
|
||||
r_decrypted.move_as_ok().as_slice().str());
|
||||
}));
|
||||
*res->data_,
|
||||
td::overloaded(
|
||||
[&res](auto&) { return std::move(res); },
|
||||
[&res, &private_key, &msg](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType {
|
||||
auto r_decrypted =
|
||||
SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key, msg->source_->account_address_);
|
||||
if (r_decrypted.is_error()) {
|
||||
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();
|
||||
}
|
||||
|
@ -3251,6 +3281,32 @@ tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const
|
|||
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::Promise<td::unique_ptr<AccountState>>&& promise) {
|
||||
auto actor_id = actor_id_++;
|
||||
|
@ -3399,4 +3455,9 @@ td::Status TonlibClient::do_request(const tonlib_api::kdf& request, P&&) {
|
|||
UNREACHABLE();
|
||||
return TonlibError::Internal();
|
||||
}
|
||||
template <class P>
|
||||
td::Status TonlibClient::do_request(const tonlib_api::msg_decryptWithProof& request, P&&) {
|
||||
UNREACHABLE();
|
||||
return TonlibError::Internal();
|
||||
}
|
||||
} // 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::kdf& request);
|
||||
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::msg_decryptWithProof& request);
|
||||
|
||||
template <class P>
|
||||
td::Status do_request(const tonlib_api::runTests& request, P&&);
|
||||
template <class P>
|
||||
|
@ -194,6 +196,8 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Status do_request(const tonlib_api::decrypt& request, P&&);
|
||||
template <class 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,
|
||||
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::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};
|
||||
std::map<td::int64, td::unique_ptr<AccountState>> smcs_;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace tonlib {
|
||||
td::AesCbcState SimpleEncryption::calc_aes_cbc_state_hash(td::Slice hash) {
|
||||
CHECK(hash.size() == 64);
|
||||
CHECK(hash.size() >= 48);
|
||||
td::SecureString key(32);
|
||||
key.as_mutable_slice().copy_from(hash.substr(0, 32));
|
||||
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::SecureString hash(64);
|
||||
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) {
|
||||
|
@ -106,10 +106,10 @@ td::Result<td::SecureString> SimpleEncryption::decrypt_data(td::Slice encrypted_
|
|||
return td::SecureString(decrypted_data.as_slice().substr(prefix_size));
|
||||
}
|
||||
|
||||
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,
|
||||
td::Slice salt) {
|
||||
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 {
|
||||
|
@ -124,9 +124,10 @@ td::SecureString secure_xor(td::Slice a, td::Slice b) {
|
|||
} // namespace
|
||||
|
||||
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));
|
||||
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());
|
||||
td::SecureString prefixed_encrypted(tmp_public_key.LENGTH + encrypted.size());
|
||||
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);
|
||||
}
|
||||
|
||||
td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice data,
|
||||
const td::Ed25519::PrivateKey &private_key) {
|
||||
td::Result<SimpleEncryptionV2::Decrypted> SimpleEncryptionV2::decrypt_data(td::Slice data,
|
||||
const td::Ed25519::PrivateKey &private_key,
|
||||
td::Slice salt) {
|
||||
if (data.size() < td::Ed25519::PublicKey::LENGTH) {
|
||||
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 =
|
||||
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(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);
|
||||
}
|
||||
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);
|
||||
td::SecureString combined(prefix.size() + data.size());
|
||||
combined.as_mutable_slice().copy_from(prefix);
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
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);
|
||||
auto iv_copy = cbc_state.raw().key.copy();
|
||||
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);
|
||||
// check hash
|
||||
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));
|
||||
}
|
||||
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);
|
||||
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);
|
||||
|
||||
td::SecureString res_buf(data.size() + 16, 0);
|
||||
|
|
|
@ -43,14 +43,27 @@ class SimpleEncryption {
|
|||
|
||||
class SimpleEncryptionV2 {
|
||||
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,
|
||||
const td::Ed25519::PrivateKey &private_key);
|
||||
static td::SecureString encrypt_data(td::Slice data, td::Slice secret);
|
||||
static td::Result<td::SecureString> decrypt_data(td::Slice encrypted_data, td::Slice secret);
|
||||
td::Slice salt = {});
|
||||
struct Decrypted {
|
||||
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:
|
||||
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
|
||||
|
|
|
@ -1384,10 +1384,10 @@ class TonlibCli : public td::actor::Actor {
|
|||
sb << "-" << Grams{td::uint64(-balance)};
|
||||
}
|
||||
sb << " Fee: " << Grams{td::uint64(t->fee_)};
|
||||
if (t->in_msg_->source_.empty()) {
|
||||
if (!t->in_msg_->source_->account_address_.empty()) {
|
||||
sb << " External ";
|
||||
} else {
|
||||
sb << " From " << t->in_msg_->source_;
|
||||
sb << " From " << t->in_msg_->source_->account_address_;
|
||||
}
|
||||
auto print_msg_data = [](td::StringBuilder& sb,
|
||||
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_);
|
||||
for (auto& ot : t->out_msgs_) {
|
||||
sb << "\n\t";
|
||||
if (ot->destination_.empty()) {
|
||||
if (ot->destination_->account_address_.empty()) {
|
||||
sb << " External ";
|
||||
} else {
|
||||
sb << " To " << ot->destination_;
|
||||
sb << " To " << ot->destination_->account_address_;
|
||||
}
|
||||
sb << " " << Grams{td::uint64(ot->value_)};
|
||||
print_msg_data(sb, ot->msg_data_);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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.h"
|
||||
|
@ -609,6 +609,7 @@ td::Status AddNetworkAddressQuery::receive(td::BufferSlice data) {
|
|||
td::Status AddNetworkProxyAddressQuery::run() {
|
||||
TRY_RESULT_ASSIGN(in_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(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() {
|
||||
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()),
|
||||
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_));
|
||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||
return td::Status::OK();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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
|
||||
|
||||
|
@ -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 <>
|
||||
inline td::Result<td::IPAddress> Tokenizer::get_token() {
|
||||
TRY_RESULT(S, get_raw_token());
|
||||
|
@ -782,7 +795,7 @@ class AddNetworkProxyAddressQuery : public Query {
|
|||
return "addproxyaddr";
|
||||
}
|
||||
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 {
|
||||
return get_name();
|
||||
|
@ -791,6 +804,7 @@ class AddNetworkProxyAddressQuery : public Query {
|
|||
private:
|
||||
td::IPAddress in_addr_;
|
||||
td::IPAddress out_addr_;
|
||||
td::Bits256 id_;
|
||||
td::BufferSlice shared_secret_;
|
||||
std::vector<td::int32> cats_;
|
||||
std::vector<td::int32> prio_cats_;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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"
|
||||
|
||||
|
@ -86,8 +86,12 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
|
|||
[&](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();
|
||||
out_ip = in_ip;
|
||||
categories = obj.categories_;
|
||||
priority_categories = obj.priority_categories_;
|
||||
for (auto cat : obj.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) {
|
||||
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());
|
||||
R.ensure();
|
||||
proxy = R.move_as_ok();
|
||||
categories = obj.categories_;
|
||||
priority_categories = obj.priority_categories_;
|
||||
for (auto cat : obj.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();
|
||||
}
|
||||
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_) {
|
||||
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));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -1156,7 +1166,9 @@ void ValidatorEngine::load_local_config(td::Promise<td::Unit> promise) {
|
|||
ig.add_promise(std::move(ret_promise));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -1378,18 +1390,25 @@ void ValidatorEngine::start_adnl() {
|
|||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, addr.addr,
|
||||
cats.proxy, cats.cats.size() ? 0 : 1);
|
||||
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, cats.in_addr,
|
||||
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());
|
||||
|
||||
for (auto cat : cats.cats) {
|
||||
CHECK(cat >= 0);
|
||||
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()));
|
||||
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());
|
||||
}
|
||||
for (auto cat : cats.priority_cats) {
|
||||
CHECK(cat >= 0);
|
||||
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()));
|
||||
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) {
|
||||
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() {
|
||||
|
@ -1526,7 +1544,7 @@ void ValidatorEngine::started_full_node() {
|
|||
|
||||
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]},
|
||||
ton::adnl::AdnlAddressList{});
|
||||
ton::adnl::AdnlAddressList{}, static_cast<td::uint8>(255));
|
||||
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_id,
|
||||
ton::adnl::AdnlNodeIdShort{id});
|
||||
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]},
|
||||
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(""),
|
||||
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});
|
||||
|
@ -1621,7 +1639,7 @@ void ValidatorEngine::started() {
|
|||
}
|
||||
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
|
@ -2136,23 +2154,24 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addAdnlId
|
|||
}
|
||||
|
||||
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_,
|
||||
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
|
||||
} else {
|
||||
promise.set_value(
|
||||
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));
|
||||
});
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), id, cat, promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
|
||||
} else {
|
||||
promise.set_value(
|
||||
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));
|
||||
});
|
||||
|
||||
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,
|
||||
|
@ -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,
|
||||
|
@ -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_,
|
||||
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_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,
|
||||
|
@ -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,
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
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
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
|||
|
||||
enum ValidatorEnginePermissions : td::uint32 { vep_default = 1, vep_modify = 2, vep_unsafe = 4 };
|
||||
|
||||
using AdnlCategory = td::int32;
|
||||
using AdnlCategory = td::uint8;
|
||||
|
||||
struct Config {
|
||||
struct Addr {
|
||||
|
@ -201,8 +201,8 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
bool started_ = false;
|
||||
|
||||
public:
|
||||
static constexpr td::uint32 max_cat() {
|
||||
return 256;
|
||||
static constexpr td::uint8 max_cat() {
|
||||
return 250;
|
||||
}
|
||||
|
||||
void set_local_config(std::string str);
|
||||
|
@ -286,7 +286,7 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
void alarm() override;
|
||||
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_validator_permanent_key(ton::PublicKeyHash key_hash, td::uint32 election_date, td::uint32 ttl,
|
||||
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,
|
||||
td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
};
|
||||
|
||||
|
|
|
@ -79,8 +79,8 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
|
|||
}
|
||||
|
||||
if (handle_->is_applied()) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[ SelfId = actor_id(this), seqno = handle_->id().id.seqno ](td::Result<BlockIdExt> R) {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), seqno = handle_->id().id.seqno](td::Result<BlockIdExt> R) {
|
||||
R.ensure();
|
||||
auto h = R.move_as_ok();
|
||||
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));
|
||||
} else {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([ SelfId = actor_id(this), handle = handle_ ](td::Result<td::Ref<BlockData>> R) {
|
||||
CHECK(handle->received());
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
}
|
||||
});
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle = handle_](td::Result<td::Ref<BlockData>> R) {
|
||||
CHECK(handle->received());
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, apply_block_priority(), timeout_,
|
||||
std::move(P));
|
||||
|
@ -136,19 +135,25 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
|
|||
|
||||
void ApplyBlock::written_block_data() {
|
||||
VLOG(VALIDATOR_DEBUG) << "apply block: written block data for " << id_;
|
||||
if (handle_->id().is_masterchain() && !handle_->inited_proof()) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "proof is absent"));
|
||||
return;
|
||||
if (!handle_->id().seqno()) {
|
||||
CHECK(handle_->inited_split_after());
|
||||
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()) {
|
||||
finish_query();
|
||||
} else {
|
||||
|
|
|
@ -39,6 +39,9 @@ namespace validator {
|
|||
using td::Ref;
|
||||
|
||||
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 NewOutMsg = block::NewOutMsg;
|
||||
const ShardIdFull shard;
|
||||
|
@ -137,6 +140,7 @@ class Collator final : public td::actor::Actor {
|
|||
bool shard_conf_adjusted_{false};
|
||||
bool ihr_enabled_{false};
|
||||
bool create_stats_enabled_{false};
|
||||
bool report_version_{false};
|
||||
td::uint64 overload_history_{0}, underload_history_{0};
|
||||
td::uint64 block_size_estimate_{};
|
||||
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_prev_blk_ref(vm::CellBuilder& cb, bool after_merge);
|
||||
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 check_value_flow();
|
||||
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();
|
||||
ihr_enabled_ = config_->ihr_enabled();
|
||||
create_stats_enabled_ = config_->create_stats_enabled();
|
||||
report_version_ = config_->has_capability(ton::capReportVersion);
|
||||
shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
|
||||
if (prev_key_block_exists_) {
|
||||
|
@ -529,6 +530,16 @@ bool Collator::unpack_last_mc_state() {
|
|||
<< ", " << block_limits_->bytes.hard() << "]";
|
||||
LOG(DEBUG) << "block limits: gas [" << block_limits_->gas.underload() << ", " << block_limits_->gas.soft() << ", "
|
||||
<< 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
|
||||
// std::cerr << " block::gen::ShardState::print_ref(mc_state_root) = ";
|
||||
// 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,
|
||||
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
|
||||
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
|
||||
|
@ -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_merge_) // want_merge: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(vert_seqno_, 32) // vert_seq_no:#
|
||||
&& 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(min_ref_mc_seqno_, 32) // min_ref_mc_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?
|
||||
&& cb.store_builder_ref_bool(std::move(cb2)))) // .. ^BlkMasterInfo
|
||||
&& 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
CHECK(prev_state_root_.not_null());
|
||||
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_);
|
||||
ihr_enabled_ = config_->ihr_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_);
|
||||
if (!is_masterchain()) {
|
||||
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,
|
||||
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
|
||||
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
|
||||
|
@ -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_)) {
|
||||
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)) {
|
||||
// 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 {
|
||||
static constexpr int supported_version = 1;
|
||||
static constexpr long long supported_capabilities =
|
||||
ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion;
|
||||
|
||||
public:
|
||||
ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
|
||||
|
|
|
@ -382,7 +382,6 @@ void ArchiveImporter::finish_query() {
|
|||
if (promise_) {
|
||||
promise_.set_value(
|
||||
std::vector<BlockSeqno>{state_->get_seqno(), std::min<BlockSeqno>(state_->get_seqno(), shard_client_seqno_)});
|
||||
td::unlink(path_).ensure();
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
|
|
@ -1393,6 +1393,39 @@ void ValidatorManagerImpl::start_up() {
|
|||
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));
|
||||
|
||||
check_waiters_at_ = td::Timestamp::in(1.0);
|
||||
|
@ -1475,23 +1508,35 @@ void ValidatorManagerImpl::download_next_archive() {
|
|||
finish_prestart_sync();
|
||||
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) {
|
||||
if (R.is_error()) {
|
||||
LOG(INFO) << "failed to download archive slice: " << R.error();
|
||||
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
|
||||
td::Timestamp::in(2.0));
|
||||
} 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));
|
||||
}
|
||||
|
||||
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;
|
||||
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()) {
|
||||
LOG(INFO) << "failed to check downloaded archive slice: " << R.error();
|
||||
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() {
|
||||
to_import_.clear();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::completed_prestart_sync);
|
||||
|
@ -1665,6 +1712,16 @@ void ValidatorManagerImpl::update_shards() {
|
|||
|
||||
if (!validator_id.is_zero()) {
|
||||
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;
|
||||
auto it = validator_groups_.find(val_group_id);
|
||||
if (it != validator_groups_.end()) {
|
||||
|
|
|
@ -264,7 +264,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
bool out_of_sync();
|
||||
void prestart_sync();
|
||||
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 finish_prestart_sync();
|
||||
void completed_prestart_sync();
|
||||
|
@ -556,6 +556,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
|
||||
td::actor::ActorOwn<AsyncStateSerializer> serializer_;
|
||||
|
||||
std::map<BlockSeqno, std::pair<std::string, bool>> to_import_;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Callback> callback_;
|
||||
td::actor::ActorOwn<Db> db_;
|
||||
|
|
Loading…
Reference in a new issue