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

updated tonlib, new fullnode queries

This commit is contained in:
ton 2019-09-24 01:10:57 +04:00
parent 87ccb27b70
commit a1e352d894
40 changed files with 1188 additions and 175 deletions

View file

@ -13,6 +13,7 @@ set(TONLIB_SOURCE
tonlib/GenericAccount.cpp
tonlib/KeyStorage.cpp
tonlib/LastBlock.cpp
tonlib/LastBlockStorage.cpp
tonlib/TestGiver.cpp
tonlib/TestWallet.cpp
tonlib/TonlibClient.cpp
@ -26,6 +27,7 @@ set(TONLIB_SOURCE
tonlib/GenericAccount.h
tonlib/KeyStorage.h
tonlib/LastBlock.h
tonlib/LastBlockStorage.h
tonlib/TestGiver.h
tonlib/TestWallet.h
tonlib/TonlibCallback.h

View file

@ -127,8 +127,8 @@ TEST(Tonlib, TestGiver) {
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
auto res = GenericAccount::create_ext_message(TestGiver::address(), {},
TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, address));
auto res = GenericAccount::create_ext_message(
TestGiver::address(), {}, TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, "GIFT", address));
vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr);
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash());
}

View file

@ -118,7 +118,7 @@ void transfer_grams(Client& client, std::string from, std::string to, td::int64
auto balance = get_balance(client, to);
sync_send(client, tonlib_api::make_object<tonlib_api::generic_sendGrams>(
std::move(input_key), tonlib_api::make_object<tonlib_api::accountAddress>(from),
tonlib_api::make_object<tonlib_api::accountAddress>(to), amount))
tonlib_api::make_object<tonlib_api::accountAddress>(to), amount, "GIFT"))
.ensure();
while (balance == get_balance(client, to)) {
client.receive(1);
@ -270,7 +270,7 @@ int main(int argc, char* argv[]) {
{
sync_send(client, make_object<tonlib_api::testGiver_sendGrams>(
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()), seqno,
1000000000ll * 6666 / 1000))
1000000000ll * 6666 / 1000, "GIFT"))
.ensure();
}
@ -307,9 +307,10 @@ int main(int argc, char* argv[]) {
}
{
sync_send(client, make_object<tonlib_api::generic_sendGrams>(
create_input_key(), make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()),
make_object<tonlib_api::accountAddress>(test_giver_address), 1000000000ll * 3333 / 1000))
sync_send(client,
make_object<tonlib_api::generic_sendGrams>(
create_input_key(), make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()),
make_object<tonlib_api::accountAddress>(test_giver_address), 1000000000ll * 3333 / 1000, "GIFT"))
.ensure();
}
while (true) {

View file

@ -21,10 +21,10 @@
#include "tonlib/LastBlock.h"
namespace tonlib {
void ExtClient::with_last_block(td::Promise<LastBlockInfo> promise) {
void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
auto query_id = last_block_queries_.create(std::move(promise));
td::Promise<LastBlockInfo> P = [query_id, self = this,
actor_id = td::actor::actor_id()](td::Result<LastBlockInfo> result) {
td::Promise<LastBlockState> P = [query_id, self = this,
actor_id = td::actor::actor_id()](td::Result<LastBlockState> result) {
send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable {
self->last_block_queries_.extract(query_id).set_result(std::move(result));
});

View file

@ -29,7 +29,7 @@
namespace tonlib {
class LastBlock;
struct LastBlockInfo;
struct LastBlockState;
struct ExtClientRef {
td::actor::ActorId<ton::adnl::AdnlExtClient> andl_ext_client_;
td::actor::ActorId<LastBlock> last_block_actor_;
@ -50,7 +50,7 @@ class ExtClient {
return client_;
}
void with_last_block(td::Promise<LastBlockInfo> promise);
void with_last_block(td::Promise<LastBlockState> promise);
template <class QueryT>
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
@ -75,7 +75,7 @@ class ExtClient {
private:
ExtClientRef client_;
td::Container<td::Promise<td::BufferSlice>> queries_;
td::Container<td::Promise<LastBlockInfo>> last_block_queries_;
td::Container<td::Promise<LastBlockState>> last_block_queries_;
void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
};

View file

@ -28,7 +28,7 @@ td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref
.finalize();
}
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) {
return block::StdAddress(workchain_id, init_state->get_hash().bits());
return block::StdAddress(workchain_id, init_state->get_hash().bits(), false);
}
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
td::Ref<vm::Cell> body) {

View file

@ -23,13 +23,23 @@
#include "lite-client/lite-client-common.h"
namespace tonlib {
LastBlock::LastBlock(ExtClientRef client, State state, td::unique_ptr<Callback> callback)
td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) {
return sb << td::tag("last_block", state.last_block_id.to_str())
<< td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime);
}
LastBlock::LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr<Callback> callback)
: state_(std::move(state)), callback_(std::move(callback)) {
client_.set_client(client);
}
void LastBlock::get_last_block(td::Promise<LastBlockInfo> promise) {
void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
if (promises_.empty()) {
total_sync_ = td::Timer();
validate_ = td::Timer(true);
queries_ = 0;
LOG(INFO) << "Begin last block synchronization " << state_;
do_get_last_block();
}
promises_.push_back(std::move(promise));
@ -41,6 +51,7 @@ void LastBlock::do_get_last_block() {
//return;
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
queries_++;
client_.send_query(
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr),
[this, from = state_.last_key_block_id](auto r_block_proof) {
@ -51,21 +62,30 @@ void LastBlock::do_get_last_block() {
td::Result<bool> LastBlock::process_block_proof(
ton::BlockIdExt from,
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
validate_.resume();
SCOPE_EXIT {
validate_.pause();
};
TRY_RESULT(block_proof, std::move(r_block_proof));
LOG(ERROR) << to_string(block_proof);
LOG(DEBUG) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_);
TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof)));
if (chain->from != from) {
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
<< ", not from requested block " << from.to_str());
}
TRY_STATUS(chain->validate());
update_mc_last_block(chain->to);
bool is_changed = false;
is_changed |= update_mc_last_block(chain->to);
if (chain->has_key_block) {
update_mc_last_key_block(chain->key_blkid);
is_changed |= update_mc_last_key_block(chain->key_blkid);
}
if (chain->has_utime) {
update_utime(chain->last_utime);
}
if (is_changed) {
callback_->on_state_changed(state_);
}
return chain->complete;
}
@ -73,17 +93,20 @@ void LastBlock::on_block_proof(
ton::BlockIdExt from,
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
auto r_is_ready = process_block_proof(from, std::move(r_block_proof));
bool is_ready;
if (r_is_ready.is_error()) {
LOG(WARNING) << "Failed liteServer_getBlockProof " << r_is_ready.error();
return;
LOG(WARNING) << "Error during last block synchronization " << r_is_ready.error();
is_ready = true;
} else {
is_ready = r_is_ready.move_as_ok();
}
auto is_ready = r_is_ready.move_as_ok();
if (is_ready) {
LOG(INFO) << "End last block synchronization " << state_ << "\n"
<< " net queries: " << queries_ << "\n"
<< " total: " << total_sync_ << " validation: " << validate_;
for (auto& promise : promises_) {
LastBlockInfo res;
res.id = state_.last_block_id;
res.utime = state_.utime;
promise.set_value(std::move(res));
auto state = state_;
promise.set_value(std::move(state));
}
promises_.clear();
} else {
@ -101,10 +124,8 @@ void LastBlock::on_masterchain_info(
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
}
for (auto& promise : promises_) {
LastBlockInfo res;
res.id = state_.last_block_id;
res.utime = state_.utime;
promise.set_value(std::move(res));
auto state = state_;
promise.set_value(std::move(state));
}
promises_.clear();
}
@ -131,25 +152,30 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
// One will have to restart ton client
}
void LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
if (!mc_block_id.is_valid()) {
LOG(ERROR) << "Ignore invalid masterchain block";
return;
return false;
}
if (!state_.last_block_id.is_valid() || state_.last_block_id.id.seqno < mc_block_id.id.seqno) {
state_.last_block_id = mc_block_id;
LOG(INFO) << "Update masterchain block id: " << state_.last_block_id.to_str();
return true;
}
return false;
}
void LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) {
bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) {
if (!mc_key_block_id.is_valid()) {
LOG(ERROR) << "Ignore invalid masterchain block";
return;
return false;
}
if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) {
state_.last_key_block_id = mc_key_block_id;
LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
return true;
}
return false;
}
void LastBlock::update_utime(td::int64 utime) {

View file

@ -22,35 +22,114 @@
#include "tonlib/ExtClient.h"
namespace tonlib {
struct LastBlockInfo {
ton::BlockIdExt id;
td::StringBuilder &operator<<(td::StringBuilder &sb, const LastBlockState &state);
template <unsigned int N, class StorerT>
void store(const td::BitArray<N> &arr, StorerT &storer) {
storer.store_binary(arr);
}
template <unsigned int N, class ParserT>
void parse(td::BitArray<N> &arr, ParserT &parser) {
arr = parser.template fetch_binary<td::BitArray<N>>();
}
template <class StorerT>
void store(const ton::ZeroStateIdExt &zero_state_id, StorerT &storer) {
using td::store;
using tonlib::store;
store(zero_state_id.workchain, storer);
store(zero_state_id.root_hash, storer);
store(zero_state_id.file_hash, storer);
}
template <class ParserT>
void parse(ton::ZeroStateIdExt &zero_state_id, ParserT &parser) {
using td::parse;
using tonlib::parse;
parse(zero_state_id.workchain, parser);
parse(zero_state_id.root_hash, parser);
parse(zero_state_id.file_hash, parser);
}
template <class StorerT>
void store(const ton::BlockId &block_id, StorerT &storer) {
using td::store;
using tonlib::store;
store(block_id.workchain, storer);
store(block_id.shard, storer);
store(block_id.seqno, storer);
}
template <class ParserT>
void parse(ton::BlockId &block_id, ParserT &parser) {
using td::parse;
using tonlib::parse;
parse(block_id.workchain, parser);
parse(block_id.shard, parser);
parse(block_id.seqno, parser);
}
template <class StorerT>
void store(const ton::BlockIdExt &block_id, StorerT &storer) {
using td::store;
using tonlib::store;
store(block_id.id, storer);
store(block_id.root_hash, storer);
store(block_id.file_hash, storer);
}
template <class ParserT>
void parse(ton::BlockIdExt &block_id, ParserT &parser) {
using td::parse;
using tonlib::parse;
parse(block_id.id, parser);
parse(block_id.root_hash, parser);
parse(block_id.file_hash, parser);
}
struct LastBlockState {
ton::ZeroStateIdExt zero_state_id;
ton::BlockIdExt last_key_block_id;
ton::BlockIdExt last_block_id;
td::int64 utime{0};
template <class StorerT>
void store(StorerT &storer) const {
using td::store;
using tonlib::store;
store(zero_state_id, storer);
store(last_key_block_id, storer);
store(last_block_id, storer);
store(utime, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
using td::parse;
using tonlib::parse;
parse(zero_state_id, parser);
parse(last_key_block_id, parser);
parse(last_block_id, parser);
parse(utime, parser);
}
};
class LastBlock : public td::actor::Actor {
public:
struct State {
ton::ZeroStateIdExt zero_state_id;
ton::BlockIdExt last_key_block_id;
ton::BlockIdExt last_block_id;
td::int64 utime{0};
};
class Callback {
public:
virtual ~Callback() {
}
virtual void on_state_changes(State state) = 0;
virtual void on_state_changed(LastBlockState state) = 0;
};
explicit LastBlock(ExtClientRef client, State state, td::unique_ptr<Callback> callback);
void get_last_block(td::Promise<LastBlockInfo> promise);
explicit LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr<Callback> callback);
void get_last_block(td::Promise<LastBlockState> promise);
private:
ExtClient client_;
State state_;
LastBlockState state_;
td::unique_ptr<Callback> callback_;
std::vector<td::Promise<LastBlockInfo>> promises_;
// stats
td::Timer total_sync_;
td::Timer validate_;
td::uint32 queries_;
std::vector<td::Promise<LastBlockState>> promises_;
void do_get_last_block();
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
@ -62,8 +141,8 @@ class LastBlock : public td::actor::Actor {
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
void update_mc_last_block(ton::BlockIdExt mc_block_id);
void update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
bool update_mc_last_block(ton::BlockIdExt mc_block_id);
bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
void update_utime(td::int64 utime);
};
} // namespace tonlib

View file

@ -0,0 +1,44 @@
#include "LastBlockStorage.h"
#include "td/utils/as.h"
#include "td/utils/filesystem.h"
#include "td/utils/port/path.h"
#include "td/utils/tl_helpers.h"
namespace tonlib {
td::Status LastBlockStorage::set_directory(std::string directory) {
TRY_RESULT(path, td::realpath(directory));
TRY_RESULT(stat, td::stat(path));
if (!stat.is_dir_) {
return td::Status::Error("not a directory");
}
directory_ = std::move(path);
return td::Status::OK();
}
std::string LastBlockStorage::get_file_name(td::Slice name) {
return directory_ + TD_DIR_SLASH + td::buffer_to_hex(name) + ".blkstate";
}
td::Result<LastBlockState> LastBlockStorage::get_state(td::Slice name) {
TRY_RESULT(data, td::read_file(get_file_name(name)));
if (data.size() < 8) {
return td::Status::Error("too short");
}
if (td::as<td::uint64>(data.data()) != td::crc64(td::Slice(data).substr(8))) {
return td::Status::Error("crc64 mismatch");
}
LastBlockState res;
TRY_STATUS(td::unserialize(res, td::Slice(data).substr(8)));
return res;
}
void LastBlockStorage::save_state(td::Slice name, LastBlockState state) {
auto x = td::serialize(state);
std::string y(x.size() + 8, 0);
td::MutableSlice(y).substr(8).copy_from(x);
td::as<td::uint64>(td::MutableSlice(y).data()) = td::crc64(x);
td::atomic_write_file(get_file_name(name), y);
}
} // namespace tonlib

View file

@ -0,0 +1,16 @@
#pragma once
#include "tonlib/LastBlock.h"
namespace tonlib {
class LastBlockStorage {
public:
td::Status set_directory(std::string directory);
td::Result<LastBlockState> get_state(td::Slice name);
void save_state(td::Slice name, LastBlockState state);
private:
std::string directory_;
std::string get_file_name(td::Slice name);
};
} // namespace tonlib

View file

@ -32,8 +32,9 @@ vm::CellHash TestGiver::get_init_code_hash() {
return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok());
}
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms,
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
const block::StdAddress& dest_address) {
CHECK(message.size() <= 128);
td::BigInt256 dest_addr;
dest_addr.import_bits(dest_address.addr.as_bitslice());
vm::CellBuilder cb;
@ -44,7 +45,7 @@ td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr
.store_int256(dest_addr, 256);
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("GIFT").finalize();
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize();
return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
}
} // namespace tonlib

