diff --git a/catchain/catchain-receiver-interface.h b/catchain/catchain-receiver-interface.h index 0a819f5b..f30b9d64 100644 --- a/catchain/catchain-receiver-interface.h +++ b/catchain/catchain-receiver-interface.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 diff --git a/catchain/catchain-receiver-source.h b/catchain/catchain-receiver-source.h index 85086573..11faf3db 100644 --- a/catchain/catchain-receiver-source.h +++ b/catchain/catchain-receiver-source.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 diff --git a/catchain/catchain-receiver-source.hpp b/catchain/catchain-receiver-source.hpp index eda5a344..74082b45 100644 --- a/catchain/catchain-receiver-source.hpp +++ b/catchain/catchain-receiver-source.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/catchain/catchain-receiver.cpp b/catchain/catchain-receiver.cpp index 95278005..3f49c136 100644 --- a/catchain/catchain-receiver.cpp +++ b/catchain/catchain-receiver.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 "td/actor/PromiseFuture.h" diff --git a/catchain/catchain-receiver.hpp b/catchain/catchain-receiver.hpp index 0015230e..c1789f3e 100644 --- a/catchain/catchain-receiver.hpp +++ b/catchain/catchain-receiver.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/catchain/catchain.cpp b/catchain/catchain.cpp index 0c801deb..4ddbf3c4 100644 --- a/catchain/catchain.cpp +++ b/catchain/catchain.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-types.h" #include "catchain.hpp" diff --git a/catchain/catchain.h b/catchain/catchain.h index 43fc795c..65182c1e 100644 --- a/catchain/catchain.h +++ b/catchain/catchain.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 diff --git a/catchain/catchain.hpp b/catchain/catchain.hpp index 7da1a389..5e015873 100644 --- a/catchain/catchain.hpp +++ b/catchain/catchain.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/crypto/block/create-state.cpp b/crypto/block/create-state.cpp index 2dc3f597..efee71f8 100644 --- a/crypto/block/create-state.cpp +++ b/crypto/block/create-state.cpp @@ -599,6 +599,18 @@ void interpret_set_config_param(vm::Stack& stack) { } } +void interpret_check_config_param(vm::Stack& stack) { + int x = stack.pop_smallint_range(0x7fffffff, 0x80000000); + Ref value = stack.pop_cell(); + if (verbosity > 2 && x >= 0) { + std::cerr << "checking validity as configuration parameter #" << x << " of "; + // vm::load_cell_slice(value).print_rec(std::cerr); + block::gen::ConfigParam{x}.print_ref(std::cerr, value); + std::cerr << std::endl; + } + stack.push_bool(x < 0 || block::gen::ConfigParam{x}.validate_ref(value)); +} + void interpret_is_shard_state(vm::Stack& stack) { Ref cell = stack.pop_cell(); if (verbosity > 4) { @@ -668,6 +680,7 @@ void init_words_custom(fift::Dictionary& d) { d.def_stack_word("globalid! ", interpret_set_global_id); d.def_stack_word("config@ ", interpret_get_config_param); d.def_stack_word("config! ", interpret_set_config_param); + d.def_stack_word("config-valid? ", interpret_check_config_param); d.def_stack_word("(configdict) ", interpret_get_config_dict); d.def_stack_word("register_smc ", interpret_register_smartcontract); d.def_stack_word("set_config_smc ", interpret_set_config_smartcontract); diff --git a/crypto/common/bitstring.h b/crypto/common/bitstring.h index 901ff709..dc3a2fa5 100644 --- a/crypto/common/bitstring.h +++ b/crypto/common/bitstring.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 #include "common/refcnt.hpp" @@ -284,7 +284,7 @@ class BitSliceGen { ensure_throw(set_size_bool(bits)); return *this; } - BitSliceGen subslice(unsigned from, unsigned bits) const& { + BitSliceGen subslice(unsigned from, unsigned bits) const & { return BitSliceGen(*this, from, bits); } BitSliceGen subslice(unsigned from, unsigned bits) && { @@ -575,6 +575,14 @@ class BitArray { std::string to_binary() const { return bitstring::bits_to_binary(cbits(), size()); } + long from_hex(td::Slice hex_str, bool allow_partial = false) { + auto res = bitstring::parse_bitstring_hex_literal(data(), m, hex_str.begin(), hex_str.end()); + return allow_partial ? std::min(res, n) : (res == n ? res : -1); + } + long from_binary(td::Slice bin_str, bool allow_partial = false) { + auto res = bitstring::parse_bitstring_binary_literal(bits(), n, bin_str.begin(), bin_str.end()); + return allow_partial ? std::min(res, n) : (res == n ? res : -1); + } int compare(const BitArray& other) const { return (n % 8 == 0) ? std::memcmp(data(), other.data(), n / 8) : bitstring::bits_memcmp(bits(), other.bits(), n); } diff --git a/crypto/fift/lib/TonUtil.fif b/crypto/fift/lib/TonUtil.fif index 4ee5fc15..bcdb4a7e 100644 --- a/crypto/fift/lib/TonUtil.fif +++ b/crypto/fift/lib/TonUtil.fif @@ -247,3 +247,16 @@ recursive append-long-bytes { // ( x a b -- a<=x<=b ) { 2 pick >= -rot >= and } : in-range? + +// ( c i -- ? ) Checks whether c is a valid value for config param #i +def? config-valid? { + { nip 0>= { ."warning: cannot check validity of configuration parameter value, use create-state instead of fift to check validity" cr } if + true } : config-valid? +} ifnot + +{ dup -1000 = { drop B B>boc dup second : nullptr; } +const TLB* TypenameLookup::lookup(td::Slice str) const { + auto it = std::lower_bound(types.begin(), types.end(), str, + [](const auto& x, const auto& y) { return td::Slice(x.first) < y; }); + return it != types.end() && td::Slice(it->first) == str ? it->second : nullptr; +} + } // namespace tlb diff --git a/crypto/tl/tlblib.hpp b/crypto/tl/tlblib.hpp index 7543d38f..b3260a74 100644 --- a/crypto/tl/tlblib.hpp +++ b/crypto/tl/tlblib.hpp @@ -594,6 +594,7 @@ class TypenameLookup { bool register_type(const char* name, const TLB* tp); bool register_types(register_func_t func); const TLB* lookup(std::string str) const; + const TLB* lookup(td::Slice str) const; }; } // namespace tlb diff --git a/crypto/vm/stack.cpp b/crypto/vm/stack.cpp index 43099927..90fea7f6 100644 --- a/crypto/vm/stack.cpp +++ b/crypto/vm/stack.cpp @@ -289,6 +289,31 @@ Ref StackEntry::as_atom() && { return move_as(); } +bool StackEntry::for_each_scalar(const std::function& func) const { + auto t = as(); + if (t.not_null()) { + for (const auto& entry : *t) { + if (!entry.for_each_scalar(func)) { + return false; + } + } + return true; + } else { + return func(*this); + } +} + +void StackEntry::for_each_scalar(const std::function& func) const { + auto t = as(); + if (t.not_null()) { + for (const auto& entry : *t) { + entry.for_each_scalar(func); + } + } else { + func(*this); + } +} + const StackEntry& tuple_index(const Tuple& tup, unsigned idx) { if (idx >= tup->size()) { throw VmError{Excno::range_chk, "tuple index out of range"}; @@ -672,6 +697,21 @@ void Stack::push_maybe_cellslice(Ref cs) { push_maybe(std::move(cs)); } +bool Stack::for_each_scalar(const std::function& func) const { + for (const auto& v : stack) { + if (!v.for_each_scalar(func)) { + return false; + } + } + return true; +} + +void Stack::for_each_scalar(const std::function& func) const { + for (const auto& v : stack) { + v.for_each_scalar(func); + } +} + /* * * SERIALIZE/DESERIALIZE STACK VALUES diff --git a/crypto/vm/stack.hpp b/crypto/vm/stack.hpp index 3fadce6b..d67a9dbb 100644 --- a/crypto/vm/stack.hpp +++ b/crypto/vm/stack.hpp @@ -285,6 +285,8 @@ class StackEntry { Ref as_object() && { return dynamic_move_as(); } + bool for_each_scalar(const std::function& func) const; + void for_each_scalar(const std::function& func) const; void dump(std::ostream& os) const; void print_list(std::ostream& os) const; std::string to_string() const; @@ -549,6 +551,8 @@ class Stack : public td::CntObject { push(std::move(val)); } } + bool for_each_scalar(const std::function& func) const; + void for_each_scalar(const std::function& func) const; // mode: +1 = add eoln, +2 = Lisp-style lists void dump(std::ostream& os, int mode = 1) const; bool serialize(vm::CellBuilder& cb, int mode = 0) const; diff --git a/lite-client/lite-client.cpp b/lite-client/lite-client.cpp index 3dedabe2..ad0cae9d 100644 --- a/lite-client/lite-client.cpp +++ b/lite-client/lite-client.cpp @@ -232,6 +232,68 @@ bool TestNode::complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& compl return false; } +const tlb::TypenameLookup& TestNode::get_tlb_dict() { + static tlb::TypenameLookup tlb_dict = []() { + tlb::TypenameLookup tlb_dict0; + tlb_dict0.register_types(block::gen::register_simple_types); + return tlb_dict0; + }(); + return tlb_dict; +} + +bool TestNode::list_cached_cells() const { + for (const auto& kv : cell_cache_) { + td::TerminalIO::out() << kv.first.to_hex() << std::endl; + } + return true; +} + +bool TestNode::dump_cached_cell(td::Slice hash_pfx, td::Slice type_name) { + if (hash_pfx.size() > 64) { + return false; + } + td::Bits256 hv_min; + int len = (int)hv_min.from_hex(hash_pfx, true); + if (len < 0 || len > 256) { + return set_error("cannot parse hex cell hash prefix"); + } + (hv_min.bits() + len).fill(false, 256 - len); + const tlb::TLB* tptr = nullptr; + block::gen::ConfigParam tpconf(0); + if (type_name.size()) { + td::int32 idx; + if (type_name.substr(0, 11) == "ConfigParam" && convert_int32(type_name.substr(11), idx) && idx >= 0) { + tpconf = block::gen::ConfigParam(idx); + tptr = &tpconf; + } else { + tptr = get_tlb_dict().lookup(type_name); + } + if (!tptr) { + return set_error("unknown TL-B type"); + } + td::TerminalIO::out() << "dumping cells as values of TLB type " << tptr->get_type_name() << std::endl; + } + auto it = std::lower_bound(cell_cache_.begin(), cell_cache_.end(), hv_min, + [](const auto& x, const auto& y) { return x.first < y; }); + int cnt = 0; + for (; it != cell_cache_.end() && it->first.bits().equals(hv_min.bits(), len); ++it) { + std::ostringstream os; + os << "C{" << it->first.to_hex() << "} =" << std::endl; + vm::load_cell_slice(it->second).print_rec(print_limit_, os, 2); + if (tptr) { + tptr->print_ref(print_limit_, os, it->second, 2); + os << std::endl; + } + td::TerminalIO::out() << os.str(); + ++cnt; + } + if (!cnt) { + LOG(ERROR) << "no known cells with specified hash prefix"; + return false; + } + return true; +} + bool TestNode::get_server_time() { auto b = ton::serialize_tl_object(ton::create_tl_object(), true); return envelope_send_query(std::move(b), [&, Self = actor_id(this) ](td::Result res)->void { @@ -863,6 +925,10 @@ bool TestNode::show_help(std::string command) { "updated after by validator public " "key\n" "known\tShows the list of all known block ids\n" + "knowncells\tShows the list of hashes of all known (cached) cells\n" + "dumpcell \nDumps a cached cell by a prefix of its hash\n" + "dumpcellas \nFinds a cached cell by a prefix of its hash and prints it as a value " + "of \n" "privkey \tLoads a private key from file\n" "help []\tThis help\n" "quit\tExit\n"; @@ -966,6 +1032,13 @@ bool TestNode::do_parse_line() { get_creator_stats(blkid, mode, count, hash, utime); } else if (word == "known") { return eoln() && show_new_blkids(true); + } else if (word == "knowncells") { + return eoln() && list_cached_cells(); + } else if (word == "dumpcell" || word == "dumpcellas") { + td::Slice chash; + td::Slice tname; + return (word == "dumpcell" || get_word_to(tname)) && get_word_to(chash) && seekeoln() && + dump_cached_cell(chash, tname); } else if (word == "quit" && eoln()) { LOG(INFO) << "Exiting"; stop(); @@ -1061,6 +1134,16 @@ td::int64 TestNode::compute_method_id(std::string method) { return method_id; } +bool TestNode::cache_cell(Ref cell) { + if (cell.is_null()) { + return false; + } + td::Bits256 hash = cell->get_hash().bits(); + LOG(INFO) << "caching cell " << hash.to_hex(); + auto res = cell_cache_.emplace(hash, std::move(cell)); + return res.second; +} + bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, std::string method_name, bool ext_mode) { auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_)); @@ -1068,9 +1151,17 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a return set_error(R.move_as_error().to_string()); } parse_ptr_ = parse_end_; - auto P = td::PromiseCreator::lambda([](td::Result> R) { + auto P = td::PromiseCreator::lambda([this](td::Result> R) { if (R.is_error()) { LOG(ERROR) << R.move_as_error(); + } else { + for (const auto& v : R.move_as_ok()) { + v.for_each_scalar([this](const vm::StackEntry& val) { + if (val.is_cell()) { + cache_cell(val.as_cell()); + } + }); + } } }); return start_run_method(workchain, addr, ref_blkid, method_name, R.move_as_ok(), ext_mode ? 0x1f : 0, std::move(P)); @@ -1294,7 +1385,8 @@ bool TestNode::show_dns_record(std::ostream& os, int cat, Ref value, b case block::gen::DNSRecord::dns_smc_address: { block::gen::DNSRecord::Record_dns_smc_address rec; if (tlb::unpack_exact(cs, rec) && block::tlb::t_MsgAddressInt.extract_std_address(rec.smc_addr, wc, addr)) { - os << "\tsmart contract " << wc << ":" << addr.to_hex() << " = " << block::StdAddress{wc, addr}.rserialize(true); + os << "\tsmart contract " << wc << ":" << addr.to_hex() << " = " + << block::StdAddress{wc, addr}.rserialize(true); } break; } diff --git a/lite-client/lite-client.h b/lite-client/lite-client.h index 7ebaaf17..50afe273 100644 --- a/lite-client/lite-client.h +++ b/lite-client/lite-client.h @@ -85,6 +85,8 @@ class TestNode : public td::actor::Actor { bool ex_mode_ = false; std::vector ex_queries_; + std::map> cell_cache_; + std::unique_ptr make_callback(); struct TransId { @@ -178,6 +180,9 @@ class TestNode : public td::actor::Actor { void got_creator_stats(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, int req_mode, int mode, td::Bits256 start_after, ton::UnixTime min_utime, td::BufferSlice state_proof, td::BufferSlice data_proof, int count, int req_count, bool complete); + bool cache_cell(Ref cell); + bool list_cached_cells() const; + bool dump_cached_cell(td::Slice hash_pfx, td::Slice type_name = {}); // parser bool do_parse_line(); bool show_help(std::string command); @@ -217,6 +222,7 @@ class TestNode : public td::actor::Actor { bool show_new_blkids(bool all = false); bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const; td::Promise trivial_promise(); + static const tlb::TypenameLookup& get_tlb_dict(); public: void conn_ready() { diff --git a/validator-engine-console/validator-engine-console.cpp b/validator-engine-console/validator-engine-console.cpp index 4cd0427f..8f85637e 100644 --- a/validator-engine-console/validator-engine-console.cpp +++ b/validator-engine-console/validator-engine-console.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "validator-engine-console.h" #include "adnl/adnl-ext-client.h" diff --git a/validator-session/validator-session.cpp b/validator-session/validator-session.cpp index 9b8f9832..a65eb4b8 100644 --- a/validator-session/validator-session.cpp +++ b/validator-session/validator-session.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 "validator-session.hpp" #include "td/utils/Random.h" diff --git a/validator-session/validator-session.h b/validator-session/validator-session.h index 4eecbbb1..8a4d6f52 100644 --- a/validator-session/validator-session.h +++ b/validator-session/validator-session.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 diff --git a/validator-session/validator-session.hpp b/validator-session/validator-session.hpp index 911a08aa..7693df76 100644 --- a/validator-session/validator-session.hpp +++ b/validator-session/validator-session.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 1fc201fd..0989a110 100644 --- a/validator/validator-group.cpp +++ b/validator/validator-group.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 "validator-group.hpp" #include "fabric.h" diff --git a/validator/validator-group.hpp b/validator/validator-group.hpp index e50af9ae..431745e9 100644 --- a/validator/validator-group.hpp +++ b/validator/validator-group.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-options.hpp b/validator/validator-options.hpp index 9bdc61c0..bbd8ce12 100644 --- a/validator/validator-options.hpp +++ b/validator/validator-options.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.h b/validator/validator.h index 347efb29..459df645 100644 --- a/validator/validator.h +++ b/validator/validator.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