mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated tonlib
This commit is contained in:
parent
c860ce3d1e
commit
3002321eb7
22 changed files with 576 additions and 109 deletions
|
@ -350,6 +350,7 @@ if (NOT CMAKE_CROSSCOMPILING)
|
|||
|
||||
GenFif(DEST smartcont/auto/config-code SOURCE smartcont/config-code.fc NAME config)
|
||||
GenFif(DEST smartcont/auto/wallet-code SOURCE smartcont/wallet-code.fc NAME wallet)
|
||||
GenFif(DEST smartcont/auto/wallet3-code SOURCE smartcont/wallet3-code.fc NAME wallet3)
|
||||
GenFif(DEST smartcont/auto/simple-wallet-code SOURCE smartcont/simple-wallet-code.fc NAME simple-wallet)
|
||||
GenFif(DEST smartcont/auto/highload-wallet-code SOURCE smartcont/highload-wallet-code.fc NAME highload-wallet)
|
||||
GenFif(DEST smartcont/auto/highload-wallet-v2-code SOURCE smartcont/highload-wallet-v2-code.fc NAME highoad-wallet-v2)
|
||||
|
@ -364,7 +365,9 @@ endif()
|
|||
add_library(smc-envelope ${SMC_ENVELOPE_SOURCE})
|
||||
target_include_directories(smc-envelope PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(smc-envelope PUBLIC ton_crypto PRIVATE tdutils ton_block)
|
||||
add_dependencies(smc-envelope gen_fif)
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
add_dependencies(smc-envelope gen_fif)
|
||||
endif()
|
||||
|
||||
add_executable(create-state block/create-state.cpp)
|
||||
target_include_directories(create-state PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
|
|
|
@ -534,19 +534,16 @@ td::Result<std::vector<StoragePrices>> Config::get_storage_prices() const {
|
|||
return std::move(res);
|
||||
}
|
||||
|
||||
td::Result<GasLimitsPrices> Config::get_gas_limits_prices(bool is_masterchain) const {
|
||||
td::Result<GasLimitsPrices> Config::do_get_gas_limits_prices(td::Ref<vm::Cell> cell, int id) {
|
||||
GasLimitsPrices res;
|
||||
auto id = is_masterchain ? 20 : 21;
|
||||
auto cell = get_config_param(id);
|
||||
if (cell.is_null()) {
|
||||
return td::Status::Error(PSLICE() << "configuration parameter " << id << " with gas prices is absent");
|
||||
}
|
||||
auto cs = vm::load_cell_slice(std::move(cell));
|
||||
auto cs = vm::load_cell_slice(cell);
|
||||
block::gen::GasLimitsPrices::Record_gas_flat_pfx flat;
|
||||
if (tlb::unpack(cs, flat)) {
|
||||
cs = *flat.other;
|
||||
res.flat_gas_limit = flat.flat_gas_limit;
|
||||
res.flat_gas_price = flat.flat_gas_price;
|
||||
} else {
|
||||
cs = vm::load_cell_slice(cell);
|
||||
}
|
||||
auto f = [&](const auto& r, td::uint64 spec_limit) {
|
||||
res.gas_limit = r.gas_limit;
|
||||
|
@ -570,6 +567,14 @@ td::Result<GasLimitsPrices> Config::get_gas_limits_prices(bool is_masterchain) c
|
|||
}
|
||||
return res;
|
||||
}
|
||||
td::Result<GasLimitsPrices> Config::get_gas_limits_prices(bool is_masterchain) const {
|
||||
auto id = is_masterchain ? 20 : 21;
|
||||
auto cell = get_config_param(id);
|
||||
if (cell.is_null()) {
|
||||
return td::Status::Error(PSLICE() << "configuration parameter " << id << " with gas prices is absent");
|
||||
}
|
||||
return do_get_gas_limits_prices(std::move(cell), id);
|
||||
}
|
||||
|
||||
td::Result<MsgPrices> Config::get_msg_prices(bool is_masterchain) const {
|
||||
auto id = is_masterchain ? 24 : 25;
|
||||
|
|
|
@ -540,6 +540,7 @@ class Config {
|
|||
static td::Result<std::unique_ptr<ValidatorSet>> unpack_validator_set(Ref<vm::Cell> valset_root);
|
||||
td::Result<std::vector<StoragePrices>> get_storage_prices() const;
|
||||
td::Result<GasLimitsPrices> get_gas_limits_prices(bool is_masterchain = false) const;
|
||||
static td::Result<GasLimitsPrices> do_get_gas_limits_prices(td::Ref<vm::Cell> cell, int id);
|
||||
td::Result<MsgPrices> get_msg_prices(bool is_masterchain = false) const;
|
||||
static CatchainValidatorsConfig unpack_catchain_validators_config(Ref<vm::Cell> cell);
|
||||
CatchainValidatorsConfig get_catchain_validators_config() const;
|
||||
|
|
|
@ -68,7 +68,7 @@ sym_idx_t SymTableBase::gen_lookup(std::string str, int mode, sym_idx_t idx) {
|
|||
if (!(mode & 1)) {
|
||||
return not_found;
|
||||
}
|
||||
if (def_sym >= ((long)p * 3) / 4) {
|
||||
if (def_sym >= ((long long)p * 3) / 4) {
|
||||
throw SymTableOverflow{def_sym};
|
||||
}
|
||||
sym_table[h1] = std::make_unique<Symbol>(str, idx <= 0 ? sym_idx_t(h1) : -idx);
|
||||
|
|
|
@ -163,6 +163,14 @@ slice create_new_entry(cs) inline {
|
|||
return begin_cell().store_int(false, 1).store_uint(0, 64).store_uint(0, 256).store_slice(cs).end_cell().begin_parse();
|
||||
}
|
||||
|
||||
(cell, int, int, slice) unpack_suggestion(slice cs) inline {
|
||||
return (cs~load_dict(), cs~load_uint(64), cs~load_uint(256), cs);
|
||||
}
|
||||
|
||||
builder pack_suggestion(cell voters, int sum_weight, int vset_id, slice body) inline {
|
||||
return begin_cell().store_dict(voters).store_uint(sum_weight, 64).store_uint(vset_id, 256).store_slice(body);
|
||||
}
|
||||
|
||||
cell register_vote(vote_dict, action, cs, idx, weight) {
|
||||
int hash = 0;
|
||||
var entry = null();
|
||||
|
|
63
crypto/smartcont/new-wallet-v3.fif
Normal file
63
crypto/smartcont/new-wallet-v3.fif
Normal file
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <workchain-id> <wallet-id> [<filename-base>]" cr
|
||||
."Creates a new advanced wallet with unique 32-bit identifier <wallet-id> in specified workchain, with private key saved to or loaded from <filename-base>.pk" cr
|
||||
."('new-wallet.pk' by default)" cr 1 halt
|
||||
} : usage
|
||||
$# 2- -2 and ' usage if
|
||||
|
||||
$1 parse-workchain-id =: wc // set workchain id from command line argument
|
||||
$2 parse-int =: subwallet-id
|
||||
def? $3 { @' $3 } { "new-wallet" } cond constant file-base
|
||||
|
||||
."Creating new advanced v3 wallet in workchain " wc . cr
|
||||
."with unique wallet id " subwallet-id . cr
|
||||
|
||||
// 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
|
||||
}>
|
||||
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
|
||||
NOW s1 s3 XCHG LEQ 35 THROWIF // signature in_msg subwallet_id cs msg_seqno
|
||||
c4 PUSH CTOS 32 LDU 32 LDU 256 LDU ENDS // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key
|
||||
s3 s2 XCPU EQUAL 33 THROWIFNOT // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet
|
||||
s4 s4 XCPU EQUAL 34 THROWIFNOT // signature in_msg stored_subwallet cs public_key stored_seqno
|
||||
s0 s4 XCHG HASHSU // signature stored_seqno stored_subwallet cs public_key msg_hash
|
||||
s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs msg_hash signature public_key
|
||||
CHKSIGNU 35 THROWIFNOT // public_key stored_seqno stored_subwallet cs
|
||||
ACCEPT
|
||||
WHILE:<{
|
||||
DUP SREFS // public_key stored_seqno stored_subwallet cs _51
|
||||
}>DO<{ // public_key stored_seqno stored_subwallet cs
|
||||
8 LDU LDREF s0 s2 XCHG // public_key stored_seqno stored_subwallet cs _56 mode
|
||||
SENDRAWMSG
|
||||
}> // public_key stored_seqno stored_subwallet cs
|
||||
ENDS SWAP INC // public_key stored_subwallet seqno'
|
||||
NEWC 32 STU 32 STU 256 STU ENDC c4 POP
|
||||
}>c // >libref
|
||||
// code
|
||||
<b 0 32 u, subwallet-id 32 u,
|
||||
file-base +".pk" load-generate-keypair
|
||||
constant wallet_pk
|
||||
B,
|
||||
b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new wallet address = " 2dup .addr cr
|
||||
2dup file-base +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
<b subwallet-id 32 u, -1 32 i, 0 32 u, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hashu wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
file-base +"-query.boc" tuck B>file
|
||||
."(Saved wallet creating query to file " type .")" cr
|
35
crypto/smartcont/wallet3-code.fc
Normal file
35
crypto/smartcont/wallet3-code.fc
Normal file
|
@ -0,0 +1,35 @@
|
|||
;; Simple wallet smart contract
|
||||
|
||||
() recv_internal(slice in_msg) impure {
|
||||
;; do nothing for internal messages
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
var signature = in_msg~load_bits(512);
|
||||
var cs = in_msg;
|
||||
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
|
||||
throw_if(35, valid_until <= now());
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
|
||||
ds.end_parse();
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
throw_unless(34, subwallet_id == stored_subwallet);
|
||||
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
accept_message();
|
||||
cs~touch();
|
||||
while (cs.slice_refs()) {
|
||||
var mode = cs~load_uint(8);
|
||||
send_raw_message(cs~load_ref(), mode);
|
||||
}
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(stored_subwallet, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
;; Get methods
|
||||
|
||||
int seqno() method_id {
|
||||
return get_data().begin_parse().preload_uint(32);
|
||||
}
|
|
@ -1021,9 +1021,9 @@ void CppTypeCode::generate_tag_pfx_selector(std::ostream& os, std::string nl, co
|
|||
}
|
||||
os << "};" << nl << "return ctab[1 + ";
|
||||
if (simple) {
|
||||
os << "(long)cs.prefetch_ulong(" << d << ")];";
|
||||
os << "(long long)cs.prefetch_ulong(" << d << ")];";
|
||||
} else {
|
||||
os << "(long)cs.bselect" << (d >= min_size ? "(" : "_ext(") << d << ", " << HexConstWriter{mask} << ")];";
|
||||
os << "(long long)cs.bselect" << (d >= min_size ? "(" : "_ext(") << d << ", " << HexConstWriter{mask} << ")];";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1153,7 +1153,7 @@ void CppTypeCode::generate_get_tag_body(std::ostream& os, std::string nl) {
|
|||
os << ")) {";
|
||||
for (int i = 0; i < l; i++) {
|
||||
if (A[i] != 0) {
|
||||
if ((long)A[i] > 0) {
|
||||
if ((long long)A[i] > 0) {
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (A[j] == A[i]) {
|
||||
|
@ -1165,7 +1165,7 @@ void CppTypeCode::generate_get_tag_body(std::ostream& os, std::string nl) {
|
|||
}
|
||||
}
|
||||
os << nl << "case " << i << ":";
|
||||
if ((long)A[i] > 0) {
|
||||
if ((long long)A[i] > 0) {
|
||||
int j;
|
||||
for (j = i + 1; j < l; j++) {
|
||||
if (A[j] == A[i]) {
|
||||
|
|
|
@ -687,7 +687,7 @@ unsigned long long BinTrie::build_submap(int depth, unsigned long long A[]) cons
|
|||
} else {
|
||||
std::memset(A + n, 0, n * 8);
|
||||
}
|
||||
if (A[n] != A[n - 1] || (long)A[n] < 0) {
|
||||
if (A[n] != A[n - 1] || (long long)A[n] < 0) {
|
||||
r2 |= 1;
|
||||
} else {
|
||||
r2 &= ~1;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "vm/cellslice.h"
|
||||
#include "vm/excno.hpp"
|
||||
|
||||
#include "td/utils/Span.h"
|
||||
|
||||
namespace td {
|
||||
extern template class td::Cnt<std::string>;
|
||||
extern template class td::Ref<td::Cnt<std::string>>;
|
||||
|
@ -156,7 +158,7 @@ class StackEntry {
|
|||
|
||||
private:
|
||||
template <typename T, Type tag>
|
||||
Ref<T> dynamic_as() const & {
|
||||
Ref<T> dynamic_as() const& {
|
||||
return tp == tag ? static_cast<Ref<T>>(ref) : td::Ref<T>{};
|
||||
}
|
||||
template <typename T, Type tag>
|
||||
|
@ -168,7 +170,7 @@ class StackEntry {
|
|||
return tp == tag ? static_cast<Ref<T>>(std::move(ref)) : td::Ref<T>{};
|
||||
}
|
||||
template <typename T, Type tag>
|
||||
Ref<T> as() const & {
|
||||
Ref<T> as() const& {
|
||||
return tp == tag ? Ref<T>{td::static_cast_ref(), ref} : td::Ref<T>{};
|
||||
}
|
||||
template <typename T, Type tag>
|
||||
|
@ -189,31 +191,31 @@ class StackEntry {
|
|||
return ref;
|
||||
}
|
||||
}
|
||||
td::RefInt256 as_int() const & {
|
||||
td::RefInt256 as_int() const& {
|
||||
return as<td::CntInt256, t_int>();
|
||||
}
|
||||
td::RefInt256 as_int() && {
|
||||
return move_as<td::CntInt256, t_int>();
|
||||
}
|
||||
Ref<Cell> as_cell() const & {
|
||||
Ref<Cell> as_cell() const& {
|
||||
return as<Cell, t_cell>();
|
||||
}
|
||||
Ref<Cell> as_cell() && {
|
||||
return move_as<Cell, t_cell>();
|
||||
}
|
||||
Ref<CellBuilder> as_builder() const & {
|
||||
Ref<CellBuilder> as_builder() const& {
|
||||
return as<CellBuilder, t_builder>();
|
||||
}
|
||||
Ref<CellBuilder> as_builder() && {
|
||||
return move_as<CellBuilder, t_builder>();
|
||||
}
|
||||
Ref<CellSlice> as_slice() const & {
|
||||
Ref<CellSlice> as_slice() const& {
|
||||
return as<CellSlice, t_slice>();
|
||||
}
|
||||
Ref<CellSlice> as_slice() && {
|
||||
return move_as<CellSlice, t_slice>();
|
||||
}
|
||||
Ref<Continuation> as_cont() const &;
|
||||
Ref<Continuation> as_cont() const&;
|
||||
Ref<Continuation> as_cont() &&;
|
||||
Ref<Cnt<std::string>> as_string_ref() const {
|
||||
return as<Cnt<std::string>, t_string>();
|
||||
|
@ -228,16 +230,16 @@ class StackEntry {
|
|||
std::string as_bytes() const {
|
||||
return tp == t_bytes ? *as_bytes_ref() : "";
|
||||
}
|
||||
Ref<Box> as_box() const &;
|
||||
Ref<Box> as_box() const&;
|
||||
Ref<Box> as_box() &&;
|
||||
Ref<Tuple> as_tuple() const &;
|
||||
Ref<Tuple> as_tuple() const&;
|
||||
Ref<Tuple> as_tuple() &&;
|
||||
Ref<Tuple> as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) const &;
|
||||
Ref<Tuple> as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) const&;
|
||||
Ref<Tuple> as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) &&;
|
||||
Ref<Atom> as_atom() const &;
|
||||
Ref<Atom> as_atom() const&;
|
||||
Ref<Atom> as_atom() &&;
|
||||
template <class T>
|
||||
Ref<T> as_object() const & {
|
||||
Ref<T> as_object() const& {
|
||||
return dynamic_as<T, t_object>();
|
||||
}
|
||||
template <class T>
|
||||
|
@ -361,6 +363,9 @@ class Stack : public td::CntObject {
|
|||
std::vector<StackEntry>::const_iterator from_top(int offs) const {
|
||||
return stack.cend() - offs;
|
||||
}
|
||||
td::Span<StackEntry> as_span() const {
|
||||
return stack;
|
||||
}
|
||||
bool at_least(int req) const {
|
||||
return depth() >= req;
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ class JsonObjectScope;
|
|||
|
||||
class JsonBuilder {
|
||||
public:
|
||||
explicit JsonBuilder(StringBuilder &&sb, int32 offset = -1) : sb_(std::move(sb)), offset_(offset) {
|
||||
explicit JsonBuilder(StringBuilder &&sb = {}, int32 offset = -1) : sb_(std::move(sb)), offset_(offset) {
|
||||
}
|
||||
StringBuilder &string_builder() {
|
||||
return sb_;
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace td {
|
|||
class StringBuilder {
|
||||
public:
|
||||
explicit StringBuilder(MutableSlice slice, bool use_buffer = false);
|
||||
StringBuilder() : StringBuilder({}, true) {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
current_ptr_ = begin_ptr_;
|
||||
|
|
|
@ -73,8 +73,22 @@ fees in_fwd_fee:int53 storage_fee:int53 gas_fee:int53 fwd_fee:int53= Fees;
|
|||
query.fees source_fees:fees destination_fees:fees = query.Fees;
|
||||
query.info id:int53 valid_until:int53 body_hash:bytes = query.Info;
|
||||
|
||||
tvm.slice bytes:string = tvm.Slice;
|
||||
tvm.cell bytes:string = tvm.Cell;
|
||||
tvm.numberDecimal number:string = tvm.Number;
|
||||
|
||||
tvm.stackEntrySlice slice:tvm.slice = tvm.StackEntry;
|
||||
tvm.stackEntryCell cell:tvm.cell = tvm.StackEntry;
|
||||
tvm.stackEntryNumber number:tvm.Number = tvm.StackEntry;
|
||||
tvm.stackEntryUnsupported = tvm.StackEntry;
|
||||
|
||||
smc.info id:int53 = smc.Info;
|
||||
|
||||
smc.methodIdNumber number:int32 = smc.MethodId;
|
||||
smc.methodIdName name:string = smc.MethodId;
|
||||
|
||||
smc.runResult gas_used:int53 stack:vector<tvm.StackEntry> exit_code:int32 = smc.RunResult;
|
||||
|
||||
updateSendLiteServerQuery id:int64 data:bytes = Update;
|
||||
updateSyncState sync_state:SyncState = Update;
|
||||
|
||||
|
@ -98,8 +112,6 @@ logTags tags:vector<string> = LogTags;
|
|||
|
||||
data bytes:secureBytes = Data;
|
||||
|
||||
tvm.cell bytes:string = tvm.Cell;
|
||||
|
||||
liteServer.info now:int53 version:int32 capabilities:int64 = liteServer.Info;
|
||||
|
||||
---functions---
|
||||
|
@ -108,6 +120,7 @@ init options:options = Ok;
|
|||
close = Ok;
|
||||
|
||||
options.setConfig config:config = Ok;
|
||||
options.validateConfig config:config = Ok;
|
||||
|
||||
createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key;
|
||||
deleteKey key:key = Ok;
|
||||
|
@ -126,7 +139,6 @@ kdf password:secureBytes salt:secureBytes iterations:int32 = Data;
|
|||
|
||||
unpackAccountAddress account_address:string = UnpackedAccountAddress;
|
||||
packAccountAddress account_address:unpackedAccountAddress = AccountAddress;
|
||||
|
||||
getBip39Hints prefix:string = Bip39Hints;
|
||||
|
||||
//raw.init initial_account_state:raw.initialAccountState = Ok;
|
||||
|
@ -168,6 +180,7 @@ smc.load account_address:accountAddress = smc.Info;
|
|||
smc.getCode id:int53 = tvm.Cell;
|
||||
smc.getData id:int53 = tvm.Cell;
|
||||
smc.getState id:int53 = tvm.Cell;
|
||||
smc.runGetMethod id:int53 method:smc.MethodId stack:vector<tvm.StackEntry> = smc.RunResult;
|
||||
|
||||
onLiteServerQueryResult id:int64 bytes:bytes = Ok;
|
||||
onLiteServerQueryError id:int64 error:error = Ok;
|
||||
|
|
Binary file not shown.
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "block/block.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "block/mc-config.h"
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "vm/boc.h"
|
||||
|
@ -246,6 +247,17 @@ TEST(Tonlib, ParseAddres) {
|
|||
ASSERT_EQ("Uf9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfdyS", addr_str2->account_address_);
|
||||
}
|
||||
|
||||
TEST(Tonlib, ConfigParseBug) {
|
||||
td::Slice literal =
|
||||
"D1000000000000006400000000000186A0DE0000000003E8000000000000000F424000000000000F42400000000000002710000000000098"
|
||||
"96800000000005F5E100000000003B9ACA00";
|
||||
unsigned char buff[128];
|
||||
int bits = (int)td::bitstring::parse_bitstring_hex_literal(buff, sizeof(buff), literal.begin(), literal.end());
|
||||
CHECK(bits >= 0);
|
||||
auto slice = vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize();
|
||||
block::Config::do_get_gas_limits_prices(std::move(slice), 21).ensure();
|
||||
}
|
||||
|
||||
TEST(Tonlib, EncryptionApi) {
|
||||
using tonlib_api::make_object;
|
||||
Client client;
|
||||
|
|
|
@ -462,29 +462,31 @@ void test_multisig(Client& client, const Wallet& giver_wallet) {
|
|||
transfer_grams(client, giver_wallet, address, 1 * Gramm).ensure();
|
||||
auto init_state = ms->get_init_state();
|
||||
|
||||
// Just transfer all (some) money back in one query
|
||||
vm::CellBuilder icb;
|
||||
ton::GenericAccount::store_int_message(icb, block::StdAddress::parse(giver_wallet.address).move_as_ok(),
|
||||
5 * Gramm / 10);
|
||||
icb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(icb, "Greatings from multisig", 35 * 8).ensure();
|
||||
ton::MultisigWallet::QueryBuilder qb(-1, icb.finalize());
|
||||
for (int i = 0; i < k - 1; i++) {
|
||||
qb.sign(i, private_keys[i]);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Just transfer all (some) money back in one query
|
||||
vm::CellBuilder icb;
|
||||
ton::GenericAccount::store_int_message(icb, block::StdAddress::parse(giver_wallet.address).move_as_ok(), 1);
|
||||
icb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(icb, "Greatings from multisig", 35 * 8).ensure();
|
||||
ton::MultisigWallet::QueryBuilder qb(-1 - i, icb.finalize());
|
||||
for (int i = 0; i < k - 1; i++) {
|
||||
qb.sign(i, private_keys[i]);
|
||||
}
|
||||
|
||||
auto query_id =
|
||||
create_raw_query(client, address,
|
||||
i == 0 ? vm::std_boc_serialize(ms->get_state().code).move_as_ok().as_slice().str() : "",
|
||||
i == 0 ? vm::std_boc_serialize(ms->get_state().data).move_as_ok().as_slice().str() : "",
|
||||
vm::std_boc_serialize(qb.create(k - 1, private_keys[k - 1])).move_as_ok().as_slice().str())
|
||||
.move_as_ok();
|
||||
auto fees = query_estimate_fees(client, query_id);
|
||||
|
||||
LOG(INFO) << "Expected src fees: " << fees.first;
|
||||
LOG(INFO) << "Expected dst fees: " << fees.second;
|
||||
auto a_state = get_account_state(client, address);
|
||||
query_send(client, query_id);
|
||||
auto new_a_state = wait_state_change(client, a_state, a_state.sync_utime + 30).move_as_ok();
|
||||
}
|
||||
|
||||
auto query_id =
|
||||
create_raw_query(client, address, vm::std_boc_serialize(ms->get_state().code).move_as_ok().as_slice().str(),
|
||||
vm::std_boc_serialize(ms->get_state().data).move_as_ok().as_slice().str(),
|
||||
vm::std_boc_serialize(qb.create(k - 1, private_keys[k - 1])).move_as_ok().as_slice().str())
|
||||
.move_as_ok();
|
||||
auto fees = query_estimate_fees(client, query_id);
|
||||
|
||||
LOG(INFO) << "Expected src fees: " << fees.first;
|
||||
LOG(INFO) << "Expected dst fees: " << fees.second;
|
||||
auto a_state = get_account_state(client, address);
|
||||
query_send(client, query_id);
|
||||
auto new_a_state = wait_state_change(client, a_state, a_state.sync_utime + 30).move_as_ok();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
@ -515,8 +517,8 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
if (reset_keystore_dir) {
|
||||
td::rmrf(keystore_dir).ignore();
|
||||
td::mkdir(keystore_dir).ensure();
|
||||
}
|
||||
td::mkdir(keystore_dir).ensure();
|
||||
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(INFO));
|
||||
static_send(make_object<tonlib_api::setLogTagVerbosityLevel>("tonlib_query", 4)).ensure();
|
||||
|
|
|
@ -42,6 +42,7 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
|||
auto it = queries_.find(id);
|
||||
if (it == queries_.end()) {
|
||||
promise.set_error(TonlibError::Internal("Unknown query id"));
|
||||
return;
|
||||
}
|
||||
it->second.set_result(std::move(r_data));
|
||||
queries_.erase(it);
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "lite-client/lite-client-common.h"
|
||||
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
// init_state <-> last_key_block
|
||||
|
@ -313,6 +315,18 @@ bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) {
|
|||
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;
|
||||
VLOG(last_block) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
|
||||
if (true) {
|
||||
td::JsonBuilder jb;
|
||||
auto jo = jb.enter_object();
|
||||
jo("workchain", state_.last_key_block_id.id.workchain);
|
||||
jo("shard", static_cast<td::int64>(state_.last_key_block_id.id.shard));
|
||||
jo("seqno", static_cast<td::int32>(state_.last_key_block_id.id.seqno));
|
||||
jo("root_hash", td::base64_encode(as_slice(state_.last_key_block_id.root_hash)));
|
||||
jo("file_hash", td::base64_encode(as_slice(state_.last_key_block_id.file_hash)));
|
||||
jo.leave();
|
||||
LOG(INFO) << jb.string_builder().as_cslice();
|
||||
}
|
||||
|
||||
//LOG(ERROR) << td::int64(state_.last_key_block_id.id.shard) << " "
|
||||
//<< td::base64_encode(state_.last_key_block_id.file_hash.as_slice()) << " "
|
||||
//<< td::base64_encode(state_.last_key_block_id.root_hash.as_slice());
|
||||
|
|
|
@ -798,18 +798,22 @@ void TonlibClient::init_ext_client() {
|
|||
if (use_callbacks_for_network_) {
|
||||
class Callback : public ExtClientOutbound::Callback {
|
||||
public:
|
||||
explicit Callback(td::actor::ActorShared<TonlibClient> parent) : parent_(std::move(parent)) {
|
||||
explicit Callback(td::actor::ActorShared<TonlibClient> parent, td::uint32 config_generation)
|
||||
: parent_(std::move(parent)), config_generation_(config_generation) {
|
||||
}
|
||||
|
||||
void request(td::int64 id, std::string data) override {
|
||||
send_closure(parent_, &TonlibClient::proxy_request, id, std::move(data));
|
||||
send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff),
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<TonlibClient> parent_;
|
||||
td::uint32 config_generation_;
|
||||
};
|
||||
ref_cnt_++;
|
||||
auto client = ExtClientOutbound::create(td::make_unique<Callback>(td::actor::actor_shared(this)));
|
||||
auto client =
|
||||
ExtClientOutbound::create(td::make_unique<Callback>(td::actor::actor_shared(this), config_generation_));
|
||||
ext_client_outbound_ = client.get();
|
||||
raw_client_ = std::move(client);
|
||||
} else {
|
||||
|
@ -836,6 +840,7 @@ void TonlibClient::update_last_block_state(LastBlockState state, td::uint32 conf
|
|||
if (config_generation != config_generation_) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_block_storage_.save_state(blockchain_name_, state);
|
||||
}
|
||||
|
||||
|
@ -858,7 +863,7 @@ void TonlibClient::update_sync_state(LastBlockSyncState state, td::uint32 config
|
|||
}
|
||||
}
|
||||
|
||||
void TonlibClient::init_last_block() {
|
||||
void TonlibClient::init_last_block(td::optional<Config> o_master_config) {
|
||||
ref_cnt_++;
|
||||
class Callback : public LastBlock::Callback {
|
||||
public:
|
||||
|
@ -893,6 +898,15 @@ void TonlibClient::init_last_block() {
|
|||
state = r_state.move_as_ok();
|
||||
}
|
||||
|
||||
if (o_master_config) {
|
||||
auto master_config = o_master_config.unwrap();
|
||||
if (master_config.init_block_id.is_valid() &&
|
||||
state.last_key_block_id.id.seqno < master_config.init_block_id.id.seqno) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
raw_last_block_ = td::actor::create_actor<LastBlock>(
|
||||
td::actor::ActorOptions().with_name("LastBlock").with_poll(false), get_client_ref(), std::move(state), config_,
|
||||
source_.get_cancellation_token(), td::make_unique<Callback>(td::actor::actor_shared(this), config_generation_));
|
||||
|
@ -988,6 +1002,7 @@ bool TonlibClient::is_static_request(td::int32 id) {
|
|||
case tonlib_api::testGiver_getAccountAddress::ID:
|
||||
case tonlib_api::packAccountAddress::ID:
|
||||
case tonlib_api::unpackAccountAddress::ID:
|
||||
case tonlib_api::options_validateConfig::ID:
|
||||
case tonlib_api::getBip39Hints::ID:
|
||||
case tonlib_api::setLogStream::ID:
|
||||
case tonlib_api::getLogStream::ID:
|
||||
|
@ -1142,37 +1157,112 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request,
|
|||
key_storage_.set_key_value(kv_);
|
||||
last_block_storage_.set_key_value(kv_);
|
||||
if (request.options_->config_) {
|
||||
TRY_STATUS(set_config(std::move(request.options_->config_)));
|
||||
TRY_RESULT(full_config, validate_config(std::move(request.options_->config_)));
|
||||
set_config(std::move(full_config));
|
||||
}
|
||||
state_ = State::Running;
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::set_config(object_ptr<tonlib_api::config> config) {
|
||||
CHECK(config);
|
||||
class MasterConfig {
|
||||
public:
|
||||
void add_config(std::string name, std::string json) {
|
||||
auto config = std::make_shared<Config>(Config::parse(json).move_as_ok());
|
||||
if (!name.empty()) {
|
||||
by_name_[name] = config;
|
||||
}
|
||||
by_root_hash_[config->zero_state_id.root_hash] = config;
|
||||
}
|
||||
td::optional<Config> by_name(std::string name) const {
|
||||
auto it = by_name_.find(name);
|
||||
if (it == by_name_.end()) {
|
||||
return {};
|
||||
}
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
td::optional<Config> by_root_hash(const ton::RootHash& root_hash) const {
|
||||
auto it = by_root_hash_.find(root_hash);
|
||||
if (it == by_root_hash_.end()) {
|
||||
return {};
|
||||
}
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t next_id_{0};
|
||||
std::map<std::string, std::shared_ptr<const Config>> by_name_;
|
||||
std::map<ton::RootHash, std::shared_ptr<const Config>> by_root_hash_;
|
||||
};
|
||||
|
||||
const MasterConfig& get_default_master_config() {
|
||||
static MasterConfig config = [] {
|
||||
MasterConfig res;
|
||||
res.add_config("testnet", R"abc({
|
||||
"liteservers": [
|
||||
],
|
||||
"validator": {
|
||||
"@type": "validator.config.global",
|
||||
"zero_state": {
|
||||
"workchain": -1,
|
||||
"shard": -9223372036854775808,
|
||||
"seqno": 0,
|
||||
"root_hash": "VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=",
|
||||
"file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo="
|
||||
},
|
||||
"init_block":
|
||||
{"workchain":-1,"shard":-9223372036854775808,"seqno":870721,"root_hash":"jYKhSQ1xeSPprzgjqiUOnAWwc2yqs7nCVAU21k922s4=","file_hash":"kHidF02CZpaz2ia9jtXUJLp0AiWMWwfzprTUIsddHSo="}
|
||||
}
|
||||
})abc");
|
||||
return res;
|
||||
}();
|
||||
return config;
|
||||
}
|
||||
|
||||
td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::object_ptr<tonlib_api::config> config) {
|
||||
if (!config) {
|
||||
return TonlibError::EmptyField("config");
|
||||
}
|
||||
if (config->config_.empty()) {
|
||||
return TonlibError::InvalidConfig("config is empty");
|
||||
}
|
||||
TRY_RESULT_PREFIX(new_config, Config::parse(std::move(config->config_)),
|
||||
TonlibError::InvalidConfig("can't parse config"));
|
||||
|
||||
if (new_config.lite_clients.empty() && !config->use_callbacks_for_network_) {
|
||||
return TonlibError::InvalidConfig("no lite clients");
|
||||
}
|
||||
config_ = std::move(new_config);
|
||||
config_generation_++;
|
||||
|
||||
td::optional<Config> o_master_config;
|
||||
if (config->blockchain_name_.empty()) {
|
||||
blockchain_name_ = td::sha256(config_.zero_state_id.to_str()).substr(0, 16);
|
||||
o_master_config = get_default_master_config().by_root_hash(new_config.zero_state_id.root_hash);
|
||||
} else {
|
||||
blockchain_name_ = config->blockchain_name_;
|
||||
o_master_config = get_default_master_config().by_name(config->blockchain_name_);
|
||||
}
|
||||
use_callbacks_for_network_ = config->use_callbacks_for_network_;
|
||||
ignore_cache_ = config->ignore_cache_;
|
||||
|
||||
if (o_master_config && o_master_config.value().zero_state_id != new_config.zero_state_id) {
|
||||
return TonlibError::InvalidConfig("zero_state differs from embedded zero_state");
|
||||
}
|
||||
FullConfig res;
|
||||
res.config = std::move(new_config);
|
||||
res.o_master_config = std::move(o_master_config);
|
||||
res.ignore_cache = config->ignore_cache_;
|
||||
res.use_callbacks_for_network = config->use_callbacks_for_network_;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
void TonlibClient::set_config(FullConfig full_config) {
|
||||
config_ = std::move(full_config.config);
|
||||
config_generation_++;
|
||||
blockchain_name_ = config_.zero_state_id.root_hash.as_slice().str();
|
||||
|
||||
use_callbacks_for_network_ = full_config.use_callbacks_for_network;
|
||||
ignore_cache_ = full_config.ignore_cache;
|
||||
init_ext_client();
|
||||
init_last_block();
|
||||
init_last_block(std::move(full_config.o_master_config));
|
||||
init_last_config();
|
||||
client_.set_client(get_client_ref());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::close& request,
|
||||
|
@ -1184,12 +1274,22 @@ td::Status TonlibClient::do_request(const tonlib_api::close& request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
tonlib_api::options_validateConfig& request) {
|
||||
auto r_config = validate_config(std::move(request.config_));
|
||||
if (r_config.is_error()) {
|
||||
return status_to_tonlib_api(r_config.move_as_error());
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::ok>();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::options_setConfig& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
if (!request.config_) {
|
||||
return TonlibError::EmptyField("config");
|
||||
}
|
||||
TRY_STATUS(set_config(std::move(request.config_)));
|
||||
TRY_RESULT(config, validate_config(std::move(request.config_)));
|
||||
set_config(std::move(config));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -2020,6 +2120,84 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getState& request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
|
||||
td::Promise<object_ptr<tonlib_api::smc_runResult>>&& promise) {
|
||||
auto it = smcs_.find(request.id_);
|
||||
if (it == smcs_.end()) {
|
||||
return TonlibError::InvalidSmcId();
|
||||
}
|
||||
|
||||
td::Ref<ton::SmartContract> smc(true, it->second->get_smc_state());
|
||||
ton::SmartContract::Args args;
|
||||
downcast_call(*request.method_,
|
||||
td::overloaded([&](tonlib_api::smc_methodIdNumber& number) { args.set_method_id(number.number_); },
|
||||
[&](tonlib_api::smc_methodIdName& name) { args.set_method_id(name.name_); }));
|
||||
td::Ref<vm::Stack> stack(true);
|
||||
td::Status status;
|
||||
// TODO: error codes
|
||||
// downcast_call
|
||||
for (auto& entry : request.stack_) {
|
||||
downcast_call(*entry, td::overloaded(
|
||||
[&](tonlib_api::tvm_stackEntryUnsupported& cell) {
|
||||
status = td::Status::Error("Unsuppored stack entry");
|
||||
},
|
||||
[&](tonlib_api::tvm_stackEntrySlice& cell) {
|
||||
auto r_cell = vm::std_boc_deserialize(cell.slice_->bytes_);
|
||||
if (r_cell.is_error()) {
|
||||
status = r_cell.move_as_error();
|
||||
return;
|
||||
}
|
||||
stack.write().push_cell(r_cell.move_as_ok());
|
||||
},
|
||||
[&](tonlib_api::tvm_stackEntryCell& cell) {
|
||||
auto r_cell = vm::std_boc_deserialize(cell.cell_->bytes_);
|
||||
if (r_cell.is_error()) {
|
||||
status = r_cell.move_as_error();
|
||||
return;
|
||||
}
|
||||
stack.write().push_cell(r_cell.move_as_ok());
|
||||
},
|
||||
[&](tonlib_api::tvm_stackEntryNumber& number) {
|
||||
[&](tonlib_api::tvm_numberDecimal& dec) {
|
||||
auto num = td::dec_string_to_int256(dec.number_);
|
||||
if (num.is_null()) {
|
||||
status = td::Status::Error("Failed to parse dec string to int256");
|
||||
return;
|
||||
}
|
||||
stack.write().push_int(std::move(num));
|
||||
}(*number.number_);
|
||||
}));
|
||||
}
|
||||
TRY_STATUS(std::move(status));
|
||||
args.set_stack(std::move(stack));
|
||||
auto res = smc->run_get_method(std::move(args));
|
||||
|
||||
// smc.runResult gas_used:int53 stack:vector<tvm.StackEntry> exit_code:int32 = smc.RunResult;
|
||||
std::vector<object_ptr<tonlib_api::tvm_StackEntry>> res_stack;
|
||||
for (auto& entry : res.stack->as_span()) {
|
||||
switch (entry.type()) {
|
||||
case vm::StackEntry::Type::t_int:
|
||||
res_stack.push_back(tonlib_api::make_object<tonlib_api::tvm_stackEntryNumber>(
|
||||
tonlib_api::make_object<tonlib_api::tvm_numberDecimal>(dec_string(entry.as_int()))));
|
||||
break;
|
||||
case vm::StackEntry::Type::t_slice:
|
||||
res_stack.push_back(
|
||||
tonlib_api::make_object<tonlib_api::tvm_stackEntryCell>(tonlib_api::make_object<tonlib_api::tvm_cell>(
|
||||
to_bytes(vm::CellBuilder().append_cellslice(entry.as_slice()).finalize()))));
|
||||
break;
|
||||
case vm::StackEntry::Type::t_cell:
|
||||
res_stack.push_back(tonlib_api::make_object<tonlib_api::tvm_stackEntryCell>(
|
||||
tonlib_api::make_object<tonlib_api::tvm_cell>(to_bytes(entry.as_cell()))));
|
||||
break;
|
||||
default:
|
||||
res_stack.push_back(tonlib_api::make_object<tonlib_api::tvm_stackEntryUnsupported>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::sync& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
client_.with_last_block(to_any_promise(std::move(promise)));
|
||||
return td::Status::OK();
|
||||
|
@ -2146,13 +2324,25 @@ td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& reque
|
|||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryResult& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_, td::BufferSlice(request.bytes_),
|
||||
to_any_promise(std::move(promise)));
|
||||
if (ext_client_outbound_.empty()) {
|
||||
return TonlibError::InvalidQueryId();
|
||||
}
|
||||
if (((request.id_ ^ config_generation_) & 0xffff) != 0) {
|
||||
return TonlibError::InvalidQueryId();
|
||||
}
|
||||
send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_ >> 16,
|
||||
td::BufferSlice(request.bytes_), to_any_promise(std::move(promise)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryError& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_,
|
||||
if (ext_client_outbound_.empty()) {
|
||||
return TonlibError::InvalidQueryId();
|
||||
}
|
||||
if (((request.id_ ^ config_generation_) & 0xffff) != 0) {
|
||||
return TonlibError::InvalidQueryId();
|
||||
}
|
||||
send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_ >> 16,
|
||||
td::Status::Error(request.error_->code_, request.error_->message_)
|
||||
.move_as_error_prefix(TonlibError::LiteServerNetwork()),
|
||||
to_any_promise(std::move(promise)));
|
||||
|
@ -2306,6 +2496,11 @@ td::Status TonlibClient::do_request(const tonlib_api::unpackAccountAddress& requ
|
|||
return TonlibError::Internal();
|
||||
}
|
||||
template <class P>
|
||||
td::Status TonlibClient::do_request(const tonlib_api::options_validateConfig& request, P&&) {
|
||||
UNREACHABLE();
|
||||
return TonlibError::Internal();
|
||||
}
|
||||
template <class P>
|
||||
td::Status TonlibClient::do_request(tonlib_api::getBip39Hints& request, P&&) {
|
||||
UNREACHABLE();
|
||||
return TonlibError::Internal();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "td/actor/actor.h"
|
||||
|
||||
#include "td/utils/CancellationToken.h"
|
||||
#include "td/utils/optional.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
|
@ -87,7 +88,7 @@ class TonlibClient : public td::actor::Actor {
|
|||
|
||||
ExtClientRef get_client_ref();
|
||||
void init_ext_client();
|
||||
void init_last_block();
|
||||
void init_last_block(td::optional<Config> o_master_config);
|
||||
void init_last_config();
|
||||
|
||||
bool is_closing_{false};
|
||||
|
@ -125,6 +126,7 @@ class TonlibClient : public td::actor::Actor {
|
|||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::testGiver_getAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::packAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::unpackAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(tonlib_api::options_validateConfig& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(tonlib_api::getBip39Hints& request);
|
||||
|
||||
static object_ptr<tonlib_api::Object> do_static_request(tonlib_api::setLogStream& request);
|
||||
|
@ -155,6 +157,8 @@ class TonlibClient : public td::actor::Actor {
|
|||
template <class P>
|
||||
td::Status do_request(const tonlib_api::unpackAccountAddress& request, P&&);
|
||||
template <class P>
|
||||
td::Status do_request(const tonlib_api::options_validateConfig& request, P&&);
|
||||
template <class P>
|
||||
td::Status do_request(tonlib_api::getBip39Hints& request, P&&);
|
||||
|
||||
template <class P>
|
||||
|
@ -189,7 +193,14 @@ class TonlibClient : public td::actor::Actor {
|
|||
}
|
||||
}
|
||||
|
||||
td::Status set_config(object_ptr<tonlib_api::config> config);
|
||||
struct FullConfig {
|
||||
Config config;
|
||||
td::optional<Config> o_master_config;
|
||||
bool use_callbacks_for_network;
|
||||
bool ignore_cache;
|
||||
};
|
||||
static td::Result<FullConfig> validate_config(tonlib_api::object_ptr<tonlib_api::config> config);
|
||||
void set_config(FullConfig config);
|
||||
td::Status do_request(const tonlib_api::init& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(const tonlib_api::close& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(tonlib_api::options_setConfig& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
|
@ -288,6 +299,9 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Status do_request(const tonlib_api::smc_getState& request,
|
||||
td::Promise<object_ptr<tonlib_api::tvm_cell>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::smc_runGetMethod& request,
|
||||
td::Promise<object_ptr<tonlib_api::smc_runResult>>&& promise);
|
||||
|
||||
td::Status do_request(int_api::GetAccountState request, td::Promise<td::unique_ptr<AccountState>>&&);
|
||||
td::Status do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&&);
|
||||
td::Status do_request(int_api::SendMessage request, td::Promise<td::Unit>&& promise);
|
||||
|
|
|
@ -29,20 +29,21 @@
|
|||
// "help [<command>]\tThis help\n" // TODO: support [<command>]
|
||||
// "quit\tExit\n";
|
||||
// "sendfile <filename>\tLoad a serialized message from <filename> and send it to server\n"
|
||||
//
|
||||
// "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> <method-id> <params>...\tRuns GET method <method-id> of account <addr> "
|
||||
// "with specified parameters\n"
|
||||
//
|
||||
// "getaccount <addr> [<block-id-ext>]\tLoads the most recent state of specified account; <addr> is in "
|
||||
// "[<workchain>:]<hex-or-base64-addr> format\n"
|
||||
//
|
||||
// WONTSUPPORT
|
||||
//
|
||||
// UNSUPPORTED
|
||||
//"last\tGet last block and state info from server\n"
|
||||
//"status\tShow connection and local database status\n"
|
||||
//"getaccount <addr> [<block-id-ext>]\tLoads the most recent state of specified account; <addr> is in "
|
||||
//"[<workchain>:]<hex-or-base64-addr> format\n"
|
||||
//"(StateInit) or just the code or data of specified account; <addr> is in "
|
||||
//"[<workchain>:]<hex-or-base64-addr> format\n"
|
||||
//"allshards [<block-id-ext>]\tShows shard configuration from the most recent masterchain "
|
||||
//"state or from masterchain state corresponding to <block-id-ext>\n"
|
||||
//"getconfig [<param>...]\tShows specified or all configuration parameters from the latest masterchain state\n"
|
||||
|
@ -266,6 +267,8 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::TerminalIO::out() << "time\tGet server time\n";
|
||||
td::TerminalIO::out() << "remote-version\tShows server time, version and capabilities\n";
|
||||
td::TerminalIO::out() << "sendfile <filename>\tLoad a serialized message from <filename> and send it to server\n";
|
||||
td::TerminalIO::out() << "setconfig|validateconfig <path> [<name>] [<use_callback>] [<force>] - set or validate "
|
||||
"lite server config\n";
|
||||
td::TerminalIO::out() << "exit\tExit\n";
|
||||
td::TerminalIO::out() << "quit\tExit\n";
|
||||
td::TerminalIO::out()
|
||||
|
@ -279,7 +282,6 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n";
|
||||
td::TerminalIO::out() << "exportkey [<key_id>] - export key\n";
|
||||
td::TerminalIO::out() << "exportkeypem [<key_id>] - export key\n";
|
||||
td::TerminalIO::out() << "setconfig <path> [<name>] [<use_callback>] [<force>] - set lite server config\n";
|
||||
td::TerminalIO::out() << "getstate <key_id> - get state of simple wallet with requested key\n";
|
||||
td::TerminalIO::out()
|
||||
<< "gethistory <key_id> - get history fo simple wallet with requested key (last 10 transactions)\n";
|
||||
|
@ -305,12 +307,6 @@ class TonlibCli : public td::actor::Actor {
|
|||
export_key(cmd.str(), parser.read_word());
|
||||
} else if (cmd == "importkey") {
|
||||
import_key(parser.read_all());
|
||||
} else if (cmd == "setconfig") {
|
||||
auto config = parser.read_word();
|
||||
auto name = parser.read_word();
|
||||
auto use_callback = parser.read_word();
|
||||
auto force = parser.read_word();
|
||||
set_config(config, name, to_bool(use_callback), to_bool(force));
|
||||
} else if (cmd == "getstate") {
|
||||
get_state(parser.read_word());
|
||||
} else if (cmd == "gethistory") {
|
||||
|
@ -346,6 +342,14 @@ class TonlibCli : public td::actor::Actor {
|
|||
auto path = parser.read_word();
|
||||
auto address = parser.read_word();
|
||||
save_account(cmd, path, address, std::move(cmd_promise));
|
||||
} else if (cmd == "runmethod") {
|
||||
run_method(parser, std::move(cmd_promise));
|
||||
} else if (cmd == "setconfig" || cmd == "validateconfig") {
|
||||
auto config = parser.read_word();
|
||||
auto name = parser.read_word();
|
||||
auto use_callback = parser.read_word();
|
||||
auto force = parser.read_word();
|
||||
set_validate_config(cmd, config, name, to_bool(use_callback), to_bool(force), std::move(cmd_promise));
|
||||
} else {
|
||||
cmd_promise.set_error(td::Status::Error(PSLICE() << "Unkwnown query `" << cmd << "`"));
|
||||
}
|
||||
|
@ -419,6 +423,107 @@ class TonlibCli : public td::actor::Actor {
|
|||
return td::Unit();
|
||||
}));
|
||||
}
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::tvm_StackEntry>> parse_stack_entry(td::Slice str) {
|
||||
if (str.empty() || str.size() > 65535) {
|
||||
return td::Status::Error("String is or empty or too big");
|
||||
}
|
||||
int l = (int)str.size();
|
||||
if (str[0] == '"') {
|
||||
vm::CellBuilder cb;
|
||||
if (l == 1 || str.back() != '"' || l >= 127 + 2 || !cb.store_bytes_bool(str.data() + 1, l - 2)) {
|
||||
return td::Status::Error("Failed to parse slice");
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::tvm_stackEntrySlice>(
|
||||
tonlib_api::make_object<tonlib_api::tvm_slice>(vm::std_boc_serialize(cb.finalize()).ok().as_slice().str()));
|
||||
}
|
||||
if (l >= 3 && (str[0] == 'x' || str[0] == 'b') && str[1] == '{' && str.back() == '}') {
|
||||
unsigned char buff[128];
|
||||
int bits =
|
||||
(str[0] == 'x')
|
||||
? (int)td::bitstring::parse_bitstring_hex_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1)
|
||||
: (int)td::bitstring::parse_bitstring_binary_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1);
|
||||
if (bits < 0) {
|
||||
return td::Status::Error("Failed to parse slice");
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::tvm_stackEntrySlice>(tonlib_api::make_object<tonlib_api::tvm_slice>(
|
||||
vm::std_boc_serialize(vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize())
|
||||
.ok()
|
||||
.as_slice()
|
||||
.str()));
|
||||
}
|
||||
auto num = td::RefInt256{true};
|
||||
auto& x = num.unique_write();
|
||||
if (l >= 3 && str[0] == '0' && str[1] == 'x') {
|
||||
if (x.parse_hex(str.data() + 2, l - 2) != l - 2) {
|
||||
return td::Status::Error("Failed to parse a number");
|
||||
}
|
||||
} else if (l >= 4 && str[0] == '-' && str[1] == '0' && str[2] == 'x') {
|
||||
if (x.parse_hex(str.data() + 3, l - 3) != l - 3) {
|
||||
return td::Status::Error("Failed to parse a number");
|
||||
}
|
||||
x.negate().normalize();
|
||||
} else if (!l || x.parse_dec(str.data(), l) != l) {
|
||||
return td::Status::Error("Failed to parse a number");
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::tvm_stackEntryNumber>(
|
||||
tonlib_api::make_object<tonlib_api::tvm_numberDecimal>(dec_string(num)));
|
||||
}
|
||||
|
||||
void run_method(td::ConstParser& parser, td::Promise<td::Unit> promise) {
|
||||
TRY_RESULT_PROMISE(promise, addr, to_account_address(parser.read_word(), false));
|
||||
|
||||
auto method_str = parser.read_word();
|
||||
tonlib_api::object_ptr<tonlib_api::smc_MethodId> method;
|
||||
if (std::all_of(method_str.begin(), method_str.end(), [](auto c) { return c >= '0' && c <= '9'; })) {
|
||||
method = tonlib_api::make_object<tonlib_api::smc_methodIdNumber>(td::to_integer<td::int32>(method_str.str()));
|
||||
} else {
|
||||
method = tonlib_api::make_object<tonlib_api::smc_methodIdName>(method_str.str());
|
||||
}
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::tvm_StackEntry>> stack;
|
||||
while (true) {
|
||||
auto word = parser.read_word();
|
||||
if (word.empty()) {
|
||||
break;
|
||||
}
|
||||
TRY_RESULT_PROMISE(promise, stack_entry, parse_stack_entry(word));
|
||||
stack.push_back(std::move(stack_entry));
|
||||
}
|
||||
auto to_run =
|
||||
tonlib_api::make_object<tonlib_api::smc_runGetMethod>(0 /*fixme*/, std::move(method), std::move(stack));
|
||||
|
||||
send_query(tonlib_api::make_object<tonlib_api::smc_load>(std::move(addr.address)),
|
||||
promise.send_closure(actor_id(this), &TonlibCli::run_method_2, std::move(to_run)));
|
||||
}
|
||||
|
||||
void run_method_2(tonlib_api::object_ptr<tonlib_api::smc_runGetMethod> to_run,
|
||||
tonlib_api::object_ptr<tonlib_api::smc_info> info, td::Promise<td::Unit> promise) {
|
||||
to_run->id_ = info->id_;
|
||||
send_query(std::move(to_run), promise.send_closure(actor_id(this), &TonlibCli::run_method_3));
|
||||
}
|
||||
|
||||
void run_method_3(tonlib_api::object_ptr<tonlib_api::smc_runResult> info, td::Promise<td::Unit> promise) {
|
||||
td::TerminalIO::out() << "Got smc result " << to_string(info);
|
||||
promise.set_value({});
|
||||
}
|
||||
|
||||
void set_validate_config(td::Slice cmd, td::Slice path, td::Slice name, bool use_callback, bool ignore_cache,
|
||||
td::Promise<td::Unit> promise) {
|
||||
TRY_RESULT_PROMISE(promise, data, td::read_file_str(path.str()));
|
||||
using tonlib_api::make_object;
|
||||
|
||||
auto config = make_object<tonlib_api::config>(std::move(data), name.str(), use_callback, ignore_cache);
|
||||
if (cmd == "setconfig") {
|
||||
send_query(make_object<tonlib_api::options_setConfig>(std::move(config)), promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Config is set\n";
|
||||
return td::Unit();
|
||||
}));
|
||||
} else {
|
||||
send_query(make_object<tonlib_api::options_validateConfig>(std::move(config)), promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Config is valid\n";
|
||||
return td::Unit();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void dump_netstats() {
|
||||
td::TerminalIO::out() << td::tag("snd", td::format::as_size(snd_bytes_)) << "\n";
|
||||
|
@ -437,6 +542,8 @@ class TonlibCli : public td::actor::Actor {
|
|||
}
|
||||
}
|
||||
|
||||
td::Timestamp sync_started_;
|
||||
|
||||
void on_tonlib_result(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::Object> result) {
|
||||
if (id == 0) {
|
||||
switch (result->get_id()) {
|
||||
|
@ -455,10 +562,15 @@ class TonlibCli : public td::actor::Actor {
|
|||
auto update = tonlib_api::move_object_as<tonlib_api::updateSyncState>(std::move(result));
|
||||
switch (update->sync_state_->get_id()) {
|
||||
case tonlib_api::syncStateDone::ID: {
|
||||
td::TerminalIO::out() << "synchronization: DONE\n";
|
||||
td::TerminalIO::out() << "synchronization: DONE in "
|
||||
<< td::format::as_time(td::Time::now() - sync_started_.at()) << "\n";
|
||||
sync_started_ = {};
|
||||
break;
|
||||
}
|
||||
case tonlib_api::syncStateInProgress::ID: {
|
||||
if (!sync_started_) {
|
||||
sync_started_ = td::Timestamp::now();
|
||||
}
|
||||
auto progress = tonlib_api::move_object_as<tonlib_api::syncStateInProgress>(update->sync_state_);
|
||||
auto from = progress->from_seqno_;
|
||||
auto to = progress->to_seqno_;
|
||||
|
@ -857,26 +969,6 @@ class TonlibCli : public td::actor::Actor {
|
|||
});
|
||||
}
|
||||
|
||||
void set_config(td::Slice path, td::Slice name, bool use_callback, bool ignore_cache) {
|
||||
auto r_data = td::read_file_str(path.str());
|
||||
if (r_data.is_error()) {
|
||||
td::TerminalIO::out() << "Can't read file [" << path << "] : " << r_data.error() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = r_data.move_as_ok();
|
||||
using tonlib_api::make_object;
|
||||
send_query(make_object<tonlib_api::options_setConfig>(
|
||||
make_object<tonlib_api::config>(std::move(data), name.str(), use_callback, ignore_cache)),
|
||||
[](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't set config: " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
});
|
||||
}
|
||||
|
||||
void get_state(td::Slice key) {
|
||||
if (key.empty()) {
|
||||
dump_keys();
|
||||
|
|
|
@ -1843,7 +1843,9 @@ void ValidatorManagerImpl::allow_block_state_gc(BlockIdExt block_id, td::Promise
|
|||
}
|
||||
|
||||
void ValidatorManagerImpl::allow_block_info_gc(BlockIdExt block_id, td::Promise<bool> promise) {
|
||||
auto P =
|
||||
promise.set_result(false);
|
||||
return;
|
||||
/*auto P =
|
||||
td::PromiseCreator::lambda([db = db_.get(), promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_result(false);
|
||||
|
@ -1860,7 +1862,7 @@ void ValidatorManagerImpl::allow_block_info_gc(BlockIdExt block_id, td::Promise<
|
|||
}
|
||||
}
|
||||
});
|
||||
get_block_handle(block_id, false, std::move(P));
|
||||
get_block_handle(block_id, false, std::move(P));*/
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::got_next_gc_masterchain_handle(BlockHandle handle) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue