1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-14 12:12:21 +00:00

updated liteserver

- new methods for liteserver/liteclient
- added ADNL/DHT client-only work mode
- fixed crash in ADNL
This commit is contained in:
ton 2020-02-02 16:53:37 +04:00
parent acf16718e6
commit 53ec9684bd
70 changed files with 816 additions and 322 deletions

2
GPLv2
View file

@ -23,5 +23,5 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */

2
LGPLv2
View file

@ -14,5 +14,5 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */

View file

@ -155,6 +155,16 @@ td::Result<AdnlAddressList> AdnlAddressList::create(const tl_object_ptr<ton_api:
return A; return A;
} }
td::Status AdnlAddressList::add_udp_address(td::IPAddress addr) {
if (addr.is_ipv4()) {
auto r = td::make_ref<AdnlAddressUdp>(addr.get_ipv4(), static_cast<td::uint16>(addr.get_port()));
addrs_.push_back(std::move(r));
return td::Status::OK();
} else {
return td::Status::Error(ErrorCode::protoviolation, "only works with ipv4");
}
}
} // namespace adnl } // namespace adnl
} // namespace ton } // namespace ton

View file

@ -88,6 +88,7 @@ class AdnlAddressList {
void add_addr(AdnlAddress addr) { void add_addr(AdnlAddress addr) {
addrs_.push_back(addr); addrs_.push_back(addr);
} }
void update(td::IPAddress addr);
bool public_only() const; bool public_only() const;
td::uint32 size() const { td::uint32 size() const {
return static_cast<td::uint32>(addrs_.size()); return static_cast<td::uint32>(addrs_.size());
@ -98,6 +99,7 @@ class AdnlAddressList {
} }
static td::Result<AdnlAddressList> create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list); static td::Result<AdnlAddressList> create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list);
td::Status add_udp_address(td::IPAddress addr);
}; };
} // namespace adnl } // namespace adnl

View file

@ -111,13 +111,15 @@ void AdnlChannelImpl::send_message(td::uint32 priority, td::actor::ActorId<AdnlN
td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_, priority, std::move(B)); td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_, priority, std::move(B));
} }
void AdnlChannelImpl::receive(td::BufferSlice data) { void AdnlChannelImpl::receive(td::IPAddress addr, td::BufferSlice data) {
auto P = td::PromiseCreator::lambda( auto P = td::PromiseCreator::lambda(
[peer = peer_pair_, channel_id = channel_in_id_, id = print_id()](td::Result<AdnlPacket> R) { [peer = peer_pair_, channel_id = channel_in_id_, addr, id = print_id()](td::Result<AdnlPacket> R) {
if (R.is_error()) { if (R.is_error()) {
VLOG(ADNL_WARNING) << id << ": dropping IN message: can not decrypt: " << R.move_as_error(); VLOG(ADNL_WARNING) << id << ": dropping IN message: can not decrypt: " << R.move_as_error();
} else { } else {
td::actor::send_closure(peer, &AdnlPeerPair::receive_packet_from_channel, channel_id, R.move_as_ok()); auto packet = R.move_as_ok();
packet.set_remote_addr(addr);
td::actor::send_closure(peer, &AdnlPeerPair::receive_packet_from_channel, channel_id, std::move(packet));
} }
}); });

View file

@ -35,7 +35,7 @@ class AdnlChannel : public td::actor::Actor {
AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id, AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
td::actor::ActorId<AdnlPeerPair> peer_pair); td::actor::ActorId<AdnlPeerPair> peer_pair);
virtual void receive(td::BufferSlice data) = 0; virtual void receive(td::IPAddress addr, td::BufferSlice data) = 0;
virtual void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn, virtual void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn,
td::BufferSlice data) = 0; td::BufferSlice data) = 0;
virtual ~AdnlChannel() = default; virtual ~AdnlChannel() = default;

View file

@ -33,7 +33,7 @@ class AdnlChannelImpl : public AdnlChannel {
AdnlChannelIdShort in_id, AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor, AdnlChannelIdShort in_id, AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
std::unique_ptr<Decryptor> decryptor); std::unique_ptr<Decryptor> decryptor);
void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise); void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise);
void receive(td::BufferSlice data) override; void receive(td::IPAddress addr, td::BufferSlice data) override;
void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn, td::BufferSlice data) override; void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn, td::BufferSlice data) override;
struct AdnlChannelPrintId { struct AdnlChannelPrintId {

View file

@ -40,13 +40,15 @@ AdnlAddressList AdnlLocalId::get_addr_list() const {
return addr_list_; return addr_list_;
} }
void AdnlLocalId::receive(td::BufferSlice data) { void AdnlLocalId::receive(td::IPAddress addr, td::BufferSlice data) {
auto P = td::PromiseCreator::lambda( auto P = td::PromiseCreator::lambda(
[peer_table = peer_table_, dst = short_id_, id = print_id()](td::Result<AdnlPacket> R) { [peer_table = peer_table_, dst = short_id_, addr, id = print_id()](td::Result<AdnlPacket> R) {
if (R.is_error()) { if (R.is_error()) {
VLOG(ADNL_WARNING) << id << ": dropping IN message: cannot decrypt: " << R.move_as_error(); VLOG(ADNL_WARNING) << id << ": dropping IN message: cannot decrypt: " << R.move_as_error();
} else { } else {
td::actor::send_closure(peer_table, &AdnlPeerTable::receive_decrypted_packet, dst, R.move_as_ok()); auto packet = R.move_as_ok();
packet.set_remote_addr(addr);
td::actor::send_closure(peer_table, &AdnlPeerTable::receive_decrypted_packet, dst, std::move(packet));
} }
}); });
@ -117,7 +119,7 @@ void AdnlLocalId::update_address_list(AdnlAddressList addr_list) {
} }
void AdnlLocalId::publish_address_list() { void AdnlLocalId::publish_address_list() {
if (dht_node_.empty() || addr_list_.empty()) { if (dht_node_.empty() || addr_list_.empty() || addr_list_.size() == 0) {
VLOG(ADNL_NOTICE) << this << ": skipping public addr list, because localid (or dht node) not fully initialized"; VLOG(ADNL_NOTICE) << this << ": skipping public addr list, because localid (or dht node) not fully initialized";
return; return;
} }
@ -178,7 +180,8 @@ AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor
id_ = std::move(id); id_ = std::move(id);
short_id_ = id_.compute_short_id(); short_id_ = id_.compute_short_id();
addr_list_ = std::move(addr_list); addr_list_ = std::move(addr_list);
if (addr_list_.addrs().size() > 0) { if (!addr_list_.empty()) {
addr_list_.set_reinit_date(Adnl::adnl_start_time());
addr_list_.set_version(static_cast<td::int32>(td::Clocks::system())); addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
} }
peer_table_ = peer_table; peer_table_ = peer_table;

View file

@ -54,7 +54,7 @@ class AdnlLocalId : public td::actor::Actor {
void decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise); void decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void deliver(AdnlNodeIdShort src, td::BufferSlice data); void deliver(AdnlNodeIdShort src, td::BufferSlice data);
void deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise); void deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void receive(td::BufferSlice data); void receive(td::IPAddress addr, td::BufferSlice data);
void subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback); void subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback);
void unsubscribe(std::string prefix); void unsubscribe(std::string prefix);

View file

@ -59,7 +59,7 @@ void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
} }
received_messages_++; received_messages_++;
if (received_messages_ % 64 == 0) { if (received_messages_ % 64 == 0) {
VLOG(ADNL_DEBUG) << this << ": received " << received_messages_ << "udp messages"; VLOG(ADNL_DEBUG) << this << ": received " << received_messages_ << " udp messages";
} }
VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size(); VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size();

View file

@ -132,6 +132,9 @@ class AdnlPacket {
auto signature() const { auto signature() const {
return signature_.clone(); return signature_.clone();
} }
auto remote_addr() const {
return remote_addr_;
}
void init_random(); void init_random();
@ -188,6 +191,10 @@ class AdnlPacket {
flags_ |= Flags::f_reinit_date; flags_ |= Flags::f_reinit_date;
} }
void set_remote_addr(td::IPAddress addr) {
remote_addr_ = addr;
}
private: private:
td::BufferSlice rand1_; td::BufferSlice rand1_;
td::uint32 flags_{0}; td::uint32 flags_{0};
@ -204,6 +211,8 @@ class AdnlPacket {
td::int32 dst_reinit_date_{0}; td::int32 dst_reinit_date_{0};
td::BufferSlice signature_; td::BufferSlice signature_;
td::BufferSlice rand2_; td::BufferSlice rand2_;
td::IPAddress remote_addr_;
}; };
} // namespace adnl } // namespace adnl

View file

@ -49,7 +49,7 @@ td::actor::ActorOwn<Adnl> Adnl::create(std::string db, td::actor::ActorId<keyrin
return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring)); return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring));
} }
void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) { void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data) {
if (data.size() < 32) { if (data.size() < 32) {
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size(); VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
return; return;
@ -60,14 +60,14 @@ void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
auto it = local_ids_own_.find(dst); auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) { if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::receive, std::move(data)); td::actor::send_closure(it->second, &AdnlLocalId::receive, addr, std::move(data));
return; return;
} }
AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()}; AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
auto it2 = channels_.find(dst_chan_id); auto it2 = channels_.find(dst_chan_id);
if (it2 != channels_.end()) { if (it2 != channels_.end()) {
td::actor::send_closure(it2->second, &AdnlChannel::receive, std::move(data)); td::actor::send_closure(it2->second, &AdnlChannel::receive, addr, std::move(data));
return; return;
} }
@ -237,7 +237,7 @@ void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkM
class Cb : public AdnlNetworkManager::Callback { class Cb : public AdnlNetworkManager::Callback {
public: public:
void receive_packet(td::IPAddress addr, td::BufferSlice data) override { void receive_packet(td::IPAddress addr, td::BufferSlice data) override {
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, std::move(data)); td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(data));
} }
Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) { Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) {
} }

View file

@ -89,7 +89,7 @@ class AdnlPeerTable : public Adnl {
virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0; virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0;
virtual void receive_packet(td::BufferSlice data) = 0; virtual void receive_packet(td::IPAddress addr, td::BufferSlice data) = 0;
virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0; virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0;
virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) = 0; virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) = 0;

View file

