Skip to content

Commit dfc040c

Browse files
author
ton
committedApr 6, 2020
validator: multiple bugfixes
1 parent 7efb345 commit dfc040c

17 files changed

+255
-65
lines changed
 

‎crypto/block/block.tlb

+3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ message$_ {X:Type} info:CommonMsgInfo
151151
message$_ {X:Type} info:CommonMsgInfoRelaxed
152152
init:(Maybe (Either StateInit ^StateInit))
153153
body:(Either X ^X) = MessageRelaxed X;
154+
155+
_ (Message Any) = MessageAny;
156+
154157
//
155158
interm_addr_regular$0 use_dest_bits:(#<= 96)
156159
= IntermediateAddress;
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/fift -s
2+
"TonUtil.fif" include
3+
"GetOpt.fif" include
4+
5+
{ show-options-help 1 halt } : usage
6+
7+
"" =: comment // comment for simple transfers
8+
true =: allow-bounce
9+
false =: force-bounce
10+
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
11+
60 =: timeout // external message expires in 60 seconds
12+
variable extra-currencies
13+
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
14+
15+
begin-options
16+
" <filename-base> <dest-addr> <subwallet-id> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
17+
+"Creates one request to highload wallet created by new-highload-wallet-v2.fif, with private key loaded from file <filename-base>.pk "
18+
+"and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
19+
disable-digit-options generic-help-setopt
20+
"n" "--no-bounce" { false =: allow-bounce } short-long-option
21+
"Clears bounce flag" option-help
22+
"b" "--force-bounce" { true =: force-bounce } short-long-option
23+
"Forces bounce flag" option-help
24+
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
25+
"Indicates the amount of extra currencies to be transfered" option-help
26+
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
27+
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
28+
"B" "--body" { =: body-boc-file } short-long-option-arg
29+
"Sets the payload of the transfer message" option-help
30+
"C" "--comment" { =: comment } short-long-option-arg
31+
"Sets the comment to be sent in the transfer message" option-help
32+
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
33+
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
34+
option-help
35+
"h" "--help" { usage } short-long-option
36+
"Shows a help message" option-help
37+
parse-options
38+
39+
$# dup 4 < swap 5 > or ' usage if
40+
5 :$1..n
41+
42+
true constant bounce
43+
$1 =: file-base
44+
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
45+
$3 parse-int =: subwallet-id
46+
$4 $>cc extra-cc+! extra-currencies @ 2=: amount
47+
$5 "wallet-query" replace-if-null =: savefile
48+
{ subwallet-id (.) $+ } : +subwallet
49+
50+
file-base +subwallet +".addr" load-address
51+
2dup 2constant wallet_addr
52+
."Source wallet address = " 2dup .addr cr 6 .Addr cr
53+
file-base +".pk" load-keypair nip constant wallet_pk
54+
55+
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
56+
constant body-cell
57+
58+
."Transferring " amount .GR+cc ."to account "
59+
dest_addr 2dup bounce 7 + .Addr ." = " .addr
60+
."subwallet-id=0x" subwallet-id x.
61+
."timeout=" timeout . ."bounce=" bounce . cr
62+
."Body of transfer message is " body-cell <s csr. cr
63+
64+
variable orders dictnew orders !
65+
variable order# order# 0!
66+
// c --
67+
{ <s order# @ dup 254 >= abort"more than 254 orders"
68+
orders @ 16 udict!+ not abort"cannot add order to dictionary"
69+
orders ! order# 1+!
70+
} : add-order
71+
// b body -- b'
72+
{ tuck <s 2dup 1 s-fits-with? not rot over 1 i, -rot
73+
{ drop swap ref, } { s, nip } cond
74+
} : append-msg-body
75+
// ng wc addr bounce body -- c
76+
{ <b b{01} s, rot 1 i, b{000100} s, 2swap addr, rot Gram,
77+
0 9 64 32 + + 1+ u, swap append-msg-body b>
78+
} : create-int-msg
79+
// ng wc addr bnc --
80+
{ ."Transferring " 3 roll .GR ."to account "
81+
-rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr
82+
} : .transfer
83+
// addr$ ng -- c
84+
{ swap parse-smc-addr force-bounce or allow-bounce and // ng wc addr bnc
85+
2over 2over .transfer
86+
<b 0 32 u, b> create-int-msg
87+
} : create-simple-transfer
88+
// c m -- c'
89+
{ <b swap 8 u, swap ref, b> } : create-order
90+
91+
// addr$ ng --
92+
{ create-simple-transfer send-mode create-order add-order } : send
93+
{ bl word bl word $>GR send } : SEND
94+
95+
// create internal message
96+
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
97+
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
98+
b>
99+
send-mode create-order add-order
100+
101+
// create external message
102+
now timeout + 32 << <b orders @ dict, b> hashu 32 1<<1- and + =: query_id
103+
<b subwallet-id 32 i, query_id 64 u, orders @ dict, b>
104+
dup ."signing message: " <s csr. cr
105+
dup hashu wallet_pk ed25519_sign_uint
106+
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
107+
swap B, swap <s s, b>
108+
dup ."resulting external message: " <s csr. cr
109+
2 boc+>B dup Bx. cr
110+
."Query_id is " query_id dup . ."= 0x" X. cr
111+
savefile +".boc" tuck B>file
112+
."(Saved to file " type .")" cr

‎crypto/smartcont/wallet.fif

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ begin-options
2626
"Sets the payload of the transfer message" option-help
2727
"C" "--comment" { =: comment } short-long-option-arg
2828
"Sets the comment to be sent in the transfer message" option-help
29+
"I" "--with-init" { =: init-file } short-long-option-arg
30+
"Indicates filename with BoC containing StateInit for internal message" option-help
2931
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
3032
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
3133
option-help
@@ -52,13 +54,17 @@ file-base +".pk" load-keypair nip constant wallet_pk
5254
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
5355
constant body-cell
5456

57+
def? init-file { @' init-file file>B B>boc <s b{11} swap |_ } { b{0} } cond
58+
=: state-init
59+
5560
."Transferring " amount .GR+cc ."to account "
5661
dest_addr 2dup bounce 7 + .Addr ." = " .addr
5762
."seqno=0x" seqno x. ."bounce=" bounce . cr
5863
."Body of transfer message is " body-cell <s csr. cr
64+
."StateInit is " state-init csr. cr
5965

6066
// create a message
61-
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
67+
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 8 64 32 + + u, state-init s,
6268
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
6369
b>
6470
<b seqno 32 u, send-mode 8 u, swap ref, b>

‎crypto/vm/dict.cpp

+17-5
Original file line numberDiff line numberDiff line change
@@ -1670,40 +1670,51 @@ Ref<vm::Cell> DictionaryFixed::extract_prefix_subdict_root(td::ConstBitPtr prefi
16701670
}
16711671

16721672
std::pair<Ref<Cell>, int> DictionaryFixed::dict_filter(Ref<Cell> dict, td::BitPtr key, int n,
1673-
const DictionaryFixed::filter_func_t& check_leaf) const {
1673+
const DictionaryFixed::filter_func_t& check_leaf,
1674+
int& skip_rest) const {
16741675
// std::cerr << "dictionary filter for " << n << "-bit key = " << (key + n - key_bits).to_hex(key_bits - n)
16751676
// << std::endl;
16761677
if (dict.is_null()) {
16771678
// empty dictionary, return unchanged
16781679
return {{}, 0};
16791680
}
1681+
if (skip_rest >= 0) {
1682+
// either drop subtree completely (if skip_rest>0), or retain it completely (if skip_rest=0)
1683+
return {{}, skip_rest};
1684+
}
16801685
LabelParser label{std::move(dict), n, label_mode()};
16811686
assert(label.l_bits >= 0 && label.l_bits <= n);
16821687
label.extract_label_to(key);
16831688
key += label.l_bits;
16841689
if (label.l_bits == n) {
16851690
// leaf
16861691
int res = check_leaf(label.remainder.write(), key - key_bits, key_bits);
1692+
if (res >= (1 << 30)) {
1693+
// skip all, or retain all
1694+
res &= (1 << 30) - 1;
1695+
skip_rest = (res ? 0 : (1 << 30));
1696+
}
16871697
return {{}, res < 0 ? res : !res};
16881698
}
16891699
// fork, process left and right subtrees
16901700
++key;
16911701
key[-1] = false;
16921702
int delta = label.l_bits + 1;
16931703
n -= delta;
1694-
auto left_res = dict_filter(label.remainder->prefetch_ref(0), key, n, check_leaf);
1704+
auto left_res = dict_filter(label.remainder->prefetch_ref(0), key, n, check_leaf, skip_rest);
16951705
if (left_res.second < 0) {
16961706
return left_res;
16971707
}
16981708
key[-1] = true;
1699-
auto right_res = dict_filter(label.remainder->prefetch_ref(1), key, n, check_leaf);
1709+
auto right_res = dict_filter(label.remainder->prefetch_ref(1), key, n, check_leaf, skip_rest);
17001710
if ((left_res.second | right_res.second) <= 0) {
17011711
// error in right, or both left and right unchanged
17021712
return right_res;
17031713
}
17041714
auto left = left_res.second ? std::move(left_res.first) : label.remainder->prefetch_ref(0);
17051715
auto right = right_res.second ? std::move(right_res.first) : label.remainder->prefetch_ref(1);
1706-
auto changes = left_res.second + right_res.second;
1716+
// 2^30 is effectively infinity, meaning that we dropped whole branches with unknown # of nodes
1717+
auto changes = ((left_res.second | right_res.second) & (1 << 30)) ? (1 << 30) : left_res.second + right_res.second;
17071718
label.clear();
17081719
if (left.is_null()) {
17091720
if (right.is_null()) {
@@ -1735,8 +1746,9 @@ std::pair<Ref<Cell>, int> DictionaryFixed::dict_filter(Ref<Cell> dict, td::BitPt
17351746

17361747
int DictionaryFixed::filter(DictionaryFixed::filter_func_t check_leaf) {
17371748
force_validate();
1749+
int skip_rest = -1;
17381750
unsigned char buffer[DictionaryFixed::max_key_bytes];
1739-
auto res = dict_filter(get_root_cell(), td::BitPtr{buffer}, key_bits, check_leaf);
1751+
auto res = dict_filter(get_root_cell(), td::BitPtr{buffer}, key_bits, check_leaf, skip_rest);
17401752
if (res.second > 0) {
17411753
// std::cerr << "after filter (" << res.second << " changes): new augmented dictionary root is:\n";
17421754
// vm::load_cell_slice(res.first).print_rec(std::cerr);

‎crypto/vm/dict.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,8 @@ class DictionaryFixed : public DictionaryBase {
293293
bool remove_prefix = false) const;
294294
bool dict_check_for_each(Ref<Cell> dict, td::BitPtr key_buffer, int n, int total_key_len,
295295
const foreach_func_t& foreach_func, bool invert_first = false) const;
296-
std::pair<Ref<Cell>, int> dict_filter(Ref<Cell> dict, td::BitPtr key, int n, const filter_func_t& check_leaf) const;
296+
std::pair<Ref<Cell>, int> dict_filter(Ref<Cell> dict, td::BitPtr key, int n, const filter_func_t& check_leaf,
297+
int& skip_rest) const;
297298
Ref<Cell> dict_combine_with(Ref<Cell> dict1, Ref<Cell> dict2, td::BitPtr key_buffer, int n, int total_key_len,
298299
const combine_func_t& combine_func, int mode = 0, int skip1 = 0, int skip2 = 0) const;
299300
bool dict_scan_diff(Ref<Cell> dict1, Ref<Cell> dict2, td::BitPtr key_buffer, int n, int total_key_len,

‎doc/ConfigParam-HOWTO

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ We see that the list of all active configuration proposals consists of exactly o
215215

216216
[6465...6321 [1586779536 0 [8 C{FDCD...} -1] 1124...2998 () 8646...209 3 0 0]]
217217

218-
Here the first number 6465..6321 is the unique identifier of the configuration proposal, equal to its 256-bit hash. The second component of this pair is a Tuple describing the status of this configuration proposal. The first component of this Tuple is the expiration Unixtime of the configuration proposal (1586779546). The second component (0) is the criticality flag. Next comes the configuration proposal proper, described by triple [8 C{FDCD...} -1], where 8 is the index of the configuration parameter to be modified, C{FDCD...} is the cell with the new value (represented by the hash of this cell), and -1 is the optional hash of the old value of this parameter (-1 means that this hash has not been specified). Next we see a large number 1124...2998 representing the identifier of the current validator set, then an empty list () representing the set of all currently active validators that have voted for this proposal so far, then *weight_remaining* equal to 8646...209 - a number that is positive if the proposal has not yet collected enough validator votes in this round, and negative otherwise. Then we see three numbers 3 0 0. These numbers are *rounds_remaining* (this proposal will survive at most three rounds, i.e., changes of the current validator set), *wins* (the count of rounds where the proposal collected votes of more than 3/4 of all validators by weight) and *losses* (the count of rounds where the proposal failed to collect 3/4 of all validator votes).
218+
Here the first number 6465..6321 is the unique identifier of the configuration proposal, equal to its 256-bit hash. The second component of this pair is a Tuple describing the status of this configuration proposal. The first component of this Tuple is the expiration Unixtime of the configuration proposal (1586779536). The second component (0) is the criticality flag. Next comes the configuration proposal proper, described by triple [8 C{FDCD...} -1], where 8 is the index of the configuration parameter to be modified, C{FDCD...} is the cell with the new value (represented by the hash of this cell), and -1 is the optional hash of the old value of this parameter (-1 means that this hash has not been specified). Next we see a large number 1124...2998 representing the identifier of the current validator set, then an empty list () representing the set of all currently active validators that have voted for this proposal so far, then *weight_remaining* equal to 8646...209 - a number that is positive if the proposal has not yet collected enough validator votes in this round, and negative otherwise. Then we see three numbers 3 0 0. These numbers are *rounds_remaining* (this proposal will survive at most three rounds, i.e., changes of the current validator set), *wins* (the count of rounds where the proposal collected votes of more than 3/4 of all validators by weight) and *losses* (the count of rounds where the proposal failed to collect 3/4 of all validator votes).
219219

220220
We can inspect the proposed value for configuration parameter #8 by asking the lite-client to expand cell C{FDCD...} using its hash FDCD... or a sufficiently long prefix of this hash to uniquely identify the cell in question:
221221

‎validator-session/validator-session-description.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
You should have received a copy of the GNU Lesser General Public License
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
17-
Copyright 2017-2019 Telegram Systems LLP
17+
Copyright 2017-2020 Telegram Systems LLP
1818
*/
1919
#include "validator-session.hpp"
2020
#include "td/utils/Random.h"
@@ -52,10 +52,10 @@ ValidatorSessionDescriptionImpl::ValidatorSessionDescriptionImpl(ValidatorSessio
5252
self_idx_ = it->second;
5353

5454
pdata_temp_ptr_ = 0;
55-
pdata_temp_size_ = 1 << 30;
55+
pdata_temp_size_ = 1 << 27;
5656
pdata_temp_ = new td::uint8[pdata_temp_size_];
5757

58-
pdata_perm_size_ = 1ull << 30;
58+
pdata_perm_size_ = 1ull << 27;
5959
pdata_perm_ptr_ = 0;
6060

6161
for (auto &el : cache_) {

‎validator-session/validator-session-description.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
You should have received a copy of the GNU Lesser General Public License
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
17-
Copyright 2017-2019 Telegram Systems LLP
17+
Copyright 2017-2020 Telegram Systems LLP
1818
*/
1919
#pragma once
2020

‎validator/impl/collator-impl.h

+3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class Collator final : public td::actor::Actor {
5959
bool preinit_complete{false};
6060
bool is_key_block_{false};
6161
bool block_full_{false};
62+
bool outq_cleanup_partial_{false};
6263
bool inbound_queues_empty_{false};
6364
bool libraries_changed_{false};
6465
bool prev_key_block_exists_{false};
@@ -144,6 +145,8 @@ class Collator final : public td::actor::Actor {
144145
bool ihr_enabled_{false};
145146
bool create_stats_enabled_{false};
146147
bool report_version_{false};
148+
bool skip_topmsgdescr_{false};
149+
bool skip_extmsg_{false};
147150
td::uint64 overload_history_{0}, underload_history_{0};
148151
td::uint64 block_size_estimate_{};
149152
Ref<block::WorkchainInfo> wc_info_;

‎validator/impl/collator.cpp

+49-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "validator-set.hpp"
3535
#include "top-shard-descr.hpp"
3636
#include <ctime>
37+
#include "td/utils/Random.h"
3738

3839
namespace ton {
3940

@@ -1208,6 +1209,9 @@ bool Collator::import_new_shard_top_blocks() {
12081209
if (shard_block_descr_.empty()) {
12091210
return true;
12101211
}
1212+
if (skip_topmsgdescr_) {
1213+
return true;
1214+
}
12111215
auto lt_limit = config_->lt + config_->get_max_lt_growth();
12121216
std::sort(shard_block_descr_.begin(), shard_block_descr_.end(), cmp_shard_block_descr_ref);
12131217
int tb_act = 0;
@@ -1442,6 +1446,37 @@ bool Collator::init_utime() {
14421446
"error initializing unix time for the new block: failed to observe end of fsm_split time interval for this "
14431447
"shard");
14441448
}
1449+
// check whether masterchain catchain rotation is overdue
1450+
auto ccvc = config_->get_catchain_validators_config();
1451+
unsigned lifetime = ccvc.mc_cc_lifetime;
1452+
if (is_masterchain() && now_ / lifetime > prev_now_ / lifetime && now_ > (prev_now_ / lifetime + 1) * lifetime + 20) {
1453+
auto overdue = now_ - (prev_now_ / lifetime + 1) * lifetime;
1454+
// masterchain catchain rotation overdue, skip topsharddescr with some probability
1455+
skip_topmsgdescr_ = (td::Random::fast(0, 1023) < 256); // probability 1/4
1456+
skip_extmsg_ = (td::Random::fast(0, 1023) < 256); // skip ext msg probability 1/4
1457+
if (skip_topmsgdescr_) {
1458+
LOG(WARNING)
1459+
<< "randomly skipping import of new shard data because of overdue masterchain catchain rotation (overdue by "
1460+
<< overdue << " seconds)";
1461+
}
1462+
if (skip_extmsg_) {
1463+
LOG(WARNING)
1464+
<< "randomly skipping external message import because of overdue masterchain catchain rotation (overdue by "
1465+
<< overdue << " seconds)";
1466+
}
1467+
} else if (is_masterchain() && now_ > prev_now_ + 60) {
1468+
auto interval = now_ - prev_now_;
1469+
skip_topmsgdescr_ = (td::Random::fast(0, 1023) < 128); // probability 1/8
1470+
skip_extmsg_ = (td::Random::fast(0, 1023) < 128); // skip ext msg probability 1/8
1471+
if (skip_topmsgdescr_) {
1472+
LOG(WARNING) << "randomly skipping import of new shard data because of overdue masterchain block (last block was "
1473+
<< interval << " seconds ago)";
1474+
}
1475+
if (skip_extmsg_) {
1476+
LOG(WARNING) << "randomly skipping external message import because of overdue masterchain block (last block was "
1477+
<< interval << " seconds ago)";
1478+
}
1479+
}
14451480
return true;
14461481
}
14471482

@@ -1742,7 +1777,7 @@ bool Collator::dequeue_message(Ref<vm::Cell> msg_envelope, ton::LogicalTime deli
17421777
}
17431778

17441779
bool Collator::out_msg_queue_cleanup() {
1745-
LOG(DEBUG) << "in out_msg_queue_cleanup()";
1780+
LOG(INFO) << "cleaning outbound queue from messages already imported by neighbors";
17461781
if (verbosity >= 2) {
17471782
auto rt = out_msg_queue_->get_root();
17481783
std::cerr << "old out_msg_queue is ";
@@ -1759,6 +1794,11 @@ bool Collator::out_msg_queue_cleanup() {
17591794
auto res = out_msg_queue_->filter([&](vm::CellSlice& cs, td::ConstBitPtr key, int n) -> int {
17601795
assert(n == 352);
17611796
// LOG(DEBUG) << "key is " << key.to_hex(n);
1797+
if (block_full_) {
1798+
LOG(WARNING) << "BLOCK FULL while cleaning up outbound queue, cleanup completed only partially";
1799+
outq_cleanup_partial_ = true;
1800+
return (1 << 30) + 1; // retain all remaining outbound queue entries including this one without processing
1801+
}
17621802
block::EnqueuedMsgDescr enq_msg_descr;
17631803
unsigned long long created_lt;
17641804
if (!(cs.fetch_ulong_bool(64, created_lt) // augmentation
@@ -1789,6 +1829,10 @@ bool Collator::out_msg_queue_cleanup() {
17891829
<< enq_msg_descr.hash_.to_hex() << ") by inserting a msg_export_deq record");
17901830
return -1;
17911831
}
1832+
register_out_msg_queue_op();
1833+
if (!block_limit_status_->fits(block::ParamLimits::cl_normal)) {
1834+
block_full_ = true;
1835+
}
17921836
}
17931837
return !delivered;
17941838
});
@@ -2631,6 +2675,10 @@ bool Collator::process_inbound_internal_messages() {
26312675
}
26322676

26332677
bool Collator::process_inbound_external_messages() {
2678+
if (skip_extmsg_) {
2679+
LOG(INFO) << "skipping processing of inbound external messages";
2680+
return true;
2681+
}
26342682
bool full = !block_limit_status_->fits(block::ParamLimits::cl_soft);
26352683
for (auto& ext_msg_pair : ext_msg_list_) {
26362684
if (full) {

0 commit comments

Comments
 (0)
Please sign in to comment.