1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 11:12:16 +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
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
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;
}
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 ton

View file

@ -88,6 +88,7 @@ class AdnlAddressList {
void add_addr(AdnlAddress addr) {
addrs_.push_back(addr);
}
void update(td::IPAddress addr);
bool public_only() const;
td::uint32 size() const {
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);
td::Status add_udp_address(td::IPAddress addr);
};
} // 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));
}
void AdnlChannelImpl::receive(td::BufferSlice data) {
void AdnlChannelImpl::receive(td::IPAddress addr, td::BufferSlice data) {
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()) {
VLOG(ADNL_WARNING) << id << ": dropping IN message: can not decrypt: " << R.move_as_error();
} 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,
AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
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,
td::BufferSlice data) = 0;
virtual ~AdnlChannel() = default;

View file

@ -33,7 +33,7 @@ class AdnlChannelImpl : public AdnlChannel {
AdnlChannelIdShort in_id, AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
std::unique_ptr<Decryptor> decryptor);
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;
struct AdnlChannelPrintId {

View file

@ -40,13 +40,15 @@ AdnlAddressList AdnlLocalId::get_addr_list() const {
return addr_list_;
}
void AdnlLocalId::receive(td::BufferSlice data) {
void AdnlLocalId::receive(td::IPAddress addr, td::BufferSlice data) {
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()) {
VLOG(ADNL_WARNING) << id << ": dropping IN message: cannot decrypt: " << R.move_as_error();
} 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() {
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";
return;
}
@ -178,7 +180,8 @@ AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor
id_ = std::move(id);
short_id_ = id_.compute_short_id();
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()));
}
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 deliver(AdnlNodeIdShort src, td::BufferSlice data);
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 unsubscribe(std::string prefix);

View file

@ -132,6 +132,9 @@ class AdnlPacket {
auto signature() const {
return signature_.clone();
}
auto remote_addr() const {
return remote_addr_;
}
void init_random();
@ -188,6 +191,10 @@ class AdnlPacket {
flags_ |= Flags::f_reinit_date;
}
void set_remote_addr(td::IPAddress addr) {
remote_addr_ = addr;
}
private:
td::BufferSlice rand1_;
td::uint32 flags_{0};
@ -204,6 +211,8 @@ class AdnlPacket {
td::int32 dst_reinit_date_{0};
td::BufferSlice signature_;
td::BufferSlice rand2_;
td::IPAddress remote_addr_;
};
} // 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));
}
void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data) {
if (data.size() < 32) {
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
return;
@ -60,14 +60,14 @@ void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
auto it = local_ids_own_.find(dst);
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;
}
AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
auto it2 = channels_.find(dst_chan_id);
if (it2 != channels_.end()) {
td::actor::send_closure(it2->second, &AdnlChannel::receive, std::move(data));
td::actor::send_closure(it2->second, &AdnlChannel::receive, addr, std::move(data));
return;
}
@ -237,7 +237,7 @@ void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkM
class Cb : public AdnlNetworkManager::Callback {
public:
void receive_packet(td::IPAddress addr, td::BufferSlice data) override {
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, std::move(data));
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, addr, std::move(data));
}
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 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 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_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 send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) 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.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()) {
update_addr_list(packet.priority_addr_list());
@ -174,7 +179,12 @@ void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
}
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()) {
update_addr_list(packet.priority_addr_list());
@ -642,7 +652,7 @@ void AdnlPeerPairImpl::update_addr_list(AdnlAddressList addr_list) {
if (addr_list.empty()) {
return;
}
CHECK(addr_list.size() > 0);
//CHECK(addr_list.size() > 0);
if (addr_list.reinit_date() > td::Clocks::system() + 60) {
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
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 "block/block-db.h"
@ -36,6 +36,8 @@
#include "block/mc-config.h"
#include "ton/ton-shard.h"
bool local_scripts{false};
HttpAnswer& HttpAnswer::operator<<(AddressCell addr_c) {
ton::WorkchainId wc;
ton::StdSmcAddress addr;
@ -425,7 +427,7 @@ HttpAnswer& HttpAnswer::operator<<(AccountCell acc_c) {
HttpAnswer& HttpAnswer::operator<<(BlockHeaderCell head_c) {
*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;
try {
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"
<< "<meta name=\"format-detection\" content=\"telephone=no\" />\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 -->"
<< "<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"
<< "<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"
<< "<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"
<< "<div class=\"container-fluid\">\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 "block/block.h"
extern bool local_scripts;
class HttpAnswer {
public:
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));
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
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),

View file

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

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "check-proof.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 {
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) {
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,
&res.last_trans_hash, &res.gen_utime, &res.gen_lt));
res.root = std::move(root);
res.true_root = std::move(true_root);
return res;
}

View file

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

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "mc-config.h"
#include "block/block.h"
@ -752,8 +752,8 @@ Ref<McShardDescr> McShardDescr::from_block(Ref<vm::Cell> block_root, Ref<vm::Cel
return {};
}
// TODO: use a suitable vm::MerkleUpdate method here
vm::CellSlice cs(vm::NoVm(), rec.state_update);
if (cs.special_type() != vm::Cell::SpecialType::MerkleUpdate) {
vm::CellSlice cs(vm::NoVmSpec(), rec.state_update);
if (!cs.is_valid() || cs.special_type() != vm::Cell::SpecialType::MerkleUpdate) {
LOG(ERROR) << "state update in a block is not a Merkle update";
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();
int len = id.pfx_len();
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);
if (t < 0) {
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;
stack.emplace(cs_ref->prefetch_ref(), ton::shardIdAll);
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;
stack.pop();
int t = (int)cs.fetch_ulong(1);

View file

@ -965,6 +965,11 @@ x{F4B5} @Defop SUBDICTRPGET
x{F4B6} @Defop SUBDICTIRPGET
x{F4B7} @Defop SUBDICTURPGET
x{F4BC} @Defop DICTIGETJMPZ
x{F4BD} @Defop DICTUGETJMPZ
x{F4BE} @Defop DICTIGETEXECZ
x{F4BF} @Defop DICTUGETEXECZ
//
// blockchain-specific primitives
@ -1117,7 +1122,7 @@ variable @gvarcnt
@procdict dup @ swap null!
} : }END
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>c <s } : }END>s