@ -43,7 +43,7 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override; void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override;
void add_static_nodes_from_config(AdnlNodesList nodes) override; void add_static_nodes_from_config(AdnlNodesList nodes) override;
void receive_packet(td::BufferSlice data) override; void receive_packet(td::IPAddress addr, td::BufferSlice data) override;
void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override; void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override;
void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) override; void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) override;
void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override { void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override {

View file

@ -131,7 +131,12 @@ void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
} }
if (packet.dst_reinit_date() > 0 && packet.dst_reinit_date() < d) { if (packet.dst_reinit_date() > 0 && packet.dst_reinit_date() < d) {
if (!packet.addr_list().empty()) { if (!packet.addr_list().empty()) {
update_addr_list(packet.addr_list()); auto addr_list = packet.addr_list();
if (packet.remote_addr().is_valid() && addr_list.size() == 0) {
VLOG(ADNL_DEBUG) << "adding implicit address " << packet.remote_addr();
addr_list.add_udp_address(packet.remote_addr());
}
update_addr_list(std::move(addr_list));
} }
if (!packet.priority_addr_list().empty()) { if (!packet.priority_addr_list().empty()) {
update_addr_list(packet.priority_addr_list()); update_addr_list(packet.priority_addr_list());
@ -174,7 +179,12 @@ void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
} }
if (!packet.addr_list().empty()) { if (!packet.addr_list().empty()) {
update_addr_list(packet.addr_list()); auto addr_list = packet.addr_list();
if (packet.remote_addr().is_valid() && addr_list.size() == 0) {
VLOG(ADNL_DEBUG) << "adding implicit address " << packet.remote_addr();
addr_list.add_udp_address(packet.remote_addr());
}
update_addr_list(std::move(addr_list));
} }
if (!packet.priority_addr_list().empty()) { if (!packet.priority_addr_list().empty()) {
update_addr_list(packet.priority_addr_list()); update_addr_list(packet.priority_addr_list());
@ -642,7 +652,7 @@ void AdnlPeerPairImpl::update_addr_list(AdnlAddressList addr_list) {
if (addr_list.empty()) { if (addr_list.empty()) {
return; return;
} }
CHECK(addr_list.size() > 0); //CHECK(addr_list.size() > 0);
if (addr_list.reinit_date() > td::Clocks::system() + 60) { if (addr_list.reinit_date() > td::Clocks::system() + 60) {
VLOG(ADNL_WARNING) << "dropping addr list with too new reinit date"; VLOG(ADNL_WARNING) << "dropping addr list with too new reinit date";

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "blockchain-explorer-http.hpp" #include "blockchain-explorer-http.hpp"
#include "block/block-db.h" #include "block/block-db.h"
@ -36,6 +36,8 @@
#include "block/mc-config.h" #include "block/mc-config.h"
#include "ton/ton-shard.h" #include "ton/ton-shard.h"
bool local_scripts{false};
HttpAnswer& HttpAnswer::operator<<(AddressCell addr_c) { HttpAnswer& HttpAnswer::operator<<(AddressCell addr_c) {
ton::WorkchainId wc; ton::WorkchainId wc;
ton::StdSmcAddress addr; ton::StdSmcAddress addr;
@ -425,7 +427,7 @@ HttpAnswer& HttpAnswer::operator<<(AccountCell acc_c) {
HttpAnswer& HttpAnswer::operator<<(BlockHeaderCell head_c) { HttpAnswer& HttpAnswer::operator<<(BlockHeaderCell head_c) {
*this << "<div>"; *this << "<div>";
vm::CellSlice cs{vm::NoVm{}, head_c.root}; vm::CellSlice cs{vm::NoVm(), head_c.root};
auto block_id = head_c.block_id; auto block_id = head_c.block_id;
try { try {
auto virt_root = vm::MerkleProof::virtualize(head_c.root, 1); auto virt_root = vm::MerkleProof::virtualize(head_c.root, 1);
@ -676,13 +678,17 @@ std::string HttpAnswer::header() {
"maximum-scale=1.0, user-scalable=no\" />\n" "maximum-scale=1.0, user-scalable=no\" />\n"
<< "<meta name=\"format-detection\" content=\"telephone=no\" />\n" << "<meta name=\"format-detection\" content=\"telephone=no\" />\n"
<< "<!-- Latest compiled and minified CSS -->\n" << "<!-- Latest compiled and minified CSS -->\n"
<< "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">\n" << "<link rel=\"stylesheet\" href=\"" << (local_scripts ? "/" : "https://")
<< "maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">\n"
<< "<!-- jQuery library -->" << "<!-- jQuery library -->"
<< "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js\"></script>\n" << "<script src=\"" << (local_scripts ? "/" : "https://")
<< "ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js\"></script>\n"
<< "<!-- Popper JS -->\n" << "<!-- Popper JS -->\n"
<< "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js\"></script>\n" << "<script src=\"" << (local_scripts ? "/" : "https://")
<< "cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js\"></script>\n"
<< "<!-- Latest compiled JavaScript -->\n" << "<!-- Latest compiled JavaScript -->\n"
<< "<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js\"></script>\n" << "<script src=\"" << (local_scripts ? "/" : "https://")
<< "maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js\"></script>\n"
<< "</head><body>\n" << "</head><body>\n"
<< "<div class=\"container-fluid\">\n" << "<div class=\"container-fluid\">\n"
<< "<nav class=\"navbar navbar-expand px-0 mt-1 flex-wrap\">\n" << "<nav class=\"navbar navbar-expand px-0 mt-1 flex-wrap\">\n"

View file

@ -33,6 +33,8 @@
#include "td/utils/Random.h" #include "td/utils/Random.h"
#include "block/block.h" #include "block/block.h"
extern bool local_scripts;
class HttpAnswer { class HttpAnswer {
public: public:
struct MessageCell { struct MessageCell {

View file

@ -639,6 +639,10 @@ int main(int argc, char* argv[]) {
td::actor::send_closure(x, &CoreActor::set_http_port, td::to_integer<td::uint32>(arg)); td::actor::send_closure(x, &CoreActor::set_http_port, td::to_integer<td::uint32>(arg));
return td::Status::OK(); return td::Status::OK();
}); });
p.add_option('L', "local-scripts", "use local copy of ajax/bootstrap/... JS", [&]() {
local_scripts = true;
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX #if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) { p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()), auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),

View file

@ -34,6 +34,8 @@
#define MAX_POST_SIZE (64 << 10) #define MAX_POST_SIZE (64 << 10)
extern bool local_scripts_;
class CoreActorInterface : public td::actor::Actor { class CoreActorInterface : public td::actor::Actor {
public: public:
struct RemoteNodeStatus { struct RemoteNodeStatus {

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "check-proof.h" #include "check-proof.h"
#include "block/block.h" #include "block/block.h"
@ -219,7 +219,17 @@ td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const
} }
td::Result<AccountState::Info> AccountState::validate(ton::BlockIdExt ref_blk, block::StdAddress addr) const { td::Result<AccountState::Info> AccountState::validate(ton::BlockIdExt ref_blk, block::StdAddress addr) const {
TRY_RESULT_PREFIX(root, vm::std_boc_deserialize(state.as_slice(), true), "cannot deserialize account state"); TRY_RESULT_PREFIX(true_root, vm::std_boc_deserialize(state.as_slice(), true), "cannot deserialize account state");
Ref<vm::Cell> root;
if (is_virtualized && true_root.not_null()) {
root = vm::MerkleProof::virtualize(true_root, 1);
if (root.is_null()) {
return td::Status::Error("account state proof is invalid");
}
} else {
root = true_root;
}
if (blk != ref_blk && ref_blk.id.seqno != ~0U) { if (blk != ref_blk && ref_blk.id.seqno != ~0U) {
return td::Status::Error(PSLICE() << "obtained getAccountState() for a different reference block " << blk.to_str() return td::Status::Error(PSLICE() << "obtained getAccountState() for a different reference block " << blk.to_str()
@ -241,6 +251,7 @@ td::Result<AccountState::Info> AccountState::validate(ton::BlockIdExt ref_blk, b
TRY_STATUS(block::check_account_proof(proof.as_slice(), shard_blk, addr, root, &res.last_trans_lt, TRY_STATUS(block::check_account_proof(proof.as_slice(), shard_blk, addr, root, &res.last_trans_lt,
&res.last_trans_hash, &res.gen_utime, &res.gen_lt)); &res.last_trans_hash, &res.gen_utime, &res.gen_lt));
res.root = std::move(root); res.root = std::move(root);
res.true_root = std::move(true_root);
return res; return res;
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -44,10 +44,11 @@ struct AccountState {
td::BufferSlice shard_proof; td::BufferSlice shard_proof;
td::BufferSlice proof; td::BufferSlice proof;
td::BufferSlice state; td::BufferSlice state;
bool is_virtualized{false};
struct Info { struct Info {
td::Ref<vm::Cell> root; td::Ref<vm::Cell> root, true_root;
ton::LogicalTime last_trans_lt = 0; ton::LogicalTime last_trans_lt{0};
ton::Bits256 last_trans_hash; ton::Bits256 last_trans_hash;
ton::LogicalTime gen_lt{0}; ton::LogicalTime gen_lt{0};
td::uint32 gen_utime{0}; td::uint32 gen_utime{0};

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "mc-config.h" #include "mc-config.h"
#include "block/block.h" #include "block/block.h"
@ -752,8 +752,8 @@ Ref<McShardDescr> McShardDescr::from_block(Ref<vm::Cell> block_root, Ref<vm::Cel
return {}; return {};
} }
// TODO: use a suitable vm::MerkleUpdate method here // TODO: use a suitable vm::MerkleUpdate method here
vm::CellSlice cs(vm::NoVm(), rec.state_update); vm::CellSlice cs(vm::NoVmSpec(), rec.state_update);
if (cs.special_type() != vm::Cell::SpecialType::MerkleUpdate) { if (!cs.is_valid() || cs.special_type() != vm::Cell::SpecialType::MerkleUpdate) {
LOG(ERROR) << "state update in a block is not a Merkle update"; LOG(ERROR) << "state update in a block is not a Merkle update";
return {}; return {};
} }
@ -870,7 +870,7 @@ bool ShardConfig::get_shard_hash_raw_from(vm::Dictionary& dict, vm::CellSlice& c
unsigned long long z = id.shard, m = std::numeric_limits<unsigned long long>::max(); unsigned long long z = id.shard, m = std::numeric_limits<unsigned long long>::max();
int len = id.pfx_len(); int len = id.pfx_len();
while (true) { while (true) {
cs.load(vm::NoVmOrd{}, leaf ? root : std::move(root)); cs.load(vm::NoVmOrd(), leaf ? root : std::move(root));
int t = (int)cs.fetch_ulong(1); int t = (int)cs.fetch_ulong(1);
if (t < 0) { if (t < 0) {
return false; // throw DictError ? return false; // throw DictError ?
@ -1108,7 +1108,7 @@ std::vector<ton::BlockId> ShardConfig::get_shard_hash_ids(
std::stack<std::pair<Ref<vm::Cell>, unsigned long long>> stack; std::stack<std::pair<Ref<vm::Cell>, unsigned long long>> stack;
stack.emplace(cs_ref->prefetch_ref(), ton::shardIdAll); stack.emplace(cs_ref->prefetch_ref(), ton::shardIdAll);
while (!stack.empty()) { while (!stack.empty()) {
vm::CellSlice cs{vm::NoVm{}, std::move(stack.top().first)}; vm::CellSlice cs{vm::NoVmOrd(), std::move(stack.top().first)};
unsigned long long shard = stack.top().second; unsigned long long shard = stack.top().second;
stack.pop(); stack.pop();
int t = (int)cs.fetch_ulong(1); int t = (int)cs.fetch_ulong(1);

View file

@ -965,6 +965,11 @@ x{F4B5} @Defop SUBDICTRPGET
x{F4B6} @Defop SUBDICTIRPGET x{F4B6} @Defop SUBDICTIRPGET
x{F4B7} @Defop SUBDICTURPGET x{F4B7} @Defop SUBDICTURPGET
x{F4BC} @Defop DICTIGETJMPZ
x{F4BD} @Defop DICTUGETJMPZ
x{F4BE} @Defop DICTIGETEXECZ
x{F4BF} @Defop DICTUGETEXECZ
// //
// blockchain-specific primitives // blockchain-specific primitives
@ -1117,7 +1122,7 @@ variable @gvarcnt
@procdict dup @ swap null! @procdict dup @ swap null!
} : }END } : }END
forget @proclist forget @proccnt forget @proclist forget @proccnt
{ }END <{ SETCP0 swap @procdictkeylen DICTPUSHCONST DICTIGETJMP 11 THROWARG }> } : }END> { }END <{ SETCP0 swap @procdictkeylen DICTPUSHCONST DICTIGETJMPZ 11 THROWARG }> } : }END>
{ }END> b> } : }END>c { }END> b> } : }END>c
{ }END>c <s } : }END>s { }END>c <s } : }END>s

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "words.h" #include "words.h"
@ -1007,8 +1007,8 @@ void interpret_store_end(vm::Stack& stack, bool special) {
void interpret_from_cell(vm::Stack& stack) { void interpret_from_cell(vm::Stack& stack) {
auto cell = stack.pop_cell(); auto cell = stack.pop_cell();
Ref<vm::CellSlice> cs{true}; Ref<vm::CellSlice> cs{true, vm::NoVmOrd(), std::move(cell)};
if (!cs.unique_write().load(vm::NoVmOrd(), std::move(cell))) { if (!cs->is_valid()) {
throw IntError{"deserializing a special cell as ordinary"}; throw IntError{"deserializing a special cell as ordinary"};
} }
stack.push(cs); stack.push(cs);
@ -1117,7 +1117,10 @@ void interpret_fetch_ref(vm::Stack& stack, int mode) {
stack.push(std::move(cs)); stack.push(std::move(cs));
} }
if (mode & 1) { if (mode & 1) {
Ref<vm::CellSlice> new_cs{true, vm::NoVm(), std::move(cell)}; Ref<vm::CellSlice> new_cs{true, vm::NoVmOrd(), std::move(cell)};
if (!new_cs->is_valid()) {
throw IntError{"cannot load ordinary cell"};
}
stack.push(std::move(new_cs)); stack.push(std::move(new_cs));
} else { } else {
stack.push_cell(std::move(cell)); stack.push_cell(std::move(cell));

View file

@ -39,3 +39,9 @@
int seqno() method_id { int seqno() method_id {
return get_data().begin_parse().preload_uint(32); return get_data().begin_parse().preload_uint(32);
} }
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(64);
return cs.preload_uint(256);
}

View file

@ -63,3 +63,9 @@ int processed?(int query_id) method_id {
(_, var found) = old_queries.udict_get?(64, query_id); (_, var found) = old_queries.udict_get?(64, query_id);
return found ? true : - (query_id <= last_cleaned); return found ? true : - (query_id <= last_cleaned);
} }
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(32 + 64);
return cs.preload_uint(256);
}

View file

@ -15,8 +15,8 @@ def? $2 { @' $2 } { "new-wallet" } cond constant file-base
// Create new advanced wallet; code adapted from `auto/wallet-code.fif` // Create new advanced wallet; code adapted from `auto/wallet-code.fif`
<{ SETCP0 DUP IFNOTRET // return if recv_internal <{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
DROP c4 PUSHCTR CTOS 32 PLDU // cnt 1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk
}> }>
INC 32 THROWIF // fail unless recv_external INC 32 THROWIF // fail unless recv_external
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs

View file

@ -18,8 +18,8 @@ $3 "new-wallet" replace-if-null =: file-base
// Create new advanced wallet; code adapted from `auto/wallet3-code.fif` // Create new advanced wallet; code adapted from `auto/wallet3-code.fif`
<{ SETCP0 DUP IFNOTRET // return if recv_internal <{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
DROP c4 PUSHCTR CTOS 32 PLDU // cnt 1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk
}> }>
INC 32 THROWIF // fail unless recv_external INC 32 THROWIF // fail unless recv_external
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs

View file

@ -15,8 +15,8 @@ def? $2 { @' $2 } { "new-wallet" } cond constant file-base
// Create new simple wallet // Create new simple wallet
<{ SETCP0 DUP IFNOTRET // return if recv_internal <{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
DROP c4 PUSHCTR CTOS 32 PLDU // cnt 1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk
}> }>
INC 32 THROWIF // fail unless recv_external INC 32 THROWIF // fail unless recv_external
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt 512 INT LDSLICEX DUP 32 PLDU // sign cs cnt

View file

@ -62,6 +62,12 @@ int seqno() method_id {
return get_data().begin_parse().preload_uint(32); return get_data().begin_parse().preload_uint(32);
} }
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(32);
return cs.preload_uint(256);
}
int balance() method_id { int balance() method_id {
return restricted?() ? 0 : get_balance().first(); return restricted?() ? 0 : get_balance().first();
} }

View file

@ -55,6 +55,12 @@ int seqno() method_id {
return get_data().begin_parse().preload_uint(32); return get_data().begin_parse().preload_uint(32);
} }
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(32);
return cs.preload_uint(256);
}
int balance() method_id { int balance() method_id {
var ds = get_data().begin_parse().skip_bits(32 + 256); var ds = get_data().begin_parse().skip_bits(32 + 256);
var rdict = ds~load_dict(); var rdict = ds~load_dict();

View file

@ -45,6 +45,11 @@ int seqno() method_id {
return get_data().begin_parse().preload_uint(32); return get_data().begin_parse().preload_uint(32);
} }
int get_public_key() method_id {
var (seqno, public_key) = load_state();
return public_key;
}
cell create_init_state(int public_key) method_id { cell create_init_state(int public_key) method_id {
return create_state(0, public_key); return create_state(0, public_key);
} }

View file

@ -29,3 +29,9 @@
int seqno() method_id { int seqno() method_id {
return get_data().begin_parse().preload_uint(32); return get_data().begin_parse().preload_uint(32);
} }
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(32);
return cs.preload_uint(256);
}

View file

@ -33,3 +33,9 @@
int seqno() method_id { int seqno() method_id {
return get_data().begin_parse().preload_uint(32); return get_data().begin_parse().preload_uint(32);
} }
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(64);
return cs.preload_uint(256);
}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "vm/cells/CellBuilder.h" #include "vm/cells/CellBuilder.h"
@ -460,6 +460,16 @@ bool CellBuilder::append_cellslice_chk(Ref<CellSlice> cs_ref, unsigned size_ext)
return cs_ref.not_null() && append_cellslice_chk(*cs_ref, size_ext); return cs_ref.not_null() && append_cellslice_chk(*cs_ref, size_ext);
} }
CellSlice CellSlice::clone() const {
CellBuilder cb;
Ref<Cell> cell;
if (cb.append_cellslice_bool(*this) && cb.finalize_to(cell)) {
return CellSlice{NoVmOrd(), std::move(cell)};
} else {
return {};
}
}
bool CellBuilder::append_bitstring(const td::BitString& bs) { bool CellBuilder::append_bitstring(const td::BitString& bs) {
return store_bits_bool(bs.cbits(), bs.size()); return store_bits_bool(bs.cbits(), bs.size());
} }
@ -536,11 +546,11 @@ CellBuilder* CellBuilder::make_copy() const {
return c; return c;
} }
CellSlice CellBuilder::as_cellslice() const& { CellSlice CellBuilder::as_cellslice() const & {
return CellSlice{finalize_copy()}; return CellSlice{finalize_copy()};
} }
Ref<CellSlice> CellBuilder::as_cellslice_ref() const& { Ref<CellSlice> CellBuilder::as_cellslice_ref() const & {
return Ref<CellSlice>{true, finalize_copy()}; return Ref<CellSlice>{true, finalize_copy()};
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -275,6 +275,7 @@ class CellSlice : public td::CntObject {
offs = std::min(offs, size()); offs = std::min(offs, size());
return CellSlice{*this, size() - offs, size_refs(), offs, 0}; return CellSlice{*this, size() - offs, size_refs(), offs, 0};
} }
CellSlice clone() const;
private: private:
void init_bits_refs(); void init_bits_refs();

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "vm/dict.h" #include "vm/dict.h"
#include "vm/cells.h" #include "vm/cells.h"
@ -179,7 +179,7 @@ bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) && {
return cb.store_maybe_ref(std::move(root_cell)); return cb.store_maybe_ref(std::move(root_cell));
} }
bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) const& { bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) const & {
return is_valid() && cb.store_maybe_ref(root_cell); return is_valid() && cb.store_maybe_ref(root_cell);
} }
@ -2240,7 +2240,7 @@ Ref<CellSlice> AugmentedDictionary::extract_root() && {
return std::move(root); return std::move(root);
} }
bool AugmentedDictionary::append_dict_to_bool(CellBuilder& cb) const& { bool AugmentedDictionary::append_dict_to_bool(CellBuilder& cb) const & {
if (!is_valid()) { if (!is_valid()) {
return false; return false;
} }
@ -2535,7 +2535,7 @@ bool AugmentedDictionary::set(td::ConstBitPtr key, int key_len, const CellSlice&
} }
auto res = dict_set(get_root_cell(), key, key_len, value, mode); auto res = dict_set(get_root_cell(), key, key_len, value, mode);
if (res.second) { if (res.second) {
//vm::CellSlice cs{vm::NoVm{}, res.first}; //vm::CellSlice cs{vm::NoVmOrd(), res.first};
//std::cerr << "new augmented dictionary root is:\n"; //std::cerr << "new augmented dictionary root is:\n";
//cs.print_rec(std::cerr); //cs.print_rec(std::cerr);
set_root_cell(std::move(res.first)); set_root_cell(std::move(res.first));

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include <functional> #include <functional>
#include "vm/log.h" #include "vm/log.h"
@ -210,7 +210,7 @@ int exec_dict_get(VmState* st, unsigned args) {
BitSlice key; BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes]; unsigned char buffer[Dictionary::max_key_bytes];
if (args & 4) { if (args & 4) {
key = dict.integer_key(stack.pop_int(), n, !(args & 2), buffer, true); key = dict.integer_key(stack.pop_int_finite(), n, !(args & 2), buffer, true);
if (!key.is_valid()) { if (!key.is_valid()) {
stack.push_smallint(0); stack.push_smallint(0);
return 0; return 0;
@ -250,7 +250,7 @@ int exec_dict_get_optref(VmState* st, unsigned args) {
BitSlice key; BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes]; unsigned char buffer[Dictionary::max_key_bytes];
if (args & 2) { if (args & 2) {
key = dict.integer_key(stack.pop_int(), n, !(args & 1), buffer, true); key = dict.integer_key(stack.pop_int_finite(), n, !(args & 1), buffer, true);
if (!key.is_valid()) { if (!key.is_valid()) {
stack.push_null(); stack.push_null();
return 0; return 0;
@ -377,7 +377,7 @@ int exec_dict_delete(VmState* st, unsigned args) {
BitSlice key; BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes]; unsigned char buffer[Dictionary::max_key_bytes];
if (args & 2) { if (args & 2) {
key = dict.integer_key(stack.pop_int(), n, !(args & 1), buffer); key = dict.integer_key(stack.pop_int_finite(), n, !(args & 1), buffer);
if (!key.is_valid()) { if (!key.is_valid()) {
push_dict(stack, std::move(dict)); push_dict(stack, std::move(dict));
stack.push_smallint(0); stack.push_smallint(0);
@ -404,7 +404,7 @@ int exec_dict_deleteget(VmState* st, unsigned args) {
BitSlice key; BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes]; unsigned char buffer[Dictionary::max_key_bytes];
if (args & 4) { if (args & 4) {
key = dict.integer_key(stack.pop_int(), n, !(args & 2), buffer); key = dict.integer_key(stack.pop_int_finite(), n, !(args & 2), buffer);
if (!key.is_valid()) { if (!key.is_valid()) {
push_dict(stack, std::move(dict)); push_dict(stack, std::move(dict));
stack.push_smallint(0); stack.push_smallint(0);
@ -588,23 +588,29 @@ int exec_pfx_dict_delete(VmState* st) {
int exec_dict_get_exec(VmState* st, unsigned args) { int exec_dict_get_exec(VmState* st, unsigned args) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute DICT" << (args & 1 ? 'U' : 'I') << "GET" << (args & 2 ? "EXEC\n" : "JMP\n"); VM_LOG(st) << "execute DICT" << (args & 1 ? 'U' : 'I') << "GET" << (args & 2 ? "EXEC" : "JMP")
<< (args & 4 ? "Z" : "");
stack.check_underflow(3); stack.check_underflow(3);
int n = stack.pop_smallint_range(Dictionary::max_key_bits); int n = stack.pop_smallint_range(Dictionary::max_key_bits);
Dictionary dict{stack.pop_maybe_cell(), n}; Dictionary dict{stack.pop_maybe_cell(), n};
unsigned char buffer[Dictionary::max_key_bytes]; unsigned char buffer[Dictionary::max_key_bytes];
dict.integer_key_simple(stack.pop_int(), n, !(args & 1), td::BitPtr{buffer}); auto idx = stack.pop_int_finite();
auto value = dict.lookup(td::BitPtr{buffer}, n); if (dict.integer_key_simple(idx, n, !(args & 1), td::BitPtr{buffer}, true)) {
if (value.not_null()) { auto value = dict.lookup(td::BitPtr{buffer}, n);
Ref<OrdCont> cont{true, std::move(value), st->get_cp()}; if (value.not_null()) {
return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont)); Ref<OrdCont> cont{true, std::move(value), st->get_cp()};
} else { return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont));
return 0; }
} }
// key not found or out of range
if (args & 4) {
stack.push_int(std::move(idx));
}
return 0;
} }
std::string dump_dict_get_exec(CellSlice& cs, unsigned args) { std::string dump_dict_get_exec(CellSlice& cs, unsigned args) {
return std::string{"DICT"} + (args & 1 ? 'U' : 'I') + "GET" + (args & 2 ? "EXEC" : "JMP"); return std::string{"DICT"} + (args & 1 ? 'U' : 'I') + "GET" + (args & 2 ? "EXEC" : "JMP") + (args & 4 ? "Z" : "");
} }
int exec_push_const_dict(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) { int exec_push_const_dict(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) {
@ -720,7 +726,7 @@ int exec_subdict_get(VmState* st, unsigned args) {
BitSlice key; BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes]; unsigned char buffer[Dictionary::max_key_bytes];
if (args & 2) { if (args & 2) {
key = dict.integer_key(stack.pop_int(), k, !(args & 1), buffer, true); key = dict.integer_key(stack.pop_int_finite(), k, !(args & 1), buffer, true);
} else { } else {
key = stack.pop_cellslice()->prefetch_bits(k); key = stack.pop_cellslice()->prefetch_bits(k);
} }
@ -805,7 +811,8 @@ void register_dictionary_ops(OpcodeTable& cp0) {
exec_const_pfx_dict_switch, compute_len_push_const_dict)) exec_const_pfx_dict_switch, compute_len_push_const_dict))
.insert(OpcodeInstr::mkfixedrange(0xf4b1, 0xf4b4, 16, 3, std::bind(dump_subdictop2, _2, "GET"), exec_subdict_get)) .insert(OpcodeInstr::mkfixedrange(0xf4b1, 0xf4b4, 16, 3, std::bind(dump_subdictop2, _2, "GET"), exec_subdict_get))
.insert( .insert(
OpcodeInstr::mkfixedrange(0xf4b5, 0xf4b8, 16, 3, std::bind(dump_subdictop2, _2, "RPGET"), exec_subdict_get)); OpcodeInstr::mkfixedrange(0xf4b5, 0xf4b8, 16, 3, std::bind(dump_subdictop2, _2, "RPGET"), exec_subdict_get))
.insert(OpcodeInstr::mkfixed(0xf4bc >> 2, 14, 2, dump_dict_get_exec, exec_dict_get_exec));
} }
} // namespace vm } // namespace vm

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -33,6 +33,12 @@ struct VmLog {
td::LogOptions log_options{td::log_options}; td::LogOptions log_options{td::log_options};
enum { DumpStack = 2 }; enum { DumpStack = 2 };
int log_mask{1}; int log_mask{1};
static VmLog Null() {
VmLog res;
res.log_options.level = 0;
res.log_mask = 0;
return res;
}
}; };
template <class State> template <class State>

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "vm/stack.hpp" #include "vm/stack.hpp"
#include "vm/continuation.h" #include "vm/continuation.h"
@ -824,7 +824,7 @@ bool StackEntry::deserialize(CellSlice& cs, int mode) {
return false; return false;
} }
} else if (n == 1) { } else if (n == 1) {
return cs.have_refs() && t[0].deserialize(cs.fetch_ref(), mode); return cs.have_refs() && t[0].deserialize(cs.fetch_ref(), mode) && set(t_tuple, std::move(tuple));
} }
return set(t_tuple, std::move(tuple)); return set(t_tuple, std::move(tuple));
} }

View file

@ -145,13 +145,13 @@ void DhtBucket::promote_node(size_t idx) {
} }
} }
void DhtBucket::check(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> dht, void DhtBucket::check(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> dht,
adnl::AdnlNodeIdShort src) { adnl::AdnlNodeIdShort src) {
size_t have_space = 0; size_t have_space = 0;
for (size_t i = 0; i < active_nodes_.size(); i++) { for (size_t i = 0; i < active_nodes_.size(); i++) {
auto &node = active_nodes_[i]; auto &node = active_nodes_[i];
if (node && td::Time::now_cached() - node->last_ping_at() > ping_timeout_) { if (node && td::Time::now_cached() - node->last_ping_at() > ping_timeout_) {
node->send_ping(adnl, dht, src); node->send_ping(client_only, adnl, dht, src);
if (node->ready_from() == 0) { if (node->ready_from() == 0) {
demote_node(i); demote_node(i);
} }
@ -163,7 +163,7 @@ void DhtBucket::check(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<Dh
for (size_t i = 0; i < backup_nodes_.size(); i++) { for (size_t i = 0; i < backup_nodes_.size(); i++) {
auto &node = backup_nodes_[i]; auto &node = backup_nodes_[i];
if (node && td::Time::now_cached() - node->last_ping_at() > ping_timeout_) { if (node && td::Time::now_cached() - node->last_ping_at() > ping_timeout_) {
node->send_ping(adnl, dht, src); node->send_ping(client_only, adnl, dht, src);
} }
if (node && have_space > 0 && node->is_ready()) { if (node && have_space > 0 && node->is_ready()) {
promote_node(i); promote_node(i);

View file

@ -39,8 +39,8 @@ class DhtBucket {
//std::map<td::UInt256, std::unique_ptr<DhtRemoteNode>> pending_nodes_; //std::map<td::UInt256, std::unique_ptr<DhtRemoteNode>> pending_nodes_;
td::uint32 k_; td::uint32 k_;
bool check_one(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src, //bool check_one(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src,
const DhtMember::PrintId &print_id); // const DhtMember::PrintId &print_id);
void demote_node(size_t idx); void demote_node(size_t idx);
void promote_node(size_t idx); void promote_node(size_t idx);
@ -52,7 +52,8 @@ class DhtBucket {
td::uint32 active_cnt(); td::uint32 active_cnt();
td::Status add_full_node(DhtKeyId id, DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, td::Status add_full_node(DhtKeyId id, DhtNode node, td::actor::ActorId<adnl::Adnl> adnl,
adnl::AdnlNodeIdShort self_id); adnl::AdnlNodeIdShort self_id);
void check(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src); void check(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
adnl::AdnlNodeIdShort src);
void receive_ping(DhtKeyId id, DhtNode result, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id); void receive_ping(DhtKeyId id, DhtNode result, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id);
void get_nearest_nodes(DhtKeyId id, td::uint32 bit, DhtNodesList &vec, td::uint32 k); void get_nearest_nodes(DhtKeyId id, td::uint32 bit, DhtNodesList &vec, td::uint32 k);
void dump(td::StringBuilder &sb) const; void dump(td::StringBuilder &sb) const;

View file

@ -94,6 +94,8 @@ class DhtMemberImpl : public DhtMember {
td::actor::ActorId<keyring::Keyring> keyring_; td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<adnl::Adnl> adnl_; td::actor::ActorId<adnl::Adnl> adnl_;
bool client_only_{false};
td::uint64 ping_queries_{0}; td::uint64 ping_queries_{0};
td::uint64 find_node_queries_{0}; td::uint64 find_node_queries_{0};
td::uint64 find_value_queries_{0}; td::uint64 find_value_queries_{0};
@ -123,8 +125,8 @@ class DhtMemberImpl : public DhtMember {
public: public:
DhtMemberImpl(adnl::AdnlNodeIdShort id, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring, DhtMemberImpl(adnl::AdnlNodeIdShort id, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a = 3) td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a = 3, bool client_only = false)
: id_(id), key_{id_}, k_(k), a_(a), db_root_(db_root), keyring_(keyring), adnl_(adnl) { : id_(id), key_{id_}, k_(k), a_(a), db_root_(db_root), keyring_(keyring), adnl_(adnl), client_only_(client_only) {
for (size_t i = 0; i < 256; i++) { for (size_t i = 0; i < 256; i++) {
buckets_.emplace_back(k_); buckets_.emplace_back(k_);
} }

View file

@ -96,7 +96,12 @@ void DhtQuery::add_nodes(DhtNodesList list) {
void DhtQueryFindNodes::send_one_query(adnl::AdnlNodeIdShort id) { void DhtQueryFindNodes::send_one_query(adnl::AdnlNodeIdShort id) {
auto P = create_serialize_tl_object<ton_api::dht_findNode>(get_key().tl(), get_k()); auto P = create_serialize_tl_object<ton_api::dht_findNode>(get_key().tl(), get_k());
auto B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl()); td::BufferSlice B;
if (client_only_) {
B = std::move(P);
} else {
B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl());
}
auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result<td::BufferSlice> R) { auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result<td::BufferSlice> R) {
td::actor::send_closure(SelfId, &DhtQueryFindNodes::on_result, std::move(R), dst); td::actor::send_closure(SelfId, &DhtQueryFindNodes::on_result, std::move(R), dst);
@ -129,7 +134,12 @@ void DhtQueryFindNodes::finish(DhtNodesList list) {
void DhtQueryFindValue::send_one_query(adnl::AdnlNodeIdShort id) { void DhtQueryFindValue::send_one_query(adnl::AdnlNodeIdShort id) {
auto P = create_serialize_tl_object<ton_api::dht_findValue>(get_key().tl(), get_k()); auto P = create_serialize_tl_object<ton_api::dht_findValue>(get_key().tl(), get_k());
auto B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl()); td::BufferSlice B;
if (client_only_) {
B = std::move(P);
} else {
B = create_serialize_tl_object_suffix<ton_api::dht_query>(P.as_slice(), self_.tl());
}
auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result<td::BufferSlice> R) { auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result<td::BufferSlice> R) {
td::actor::send_closure(SelfId, &DhtQueryFindValue::on_result, std::move(R), dst); td::actor::send_closure(SelfId, &DhtQueryFindValue::on_result, std::move(R), dst);
@ -186,7 +196,7 @@ void DhtQueryFindValue::finish(DhtNodesList list) {
} }
DhtQueryStore::DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtQueryStore::DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src,
DhtNodesList list, td::uint32 k, td::uint32 a, DhtNode self, DhtNodesList list, td::uint32 k, td::uint32 a, DhtNode self, bool client_only,
td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl,
td::Promise<td::Unit> promise) td::Promise<td::Unit> promise)
: print_id_(print_id) : print_id_(print_id)
@ -195,7 +205,8 @@ DhtQueryStore::DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, ad
, promise_(std::move(promise)) , promise_(std::move(promise))
, value_(std::move(key_value)) , value_(std::move(key_value))
, list_(std::move(list)) , list_(std::move(list))
, self_(std::move(self)) { , self_(std::move(self))
, client_only_(client_only) {
node_ = node; node_ = node;
adnl_ = adnl; adnl_ = adnl;
src_ = src; src_ = src;
@ -208,7 +219,7 @@ void DhtQueryStore::start_up() {
auto key = value_.key_id(); auto key = value_.key_id();
auto A = td::actor::create_actor<DhtQueryFindNodes>("FindNodesQuery", key, print_id_, src_, std::move(list_), k_, a_, auto A = td::actor::create_actor<DhtQueryFindNodes>("FindNodesQuery", key, print_id_, src_, std::move(list_), k_, a_,
self_.clone(), node_, adnl_, std::move(P)); self_.clone(), client_only_, node_, adnl_, std::move(P));
A.release(); A.release();
} }

View file

@ -41,11 +41,21 @@ class DhtQuery : public td::actor::Actor {
protected: protected:
DhtKeyId key_; DhtKeyId key_;
DhtNode self_; DhtNode self_;
bool client_only_;
public: public:
DhtQuery(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, td::uint32 k, DhtQuery(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, td::uint32 k,
td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl) td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
: key_(key), self_(std::move(self)), print_id_(print_id), src_(src), k_(k), a_(a), node_(node), adnl_(adnl) { td::actor::ActorId<adnl::Adnl> adnl)
: key_(key)
, self_(std::move(self))
, client_only_(client_only)
, print_id_(print_id)
, src_(src)
, k_(k)
, a_(a)
, node_(node)
, adnl_(adnl) {
add_nodes(std::move(list)); add_nodes(std::move(list));
} }
DhtMember::PrintId print_id() const { DhtMember::PrintId print_id() const {
@ -94,9 +104,10 @@ class DhtQueryFindNodes : public DhtQuery {
public: public:
DhtQueryFindNodes(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, DhtQueryFindNodes(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list,
td::uint32 k, td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node, td::uint32 k, td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
td::actor::ActorId<adnl::Adnl> adnl, td::Promise<DhtNodesList> promise) td::actor::ActorId<adnl::Adnl> adnl, td::Promise<DhtNodesList> promise)
: DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), node, adnl), promise_(std::move(promise)) { : DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), client_only, node, adnl)
, promise_(std::move(promise)) {
} }
void send_one_query(adnl::AdnlNodeIdShort id) override; void send_one_query(adnl::AdnlNodeIdShort id) override;
void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst); void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
@ -112,9 +123,10 @@ class DhtQueryFindValue : public DhtQuery {
public: public:
DhtQueryFindValue(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, DhtQueryFindValue(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list,
td::uint32 k, td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node, td::uint32 k, td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
td::actor::ActorId<adnl::Adnl> adnl, td::Promise<DhtValue> promise) td::actor::ActorId<adnl::Adnl> adnl, td::Promise<DhtValue> promise)
: DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), node, adnl), promise_(std::move(promise)) { : DhtQuery(key, print_id, src, std::move(list), k, a, std::move(self), client_only, node, adnl)
, promise_(std::move(promise)) {
} }
void send_one_query(adnl::AdnlNodeIdShort id) override; void send_one_query(adnl::AdnlNodeIdShort id) override;
void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst); void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
@ -139,10 +151,11 @@ class DhtQueryStore : public td::actor::Actor {
td::uint32 remaining_; td::uint32 remaining_;
DhtNodesList list_; DhtNodesList list_;
DhtNode self_; DhtNode self_;
bool client_only_;
public: public:
DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list,
td::uint32 k, td::uint32 a, DhtNode self, td::actor::ActorId<DhtMember> node, td::uint32 k, td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
td::actor::ActorId<adnl::Adnl> adnl, td::Promise<td::Unit> promise); td::actor::ActorId<adnl::Adnl> adnl, td::Promise<td::Unit> promise);
void send_stores(td::Result<DhtNodesList> res); void send_stores(td::Result<DhtNodesList> res);
void store_ready(td::Result<td::BufferSlice> res); void store_ready(td::Result<td::BufferSlice> res);

View file

@ -63,7 +63,7 @@ td::Status DhtRemoteNode::update_value(DhtNode node, td::actor::ActorId<adnl::Ad
return td::Status::OK(); return td::Status::OK();
} }
void DhtRemoteNode::send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, void DhtRemoteNode::send_ping(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
adnl::AdnlNodeIdShort src) { adnl::AdnlNodeIdShort src) {
missed_pings_++; missed_pings_++;
if (missed_pings_ > max_missed_pings_ && ready_from_ > 0) { if (missed_pings_ > max_missed_pings_ && ready_from_ > 0) {
@ -75,37 +75,42 @@ void DhtRemoteNode::send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::Ac
td::actor::send_closure(adnl, &adnl::Adnl::add_peer, src, node_.adnl_id(), node_.addr_list()); td::actor::send_closure(adnl, &adnl::Adnl::add_peer, src, node_.adnl_id(), node_.addr_list());
auto P = td::PromiseCreator::lambda( auto P = td::PromiseCreator::lambda([key = id_, id = node_.adnl_id().compute_short_id(), client_only, node, src,
[key = id_, id = node_.adnl_id().compute_short_id(), node, src, adnl](td::Result<DhtNode> R) mutable { adnl](td::Result<DhtNode> R) mutable {
if (R.is_error()) { if (R.is_error()) {
LOG(ERROR) << "[dht]: failed to get self node"; LOG(ERROR) << "[dht]: failed to get self node";
return; return;
} }
auto P = td::PromiseCreator::lambda([key, node, adnl](td::Result<td::BufferSlice> R) { auto P = td::PromiseCreator::lambda([key, node, adnl](td::Result<td::BufferSlice> R) {
if (R.is_error()) { if (R.is_error()) {
VLOG(DHT_INFO) << "[dht]: received error for query to " << key << ": " << R.move_as_error(); VLOG(DHT_INFO) << "[dht]: received error for query to " << key << ": " << R.move_as_error();
return; return;
} }
auto F = fetch_tl_object<ton_api::dht_node>(R.move_as_ok(), true); auto F = fetch_tl_object<ton_api::dht_node>(R.move_as_ok(), true);
if (F.is_ok()) { if (F.is_ok()) {
auto N = DhtNode::create(F.move_as_ok()); auto N = DhtNode::create(F.move_as_ok());
if (N.is_ok()) { if (N.is_ok()) {
td::actor::send_closure(node, &DhtMember::receive_ping, key, N.move_as_ok()); td::actor::send_closure(node, &DhtMember::receive_ping, key, N.move_as_ok());
} else { } else {
VLOG(DHT_WARNING) << "[dht]: bad answer from " << key VLOG(DHT_WARNING) << "[dht]: bad answer from " << key
<< ": dropping bad getSignedAddressList() query answer: " << N.move_as_error(); << ": dropping bad getSignedAddressList() query answer: " << N.move_as_error();
} }
} else { } else {
VLOG(DHT_WARNING) << "[dht]: bad answer from " << key VLOG(DHT_WARNING) << "[dht]: bad answer from " << key
<< ": dropping invalid getSignedAddressList() query answer: " << F.move_as_error(); << ": dropping invalid getSignedAddressList() query answer: " << F.move_as_error();
} }
}); });
auto Q = create_serialize_tl_object<ton_api::dht_getSignedAddressList>(); auto Q = create_serialize_tl_object<ton_api::dht_getSignedAddressList>();
auto B = create_serialize_tl_object_suffix<ton_api::dht_query>(Q.as_slice(), R.move_as_ok().tl()); td::BufferSlice B;
td::actor::send_closure(adnl, &adnl::Adnl::send_query, src, id, "dht ping", std::move(P), if (client_only) {
td::Timestamp::in(10.0 + td::Random::fast(0, 100) * 0.1), std::move(B)); B = std::move(Q);
}); } else {
B = create_serialize_tl_object_suffix<ton_api::dht_query>(Q.as_slice(), R.move_as_ok().tl());
}
td::actor::send_closure(adnl, &adnl::Adnl::send_query, src, id, "dht ping", std::move(P),
td::Timestamp::in(10.0 + td::Random::fast(0, 100) * 0.1), std::move(B));
});
td::actor::send_closure(node, &DhtMember::get_self_node, std::move(P)); td::actor::send_closure(node, &DhtMember::get_self_node, std::move(P));
} }

View file

@ -76,7 +76,8 @@ class DhtRemoteNode {
double last_ping_at() const { double last_ping_at() const {
return last_ping_at_; return last_ping_at_;
} }
void send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src); void send_ping(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node,
adnl::AdnlNodeIdShort src);
td::Status receive_ping(DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id); td::Status receive_ping(DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id);
td::Status update_value(DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id); td::Status update_value(DhtNode node, td::actor::ActorId<adnl::Adnl> adnl, adnl::AdnlNodeIdShort self_id);
}; };

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "dht.hpp" #include "dht.hpp"
@ -44,9 +44,10 @@ namespace dht {
td::actor::ActorOwn<DhtMember> DhtMember::create(adnl::AdnlNodeIdShort id, std::string db_root, td::actor::ActorOwn<DhtMember> DhtMember::create(adnl::AdnlNodeIdShort id, std::string db_root,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a) { td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a,
bool client_only) {
return td::actor::ActorOwn<DhtMember>( return td::actor::ActorOwn<DhtMember>(
td::actor::create_actor<DhtMemberImpl>("dht", id, db_root, keyring, adnl, k, a)); td::actor::create_actor<DhtMemberImpl>("dht", id, db_root, keyring, adnl, k, a, client_only));
} }
td::Result<td::actor::ActorOwn<Dht>> Dht::create(adnl::AdnlNodeIdShort id, std::string db_root, td::Result<td::actor::ActorOwn<Dht>> Dht::create(adnl::AdnlNodeIdShort id, std::string db_root,
@ -66,9 +67,24 @@ td::Result<td::actor::ActorOwn<Dht>> Dht::create(adnl::AdnlNodeIdShort id, std::
return std::move(D); return std::move(D);
} }
td::Result<td::actor::ActorOwn<Dht>> Dht::create_client(adnl::AdnlNodeIdShort id, std::string db_root,
std::shared_ptr<DhtGlobalConfig> conf,
td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl) {
CHECK(conf->get_k() > 0);
CHECK(conf->get_a() > 0);
auto D = DhtMember::create(id, db_root, keyring, adnl, conf->get_k(), conf->get_a(), true);
auto &nodes = conf->nodes();
for (auto &node : nodes.list()) {
auto key = node.get_key();
td::actor::send_closure(D, &DhtMember::add_full_node, key, node.clone());
}
return std::move(D);
}
void DhtMemberImpl::start_up() { void DhtMemberImpl::start_up() {
std::shared_ptr<td::KeyValue> kv = std::make_shared<td::RocksDb>(
td::RocksDb::open(PSTRING() << db_root_ << "/dht-" << td::base64url_encode(id_.as_slice())).move_as_ok());
std::vector<td::int32> methods = {ton_api::dht_getSignedAddressList::ID, std::vector<td::int32> methods = {ton_api::dht_getSignedAddressList::ID,
ton_api::dht_findNode::ID, ton_api::dht_findNode::ID,
ton_api::dht_findValue::ID, ton_api::dht_findValue::ID,
@ -82,26 +98,31 @@ void DhtMemberImpl::start_up() {
std::make_unique<Callback>(actor_id(this), id_)); std::make_unique<Callback>(actor_id(this), id_));
} }
alarm_timestamp() = td::Timestamp::in(1.0); alarm_timestamp() = td::Timestamp::in(1.0);
for (td::uint32 bit = 0; bit < 256; bit++) {
auto key = create_hash_tl_object<ton_api::dht_db_key_bucket>(bit); if (!db_root_.empty()) {
std::string value; std::shared_ptr<td::KeyValue> kv = std::make_shared<td::RocksDb>(
auto R = kv->get(key.as_slice(), value); td::RocksDb::open(PSTRING() << db_root_ << "/dht-" << td::base64url_encode(id_.as_slice())).move_as_ok());
R.ensure(); for (td::uint32 bit = 0; bit < 256; bit++) {
if (R.move_as_ok() == td::KeyValue::GetStatus::Ok) { auto key = create_hash_tl_object<ton_api::dht_db_key_bucket>(bit);
auto V = fetch_tl_object<ton_api::dht_db_bucket>(td::BufferSlice{value}, true); std::string value;
V.ensure(); auto R = kv->get(key.as_slice(), value);
auto nodes = std::move(V.move_as_ok()->nodes_); R.ensure();
auto s = nodes->nodes_.size(); if (R.move_as_ok() == td::KeyValue::GetStatus::Ok) {
DhtNodesList list{std::move(nodes)}; auto V = fetch_tl_object<ton_api::dht_db_bucket>(td::BufferSlice{value}, true);
CHECK(list.size() == s); V.ensure();
auto &B = buckets_[bit]; auto nodes = std::move(V.move_as_ok()->nodes_);
for (auto &node : list.list()) { auto s = nodes->nodes_.size();
auto key = node.get_key(); DhtNodesList list{std::move(nodes)};
B.add_full_node(key, std::move(node), adnl_, id_); CHECK(list.size() == s);
auto &B = buckets_[bit];
for (auto &node : list.list()) {
auto key = node.get_key();
B.add_full_node(key, std::move(node), adnl_, id_);
}
} }
} }
db_ = DbType{std::move(kv)};
} }
db_ = DbType{std::move(kv)};
} }
void DhtMemberImpl::tear_down() { void DhtMemberImpl::tear_down() {
@ -119,6 +140,9 @@ void DhtMemberImpl::tear_down() {
} }
void DhtMemberImpl::save_to_db() { void DhtMemberImpl::save_to_db() {
if (db_root_.empty()) {
return;
}
next_save_to_db_at_ = td::Timestamp::in(10.0); next_save_to_db_at_ = td::Timestamp::in(10.0);
alarm_timestamp().relax(next_save_to_db_at_); alarm_timestamp().relax(next_save_to_db_at_);
@ -277,6 +301,9 @@ void DhtMemberImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::dht_getSig
void DhtMemberImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, void DhtMemberImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) { td::Promise<td::BufferSlice> promise) {
if (client_only_) {
return;
}
{ {
auto R = fetch_tl_prefix<ton_api::dht_query>(data, true); auto R = fetch_tl_prefix<ton_api::dht_query>(data, true);
if (R.is_ok()) { if (R.is_ok()) {
@ -358,11 +385,11 @@ void DhtMemberImpl::set_value(DhtValue value, td::Promise<td::Unit> promise) {
void DhtMemberImpl::get_value_in(DhtKeyId key, td::Promise<DhtValue> result) { void DhtMemberImpl::get_value_in(DhtKeyId key, td::Promise<DhtValue> result) {
auto P = td::PromiseCreator::lambda([key, promise = std::move(result), SelfId = actor_id(this), print_id = print_id(), auto P = td::PromiseCreator::lambda([key, promise = std::move(result), SelfId = actor_id(this), print_id = print_id(),
adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_, a = a_, adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_, a = a_, id = id_,
id = id_](td::Result<DhtNode> R) mutable { client_only = client_only_](td::Result<DhtNode> R) mutable {
R.ensure(); R.ensure();
td::actor::create_actor<DhtQueryFindValue>("FindValueQuery", key, print_id, id, std::move(list), k, a, td::actor::create_actor<DhtQueryFindValue>("FindValueQuery", key, print_id, id, std::move(list), k, a,
R.move_as_ok(), SelfId, adnl, std::move(promise)) R.move_as_ok(), client_only, SelfId, adnl, std::move(promise))
.release(); .release();
}); });
@ -374,7 +401,7 @@ void DhtMemberImpl::check() {
<< " fvalue=" << find_value_queries_ << " store=" << store_queries_ << " fvalue=" << find_value_queries_ << " store=" << store_queries_
<< " addrlist=" << get_addr_list_queries_; << " addrlist=" << get_addr_list_queries_;
for (auto &bucket : buckets_) { for (auto &bucket : buckets_) {
bucket.check(adnl_, actor_id(this), id_); bucket.check(client_only_, adnl_, actor_id(this), id_);
} }
if (next_save_to_db_at_.is_in_past()) { if (next_save_to_db_at_.is_in_past()) {
save_to_db(); save_to_db();
@ -469,10 +496,10 @@ void DhtMemberImpl::check() {
DhtKeyId key{x}; DhtKeyId key{x};
auto P = td::PromiseCreator::lambda([key, promise = std::move(promise), SelfId = actor_id(this), auto P = td::PromiseCreator::lambda([key, promise = std::move(promise), SelfId = actor_id(this),
print_id = print_id(), adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_, print_id = print_id(), adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_,
a = a_, id = id_](td::Result<DhtNode> R) mutable { a = a_, id = id_, client_only = client_only_](td::Result<DhtNode> R) mutable {
R.ensure(); R.ensure();
td::actor::create_actor<DhtQueryFindNodes>("FindNodesQuery", key, print_id, id, std::move(list), k, a, td::actor::create_actor<DhtQueryFindNodes>("FindNodesQuery", key, print_id, id, std::move(list), k, a,
R.move_as_ok(), SelfId, adnl, std::move(promise)) R.move_as_ok(), client_only, SelfId, adnl, std::move(promise))
.release(); .release();
}); });
@ -492,35 +519,39 @@ void DhtMemberImpl::send_store(DhtValue value, td::Promise<td::Unit> promise) {
value.check().ensure(); value.check().ensure();
auto key_id = value.key_id(); auto key_id = value.key_id();
auto P = td::PromiseCreator::lambda([value = std::move(value), print_id = print_id(), id = id_, auto P =
list = get_nearest_nodes(key_id, k_), k = k_, a = a_, SelfId = actor_id(this), td::PromiseCreator::lambda([value = std::move(value), print_id = print_id(), id = id_, client_only = client_only_,
adnl = adnl_, promise = std::move(promise)](td::Result<DhtNode> R) mutable { list = get_nearest_nodes(key_id, k_), k = k_, a = a_, SelfId = actor_id(this),
R.ensure(); adnl = adnl_, promise = std::move(promise)](td::Result<DhtNode> R) mutable {
td::actor::create_actor<DhtQueryStore>("StoreQuery", std::move(value), print_id, id, std::move(list), k, a, R.ensure();
R.move_as_ok(), SelfId, adnl, std::move(promise)) td::actor::create_actor<DhtQueryStore>("StoreQuery", std::move(value), print_id, id, std::move(list), k, a,
.release(); R.move_as_ok(), client_only, SelfId, adnl, std::move(promise))
}); .release();
});
get_self_node(std::move(P)); get_self_node(std::move(P));
} }
void DhtMemberImpl::get_self_node(td::Promise<DhtNode> promise) { void DhtMemberImpl::get_self_node(td::Promise<DhtNode> promise) {
auto P = td::PromiseCreator::lambda([promise = std::move(promise), print_id = print_id(), id = id_, auto P =
keyring = keyring_](td::Result<adnl::AdnlNode> R) mutable { td::PromiseCreator::lambda([promise = std::move(promise), print_id = print_id(), id = id_, keyring = keyring_,
R.ensure(); client_only = client_only_](td::Result<adnl::AdnlNode> R) mutable {
auto node = R.move_as_ok(); R.ensure();
auto version = static_cast<td::int32>(td::Clocks::system()); auto node = R.move_as_ok();
auto B = create_serialize_tl_object<ton_api::dht_node>(node.pub_id().tl(), node.addr_list().tl(), version, auto version = static_cast<td::int32>(td::Clocks::system());
td::BufferSlice()); auto B = create_serialize_tl_object<ton_api::dht_node>(node.pub_id().tl(), node.addr_list().tl(), version,
CHECK(node.addr_list().size() > 0); td::BufferSlice());
auto P = td::PromiseCreator::lambda( if (!client_only) {
[promise = std::move(promise), node = std::move(node), version](td::Result<td::BufferSlice> R) mutable { CHECK(node.addr_list().size() > 0);
R.ensure(); }
DhtNode n{node.pub_id(), node.addr_list(), version, R.move_as_ok()}; auto P = td::PromiseCreator::lambda(
promise.set_result(std::move(n)); [promise = std::move(promise), node = std::move(node), version](td::Result<td::BufferSlice> R) mutable {
}); R.ensure();
td::actor::send_closure(keyring, &keyring::Keyring::sign_message, id.pubkey_hash(), std::move(B), std::move(P)); DhtNode n{node.pub_id(), node.addr_list(), version, R.move_as_ok()};
}); promise.set_result(std::move(n));
});
td::actor::send_closure(keyring, &keyring::Keyring::sign_message, id.pubkey_hash(), std::move(B), std::move(P));
});
td::actor::send_closure(adnl_, &adnl::Adnl::get_self_node, id_, std::move(P)); td::actor::send_closure(adnl_, &adnl::Adnl::get_self_node, id_, std::move(P));
} }

View file

@ -42,6 +42,10 @@ class Dht : public td::actor::Actor {
std::shared_ptr<DhtGlobalConfig> conf, std::shared_ptr<DhtGlobalConfig> conf,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl); td::actor::ActorId<adnl::Adnl> adnl);
static td::Result<td::actor::ActorOwn<Dht>> create_client(adnl::AdnlNodeIdShort id, std::string db_root,
std::shared_ptr<DhtGlobalConfig> conf,
td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl);
static td::Result<std::shared_ptr<DhtGlobalConfig>> create_global_config( static td::Result<std::shared_ptr<DhtGlobalConfig>> create_global_config(
tl_object_ptr<ton_api::dht_config_global> conf); tl_object_ptr<ton_api::dht_config_global> conf);

View file

@ -85,8 +85,8 @@ class DhtMember : public Dht {
static td::actor::ActorOwn<DhtMember> create(adnl::AdnlNodeIdShort id, std::string db_root, static td::actor::ActorOwn<DhtMember> create(adnl::AdnlNodeIdShort id, std::string db_root,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k = 10, td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k = 10, td::uint32 a = 3,
td::uint32 a = 3); bool client_only = false);
//virtual void update_addr_list(tl_object_ptr<ton_api::adnl_addressList> addr_list) = 0; //virtual void update_addr_list(tl_object_ptr<ton_api::adnl_addressList> addr_list) = 0;
//virtual void add_node(adnl::AdnlNodeIdShort id) = 0; //virtual void add_node(adnl::AdnlNodeIdShort id) = 0;

View file

@ -2140,6 +2140,10 @@ These primitives are completely similar to their non-prefix code counterparts {\
\item {\tt F4AA} --- {\tt PFXDICTGETJMP} ($s$ $D$ $n$ -- $s'$ $s''$ or $s$), similar to {\tt PFXDICTGETQ}, but on success {\tt BLESS}es the value $x$ into a {\em Continuation\/} and transfers control to it as if by a {\tt JMPX}. On failure, returns $s$ unchanged and continues execution. \item {\tt F4AA} --- {\tt PFXDICTGETJMP} ($s$ $D$ $n$ -- $s'$ $s''$ or $s$), similar to {\tt PFXDICTGETQ}, but on success {\tt BLESS}es the value $x$ into a {\em Continuation\/} and transfers control to it as if by a {\tt JMPX}. On failure, returns $s$ unchanged and continues execution.
\item {\tt F4AB} --- {\tt PFXDICTGETEXEC} ($s$ $D$ $n$ -- $s'$ $s''$), similar to {\tt PFXDICTGETJMP}, but {\tt EXEC}utes the continuation found instead of jumping to it. On failure, throws a cell deserialization exception. \item {\tt F4AB} --- {\tt PFXDICTGETEXEC} ($s$ $D$ $n$ -- $s'$ $s''$), similar to {\tt PFXDICTGETJMP}, but {\tt EXEC}utes the continuation found instead of jumping to it. On failure, throws a cell deserialization exception.
\item {\tt F4AE\_$n$} --- {\tt PFXDICTCONSTGETJMP $n$} or {\tt PFXDICTSWITCH $n$} ($s$ -- $s'$ $s''$ or $s$), combines {\tt DICTPUSHCONST $n$} for $0\leq n\leq 1023$ with {\tt PFXDICTGETJMP}. \item {\tt F4AE\_$n$} --- {\tt PFXDICTCONSTGETJMP $n$} or {\tt PFXDICTSWITCH $n$} ($s$ -- $s'$ $s''$ or $s$), combines {\tt DICTPUSHCONST $n$} for $0\leq n\leq 1023$ with {\tt PFXDICTGETJMP}.
\item {\tt F4BC} --- {\tt DICTIGETJMPZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTIGETJMP} that returns index $i$ on failure.
\item {\tt F4BD} --- {\tt DICTUGETJMPZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTUGETJMP} that returns index $i$ on failure.
\item {\tt F4BE} --- {\tt DICTIGETEXECZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTIGETEXEC} that returns index $i$ on failure.
\item {\tt F4BF} --- {\tt DICTUGETEXECZ} ($i$ $D$ $n$ -- $i$ or nothing), a variant of {\tt DICTUGETEXEC} that returns index $i$ on failure.
\end{itemize} \end{itemize}
\nxsubpoint\label{sp:prim.dict.get}\emb{{\sc SubDict} dictionary operations} \nxsubpoint\label{sp:prim.dict.get}\emb{{\sc SubDict} dictionary operations}
@ -2150,6 +2154,7 @@ These primitives are completely similar to their non-prefix code counterparts {\
\item {\tt F4B5} --- {\tt SUBDICTRPGET} ($k$ $l$ $D$ $n$ -- $D'$), similar to {\tt SUBDICTGET}, but removes the common prefix $k$ from all keys of the new dictionary $D'$, which becomes of type $\HashmapE(n-l,X)$. \item {\tt F4B5} --- {\tt SUBDICTRPGET} ($k$ $l$ $D$ $n$ -- $D'$), similar to {\tt SUBDICTGET}, but removes the common prefix $k$ from all keys of the new dictionary $D'$, which becomes of type $\HashmapE(n-l,X)$.
\item {\tt F4B6} --- {\tt SUBDICTIRPGET} ($x$ $l$ $D$ $n$ -- $D'$), variant of {\tt SUBDICTRPGET} with the prefix represented by a signed big-endian $l$-bit {\em Integer\/}~$x$, where necessarily $l\leq257$. \item {\tt F4B6} --- {\tt SUBDICTIRPGET} ($x$ $l$ $D$ $n$ -- $D'$), variant of {\tt SUBDICTRPGET} with the prefix represented by a signed big-endian $l$-bit {\em Integer\/}~$x$, where necessarily $l\leq257$.
\item {\tt F4B7} --- {\tt SUBDICTURPGET} ($x$ $l$ $D$ $n$ -- $D'$), variant of {\tt SUBDICTRPGET} with the prefix represented by an unsigned big-endian $l$-bit {\em Integer\/}~$x$, where necessarily $l\leq256$. \item {\tt F4B7} --- {\tt SUBDICTURPGET} ($x$ $l$ $D$ $n$ -- $D'$), variant of {\tt SUBDICTRPGET} with the prefix represented by an unsigned big-endian $l$-bit {\em Integer\/}~$x$, where necessarily $l\leq256$.
\item {\tt F4BC}--{\tt F4BF} --- used by {\tt DICT\dots Z} primitives in \ptref{sp:prim.dict.get.spec}.
\end{itemize} \end{itemize}
\mysubsection{Application-specific primitives}\label{p:prim.app} \mysubsection{Application-specific primitives}\label{p:prim.app}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "keyring.hpp" #include "keyring.hpp"
#include "common/errorcode.h" #include "common/errorcode.h"
@ -28,7 +28,9 @@ namespace ton {
namespace keyring { namespace keyring {
void KeyringImpl::start_up() { void KeyringImpl::start_up() {
td::mkdir(db_root_).ensure(); if (db_root_.size() > 0) {
td::mkdir(db_root_).ensure();
}
} }
td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash key_hash) { td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash key_hash) {
@ -37,6 +39,10 @@ td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash k
return it->second.get(); return it->second.get();
} }
if (db_root_.size() == 0) {
return td::Status::Error(ErrorCode::notready, "key not in db");
}
auto name = db_root_ + "/" + key_hash.bits256_value().to_hex(); auto name = db_root_ + "/" + key_hash.bits256_value().to_hex();
auto R = td::read_file(td::CSlice{name}); auto R = td::read_file(td::CSlice{name});
@ -67,6 +73,9 @@ void KeyringImpl::add_key(PrivateKey key, bool is_temp, td::Promise<td::Unit> pr
promise.set_value(td::Unit()); promise.set_value(td::Unit());
return; return;
} }
if (db_root_.size() == 0) {
CHECK(is_temp);
}
auto D = key.create_decryptor_async(); auto D = key.create_decryptor_async();
D.ensure(); D.ensure();
@ -103,6 +112,9 @@ void KeyringImpl::add_key_short(PublicKeyHash key_hash, td::Promise<PublicKey> p
void KeyringImpl::del_key(PublicKeyHash key_hash, td::Promise<td::Unit> promise) { void KeyringImpl::del_key(PublicKeyHash key_hash, td::Promise<td::Unit> promise) {
map_.erase(key_hash); map_.erase(key_hash);
if (db_root_.size() == 0) {
return promise.set_value(td::Unit());
}
auto name = db_root_ + "/" + key_hash.bits256_value().to_hex(); auto name = db_root_ + "/" + key_hash.bits256_value().to_hex();
td::BufferSlice d{256}; td::BufferSlice d{256};
td::Random::secure_bytes(d.as_slice()); td::Random::secure_bytes(d.as_slice());

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "lite-client.h" #include "lite-client.h"
@ -800,7 +800,7 @@ bool TestNode::show_help(std::string command) {
"saveaccount[code|data] <filename> <addr> [<block-id-ext>]\tSaves into specified file the most recent state " "saveaccount[code|data] <filename> <addr> [<block-id-ext>]\tSaves into specified file the most recent state "
"(StateInit) or just the code or data of specified account; <addr> is in " "(StateInit) or just the code or data of specified account; <addr> is in "
"[<workchain>:]<hex-or-base64-addr> format\n" "[<workchain>:]<hex-or-base64-addr> format\n"
"runmethod <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account <addr> " "runmethod[x] <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account <addr> "
"with specified parameters\n" "with specified parameters\n"
"allshards [<block-id-ext>]\tShows shard configuration from the most recent masterchain " "allshards [<block-id-ext>]\tShows shard configuration from the most recent masterchain "
"state or from masterchain state corresponding to <block-id-ext>\n" "state or from masterchain state corresponding to <block-id-ext>\n"
@ -871,11 +871,11 @@ bool TestNode::do_parse_line() {
(seekeoln() (seekeoln()
? get_account_state(workchain, addr, mc_last_id_, filename, mode) ? get_account_state(workchain, addr, mc_last_id_, filename, mode)
: parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, filename, mode)); : parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, filename, mode));
} else if (word == "runmethod") { } else if (word == "runmethod" || word == "runmethodx") {
std::string method; std::string method;
return parse_account_addr(workchain, addr) && get_word_to(method) && return parse_account_addr(workchain, addr) && get_word_to(method) &&
(parse_block_id_ext(method, blkid) ? get_word_to(method) : (blkid = mc_last_id_).is_valid()) && (parse_block_id_ext(method, blkid) ? get_word_to(method) : (blkid = mc_last_id_).is_valid()) &&
parse_run_method(workchain, addr, blkid, method); parse_run_method(workchain, addr, blkid, method, word.size() > 9);
} else if (word == "allshards") { } else if (word == "allshards") {
return eoln() ? get_all_shards() : (parse_block_id_ext(blkid) && seekeoln() && get_all_shards(false, blkid)); return eoln() ? get_all_shards() : (parse_block_id_ext(blkid) && seekeoln() && get_all_shards(false, blkid));
} else if (word == "saveconfig") { } else if (word == "saveconfig") {
@ -1015,8 +1015,16 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress
}); });
} }
td::int64 TestNode::compute_method_id(std::string method) {
td::int64 method_id;
if (!convert_int64(method, method_id)) {
method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000;
}
return method_id;
}
bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
std::string method_name) { std::string method_name, bool ext_mode) {
auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_)); auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_));
if (R.is_error()) { if (R.is_error()) {
return set_error(R.move_as_error().to_string()); return set_error(R.move_as_error().to_string());
@ -1030,28 +1038,69 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
return set_error("server connection not ready"); return set_error("server connection not ready");
} }
auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr); auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>( int mode = (ext_mode ? 0x1f : 0);
ton::create_tl_lite_block_id(ref_blkid), std::move(a)), if (!mode) {
true); auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to " ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
<< ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters"; true);
return envelope_send_query( LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to "
std::move(b), [ Self = actor_id(this), workchain, addr, ref_blkid, method_name, << ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters";
params = std::move(params) ](td::Result<td::BufferSlice> R) mutable { return envelope_send_query(
if (R.is_error()) { std::move(b), [ Self = actor_id(this), workchain, addr, ref_blkid, method_name,
return; params = std::move(params) ](td::Result<td::BufferSlice> R) mutable {
} if (R.is_error()) {
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(R.move_as_ok(), true); return;
if (F.is_error()) { }
LOG(ERROR) << "cannot parse answer to liteServer.getAccountState"; auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(R.move_as_ok(), true);
} else { if (F.is_error()) {
auto f = F.move_as_ok(); LOG(ERROR) << "cannot parse answer to liteServer.getAccountState";
td::actor::send_closure_later(Self, &TestNode::run_smc_method, ref_blkid, ton::create_block_id(f->id_), } else {
ton::create_block_id(f->shardblk_), std::move(f->shard_proof_), auto f = F.move_as_ok();
std::move(f->proof_), std::move(f->state_), workchain, addr, method_name, td::actor::send_closure_later(Self, &TestNode::run_smc_method, 0, ref_blkid, ton::create_block_id(f->id_),
std::move(params)); ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
} std::move(f->proof_), std::move(f->state_), workchain, addr, method_name,
}); std::move(params), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(),
-0x10000);
}
});
} else {
td::int64 method_id = compute_method_id(method_name);
// serialize parameters
vm::CellBuilder cb;
Ref<vm::Cell> cell;
if (!(vm::Stack{params}.serialize(cb) && cb.finalize_to(cell))) {
return set_error("cannot serialize stack with get-method parameters");
}
auto stk = vm::std_boc_serialize(std::move(cell));
if (stk.is_error()) {
return set_error("cannot serialize stack with get-method parameters : "s + stk.move_as_error().to_string());
}
auto b = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>(mode, ton::create_tl_lite_block_id(ref_blkid),
std::move(a), method_id, stk.move_as_ok()),
true);
LOG(INFO) << "requesting remote get-method execution for " << workchain << ":" << addr.to_hex()
<< " with respect to " << ref_blkid.to_str() << " to run method " << method_name << " with "
<< params.size() << " parameters";
return envelope_send_query(std::move(b), [
Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params)
](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
return;
}
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_runMethodResult>(R.move_as_ok(), true);
if (F.is_error()) {
LOG(ERROR) << "cannot parse answer to liteServer.runSmcMethod";
} else {
auto f = F.move_as_ok();
td::actor::send_closure_later(Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_),
ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
std::move(f->proof_), std::move(f->state_proof_), workchain, addr, method_name,
std::move(params), std::move(f->init_c7_), std::move(f->lib_extras_),
std::move(f->result_), f->exit_code_);
}
});
}
} }
bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workchain, ton::StdSmcAddress addr, bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workchain, ton::StdSmcAddress addr,
@ -1212,87 +1261,147 @@ void TestNode::got_account_state(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, t
} }
} }
void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk, void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state, td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method, ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
std::vector<vm::StackEntry> params) { std::vector<vm::StackEntry> params, td::BufferSlice remote_c7,
LOG(INFO) << "got account state for " << workchain << ":" << addr.to_hex() << " with respect to blocks " td::BufferSlice remote_libs, td::BufferSlice remote_result, int remote_exit_code) {
<< blk.to_str() << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str()); LOG(INFO) << "got (partial) account state with mode=" << mode << " for " << workchain << ":" << addr.to_hex()
block::AccountState account_state; << " with respect to blocks " << blk.to_str()
account_state.blk = blk; << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str());
account_state.shard_blk = shard_blk;
account_state.shard_proof = std::move(shard_proof);
account_state.proof = std::move(proof);
account_state.state = std::move(state);
auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr));
if (r_info.is_error()) {
LOG(ERROR) << r_info.error().message();
return;
}
auto out = td::TerminalIO::out(); auto out = td::TerminalIO::out();
auto info = r_info.move_as_ok(); try {
if (info.root.is_null()) { block::AccountState account_state;
LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `" << method account_state.blk = blk;
<< "`)"; account_state.shard_blk = shard_blk;
return; account_state.shard_proof = std::move(shard_proof);
} account_state.proof = std::move(proof);
block::gen::Account::Record_account acc; LOG(DEBUG) << "serialized state is " << state.size() << " bytes";
block::gen::AccountStorage::Record store; LOG(DEBUG) << "serialized remote c7 is " << remote_c7.size() << " bytes";
block::CurrencyCollection balance; account_state.state = std::move(state);
if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) && account_state.is_virtualized = (mode > 0);
balance.validate_unpack(store.balance))) { auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr));
LOG(ERROR) << "error unpacking account state"; if (r_info.is_error()) {
return; LOG(ERROR) << r_info.error().message();
}
int tag = block::gen::t_AccountState.get_tag(*store.state);
switch (tag) {
case block::gen::AccountState::account_uninit:
LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " not initialized yet (cannot run any methods)";
return; return;
case block::gen::AccountState::account_frozen: }
LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)"; auto out = td::TerminalIO::out();
auto info = r_info.move_as_ok();
if (info.root.is_null()) {
LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `"
<< method << "`)";
return; return;
} }
CHECK(store.state.write().fetch_ulong(1) == 1); // account_init$1 _:StateInit = AccountState; if (false) {
block::gen::StateInit::Record state_init; // DEBUG (dump state)
CHECK(tlb::csr_unpack(store.state, state_init)); std::ostringstream os;
auto code = state_init.code->prefetch_ref(); vm::CellSlice{vm::NoVm(), info.true_root}.print_rec(os);
auto data = state_init.data->prefetch_ref(); out << "dump of account state (proof): " << os.str() << std::endl;
auto stack = td::make_ref<vm::Stack>(std::move(params)); }
td::int64 method_id; if (false && remote_c7.size()) {
if (!convert_int64(method, method_id)) { // DEBUG (dump remote_c7)
method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000; auto r_c7 = vm::std_boc_deserialize(remote_c7).move_as_ok();
} std::ostringstream os;
stack.write().push_smallint(method_id); vm::StackEntry val;
{ bool ok = val.deserialize(r_c7);
std::ostringstream os; val.dump(os);
os << "arguments: "; // os << std::endl;
stack->dump(os, 3); // block::gen::t_VmStackValue.print_ref(os, r_c7);
out << os.str(); // os << std::endl;
} // vm::CellSlice{vm::NoVmOrd(), r_c7}.print_rec(os);
long long gas_limit = vm::GasLimits::infty; out << "remote_c7 (deserialized=" << ok << "): " << os.str() << std::endl;
// OstreamLogger ostream_logger(ctx.error_stream); }
// auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); block::gen::Account::Record_account acc;
vm::GasLimits gas{gas_limit}; block::gen::AccountStorage::Record store;
LOG(DEBUG) << "creating VM"; block::CurrencyCollection balance;
vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()}; if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) &&
vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, acc.addr, balance)); // tuple with SmartContractInfo balance.validate_unpack(store.balance))) {
// vm.incr_stack_trace(1); // enable stack dump after each step LOG(ERROR) << "error unpacking account state";
LOG(INFO) << "starting VM to run method `" << method << "` (" << method_id << ") of smart contract " << workchain return;
<< ":" << addr.to_hex(); }
int exit_code = ~vm.run(); int tag = block::gen::t_AccountState.get_tag(*store.state);
LOG(DEBUG) << "VM terminated with exit code " << exit_code; switch (tag) {
if (exit_code != 0) { case block::gen::AccountState::account_uninit:
LOG(ERROR) << "VM terminated with error code " << exit_code; LOG(ERROR) << "account " << workchain << ":" << addr.to_hex()
out << "result: error " << exit_code << std::endl; << " not initialized yet (cannot run any methods)";
return; return;
} case block::gen::AccountState::account_frozen:
stack = vm.get_stack_ref(); LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)";
{ return;
std::ostringstream os; }
os << "result: "; CHECK(store.state.write().fetch_ulong(1) == 1); // account_init$1 _:StateInit = AccountState;
stack->dump(os, 3); block::gen::StateInit::Record state_init;
out << os.str(); CHECK(tlb::csr_unpack(store.state, state_init));
auto code = state_init.code->prefetch_ref();
auto data = state_init.data->prefetch_ref();
auto stack = td::make_ref<vm::Stack>(std::move(params));
td::int64 method_id = compute_method_id(method);
stack.write().push_smallint(method_id);
{
std::ostringstream os;
os << "arguments: ";
stack->dump(os, 3);
out << os.str();
}
long long gas_limit = vm::GasLimits::infty;
// OstreamLogger ostream_logger(ctx.error_stream);
// auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
vm::GasLimits gas{gas_limit};
LOG(DEBUG) << "creating VM";
vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()),
balance)); // tuple with SmartContractInfo
// vm.incr_stack_trace(1); // enable stack dump after each step
LOG(INFO) << "starting VM to run method `" << method << "` (" << method_id << ") of smart contract " << workchain
<< ":" << addr.to_hex();
int exit_code = ~vm.run();
LOG(DEBUG) << "VM terminated with exit code " << exit_code;
if (mode > 0) {
LOG(DEBUG) << "remote VM exit code is " << remote_exit_code;
}
if (exit_code != 0) {
LOG(ERROR) << "VM terminated with error code " << exit_code;
out << "result: error " << exit_code << std::endl;
return;
}
stack = vm.get_stack_ref();
{
std::ostringstream os;
os << "result: ";
stack->dump(os, 3);
out << os.str();
}
if (mode & 4) {
if (remote_result.empty()) {
out << "remote result: <none>, exit code " << remote_exit_code;
} else {
auto res = vm::std_boc_deserialize(std::move(remote_result));
if (res.is_error()) {
LOG(ERROR) << "cannot deserialize remote VM result boc: " << res.move_as_error();
return;
}
auto cs = vm::load_cell_slice(res.move_as_ok());
Ref<vm::Stack> remote_stack;
if (!(vm::Stack::deserialize_to(cs, remote_stack, 0) && cs.empty_ext())) {
LOG(ERROR) << "remote VM result boc cannot be deserialized as a VmStack";
return;
}
std::ostringstream os;
os << "remote result (not to be trusted): ";
remote_stack->dump(os, 3);
out << os.str();
}
}
if (0) { // DEBUG
std::ostringstream os;
LOG(DEBUG) << "dumping constructed proof";
//vm::CellSlice{vm::NoVm(), pb.extract_proof()}.print_rec(os);
out << "constructed state proof: " << os.str();
}
} catch (vm::VmVirtError& err) {
out << "virtualization error while parsing runSmcMethod result: " << err.get_msg();
} catch (vm::VmError& err) {
out << "error while parsing runSmcMethod result: " << err.get_msg();
} }
} }
@ -2062,7 +2171,7 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int
} }
auto root = res.move_as_ok(); auto root = res.move_as_ok();
std::ostringstream outp; std::ostringstream outp;
vm::CellSlice cs{vm::NoVm{}, root}; vm::CellSlice cs{vm::NoVm(), root};
cs.print_rec(outp); cs.print_rec(outp);
td::TerminalIO::out() << outp.str(); td::TerminalIO::out() << outp.str();
try { try {

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here. from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
#include "adnl/adnl-ext-client.h" #include "adnl/adnl-ext-client.h"
@ -117,11 +117,12 @@ class TestNode : public td::actor::Actor {
td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state, td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string filename, int mode); ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string filename, int mode);
bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
std::string method_name); std::string method_name, bool ext_mode);
void run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk, void run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state, td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method, ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
std::vector<vm::StackEntry> params); std::vector<vm::StackEntry> params, td::BufferSlice remote_c7, td::BufferSlice remote_libs,
td::BufferSlice remote_result, int remote_exit_code);
bool get_all_shards(bool use_last = true, ton::BlockIdExt blkid = {}); bool get_all_shards(bool use_last = true, ton::BlockIdExt blkid = {});
void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data); void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data);
bool get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = ""); bool get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "");
@ -181,6 +182,7 @@ class TestNode : public td::actor::Actor {
static bool convert_uint32(td::Slice word, td::uint32& val); static bool convert_uint32(td::Slice word, td::uint32& val);
static bool convert_int32(td::Slice word, td::int32& val); static bool convert_int32(td::Slice word, td::int32& val);
static bool convert_shard_id(td::Slice str, ton::ShardIdFull& shard); static bool convert_shard_id(td::Slice str, ton::ShardIdFull& shard);
static td::int64 compute_method_id(std::string method);
bool parse_hash(ton::Bits256& hash); bool parse_hash(ton::Bits256& hash);
bool parse_lt(ton::LogicalTime& lt); bool parse_lt(ton::LogicalTime& lt);
bool parse_uint32(td::uint32& val); bool parse_uint32(td::uint32& val);

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -84,6 +84,12 @@ class BufferedFd : public BufferedFdBase<FdT> {
~BufferedFd(); ~BufferedFd();
void close(); void close();
size_t left_unread() {
return input_reader_.size();
}
size_t left_unwritten() {
return output_reader_.size();
}
Result<size_t> flush_read(size_t max_read = std::numeric_limits<size_t>::max()) TD_WARN_UNUSED_RESULT; Result<size_t> flush_read(size_t max_read = std::numeric_limits<size_t>::max()) TD_WARN_UNUSED_RESULT;
Result<size_t> flush_write() TD_WARN_UNUSED_RESULT; Result<size_t> flush_write() TD_WARN_UNUSED_RESULT;

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "td/utils/FileLog.h" #include "td/utils/FileLog.h"
@ -128,4 +128,10 @@ void FileLog::do_rotate() {
SET_VERBOSITY_LEVEL(current_verbosity_level); SET_VERBOSITY_LEVEL(current_verbosity_level);
} }
Result<td::unique_ptr<LogInterface>> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) {
auto l = make_unique<FileLog>();
TRY_STATUS(l->init(std::move(path), rotate_threshold, redirect_stderr));
return std::move(l);
}
} // namespace td } // namespace td

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -30,6 +30,8 @@ class FileLog : public LogInterface {
static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20); static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
public: public:
static Result<td::unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD,
bool redirect_stderr = true);
Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, bool redirect_stderr = true); Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, bool redirect_stderr = true);
Slice get_path() const; Slice get_path() const;

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -44,12 +44,12 @@ std::pair<T, T> split(T s, char delimiter = ' ') {
} }
template <class T> template <class T>
vector<T> full_split(T s, char delimiter = ' ') { vector<T> full_split(T s, char delimiter = ' ', size_t max_parts = std::numeric_limits<size_t>::max()) {
vector<T> result; vector<T> result;
if (s.empty()) { if (s.empty()) {
return result; return result;
} }
while (true) { while (result.size() + 1 < max_parts) {
auto delimiter_pos = s.find(delimiter); auto delimiter_pos = s.find(delimiter);
if (delimiter_pos == string::npos) { if (delimiter_pos == string::npos) {
result.push_back(std::move(s)); result.push_back(std::move(s));
@ -59,6 +59,8 @@ vector<T> full_split(T s, char delimiter = ' ') {
s = s.substr(delimiter_pos + 1); s = s.substr(delimiter_pos + 1);
} }
} }
result.push_back(std::move(s));
return result;
} }
string implode(const vector<string> &v, char delimiter = ' '); string implode(const vector<string> &v, char delimiter = ' ');

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "td/utils/port/detail/Epoll.h" #include "td/utils/port/detail/Epoll.h"
@ -109,6 +109,7 @@ void Epoll::run(int timeout_ms) {
#ifdef EPOLLRDHUP #ifdef EPOLLRDHUP
if (event->events & EPOLLRDHUP) { if (event->events & EPOLLRDHUP) {
event->events &= ~EPOLLRDHUP; event->events &= ~EPOLLRDHUP;
flags = flags | PollFlags::Close();
// flags |= Fd::Close; // flags |= Fd::Close;
// TODO // TODO
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "td/utils/as.h" #include "td/utils/as.h"
#include "td/utils/base64.h" #include "td/utils/base64.h"
@ -570,6 +570,10 @@ static void test_full_split(Slice str, vector<Slice> expected) {
ASSERT_EQ(expected, td::full_split(str)); ASSERT_EQ(expected, td::full_split(str));
} }
static void test_full_split(Slice str, char c, size_t max_parts, vector<Slice> expected) {
ASSERT_EQ(expected, td::full_split(str, c, max_parts));
}
TEST(Misc, full_split) { TEST(Misc, full_split) {
test_full_split("", {}); test_full_split("", {});
test_full_split(" ", {"", ""}); test_full_split(" ", {"", ""});
@ -585,6 +589,7 @@ TEST(Misc, full_split) {
test_full_split(" abcdef ", {"", "abcdef", ""}); test_full_split(" abcdef ", {"", "abcdef", ""});
test_full_split(" ab cd ef ", {"", "ab", "cd", "ef", ""}); test_full_split(" ab cd ef ", {"", "ab", "cd", "ef", ""});
test_full_split(" ab cd ef ", {"", "", "ab", "", "cd", "", "ef", "", ""}); test_full_split(" ab cd ef ", {"", "", "ab", "", "cd", "", "ef", "", ""});
test_full_split("ab cd ef gh", ' ', 3, {"ab", "cd", "ef gh"});
} }
TEST(Misc, StringBuilder) { TEST(Misc, StringBuilder) {

View file

@ -23,7 +23,7 @@ Test_Fift_testvm6_default dd6353c8f3f21cf62a4769ee1f3daaec46f43fd633ffb84c5d6535
Test_Fift_testvm7_default 77f54b6c8c9a728d262e912efcc347de7014a37d08793c3adeac8b96fe063342 Test_Fift_testvm7_default 77f54b6c8c9a728d262e912efcc347de7014a37d08793c3adeac8b96fe063342
Test_Fift_testvm8_default 17c9e2205ccecfd8549328b4a501d07dde0336899a7a496e747e1032ad5efff9 Test_Fift_testvm8_default 17c9e2205ccecfd8549328b4a501d07dde0336899a7a496e747e1032ad5efff9
Test_Fift_testvm_default ee4cbfec76c050b6de7877cfc39817d594cd1e175b6265b76fb642e30b940437 Test_Fift_testvm_default ee4cbfec76c050b6de7877cfc39817d594cd1e175b6265b76fb642e30b940437
Test_Fift_testvmprog_default 3aeebf868c0492f2bafe339505751449e9d258bf25ea5d956efe70c6fce408ed Test_Fift_testvmprog_default a6d40d8a7bf0dd3b719c8b1023fef59e01ef094f732951cec4577556c6c68e64
Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb
Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d
Test_VM_assert_extract_minmax_key_default c352309c61bdf62ba7a0ba7280d303c88b0696fe7efa550c05feb2c662275297 Test_VM_assert_extract_minmax_key_default c352309c61bdf62ba7a0ba7280d303c88b0696fe7efa550c05feb2c662275297

View file

@ -35,7 +35,7 @@ liteServer.blockState id:tonNode.blockIdExt root_hash:int256 file_hash:int256 da
liteServer.blockHeader id:tonNode.blockIdExt mode:# header_proof:bytes = liteServer.BlockHeader; liteServer.blockHeader id:tonNode.blockIdExt mode:# header_proof:bytes = liteServer.BlockHeader;
liteServer.sendMsgStatus status:int = liteServer.SendMsgStatus; liteServer.sendMsgStatus status:int = liteServer.SendMsgStatus;
liteServer.accountState id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state:bytes = liteServer.AccountState; liteServer.accountState id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state:bytes = liteServer.AccountState;
liteServer.runMethodResult mode:# id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state_proof:bytes init_c7:bytes lib_extras:bytes exit_code:int result:bytes = liteServer.RunMethodResult; liteServer.runMethodResult mode:# id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:mode.0?bytes proof:mode.0?bytes state_proof:mode.1?bytes init_c7:mode.3?bytes lib_extras:mode.4?bytes exit_code:int result:mode.2?bytes = liteServer.RunMethodResult;
liteServer.shardInfo id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes shard_descr:bytes = liteServer.ShardInfo; liteServer.shardInfo id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes shard_descr:bytes = liteServer.ShardInfo;
liteServer.allShardsInfo id:tonNode.blockIdExt proof:bytes data:bytes = liteServer.AllShardsInfo; liteServer.allShardsInfo id:tonNode.blockIdExt proof:bytes data:bytes = liteServer.AllShardsInfo;
liteServer.transactionInfo id:tonNode.blockIdExt proof:bytes transaction:bytes = liteServer.TransactionInfo; liteServer.transactionInfo id:tonNode.blockIdExt proof:bytes transaction:bytes = liteServer.TransactionInfo;
@ -64,7 +64,7 @@ liteServer.getState id:tonNode.blockIdExt = liteServer.BlockState;
liteServer.getBlockHeader id:tonNode.blockIdExt mode:# = liteServer.BlockHeader; liteServer.getBlockHeader id:tonNode.blockIdExt mode:# = liteServer.BlockHeader;
liteServer.sendMessage body:bytes = liteServer.SendMsgStatus; liteServer.sendMessage body:bytes = liteServer.SendMsgStatus;
liteServer.getAccountState id:tonNode.blockIdExt account:liteServer.accountId = liteServer.AccountState; liteServer.getAccountState id:tonNode.blockIdExt account:liteServer.accountId = liteServer.AccountState;
liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:int params:bytes = liteServer.RunMethodResult; liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult;
liteServer.getShardInfo id:tonNode.blockIdExt workchain:int shard:long exact:Bool = liteServer.ShardInfo; liteServer.getShardInfo id:tonNode.blockIdExt workchain:int shard:long exact:Bool = liteServer.ShardInfo;
liteServer.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo; liteServer.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo;
liteServer.getOneTransaction id:tonNode.blockIdExt account:liteServer.accountId lt:long = liteServer.TransactionInfo; liteServer.getOneTransaction id:tonNode.blockIdExt account:liteServer.accountId lt:long = liteServer.TransactionInfo;

Binary file not shown.

View file

@ -614,3 +614,25 @@ engine.validator.createElectionBid election_date:int election_addr:string wallet
engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus; engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus;
engine.validator.controlQuery data:bytes = Object; engine.validator.controlQuery data:bytes = Object;
---types---
http.header name:string value:string = http.Header;
http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart;
http.response http_version:string status_code:int reason:string headers:(vector http.header) = http.Response;
---functions---
http.request id:int256 method:string url:string http_version:string headers:(vector http.header) = http.Response;
http.getNextPayloadPart id:int256 seqno:int max_chunk_size:int = http.PayloadPart;
---types---
http.server.dnsEntry domain:string addr:adnl.id.short = http.server.DnsEntry;
http.server.host domains:(vector string) ip:int port:int adnl_id:adnl.id.short = http.server.Host;
http.server.config dhs:(vector http.server.dnsEntry) local_hosts:(vector http.server.host) = http.server.Config;
---functions---

Binary file not shown.

View file

@ -504,6 +504,13 @@ void ArchiveManager::load_package(PackageId id) {
return; return;
} }
std::string prefix = PSTRING() << db_root_ << id.path() << id.name();
auto f = td::FileFd::open(prefix + ".pack", td::FileFd::Read);
if (f.is_error()) {
x->deleted_ = true;
return;
}
FileDescription desc{id, false}; FileDescription desc{id, false};
if (!id.temp) { if (!id.temp) {
for (auto &e : x->firstblocks_) { for (auto &e : x->firstblocks_) {
@ -512,7 +519,6 @@ void ArchiveManager::load_package(PackageId id) {
} }
} }
std::string prefix = PSTRING() << db_root_ << id.path() << id.name();
desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.key, id.temp, prefix); desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.key, id.temp, prefix);
get_file_map(id).emplace(id, std::move(desc)); get_file_map(id).emplace(id, std::move(desc));

View file

@ -28,6 +28,7 @@ class PackageReader : public td::actor::Actor {
} }
void start_up() { void start_up() {
promise_.set_result(package_->read(offset_)); promise_.set_result(package_->read(offset_));
stop();
} }
private: private:

View file

@ -46,8 +46,14 @@ td::uint64 Package::append(std::string filename, td::Slice data, bool sync) {
size += 8; size += 8;
CHECK(fd_.pwrite(filename, size).move_as_ok() == filename.size()); CHECK(fd_.pwrite(filename, size).move_as_ok() == filename.size());
size += filename.size(); size += filename.size();
CHECK(fd_.pwrite(data, size).move_as_ok() == data.size()); while (data.size() != 0) {
size += data.size(); auto R = fd_.pwrite(data, size);
R.ensure();
auto x = R.move_as_ok();
CHECK(x > 0);
size += x;
data.remove_prefix(x);
}
if (sync) { if (sync) {
fd_.sync().ensure(); fd_.sync().ensure();
} }

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "liteserver.hpp" #include "liteserver.hpp"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
@ -26,6 +26,7 @@
#include "adnl/utils.hpp" #include "adnl/utils.hpp"
#include "ton/lite-tl.hpp" #include "ton/lite-tl.hpp"
#include "tl-utils/lite-utils.hpp" #include "tl-utils/lite-utils.hpp"
#include "td/utils/Random.h"
#include "vm/boc.h" #include "vm/boc.h"
#include "tl/tlblib.hpp" #include "tl/tlblib.hpp"
#include "block/block.h" #include "block/block.h"
@ -33,6 +34,7 @@
#include "block/block-auto.h" #include "block/block-auto.h"
#include "vm/dict.h" #include "vm/dict.h"
#include "vm/cells/MerkleProof.h" #include "vm/cells/MerkleProof.h"
#include "vm/continuation.h"
#include "shard.hpp" #include "shard.hpp"
#include "validator-set.hpp" #include "validator-set.hpp"
#include "signature-set.hpp" #include "signature-set.hpp"
@ -665,14 +667,14 @@ void LiteQuery::continue_getAccountState_0(Ref<ton::validator::MasterchainState>
} }
void LiteQuery::perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode, void LiteQuery::perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode,
int method_id, td::BufferSlice params) { td::int64 method_id, td::BufferSlice params) {
LOG(INFO) << "started a runSmcMethod(" << blkid.to_str() << ", " << workchain << ", " << addr.to_hex() << ", " LOG(INFO) << "started a runSmcMethod(" << blkid.to_str() << ", " << workchain << ", " << addr.to_hex() << ", "
<< method_id << ", " << mode << ") liteserver query with " << params.size() << " parameter bytes"; << method_id << ", " << mode << ") liteserver query with " << params.size() << " parameter bytes";
if (params.size() >= 65536) { if (params.size() >= 65536) {
fatal_error("more than 64k parameter bytes passed"); fatal_error("more than 64k parameter bytes passed");
return; return;
} }
if (mode & ~0xf) { if (mode & ~0x1f) {
fatal_error("unsupported mode in runSmcMethod"); fatal_error("unsupported mode in runSmcMethod");
return; return;
} }
@ -984,7 +986,8 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
return; return;
} }
if (mode_ & 0x10000) { if (mode_ & 0x10000) {
finish_runSmcMethod(std::move(shard_proof), proof.move_as_ok(), std::move(acc_root)); finish_runSmcMethod(std::move(shard_proof), proof.move_as_ok(), std::move(acc_root), sstate.gen_utime,
sstate.gen_lt);
return; return;
} }
td::BufferSlice data; td::BufferSlice data;
@ -1003,11 +1006,112 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
finish_query(std::move(b)); finish_query(std::move(b));
} }
void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root) { // same as in lite-client/lite-client-common.cpp
static td::Ref<vm::Tuple> prepare_vm_c7(ton::UnixTime now, ton::LogicalTime lt, td::Ref<vm::CellSlice> my_addr,
const block::CurrencyCollection& balance) {
td::BitArray<256> rand_seed;
td::RefInt256 rand_seed_int{true};
td::Random::secure_bytes(rand_seed.as_slice());
if (!rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false)) {
return {};
}
auto tuple = vm::make_tuple_ref(td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
td::make_refint(0), // actions:Integer
td::make_refint(0), // msgs_sent:Integer
td::make_refint(now), // unixtime:Integer
td::make_refint(lt), // block_lt:Integer
td::make_refint(lt), // trans_lt:Integer
std::move(rand_seed_int), // rand_seed:Integer
balance.as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
my_addr, // myself:MsgAddressInt
vm::StackEntry()); // global_config:(Maybe Cell) ] = SmartContractInfo;
LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
return vm::make_tuple_ref(std::move(tuple));
}
void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root,
UnixTime gen_utime, LogicalTime gen_lt) {
LOG(INFO) << "completing runSmcMethod() query"; LOG(INFO) << "completing runSmcMethod() query";
// ... TODO ... int mode = mode_ & 0xffff;
fatal_error("runSmcMethod not implemented"); if (acc_root.is_null()) {
return; // no such account
LOG(INFO) << "runSmcMethod(" << acc_workchain_ << ":" << acc_addr_.to_hex()
<< ") query completed: account state is empty";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
std::move(state_proof), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(), -0x100, td::BufferSlice());
finish_query(std::move(b));
return;
}
vm::MerkleProofBuilder pb{std::move(acc_root)};
block::gen::Account::Record_account acc;
block::gen::AccountStorage::Record store;
block::CurrencyCollection balance;
block::gen::StateInit::Record state_init;
if (!(tlb::unpack_cell(pb.root(), acc) && tlb::csr_unpack(std::move(acc.storage), store) &&
balance.validate_unpack(store.balance) && store.state->prefetch_ulong(1) == 1 &&
store.state.write().advance(1) && tlb::csr_unpack(std::move(store.state), state_init))) {
LOG(INFO) << "error unpacking account state, or account is frozen or uninitialized";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), td::BufferSlice(),
td::BufferSlice(), -0x100, td::BufferSlice());
finish_query(std::move(b));
return;
}
auto code = state_init.code->prefetch_ref();
auto data = state_init.data->prefetch_ref();
long long gas_limit = client_method_gas_limit;
LOG(DEBUG) << "creating VM with gas limit " << gas_limit;
// **** INIT VM ****
vm::GasLimits gas{gas_limit};
vm::VmState vm{std::move(code), std::move(stack_), gas, 1, std::move(data), vm::VmLog::Null()};
auto c7 = prepare_vm_c7(gen_utime, gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()), balance);
vm.set_c7(c7); // tuple with SmartContractInfo
// vm.incr_stack_trace(1); // enable stack dump after each step
LOG(INFO) << "starting VM to run GET-method of smart contract " << acc_workchain_ << ":" << acc_addr_.to_hex();
// **** RUN VM ****
int exit_code = ~vm.run();
LOG(DEBUG) << "VM terminated with exit code " << exit_code;
stack_ = vm.get_stack_ref();
LOG(INFO) << "runSmcMethod(" << acc_workchain_ << ":" << acc_addr_.to_hex() << ") query completed: exit code is "
<< exit_code;
Ref<vm::Cell> cell;
td::BufferSlice c7_info, result;
if (mode & 8) {
// serialize c7
vm::CellBuilder cb;
if (!(vm::StackEntry{std::move(c7)}.serialize(cb) && cb.finalize_to(cell))) {
fatal_error("cannot serialize c7");
return;
}
auto res = vm::std_boc_serialize(std::move(cell));
if (res.is_error()) {
fatal_error("cannot serialize c7 : "s + res.move_as_error().to_string());
return;
}
c7_info = res.move_as_ok();
}
// pre-serialize stack always (to visit all data cells referred from the result)
vm::CellBuilder cb;
if (!(stack_->serialize(cb) && cb.finalize_to(cell))) {
fatal_error("cannot serialize resulting stack");
return;
}
if (mode & 4) {
// serialize stack if required
auto res = vm::std_boc_serialize(std::move(cell));
if (res.is_error()) {
fatal_error("cannot serialize resulting stack : "s + res.move_as_error().to_string());
return;
}
result = res.move_as_ok();
}
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), std::move(c7_info),
td::BufferSlice(), exit_code, std::move(result));
finish_query(std::move(b));
} }
void LiteQuery::continue_getOneTransaction() { void LiteQuery::continue_getOneTransaction() {

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
#include "ton/ton-types.h" #include "ton/ton-types.h"
@ -60,13 +60,14 @@ class LiteQuery : public td::actor::Actor {
public: public:
enum { enum {
default_timeout_msec = 4500, // 4.5 seconds default_timeout_msec = 4500, // 4.5 seconds
max_transaction_count = 16 // fetch at most 16 transactions in one query max_transaction_count = 16, // fetch at most 16 transactions in one query
client_method_gas_limit = 100000 // gas limit for liteServer.runSmcMethod
}; };
enum { enum {
ls_version = 0x101, ls_version = 0x101,
ls_capabilities = 3 ls_capabilities = 7
}; // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt }; // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt, +4 = runSmcMethod
LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager, LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::BufferSlice> promise); td::Promise<td::BufferSlice> promise);
static void run_query(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager, static void run_query(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
@ -97,9 +98,10 @@ class LiteQuery : public td::actor::Actor {
void continue_getAccountState_0(Ref<MasterchainState> mc_state, BlockIdExt blkid); void continue_getAccountState_0(Ref<MasterchainState> mc_state, BlockIdExt blkid);
void continue_getAccountState(); void continue_getAccountState();
void finish_getAccountState(td::BufferSlice shard_proof); void finish_getAccountState(td::BufferSlice shard_proof);
void perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode, int method_id, void perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode, td::int64 method_id,
td::BufferSlice params); td::BufferSlice params);
void finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root); void finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root,
UnixTime gen_utime, LogicalTime gen_lt);
void perform_getOneTransaction(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, LogicalTime lt); void perform_getOneTransaction(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, LogicalTime lt);
void continue_getOneTransaction(); void continue_getOneTransaction();
void perform_getTransactions(WorkchainId workchain, StdSmcAddress addr, LogicalTime lt, Bits256 hash, unsigned count); void perform_getTransactions(WorkchainId workchain, StdSmcAddress addr, LogicalTime lt, Bits256 hash, unsigned count);