View file

@ -23,7 +23,7 @@ class TestGiver {
public:
static const block::StdAddress& address();
static vm::CellHash get_init_code_hash();
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms,
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
const block::StdAddress& dest_address);
};
} // namespace tonlib

View file

@ -38,7 +38,9 @@ td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr
}
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
td::int64 gramms, const block::StdAddress& dest_address) {
td::int64 gramms, td::Slice message,
const block::StdAddress& dest_address) {
CHECK(message.size() <= 128);
td::BigInt256 dest_addr;
dest_addr.import_bits(dest_address.addr.as_bitslice());
vm::CellBuilder cb;
@ -46,11 +48,11 @@ td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey&
.store_long(dest_address.workchain, 8)
.store_int256(dest_addr, 256);
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("GIFT").finalize();
auto message = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize();
auto message_outer = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
std::string seq_no(4, 0);
auto signature = private_key.sign(message->get_hash().as_slice()).move_as_ok();
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message)).finalize();
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
}
td::Ref<vm::Cell> TestWallet::get_init_code() {

View file

@ -28,7 +28,8 @@ class TestWallet {
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key);
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key);
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
td::int64 gramms, const block::StdAddress& dest_address);
td::int64 gramms, td::Slice message,
const block::StdAddress& dest_address);
static td::Ref<vm::Cell> get_init_code();
static vm::CellHash get_init_code_hash();

View file

@ -41,8 +41,6 @@
#include "td/utils/tests.h"
#include "td/utils/port/path.h"
namespace ton {} // namespace ton
namespace tonlib {
template <class F>
@ -152,6 +150,11 @@ class GetTransactionHistory : public td::actor::Actor {
}
void start_up() override {
if (lt_ == 0) {
promise_.set_value(block::TransactionList::Info());
stop();
return;
}
client_.send_query(
ton::lite_api::liteServer_getTransactions(
count_, ton::create_tl_object<ton::lite_api::liteServer_accountId>(address_.workchain, address_.addr), lt_,
@ -171,7 +174,7 @@ class GetRawAccountState : public td::actor::Actor {
block::StdAddress address_;
td::Promise<RawAccountState> promise_;
ExtClient client_;
LastBlockInfo last_block_;
LastBlockState last_block_;
void with_account_state(td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
promise_.set_result(TRY_VM(do_with_account_state(std::move(r_account_state))));
@ -182,7 +185,7 @@ class GetRawAccountState : public td::actor::Actor {
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
TRY_RESULT(raw_account_state, std::move(r_account_state));
auto account_state = create_account_state(std::move(raw_account_state));
TRY_RESULT(info, account_state.validate(last_block_.id, address_));
TRY_RESULT(info, account_state.validate(last_block_.last_block_id, address_));
auto serialized_state = account_state.state.clone();
RawAccountState res;
res.info = std::move(info);
@ -225,14 +228,14 @@ class GetRawAccountState : public td::actor::Actor {
}
void start_up() override {
client_.with_last_block([self = this](td::Result<LastBlockInfo> r_last_block) {
client_.with_last_block([self = this](td::Result<LastBlockState> r_last_block) {
if (r_last_block.is_error()) {
return self->check(r_last_block.move_as_error());
}
self->last_block_ = r_last_block.move_as_ok();
self->client_.send_query(
ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.id),
ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.last_block_id),
ton::create_tl_object<ton::lite_api::liteServer_accountId>(
self->address_.workchain, self->address_.addr)),
[self](auto r_state) { self->with_account_state(std::move(r_state)); });
@ -307,24 +310,36 @@ void TonlibClient::init_ext_client() {
td::make_unique<Callback>(td::actor::actor_shared()));
}
}
void TonlibClient::update_last_block_state(LastBlockState state) {
last_block_storage_.save_state("none", state);
}
void TonlibClient::init_last_block() {
ref_cnt_++;
class Callback : public LastBlock::Callback {
public:
Callback(td::actor::ActorShared<TonlibClient> client) : client_(std::move(client)) {
}
void on_state_changes(LastBlock::State state) override {
//TODO
void on_state_changed(LastBlockState state) override {
send_closure(client_, &TonlibClient::update_last_block_state, std::move(state));
}
private:
td::actor::ActorShared<TonlibClient> client_;
};
LastBlock::State state;
//state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
//config_.zero_state_id.file_hash),
state.last_block_id = config_.zero_state_id;
state.last_key_block_id = config_.zero_state_id;
LastBlockState state;
auto r_state = last_block_storage_.get_state("none");
if (r_state.is_error()) {
LOG(WARNING) << "Unknown LastBlockState: " << r_state.error();
state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
config_.zero_state_id.file_hash),
state.last_block_id = config_.zero_state_id;
state.last_key_block_id = config_.zero_state_id;
} else {
state = r_state.move_as_ok();
}
raw_last_block_ = td::actor::create_actor<LastBlock>("LastBlock", get_client_ref(), std::move(state),
td::make_unique<Callback>(td::actor::actor_shared(this)));
@ -469,6 +484,7 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request,
return td::Status::Error(400, "Field options must not be empty");
}
TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_));
TRY_STATUS(last_block_storage_.set_directory(request.options_->keystore_directory_));
use_callbacks_for_network_ = request.options_->use_callbacks_for_network_;
if (!request.options_->config_.empty()) {
TRY_STATUS(set_config(std::move(request.options_->config_)));
@ -570,10 +586,25 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
if (!tlb::csr_unpack(message.info, msg_info)) {
return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info");
}
TRY_RESULT(balance, to_balance(msg_info.value));
TRY_RESULT(src, to_std_address(msg_info.src));
TRY_RESULT(dest, to_std_address(msg_info.dest));
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance);
td::Ref<vm::CellSlice> body;
if (message.body->prefetch_long(1) == 0) {
body = std::move(message.body);
body.write().advance(1);
} else {
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
}
std::string body_message;
if (body->size() % 8 == 0) {
body_message = std::string(body->size() / 8, 0);
body->prefetch_bytes(td::MutableSlice(body_message).ubegin(), body->size() / 8);
}
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance,
std::move(body_message));
}
case block::gen::CommonMsgInfo::ext_in_msg_info: {
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
@ -581,7 +612,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
}
TRY_RESULT(dest, to_std_address(msg_info.dest));
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0);
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0, "");
}
case block::gen::CommonMsgInfo::ext_out_msg_info: {
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
@ -589,7 +620,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
}
TRY_RESULT(src, to_std_address(msg_info.src));
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0);
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, "");
}
}
@ -626,7 +657,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transaction>> to_raw_transacti
if (is_just == trans.r1.in_msg->fetch_long_eof) {
return td::Status::Error("Failed to parse long");
}
if (is_just == 1) {
if (is_just == -1) {
auto msg = trans.r1.in_msg->prefetch_ref();
TRY_RESULT(in_msg_copy, to_raw_message(trans.r1.in_msg->prefetch_ref()));
in_msg = std::move(in_msg_copy);
@ -702,7 +733,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> to_generic_
RawAccountState&& raw_state) {
if (raw_state.code.is_null()) {
return tonlib_api::make_object<tonlib_api::generic_accountStateUninited>(
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance, empty_transaction_id(),
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance, to_transaction_id(raw_state.info),
raw_state.sync_utime));
}
@ -827,21 +858,24 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ
if (!request.private_key_) {
return td::Status::Error(400, "Field private_key must not be empty");
}
if (request.message_.size() > 128) {
return td::Status::Error(400, "Message is too long");
}
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
account_address.bounceable = false;
TRY_RESULT(input_key, from_tonlib(*request.private_key_));
auto address = GenericAccount::get_address(
0 /*zerochain*/, TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy())));
TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key)));
return do_request(
tonlib_api::raw_sendMessage(tonlib_api::make_object<tonlib_api::accountAddress>(address.rserialize()), "",
vm::std_boc_serialize(TestWallet::make_a_gift_message(
td::Ed25519::PrivateKey(std::move(private_key.private_key)),
request.seqno_, request.amount_, account_address))
.move_as_ok()
.as_slice()
.str()),
std::move(promise));
return do_request(tonlib_api::raw_sendMessage(
tonlib_api::make_object<tonlib_api::accountAddress>(address.rserialize()), "",
vm::std_boc_serialize(TestWallet::make_a_gift_message(
td::Ed25519::PrivateKey(std::move(private_key.private_key)),
request.seqno_, request.amount_, request.message_, account_address))
.move_as_ok()
.as_slice()
.str()),
std::move(promise));
}
td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request,
@ -868,16 +902,19 @@ td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& reque
if (!request.destination_) {
return td::Status::Error(400, "Field destination must not be empty");
}
if (request.message_.size() > 128) {
return td::Status::Error(400, "Message is too long");
}
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
account_address.bounceable = false;
return do_request(
tonlib_api::raw_sendMessage(
tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize()), "",
vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, account_address))
.move_as_ok()
.as_slice()
.str()),
std::move(promise));
return do_request(tonlib_api::raw_sendMessage(
tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize()), "",
vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_,
request.message_, account_address))
.move_as_ok()
.as_slice()
.str()),
std::move(promise));
}
td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request,
@ -920,7 +957,7 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request,
"GetAccountState", client_.get_client(), std::move(account_address),
[promise = std::move(promise), self = this, actor_id = td::actor::actor_id(),
private_key = std::move(request.private_key_), destination = std::move(request.destination_),
amount = request.amount_](td::Result<RawAccountState> r_state) mutable {
amount = request.amount_, message = std::move(request.message_)](td::Result<RawAccountState> r_state) mutable {
if (r_state.is_error()) {
return promise.set_error(r_state.move_as_error());
}
@ -930,40 +967,41 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request,
}
auto state = rr_state.move_as_ok();
downcast_call(*state,
td::overloaded(
[&](tonlib_api::generic_accountStateTestGiver& test_giver_state) {
send_lambda(actor_id, [promise = std::move(promise), self,
query = tonlib_api::testGiver_sendGrams(
std::move(destination), test_giver_state.account_state_->seqno_,
amount)]() mutable {
LOG(INFO) << "Send " << to_string(query);
auto status = self->do_request(query, std::move(promise));
if (status.is_error()) {
CHECK(promise);
promise.set_error(std::move(status));
}
});
return;
},
[&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) {
send_lambda(actor_id, [promise = std::move(promise), self,
query = tonlib_api::testWallet_sendGrams(
std::move(private_key), std::move(destination),
test_wallet_state.account_state_->seqno_, amount)]() mutable {
auto status = self->do_request(query, std::move(promise));
if (status.is_error()) {
CHECK(promise);
promise.set_error(std::move(status));
}
});
},
[&](tonlib_api::generic_accountStateUninited&) {
promise.set_error(td::Status::Error(400, "Account is not inited"));
},
[&](tonlib_api::generic_accountStateRaw&) {
promise.set_error(td::Status::Error(400, "Unknown account type"));
}));
downcast_call(*state, td::overloaded(
[&](tonlib_api::generic_accountStateTestGiver& test_giver_state) {
send_lambda(actor_id,
[promise = std::move(promise), self,
query = tonlib_api::testGiver_sendGrams(
std::move(destination), test_giver_state.account_state_->seqno_,
amount, std::move(message))]() mutable {
LOG(INFO) << "Send " << to_string(query);
auto status = self->do_request(query, std::move(promise));
if (status.is_error()) {
CHECK(promise);
promise.set_error(std::move(status));
}
});
return;
},
[&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) {
send_lambda(actor_id, [promise = std::move(promise), self,
query = tonlib_api::testWallet_sendGrams(
std::move(private_key), std::move(destination),
test_wallet_state.account_state_->seqno_, amount,
std::move(message))]() mutable {
auto status = self->do_request(query, std::move(promise));
if (status.is_error()) {
CHECK(promise);
promise.set_error(std::move(status));
}
});
},
[&](tonlib_api::generic_accountStateUninited&) {
promise.set_error(td::Status::Error(400, "Account is not inited"));
},
[&](tonlib_api::generic_accountStateRaw&) {
promise.set_error(td::Status::Error(400, "Unknown account type"));
}));
})
.release();
return td::Status::OK();

View file

@ -24,6 +24,7 @@
#include "tonlib/ExtClient.h"
#include "tonlib/ExtClientOutbound.h"
#include "tonlib/KeyStorage.h"
#include "tonlib/LastBlockStorage.h"
#include "td/actor/actor.h"
@ -50,6 +51,7 @@ class TonlibClient : public td::actor::Actor {
// KeyStorage
KeyStorage key_storage_;
LastBlockStorage last_block_storage_;
// network
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
@ -73,6 +75,7 @@ class TonlibClient : public td::actor::Actor {
}
}
void update_last_block_state(LastBlockState state);
void on_result(td::uint64 id, object_ptr<tonlib_api::Object> response);
static bool is_static_request(td::int32 id);
static bool is_uninited_request(td::int32 id);

View file

@ -6,6 +6,7 @@
#include "td/utils/port/signals.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "td/utils/as.h"
#include "terminal/terminal.h"
@ -327,6 +328,8 @@ class TonlibCli : public td::actor::Actor {
<< "\n";
for (size_t i = 0; i < keys_.size(); i++) {
td::TerminalIO::out() << " #" << i << ": " << keys_[i].public_key << "\n";
td::TerminalIO::out() << " " << to_account_address(PSLICE() << i, false).move_as_ok().address->account_address_
<< "\n";
}
}
@ -598,13 +601,21 @@ class TonlibCli : public td::actor::Actor {
}
void transfer(Address from, Address to, td::uint64 grams, td::Slice password) {
td::TerminalIO::out() << "Enter message (could be empty)";
cont_ = [this, from = std::move(from), to = std::move(to), grams,
password = password.str()](td::Slice message) mutable {
this->transfer(std::move(from), std::move(to), grams, password, message);
};
return;
}
void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message) {
using tonlib_api::make_object;
auto key = !from.secret.empty()
? make_object<tonlib_api::inputKey>(
make_object<tonlib_api::key>(from.public_key, from.secret.copy()), td::SecureString(password))
: nullptr;
send_query(make_object<tonlib_api::generic_sendGrams>(std::move(key), std::move(from.address),
std::move(to.address), grams),
std::move(to.address), grams, message.str()),
[](auto r_res) {
if (r_res.is_error()) {
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";