View file

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

View file

@ -39,3 +39,9 @@
int seqno() method_id {
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);
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`
<{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk
}>
INC 32 THROWIF // fail unless recv_external
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs

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`
<{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk
}>
INC 32 THROWIF // fail unless recv_external
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs

View file

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

View file

@ -62,6 +62,12 @@ int seqno() method_id {
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 {
return restricted?() ? 0 : get_balance().first();
}

View file

@ -55,6 +55,12 @@ int seqno() method_id {
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 {
var ds = get_data().begin_parse().skip_bits(32 + 256);
var rdict = ds~load_dict();

View file

@ -45,6 +45,11 @@ int seqno() method_id {
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 {
return create_state(0, public_key);
}

View file

@ -29,3 +29,9 @@
int seqno() method_id {
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 {
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
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"
@ -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);
}
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) {
return store_bits_bool(bs.cbits(), bs.size());
}

View file

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

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "vm/dict.h"
#include "vm/cells.h"
@ -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);
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";
//cs.print_rec(std::cerr);
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
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 "vm/log.h"
@ -210,7 +210,7 @@ int exec_dict_get(VmState* st, unsigned args) {
BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes];
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()) {
stack.push_smallint(0);
return 0;
@ -250,7 +250,7 @@ int exec_dict_get_optref(VmState* st, unsigned args) {
BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes];
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()) {
stack.push_null();
return 0;
@ -377,7 +377,7 @@ int exec_dict_delete(VmState* st, unsigned args) {
BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes];
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()) {
push_dict(stack, std::move(dict));
stack.push_smallint(0);
@ -404,7 +404,7 @@ int exec_dict_deleteget(VmState* st, unsigned args) {
BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes];
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()) {
push_dict(stack, std::move(dict));
stack.push_smallint(0);
@ -588,23 +588,29 @@ int exec_pfx_dict_delete(VmState* st) {
int exec_dict_get_exec(VmState* st, unsigned args) {
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);
int n = stack.pop_smallint_range(Dictionary::max_key_bits);
Dictionary dict{stack.pop_maybe_cell(), n};
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();
if (dict.integer_key_simple(idx, n, !(args & 1), td::BitPtr{buffer}, true)) {
auto value = dict.lookup(td::BitPtr{buffer}, n);
if (value.not_null()) {
Ref<OrdCont> cont{true, std::move(value), st->get_cp()};
return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont));
} else {
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) {
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) {
@ -720,7 +726,7 @@ int exec_subdict_get(VmState* st, unsigned args) {
BitSlice key;
unsigned char buffer[Dictionary::max_key_bytes];
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 {
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))
.insert(OpcodeInstr::mkfixedrange(0xf4b1, 0xf4b4, 16, 3, std::bind(dump_subdictop2, _2, "GET"), exec_subdict_get))
.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

View file

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

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "vm/stack.hpp"
#include "vm/continuation.h"
@ -824,7 +824,7 @@ bool StackEntry::deserialize(CellSlice& cs, int mode) {
return false;
}
} 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));
}

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) {
size_t have_space = 0;
for (size_t i = 0; i < active_nodes_.size(); i++) {
auto &node = active_nodes_[i];
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) {
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++) {
auto &node = backup_nodes_[i];
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()) {
promote_node(i);

View file

@ -39,8 +39,8 @@ class DhtBucket {
//std::map<td::UInt256, std::unique_ptr<DhtRemoteNode>> pending_nodes_;
td::uint32 k_;
bool check_one(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src,
const DhtMember::PrintId &print_id);
//bool check_one(td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> node, adnl::AdnlNodeIdShort src,
// const DhtMember::PrintId &print_id);
void demote_node(size_t idx);
void promote_node(size_t idx);
@ -52,7 +52,8 @@ class DhtBucket {
td::uint32 active_cnt();
td::Status add_full_node(DhtKeyId id, DhtNode node, td::actor::ActorId<adnl::Adnl> adnl,
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 get_nearest_nodes(DhtKeyId id, td::uint32 bit, DhtNodesList &vec, td::uint32 k);
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<adnl::Adnl> adnl_;
bool client_only_{false};
td::uint64 ping_queries_{0};
td::uint64 find_node_queries_{0};
td::uint64 find_value_queries_{0};
@ -123,8 +125,8 @@ class DhtMemberImpl : public DhtMember {
public:
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)
: id_(id), key_{id_}, k_(k), a_(a), db_root_(db_root), keyring_(keyring), adnl_(adnl) {
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), client_only_(client_only) {
for (size_t i = 0; i < 256; i++) {
buckets_.emplace_back(k_);
}

View file

@ -96,7 +96,12 @@ void DhtQuery::add_nodes(DhtNodesList list) {
void DhtQueryFindNodes::send_one_query(adnl::AdnlNodeIdShort id) {
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) {
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) {
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) {
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,
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::Promise<td::Unit> promise)
: print_id_(print_id)
@ -195,7 +205,8 @@ DhtQueryStore::DhtQueryStore(DhtValue key_value, DhtMember::PrintId print_id, ad
, promise_(std::move(promise))
, value_(std::move(key_value))
, list_(std::move(list))
, self_(std::move(self)) {
, self_(std::move(self))
, client_only_(client_only) {
node_ = node;
adnl_ = adnl;
src_ = src;
@ -208,7 +219,7 @@ void DhtQueryStore::start_up() {
auto key = value_.key_id();
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();
}

View file

@ -41,11 +41,21 @@ class DhtQuery : public td::actor::Actor {
protected:
DhtKeyId key_;
DhtNode self_;
bool client_only_;
public:
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)
: key_(key), self_(std::move(self)), print_id_(print_id), src_(src), k_(k), a_(a), node_(node), adnl_(adnl) {
td::uint32 a, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
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));
}
DhtMember::PrintId print_id() const {
@ -94,9 +104,10 @@ class DhtQueryFindNodes : public DhtQuery {
public:
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)
: 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 on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
@ -112,9 +123,10 @@ class DhtQueryFindValue : public DhtQuery {
public:
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)
: 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 on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
@ -139,10 +151,11 @@ class DhtQueryStore : public td::actor::Actor {
td::uint32 remaining_;
DhtNodesList list_;
DhtNode self_;
bool client_only_;
public:
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);
void send_stores(td::Result<DhtNodesList> 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();
}
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) {
missed_pings_++;
if (missed_pings_ > max_missed_pings_ && ready_from_ > 0) {
@ -75,8 +75,8 @@ 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());
auto P = td::PromiseCreator::lambda(
[key = id_, id = node_.adnl_id().compute_short_id(), node, src, adnl](td::Result<DhtNode> R) mutable {
auto P = td::PromiseCreator::lambda([key = id_, id = node_.adnl_id().compute_short_id(), client_only, node, src,
adnl](td::Result<DhtNode> R) mutable {
if (R.is_error()) {
LOG(ERROR) << "[dht]: failed to get self node";
return;
@ -102,7 +102,12 @@ void DhtRemoteNode::send_ping(td::actor::ActorId<adnl::Adnl> adnl, td::actor::Ac
}
});
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;
if (client_only) {
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));
});

View file

@ -76,7 +76,8 @@ class DhtRemoteNode {
double last_ping_at() const {
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 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
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"
@ -44,9 +44,10 @@ namespace dht {
td::actor::ActorOwn<DhtMember> DhtMember::create(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) {
td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k, td::uint32 a,
bool client_only) {
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,
@ -66,9 +67,24 @@ td::Result<td::actor::ActorOwn<Dht>> Dht::create(adnl::AdnlNodeIdShort id, std::
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() {
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,
ton_api::dht_findNode::ID,
ton_api::dht_findValue::ID,
@ -82,6 +98,10 @@ void DhtMemberImpl::start_up() {
std::make_unique<Callback>(actor_id(this), id_));
}
alarm_timestamp() = td::Timestamp::in(1.0);
if (!db_root_.empty()) {
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());
for (td::uint32 bit = 0; bit < 256; bit++) {
auto key = create_hash_tl_object<ton_api::dht_db_key_bucket>(bit);
std::string value;
@ -103,6 +123,7 @@ void DhtMemberImpl::start_up() {
}
db_ = DbType{std::move(kv)};
}
}
void DhtMemberImpl::tear_down() {
std::vector<td::int32> methods = {ton_api::dht_getSignedAddressList::ID,
@ -119,6 +140,9 @@ void DhtMemberImpl::tear_down() {
}
void DhtMemberImpl::save_to_db() {
if (db_root_.empty()) {
return;
}
next_save_to_db_at_ = td::Timestamp::in(10.0);
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,
td::Promise<td::BufferSlice> promise) {
if (client_only_) {
return;
}
{
auto R = fetch_tl_prefix<ton_api::dht_query>(data, true);
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) {
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_,
id = id_](td::Result<DhtNode> R) mutable {
adnl = adnl_, list = get_nearest_nodes(key, k_), k = k_, a = a_, id = id_,
client_only = client_only_](td::Result<DhtNode> R) mutable {
R.ensure();
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();
});
@ -374,7 +401,7 @@ void DhtMemberImpl::check() {
<< " fvalue=" << find_value_queries_ << " store=" << store_queries_
<< " addrlist=" << get_addr_list_queries_;
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()) {
save_to_db();
@ -469,10 +496,10 @@ void DhtMemberImpl::check() {
DhtKeyId key{x};
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_,
a = a_, id = id_](td::Result<DhtNode> R) mutable {
a = a_, id = id_, client_only = client_only_](td::Result<DhtNode> R) mutable {
R.ensure();
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();
});
@ -492,12 +519,13 @@ void DhtMemberImpl::send_store(DhtValue value, td::Promise<td::Unit> promise) {
value.check().ensure();
auto key_id = value.key_id();
auto P = td::PromiseCreator::lambda([value = std::move(value), print_id = print_id(), id = id_,
auto P =
td::PromiseCreator::lambda([value = std::move(value), print_id = print_id(), id = id_, client_only = client_only_,
list = get_nearest_nodes(key_id, k_), k = k_, a = a_, SelfId = actor_id(this),
adnl = adnl_, promise = std::move(promise)](td::Result<DhtNode> R) mutable {
R.ensure();
td::actor::create_actor<DhtQueryStore>("StoreQuery", std::move(value), 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();
});
@ -505,14 +533,17 @@ void DhtMemberImpl::send_store(DhtValue value, td::Promise<td::Unit> 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_,
keyring = keyring_](td::Result<adnl::AdnlNode> R) mutable {
auto P =
td::PromiseCreator::lambda([promise = std::move(promise), print_id = print_id(), id = id_, keyring = keyring_,
client_only = client_only_](td::Result<adnl::AdnlNode> R) mutable {
R.ensure();
auto node = R.move_as_ok();
auto version = static_cast<td::int32>(td::Clocks::system());
auto B = create_serialize_tl_object<ton_api::dht_node>(node.pub_id().tl(), node.addr_list().tl(), version,
td::BufferSlice());
if (!client_only) {
CHECK(node.addr_list().size() > 0);
}
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), node = std::move(node), version](td::Result<td::BufferSlice> R) mutable {
R.ensure();

View file

@ -42,6 +42,10 @@ class Dht : public td::actor::Actor {
std::shared_ptr<DhtGlobalConfig> conf,
td::actor::ActorId<keyring::Keyring> keyring,
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(
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,
td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k = 10,
td::uint32 a = 3);
td::actor::ActorId<adnl::Adnl> adnl, td::uint32 k = 10, 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 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 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 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}
\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 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 F4BC}--{\tt F4BF} --- used by {\tt DICT\dots Z} primitives in \ptref{sp:prim.dict.get.spec}.
\end{itemize}
\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
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 "common/errorcode.h"
@ -28,8 +28,10 @@ namespace ton {
namespace keyring {
void KeyringImpl::start_up() {
if (db_root_.size() > 0) {
td::mkdir(db_root_).ensure();
}
}
td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash key_hash) {
auto it = map_.find(key_hash);
@ -37,6 +39,10 @@ td::Result<KeyringImpl::PrivateKeyDescr *> KeyringImpl::load_key(PublicKeyHash k
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 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());
return;
}
if (db_root_.size() == 0) {
CHECK(is_temp);
}
auto D = key.create_decryptor_async();
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) {
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();
td::BufferSlice d{256};
td::Random::secure_bytes(d.as_slice());

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "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 "
"(StateInit) or just the code or data of specified account; <addr> is in "
"[<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"
"allshards [<block-id-ext>]\tShows shard configuration from the most recent masterchain "
"state or from masterchain state corresponding to <block-id-ext>\n"
@ -871,11 +871,11 @@ bool TestNode::do_parse_line() {
(seekeoln()
? get_account_state(workchain, addr, mc_last_id_, 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;
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_run_method(workchain, addr, blkid, method);
parse_run_method(workchain, addr, blkid, method, word.size() > 9);
} else if (word == "allshards") {
return eoln() ? get_all_shards() : (parse_block_id_ext(blkid) && seekeoln() && get_all_shards(false, blkid));
} 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,
std::string method_name) {
std::string method_name, bool ext_mode) {
auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_));
if (R.is_error()) {
return set_error(R.move_as_error().to_string());
@ -1030,6 +1038,8 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
return set_error("server connection not ready");
}
auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
int mode = (ext_mode ? 0x1f : 0);
if (!mode) {
auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
true);
@ -1046,12 +1056,51 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
LOG(ERROR) << "cannot parse answer to liteServer.getAccountState";
} else {
auto f = F.move_as_ok();
td::actor::send_closure_later(Self, &TestNode::run_smc_method, ref_blkid, ton::create_block_id(f->id_),
td::actor::send_closure_later(Self, &TestNode::run_smc_method, 0, 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_), workchain, addr, method_name,
std::move(params));
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,
@ -1212,18 +1261,25 @@ 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,
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
std::vector<vm::StackEntry> params) {
LOG(INFO) << "got account state for " << workchain << ":" << addr.to_hex() << " with respect to blocks "
<< blk.to_str() << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str());
std::vector<vm::StackEntry> params, td::BufferSlice remote_c7,
td::BufferSlice remote_libs, td::BufferSlice remote_result, int remote_exit_code) {
LOG(INFO) << "got (partial) account state with mode=" << mode << " for " << workchain << ":" << addr.to_hex()
<< " with respect to blocks " << blk.to_str()
<< (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str());
auto out = td::TerminalIO::out();
try {
block::AccountState account_state;
account_state.blk = blk;
account_state.shard_blk = shard_blk;
account_state.shard_proof = std::move(shard_proof);
account_state.proof = std::move(proof);
LOG(DEBUG) << "serialized state is " << state.size() << " bytes";
LOG(DEBUG) << "serialized remote c7 is " << remote_c7.size() << " bytes";
account_state.state = std::move(state);
account_state.is_virtualized = (mode > 0);
auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr));
if (r_info.is_error()) {
LOG(ERROR) << r_info.error().message();
@ -1232,10 +1288,29 @@ void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton:
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
<< "`)";
LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `"
<< method << "`)";
return;
}
if (false) {
// DEBUG (dump state)
std::ostringstream os;
vm::CellSlice{vm::NoVm(), info.true_root}.print_rec(os);
out << "dump of account state (proof): " << os.str() << std::endl;
}
if (false && remote_c7.size()) {
// DEBUG (dump remote_c7)
auto r_c7 = vm::std_boc_deserialize(remote_c7).move_as_ok();
std::ostringstream os;
vm::StackEntry val;
bool ok = val.deserialize(r_c7);
val.dump(os);
// os << std::endl;
// block::gen::t_VmStackValue.print_ref(os, r_c7);
// os << std::endl;
// vm::CellSlice{vm::NoVmOrd(), r_c7}.print_rec(os);
out << "remote_c7 (deserialized=" << ok << "): " << os.str() << std::endl;
}
block::gen::Account::Record_account acc;
block::gen::AccountStorage::Record store;
block::CurrencyCollection balance;
@ -1247,7 +1322,8 @@ void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton:
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)";
LOG(ERROR) << "account " << workchain << ":" << addr.to_hex()
<< " not initialized yet (cannot run any methods)";
return;
case block::gen::AccountState::account_frozen:
LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)";
@ -1259,10 +1335,7 @@ void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton:
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;
if (!convert_int64(method, method_id)) {
method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000;
}
td::int64 method_id = compute_method_id(method);
stack.write().push_smallint(method_id);
{
std::ostringstream os;
@ -1276,12 +1349,16 @@ void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton:
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, acc.addr, balance)); // tuple with SmartContractInfo
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;
@ -1294,6 +1371,38 @@ void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton:
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();
}
}
void TestNode::got_one_transaction(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, td::BufferSlice proof,
@ -2062,7 +2171,7 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int
}
auto root = res.move_as_ok();
std::ostringstream outp;
vm::CellSlice cs{vm::NoVm{}, root};
vm::CellSlice cs{vm::NoVm(), root};
cs.print_rec(outp);
td::TerminalIO::out() << outp.str();
try {

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#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,
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,
std::string method_name);
void run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
std::string method_name, bool ext_mode);
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,
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 = {});
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 = "");
@ -181,6 +182,7 @@ class TestNode : public td::actor::Actor {
static bool convert_uint32(td::Slice word, td::uint32& val);
static bool convert_int32(td::Slice word, td::int32& val);
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_lt(ton::LogicalTime& lt);
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
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
@ -84,6 +84,12 @@ class BufferedFd : public BufferedFdBase<FdT> {
~BufferedFd();
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_write() TD_WARN_UNUSED_RESULT;

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "td/utils/FileLog.h"
@ -128,4 +128,10 @@ void FileLog::do_rotate() {
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

View file

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

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
@ -44,12 +44,12 @@ std::pair<T, T> split(T s, char delimiter = ' ') {
}
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;
if (s.empty()) {
return result;
}
while (true) {
while (result.size() + 1 < max_parts) {
auto delimiter_pos = s.find(delimiter);
if (delimiter_pos == string::npos) {
result.push_back(std::move(s));
@ -59,6 +59,8 @@ vector<T> full_split(T s, char delimiter = ' ') {
s = s.substr(delimiter_pos + 1);
}
}
result.push_back(std::move(s));
return result;
}
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
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"
@ -109,6 +109,7 @@ void Epoll::run(int timeout_ms) {
#ifdef EPOLLRDHUP
if (event->events & EPOLLRDHUP) {
event->events &= ~EPOLLRDHUP;
flags = flags | PollFlags::Close();
// flags |= Fd::Close;
// TODO
}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "td/utils/as.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));
}
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_full_split("", {});
test_full_split(" ", {"", ""});
@ -585,6 +589,7 @@ TEST(Misc, full_split) {
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 gh", ' ', 3, {"ab", "cd", "ef gh"});
}
TEST(Misc, StringBuilder) {

View file

@ -23,7 +23,7 @@ Test_Fift_testvm6_default dd6353c8f3f21cf62a4769ee1f3daaec46f43fd633ffb84c5d6535
Test_Fift_testvm7_default 77f54b6c8c9a728d262e912efcc347de7014a37d08793c3adeac8b96fe063342
Test_Fift_testvm8_default 17c9e2205ccecfd8549328b4a501d07dde0336899a7a496e747e1032ad5efff9
Test_Fift_testvm_default ee4cbfec76c050b6de7877cfc39817d594cd1e175b6265b76fb642e30b940437
Test_Fift_testvmprog_default 3aeebf868c0492f2bafe339505751449e9d258bf25ea5d956efe70c6fce408ed
Test_Fift_testvmprog_default a6d40d8a7bf0dd3b719c8b1023fef59e01ef094f732951cec4577556c6c68e64
Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb
Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d
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.sendMsgStatus status:int = liteServer.SendMsgStatus;
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.allShardsInfo id:tonNode.blockIdExt proof:bytes data:bytes = liteServer.AllShardsInfo;
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.sendMessage body:bytes = liteServer.SendMsgStatus;
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.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo;
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.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;
}
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};
if (!id.temp) {
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);
get_file_map(id).emplace(id, std::move(desc));

View file

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

View file

@ -46,8 +46,14 @@ td::uint64 Package::append(std::string filename, td::Slice data, bool sync) {
size += 8;
CHECK(fd_.pwrite(filename, size).move_as_ok() == filename.size());
size += filename.size();
CHECK(fd_.pwrite(data, size).move_as_ok() == data.size());
size += data.size();
while (data.size() != 0) {
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) {
fd_.sync().ensure();
}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "liteserver.hpp"
#include "td/utils/Slice.h"
@ -26,6 +26,7 @@
#include "adnl/utils.hpp"
#include "ton/lite-tl.hpp"
#include "tl-utils/lite-utils.hpp"
#include "td/utils/Random.h"
#include "vm/boc.h"
#include "tl/tlblib.hpp"
#include "block/block.h"
@ -33,6 +34,7 @@
#include "block/block-auto.h"
#include "vm/dict.h"
#include "vm/cells/MerkleProof.h"
#include "vm/continuation.h"
#include "shard.hpp"
#include "validator-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,
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() << ", "
<< method_id << ", " << mode << ") liteserver query with " << params.size() << " parameter bytes";
if (params.size() >= 65536) {
fatal_error("more than 64k parameter bytes passed");
return;
}
if (mode & ~0xf) {
if (mode & ~0x1f) {
fatal_error("unsupported mode in runSmcMethod");
return;
}
@ -984,7 +986,8 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
return;
}
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;
}
td::BufferSlice data;
@ -1003,12 +1006,113 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
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";
// ... TODO ...
fatal_error("runSmcMethod not implemented");
int mode = mode_ & 0xffff;
if (acc_root.is_null()) {
// 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() {
LOG(INFO) << "completing getOneTransaction() query";

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "ton/ton-types.h"
@ -61,12 +61,13 @@ class LiteQuery : public td::actor::Actor {
public:
enum {
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 {
ls_version = 0x101,
ls_capabilities = 3
}; // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt
ls_capabilities = 7
}; // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt, +4 = runSmcMethod
LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::BufferSlice> promise);
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();
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);
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 continue_getOneTransaction();
void perform_getTransactions(WorkchainId workchain, StdSmcAddress addr, LogicalTime lt, Bits256 hash, unsigned count);