diff --git a/catchain/catchain-receiver.cpp b/catchain/catchain-receiver.cpp index 85f17498..7b8a6415 100644 --- a/catchain/catchain-receiver.cpp +++ b/catchain/catchain-receiver.cpp @@ -588,7 +588,7 @@ void CatChainReceiverImpl::read_db() { read_db_ = true; next_rotate_ = td::Timestamp::in(60 + td::Random::fast(0, 60)); - next_sync_ = td::Timestamp::in(0.01 * td::Random::fast(0, 60)); + next_sync_ = td::Timestamp::in(0.001 * td::Random::fast(0, 60)); alarm_timestamp().relax(next_rotate_); alarm_timestamp().relax(next_sync_); @@ -627,7 +627,7 @@ void CatChainReceiverImpl::receive_query_from_overlay(adnl::AdnlNodeIdShort src, promise.set_error(td::Status::Error(ErrorCode::notready, "db not read")); return; } - td::PerfWarningTimer t{"catchain query process", 0.001}; + td::PerfWarningTimer t{"catchain query process", 0.05}; auto F = fetch_tl_object(data.clone(), true); if (F.is_error()) { callback_->on_custom_query(get_source_by_adnl_id(src)->get_hash(), std::move(data), std::move(promise)); @@ -909,7 +909,7 @@ void CatChainReceiverImpl::choose_neighbours() { void CatChainReceiverImpl::alarm() { alarm_timestamp() = td::Timestamp::never(); if (next_sync_ && next_sync_.is_in_past()) { - next_sync_ = td::Timestamp::in(td::Random::fast(2.0, 3.0)); + next_sync_ = td::Timestamp::in(td::Random::fast(0.1, 0.2)); for (auto i = 0; i < 3; i++) { auto S = get_source(td::Random::fast(0, get_sources_cnt() - 1)); CHECK(S != nullptr); diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index c76de707..acf88eee 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -315,6 +315,8 @@ if (NOT CMAKE_CROSSCOMPILING) GenFif(DEST smartcont/config-code.fif SOURCE smartcont/config-code.fc) GenFif(DEST smartcont/wallet-code.fif SOURCE smartcont/wallet-code.fc) GenFif(DEST smartcont/simple-wallet-code.fif SOURCE smartcont/simple-wallet-code.fc) + GenFif(DEST smartcont/highload-wallet-code.fif SOURCE smartcont/highload-wallet-code.fc) + GenFif(DEST smartcont/highload-wallet-v2-code.fif SOURCE smartcont/highload-wallet-v2-code.fc) GenFif(DEST smartcont/elector-code.fif SOURCE smartcont/elector-code.fc) endif() @@ -333,3 +335,6 @@ target_link_libraries(dump-block PUBLIC ton_crypto fift-lib ton_block) if (WINGETOPT_FOUND) target_link_libraries_system(dump-block wingetopt) endif() + +install(TARGETS fift func RUNTIME DESTINATION bin) +install(DIRECTORY fift/lib/ DESTINATION lib/fift) diff --git a/crypto/parser/srcread.cpp b/crypto/parser/srcread.cpp index ac031e1e..3b363242 100644 --- a/crypto/parser/srcread.cpp +++ b/crypto/parser/srcread.cpp @@ -169,6 +169,11 @@ bool SourceReader::load_line() { error("line too long"); return false; } + if (len && cur_line.back() == '\r') { + // CP/M line breaks support + cur_line.pop_back(); + --len; + } loc.text = cur_line; cur_line_len = (int)len; loc.line_pos = 0; diff --git a/crypto/smartcont/highload-wallet-code.fc b/crypto/smartcont/highload-wallet-code.fc new file mode 100644 index 00000000..70abb48e --- /dev/null +++ b/crypto/smartcont/highload-wallet-code.fc @@ -0,0 +1,41 @@ +;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges) +;; accepts orders for up to 254 internal messages (transfers) in one external message + +() 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)); + var dict = cs~load_dict(); + cs.end_parse(); + accept_message(); + int i = -1; + do { + (i, var cs, var f) = dict.idict_get_next?(16, i); + if (f) { + var mode = cs~load_uint(8); + send_raw_message(cs~load_ref(), mode); + } + } until (~ f); + 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); +} diff --git a/crypto/smartcont/highload-wallet-v2-code.fc b/crypto/smartcont/highload-wallet-v2-code.fc new file mode 100644 index 00000000..88d78855 --- /dev/null +++ b/crypto/smartcont/highload-wallet-v2-code.fc @@ -0,0 +1,65 @@ +;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges) +;; accepts orders for up to 254 internal messages (transfers) in one external message +;; this version does not use seqno for replay protection; instead, it remembers all recent query_ids +;; in this way several external messages with different query_id can be sent in parallel + +() 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, query_id) = (cs~load_uint(32), cs~load_uint(64)); + var bound = (now() << 32); + throw_if(35, query_id < bound); + var ds = get_data().begin_parse(); + var (stored_subwallet, last_cleaned, public_key, old_queries) = (ds~load_uint(32), ds~load_uint(64), ds~load_uint(256), ds~load_dict()); + ds.end_parse(); + (_, var found?) = old_queries.udict_get?(64, query_id); + throw_if(32, found?); + throw_unless(34, subwallet_id == stored_subwallet); + throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key)); + var dict = cs~load_dict(); + cs.end_parse(); + accept_message(); + int i = -1; + do { + (i, var cs, var f) = dict.idict_get_next?(16, i); + if (f) { + var mode = cs~load_uint(8); + send_raw_message(cs~load_ref(), mode); + } + } until (~ f); + bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago + old_queries~udict_set_builder(64, query_id, begin_cell()); + var queries = old_queries; + do { + var (old_queries', i, _, f) = old_queries.udict_delete_get_min(64); + f~touch(); + if (f) { + f = (i < bound); + } + if (f) { + old_queries = old_queries'; + last_cleaned = i; + } + } until (~ f); + set_data(begin_cell() + .store_uint(stored_subwallet, 32) + .store_uint(last_cleaned, 64) + .store_uint(public_key, 256) + .store_dict(old_queries) + .end_cell()); +} + +;; Get methods + +;; returns -1 for processed queries, 0 for unprocessed, 1 for unknown (forgotten) +int processed?(int query_id) method_id { + var ds = get_data().begin_parse(); + var (_, last_cleaned, _, old_queries) = (ds~load_uint(32), ds~load_uint(64), ds~load_uint(256), ds~load_dict()); + ds.end_parse(); + (_, var found) = old_queries.udict_get?(64, query_id); + return found ? true : - (query_id <= last_cleaned); +} diff --git a/crypto/smartcont/highload-wallet.fif b/crypto/smartcont/highload-wallet.fif new file mode 100644 index 00000000..58ebda06 --- /dev/null +++ b/crypto/smartcont/highload-wallet.fif @@ -0,0 +1,68 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a request with up to 254 orders loaded from to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file .pk " + ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr + ." is a text file with lines `SEND `" cr 1 halt +} : usage +$# dup 4 < swap 5 > or ' usage if + +$1 =: file-base +$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id +{ subwallet-id (.) $+ } : +subwallet +$3 parse-int =: seqno +$4 =: order-file +def? $5 { @' $5 } { "wallet-query" } cond constant savefile +3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +60 constant timeout // external message expires in 60 seconds + +file-base +subwallet +".addr" load-address +2dup 2constant wallet_addr +."Source wallet address = " 2dup .addr cr 6 .Addr cr +file-base +".pk" load-keypair nip constant wallet_pk + +variable orders dictnew orders ! +variable order# order# 0! +// c -- +{ = abort"more than 254 orders" + orders @ 16 udict!+ not abort"cannot add order to dictionary" + orders ! order# 1+! +} : add-order +// b body -- b' +{ tuck +} : create-int-msg +// ng wc addr bnc -- +{ ."Transferring " 3 roll .GR ."to account " + -rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr +} : .transfer +// addr$ ng -- c +{ swap parse-smc-addr // ng wc addr bnc + 2over 2over .transfer + create-int-msg +} : create-simple-transfer +// c m -- c' +{ } : create-order + +// addr$ ng -- +{ create-simple-transfer send-mode create-order add-order } : send +{ bl word bl word $>GR send } : SEND + +// parse order file +order-file include + +// create external message + +dup ."signing message: " +dup ."resulting external message: " B dup Bx. cr +savefile +".boc" tuck B>file +."(Saved to file " type .")" cr diff --git a/crypto/smartcont/new-highload-wallet.fif b/crypto/smartcont/new-highload-wallet.fif new file mode 100644 index 00000000..b7a1a1db --- /dev/null +++ b/crypto/smartcont/new-highload-wallet.fif @@ -0,0 +1,44 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a new high-load wallet in the specified workchain, with the controlling private key saved to or loaded from .pk " + ."('new-wallet.pk' by default)" cr + ." is the 32-bit identifier of this subwallet among all controlled by the same private key" cr 1 halt +} : usage +$# 2- -2 and ' usage if + +$1 parse-workchain-id =: wc // set workchain id from command line argument +$2 parse-int dup =: subwallet-id // parse subwallet-id +32 fits ' usage ifnot +{ subwallet-id (.) $+ } : +subwallet +def? $3 { @' $3 } { "new-wallet" } cond constant file-base + +."Creating new high-load wallet in workchain " wc . +."with subwallet id " subwallet-id . cr + +// Create new high-load wallet; source code included from `highload-wallet-code.fif` +"highload-wallet-code.fif" include +// code + // data +null // no libraries + // create StateInit +dup ."StateInit: " +dup ."signing message: " +dup ."External message for initialization is " B dup Bx. cr +file-base +subwallet +"-query.boc" tuck B>file +."(Saved wallet creating query to file " type .")" cr diff --git a/crypto/smartcont/stdlib.fc b/crypto/smartcont/stdlib.fc index 4fb30bdd..fb9b49f5 100644 --- a/crypto/smartcont/stdlib.fc +++ b/crypto/smartcont/stdlib.fc @@ -86,6 +86,8 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va (cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; (int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; (int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; cell new_dict() asm "NEWDICT"; int dict_empty?(cell c) asm "DICTEMPTY"; diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index 07a2f32c..3729d3f3 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -16,8 +16,12 @@ vector {t:Type} # [ t ] = Vector t; error code:int32 message:string = Error; ok = Ok; +keyStoreTypeDirectory directory:string = KeyStoreType; +keyStoreTypeInMemory = KeyStoreType; + config config:string blockchain_name:string use_callbacks_for_network:Bool ignore_cache:Bool = Config; -options config:config keystore_directory:string = Options; + +options config:config keystore_type:KeyStoreType = Options; key public_key:string secret:secureBytes = Key; inputKey key:key local_password:secureBytes = InputKey; @@ -37,7 +41,7 @@ raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState; raw.message source:string destination:string value:int64 message:bytes = raw.Message; raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; -raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; +raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; testWallet.initialAccountState public_key:string = testWallet.InitialAccountState; testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = testWallet.AccountState; diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index b77565e0..a88c1fd1 100644 Binary files a/tl/generate/scheme/tonlib_api.tlo and b/tl/generate/scheme/tonlib_api.tlo differ diff --git a/tonlib/CMakeLists.txt b/tonlib/CMakeLists.txt index 38677796..a46f3d3c 100644 --- a/tonlib/CMakeLists.txt +++ b/tonlib/CMakeLists.txt @@ -5,6 +5,7 @@ if (NOT OPENSSL_FOUND) endif() set(TONLIB_SOURCE + tonlib/CellString.cpp tonlib/Client.cpp tonlib/Config.cpp tonlib/ExtClient.cpp @@ -12,6 +13,7 @@ set(TONLIB_SOURCE tonlib/ExtClientOutbound.cpp tonlib/GenericAccount.cpp tonlib/KeyStorage.cpp + tonlib/KeyValue.cpp tonlib/LastBlock.cpp tonlib/LastBlockStorage.cpp tonlib/Logging.cpp @@ -21,6 +23,7 @@ set(TONLIB_SOURCE tonlib/utils.cpp tonlib/Wallet.cpp + tonlib/CellString.h tonlib/Client.h tonlib/Config.h tonlib/ExtClient.h @@ -28,6 +31,7 @@ set(TONLIB_SOURCE tonlib/ExtClientOutbound.h tonlib/GenericAccount.h tonlib/KeyStorage.h + tonlib/KeyValue.h tonlib/LastBlock.h tonlib/LastBlockStorage.h tonlib/Logging.h diff --git a/tonlib/TonlibConfig.cmake b/tonlib/TonlibConfig.cmake new file mode 100644 index 00000000..5f3a33eb --- /dev/null +++ b/tonlib/TonlibConfig.cmake @@ -0,0 +1,3 @@ +include(CMakeFindDependencyMacro) +#TODO: write all external dependencies +include("${CMAKE_CURRENT_LIST_DIR}/TonlibTargets.cmake") diff --git a/tonlib/test/offline.cpp b/tonlib/test/offline.cpp index 63a52fae..d6f6d92c 100644 --- a/tonlib/test/offline.cpp +++ b/tonlib/test/offline.cpp @@ -28,6 +28,7 @@ #include "vm/boc.h" #include "vm/cells/MerkleProof.h" +#include "tonlib/CellString.h" #include "tonlib/utils.h" #include "tonlib/TestGiver.h" #include "tonlib/TestWallet.h" @@ -53,6 +54,20 @@ #include "tonlib/keys/Mnemonic.h" #include "tonlib/keys/SimpleEncryption.h" +TEST(Tonlib, CellString) { + for (unsigned size : + {0, 1, 7, 8, 35, 127, 128, 255, 256, (int)vm::CellString::max_bytes - 1, (int)vm::CellString::max_bytes}) { + auto str = td::rand_string('a', 'z', size); + for (unsigned head : {0, 1, 7, 8, 127, 35 * 8, 127 * 8, 1023, 1024}) { + vm::CellBuilder cb; + vm::CellString::store(cb, str, head).ensure(); + auto cs = vm::load_cell_slice(cb.finalize()); + auto got_str = vm::CellString::load(cs, head).move_as_ok(); + ASSERT_EQ(str, got_str); + } + } +}; + using namespace tonlib; std::string current_dir() { @@ -268,20 +283,23 @@ static auto sync_send = [](auto &client, auto query) { TEST(Tonlib, InitClose) { using tonlib_api::make_object; auto cfg = [](auto str) { return make_object(str, "", false, false); }; + auto dir = [](auto str) { return make_object(str); }; { Client client; sync_send(client, make_object()).ensure(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure_error(); + sync_send(client, make_object(make_object(nullptr, dir(".")))) + .ensure_error(); } { Client client; sync_send(client, make_object(nullptr)).ensure_error(); - sync_send(client, make_object(make_object(cfg("fdajkfldsjkafld"), "."))) + sync_send(client, make_object(make_object(cfg("fdajkfldsjkafld"), dir(".")))) .ensure_error(); - sync_send(client, make_object(make_object(nullptr, "fdhskfds"))) + sync_send(client, make_object(make_object(nullptr, dir("fdhskfds")))) + .ensure_error(); + sync_send(client, make_object(make_object(nullptr, dir(".")))).ensure(); + sync_send(client, make_object(make_object(nullptr, dir(".")))) .ensure_error(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure_error(); td::Slice bad_config = R"abc( { @@ -294,7 +312,8 @@ TEST(Tonlib, InitClose) { sync_send(client, make_object()).ensure_error(); sync_send(client, make_object()).ensure(); sync_send(client, make_object()).ensure_error(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure_error(); + sync_send(client, make_object(make_object(nullptr, dir(".")))) + .ensure_error(); } } @@ -389,7 +408,9 @@ TEST(Tonlib, ParseAddres) { Client client; // init - sync_send(client, make_object(make_object(nullptr, "."))).ensure(); + sync_send(client, make_object( + make_object(nullptr, make_object(".")))) + .ensure(); sync_send(client, make_object("hello")).ensure_error(); auto addr = @@ -409,7 +430,9 @@ TEST(Tonlib, KeysApi) { Client client; // init - sync_send(client, make_object(make_object(nullptr, "."))).ensure(); + sync_send(client, make_object( + make_object(nullptr, make_object(".")))) + .ensure(); auto local_password = td::SecureString("local password"); auto mnemonic_password = td::SecureString("mnemonic password"); { diff --git a/tonlib/test/online.cpp b/tonlib/test/online.cpp index 0425f537..6ac47921 100644 --- a/tonlib/test/online.cpp +++ b/tonlib/test/online.cpp @@ -197,7 +197,8 @@ int main(int argc, char* argv[]) { Client client; { sync_send(client, make_object(make_object( - make_object(global_config_str, "", false, false), "."))) + make_object(global_config_str, "", false, false), + make_object(".")))) .ensure(); } //dump_transaction_history(client, get_test_giver_address(client)); @@ -211,7 +212,8 @@ int main(int argc, char* argv[]) { { // init sync_send(client, make_object(make_object( - make_object(global_config_str, "", false, false), "."))) + make_object(global_config_str, "", false, false), + make_object(".")))) .ensure(); auto key = sync_send(client, make_object( diff --git a/tonlib/tonlib/CellString.cpp b/tonlib/tonlib/CellString.cpp new file mode 100644 index 00000000..ad2cbf5f --- /dev/null +++ b/tonlib/tonlib/CellString.cpp @@ -0,0 +1,64 @@ +#include "CellString.h" +#include "td/utils/misc.h" + +#include "vm/cells/CellSlice.h" + +namespace vm { +td::Status CellString::store(CellBuilder &cb, td::Slice slice, unsigned int top_bits) { + td::uint32 size = td::narrow_cast(slice.size() * 8); + return store(cb, td::BitSlice(slice.ubegin(), size), top_bits); +} + +td::Status CellString::store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits) { + if (slice.size() > max_bytes * 8) { + return td::Status::Error("String is too long (1)"); + } + unsigned int head = td::min(slice.size(), td::min(cb.remaining_bits(), top_bits)) / 8 * 8; + auto max_bits = vm::Cell::max_bits / 8 * 8; + auto depth = 1 + (slice.size() - head + max_bits - 1) / max_bits; + if (depth > max_chain_length) { + return td::Status::Error("String is too long (2)"); + } + cb.append_bitslice(slice.subslice(0, head)); + slice.advance(head); + if (slice.size() == 0) { + return td::Status::OK(); + } + CellBuilder child_cb; + store(child_cb, std::move(slice)); + cb.store_ref(child_cb.finalize()); + return td::Status::OK(); +} + +template +void CellString::for_each(F &&f, CellSlice &cs, unsigned int top_bits) { + unsigned int head = td::min(cs.size(), top_bits); + f(cs.prefetch_bits(head)); + if (!cs.have_refs()) { + return; + } + auto ref = cs.prefetch_ref(); + while (true) { + auto cs = vm::load_cell_slice(ref); + f(cs.prefetch_bits(cs.size())); + if (!cs.have_refs()) { + return; + } + ref = cs.prefetch_ref(); + } +} + +td::Result CellString::load(CellSlice &cs, unsigned int top_bits) { + unsigned int size = 0; + for_each([&](auto slice) { size += slice.size(); }, cs, top_bits); + if (size % 8 != 0) { + return td::Status::Error("Size is not divisible by 8"); + } + std::string res(size / 8, 0); + + td::BitPtr to(td::MutableSlice(res).ubegin()); + for_each([&](auto slice) { to.concat(slice); }, cs, top_bits); + CHECK(to.offs == (int)size); + return res; +} +} // namespace vm diff --git a/tonlib/tonlib/CellString.h b/tonlib/tonlib/CellString.h new file mode 100644 index 00000000..89c933d8 --- /dev/null +++ b/tonlib/tonlib/CellString.h @@ -0,0 +1,22 @@ +#pragma once + +#include "td/utils/Status.h" + +#include "vm/cells/CellBuilder.h" + +namespace vm { +class CellString { + public: + static constexpr unsigned int max_bytes = 1024; + static constexpr unsigned int max_chain_length = 16; + + static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits); + static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits); + static td::Result load(CellSlice &cs, unsigned int top_bits = Cell::max_bits); + + private: + template + static void for_each(F &&f, CellSlice &cs, unsigned int top_bits = Cell::max_bits); +}; + +} // namespace vm diff --git a/tonlib/tonlib/KeyStorage.cpp b/tonlib/tonlib/KeyStorage.cpp index 6137c0e3..8703a3ef 100644 --- a/tonlib/tonlib/KeyStorage.cpp +++ b/tonlib/tonlib/KeyStorage.cpp @@ -27,29 +27,18 @@ #include "td/utils/crypto.h" namespace tonlib { +namespace { std::string to_file_name_old(const KeyStorage::Key &key) { return td::buffer_to_hex(key.public_key); } -std::string KeyStorage::to_file_path_old(const Key &key) { - return directory_ + TD_DIR_SLASH + to_file_name_old(key); -} - std::string to_file_name(const KeyStorage::Key &key) { return td::buffer_to_hex(td::sha512(key.secret.as_slice()).substr(0, 32)); } +} // namespace -std::string KeyStorage::to_file_path(const Key &key) { - return directory_ + TD_DIR_SLASH + to_file_name(key); -} -td::Status KeyStorage::set_directory(std::string directory) { - TRY_RESULT(path, td::realpath(directory)); - TRY_RESULT(stat, td::stat(path)); - if (!stat.is_dir_) { - return td::Status::Error("not a directory"); - } - directory_ = std::move(path); - return td::Status::OK(); +void KeyStorage::set_key_value(std::shared_ptr kv) { + kv_ = std::move(kv); } td::Result KeyStorage::save_key(const DecryptedKey &decrypted_key, td::Slice local_password) { @@ -58,17 +47,7 @@ td::Result KeyStorage::save_key(const DecryptedKey &decrypted_k Key res; res.public_key = encrypted_key.public_key.as_octet_string(); res.secret = std::move(encrypted_key.secret); - - auto size = encrypted_key.encrypted_data.size(); - - LOG(ERROR) << "SAVE " << to_file_name(res); - TRY_RESULT(to_file, td::FileFd::open(to_file_path(res), td::FileFd::CreateNew | td::FileFd::Write)); - TRY_RESULT(written, to_file.write(encrypted_key.encrypted_data)); - if (written != static_cast(size)) { - return td::Status::Error(PSLICE() << "Failed to write file: written " << written << " bytes instead of " << size); - } - to_file.close(); - + TRY_STATUS(kv_->set(to_file_name(res), encrypted_key.encrypted_data)); return std::move(res); } @@ -83,13 +62,14 @@ td::Result KeyStorage::create_new_key(td::Slice local_password, } td::Result KeyStorage::export_decrypted_key(InputKey input_key) { - auto r_encrypted_data = td::read_file_secure(to_file_path(input_key.key)); + auto r_encrypted_data = kv_->get(to_file_name(input_key.key)); if (r_encrypted_data.is_error()) { - r_encrypted_data = td::read_file_secure(to_file_path_old(input_key.key)); + r_encrypted_data = kv_->get(to_file_name_old(input_key.key)); if (r_encrypted_data.is_ok()) { - LOG(WARNING) << "Restore private from deprecated location " << to_file_path_old(input_key.key) << " --> " - << to_file_path(input_key.key); - td::rename(to_file_path_old(input_key.key), to_file_path(input_key.key)).ignore(); + LOG(WARNING) << "Restore private from deprecated location " << to_file_name_old(input_key.key) << " --> " + << to_file_name(input_key.key); + TRY_STATUS(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok())); + kv_->erase(to_file_name_old(input_key.key)).ignore(); } } TRY_RESULT(encrypted_data, std::move(r_encrypted_data)); @@ -113,7 +93,7 @@ td::Result KeyStorage::load_private_key(InputKey input_k } td::Status KeyStorage::delete_key(const Key &key) { - return td::unlink(to_file_path(key)); + return kv_->erase(to_file_name(key)); } td::Result KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password, @@ -140,7 +120,8 @@ td::Result KeyStorage::change_local_password(InputKey input_key Key res; res.public_key = std::move(input_key.key.public_key); res.secret = std::move(new_secret); - TRY_STATUS(td::copy_file(to_file_path(input_key.key), to_file_path(res))); + TRY_RESULT(value, kv_->get(to_file_name(input_key.key))); + TRY_STATUS(kv_->add(to_file_name(res), value)); return std::move(res); } diff --git a/tonlib/tonlib/KeyStorage.h b/tonlib/tonlib/KeyStorage.h index f7982805..fbde2a32 100644 --- a/tonlib/tonlib/KeyStorage.h +++ b/tonlib/tonlib/KeyStorage.h @@ -21,6 +21,8 @@ #include "td/utils/Status.h" #include "td/utils/SharedSlice.h" +#include "KeyValue.h" + #include namespace tonlib { @@ -48,7 +50,7 @@ class KeyStorage { td::SecureString private_key; }; - td::Status set_directory(std::string directory); + void set_key_value(std::shared_ptr kv); td::Result create_new_key(td::Slice local_password, td::Slice key_password, td::Slice entropy); @@ -67,12 +69,9 @@ class KeyStorage { td::Result load_private_key(InputKey input_key); private: - std::string directory_; + std::shared_ptr kv_; td::Result save_key(const DecryptedKey& mnemonic, td::Slice local_password); td::Result export_decrypted_key(InputKey input_key); - - std::string to_file_path(const Key& key); - std::string to_file_path_old(const Key& key); }; } // namespace tonlib diff --git a/tonlib/tonlib/KeyValue.cpp b/tonlib/tonlib/KeyValue.cpp new file mode 100644 index 00000000..fa2f8ae3 --- /dev/null +++ b/tonlib/tonlib/KeyValue.cpp @@ -0,0 +1,103 @@ +#include "KeyValue.h" + +#include "td/utils/filesystem.h" +#include "td/utils/port/path.h" + +#include +#include + +namespace tonlib { +namespace detail { +class KeyValueDir : public KeyValue { + public: + static td::Result> create(td::CSlice directory) { + TRY_RESULT(path, td::realpath(directory)); + TRY_RESULT(stat, td::stat(path)); + if (!stat.is_dir_) { + return td::Status::Error("not a directory"); + } + return td::make_unique(path); + } + + KeyValueDir(std::string directory) : directory_(std::move(directory)) { + } + + td::Status add(td::Slice key, td::Slice value) override { + auto path = to_file_path(key.str()); + if (td::stat(path).is_ok()) { + return td::Status::Error(PSLICE() << "File " << path << "already exists"); + } + return td::atomic_write_file(path, value); + } + + td::Status set(td::Slice key, td::Slice value) override { + return td::atomic_write_file(to_file_path(key.str()), value); + } + + td::Result get(td::Slice key) override { + return td::read_file_secure(to_file_path(key.str())); + } + + td::Status erase(td::Slice key) override { + return td::unlink(key.str()); + } + + private: + std::string directory_; + + std::string to_file_path(std::string key) { + return directory_ + TD_DIR_SLASH + key; + } +}; + +class KeyValueInmemory : public KeyValue { + public: + td::Status add(td::Slice key, td::Slice value) override { + auto res = map_.insert(std::make_pair(key.str(), td::SecureString(value))); + if (!res.second) { + return td::Status::Error(PSLICE() << "Add failed: value with key=`" << key << "` already exists"); + } + return td::Status::OK(); + } + + td::Status set(td::Slice key, td::Slice value) override { + map_[key.str()] = td::SecureString(value); + return td::Status::OK(); + } + td::Result get(td::Slice key) override { + auto it = map_.find(key); + if (it == map_.end()) { + return td::Status::Error("Unknown key"); + } + return it->second.copy(); + } + static td::Result> create() { + return td::make_unique(); + } + td::Status erase(td::Slice key) override { + auto it = map_.find(key); + if (it == map_.end()) { + return td::Status::Error("Unknown key"); + } + map_.erase(it); + return td::Status::OK(); + } + + private: + class Cmp : public std::less<> { + public: + using is_transparent = void; + }; + std::map map_; +}; +} // namespace detail + +td::Result> KeyValue::create_dir(td::CSlice dir) { + TRY_RESULT(res, detail::KeyValueDir::create(dir.str())); + return std::move(res); +} +td::Result> KeyValue::create_inmemory() { + TRY_RESULT(res, detail::KeyValueInmemory::create()); + return std::move(res); +} +} // namespace tonlib diff --git a/tonlib/tonlib/KeyValue.h b/tonlib/tonlib/KeyValue.h new file mode 100644 index 00000000..6ccd929f --- /dev/null +++ b/tonlib/tonlib/KeyValue.h @@ -0,0 +1,18 @@ +#pragma once +#include "td/utils/SharedSlice.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" + +namespace tonlib { +class KeyValue { + public: + virtual ~KeyValue() = default; + virtual td::Status add(td::Slice key, td::Slice value) = 0; + virtual td::Status set(td::Slice key, td::Slice value) = 0; + virtual td::Status erase(td::Slice key) = 0; + virtual td::Result get(td::Slice key) = 0; + + static td::Result> create_dir(td::CSlice dir); + static td::Result> create_inmemory(); +}; +} // namespace tonlib diff --git a/tonlib/tonlib/LastBlockStorage.cpp b/tonlib/tonlib/LastBlockStorage.cpp index 684b2c05..f25632c0 100644 --- a/tonlib/tonlib/LastBlockStorage.cpp +++ b/tonlib/tonlib/LastBlockStorage.cpp @@ -25,22 +25,18 @@ namespace tonlib { -td::Status LastBlockStorage::set_directory(std::string directory) { - TRY_RESULT(path, td::realpath(directory)); - TRY_RESULT(stat, td::stat(path)); - if (!stat.is_dir_) { - return td::Status::Error("not a directory"); - } - directory_ = std::move(path); - return td::Status::OK(); +void LastBlockStorage::set_key_value(std::shared_ptr kv) { + kv_ = std::move(kv); } -std::string LastBlockStorage::get_file_name(td::Slice name) { - return directory_ + TD_DIR_SLASH + td::buffer_to_hex(name) + ".blkstate"; +namespace { +std::string get_file_name(td::Slice name) { + return td::buffer_to_hex(name) + ".blkstate"; } +} // namespace td::Result LastBlockStorage::get_state(td::Slice name) { - TRY_RESULT(data, td::read_file(get_file_name(name))); + TRY_RESULT(data, kv_->get(get_file_name(name))); if (data.size() < 8) { return td::Status::Error("too short"); } @@ -57,6 +53,6 @@ void LastBlockStorage::save_state(td::Slice name, LastBlockState state) { std::string y(x.size() + 8, 0); td::MutableSlice(y).substr(8).copy_from(x); td::as(td::MutableSlice(y).data()) = td::crc64(x); - td::atomic_write_file(get_file_name(name), y); + kv_->set(get_file_name(name), y); } } // namespace tonlib diff --git a/tonlib/tonlib/LastBlockStorage.h b/tonlib/tonlib/LastBlockStorage.h index d8cbd3fc..df5dd12c 100644 --- a/tonlib/tonlib/LastBlockStorage.h +++ b/tonlib/tonlib/LastBlockStorage.h @@ -20,15 +20,16 @@ #include "tonlib/LastBlock.h" +#include "tonlib/KeyValue.h" + namespace tonlib { class LastBlockStorage { public: - td::Status set_directory(std::string directory); + void set_key_value(std::shared_ptr kv); td::Result get_state(td::Slice name); void save_state(td::Slice name, LastBlockState state); private: - std::string directory_; - std::string get_file_name(td::Slice name); + std::shared_ptr kv_; }; } // namespace tonlib diff --git a/tonlib/tonlib/TestGiver.cpp b/tonlib/tonlib/TestGiver.cpp index 50c68571..17c36a55 100644 --- a/tonlib/tonlib/TestGiver.cpp +++ b/tonlib/tonlib/TestGiver.cpp @@ -34,7 +34,6 @@ vm::CellHash TestGiver::get_init_code_hash() { td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, const block::StdAddress& dest_address) { - CHECK(message.size() <= 124); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -45,7 +44,9 @@ td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize(); + cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); } } // namespace tonlib diff --git a/tonlib/tonlib/TestGiver.h b/tonlib/tonlib/TestGiver.h index 6859be8f..a5d8b79c 100644 --- a/tonlib/tonlib/TestGiver.h +++ b/tonlib/tonlib/TestGiver.h @@ -18,9 +18,11 @@ */ #pragma once #include "block/block.h" +#include "CellString.h" namespace tonlib { class TestGiver { public: + static constexpr unsigned max_message_size = vm::CellString::max_bytes; static const block::StdAddress& address(); static vm::CellHash get_init_code_hash(); static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, diff --git a/tonlib/tonlib/TestWallet.cpp b/tonlib/tonlib/TestWallet.cpp index 022eaca9..dadb1748 100644 --- a/tonlib/tonlib/TestWallet.cpp +++ b/tonlib/tonlib/TestWallet.cpp @@ -40,7 +40,6 @@ td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, td::int64 gramms, td::Slice message, const block::StdAddress& dest_address) { - CHECK(message.size() <= 124); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -50,7 +49,9 @@ td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& .store_long(dest_address.workchain, 8) .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize(); + cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); td::int8 send_mode = 3; auto message_outer = vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize(); diff --git a/tonlib/tonlib/TestWallet.h b/tonlib/tonlib/TestWallet.h index 921e3b3a..28c97ce1 100644 --- a/tonlib/tonlib/TestWallet.h +++ b/tonlib/tonlib/TestWallet.h @@ -21,10 +21,12 @@ #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" +#include "CellString.h" namespace tonlib { class TestWallet { public: + static constexpr unsigned max_message_size = vm::CellString::max_bytes; static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key); static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key); static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index d0a9cba7..7a7e1d8d 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -547,8 +547,21 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request, if (!request.options_) { return td::Status::Error(400, "Field options must not be empty"); } - TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_)); - TRY_STATUS(last_block_storage_.set_directory(request.options_->keystore_directory_)); + if (!request.options_->keystore_type_) { + return td::Status::Error(400, "Field options.keystore_type must not be empty"); + } + + td::Result> r_kv; + downcast_call( + *request.options_->keystore_type_, + td::overloaded( + [&](tonlib_api::keyStoreTypeDirectory& directory) { r_kv = KeyValue::create_dir(directory.directory_); }, + [&](tonlib_api::keyStoreTypeInMemory& inmemory) { r_kv = KeyValue::create_inmemory(); })); + TRY_RESULT(kv, std::move(r_kv)); + kv_ = std::shared_ptr(kv.release()); + + 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_))); } @@ -672,12 +685,11 @@ td::Result> to_raw_message_or_th body = vm::load_cell_slice_ref(message.body->prefetch_ref()); } std::string body_message; - if (body->size() % 8 == 0) { - body_message = std::string(body->size() / 8, 0); - body->prefetch_bytes(td::MutableSlice(body_message).ubegin(), body->size() / 8); - if (body_message.size() >= 4 && body_message[0] == 0 && body_message[1] == 0 && body_message[2] == 0 && - body_message[3] == 0) { - body_message = body_message.substr(4); + if (body->size() >= 32 && body->prefetch_long(32) == 0) { + body.write().fetch_long(32); + auto r_body_message = vm::CellString::load(body.write()); + if (r_body_message.is_ok()) { + body_message = r_body_message.move_as_ok(); } } @@ -955,7 +967,7 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ if (!request.private_key_) { return td::Status::Error(400, "Field private_key must not be empty"); } - if (request.message_.size() > 70) { + if (request.message_.size() > TestWallet::max_message_size) { return td::Status::Error(400, "Message is too long"); } TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); @@ -1033,7 +1045,7 @@ td::Status TonlibClient::do_request(const tonlib_api::wallet_sendGrams& request, if (!request.private_key_) { return td::Status::Error(400, "Field private_key must not be empty"); } - if (request.message_.size() > 70) { + if (request.message_.size() > Wallet::max_message_size) { return td::Status::Error(400, "Message is too long"); } TRY_RESULT(valid_until, td::narrow_cast_safe(request.valid_until_)); @@ -1092,7 +1104,7 @@ td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& reque if (!request.destination_) { return td::Status::Error(400, "Field destination must not be empty"); } - if (request.message_.size() > 70) { + if (request.message_.size() > TestGiver::max_message_size) { return td::Status::Error(400, "Message is too long"); } TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); diff --git a/tonlib/tonlib/TonlibClient.h b/tonlib/tonlib/TonlibClient.h index 9e7ecdaf..90063551 100644 --- a/tonlib/tonlib/TonlibClient.h +++ b/tonlib/tonlib/TonlibClient.h @@ -24,6 +24,7 @@ #include "tonlib/ExtClient.h" #include "tonlib/ExtClientOutbound.h" #include "tonlib/KeyStorage.h" +#include "tonlib/KeyValue.h" #include "tonlib/LastBlockStorage.h" #include "td/actor/actor.h" @@ -55,6 +56,7 @@ class TonlibClient : public td::actor::Actor { td::actor::ActorId ext_client_outbound_; // KeyStorage + std::shared_ptr kv_; KeyStorage key_storage_; LastBlockStorage last_block_storage_; diff --git a/tonlib/tonlib/Wallet.cpp b/tonlib/tonlib/Wallet.cpp index 7546e8fd..dbd12d25 100644 --- a/tonlib/tonlib/Wallet.cpp +++ b/tonlib/tonlib/Wallet.cpp @@ -17,6 +17,7 @@ Copyright 2017-2019 Telegram Systems LLP */ #include "tonlib/Wallet.h" +#include "tonlib/CellString.h" #include "tonlib/GenericAccount.h" #include "tonlib/utils.h" @@ -45,7 +46,6 @@ td::Ref Wallet::get_init_message(const td::Ed25519::PrivateKey& privat td::Ref Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, td::uint32 valid_until, td::int64 gramms, td::Slice message, const block::StdAddress& dest_address) { - CHECK(message.size() <= 124); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -55,7 +55,9 @@ td::Ref Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& pri .store_long(dest_address.workchain, 8) .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize(); + cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); td::int8 send_mode = 3; auto message_outer = vm::CellBuilder() .store_long(seqno, 32) diff --git a/tonlib/tonlib/Wallet.h b/tonlib/tonlib/Wallet.h index 2f2d8a8d..e4ee5aec 100644 --- a/tonlib/tonlib/Wallet.h +++ b/tonlib/tonlib/Wallet.h @@ -21,10 +21,12 @@ #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" +#include "CellString.h" namespace tonlib { class Wallet { public: + static constexpr unsigned max_message_size = vm::CellString::max_bytes; static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key); static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key); static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, diff --git a/tonlib/tonlib/keys/DecryptedKey.cpp b/tonlib/tonlib/keys/DecryptedKey.cpp index 3161d904..746ca188 100644 --- a/tonlib/tonlib/keys/DecryptedKey.cpp +++ b/tonlib/tonlib/keys/DecryptedKey.cpp @@ -67,7 +67,8 @@ EncryptedKey DecryptedKey::encrypt(td::Slice local_password, td::Slice old_secre } td::SecureString encryption_secret(64); - pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", PBKDF_ITERATIONS, encryption_secret.as_mutable_slice()); + pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS, + encryption_secret.as_mutable_slice()); std::vector mnemonic_words_copy; for (auto &w : mnemonic_words) { diff --git a/tonlib/tonlib/keys/EncryptedKey.h b/tonlib/tonlib/keys/EncryptedKey.h index 5a32c9f8..56aa6615 100644 --- a/tonlib/tonlib/keys/EncryptedKey.h +++ b/tonlib/tonlib/keys/EncryptedKey.h @@ -25,9 +25,9 @@ #include namespace tonlib { -constexpr int PBKDF_ITERATIONS = 100000; struct DecryptedKey; struct EncryptedKey { + static constexpr int PBKDF_ITERATIONS = 100000; td::SecureString encrypted_data; td::Ed25519::PublicKey public_key; td::SecureString secret; diff --git a/tonlib/tonlib/keys/SimpleEncryption.cpp b/tonlib/tonlib/keys/SimpleEncryption.cpp index 760dda36..026a3429 100644 --- a/tonlib/tonlib/keys/SimpleEncryption.cpp +++ b/tonlib/tonlib/keys/SimpleEncryption.cpp @@ -77,7 +77,7 @@ td::Result SimpleEncryption::decrypt_data(td::Slice encrypted_ return td::Status::Error("Failed to decrypt: data is too small"); } if (encrypted_data.size() % 16 != 0) { - return td::Status::Error("Failed to decrypt: data size is not divisible by 32"); + return td::Status::Error("Failed to decrypt: data size is not divisible by 16"); } auto data_hash = encrypted_data.substr(0, 32); encrypted_data = encrypted_data.substr(32); diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index ce8d5f48..298027a0 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -27,6 +27,7 @@ class TonlibCli : public td::actor::Actor { std::string config; std::string name; std::string key_dir{"."}; + bool in_memory{false}; bool use_callbacks_for_network{false}; bool use_simple_wallet{false}; bool ignore_cache{false}; @@ -120,7 +121,14 @@ class TonlibCli : public td::actor::Actor { ? make_object(options_.config, options_.name, options_.use_callbacks_for_network, options_.ignore_cache) : nullptr; - send_query(make_object(make_object(std::move(config), options_.key_dir)), + + tonlib_api::object_ptr ks_type; + if (options_.in_memory) { + ks_type = make_object(); + } else { + ks_type = make_object(options_.key_dir); + } + send_query(make_object(make_object(std::move(config), std::move(ks_type))), [](auto r_ok) { LOG_IF(ERROR, r_ok.is_error()) << r_ok.error(); td::TerminalIO::out() << "Tonlib is inited\n"; @@ -824,6 +832,10 @@ int main(int argc, char* argv[]) { options.key_dir = arg.str(); return td::Status::OK(); }); + p.add_option('M', "in-memory", "store keys only in-memory", [&]() { + options.in_memory = true; + return td::Status::OK(); + }); p.add_option('E', "execute", "execute one command", [&](td::Slice arg) { options.one_shot = true; options.cmd = arg.str(); diff --git a/validator-engine-console/CMakeLists.txt b/validator-engine-console/CMakeLists.txt index 3fbfffb2..42d60afb 100644 --- a/validator-engine-console/CMakeLists.txt +++ b/validator-engine-console/CMakeLists.txt @@ -5,3 +5,5 @@ add_executable (validator-engine-console validator-engine-console.cpp validator-engine-console-query.h ) target_link_libraries(validator-engine-console tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block terminal) +install(TARGETS validator-engine-console RUNTIME DESTINATION bin) + diff --git a/validator-engine/CMakeLists.txt b/validator-engine/CMakeLists.txt index d2f608d7..02040d5f 100644 --- a/validator-engine/CMakeLists.txt +++ b/validator-engine/CMakeLists.txt @@ -14,3 +14,5 @@ add_executable(validator-engine ${VALIDATOR_ENGINE_SOURCE}) target_link_libraries(validator-engine overlay tdutils tdactor adnl tl_api dht rldp catchain validatorsession full-node validator ton_validator validator fift-lib memprof ${JEMALLOC_LIBRARIES}) + +install(TARGETS validator-engine RUNTIME DESTINATION bin) diff --git a/validator-session/validator-session-description.cpp b/validator-session/validator-session-description.cpp index 5f74df5e..f6e6f582 100644 --- a/validator-session/validator-session-description.cpp +++ b/validator-session/validator-session-description.cpp @@ -55,7 +55,7 @@ ValidatorSessionDescriptionImpl::ValidatorSessionDescriptionImpl(ValidatorSessio pdata_temp_size_ = 1 << 30; pdata_temp_ = new td::uint8[pdata_temp_size_]; - pdata_perm_size_ = 1 << 30; + pdata_perm_size_ = 1ull << 30; pdata_perm_ptr_ = 0; for (auto &el : cache_) {