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

updated submodules, bugfixes

- added new fift/func code for validator complaint creation
- bugfixes in validator
- updates in tonlib
- new versions of rocksdb/abseil
- hardfork support
This commit is contained in:
ton 2020-04-27 16:01:46 +04:00
parent 16a4566091
commit 9f008b129f
129 changed files with 8438 additions and 879 deletions

View file

@ -121,11 +121,12 @@ struct TransactionId {
};
struct AccountState {
enum Type { Empty, Wallet, Dns, Unknown } type{Empty};
enum Type { Empty, Wallet, Dns, Pchan, Unknown } type{Empty};
td::int64 sync_utime{-1};
td::int64 balance{-1};
TransactionId last_transaction_id;
std::string address;
tonlib_api::object_ptr<tonlib_api::fullAccountState> state;
bool is_inited() const {
return type != Empty;
@ -187,6 +188,10 @@ AccountState get_account_state(Client& client, std::string address) {
case tonlib_api::dns_accountState::ID:
res.type = AccountState::Dns;
break;
case tonlib_api::pchan_accountState::ID:
res.type = AccountState::Pchan;
res.state = std::move(state);
break;
default:
res.type = AccountState::Unknown;
break;
@ -228,15 +233,38 @@ struct QueryInfo {
std::string body_hash;
};
struct Message {
bool encrypted = false;
td::optional<std::string> text;
td::optional<td::string> raw;
td::optional<td::string> init_state;
static Message create_text(std::string text, bool encrypted) {
Message res;
res.text = text;
res.encrypted = encrypted;
return res;
}
static Message create_raw(std::string raw, std::string init_state) {
Message res;
res.raw = raw;
res.init_state = init_state;
return res;
}
};
td::Result<QueryId> create_send_grams_query(Client& client, const Wallet& source, std::string destination,
td::int64 amount, bool encrypted, std::string message, bool force = false,
int timeout = 0, bool fake = false) {
td::int64 amount, Message message, bool force = false, int timeout = 0,
bool fake = false) {
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message>> msgs;
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
if (encrypted) {
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(std::move(message));
if (message.text) {
if (message.encrypted) {
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(message.text.unwrap());
} else {
data = tonlib_api::make_object<tonlib_api::msg_dataText>(message.text.unwrap());
}
} else {
data = tonlib_api::make_object<tonlib_api::msg_dataText>(std::move(message));
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(message.raw.unwrap(), message.init_state.unwrap());
}
msgs.push_back(tonlib_api::make_object<tonlib_api::msg_message>(
tonlib_api::make_object<tonlib_api::accountAddress>(destination), "", amount, std::move(data)));
@ -244,7 +272,7 @@ td::Result<QueryId> create_send_grams_query(Client& client, const Wallet& source
auto r_id =
sync_send(client, tonlib_api::make_object<tonlib_api::createQuery>(
fake ? source.key.get_fake_input_key() : source.key.get_input_key(), source.get_address(),
timeout, tonlib_api::make_object<tonlib_api::actionMsg>(std::move(msgs), force)));
timeout, tonlib_api::make_object<tonlib_api::actionMsg>(std::move(msgs), force), nullptr));
TRY_RESULT(id, std::move(r_id));
return QueryId{id->id_};
}
@ -253,7 +281,7 @@ td::Result<QueryId> create_update_dns_query(Client& client, const Wallet& dns,
std::vector<tonlib_api::object_ptr<tonlib_api::dns_Action>> entries) {
using namespace ton::tonlib_api;
auto r_id = sync_send(client, make_object<createQuery>(dns.key.get_input_key(), dns.get_address(), 60,
make_object<actionDns>(std::move(entries))));
make_object<actionDns>(std::move(entries)), nullptr));
TRY_RESULT(id, std::move(r_id));
return QueryId{id->id_};
}
@ -289,7 +317,7 @@ td::Result<AccountState> wait_state_change(Client& client, const AccountState& o
while (true) {
auto new_state = get_account_state(client, old_state.address);
if (new_state.last_transaction_id.lt != old_state.last_transaction_id.lt) {
return new_state;
return std::move(new_state);
}
if (valid_until != 0 && new_state.sync_utime >= valid_until) {
return td::Status::Error("valid_until expired");
@ -325,18 +353,19 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
LOG(INFO) << "Transfer: create query " << (double)amount / Gramm << " from " << wallet.address << " to " << address;
bool encrypt = true;
auto r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
auto r_query_id =
create_send_grams_query(client, wallet, address, amount, Message::create_text(message, encrypt), fast);
if (r_query_id.is_error()) {
LOG(INFO) << "Send query WITHOUT message encryption " << r_query_id.error();
encrypt = false;
r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
r_query_id = create_send_grams_query(client, wallet, address, amount, Message::create_text(message, encrypt), fast);
} else {
LOG(INFO) << "Send query WITH message encryption";
}
if (r_query_id.is_error() && td::begins_with(r_query_id.error().message(), "DANGEROUS_TRANSACTION")) {
ASSERT_TRUE(dst_state.type == AccountState::Empty);
LOG(INFO) << "Transfer: recreate query due to DANGEROUS_TRANSACTION error";
r_query_id = create_send_grams_query(client, wallet, address, amount, false, message, true);
r_query_id = create_send_grams_query(client, wallet, address, amount, Message::create_text(message, encrypt), true);
}
r_query_id.ensure();
@ -458,8 +487,9 @@ Wallet create_empty_dns(Client& client) {
void test_estimate_fees_without_key(Client& client, const Wallet& wallet_a, const Wallet& wallet_b) {
LOG(ERROR) << " SUBTEST: estimate fees without key";
{
auto query_id =
create_send_grams_query(client, wallet_a, wallet_b.address, 0, false, "???", true, 0, true).move_as_ok();
auto query_id = create_send_grams_query(client, wallet_a, wallet_b.address, 0, Message::create_text("???", false),
true, 0, true)
.move_as_ok();
auto fees1 = query_estimate_fees(client, query_id, false);
auto fees2 = query_estimate_fees(client, query_id, true);
LOG(INFO) << "Fee without ignore_chksig\t" << fees1;
@ -564,6 +594,141 @@ void dns_resolve(Client& client, const Wallet& dns, std::string name) {
LOG(INFO) << "OK";
}
void test_paychan(Client& client, const Wallet& giver_wallet) {
LOG(INFO) << "Start test paychan";
auto alice = create_empty_wallet(client);
auto bob = create_empty_wallet(client);
using namespace ton::tonlib_api;
int init_timeout = 10;
int close_timeout = 10;
int64 channel_id = static_cast<td::int64>(td::Random::fast_uint64());
auto get_initial_state = [&] {
return make_object<pchan_initialAccountState>(make_object<pchan_config>(alice.key.public_key, alice.get_address(),
bob.key.public_key, bob.get_address(),
init_timeout, close_timeout, channel_id));
};
auto account_address = sync_send(client, make_object<tonlib_api::getAccountAddress>(get_initial_state(), -1))
.move_as_ok()
->account_address_;
auto get_account_address = [&] { return make_object<accountAddress>(account_address); };
//pchan.actionInit inc_A:int64 inc_B:int64 min_A:int64 min_B:int64 = pchan.Action;
//pchan.actionClose extra_A:int64 extra_B:int64 promise:pchan.promise = pchan.Action;
//pchan.actionTimeout = pchan.Action;
auto create_init_query = [&](auto& wallet, td::int64 inc_A, td::int64 inc_B) {
auto action = make_object<tonlib_api::actionPchan>(make_object<tonlib_api::pchan_actionInit>(inc_A, inc_B, 0, 0));
auto r_id = sync_send(client, make_object<createQuery>(wallet.key.get_input_key(), get_account_address(), 60,
std::move(action), get_initial_state()));
r_id.ensure();
return r_id.move_as_ok();
};
auto send_query_via = [&](auto& wallet, auto query_info, auto destination, td::int64 value) {
auto transfer_id =
create_send_grams_query(client, wallet, std::move(destination), value,
Message::create_raw(query_info->body_, query_info->init_state_), true, 60)
.move_as_ok();
::query_send(client, transfer_id);
};
send_query_via(giver_wallet, create_init_query(alice, 1 * Gramm, 0), account_address, 11 * Gramm / 10);
send_query_via(giver_wallet, create_init_query(bob, 0, 1 * Gramm), account_address, 11 * Gramm / 10);
LOG(INFO) << "Wait till pchan " << account_address << " is inited ";
td::optional<td::int64> now;
while (true) {
client.receive(1);
auto state = get_account_state(client, account_address);
if (!now) {
now = state.sync_utime;
}
CHECK(now.value() + 60 > state.sync_utime);
if (state.type != ::AccountState::Pchan) {
continue;
}
auto pchan_state = tonlib_api::move_object_as<tonlib_api::pchan_accountState>(state.state->account_state_);
if (pchan_state->state_->get_id() != tonlib_api::pchan_stateClose::ID) {
continue;
}
LOG(INFO) << "Account type: " << state.type << " " << state.sync_utime << "\n" << to_string(pchan_state->state_);
break;
}
auto create_close_query = [&](auto& x_wallet, auto& y_wallet, td::int64 A, td::int64 B) {
auto p = sync_send(client, make_object<pchan_signPromise>(y_wallet.key.get_input_key(),
make_object<pchan_promise>("", A, B, channel_id)))
.move_as_ok();
auto action = make_object<tonlib_api::actionPchan>(make_object<tonlib_api::pchan_actionClose>(0, 0, std::move(p)));
auto r_id = sync_send(client, make_object<createQuery>(x_wallet.key.get_input_key(), get_account_address(), 60,
std::move(action), get_initial_state()));
r_id.ensure();
return r_id.move_as_ok();
};
//auto send_query_ext = [&](auto query_info) { ::query_send(client, QueryId{query_info->id_}); };
send_query_via(giver_wallet, create_close_query(alice, bob, 0, 10 * Gramm), account_address, Gramm / 10);
send_query_via(giver_wallet, create_close_query(bob, alice, 11 * Gramm, 0), account_address, Gramm / 10);
LOG(INFO) << "Wait till pchan " << account_address << " is closed ";
now = {};
int64 payout_A = 0;
int64 payout_B = 0;
while (true) {
client.receive(1);
auto state = get_account_state(client, account_address);
if (!now) {
now = state.sync_utime;
}
CHECK(now.value() + 60 > state.sync_utime);
if (state.type != ::AccountState::Pchan) {
continue;
}
auto pchan_state = tonlib_api::move_object_as<tonlib_api::pchan_accountState>(state.state->account_state_);
if (pchan_state->state_->get_id() != tonlib_api::pchan_statePayout::ID) {
continue;
}
LOG(INFO) << "Account type: " << state.type << " " << state.sync_utime << "\n" << to_string(pchan_state->state_);
auto payout = tonlib_api::move_object_as<tonlib_api::pchan_statePayout>(pchan_state->state_);
payout_A = payout->A_;
payout_B = payout->B_;
break;
}
LOG(INFO) << "Wait till Alice has its share";
now = {};
while (payout_A != 0) {
auto state = get_account_state(client, alice.address);
if (!now) {
now = state.sync_utime;
}
CHECK(now.value() + 60 > state.sync_utime);
if (state.balance > 0) {
ASSERT_EQ(payout_A, state.balance);
LOG(INFO) << "Alice got: " << state.balance;
break;
}
client.receive(1);
}
LOG(INFO) << "Wait till Bob has its share";
now = {};
while (payout_B != 0) {
auto state = get_account_state(client, bob.address);
if (!now) {
now = state.sync_utime;
}
CHECK(now.value() + 60 > state.sync_utime);
if (state.balance > 0) {
ASSERT_EQ(payout_B, state.balance);
LOG(INFO) << "Bob got: " << state.balance;
break;
}
client.receive(1);
}
}
void test_dns(Client& client, const Wallet& giver_wallet) {
auto A = create_empty_dns(client);
auto A_B = create_empty_dns(client);
@ -669,6 +834,7 @@ int main(int argc, char* argv[]) {
// give wallet with some test grams to run test
auto giver_wallet = import_wallet_from_pkey(client, giver_key_str, giver_key_pwd);
test_paychan(client, giver_wallet);
test_dns(client, giver_wallet);
test_back_and_forth_transfer(client, giver_wallet, false);
test_back_and_forth_transfer(client, giver_wallet, true);

View file

@ -101,6 +101,7 @@ class Client::Impl final {
scheduler_.run_in_context_external([] { td::actor::SchedulerContext::get()->stop(); });
LOG(ERROR) << "join";
scheduler_thread_.join();
LOG(ERROR) << "join - done";
}
private:

View file

@ -121,6 +121,26 @@ td::Result<Config> Config::parse(std::string str) {
res.init_block_id = init_block_id;
}
auto r_hardforks = td::get_json_object_field(validator, "hardforks", td::JsonValue::Type::Array, false);
if (r_hardforks.is_ok()) {
auto hardforks_obj = r_hardforks.move_as_ok();
auto &hardforks = hardforks_obj.get_array();
for (auto &fork : hardforks) {
if (fork.type() != td::JsonValue::Type::Object) {
return td::Status::Error("Invalid config (8)");
}
TRY_RESULT(fork_block, parse_block_id_ext(fork.get_object()));
res.hardforks.push_back(std::move(fork_block));
}
}
for (auto hardfork : res.hardforks) {
if (!res.init_block_id.is_valid() || hardfork.seqno() > res.init_block_id.seqno()) {
LOG(INFO) << "Replace init_block with hardfork: " << res.init_block_id.to_str() << " -> " << hardfork.to_str();
res.init_block_id = hardfork;
}
}
return res;
}
} // namespace tonlib

View file

@ -29,7 +29,9 @@ struct Config {
};
ton::BlockIdExt zero_state_id;
ton::BlockIdExt init_block_id;
std::vector<ton::BlockIdExt> hardforks;
std::vector<LiteClient> lite_clients;
std::string name;
static td::Result<Config> parse(std::string str);
};
} // namespace tonlib

View file

@ -93,9 +93,10 @@ struct LastBlockState {
ton::BlockIdExt last_block_id;
td::int64 utime{0};
ton::BlockIdExt init_block_id;
td::int32 vert_seqno{0};
static constexpr td::int32 magic = 0xa7f171a4;
enum Version { None = 0, Magic, InitBlock, Next };
enum Version { None = 0, Magic, InitBlock, VertSeqno, Next };
static constexpr td::int32 version = Version::Next - 1;
template <class StorerT>
@ -110,6 +111,7 @@ struct LastBlockState {
store(last_block_id, storer);
store(utime, storer);
store(init_block_id, storer);
store(vert_seqno, storer);
}
template <class ParserT>
@ -130,6 +132,9 @@ struct LastBlockState {
if (version >= InitBlock) {
parse(init_block_id, parser);
}
if (version >= VertSeqno) {
parse(vert_seqno, parser);
}
}
};

View file

@ -36,6 +36,7 @@
#include "smc-envelope/HighloadWallet.h"
#include "smc-envelope/HighloadWalletV2.h"
#include "smc-envelope/TestGiver.h"
#include "smc-envelope/PaymentChannel.h"
#include "smc-envelope/SmartContractCode.h"
#include "auto/tl/tonlib_api.hpp"
@ -106,7 +107,8 @@ auto to_tonlib_api(const ton::BlockIdExt& blk) {
}
tonlib_api::object_ptr<tonlib_api::options_configInfo> to_tonlib_api(const TonlibClient::FullConfig& full_config) {
return tonlib_api::make_object<tonlib_api::options_configInfo>(full_config.wallet_id);
return tonlib_api::make_object<tonlib_api::options_configInfo>(full_config.wallet_id,
full_config.rwallet_init_public_key);
}
class TonlibQueryActor : public td::actor::Actor {
@ -172,9 +174,69 @@ tonlib_api::object_ptr<tonlib_api::internal_transactionId> to_transaction_id(con
}
std::string to_bytes(td::Ref<vm::Cell> cell) {
if (cell.is_null()) {
return "";
}
return vm::std_boc_serialize(cell, vm::BagOfCells::Mode::WithCRC32C).move_as_ok().as_slice().str();
}
td::Result<block::PublicKey> get_public_key(td::Slice public_key) {
TRY_RESULT_PREFIX(address, block::PublicKey::parse(public_key), TonlibError::InvalidPublicKey());
return address;
}
td::Result<block::StdAddress> get_account_address(td::Slice account_address) {
TRY_RESULT_PREFIX(address, block::StdAddress::parse(account_address), TonlibError::InvalidAccountAddress());
return address;
}
td::Result<block::PublicKey> public_key_from_bytes(td::Slice bytes) {
TRY_RESULT_PREFIX(key_bytes, block::PublicKey::from_bytes(bytes), TonlibError::Internal());
return key_bytes;
}
td::Result<ton::RestrictedWallet::InitData> to_init_data(const tonlib_api::rwallet_initialAccountState& rwallet_state) {
TRY_RESULT(init_key_bytes, get_public_key(rwallet_state.init_public_key_));
TRY_RESULT(key_bytes, get_public_key(rwallet_state.public_key_));
ton::RestrictedWallet::InitData init_data;
init_data.init_key = td::SecureString(init_key_bytes.key);
init_data.main_key = td::SecureString(key_bytes.key);
init_data.wallet_id = static_cast<td::uint32>(rwallet_state.wallet_id_);
return std::move(init_data);
}
td::Result<ton::pchan::Config> to_pchan_config(const tonlib_api::pchan_initialAccountState& pchan_state) {
ton::pchan::Config config;
if (!pchan_state.config_) {
return TonlibError::EmptyField("config");
}
TRY_RESULT_PREFIX(a_key, get_public_key(pchan_state.config_->alice_public_key_),
TonlibError::InvalidField("alice_public_key", ""));
config.a_key = td::SecureString(a_key.key);
TRY_RESULT_PREFIX(b_key, get_public_key(pchan_state.config_->bob_public_key_),
TonlibError::InvalidField("bob_public_key", ""));
config.b_key = td::SecureString(b_key.key);
if (!pchan_state.config_->alice_address_) {
return TonlibError::EmptyField("config.alice_address");
}
TRY_RESULT_PREFIX(a_addr, get_account_address(pchan_state.config_->alice_address_->account_address_),
TonlibError::InvalidField("alice_address", ""));
config.a_addr = std::move(a_addr);
if (!pchan_state.config_->bob_address_) {
return TonlibError::EmptyField("config.bob_address");
}
TRY_RESULT_PREFIX(b_addr, get_account_address(pchan_state.config_->bob_address_->account_address_),
TonlibError::InvalidField("bob_address", ""));
config.b_addr = std::move(b_addr);
config.channel_id = pchan_state.config_->channel_id_;
config.init_timeout = pchan_state.config_->init_timeout_;
config.close_timeout = pchan_state.config_->close_timeout_;
return std::move(config);
}
class AccountState {
public:
AccountState(block::StdAddress address, RawAccountState&& raw, td::uint32 wallet_id)
@ -259,6 +321,55 @@ class AccountState {
TRY_RESULT(wallet_id, wallet.get_wallet_id());
return tonlib_api::make_object<tonlib_api::wallet_highload_v2_accountState>(static_cast<td::uint32>(wallet_id));
}
td::Result<tonlib_api::object_ptr<tonlib_api::rwallet_accountState>> to_rwallet_accountState() const {
if (wallet_type_ != RestrictedWallet) {
return TonlibError::AccountTypeUnexpected("RestrictedWallet");
}
auto wallet = ton::RestrictedWallet::create(get_smc_state());
TRY_RESULT(seqno, wallet->get_seqno());
TRY_RESULT(wallet_id, wallet->get_wallet_id());
TRY_RESULT(balance, wallet->get_balance(raw_.balance, raw_.info.gen_utime));
TRY_RESULT(config, wallet->get_config());
auto api_config = tonlib_api::make_object<tonlib_api::rwallet_config>();
api_config->start_at_ = config.start_at;
for (auto& limit : config.limits) {
api_config->limits_.push_back(tonlib_api::make_object<tonlib_api::rwallet_limit>(limit.first, limit.second));
}
return tonlib_api::make_object<tonlib_api::rwallet_accountState>(wallet_id, seqno, balance, std::move(api_config));
}
td::Result<tonlib_api::object_ptr<tonlib_api::pchan_accountState>> to_payment_channel_accountState() const {
if (wallet_type_ != PaymentChannel) {
return TonlibError::AccountTypeUnexpected("PaymentChannel");
}
auto pchan = ton::PaymentChannel::create(get_smc_state());
TRY_RESULT(info, pchan->get_info());
TRY_RESULT(a_key, public_key_from_bytes(info.config.a_key));
TRY_RESULT(b_key, public_key_from_bytes(info.config.b_key));
tonlib_api::object_ptr<tonlib_api::pchan_State> tl_state;
info.state.visit(td::overloaded(
[&](const ton::pchan::StateInit& state) {
tl_state = tonlib_api::make_object<tonlib_api::pchan_stateInit>(
state.signed_A, state.signed_B, state.min_A, state.min_B, state.A, state.B, state.expire_at);
},
[&](const ton::pchan::StateClose& state) {
tl_state = tonlib_api::make_object<tonlib_api::pchan_stateClose>(
state.signed_A, state.signed_B, state.promise_A, state.promise_B, state.A, state.B, state.expire_at);
},
[&](const ton::pchan::StatePayout& state) {
tl_state = tonlib_api::make_object<tonlib_api::pchan_statePayout>(state.A, state.B);
}));
using tonlib_api::make_object;
return tonlib_api::make_object<tonlib_api::pchan_accountState>(
tonlib_api::make_object<tonlib_api::pchan_config>(
a_key.serialize(true), make_object<tonlib_api::accountAddress>(info.config.a_addr.rserialize(true)),
b_key.serialize(true), make_object<tonlib_api::accountAddress>(info.config.b_addr.rserialize(true)),
info.config.init_timeout, info.config.close_timeout, info.config.channel_id),
std::move(tl_state), info.description);
}
td::Result<tonlib_api::object_ptr<tonlib_api::testGiver_accountState>> to_testGiver_accountState() const {
if (wallet_type_ != Giver) {
@ -298,11 +409,14 @@ class AccountState {
return f(to_wallet_highload_v1_accountState());
case HighloadWalletV2:
return f(to_wallet_highload_v2_accountState());
case RestrictedWallet:
return f(to_rwallet_accountState());
case ManualDns:
return f(to_dns_accountState());
default:
UNREACHABLE();
case PaymentChannel:
return f(to_payment_channel_accountState());
}
UNREACHABLE();
}
td::Result<tonlib_api::object_ptr<tonlib_api::fullAccountState>> to_fullAccountState() const {
@ -321,7 +435,9 @@ class AccountState {
WalletV3,
HighloadWalletV1,
HighloadWalletV2,
ManualDns
ManualDns,
PaymentChannel,
RestrictedWallet
};
WalletType get_wallet_type() const {
return wallet_type_;
@ -331,6 +447,7 @@ class AccountState {
case AccountState::Empty:
case AccountState::Unknown:
case AccountState::ManualDns:
case AccountState::PaymentChannel:
return false;
case AccountState::Giver:
case AccountState::SimpleWallet:
@ -338,6 +455,7 @@ class AccountState {
case AccountState::WalletV3:
case AccountState::HighloadWalletV1:
case AccountState::HighloadWalletV2:
case AccountState::RestrictedWallet:
return true;
}
UNREACHABLE();
@ -348,6 +466,7 @@ class AccountState {
case AccountState::Empty:
case AccountState::Unknown:
case AccountState::ManualDns:
case AccountState::PaymentChannel:
return {};
case AccountState::Giver:
return td::make_unique<ton::TestGiver>(get_smc_state());
@ -361,6 +480,8 @@ class AccountState {
return td::make_unique<ton::HighloadWallet>(get_smc_state());
case AccountState::HighloadWalletV2:
return td::make_unique<ton::HighloadWalletV2>(get_smc_state());
case AccountState::RestrictedWallet:
return td::make_unique<ton::RestrictedWallet>(get_smc_state());
}
UNREACHABLE();
return {};
@ -393,6 +514,50 @@ class AccountState {
return raw_;
}
WalletType guess_type_by_init_state(tonlib_api::InitialAccountState& initial_account_state) {
if (wallet_type_ != WalletType::Empty) {
return wallet_type_;
}
downcast_call(
initial_account_state,
td::overloaded(
[](auto& x) {},
[&](tonlib_api::rwallet_initialAccountState& rwallet) {
for (auto revision : ton::SmartContractCode::get_revisions(ton::SmartContractCode::RestrictedWallet)) {
auto r_init_data = to_init_data(rwallet);
if (r_init_data.is_error()) {
continue;
}
auto wallet = ton::RestrictedWallet::create(r_init_data.move_as_ok(), revision);
if (!(wallet->get_address() == address_)) {
continue;
}
wallet_type_ = WalletType::RestrictedWallet;
wallet_revision_ = revision;
set_new_state(wallet->get_state());
break;
}
},
[&](tonlib_api::pchan_initialAccountState& pchan) {
for (auto revision : ton::SmartContractCode::get_revisions(ton::SmartContractCode::PaymentChannel)) {
auto r_conf = to_pchan_config(pchan);
if (r_conf.is_error()) {
continue;
}
auto conf = r_conf.move_as_ok();
auto wallet = ton::PaymentChannel::create(conf, -1);
if (!(wallet->get_address() == address_)) {
continue;
}
wallet_type_ = WalletType::PaymentChannel;
wallet_revision_ = revision;
set_new_state(wallet->get_state());
break;
}
}));
return wallet_type_;
}
WalletType guess_type_by_public_key(td::Ed25519::PublicKey& key) {
if (wallet_type_ != WalletType::Empty) {
return wallet_type_;
@ -509,6 +674,18 @@ class AccountState {
wallet_revision_ = o_revision.value();
return wallet_type_;
}
o_revision = ton::PaymentChannel::guess_revision(code_hash);
if (o_revision) {
wallet_type_ = WalletType::PaymentChannel;
wallet_revision_ = o_revision.value();
return wallet_type_;
}
o_revision = ton::RestrictedWallet::guess_revision(code_hash);
if (o_revision) {
wallet_type_ = WalletType::RestrictedWallet;
wallet_revision_ = o_revision.value();
return wallet_type_;
}
if (code_hash == ton::TestGiver::get_init_code_hash()) {
wallet_type_ = WalletType::Giver;
@ -516,8 +693,6 @@ class AccountState {
wallet_type_ = WalletType::SimpleWallet;
} else if (code_hash == ton::Wallet::get_init_code_hash()) {
wallet_type_ = WalletType::Wallet;
} else if (code_hash == ton::HighloadWallet::get_init_code_hash()) {
wallet_type_ = WalletType::HighloadWalletV1;
} else {
LOG(WARNING) << "Unknown code hash: " << td::base64_encode(code_hash.as_slice());
wallet_type_ = WalletType::Unknown;
@ -545,6 +720,12 @@ class Query {
td::Ref<vm::Cell> get_message() const {
return raw_.message;
}
td::Ref<vm::Cell> get_message_body() const {
return raw_.message_body;
}
td::Ref<vm::Cell> get_init_state() const {
return raw_.new_state;
}
vm::CellHash get_body_hash() const {
return raw_.message_body->get_hash();
@ -722,11 +903,8 @@ class Query {
raw_.message_body, ton::SmartContract::Args().set_limits(gas_limits).set_ignore_chksig(ignore_chksig));
td::int64 fwd_fee = 0;
if (res.success) {
//std::cerr << "new smart contract data: ";
//load_cell_slice(res.new_state.data).print_rec(std::cerr);
//std::cerr << "output actions: ";
//int out_act_num = output_actions_count(res.actions);
//block::gen::OutList{out_act_num}.print_ref(std::cerr, res.actions);
LOG(DEBUG) << "output actions:\n"
<< block::gen::OutList{output_actions_count(res.actions)}.as_string_ref(res.actions);
TRY_RESULT_ASSIGN(fwd_fee, calc_fwd_fees(res.actions, msg_prices, is_masterchain));
}
@ -1402,11 +1580,6 @@ tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const
return tonlib_api::make_object<tonlib_api::ok>();
}
td::Result<block::PublicKey> get_public_key(td::Slice public_key) {
TRY_RESULT_PREFIX(address, block::PublicKey::parse(public_key), TonlibError::InvalidPublicKey());
return address;
}
td::Result<block::StdAddress> get_account_address(const tonlib_api::raw_initialAccountState& raw_state,
td::int32 revision) {
TRY_RESULT_PREFIX(code, vm::std_boc_deserialize(raw_state.code_), TonlibError::InvalidBagOfCells("raw_state.code"));
@ -1467,9 +1640,15 @@ td::Result<block::StdAddress> get_account_address(const tonlib_api::dns_initialA
return ton::ManualDns::create(key, static_cast<td::uint32>(dns_state.wallet_id_), revision)->get_address();
}
td::Result<block::StdAddress> get_account_address(td::Slice account_address) {
TRY_RESULT_PREFIX(address, block::StdAddress::parse(account_address), TonlibError::InvalidAccountAddress());
return address;
td::Result<block::StdAddress> get_account_address(const tonlib_api::pchan_initialAccountState& pchan_state,
td::int32 revision) {
TRY_RESULT(config, to_pchan_config(pchan_state));
return ton::PaymentChannel::create(config, revision)->get_address();
}
td::Result<block::StdAddress> get_account_address(const tonlib_api::rwallet_initialAccountState& rwallet_state,
td::int32 revision) {
TRY_RESULT(init_data, to_init_data(rwallet_state));
return ton::RestrictedWallet::create(init_data, revision)->get_address();
}
td::Result<td::Bits256> get_adnl_address(td::Slice adnl_address) {
@ -1493,6 +1672,8 @@ static td::optional<ton::SmartContractCode::Type> get_wallet_type(tonlib_api::In
[](const tonlib_api::wallet_highload_v2_initialAccountState&) {
return ton::SmartContractCode::HighloadWalletV2;
},
[](const tonlib_api::rwallet_initialAccountState&) { return ton::SmartContractCode::RestrictedWallet; },
[](const tonlib_api::pchan_initialAccountState&) { return ton::SmartContractCode::PaymentChannel; },
[](const tonlib_api::dns_initialAccountState&) { return ton::SmartContractCode::ManualDns; }));
}
@ -1555,7 +1736,18 @@ td::Status TonlibClient::do_request(const tonlib_api::guessAccountRevision& requ
td::Promise<std::vector<int>> promise_;
size_t left_{0};
std::vector<int> res;
struct Item {
bool is_inited;
td::int64 balance;
int revision;
auto key() const {
return std::make_tuple(is_inited, balance, revision);
}
bool operator<(const Item& other) const {
return key() > other.key();
}
};
std::vector<Item> res;
void start_up() {
left_ += addresses_.size();
@ -1565,12 +1757,24 @@ td::Status TonlibClient::do_request(const tonlib_api::guessAccountRevision& requ
}
}
void on_account_state(int revision, td::Result<td::unique_ptr<AccountState>> r_state) {
if (r_state.is_ok() && r_state.ok()->get_wallet_type() != AccountState::WalletType::Empty) {
res.push_back(revision);
SCOPE_EXIT {
on_account_state_finish();
};
if (!r_state.is_ok()) {
return;
}
auto state = r_state.move_as_ok();
if (state->get_balance() < 0) {
return;
}
res.push_back({state->get_wallet_type() != AccountState::WalletType::Empty, state->get_balance(), revision});
}
void on_account_state_finish() {
left_--;
if (left_ == 0) {
promise_.set_value(std::move(res));
std::sort(res.begin(), res.end());
promise_.set_value(td::transform(std::move(res), [](auto x) { return x.revision; }));
stop();
}
}
@ -1653,6 +1857,7 @@ class MasterConfig {
public:
void add_config(std::string name, std::string json) {
auto config = std::make_shared<Config>(Config::parse(json).move_as_ok());
config->name = name;
if (!name.empty()) {
by_name_[name] = config;
}
@ -1701,14 +1906,6 @@ const MasterConfig& get_default_master_config() {
})abc");
res.add_config("testnet2", R"abc({
"liteservers": [
{
"ip": 1137658550,
"port": 4924,
"id": {
"@type": "pub.ed25519",
"key": "peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M="
}
}
],
"validator": {
"@type": "validator.config.global",
@ -1721,6 +1918,20 @@ const MasterConfig& get_default_master_config() {
},
"init_block": {"workchain":-1,"shard":-9223372036854775808,"seqno":2908451,"root_hash":"5+7X1QHVUBFLFMwa/yd/2fGzt2KeQtwr+o6UUFOQ7Qc=","file_hash":"gmiUgrtAbvEJZYDEkcbeNOhGPS3g+qCepSOEBFLZFzk="}
}
})abc");
res.add_config("mainnet", R"abc({
"liteservers": [
],
"validator": {
"@type": "validator.config.global",
"zero_state": {
"workchain": -1,
"shard": -9223372036854775808,
"seqno": 0,
"root_hash": "KbTmuSarbve4ce9SET3BRyDnlPZr4GMdWswt1nDQAl4=",
"file_hash": "yRCjDRa-ChWiAGf5n3b25U17aqKzVL13C2Tzz8sqtJA="
}
}
})abc");
return res;
}();
@ -1740,7 +1951,6 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
if (new_config.lite_clients.empty() && !config->use_callbacks_for_network_) {
return TonlibError::InvalidConfig("no lite clients");
}
td::optional<Config> o_master_config;
std::string last_state_key;
if (config->blockchain_name_.empty()) {
@ -1755,6 +1965,12 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
return TonlibError::InvalidConfig("zero_state differs from embedded zero_state");
}
if (o_master_config && o_master_config.value().hardforks != new_config.hardforks) {
return TonlibError::InvalidConfig("hardforks differs from embedded hardforks");
}
int vert_seqno = static_cast<int>(new_config.hardforks.size());
LastBlockState state;
td::Result<LastBlockState> r_state;
if (!config->ignore_cache_) {
@ -1773,6 +1989,25 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
LOG(ERROR) << state.zero_state_id.to_str() << " " << zero_state.to_str();
return TonlibError::InvalidConfig("zero_state differs from cached zero_state");
}
if (state.vert_seqno > vert_seqno) {
LOG(ERROR) << "Stored vert_seqno is bigger than one in config: " << state.vert_seqno << " vs " << vert_seqno;
return TonlibError::InvalidConfig("vert_seqno in cached state is bigger");
}
if (state.vert_seqno < vert_seqno) {
state.zero_state_id = zero_state;
state.last_block_id = new_config.zero_state_id;
state.last_key_block_id = new_config.zero_state_id;
state.init_block_id = ton::BlockIdExt{};
LOG(WARNING) << "Drop cached state - vert_seqno is smaller than in config";
}
}
state.vert_seqno = vert_seqno;
//TODO: this could be useful to override master config
if (false && new_config.init_block_id.is_valid() &&
state.last_key_block_id.id.seqno < new_config.init_block_id.id.seqno) {
state.last_key_block_id = new_config.init_block_id;
LOG(INFO) << "Use init block from USER config: " << new_config.init_block_id.to_str();
}
if (o_master_config) {
@ -1782,12 +2017,23 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
state.last_key_block_id = master_config.init_block_id;
LOG(INFO) << "Use init block from MASTER config: " << master_config.init_block_id.to_str();
}
if (!master_config.name.empty()) {
if (new_config.name != master_config.name) {
LOG(INFO) << "Use blockchain name from MASTER config: '" << master_config.name << "' (was '" << new_config.name
<< "')";
new_config.name = master_config.name;
}
}
}
FullConfig res;
res.config = std::move(new_config);
res.use_callbacks_for_network = config->use_callbacks_for_network_;
res.wallet_id = td::as<td::uint32>(res.config.zero_state_id.root_hash.as_slice().data());
if (res.config.name.empty()) { // TODO == "mainnet"
res.wallet_id = 0x4BA92D89;
}
res.rwallet_init_public_key = "Puasxr0QfFZZnYISRphVse7XHKfW7pZU5SJarVHXvQ+rpzkD";
res.last_state_key = std::move(last_state_key);
res.last_state = std::move(state);
@ -1906,7 +2152,7 @@ struct ToRawTransactions {
}
}
if (!data) {
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)));
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)), "");
}
return data;
};
@ -2114,7 +2360,7 @@ td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request,
td::optional<td::Ed25519::PrivateKey> private_key;
if (request.private_key_) {
TRY_RESULT(input_key, from_tonlib(*request.private_key_));
//NB: options<Status> has lot of problems. We use emplace to migitate them
//NB: optional<Status> has lot of problems. We use emplace to migitate them
td::optional<td::Status> o_status;
//NB: rely on (and assert) that GetPrivateKey is a synchonous request
make_request(int_api::GetPrivateKey{std::move(input_key)}, [&](auto&& r_key) {
@ -2217,6 +2463,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
std::string message;
td::Ref<vm::Cell> body;
td::Ref<vm::Cell> init_state;
td::optional<td::Ed25519::PublicKey> o_public_key;
};
@ -2227,6 +2474,10 @@ class GenericCreateSendGrams : public TonlibQueryActor {
// Should be splitted eventually
std::vector<ton::ManualDns::Action> dns_actions_;
bool pchan_action_{false};
bool rwallet_action_{false};
void check(td::Status status) {
if (status.is_error()) {
promise_.set_error(std::move(status));
@ -2257,34 +2508,36 @@ class GenericCreateSendGrams : public TonlibQueryActor {
auto key = td::Ed25519::PublicKey(td::SecureString(public_key.key));
res.o_public_key = std::move(key);
}
auto status =
downcast_call2<td::Status>(*message.data_, td::overloaded(
[&](tonlib_api::msg_dataRaw& text) {
TRY_RESULT(body, vm::std_boc_deserialize(text.body_));
res.body = std::move(body);
return td::Status::OK();
},
[&](tonlib_api::msg_dataText& text) {
res.message = text.text_;
res.should_encrypt = false;
res.is_encrypted = false;
return td::Status::OK();
},
[&](tonlib_api::msg_dataDecryptedText& text) {
res.message = text.text_;
if (!has_private_key_) {
return TonlibError::EmptyField("input_key");
}
res.should_encrypt = true;
res.is_encrypted = true;
return td::Status::OK();
},
[&](tonlib_api::msg_dataEncryptedText& text) {
res.message = text.text_;
res.should_encrypt = false;
res.is_encrypted = true;
return td::Status::OK();
}));
auto status = downcast_call2<td::Status>(
*message.data_, td::overloaded(
[&](tonlib_api::msg_dataRaw& text) {
TRY_RESULT(body, vm::std_boc_deserialize(text.body_));
TRY_RESULT(init_state, vm::std_boc_deserialize(text.init_state_, true));
res.body = std::move(body);
res.init_state = std::move(init_state);
return td::Status::OK();
},
[&](tonlib_api::msg_dataText& text) {
res.message = text.text_;
res.should_encrypt = false;
res.is_encrypted = false;
return td::Status::OK();
},
[&](tonlib_api::msg_dataDecryptedText& text) {
res.message = text.text_;
if (!has_private_key_) {
return TonlibError::EmptyField("input_key");
}
res.should_encrypt = true;
res.is_encrypted = true;
return td::Status::OK();
},
[&](tonlib_api::msg_dataEncryptedText& text) {
res.message = text.text_;
res.should_encrypt = false;
res.is_encrypted = true;
return td::Status::OK();
}));
// Use this limit as a preventive check
if (res.message.size() > ton::Wallet::max_message_size) {
return TonlibError::MessageTooLong();
@ -2332,6 +2585,14 @@ class GenericCreateSendGrams : public TonlibQueryActor {
}
return td::Status::OK();
},
[&](tonlib_api::actionPchan& cell) {
pchan_action_ = true;
return td::Status::OK();
},
[&](tonlib_api::actionRwallet& cell) {
rwallet_action_ = true;
return td::Status::OK();
},
[&](tonlib_api::actionDns& cell) {
for (auto& from_action : cell.actions_) {
if (!from_action) {
@ -2397,6 +2658,9 @@ class GenericCreateSendGrams : public TonlibQueryActor {
td::Status do_on_source_state(td::Result<td::unique_ptr<AccountState>> r_state) {
TRY_RESULT(state, std::move(r_state));
source_ = std::move(state);
if (source_->get_wallet_type() == AccountState::Empty && query_.initial_account_state_) {
source_->guess_type_by_init_state(*query_.initial_account_state_);
}
if (source_->get_wallet_type() == AccountState::Empty && public_key_) {
source_->guess_type_by_public_key(public_key_.value());
}
@ -2459,6 +2723,165 @@ class GenericCreateSendGrams : public TonlibQueryActor {
return td::Status::OK();
}
td::Status do_pchan_loop(td::Ref<ton::PaymentChannel> pchan, tonlib_api::actionPchan& action) {
if (!action.action_) {
return TonlibError::EmptyField("action");
}
Query::Raw raw;
auto valid_until = source_->get_sync_time();
valid_until += query_.timeout_ == 0 ? 60 : query_.timeout_;
raw.valid_until = valid_until;
TRY_RESULT(info, pchan->get_info());
bool is_alice = false;
bool is_bob = false;
if (info.config.a_key == private_key_.value().get_public_key().move_as_ok().as_octet_string()) {
LOG(ERROR) << "Alice key";
is_alice = true;
} else if (info.config.b_key == private_key_.value().get_public_key().move_as_ok().as_octet_string()) {
LOG(ERROR) << "Bob key";
is_bob = true;
}
if (!is_alice && !is_bob) {
return TonlibError::InvalidField("private_key", "invalid for this smartcontract");
}
auto status = downcast_call2<td::Status>(
*action.action_,
td::overloaded(
[&](tonlib_api::pchan_actionTimeout& timeout) {
auto builder = ton::pchan::MsgTimeoutBuilder();
if (is_alice) {
std::move(builder).with_a_key(&private_key_.value());
}
if (is_bob) {
std::move(builder).with_b_key(&private_key_.value());
}
raw.message_body = std::move(builder).finalize();
return td::Status::OK();
},
[&](tonlib_api::pchan_actionInit& init) {
auto builder = ton::pchan::MsgInitBuilder()
.inc_A(init.inc_A_)
.inc_B(init.inc_B_)
.min_A(init.min_A_)
.min_B(init.min_B_)
.channel_id(info.config.channel_id);
if (is_alice) {
std::move(builder).with_a_key(&private_key_.value());
}
if (is_bob) {
std::move(builder).with_b_key(&private_key_.value());
}
raw.message_body = std::move(builder).finalize();
return td::Status::OK();
},
[&](tonlib_api::pchan_actionClose& close) {
if (!close.promise_) {
return TonlibError::EmptyField("promise");
}
ton::pchan::SignedPromiseBuilder sbuilder;
sbuilder.promise_A(close.promise_->promise_A_)
.promise_B(close.promise_->promise_B_)
.channel_id(close.promise_->channel_id_)
.signature(td::SecureString(close.promise_->signature_));
if (is_alice && !sbuilder.check_signature(close.promise_->signature_,
td::Ed25519::PublicKey(info.config.b_key.copy()))) {
return TonlibError::InvalidSignature();
}
if (is_bob && !sbuilder.check_signature(close.promise_->signature_,
td::Ed25519::PublicKey(info.config.a_key.copy()))) {
return TonlibError::InvalidSignature();
}
auto builder = ton::pchan::MsgCloseBuilder()
.extra_A(close.extra_A_)
.extra_B(close.extra_B_)
.signed_promise(sbuilder.finalize());
if (is_alice) {
std::move(builder).with_a_key(&private_key_.value());
}
if (is_bob) {
std::move(builder).with_b_key(&private_key_.value());
}
raw.message_body = std::move(builder).finalize();
return td::Status::OK();
}));
TRY_STATUS(std::move(status));
raw.new_state = source_->get_new_state();
raw.message = ton::GenericAccount::create_ext_message(source_->get_address(), raw.new_state, raw.message_body);
raw.source = std::move(source_);
promise_.set_value(td::make_unique<Query>(std::move(raw)));
stop();
return td::Status::OK();
}
td::Status do_pchan_loop() {
if (!private_key_) {
return TonlibError::EmptyField("private_key");
}
auto pchan = ton::PaymentChannel::create(source_->get_smc_state());
return downcast_call2<td::Status>(
*query_.action_, td::overloaded([&](tonlib_api::actionNoop& cell) { return td::Status::OK(); },
[&](auto& cell) { return td::Status::Error(); },
[&](tonlib_api::actionPchan& cell) { return do_pchan_loop(pchan, cell); }));
}
td::Status do_rwallet_action(td::Ref<ton::RestrictedWallet> rwallet, tonlib_api::actionRwallet& action) {
if (!action.action_) {
return TonlibError::EmptyField("action");
}
auto& init = *action.action_;
if (!init.config_) {
return TonlibError::EmptyField("config");
}
TRY_RESULT_PREFIX(start_at, td::narrow_cast_safe<td::uint32>(init.config_->start_at_),
TonlibError::InvalidField("start_at", "not a uint32"));
ton::RestrictedWallet::Config config;
config.start_at = start_at;
for (auto& limit : init.config_->limits_) {
if (!limit) {
return TonlibError::EmptyField("limits");
}
TRY_RESULT_PREFIX(seconds, td::narrow_cast_safe<td::int32>(limit->seconds_),
TonlibError::InvalidField("seconds", "not a int32"));
TRY_RESULT_PREFIX(value, td::narrow_cast_safe<td::uint64>(limit->value_),
TonlibError::InvalidField("value", "not a uint64"));
config.limits.emplace_back(seconds, value);
}
Query::Raw raw;
auto valid_until = source_->get_sync_time();
valid_until += query_.timeout_ == 0 ? 60 : query_.timeout_;
raw.valid_until = valid_until;
TRY_RESULT_PREFIX(message_body, rwallet->get_init_message(private_key_.value(), valid_until, config),
TonlibError::Internal("Invalid rwalet init query"));
raw.message_body = std::move(message_body);
raw.new_state = source_->get_new_state();
raw.message = ton::GenericAccount::create_ext_message(source_->get_address(), raw.new_state, raw.message_body);
raw.source = std::move(source_);
raw.destinations = std::move(destinations_);
promise_.set_value(td::make_unique<Query>(std::move(raw)));
stop();
return td::Status::OK();
}
td::Status do_rwallet_action() {
if (!private_key_) {
return TonlibError::EmptyField("private_key");
}
auto rwallet = ton::RestrictedWallet::create(source_->get_smc_state());
LOG(ERROR) << rwallet->get_address().rserialize(true);
return downcast_call2<td::Status>(
*query_.action_,
td::overloaded([&](auto& cell) { return td::Status::Error("UNREACHABLE"); },
[&](tonlib_api::actionRwallet& cell) { return do_rwallet_action(rwallet, cell); }));
}
td::Status do_loop() {
if (!source_ || destinations_left_ != 0) {
return td::Status::OK();
@ -2470,6 +2893,12 @@ class GenericCreateSendGrams : public TonlibQueryActor {
if (source_->get_wallet_type() == AccountState::ManualDns) {
return do_dns_loop();
}
if (source_->get_wallet_type() == AccountState::PaymentChannel) {
return do_pchan_loop();
}
if (rwallet_action_) {
return do_rwallet_action();
}
switch (source_->get_wallet_type()) {
case AccountState::Empty:
@ -2507,6 +2936,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
}
if (action.body.not_null()) {
gift.body = action.body;
gift.init_state = action.init_state;
} else if (action.should_encrypt) {
LOG(ERROR) << "TRY ENCRYPT";
if (!private_key_) {
@ -2581,7 +3011,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
return with_wallet(*source_->get_wallet());
}
};
}; // namespace tonlib
td::int64 TonlibClient::register_query(td::unique_ptr<Query> query) {
auto query_id = ++next_query_id_;
@ -2594,8 +3024,9 @@ td::Result<tonlib_api::object_ptr<tonlib_api::query_info>> TonlibClient::get_que
if (it == queries_.end()) {
return TonlibError::InvalidQueryId();
}
return tonlib_api::make_object<tonlib_api::query_info>(id, it->second->get_valid_until(),
it->second->get_body_hash().as_slice().str());
return tonlib_api::make_object<tonlib_api::query_info>(
id, it->second->get_valid_until(), it->second->get_body_hash().as_slice().str(),
to_bytes(it->second->get_message_body()), to_bytes(it->second->get_init_state()));
}
void TonlibClient::finish_create_query(td::Result<td::unique_ptr<Query>> r_query,
@ -2938,6 +3369,8 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
stack.write().push(std::move(e));
}
args.set_stack(std::move(stack));
args.set_balance(it->second->get_balance());
args.set_now(it->second->get_sync_time());
auto res = smc->run_get_method(std::move(args));
// smc.runResult gas_used:int53 stack:vector<tvm.StackEntry> exit_code:int32 = smc.RunResult;
@ -3057,6 +3490,76 @@ td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
return td::Status::OK();
}
td::Status TonlibClient::do_request(tonlib_api::pchan_signPromise& request,
td::Promise<object_ptr<tonlib_api::pchan_promise>>&& promise) {
if (!request.promise_) {
return TonlibError::EmptyField("promise");
}
if (!request.input_key_) {
return TonlibError::EmptyField("input_key");
}
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
make_request(int_api::GetPrivateKey{std::move(input_key)},
promise.wrap([promise = std::move(request.promise_)](auto key) mutable {
auto private_key = td::Ed25519::PrivateKey(std::move(key.private_key));
promise->signature_ = ton::pchan::SignedPromiseBuilder()
.promise_A(promise->promise_A_)
.promise_B(promise->promise_B_)
.channel_id(promise->channel_id_)
.with_key(&private_key)
.calc_signature()
.as_slice()
.str();
return std::move(promise);
}));
return td::Status::OK();
}
td::Status TonlibClient::do_request(tonlib_api::pchan_validatePromise& request,
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
if (!request.promise_) {
return TonlibError::EmptyField("promise");
}
TRY_RESULT(key_bytes, get_public_key(request.public_key_));
auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key));
bool is_ok = ton::pchan::SignedPromiseBuilder()
.promise_A(request.promise_->promise_A_)
.promise_B(request.promise_->promise_B_)
.channel_id(request.promise_->channel_id_)
.check_signature(request.promise_->signature_, key);
if (!is_ok) {
return TonlibError::InvalidSignature();
}
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
return td::Status::OK();
}
td::Status TonlibClient::do_request(tonlib_api::pchan_packPromise& request,
td::Promise<object_ptr<tonlib_api::data>>&& promise) {
if (!request.promise_) {
return TonlibError::EmptyField("promise");
}
promise.set_value(tonlib_api::make_object<tonlib_api::data>(
td::SecureString(to_bytes(ton::pchan::SignedPromiseBuilder()
.promise_A(request.promise_->promise_A_)
.promise_B(request.promise_->promise_B_)
.channel_id(request.promise_->channel_id_)
.signature(td::SecureString(request.promise_->signature_))
.finalize()))));
return td::Status::OK();
}
td::Status TonlibClient::do_request(tonlib_api::pchan_unpackPromise& request,
td::Promise<object_ptr<tonlib_api::pchan_promise>>&& promise) {
TRY_RESULT_PREFIX(body, vm::std_boc_deserialize(request.data_), TonlibError::InvalidBagOfCells("data"));
ton::pchan::SignedPromise spromise;
if (!spromise.unpack(body)) {
return TonlibError::InvalidField("data", "Can't unpack as a promise");
}
promise.set_value(tonlib_api::make_object<tonlib_api::pchan_promise>(
spromise.o_signature.value().as_slice().str(), spromise.promise.promise_A, spromise.promise.promise_B,
spromise.promise.channel_id));
return td::Status::OK();
}
td::Status TonlibClient::do_request(tonlib_api::sync& request,
td::Promise<object_ptr<tonlib_api::ton_blockIdExt>>&& promise) {
// ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt;
@ -3067,11 +3570,6 @@ td::Status TonlibClient::do_request(tonlib_api::sync& request,
return td::Status::OK();
}
td::Result<block::PublicKey> public_key_from_bytes(td::Slice bytes) {
TRY_RESULT_PREFIX(key_bytes, block::PublicKey::from_bytes(bytes), TonlibError::Internal());
return key_bytes;
}
td::Status TonlibClient::do_request(const tonlib_api::createNewKey& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
TRY_RESULT_PREFIX(

View file

@ -74,6 +74,7 @@ class TonlibClient : public td::actor::Actor {
LastBlockState last_state;
std::string last_state_key;
td::uint32 wallet_id;
std::string rwallet_init_public_key;
};
private:
@ -307,6 +308,15 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(const tonlib_api::dns_resolve& request,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
td::Status do_request(tonlib_api::pchan_signPromise& request,
td::Promise<object_ptr<tonlib_api::pchan_promise>>&& promise);
td::Status do_request(tonlib_api::pchan_validatePromise& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
td::Status do_request(tonlib_api::pchan_packPromise& request, td::Promise<object_ptr<tonlib_api::data>>&& promise);
td::Status do_request(tonlib_api::pchan_unpackPromise& request,
td::Promise<object_ptr<tonlib_api::pchan_promise>>&& promise);
void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
block::StdAddress address, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
struct DnsFinishData {

View file

@ -32,7 +32,7 @@
// INVALID_ACCOUNT_ADDRESS
// INVALID_CONFIG
// INVALID_PEM_KEY
// INVALID_REVISION
// INVALID_SIGNATURE
// MESSAGE_TOO_LONG
// EMPTY_FIELD
// INVALID_FIELD
@ -84,6 +84,9 @@ struct TonlibError {
static td::Status InvalidRevision() {
return td::Status::Error(400, "INVALID_REVISION");
}
static td::Status InvalidSignature() {
return td::Status::Error(400, "INVALID_SIGNATURE");
}
static td::Status NeedConfig() {
return td::Status::Error(400, "NeedConfig");
}

File diff suppressed because it is too large Load diff