From a31f8d44248f6d17f8fed817fe45a860076d8dd1 Mon Sep 17 00:00:00 2001 From: ton Date: Fri, 27 Mar 2020 18:59:00 +0400 Subject: [PATCH] bugfixed + crypto update - compiles vs BoringSSL - config proposal/vote fift code - bugfixes in catchain - other small fixes --- CMakeLists.txt | 12 + catchain/catchain-receiver-source.cpp | 3 +- crypto/CMakeLists.txt | 12 +- crypto/block/check-proof.cpp | 2 +- crypto/block/create-state.cpp | 11 +- crypto/block/mc-config.cpp | 2 +- crypto/common/bitstring.cpp | 4 +- crypto/ellcurve/Ed25519.h | 4 +- crypto/fift/words.cpp | 2 + crypto/func/func.h | 2 +- crypto/openssl/bignum.cpp | 6 +- crypto/openssl/bignum.h | 4 +- crypto/openssl/digest.hpp | 151 ++++++++++ crypto/smartcont/CreateState.fif | 14 +- crypto/smartcont/config-code.fc | 285 ++++++++++++++---- crypto/smartcont/config-proposal-vote-req.fif | 33 ++ .../smartcont/config-proposal-vote-signed.fif | 51 ++++ crypto/smartcont/create-config-proposal.fif | 63 ++++ crypto/smartcont/gen-zerostate.fif | 10 +- crypto/smc-envelope/HighloadWallet.cpp | 29 +- crypto/smc-envelope/HighloadWallet.h | 9 +- crypto/smc-envelope/SmartContractCode.cpp | 1 + crypto/test/test-cells.cpp | 4 +- crypto/test/test-db.cpp | 2 + crypto/test/test-smartcont.cpp | 5 +- crypto/vm/cells.h | 12 +- crypto/vm/cells/CellBuilder.cpp | 2 +- crypto/vm/cells/DataCell.cpp | 4 +- crypto/vm/tonops.cpp | 2 + tddb/test/key_value.cpp | 2 +- tdutils/td/utils/BigNum.cpp | 10 +- tdutils/td/utils/crypto.cpp | 7 + tdutils/test/ConcurrentHashMap.cpp | 4 +- test/test-adnl.cpp | 2 + tonlib/test/offline.cpp | 5 +- tonlib/tonlib/TonlibClient.cpp | 45 ++- validator/manager.cpp | 27 +- validator/manager.hpp | 2 +- validator/validator-group.cpp | 9 +- 39 files changed, 722 insertions(+), 132 deletions(-) create mode 100644 crypto/openssl/digest.hpp create mode 100644 crypto/smartcont/config-proposal-vote-req.fif create mode 100644 crypto/smartcont/config-proposal-vote-signed.fif create mode 100644 crypto/smartcont/create-config-proposal.fif diff --git a/CMakeLists.txt b/CMakeLists.txt index a005e915..4e85633b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,6 +255,18 @@ if (NOT ANDROID) # _FILE_OFFSET_BITS is broken in ndk r15 and r15b and doesn't w add_definitions(-D_FILE_OFFSET_BITS=64) endif() +set(INTERNAL_COMPILE "0") +#BEGIN internal + add_definitions(-D_INTERNAL_COMPILE=1) + set(INTERNAL_COMPILE "1") +#END internal + +set(TONLIB_COMPILE "0") +#BEGIN tonlib + add_definitions(-D_TONLIB_COMPILE=1) + set(TONLIB_COMPILE "1") +#END tonlib + include(AddCXXCompilerFlag) if (MSVC) add_cxx_compiler_flag("/experimental:external /external:anglebrackets /external:W0") diff --git a/catchain/catchain-receiver-source.cpp b/catchain/catchain-receiver-source.cpp index 502843f9..aca522dc 100644 --- a/catchain/catchain-receiver-source.cpp +++ b/catchain/catchain-receiver-source.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "catchain-receiver-source.hpp" #include "common/errorlog.h" @@ -75,6 +75,7 @@ void CatChainReceiverSourceImpl::blame() { if (!blamed_) { LOG(ERROR) << this << ": CATCHAIN: blaming source " << id_; blocks_.clear(); + delivered_height_ = 0; chain_->on_blame(id_); } blamed_ = true; diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index 7be5475b..f2865f55 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -56,7 +56,7 @@ set(TON_CRYPTO_SOURCE ellcurve/TwEdwards.h openssl/bignum.h - openssl/digest.h + openssl/digest.hpp openssl/rand.hpp openssl/residue.h @@ -391,7 +391,15 @@ endif() add_executable(create-state block/create-state.cpp) target_include_directories(create-state PUBLIC $ $) -target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block tonlib) +if (INTERNAL_COMPILE) + target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block tonlib) +else() + if (TONLIB_COMPILE) + target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block tonlib) + else() + target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block) + endif() +endif() if (WINGETOPT_FOUND) target_link_libraries_system(create-state wingetopt) endif() diff --git a/crypto/block/check-proof.cpp b/crypto/block/check-proof.cpp index f8d38baa..6d991256 100644 --- a/crypto/block/check-proof.cpp +++ b/crypto/block/check-proof.cpp @@ -25,7 +25,7 @@ #include "ton/ton-shard.h" #include "vm/cells/MerkleProof.h" -#include "openssl/digest.h" +#include "openssl/digest.hpp" #include "Ed25519.h" namespace block { diff --git a/crypto/block/create-state.cpp b/crypto/block/create-state.cpp index e850603f..2dc3f597 100644 --- a/crypto/block/create-state.cpp +++ b/crypto/block/create-state.cpp @@ -55,13 +55,16 @@ #include "td/utils/port/path.h" #include "td/utils/port/signals.h" -#include "tonlib/keys/Mnemonic.h" - #include "block.h" #include "block-parse.h" #include "block-auto.h" #include "mc-config.h" +#if defined(_INTERNAL_COMPILE) || defined(_TONLIB_COMPILE) +# define WITH_TONLIB +# include "tonlib/keys/Mnemonic.h" +#endif + #define PDO(__op) \ if (!(__op)) { \ ok = false; \ @@ -636,6 +639,7 @@ void interpret_sub_extra_currencies(vm::Stack& stack) { stack.push_bool(ok); } +#ifdef WITH_TONLIB void interpret_mnemonic_to_privkey(vm::Stack& stack, int mode) { td::SecureString str{td::Slice{stack.pop_string()}}; auto res = tonlib::Mnemonic::create(std::move(str), td::SecureString()); @@ -652,6 +656,7 @@ void interpret_mnemonic_to_privkey(vm::Stack& stack, int mode) { } stack.push_bytes(key.as_slice()); } +#endif void init_words_custom(fift::Dictionary& d) { using namespace std::placeholders; @@ -671,8 +676,10 @@ void init_words_custom(fift::Dictionary& d) { d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr); d.def_stack_word("CC+? ", interpret_add_extra_currencies); d.def_stack_word("CC-? ", interpret_sub_extra_currencies); +#ifdef WITH_TONLIB d.def_stack_word("mnemo>priv ", std::bind(interpret_mnemonic_to_privkey, _1, 0)); d.def_stack_word("mnemo>pub ", std::bind(interpret_mnemonic_to_privkey, _1, 1)); +#endif } tlb::TypenameLookup tlb_dict; diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index d2774797..b202b60c 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -35,7 +35,7 @@ #include "td/utils/uint128.h" #include "ton/ton-types.h" #include "ton/ton-shard.h" -#include "crypto/openssl/digest.h" +#include "openssl/digest.hpp" #include #include diff --git a/crypto/common/bitstring.cpp b/crypto/common/bitstring.cpp index 6a23f072..0a273949 100644 --- a/crypto/common/bitstring.cpp +++ b/crypto/common/bitstring.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "common/bitstring.h" #include @@ -22,7 +22,7 @@ #include "td/utils/as.h" #include "td/utils/bits.h" #include "td/utils/misc.h" -#include "crypto/openssl/digest.h" +#include "crypto/openssl/digest.hpp" namespace td { diff --git a/crypto/ellcurve/Ed25519.h b/crypto/ellcurve/Ed25519.h index cb899cc1..4b9e6348 100644 --- a/crypto/ellcurve/Ed25519.h +++ b/crypto/ellcurve/Ed25519.h @@ -14,12 +14,12 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "ellcurve/Montgomery.h" #include "ellcurve/TwEdwards.h" -#include "openssl/digest.h" +#include "openssl/digest.hpp" #include "openssl/rand.hpp" #include #include diff --git a/crypto/fift/words.cpp b/crypto/fift/words.cpp index f9be336f..775e821a 100644 --- a/crypto/fift/words.cpp +++ b/crypto/fift/words.cpp @@ -28,6 +28,8 @@ #include "common/bitstring.h" #include "common/util.h" +#include "openssl/digest.hpp" + #include "Ed25519.h" #include "vm/cells.h" diff --git a/crypto/func/func.h b/crypto/func/func.h index fd2bffd6..1506b974 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -934,7 +934,7 @@ struct AsmOp { void out_indent_nl(std::ostream& os, bool no_nl = false) const; std::string to_string() const; void compute_gconst() { - gconst = (is_custom() && (op == "PUSHNULL" || op == "NEWC" || op == "NEWB" || op == "TRUE" || op == "FALSE")); + gconst = (is_custom() && (op == "PUSHNULL" || op == "NEWC" || op == "NEWB" || op == "TRUE" || op == "FALSE" || op == "NOW")); } bool is_nop() const { return t == a_none && op.empty(); diff --git a/crypto/openssl/bignum.cpp b/crypto/openssl/bignum.cpp index 275b01bb..74dd6bbf 100644 --- a/crypto/openssl/bignum.cpp +++ b/crypto/openssl/bignum.cpp @@ -14,10 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "openssl/bignum.h" +#ifdef OPENSSL_IS_BORINGSSL +#include +#endif + // impl only #include diff --git a/crypto/openssl/bignum.h b/crypto/openssl/bignum.h index 40d7d582..2a8dd8a0 100644 --- a/crypto/openssl/bignum.h +++ b/crypto/openssl/bignum.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -115,7 +115,7 @@ class Bignum { return set_hex_str(hs.str); } Bignum& swap(Bignum& x) { - BN_swap(val, x.val); + std::swap(val, x.val); return *this; } BIGNUM* bn_ptr() { diff --git a/crypto/openssl/digest.hpp b/crypto/openssl/digest.hpp new file mode 100644 index 00000000..5c232df9 --- /dev/null +++ b/crypto/openssl/digest.hpp @@ -0,0 +1,151 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#pragma once +#include + +#include +#include + +#include "td/utils/Slice.h" + +namespace digest { +struct OpensslEVP_SHA1 { + enum { digest_bytes = 20 }; + static const EVP_MD *get_evp() { + return EVP_sha1(); + } +}; + +struct OpensslEVP_SHA256 { + enum { digest_bytes = 32 }; + static const EVP_MD *get_evp() { + return EVP_sha256(); + } +}; + +struct OpensslEVP_SHA512 { + enum { digest_bytes = 64 }; + static const EVP_MD *get_evp() { + return EVP_sha512(); + } +}; + +template +class HashCtx { + EVP_MD_CTX *ctx{nullptr}; + void init(); + void clear(); + + public: + enum { digest_bytes = H::digest_bytes }; + HashCtx() { + init(); + } + HashCtx(const void *data, std::size_t len) { + init(); + feed(data, len); + } + ~HashCtx() { + clear(); + } + void reset(); + void feed(const void *data, std::size_t len); + void feed(td::Slice slice) { + feed(slice.data(), slice.size()); + } + std::size_t extract(unsigned char buffer[digest_bytes]); + std::size_t extract(td::MutableSlice slice); + std::string extract(); +}; + +template +void HashCtx::init() { + ctx = EVP_MD_CTX_create(); + reset(); +} + +template +void HashCtx::reset() { + EVP_DigestInit_ex(ctx, H::get_evp(), 0); +} + +template +void HashCtx::clear() { + EVP_MD_CTX_destroy(ctx); + ctx = nullptr; +} + +template +void HashCtx::feed(const void *data, std::size_t len) { + EVP_DigestUpdate(ctx, data, len); +} + +template +std::size_t HashCtx::extract(unsigned char buffer[digest_bytes]) { + unsigned olen = 0; + EVP_DigestFinal_ex(ctx, buffer, &olen); + assert(olen == digest_bytes); + return olen; +} + +template +std::size_t HashCtx::extract(td::MutableSlice slice) { + return extract(slice.ubegin()); +} + +template +std::string HashCtx::extract() { + unsigned char buffer[digest_bytes]; + unsigned olen = 0; + EVP_DigestFinal_ex(ctx, buffer, &olen); + assert(olen == digest_bytes); + return std::string((char *)buffer, olen); +} + +typedef HashCtx SHA1; +typedef HashCtx SHA256; +typedef HashCtx SHA512; + +template +std::size_t hash_str(unsigned char buffer[T::digest_bytes], const void *data, std::size_t size) { + T hasher(data, size); + return hasher.extract(buffer); +} + +template +std::size_t hash_two_str(unsigned char buffer[T::digest_bytes], const void *data1, std::size_t size1, const void *data2, + std::size_t size2) { + T hasher(data1, size1); + hasher.feed(data2, size2); + return hasher.extract(buffer); +} + +template +std::string hash_str(const void *data, std::size_t size) { + T hasher(data, size); + return hasher.extract(); +} + +template +std::string hash_two_str(const void *data1, std::size_t size1, const void *data2, std::size_t size2) { + T hasher(data1, size1); + hasher.feed(data2, size2); + return hasher.extract(); +} +} // namespace digest diff --git a/crypto/smartcont/CreateState.fif b/crypto/smartcont/CreateState.fif index c369df56..7497cb44 100644 --- a/crypto/smartcont/CreateState.fif +++ b/crypto/smartcont/CreateState.fif @@ -40,6 +40,9 @@ { 8 config! } : config.version! 1 constant capIhr 2 constant capCreateStats +4 constant capBounceMsgBody +8 constant capReportVersion +16 constant capSplitMergeTransactions // max-validators masterchain-validators min-validators -- { swap rot 16 config! } : config.validator_num! @@ -54,21 +57,24 @@ variable validator-dict dictnew 0 validator-dict 2! +variable validators-weight +validators-weight 0! + { validator-dict @ second } : validator# // val-pubkey weight -- { dup 0<= abort"validator weight must be non-negative" dup 64 ufits not abort"validator weight must fit into 64 bits" over Blen 32 <> abort"validator public key must be 32 bytes long" - + rot 34 config! } : config.validators! diff --git a/crypto/smartcont/config-code.fc b/crypto/smartcont/config-code.fc index 5559ba27..612d8c93 100644 --- a/crypto/smartcont/config-code.fc +++ b/crypto/smartcont/config-code.fc @@ -91,7 +91,7 @@ _ get_vote_config(int critical?) inline_ref { () after_code_upgrade(slice param, cont old_code) impure method_id(1666) { } -_ perform_action(cfg_dict, public_key, action, cs) { +_ perform_action(cfg_dict, public_key, action, cs) inline_ref { if (action == 0x43665021) { ;; change one configuration parameter var param_index = cs~load_int(32); @@ -166,6 +166,58 @@ _ perform_action(cfg_dict, public_key, action, cs) { return (id, val, hash); } +(cell, int, cell) accept_proposal(cell cfg_dict, cell proposal, int critical?) inline_ref { + var (param_id, param_val, req_hash) = parse_config_proposal(proposal); + cell cur_val = cfg_dict.idict_get_ref(32, param_id); + int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val); + if ((cur_hash != req_hash) & (req_hash >= 0)) { + ;; current value has incorrect hash, do not apply changes + return (cfg_dict, 0, null()); + } + cell mparams = cfg_dict.idict_get_ref(32, 9); ;; mandatory parameters + var (_, found?) = mparams.idict_get?(32, param_id); + if (found? & param_val.null?()) { + ;; cannot set a mandatory parameter to (null) + return (cfg_dict, 0, null()); + } + cell cparams = cfg_dict.idict_get_ref(32, 10); ;; critical parameters + (_, found?) = cparams.idict_get?(32, param_id); + if (found? < critical?) { + ;; trying to set a critical parameter after a non-critical voting + return (cfg_dict, 0, null()); + } + ;; CHANGE ONE CONFIGURATION PARAMETER (!) + cfg_dict~idict_set_ref(32, param_id, param_val); + return (cfg_dict, param_id, param_val); +} + +(cell, int) perform_proposed_action(cell cfg_dict, int public_key, int param_id, cell param_val) inline_ref { + if (param_id == -999) { + ;; appoint or depose dictator + return (cfg_dict, param_val.null?() ? 0 : param_val.begin_parse().preload_uint(256)); + } + if (param_val.null?()) { + return (cfg_dict, public_key); + } + if (param_id == -1000) { + ;; upgrade code + var cs = param_val.begin_parse(); + var new_code = cs~load_ref(); + set_code(new_code); + var old_code = get_c3(); + set_c3(new_code.begin_parse().bless()); + after_code_upgrade(cs, old_code); + throw(0); + return (cfg_dict, public_key); + } + if (param_id == -1001) { + ;; update elector code + var cs = param_val.begin_parse(); + change_elector_code(cs); + } + return (cfg_dict, public_key); +} + ;; cfg_proposal_status#ce expires:uint32 proposal:^ConfigProposal is_critical:Bool ;; voters:(HashmapE 16 True) remaining_weight:int64 validator_set_id:uint256 ;; rounds_remaining:uint8 wins:uint8 losses:uint8 = ConfigProposalStatus; @@ -174,6 +226,26 @@ _ perform_action(cfg_dict, public_key, action, cs) { return (cs~load_uint(32), cs~load_ref(), cs~load_int(1), cs~load_dict(), cs~load_int(64), cs~load_uint(256), cs); } +slice update_proposal_status(slice rest, int weight_remaining, int critical?) inline_ref { + var [min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _] = get_vote_config(critical?); + var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8)); + losses -= (weight_remaining >= 0); + if (losses > max_losses) { + ;; lost too many times + return null(); + } + rounds_remaining -= 1; + if (rounds_remaining < 0) { + ;; existed for too many rounds + return null(); + } + return begin_cell() + .store_uint(rounds_remaining, 8) + .store_uint(losses, 8) + .store_uint(wins, 8) + .end_cell().begin_parse(); +} + builder begin_pack_proposal_status(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id) inline { return begin_cell() .store_int(0xce - 0x100, 8) @@ -185,54 +257,107 @@ builder begin_pack_proposal_status(int expires, cell proposal, int critical?, ce .store_uint(vset_id, 256); } -(cell, int, int, slice) new_proposal(cs) inline { - return (null(), 0, 0, cs); -} - -(cell, int, int, slice) unpack_proposal(slice cs) inline { - return (cs~load_dict(), cs~load_uint(64), cs~load_uint(256), cs); -} - -builder pack_proposal(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, slice) register_vote(vote_dict, action, cs, idx, weight, total_weight, cur_vset_id) { - int hash = 0; - int found? = 0; - var entry = null(); - if (action & 1) { - hash = slice_hash(cs); - (entry, found?) = vote_dict.udict_get?(256, hash); - } else { - hash = cs.preload_uint(256); - (entry, found?) = vote_dict.udict_get?(256, hash); - throw_unless(42, found?); +(cell, cell, int) register_vote(vote_dict, phash, idx, weight) inline_ref { + var (pstatus, found?) = vote_dict.udict_get?(256, phash); + ifnot (found?) { + ;; config proposal not found + return (vote_dict, null(), false); + } + var (cur_vset, total_weight, _) = get_current_vset(); + int cur_vset_id = cur_vset.cell_hash(); + var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus); + if (expires <= now()) { + ;; config proposal expired, delete and report not found + vote_dict~udict_delete?(256, phash); + return (vote_dict, null(), false); } - var (voters, sum_weight, vset_id, body) = found? ? unpack_proposal(entry) : (null(), 0, cur_vset_id, cs); if (vset_id != cur_vset_id) { - voters = null(); - sum_weight = 0; + ;; config proposal belongs to a previous validator set vset_id = cur_vset_id; + rest = update_proposal_status(rest, weight_remaining, critical?); + voters = null(); + weight_remaining = muldiv(total_weight, 3, 4); + } + if (rest.null?()) { + ;; discard proposal (existed for too many rounds, or too many losses) + vote_dict~udict_delete?(256, phash); + return (vote_dict, null(), false); } var (_, found?) = voters.udict_get?(16, idx); - ifnot (found?) { - voters~udict_set_builder(16, idx, begin_cell().store_uint(32, now())); - sum_weight += weight; - if (sum_weight * 3 > total_weight * 2) { - ;; proposal accepted - vote_dict~udict_delete?(256, hash); - return (vote_dict, body); - } else { - vote_dict~udict_set_builder(256, hash, pack_proposal(voters, sum_weight, cur_vset_id, body)); - return (vote_dict, null()); - } - } else { - return (vote_dict, null()); + if (found?) { + ;; already voted for this proposal, ignore vote + return (vote_dict, null(), false); } + ;; register vote + voters~udict_set_builder(16, idx, begin_cell().store_uint(now(), 32)); + int old_wr = weight_remaining; + weight_remaining -= weight; + if ((weight_remaining ^ old_wr) >= 0) { + ;; not enough votes, or proposal already accepted in this round + ;; simply update weight_remaining + vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest)); + return (vote_dict, null(), false); + } + ;; proposal wins in this round + var [min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _] = get_vote_config(critical?); + var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8)); + wins += 1; + if (wins >= min_wins) { + ;; proposal is accepted, remove and process + vote_dict~udict_delete?(256, phash); + return (vote_dict, proposal, critical?); + } + ;; update proposal info + vote_dict~udict_set_builder(256, phash, + begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id) + .store_uint(rounds_remaining, 8) + .store_uint(wins, 8) + .store_uint(losses, 8)); + return (vote_dict, null(), false); } -int register_voting_proposal(slice cs, int msg_value) inline_ref { +(slice, int) scan_proposal(int phash, slice pstatus) inline_ref { + var (cur_vset, total_weight, _) = get_current_vset(); + int cur_vset_id = cur_vset.cell_hash(); + var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus); + if (expires <= now()) { + ;; config proposal expired, delete + return (null(), true); + } + if (vset_id == cur_vset_id) { + ;; config proposal already processed or voted for in this round, change nothing + return (pstatus, false); + } + ;; config proposal belongs to a previous validator set + vset_id = cur_vset_id; + rest = update_proposal_status(rest, weight_remaining, critical?); + voters = null(); + weight_remaining = muldiv(total_weight, 3, 4); + if (rest.null?()) { + ;; discard proposal (existed for too many rounds, or too many losses) + return (null(), true); + } + ;; return updated proposal + return (begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest).end_cell().begin_parse(), true); +} + +cell scan_random_proposal(cell vote_dict) inline_ref { + var (phash, pstatus, found?) = vote_dict.udict_get_nexteq?(256, random()); + ifnot (found?) { + return vote_dict; + } + (pstatus, var changed?) = scan_proposal(phash, pstatus); + if (changed?) { + if (pstatus.null?()) { + vote_dict~udict_delete?(256, phash); + } else { + vote_dict~udict_set(256, phash, pstatus); + } + } + return vote_dict; +} + +int register_voting_proposal(slice cs, int msg_value) impure inline_ref { var (expire_at, proposal, critical?) = (cs~load_uint(32), cs~load_ref(), cs~load_int(1)); if (expire_at >> 30) { expire_at -= now(); @@ -306,7 +431,7 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref { } ;; obtain current validator set data var (vset, total_weight, _) = get_current_vset(); - int weight_remaining = muldiv(total_weight, 2, 3) + 1; + int weight_remaining = muldiv(total_weight, 3, 4); ;; create new proposal vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expire_at, proposal, critical?, null(), weight_remaining, vset.cell_hash()) @@ -374,27 +499,32 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref { int msg_seqno = cs~load_uint(32); var valid_until = cs~load_uint(32); throw_if(35, valid_until < now()); - throw_if(39, slice_depth(cs) > 64); + throw_if(39, slice_depth(cs) > 128); var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data(); - throw_unless(33, msg_seqno == stored_seqno); - ifnot ((action - 0x566f7465) & -2) { - var idx = cs~load_uint(16); + if (action == 0x566f7465) { + var (idx, phash) = (cs~load_uint(16), cs~load_uint(256)); + cs.end_parse(); var (vdescr, total_weight) = get_validator_descr(idx); var (val_pubkey, weight) = unpack_validator_descr(vdescr); - throw_unless(34, check_signature(slice_hash(in_msg), signature, val_pubkey)); + throw_unless(34, check_data_signature(in_msg, signature, val_pubkey)); accept_message(); stored_seqno += 1; store_data(cfg_dict, stored_seqno, public_key, vote_dict); commit(); - var (_, bits, refs) = cs.slice_compute_data_size(1024); - (vote_dict, var accepted) = register_vote(vote_dict, action, cs, idx, weight, total_weight, config_param(34).cell_hash()); + (vote_dict, var accepted_proposal, var critical?) = register_vote(vote_dict, phash, idx, weight); store_data(cfg_dict, stored_seqno, public_key, vote_dict); - ifnot (accepted.null?()) { - (cfg_dict, public_key) = perform_action(cfg_dict, public_key, accepted~load_uint(32), accepted); + ifnot (accepted_proposal.null?()) { + (cfg_dict, var param_id, var param_val) = accept_proposal(cfg_dict, accepted_proposal, critical?); store_data(cfg_dict, stored_seqno, public_key, vote_dict); + if (param_id) { + commit(); + (cfg_dict, public_key) = perform_proposed_action(cfg_dict, public_key, param_id, param_val); + store_data(cfg_dict, stored_seqno, public_key, vote_dict); + } } return (); } + throw_unless(33, msg_seqno == stored_seqno); throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key)); accept_message(); stored_seqno += 1; @@ -405,11 +535,10 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref { } () run_ticktock(int is_tock) impure { - var cs = begin_parse(get_data()); - var cfg_dict = cs~load_ref(); + var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data(); int kl = 32; - ;; cfg_dict~idict_set_ref(kl, -17, begin_cell().store_uint(now() >> 16, 32).end_cell()); var next_vset = cfg_dict.idict_get_ref(kl, 36); + var updated? = false; ifnot (next_vset.null?()) { ;; check whether we have to set next_vset as the current validator set var ds = next_vset.begin_parse(); @@ -421,12 +550,56 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref { var cur_vset = cfg_dict~idict_set_get_ref(kl, 34, next_vset); ;; next_vset -> cur_vset cfg_dict~idict_set_get_ref(kl, 32, cur_vset); ;; cur_vset -> prev_vset cfg_dict~idict_delete?(kl, 36); ;; (null) -> next_vset + updated? = true; } } } - set_data(begin_cell().store_ref(cfg_dict).store_slice(cs).end_cell()); + ifnot (updated?) { + ;; if nothing has been done so far, scan a random voting proposal instead + vote_dict = scan_random_proposal(vote_dict); + } + ;; save data and return + return store_data(cfg_dict, stored_seqno, public_key, vote_dict); } -int seqno() impure method_id { +int seqno() method_id { return get_data().begin_parse().preload_uint(32); } + +_ unpack_proposal(slice pstatus) inline_ref { + (int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id, slice rest) = unpack_proposal_status(pstatus); + var voters_list = null(); + var voter_id = (1 << 32); + do { + (voter_id, _, var f) = voters.udict_get_prev?(16, voter_id); + if (f) { + voters_list = cons(voter_id, voters_list); + } + } until (~ f); + var (rounds_remaining, losses, wins) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8)); + rest.end_parse(); + var (param_id, param_val, param_hash) = parse_config_proposal(proposal); + return [expires, critical?, [param_id, param_val, param_hash], vset_id, voters_list, weight_remaining, rounds_remaining, losses, wins]; +} + +_ get_proposal(int phash) method_id { + (_, _, _, var vote_dict) = load_data(); + var (pstatus, found?) = vote_dict.udict_get?(256, phash); + ifnot (found?) { + return null(); + } + return unpack_proposal(pstatus); +} + +_ list_proposals() method_id { + (_, _, _, var vote_dict) = load_data(); + var phash = (1 << 255) + ((1 << 255) - 1); + var list = null(); + do { + (phash, var pstatus, var f) = vote_dict.udict_get_prev?(256, phash); + if (f) { + list = cons([phash, unpack_proposal(pstatus)], list); + } + } until (~ f); + return list; +} diff --git a/crypto/smartcont/config-proposal-vote-req.fif b/crypto/smartcont/config-proposal-vote-req.fif new file mode 100644 index 00000000..654a6064 --- /dev/null +++ b/crypto/smartcont/config-proposal-vote-req.fif @@ -0,0 +1,33 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include +"GetOpt.fif" include + +"validator-to-sign.req" =: savefile + +{ ."usage: " @' $0 type ." []" cr + ."Creates an unsigned request expiring at unixtime to vote for configuration proposal (decimal; prefix with '0x' if needed) on behalf of validator with zero-based index in current validator set (as stored in configuration parameter 34)" cr + ."The result is saved into (" savefile type ." by default) and output in hexadecimal form, to be signed later by the validator public key" cr 1 halt +} : usage + +$# dup 3 < swap 4 > or ' usage if +4 :$1..n + +$1 parse-int dup 30 1<< < { now + 1000 + 2000 /c 2000 * } if + dup =: expire-at + dup now <= abort"expiration time must be in the future" + 32 ufits not abort"invalid expiration time" +$2 parse-int dup =: val-idx + 16 ufits not abort"validator index out of range" +$3 parse-int dup =: prop-hash + 256 ufits not abort"invalid proposal hash" +$4 savefile replace-if-null =: savefile +0 =: seqno + +."Creating a request expiring at " expire-at . +."to vote for configuration proposal 0x" prop-hash 64x. +."on behalf of validator with index " val-idx . cr + +B{566f7465} seqno 32 u>B B+ expire-at 32 u>B B+ val-idx 16 u>B B+ prop-hash 256 u>B B+ +dup Bx. cr +dup B>base64url type cr +savefile tuck B>file ."Saved to file " type cr diff --git a/crypto/smartcont/config-proposal-vote-signed.fif b/crypto/smartcont/config-proposal-vote-signed.fif new file mode 100644 index 00000000..38f1eff4 --- /dev/null +++ b/crypto/smartcont/config-proposal-vote-signed.fif @@ -0,0 +1,51 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include +"GetOpt.fif" include + +"vote-query.boc" =: savefile + +{ ."usage: " @' $0 type ." []" cr + ."Creates an external message addressed to the configuration smart contract containing a signed request expiring at unixtime to vote for configuration proposal (decimal; prefix with '0x' if needed) on behalf of validator with zero-based index and (Base64) public key in current validator set (as stored in configuration parameter 34)" cr + ." must be the base64 representation of Ed25519 signature of the previously generated unsigned request by means of " cr + ."The result is saved into (" savefile type ." by default), to be sent later by the lite-client" cr 1 halt +} : usage + +$# dup 6 < swap 7 > or ' usage if +7 :$1..n + +$1 true parse-load-address drop over 1+ abort"configuration smart contract must be in masterchain" + 2=: config-addr +$2 parse-int dup 30 1<< < { now + 1000 + 2000 /c 2000 * } if + dup =: expire-at + dup now <= abort"expiration time must be in the future" + 32 ufits not abort"invalid expiration time" +$3 parse-int dup =: val-idx + 16 ufits not abort"validator index out of range" +$4 parse-int dup =: prop-hash + 256 ufits not abort"invalid proposal hash" +$5 base64>B dup Blen 36 <> abort"validator Ed25519 public key must be exactly 36 bytes long" + 32 B>u@+ 0xC6B41348 <> abort"invalid Ed25519 public key: unknown magic number" + =: pubkey +$6 base64>B dup Blen 64 <> abort"validator Ed25519 signature must be exactly 64 bytes long" + =: signature +$7 savefile replace-if-null =: savefile +0 =: seqno + +."Creating an external message to configuration smart contract " +config-addr 2dup 6 .Addr ." = " .addr cr +."containing a signed request expiring at " expire-at . +."to vote for configuration proposal 0x" prop-hash 64x. +."on behalf of validator with index " val-idx . "and public key" pubkey 64x. cr + +B{566f7465} seqno 32 u>B B+ expire-at 32 u>B B+ val-idx 16 u>B B+ prop-hash 256 u>B B+ +dup =: to_sign +."String to sign is " Bx. cr + +to_sign signature pubkey ed25519_chksign not abort"Ed25519 signature is invalid" +."Provided a valid Ed25519 signature " signature Bx. ." with validator public key " pubkey Bx. cr + + +cr ."External message is " dup B savefile tuck B>file ."Saved to file " type cr diff --git a/crypto/smartcont/create-config-proposal.fif b/crypto/smartcont/create-config-proposal.fif new file mode 100644 index 00000000..427f2f25 --- /dev/null +++ b/crypto/smartcont/create-config-proposal.fif @@ -0,0 +1,63 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include +"GetOpt.fif" include + +{ show-options-help 1 halt } : usage +86400 30 * =: expire-in +false =: critical +-1 =: old-hash + +begin-options + " [-x ] [-c] [-H ] []" +cr +tab + +"Creates a new configuration proposal for setting configuration parameter to (`null` means no new value), " + +"and saves it as an internal message body into .boc ('config-msg-body.boc' by default)" + disable-digit-options generic-help-setopt + "c" "--critical" { true =: critical } short-long-option + "Creates a critical parameter change proposal" option-help + "x" "--expires-in" { parse-int =: expire-in } short-long-option-arg + "Sets proposal expiration time in seconds (default " expire-in (.) $+ +")" option-help + "H" "--old-hash" { (hex-number) not abort"256-bit hex number expected as hash" =: old-hash } + short-long-option-arg + "Sets the required cell hash of existing parameter value (0 means no value)" option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + +$# dup 2 < swap 3 > or ' usage if +3 :$1..n + +$1 parse-int dup =: param-idx + 32 fits not abort"parameter index out of range" +$2 =: boc-filename +$3 "config-msg-body.boc" replace-if-null =: savefile +expire-in now + =: expire-at + +boc-filename dup "null" $= { + ."New value of configuration parameter" param-idx . ."is null" cr drop null +} { + ."Loading new value of configuration parameter " param-idx . ."from file " dup type cr + boc-filename file>B B>boc + dup = tuck 1 i, -rot { 256 u, } { drop } cond b> ref, + critical 1 i, b> + +dup ."resulting internal message body: " B dup Bx. cr +savefile tuck B>file +."(Saved to file " type .")" cr diff --git a/crypto/smartcont/gen-zerostate.fif b/crypto/smartcont/gen-zerostate.fif index 8fc00c32..eb0902fa 100644 --- a/crypto/smartcont/gen-zerostate.fif +++ b/crypto/smartcont/gen-zerostate.fif @@ -157,7 +157,7 @@ Masterchain swap * */ // version capabilities -0 capCreateStats config.version! +1 capCreateStats capBounceMsgBody or capReportVersion or config.version! // max-validators max-main-validators min-validators // 9 4 1 config.validator_num! 1000 100 13 config.validator_num! @@ -202,12 +202,12 @@ smc1_addr config.minter_smc! 1000000000000 -17 of-cc 666666666666 239 of-cc cc+ config.to_mint! ( 0 1 9 10 12 14 15 16 17 18 20 21 22 23 24 25 28 34 ) config.mandatory_params! -( -1000 -1001 0 1 9 10 12 14 15 16 17 32 34 36 ) config.critical_params! +( -999 -1000 -1001 0 1 9 10 12 14 15 16 17 32 34 36 ) config.critical_params! -// [ min_tot_rounds max_tot_rounds min_wins max_losses min_store_sec max_store_sec bit_price cell_price ] +// [ min_tot_rounds max_tot_rounds min_wins max_losses min_store_sec max_store_sec bit_pps cell_pps ] // first for ordinary proposals, then for critical proposals -_( 2 3 2 2 1000000 10000000 GR$.001 GR$.2 ) -_( 4 7 4 2 5000000 20000000 GR$.002 GR$.8 ) +_( 2 3 2 2 1000000 10000000 1 500 ) +_( 4 7 4 2 5000000 20000000 2 1000 ) config.param_proposals_setup! "validator-keys" +suffix +".pub" file>B diff --git a/crypto/smc-envelope/HighloadWallet.cpp b/crypto/smc-envelope/HighloadWallet.cpp index faf08950..af529a1b 100644 --- a/crypto/smc-envelope/HighloadWallet.cpp +++ b/crypto/smc-envelope/HighloadWallet.cpp @@ -27,9 +27,26 @@ #include namespace ton { -td::Ref HighloadWallet::get_init_state(const td::Ed25519::PublicKey& public_key, - td::uint32 wallet_id) noexcept { - auto code = get_init_code(); +td::optional HighloadWallet::guess_revision(const vm::Cell::Hash& code_hash) { + for (td::int32 i = 1; i <= 2; i++) { + if (get_init_code(i)->get_hash() == code_hash) { + return i; + } + } + return {}; +} +td::optional HighloadWallet::guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) { + for (td::int32 i = 1; i <= 2; i++) { + if (GenericAccount::get_address(address.workchain, get_init_state(public_key, wallet_id, i)) == address) { + return i; + } + } + return {}; +} +td::Ref HighloadWallet::get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::int32 revision) noexcept { + auto code = get_init_code(revision); auto data = get_init_data(public_key, wallet_id); return GenericAccount::get_init_state(std::move(code), std::move(data)); } @@ -80,12 +97,12 @@ td::Ref HighloadWallet::make_a_gift_message(const td::Ed25519::Private return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } -td::Ref HighloadWallet::get_init_code() noexcept { - return SmartContractCode::get_code(SmartContractCode::HighloadWalletV1); +td::Ref HighloadWallet::get_init_code(td::int32 revision) noexcept { + return SmartContractCode::get_code(SmartContractCode::HighloadWalletV1, revision); } vm::CellHash HighloadWallet::get_init_code_hash() noexcept { - return get_init_code()->get_hash(); + return get_init_code(0)->get_hash(); } td::Ref HighloadWallet::get_init_data(const td::Ed25519::PublicKey& public_key, diff --git a/crypto/smc-envelope/HighloadWallet.h b/crypto/smc-envelope/HighloadWallet.h index 68d3fe43..ce37af49 100644 --- a/crypto/smc-envelope/HighloadWallet.h +++ b/crypto/smc-envelope/HighloadWallet.h @@ -32,15 +32,18 @@ class HighloadWallet : public ton::SmartContract, public WalletInterface { } static constexpr unsigned max_message_size = vm::CellString::max_bytes; static constexpr unsigned max_gifts_size = 254; - static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::int32 revision) noexcept; static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id) noexcept; static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, td::uint32 seqno, td::uint32 valid_until, td::Span gifts) noexcept; - static td::Ref get_init_code() noexcept; + static td::Ref get_init_code(td::int32 revision) noexcept; static vm::CellHash get_init_code_hash() noexcept; static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; - + static td::optional guess_revision(const vm::Cell::Hash& code_hash); + static td::optional guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id); td::Result get_seqno() const; td::Result get_wallet_id() const; diff --git a/crypto/smc-envelope/SmartContractCode.cpp b/crypto/smc-envelope/SmartContractCode.cpp index 6256dcc0..27bf58ab 100644 --- a/crypto/smc-envelope/SmartContractCode.cpp +++ b/crypto/smc-envelope/SmartContractCode.cpp @@ -103,6 +103,7 @@ const auto& get_map() { } // namespace td::Result> SmartContractCode::load(td::Slice name) { + LOG(ERROR) << "LOAD " << name; auto& map = get_map(); auto it = map.find(name); if (it == map.end()) { diff --git a/crypto/test/test-cells.cpp b/crypto/test/test-cells.cpp index bda9caa6..327f73c6 100644 --- a/crypto/test/test-cells.cpp +++ b/crypto/test/test-cells.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include @@ -580,7 +580,7 @@ bool check_exp(std::ostream& stream, const td::NegExpBinTable& tab, double x) { } double y = yy.to_double() * exp2(-252); double y0 = exp(x); - bool ok = (abs(y - y0) < 1e-15); + bool ok = (fabs(y - y0) < 1e-15); if (!ok) { stream << "exp(" << x << ") = exp(" << xx << " * 2^(-52)) = " << yy << " / 2^252 = " << y << " (correct value is " << y0 << ") " << (ok ? "match" : "incorrect") << std::endl; diff --git a/crypto/test/test-db.cpp b/crypto/test/test-db.cpp index 411e0c77..f143ca0a 100644 --- a/crypto/test/test-db.cpp +++ b/crypto/test/test-db.cpp @@ -52,6 +52,8 @@ #include +#include "openssl/digest.hpp" + namespace vm { std::vector do_get_serialization_modes() { diff --git a/crypto/test/test-smartcont.cpp b/crypto/test/test-smartcont.cpp index 08b19a05..5048bb28 100644 --- a/crypto/test/test-smartcont.cpp +++ b/crypto/test/test-smartcont.cpp @@ -331,11 +331,12 @@ TEST(Tonlib, HighloadWallet) { td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}}; auto pub_key = priv_key.get_public_key().move_as_ok(); - auto init_state = ton::HighloadWallet::get_init_state(pub_key, 239); + auto init_state = ton::HighloadWallet::get_init_state(pub_key, 239, -1); auto init_message = ton::HighloadWallet::get_init_message(priv_key, 239); auto address = ton::GenericAccount::get_address(0, init_state); - ton::HighloadWallet wallet({ton::HighloadWallet::get_init_code(), ton::HighloadWallet::get_init_data(pub_key, 239)}); + ton::HighloadWallet wallet( + {ton::HighloadWallet::get_init_code(-1), ton::HighloadWallet::get_init_data(pub_key, 239)}); ASSERT_EQ(239u, wallet.get_wallet_id().ok()); ASSERT_EQ(0u, wallet.get_seqno().ok()); CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string()); diff --git a/crypto/vm/cells.h b/crypto/vm/cells.h index ea362597..cf917eff 100644 --- a/crypto/vm/cells.h +++ b/crypto/vm/cells.h @@ -14,26 +14,16 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once -#include -#include "common/refcnt.hpp" -#include "common/bitstring.h" -#include "common/bigint.hpp" -#include "common/refint.h" - #include "vm/cells/Cell.h" #include "vm/cells/CellBuilder.h" #include "vm/cells/DataCell.h" #include "vm/cells/UsageCell.h" #include "vm/cells/VirtualCell.h" -#include "td/utils/Slice.h" -#include "td/utils/StringBuilder.h" -#include "openssl/digest.h" - // H_i(cell) = H(cell_i) // cell.hash = sha256( // d1, d2, diff --git a/crypto/vm/cells/CellBuilder.cpp b/crypto/vm/cells/CellBuilder.cpp index dc7f5eb8..481c2581 100644 --- a/crypto/vm/cells/CellBuilder.cpp +++ b/crypto/vm/cells/CellBuilder.cpp @@ -24,7 +24,7 @@ #include "td/utils/misc.h" #include "td/utils/format.h" -#include "openssl/digest.h" +#include "openssl/digest.hpp" namespace vm { diff --git a/crypto/vm/cells/DataCell.cpp b/crypto/vm/cells/DataCell.cpp index 4a89a276..cccb11dc 100644 --- a/crypto/vm/cells/DataCell.cpp +++ b/crypto/vm/cells/DataCell.cpp @@ -14,11 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/cells/DataCell.h" -#include "openssl/digest.h" +#include "openssl/digest.hpp" #include "td/utils/ScopeGuard.h" diff --git a/crypto/vm/tonops.cpp b/crypto/vm/tonops.cpp index ca8e4b00..88d8fda9 100644 --- a/crypto/vm/tonops.cpp +++ b/crypto/vm/tonops.cpp @@ -26,6 +26,8 @@ #include "vm/dict.h" #include "Ed25519.h" +#include "openssl/digest.hpp" + namespace vm { namespace { diff --git a/tddb/test/key_value.cpp b/tddb/test/key_value.cpp index c7d3c8f3..e04e7ee9 100644 --- a/tddb/test/key_value.cpp +++ b/tddb/test/key_value.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/tests.h" diff --git a/tdutils/td/utils/BigNum.cpp b/tdutils/td/utils/BigNum.cpp index 66a51187..49b44899 100644 --- a/tdutils/td/utils/BigNum.cpp +++ b/tdutils/td/utils/BigNum.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/BigNum.h" @@ -98,7 +98,7 @@ BigNum BigNum::from_binary(Slice str) { } BigNum BigNum::from_le_binary(Slice str) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) return BigNum(make_unique(BN_lebin2bn(str.ubegin(), narrow_cast(str.size()), nullptr))); #else LOG(FATAL) << "Unsupported from_le_binary"; @@ -132,7 +132,11 @@ BigNum::BigNum(unique_ptr &&impl) : impl_(std::move(impl)) { } void BigNum::ensure_const_time() { +#if !defined(OPENSSL_IS_BORINGSSL) BN_set_flags(impl_->big_num, BN_FLG_CONSTTIME); +#else + LOG(FATAL) << "Unsupported BN_FLG_CONSTTIME"; +#endif } int BigNum::get_num_bits() const { @@ -217,7 +221,7 @@ string BigNum::to_binary(int exact_size) const { } string BigNum::to_le_binary(int exact_size) const { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) int num_size = get_num_bytes(); if (exact_size == -1) { exact_size = num_size; diff --git a/tdutils/td/utils/crypto.cpp b/tdutils/td/utils/crypto.cpp index d8a0d7b6..02bc4fcf 100644 --- a/tdutils/td/utils/crypto.cpp +++ b/tdutils/td/utils/crypto.cpp @@ -253,6 +253,13 @@ int pq_factorize(Slice pq_str, string *p_str, string *q_str) { return 0; } +#ifdef OPENSSL_IS_BORINGSSL +extern "C" { +void AES_ige_encrypt(const unsigned char *in_ptr, unsigned char *out, size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +} +#endif + static void aes_ige_xcrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlice to, bool encrypt_flag) { CHECK(aes_key.size() == 32); CHECK(aes_iv.size() == 16); diff --git a/tdutils/test/ConcurrentHashMap.cpp b/tdutils/test/ConcurrentHashMap.cpp index ba52105d..baceae6a 100644 --- a/tdutils/test/ConcurrentHashMap.cpp +++ b/tdutils/test/ConcurrentHashMap.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/benchmark.h" #include "td/utils/ConcurrentHashTable.h" @@ -263,4 +263,4 @@ TEST(ConcurrentHashMap, Benchmark) { #endif } -#endif \ No newline at end of file +#endif diff --git a/test/test-adnl.cpp b/test/test-adnl.cpp index 14fd92c2..d9ae4abe 100644 --- a/test/test-adnl.cpp +++ b/test/test-adnl.cpp @@ -50,6 +50,8 @@ int main() { CHECK(id.serialize() == td::to_lower(id_str)); } + td::to_integer_safe("0").ensure(); + std::string db_root_ = "tmp-ee"; td::rmrf(db_root_).ignore(); td::mkdir(db_root_).ensure(); diff --git a/tonlib/test/offline.cpp b/tonlib/test/offline.cpp index 799c246f..2c35d934 100644 --- a/tonlib/test/offline.cpp +++ b/tonlib/test/offline.cpp @@ -566,6 +566,7 @@ TEST(Tonlib, ConfigCache) { using tonlib_api::make_object; Client client; + td::rmrf("testdir").ignore(); td::mkdir("testdir").ignore(); // init sync_send(client, make_object(make_object( @@ -595,8 +596,8 @@ TEST(Tonlib, ConfigCache) { "workchain": -1, "shard": -9223372036854775808, "seqno": 0, - "root_hash": "VXSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=", - "file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=" + "root_hash": "F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=", + "file_hash": "XplPz01CXAps5qeSWUtxcyBfdAo5zVb1N979KLSKD24=" } } })abc"; diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index d9dc0660..532cc73f 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -412,6 +412,14 @@ class AccountState { {ton::HighloadWalletV2::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)}); return wallet_type_; } + o_revision = ton::HighloadWallet::guess_revision(address_, key, wallet_id_); + if (o_revision) { + wallet_type_ = WalletType::HighloadWalletV1; + wallet_revision_ = o_revision.value(); + set_new_state( + {ton::HighloadWallet::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)}); + return wallet_type_; + } o_revision = ton::ManualDns::guess_revision(address_, key, wallet_id_); if (o_revision) { wallet_type_ = WalletType::ManualDns; @@ -428,11 +436,6 @@ class AccountState { address_.addr) { set_new_state({ton::Wallet::get_init_code(), ton::Wallet::get_init_data(key)}); wallet_type_ = WalletType::Wallet; - } else if (ton::GenericAccount::get_address(address_.workchain, - ton::HighloadWallet::get_init_state(key, wallet_id_)) - .addr == address_.addr) { - set_new_state({ton::HighloadWallet::get_init_code(), ton::HighloadWallet::get_init_data(key, wallet_id_)}); - wallet_type_ = WalletType::HighloadWalletV1; } return wallet_type_; } @@ -494,6 +497,12 @@ class AccountState { wallet_revision_ = o_revision.value(); return wallet_type_; } + o_revision = ton::HighloadWallet::guess_revision(code_hash); + if (o_revision) { + wallet_type_ = WalletType::HighloadWalletV1; + wallet_revision_ = o_revision.value(); + return wallet_type_; + } o_revision = ton::ManualDns::guess_revision(code_hash); if (o_revision) { wallet_type_ = WalletType::ManualDns; @@ -1438,7 +1447,8 @@ td::Result get_account_address( TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); return ton::GenericAccount::get_address( - 0 /*zerochain*/, ton::HighloadWallet::get_init_state(key, static_cast(test_wallet_state.wallet_id_))); + 0 /*zerochain*/, + ton::HighloadWallet::get_init_state(key, static_cast(test_wallet_state.wallet_id_), revision)); } td::Result get_account_address( @@ -1688,6 +1698,29 @@ const MasterConfig& get_default_master_config() { "init_block": {"workchain":-1,"shard":-9223372036854775808,"seqno":870721,"root_hash":"jYKhSQ1xeSPprzgjqiUOnAWwc2yqs7nCVAU21k922s4=","file_hash":"kHidF02CZpaz2ia9jtXUJLp0AiWMWwfzprTUIsddHSo="} } +})abc"); + res.add_config("testnet2", R"abc({ + "liteservers": [ + { + "ip": 1137658550, + "port": 4924, + "id": { + "@type": "pub.ed25519", + "key": "peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M=" + } + } + ], + "validator": { + "@type": "validator.config.global", + "zero_state": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 0, + "root_hash": "F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=", + "file_hash": "XplPz01CXAps5qeSWUtxcyBfdAo5zVb1N979KLSKD24=" + }, + "init_block": {"workchain":-1,"shard":-9223372036854775808,"seqno":2908451,"root_hash":"5+7X1QHVUBFLFMwa/yd/2fGzt2KeQtwr+o6UUFOQ7Qc=","file_hash":"gmiUgrtAbvEJZYDEkcbeNOhGPS3g+qCepSOEBFLZFzk="} + } })abc"); return res; }(); diff --git a/validator/manager.cpp b/validator/manager.cpp index cad63baf..f4829b97 100644 --- a/validator/manager.cpp +++ b/validator/manager.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "manager.hpp" #include "validator-group.hpp" @@ -1413,6 +1413,9 @@ void ValidatorManagerImpl::start_up() { } fname = fname.substr(8); + while (fname.size() > 1 && fname[0] == '0') { + fname.remove_prefix(1); + } auto v = td::to_integer_safe(fname); if (v.is_error()) { return; @@ -1486,6 +1489,10 @@ bool ValidatorManagerImpl::out_of_sync() { return false; } + if (last_masterchain_seqno_ < last_known_key_block_handle_->id().seqno()) { + return true; + } + if (validator_groups_.size() > 0 && last_known_key_block_handle_->id().seqno() <= last_masterchain_seqno_) { return false; } @@ -1510,7 +1517,7 @@ void ValidatorManagerImpl::download_next_archive() { } auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno()); - auto it = to_import_.upper_bound(seqno); + auto it = to_import_.upper_bound(seqno + 1); if (it != to_import_.begin()) { it--; if (it->second.second) { @@ -1715,12 +1722,12 @@ void ValidatorManagerImpl::update_shards() { // DIRTY. But we don't want to create hardfork now // TODO! DELETE IT LATER - if (last_masterchain_seqno_ >= 2904932 && val_set->get_catchain_seqno() == 44896) { - if (opts_->zero_block_id().file_hash.to_hex() == - "5E994FCF4D425C0A6CE6A792594B7173205F740A39CD56F537DEFD28B48A0F6E") { - val_group_id[0] = !val_group_id[0]; - } - } + //if (last_masterchain_seqno_ >= 2904932 && val_set->get_catchain_seqno() == 44896) { + // if (opts_->zero_block_id().file_hash.to_hex() == + // "5E994FCF4D425C0A6CE6A792594B7173205F740A39CD56F537DEFD28B48A0F6E") { + // val_group_id[0] = !val_group_id[0]; + // } + //} VLOG(VALIDATOR_DEBUG) << "validating group " << val_group_id; auto it = validator_groups_.find(val_group_id); @@ -2214,6 +2221,10 @@ void ValidatorManagerImpl::try_get_static_file(FileHash file_hash, td::Promise promise) { + if (masterchain_seqno > last_masterchain_seqno_) { + promise.set_error(td::Status::Error(ErrorCode::notready, "masterchain seqno too big")); + return; + } td::actor::send_closure(db_, &Db::get_archive_id, masterchain_seqno, std::move(promise)); } diff --git a/validator/manager.hpp b/validator/manager.hpp index de788081..fdb53670 100644 --- a/validator/manager.hpp +++ b/validator/manager.hpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once diff --git a/validator/validator-group.cpp b/validator/validator-group.cpp index 9643b487..ca5fa065 100644 --- a/validator/validator-group.cpp +++ b/validator/validator-group.cpp @@ -20,6 +20,7 @@ #include "fabric.h" #include "ton/ton-io.hpp" #include "td/utils/overloaded.h" +#include "common/delay.h" namespace ton { @@ -50,8 +51,12 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat if (S.code() != ErrorCode::timeout && S.code() != ErrorCode::notready) { LOG(ERROR) << "failed to validate candidate: " << S; } - td::actor::send_closure(SelfId, &ValidatorGroup::validate_block_candidate, round_id, std::move(block), - std::move(promise)); + delay_action( + [SelfId, round_id, block = std::move(block), promise = std::move(promise)]() mutable { + td::actor::send_closure(SelfId, &ValidatorGroup::validate_block_candidate, round_id, std::move(block), + std::move(promise)); + }, + td::Timestamp::in(0.1)); } else { auto v = R.move_as_ok(); v.visit(td::overloaded([&](UnixTime ts) { promise.set_result(ts); },