Ton

Форк
0
/
block-parse.cpp 
2328 строк · 100.5 Кб
1
/*
2
    This file is part of TON Blockchain Library.
3

4
    TON Blockchain Library is free software: you can redistribute it and/or modify
5
    it under the terms of the GNU Lesser General Public License as published by
6
    the Free Software Foundation, either version 2 of the License, or
7
    (at your option) any later version.
8

9
    TON Blockchain Library is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU Lesser General Public License for more details.
13

14
    You should have received a copy of the GNU Lesser General Public License
15
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
16

17
    Copyright 2017-2020 Telegram Systems LLP
18
*/
19
#include "td/utils/bits.h"
20
#include "block/block-parse.h"
21
#include "block/block-auto.h"
22
#include "ton/ton-shard.h"
23
#include "common/util.h"
24
#include "td/utils/crypto.h"
25

26
namespace block {
27
using namespace std::literals::string_literals;
28

29
using CombineError = vm::CombineError;
30

31
namespace {
32
bool debug(const char* str) TD_UNUSED;
33
bool debug(const char* str) {
34
  std::cerr << str;
35
  return true;
36
}
37

38
bool debug(int x) TD_UNUSED;
39
bool debug(int x) {
40
  if (x < 100) {
41
    std::cerr << '[' << (char)(64 + x) << ']';
42
  } else {
43
    std::cerr << '[' << (char)(64 + x / 100) << x % 100 << ']';
44
  }
45
  return true;
46
}
47
}  // namespace
48

49
#define DBG_START int dbg = 0;
50
#define DBG debug(++dbg)&&
51
#define DEB_START DBG_START
52
#define DEB DBG
53

54
namespace tlb {
55

56
using namespace ::tlb;
57

58
int MsgAddressExt::get_size(const vm::CellSlice& cs) const {
59
  switch (get_tag(cs)) {
60
    case addr_none:  // 00, addr_none
61
      return 2;
62
    case addr_ext:  // 01, addr_extern
63
      if (cs.have(2 + 9)) {
64
        int len = cs.prefetch_long(2 + 9) & 0x1ff;
65
        return 2 + 9 + len;
66
      }
67
  }
68
  return -1;
69
}
70

71
const MsgAddressExt t_MsgAddressExt;
72

73
const Anycast t_Anycast;
74

75
bool Maybe_Anycast::skip_get_depth(vm::CellSlice& cs, int& depth) const {
76
  depth = 0;
77
  bool have;
78
  return cs.fetch_bool_to(have) && (!have || t_Anycast.skip_get_depth(cs, depth));
79
}
80

81
const Maybe_Anycast t_Maybe_Anycast;
82

83
bool MsgAddressInt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
84
  if (!cs.have(3)) {
85
    return false;
86
  }
87
  switch (get_tag(cs)) {
88
    case addr_std:
89
      return cs.advance(2) && t_Maybe_Anycast.skip(cs) && cs.advance(8 + 256);
90
    case addr_var:
91
      if (cs.advance(2) && t_Maybe_Anycast.skip(cs) && cs.have(9 + 32)) {
92
        int addr_len = (int)cs.fetch_ulong(9);
93
        int workchain_id = (int)cs.fetch_long(32);
94
        return cs.advance(addr_len) && (workchain_id < -0x80 || workchain_id > 0x7f || addr_len != 256) &&
95
               (workchain_id != 0 && workchain_id != -1);
96
      }
97
  }
98
  return false;
99
}
100

101
bool MsgAddressInt::skip_get_depth(vm::CellSlice& cs, int& depth) const {
102
  if (!cs.have(3)) {
103
    return false;
104
  }
105
  switch (get_tag(cs)) {
106
    case addr_std:
107
      return cs.advance(2) && t_Maybe_Anycast.skip_get_depth(cs, depth) && cs.advance(8 + 256);
108
    case addr_var:
109
      if (cs.advance(2) && t_Maybe_Anycast.skip_get_depth(cs, depth) && cs.have(9 + 32)) {
110
        int addr_len = (int)cs.fetch_ulong(9);
111
        return cs.advance(32 + addr_len);
112
      }
113
  }
114
  return false;
115
}
116

117
ton::AccountIdPrefixFull MsgAddressInt::get_prefix(vm::CellSlice&& cs) {
118
  if (!cs.have(3 + 8 + 64)) {
119
    return {};
120
  }
121
  ton::WorkchainId workchain;
122
  unsigned long long prefix;
123
  int t = (int)cs.prefetch_ulong(2 + 1 + 5);
124
  switch (t >> 5) {
125
    case 4: {  // addr_std$10, anycast=nothing$0
126
      if (cs.advance(3) && cs.fetch_int_to(8, workchain) && cs.fetch_uint_to(64, prefix)) {
127
        return {workchain, prefix};
128
      }
129
      break;
130
    }
131
    case 5: {   // addr_std$10, anycast=just$1 (Anycast)
132
      t &= 31;  // depth:(## 5)
133
      unsigned long long rewrite;
134
      if (cs.advance(8) && cs.fetch_uint_to(t, rewrite)  // rewrite_pfx:(bits depth)
135
          && cs.fetch_int_to(8, workchain)               // workchain_id:int8
136
          && cs.fetch_uint_to(64, prefix)) {             // address:bits256
137
        rewrite <<= 64 - t;
138
        return {workchain, (prefix & (std::numeric_limits<td::uint64>::max() >> t)) | rewrite};
139
      }
140
      break;
141
    }
142
    case 6: {  // addr_var$11, anycast=nothing$0
143
      int len;
144
      if (cs.advance(3) && cs.fetch_uint_to(9, len)  // addr_len:(## 9)
145
          && len >= 64                               // { len >= 64 }
146
          && cs.fetch_int_to(32, workchain)          // workchain_id:int32
147
          && cs.fetch_uint_to(64, prefix)) {         // address:(bits addr_len)
148
        return {workchain, prefix};
149
      }
150
      break;
151
    }
152
    case 7: {   // addr_var$11, anycast=just$1 (Anycast)
153
      t &= 31;  // depth:(## 5)
154
      int len;
155
      unsigned long long rewrite;
156
      if (cs.advance(8) && cs.fetch_uint_to(t, rewrite)  // rewrite_pfx:(bits depth)
157
          && cs.fetch_uint_to(9, len)                    // addr_len:(## 9)
158
          && len >= 64                                   // { len >= 64 }
159
          && cs.fetch_int_to(32, workchain)              // workchain_id:int32
160
          && cs.fetch_uint_to(64, prefix)) {             // address:bits256
161
        rewrite <<= 64 - t;
162
        return {workchain, (prefix & (std::numeric_limits<td::uint64>::max() >> t)) | rewrite};
163
      }
164
      break;
165
    }
166
  }
167
  return {};
168
}
169

170
ton::AccountIdPrefixFull MsgAddressInt::get_prefix(const vm::CellSlice& cs) {
171
  return get_prefix(vm::CellSlice{cs});
172
}
173

174
ton::AccountIdPrefixFull MsgAddressInt::get_prefix(Ref<vm::CellSlice> cs_ref) {
175
  if (cs_ref->is_unique()) {
176
    return get_prefix(std::move(cs_ref.unique_write()));
177
  } else {
178
    return get_prefix(vm::CellSlice{*cs_ref});
179
  }
180
}
181

182
bool MsgAddressInt::extract_std_address(Ref<vm::CellSlice> cs_ref, ton::WorkchainId& workchain,
183
                                        ton::StdSmcAddress& addr, bool rewrite) const {
184
  if (cs_ref.is_null()) {
185
    return false;
186
  } else if (cs_ref->is_unique()) {
187
    return extract_std_address(cs_ref.unique_write(), workchain, addr, rewrite);
188
  } else {
189
    vm::CellSlice cs{*cs_ref};
190
    return extract_std_address(cs, workchain, addr, rewrite);
191
  }
192
}
193

194
bool MsgAddressInt::extract_std_address(vm::CellSlice& cs, ton::WorkchainId& workchain, ton::StdSmcAddress& addr,
195
                                        bool do_rewrite) const {
196
  if (!cs.have(3 + 8 + 64)) {
197
    return {};
198
  }
199
  int t = (int)cs.prefetch_ulong(2 + 1 + 5);
200
  switch (t >> 5) {
201
    case 4: {  // addr_std$10, anycast=nothing$0
202
      return cs.advance(3) && cs.fetch_int_to(8, workchain) && cs.fetch_bits_to(addr);
203
    }
204
    case 5: {   // addr_std$10, anycast=just$1 (Anycast)
205
      t &= 31;  // depth:(## 5)
206
      unsigned long long rewrite;
207
      if (cs.advance(8) && cs.fetch_uint_to(t, rewrite)  // rewrite_pfx:(bits depth)
208
          && cs.fetch_int_to(8, workchain)               // workchain_id:int8
209
          && cs.fetch_bits_to(addr)) {                   // address:bits256
210
        if (do_rewrite) {
211
          addr.bits().store_uint(rewrite, t);
212
        }
213
        return true;
214
      }
215
      break;
216
    }
217
    case 6: {  // addr_var$11, anycast=nothing$0
218
      int len;
219
      return cs.advance(3) && cs.fetch_uint_to(9, len)  // addr_len:(## 9)
220
             && len == 256                              // only 256-bit addresses are standard
221
             && cs.fetch_int_to(32, workchain)          // workchain_id:int32
222
             && cs.fetch_bits_to(addr);                 // address:(bits addr_len)
223
    }
224
    case 7: {   // addr_var$11, anycast=just$1 (Anycast)
225
      t &= 31;  // depth:(## 5)
226
      int len;
227
      unsigned long long rewrite;
228
      if (cs.advance(8) && cs.fetch_uint_to(t, rewrite)  // rewrite_pfx:(bits depth)
229
          && cs.fetch_uint_to(9, len)                    // addr_len:(## 9)
230
          && len == 256                                  // only 256-bit addresses are standard
231
          && cs.fetch_int_to(32, workchain)              // workchain_id:int32
232
          && cs.fetch_bits_to(addr)) {                   // address:bits256
233
        if (do_rewrite) {
234
          addr.bits().store_uint(rewrite, t);
235
        }
236
        return true;
237
      }
238
      break;
239
    }
240
  }
241
  return false;
242
}
243

244
bool MsgAddressInt::extract_std_address(Ref<vm::CellSlice> cs_ref, block::StdAddress& addr, bool rewrite) const {
245
  return extract_std_address(std::move(cs_ref), addr.workchain, addr.addr, rewrite);
246
}
247

248
bool MsgAddressInt::extract_std_address(vm::CellSlice& cs, block::StdAddress& addr, bool rewrite) const {
249
  return extract_std_address(cs, addr.workchain, addr.addr, rewrite);
250
}
251

252
bool MsgAddressInt::store_std_address(vm::CellBuilder& cb, ton::WorkchainId workchain,
253
                                      const ton::StdSmcAddress& addr) const {
254
  if (workchain >= -128 && workchain < 128) {
255
    return cb.store_long_bool(4, 3)             // addr_std$10 anycast:(Maybe Anycast)
256
           && cb.store_long_bool(workchain, 8)  // workchain_id:int8
257
           && cb.store_bits_bool(addr);         // address:bits256 = MsgAddressInt;
258
  } else {
259
    return cb.store_long_bool(0xd00, 12)         // addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
260
           && cb.store_long_bool(workchain, 32)  // workchain_id:int32
261
           && cb.store_bits_bool(addr);          // address:(bits addr_len) = MsgAddressInt;
262
  }
263
}
264

265
Ref<vm::CellSlice> MsgAddressInt::pack_std_address(ton::WorkchainId workchain, const ton::StdSmcAddress& addr) const {
266
  vm::CellBuilder cb;
267
  if (store_std_address(cb, workchain, addr)) {
268
    return vm::load_cell_slice_ref(cb.finalize());
269
  } else {
270
    return {};
271
  }
272
}
273

274
bool MsgAddressInt::store_std_address(vm::CellBuilder& cb, const block::StdAddress& addr) const {
275
  return store_std_address(cb, addr.workchain, addr.addr);
276
}
277

278
Ref<vm::CellSlice> MsgAddressInt::pack_std_address(const block::StdAddress& addr) const {
279
  return pack_std_address(addr.workchain, addr.addr);
280
}
281

282
const MsgAddressInt t_MsgAddressInt;
283

284
bool MsgAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
285
  switch (get_tag(cs)) {
286
    case addr_none:
287
    case addr_ext:
288
      return t_MsgAddressExt.validate_skip(ops, cs, weak);
289
    case addr_std:
290
    case addr_var:
291
      return t_MsgAddressInt.validate_skip(ops, cs, weak);
292
  }
293
  return false;
294
}
295

296
const MsgAddress t_MsgAddress;
297

298
bool VarUInteger::skip(vm::CellSlice& cs) const {
299
  int len = (int)cs.fetch_ulong(ln);
300
  return len >= 0 && len < n && cs.advance(len * 8);
301
}
302

303
bool VarUInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
304
  int len = (int)cs.fetch_ulong(ln);
305
  return len >= 0 && len < n && (!len || cs.prefetch_ulong(8)) && cs.advance(len * 8);
306
}
307

308
td::RefInt256 VarUInteger::as_integer_skip(vm::CellSlice& cs) const {
309
  int len = (int)cs.fetch_ulong(ln);
310
  return (len >= 0 && len < n && (!len || cs.prefetch_ulong(8))) ? cs.fetch_int256(len * 8, false) : td::RefInt256{};
311
}
312

313
unsigned long long VarUInteger::as_uint(const vm::CellSlice& cs) const {
314
  int len = (int)cs.prefetch_ulong(ln);
315
  return len >= 0 && len <= 8 && cs.have(ln + len * 8) ? td::bitstring::bits_load_ulong(cs.data_bits() + ln, len * 8)
316
                                                       : std::numeric_limits<td::uint64>::max();
317
}
318

319
bool VarUInteger::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
320
  int k = value.bit_size(false);
321
  return k <= (n - 1) * 8 && cb.store_long_bool((k + 7) >> 3, ln) && cb.store_int256_bool(value, (k + 7) & -8, false);
322
}
323

324
unsigned VarUInteger::precompute_integer_size(const td::BigInt256& value) const {
325
  int k = value.bit_size(false);
326
  return k <= (n - 1) * 8 ? ln + ((k + 7) & -8) : 0xfff;
327
}
328

329
unsigned VarUInteger::precompute_integer_size(td::RefInt256 value) const {
330
  if (value.is_null()) {
331
    return 0xfff;
332
  }
333
  int k = value->bit_size(false);
334
  return k <= (n - 1) * 8 ? ln + ((k + 7) & -8) : 0xfff;
335
}
336

337
const VarUInteger t_VarUInteger_3{3}, t_VarUInteger_7{7}, t_VarUInteger_16{16}, t_VarUInteger_32{32};
338

339
bool VarUIntegerPos::skip(vm::CellSlice& cs) const {
340
  int len = (int)cs.fetch_ulong(ln);
341
  return len > 0 && len < n && cs.advance(len * 8);
342
}
343

344
bool VarUIntegerPos::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
345
  int len = (int)cs.fetch_ulong(ln);
346
  return len > 0 && len < n && cs.prefetch_ulong(8) && cs.advance(len * 8);
347
}
348

349
td::RefInt256 VarUIntegerPos::as_integer_skip(vm::CellSlice& cs) const {
350
  int len = (int)cs.fetch_ulong(ln);
351
  return (len > 0 && len < n && cs.prefetch_ulong(8)) ? cs.fetch_int256(len * 8, false) : td::RefInt256{};
352
}
353

354
unsigned long long VarUIntegerPos::as_uint(const vm::CellSlice& cs) const {
355
  int len = (int)cs.prefetch_ulong(ln);
356
  return len > 0 && len <= 8 && cs.have(ln + len * 8) && cs.prefetch_ulong(8)
357
             ? td::bitstring::bits_load_ulong(cs.data_bits() + ln, len * 8)
358
             : std::numeric_limits<td::uint64>::max();
359
}
360

361
bool VarUIntegerPos::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
362
  int k = value.bit_size(false);
363
  return k <= (n - 1) * 8 && value.sgn() >= (int)store_pos_only && cb.store_long_bool((k + 7) >> 3, ln) &&
364
         cb.store_int256_bool(value, (k + 7) & -8, false);
365
}
366

367
const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32}, t_VarUIntegerPosRelaxed_32{32, true};
368

369
static inline bool redundant_int(const vm::CellSlice& cs) {
370
  int t = (int)cs.prefetch_long(9);
371
  return t == 0 || t == -1;
372
}
373

374
bool VarInteger::skip(vm::CellSlice& cs) const {
375
  int len = (int)cs.fetch_ulong(ln);
376
  return len >= 0 && len < n && cs.advance(len * 8);
377
}
378

379
bool VarInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
380
  int len = (int)cs.fetch_ulong(ln);
381
  return len >= 0 && len < n && (!len || !redundant_int(cs)) && cs.advance(len * 8);
382
}
383

384
td::RefInt256 VarInteger::as_integer_skip(vm::CellSlice& cs) const {
385
  int len = (int)cs.fetch_ulong(ln);
386
  return (len >= 0 && len < n && (!len || !redundant_int(cs))) ? cs.fetch_int256(len * 8, true) : td::RefInt256{};
387
}
388

389
long long VarInteger::as_int(const vm::CellSlice& cs) const {
390
  int len = (int)cs.prefetch_ulong(ln);
391
  return len >= 0 && len <= 8 && cs.have(ln + len * 8) ? td::bitstring::bits_load_long(cs.data_bits() + ln, len * 8)
392
                                                       : (1ULL << 63);
393
}
394

395
bool VarInteger::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
396
  int k = value.bit_size(true);
397
  return k <= (n - 1) * 8 && cb.store_long_bool((k + 7) >> 3, ln) && cb.store_int256_bool(value, (k + 7) & -8, true);
398
}
399

400
bool VarIntegerNz::skip(vm::CellSlice& cs) const {
401
  int len = (int)cs.fetch_ulong(ln);
402
  return len > 0 && len < n && cs.advance(len * 8);
403
}
404

405
bool VarIntegerNz::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
406
  int len = (int)cs.fetch_ulong(ln);
407
  return len > 0 && len < n && !redundant_int(cs) && cs.advance(len * 8);
408
}
409

410
td::RefInt256 VarIntegerNz::as_integer_skip(vm::CellSlice& cs) const {
411
  int len = (int)cs.fetch_ulong(ln);
412
  return (len > 0 && len < n && !redundant_int(cs)) ? cs.fetch_int256(len * 8, true) : td::RefInt256{};
413
}
414

415
long long VarIntegerNz::as_int(const vm::CellSlice& cs) const {
416
  int len = (int)cs.prefetch_ulong(ln);
417
  return len > 0 && len <= 8 && cs.have(ln + len * 8) && !redundant_int(cs)
418
             ? td::bitstring::bits_load_long(cs.data_bits() + ln, len * 8)
419
             : (1ULL << 63);
420
}
421

422
bool VarIntegerNz::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
423
  int k = value.bit_size(true);
424
  return k <= (n - 1) * 8 && value.sgn() != 0 && cb.store_long_bool((k + 7) >> 3, ln) &&
425
         cb.store_int256_bool(value, (k + 7) & -8, true);
426
}
427

428
bool Grams::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
429
  return t_VarUInteger_16.validate_skip(ops, cs, weak);
430
}
431

432
td::RefInt256 Grams::as_integer_skip(vm::CellSlice& cs) const {
433
  return t_VarUInteger_16.as_integer_skip(cs);
434
}
435

436
bool Grams::null_value(vm::CellBuilder& cb) const {
437
  return t_VarUInteger_16.null_value(cb);
438
}
439

440
bool Grams::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
441
  return t_VarUInteger_16.store_integer_value(cb, value);
442
}
443

444
unsigned Grams::precompute_size(const td::BigInt256& value) const {
445
  return t_VarUInteger_16.precompute_integer_size(value);
446
}
447

448
unsigned Grams::precompute_size(td::RefInt256 value) const {
449
  return t_VarUInteger_16.precompute_integer_size(std::move(value));
450
}
451

452
const Grams t_Grams;
453

454
const Unary t_Unary;
455

456
bool HmLabel::validate_skip(vm::CellSlice& cs, bool weak, int& n) const {
457
  switch (get_tag(cs)) {
458
    case hml_short:
459
      return cs.advance(1) && (n = cs.count_leading(1)) <= m && cs.advance(2 * n + 1);
460
    case hml_long:
461
      return cs.advance(2) && cs.fetch_uint_leq(m, n) && cs.advance(n);
462
    case hml_same:
463
      return cs.advance(3) && cs.fetch_uint_leq(m, n);
464
  }
465
  return false;
466
}
467

468
int HmLabel::get_tag(const vm::CellSlice& cs) const {
469
  int tag = (int)cs.prefetch_ulong(2);
470
  return tag != 1 ? tag : hml_short;
471
}
472

473
int HashmapNode::get_size(const vm::CellSlice& cs) const {
474
  assert(n >= 0);
475
  return n ? 0x20000 : value_type.get_size(cs);
476
}
477

478
bool HashmapNode::skip(vm::CellSlice& cs) const {
479
  assert(n >= 0);
480
  return n ? cs.advance_refs(2) : value_type.skip(cs);
481
}
482

483
bool HashmapNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
484
  assert(n >= 0);
485
  if (!n) {
486
    // hmn_leaf
487
    return value_type.validate_skip(ops, cs, weak);
488
  } else {
489
    // hmn_fork
490
    Hashmap branch_type{n - 1, value_type};
491
    return branch_type.validate_ref(ops, cs.fetch_ref(), weak) && branch_type.validate_ref(ops, cs.fetch_ref(), weak);
492
  }
493
}
494

495
bool Hashmap::skip(vm::CellSlice& cs) const {
496
  int l;
497
  return HmLabel{n}.skip(cs, l) && HashmapNode{n - l, value_type}.skip(cs);
498
}
499

500
bool Hashmap::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
501
  int l;
502
  return HmLabel{n}.validate_skip(cs, weak, l) && HashmapNode{n - l, value_type}.validate_skip(ops, cs, weak);
503
}
504

505
int HashmapE::get_size(const vm::CellSlice& cs) const {
506
  int tag = get_tag(cs);
507
  return (tag >= 0 ? (tag > 0 ? 0x10001 : 1) : -1);
508
}
509

510
bool HashmapE::validate(int* ops, const vm::CellSlice& cs, bool weak) const {
511
  int tag = get_tag(cs);
512
  return tag <= 0 ? !tag : root_type.validate_ref(ops, cs.prefetch_ref(), weak);
513
}
514

515
bool HashmapE::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
516
  int n = root_type.n;
517
  vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n};
518
  const TLB& vt = root_type.value_type;
519
  vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
520
                                                        Ref<vm::CellSlice> cs2_ref) -> bool {
521
    if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) {
522
      throw CombineError{};
523
    }
524
    return true;
525
  };
526
  return dict1.combine_with(dict2, combine) && std::move(dict1).append_dict_to_bool(cb);
527
}
528

529
bool HashmapE::add_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cell> arg2) const {
530
  int n = root_type.n;
531
  vm::Dictionary dict1{std::move(arg1), n}, dict2{std::move(arg2), n};
532
  const TLB& vt = root_type.value_type;
533
  vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
534
                                                        Ref<vm::CellSlice> cs2_ref) -> bool {
535
    if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) {
536
      throw CombineError{};
537
    }
538
    return true;
539
  };
540
  if (dict1.combine_with(dict2, combine)) {
541
    dict2.reset();
542
    res = std::move(dict1).extract_root_cell();
543
    return true;
544
  } else {
545
    res = Ref<vm::Cell>{};
546
    return false;
547
  }
548
}
549

550
int HashmapE::sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
551
  int n = root_type.n;
552
  vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n};
553
  const TLB& vt = root_type.value_type;
554
  vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
555
                                                        Ref<vm::CellSlice> cs2_ref) -> bool {
556
    int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write());
557
    if (r < 0) {
558
      throw CombineError{};
559
    }
560
    return r;
561
  };
562
  if (!dict1.combine_with(dict2, combine, 1)) {
563
    return -1;
564
  }
565
  dict2.reset();
566
  bool not_empty = !dict1.is_empty();
567
  return std::move(dict1).append_dict_to_bool(cb) ? not_empty : -1;
568
}
569

570
int HashmapE::sub_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cell> arg2) const {
571
  int n = root_type.n;
572
  vm::Dictionary dict1{std::move(arg1), n}, dict2{std::move(arg2), n};
573
  const TLB& vt = root_type.value_type;
574
  vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
575
                                                        Ref<vm::CellSlice> cs2_ref) -> bool {
576
    int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write());
577
    if (r < 0) {
578
      throw CombineError{};
579
    }
580
    return r;
581
  };
582
  if (dict1.combine_with(dict2, combine, 1)) {
583
    dict2.reset();
584
    res = std::move(dict1).extract_root_cell();
585
    return res.not_null();
586
  } else {
587
    res = Ref<vm::Cell>{};
588
    return -1;
589
  }
590
}
591

592
bool HashmapE::store_ref(vm::CellBuilder& cb, Ref<vm::Cell> arg) const {
593
  if (arg.is_null()) {
594
    return cb.store_long_bool(0, 1);
595
  } else {
596
    return cb.store_long_bool(1, 1) && cb.store_ref_bool(std::move(arg));
597
  }
598
}
599

600
const ExtraCurrencyCollection t_ExtraCurrencyCollection;
601

602
bool CurrencyCollection::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
603
  return t_Grams.validate_skip(ops, cs, weak) && t_ExtraCurrencyCollection.validate_skip(ops, cs, weak);
604
}
605

606
bool CurrencyCollection::skip(vm::CellSlice& cs) const {
607
  return t_Grams.skip(cs) && t_ExtraCurrencyCollection.skip(cs);
608
}
609

610
td::RefInt256 CurrencyCollection::as_integer_skip(vm::CellSlice& cs) const {
611
  auto res = t_Grams.as_integer_skip(cs);
612
  if (res.not_null() && t_ExtraCurrencyCollection.skip(cs)) {
613
    return res;
614
  } else {
615
    return {};
616
  }
617
}
618

619
bool CurrencyCollection::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
620
  return t_Grams.add_values(cb, cs1, cs2) && t_ExtraCurrencyCollection.add_values(cb, cs1, cs2);
621
}
622

623
bool CurrencyCollection::unpack_special(vm::CellSlice& cs, td::RefInt256& balance, Ref<vm::Cell>& extra,
624
                                        bool inexact) const {
625
  balance = t_Grams.as_integer_skip(cs);
626
  if (cs.fetch_ulong(1) == 1) {
627
    return balance.not_null() && cs.fetch_ref_to(extra) && (inexact || cs.empty_ext());
628
  } else {
629
    extra.clear();
630
    return balance.not_null() && (inexact || cs.empty_ext());
631
  }
632
}
633

634
bool CurrencyCollection::unpack_special(vm::CellSlice& cs, block::CurrencyCollection& value, bool inexact) const {
635
  return unpack_special(cs, value.grams, value.extra, inexact);
636
}
637

638
bool CurrencyCollection::pack_special(vm::CellBuilder& cb, td::RefInt256 balance, Ref<vm::Cell> extra) const {
639
  return t_Grams.store_integer_ref(cb, std::move(balance)) && t_ExtraCurrencyCollection.store_ref(cb, std::move(extra));
640
}
641

642
bool CurrencyCollection::pack_special(vm::CellBuilder& cb, const block::CurrencyCollection& value) const {
643
  return value.is_valid() && pack_special(cb, value.grams, value.extra);
644
}
645

646
bool CurrencyCollection::pack_special(vm::CellBuilder& cb, block::CurrencyCollection&& value) const {
647
  return value.is_valid() && pack_special(cb, std::move(value.grams), std::move(value.extra));
648
}
649

650
bool CurrencyCollection::unpack(vm::CellSlice& cs, block::CurrencyCollection& res) const {
651
  return unpack_special(cs, res.grams, res.extra);
652
}
653

654
bool CurrencyCollection::pack(vm::CellBuilder& cb, const block::CurrencyCollection& res) const {
655
  return res.is_valid() && pack_special(cb, res.grams, res.extra);
656
}
657

658
const CurrencyCollection t_CurrencyCollection;
659

660
bool CommonMsgInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
661
  int tag = get_tag(cs);
662
  switch (tag) {
663
    case int_msg_info:
664
      return cs.advance(4)  // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
665
             && t_MsgAddressInt.validate_skip(ops, cs, weak)       // src
666
             && t_MsgAddressInt.validate_skip(ops, cs, weak)       // dest
667
             && t_CurrencyCollection.validate_skip(ops, cs, weak)  // value
668
             && t_Grams.validate_skip(ops, cs, weak)               // ihr_fee
669
             && t_Grams.validate_skip(ops, cs, weak)               // fwd_fee
670
             && cs.advance(64 + 32);                               // created_lt:uint64 created_at:uint32
671
    case ext_in_msg_info:
672
      return cs.advance(2) && t_MsgAddressExt.validate_skip(ops, cs, weak)  // src
673
             && t_MsgAddressInt.validate_skip(ops, cs, weak)                // dest
674
             && t_Grams.validate_skip(ops, cs, weak);                       // import_fee
675
    case ext_out_msg_info:
676
      return cs.advance(2) && t_MsgAddressInt.validate_skip(ops, cs, weak)  // src
677
             && t_MsgAddressExt.validate_skip(ops, cs, weak)                // dest
678
             && cs.advance(64 + 32);                                        // created_lt:uint64 created_at:uint32
679
  }
680
  return false;
681
}
682

683
bool CommonMsgInfo::unpack(vm::CellSlice& cs, CommonMsgInfo::Record_int_msg_info& data) const {
684
  return get_tag(cs) == int_msg_info && cs.advance(1) && cs.fetch_bool_to(data.ihr_disabled) &&
685
         cs.fetch_bool_to(data.bounce) && cs.fetch_bool_to(data.bounced) && t_MsgAddressInt.fetch_to(cs, data.src) &&
686
         t_MsgAddressInt.fetch_to(cs, data.dest) && t_CurrencyCollection.fetch_to(cs, data.value) &&
687
         t_Grams.fetch_to(cs, data.ihr_fee) && t_Grams.fetch_to(cs, data.fwd_fee) &&
688
         cs.fetch_uint_to(64, data.created_lt) && cs.fetch_uint_to(32, data.created_at);
689
}
690

691
bool CommonMsgInfo::skip(vm::CellSlice& cs) const {
692
  int tag = get_tag(cs);
693
  switch (tag) {
694
    case int_msg_info:
695
      return cs.advance(4)                     // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
696
             && t_MsgAddressInt.skip(cs)       // src
697
             && t_MsgAddressInt.skip(cs)       // dest
698
             && t_CurrencyCollection.skip(cs)  // value
699
             && t_Grams.skip(cs)               // ihr_fee
700
             && t_Grams.skip(cs)               // fwd_fee
701
             && cs.advance(64 + 32);           // created_lt:uint64 created_at:uint32
702
    case ext_in_msg_info:
703
      return cs.advance(2) && t_MsgAddressExt.skip(cs)  // src
704
             && t_MsgAddressInt.skip(cs)                // dest
705
             && t_Grams.skip(cs);                       // import_fee
706
    case ext_out_msg_info:
707
      return cs.advance(2) && t_MsgAddressInt.skip(cs)  // src
708
             && t_MsgAddressExt.skip(cs)                // dest
709
             && cs.advance(64 + 32);                    // created_lt:uint64 created_at:uint32
710
  }
711
  return false;
712
}
713

714
bool CommonMsgInfo::get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const {
715
  switch (get_tag(cs)) {
716
    case int_msg_info:
717
      return cs.advance(4)                           // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
718
             && t_MsgAddressInt.skip(cs)             // src
719
             && t_MsgAddressInt.skip(cs)             // dest
720
             && t_CurrencyCollection.skip(cs)        // value
721
             && t_Grams.skip(cs)                     // ihr_fee
722
             && t_Grams.skip(cs)                     // fwd_fee
723
             && cs.fetch_ulong_bool(64, created_lt)  // created_lt:uint64
724
             && cs.advance(32);                      // created_at:uint32
725
    case ext_in_msg_info:
726
      return false;
727
    case ext_out_msg_info:
728
      return cs.advance(2) && t_MsgAddressInt.skip(cs)  // src
729
             && t_MsgAddressExt.skip(cs)                // dest
730
             && cs.fetch_ulong_bool(64, created_lt)     // created_lt:uint64
731
             && cs.advance(32);                         // created_at:uint32
732
  }
733
  return false;
734
}
735

736
const CommonMsgInfo t_CommonMsgInfo;
737
const TickTock t_TickTock;
738
const RefAnything t_RefCell;
739

740
bool StateInit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
741
  return Maybe<UInt>{5}.validate_skip(ops, cs, weak)            // split_depth:(Maybe (## 5))
742
         && Maybe<TickTock>{}.validate_skip(ops, cs, weak)      // special:(Maybe TickTock)
743
         && Maybe<RefAnything>{}.validate_skip(ops, cs, weak)   // code:(Maybe ^Cell)
744
         && Maybe<RefAnything>{}.validate_skip(ops, cs, weak)   // data:(Maybe ^Cell)
745
         && Maybe<RefAnything>{}.validate_skip(ops, cs, weak);  // library:(Maybe ^Cell)
746
}
747

748
bool StateInit::get_ticktock(vm::CellSlice& cs, int& ticktock) const {
749
  bool have_tt;
750
  ticktock = 0;
751
  return Maybe<UInt>{5}.validate_skip_upto(1, cs) && cs.fetch_bool_to(have_tt) &&
752
         (!have_tt || cs.fetch_uint_to(2, ticktock));
753
}
754

755
const StateInit t_StateInit;
756

757
bool Message::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
758
  static const Maybe<Either<StateInit, RefTo<StateInit>>> init_type;
759
  static const Either<Anything, RefAnything> body_type;
760
  return t_CommonMsgInfo.validate_skip(ops, cs, weak)  // info:CommonMsgInfo
761
         && init_type.validate_skip(ops, cs, weak)     // init:(Maybe (Either StateInit ^StateInit))
762
         && body_type.validate_skip(ops, cs, weak);    // body:(Either X ^X)
763
}
764

765
bool Message::extract_info(vm::CellSlice& cs) const {
766
  return t_CommonMsgInfo.extract(cs);
767
}
768

769
bool Message::get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const {
770
  return t_CommonMsgInfo.get_created_lt(cs, created_lt);
771
}
772

773
bool Message::is_internal(Ref<vm::Cell> ref) const {
774
  return is_internal(load_cell_slice(std::move(ref)));
775
}
776

777
const Message t_Message;
778
const RefTo<Message> t_Ref_Message;
779

780
bool IntermediateAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
781
  switch (get_tag(cs)) {
782
    case interm_addr_regular:
783
      return cs.advance(1) && cs.fetch_ulong(7) <= 96U;
784
    case interm_addr_simple:
785
      return cs.advance(2 + 8 + 64);
786
    case interm_addr_ext:
787
      if (cs.have(2 + 32 + 64)) {
788
        cs.advance(2);
789
        int workchain_id = (int)cs.fetch_long(32);
790
        return (workchain_id < -128 || workchain_id >= 128) && cs.advance(64);
791
      }
792
      // no break
793
  }
794
  return false;
795
}
796

797
bool IntermediateAddress::skip(vm::CellSlice& cs) const {
798
  return cs.advance(get_size(cs));
799
}
800

801
int IntermediateAddress::get_size(const vm::CellSlice& cs) const {
802
  switch (get_tag(cs)) {
803
    case interm_addr_regular:
804
      return 1 + 7;
805
    case interm_addr_simple:
806
      return 2 + 8 + 64;
807
    case interm_addr_ext:
808
      return 2 + 32 + 64;
809
  }
810
  return -1;
811
}
812

813
const IntermediateAddress t_IntermediateAddress;
814

815
bool MsgEnvelope::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
816
  return cs.fetch_ulong(4) == 4                                 // msg_envelope#4
817
         && t_IntermediateAddress.validate_skip(ops, cs, weak)  // cur_addr:IntermediateAddress
818
         && t_IntermediateAddress.validate_skip(ops, cs, weak)  // next_addr:IntermediateAddress
819
         && t_Grams.validate_skip(ops, cs, weak)                // fwd_fee_remaining:Grams
820
         && t_Ref_Message.validate_skip(ops, cs, weak);         // msg:^Message
821
}
822

823
bool MsgEnvelope::skip(vm::CellSlice& cs) const {
824
  return cs.advance(4)                      // msg_envelope#4
825
         && t_IntermediateAddress.skip(cs)  // cur_addr:IntermediateAddress
826
         && t_IntermediateAddress.skip(cs)  // next_addr:IntermediateAddress
827
         && t_Grams.skip(cs)                // fwd_fee_remaining:Grams
828
         && t_Ref_Message.skip(cs);         // msg:^Message
829
}
830

831
bool MsgEnvelope::extract_fwd_fees_remaining(vm::CellSlice& cs) const {
832
  return t_IntermediateAddress.skip(cs) && t_IntermediateAddress.skip(cs) && t_Grams.extract(cs);
833
}
834

835
bool MsgEnvelope::unpack(vm::CellSlice& cs, MsgEnvelope::Record& data) const {
836
  return cs.fetch_ulong(4) == 4                                 // msg_envelope#4
837
         && t_IntermediateAddress.fetch_to(cs, data.cur_addr)   // cur_addr:IntermediateAddress
838
         && t_IntermediateAddress.fetch_to(cs, data.next_addr)  // next_addr:IntermediateAddress
839
         && t_Grams.fetch_to(cs, data.fwd_fee_remaining)        // fwd_fee_remaining:Grams
840
         && cs.fetch_ref_to(data.msg);                          // msg:^Message
841
}
842

843
bool MsgEnvelope::unpack(vm::CellSlice& cs, MsgEnvelope::Record_std& data) const {
844
  return cs.fetch_ulong(4) == 4                                      // msg_envelope#4
845
         && t_IntermediateAddress.fetch_regular(cs, data.cur_addr)   // cur_addr:IntermediateAddress
846
         && t_IntermediateAddress.fetch_regular(cs, data.next_addr)  // next_addr:IntermediateAddress
847
         && t_Grams.as_integer_skip_to(cs, data.fwd_fee_remaining)   // fwd_fee_remaining:Grams
848
         && cs.fetch_ref_to(data.msg);                               // msg:^Message
849
}
850

851
bool MsgEnvelope::unpack_std(vm::CellSlice& cs, int& cur_a, int& nhop_a, Ref<vm::Cell>& msg) const {
852
  return cs.fetch_ulong(4) == 4                              // msg_envelope#4
853
         && t_IntermediateAddress.fetch_regular(cs, cur_a)   // cur_addr:IntermediateAddress
854
         && t_IntermediateAddress.fetch_regular(cs, nhop_a)  // next_addr:IntermediateAddress
855
         && cs.fetch_ref_to(msg);
856
}
857

858
bool MsgEnvelope::get_created_lt(const vm::CellSlice& cs, unsigned long long& created_lt) const {
859
  if (!cs.size_refs()) {
860
    return false;
861
  }
862
  auto msg_cs = load_cell_slice(cs.prefetch_ref());
863
  return t_Message.get_created_lt(msg_cs, created_lt);
864
}
865

866
const MsgEnvelope t_MsgEnvelope;
867
const RefTo<MsgEnvelope> t_Ref_MsgEnvelope;
868

869
bool StorageUsed::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
870
  return t_VarUInteger_7.validate_skip(ops, cs, weak)      // cells:(VarUInteger 7)
871
         && t_VarUInteger_7.validate_skip(ops, cs, weak)   // bits:(VarUInteger 7)
872
         && t_VarUInteger_7.validate_skip(ops, cs, weak);  // public_cells:(VarUInteger 7)
873
}
874

875
bool StorageUsed::skip(vm::CellSlice& cs) const {
876
  return t_VarUInteger_7.skip(cs)      // cells:(VarUInteger 7)
877
         && t_VarUInteger_7.skip(cs)   // bits:(VarUInteger 7)
878
         && t_VarUInteger_7.skip(cs);  // public_cells:(VarUInteger 7)
879
}
880

881
const StorageUsed t_StorageUsed;
882

883
bool StorageUsedShort::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
884
  return t_VarUInteger_7.validate_skip(ops, cs, weak)      // cells:(VarUInteger 7)
885
         && t_VarUInteger_7.validate_skip(ops, cs, weak);  // bits:(VarUInteger 7)
886
}
887

888
bool StorageUsedShort::skip(vm::CellSlice& cs) const {
889
  return t_VarUInteger_7.skip(cs)      // cells:(VarUInteger 7)
890
         && t_VarUInteger_7.skip(cs);  // bits:(VarUInteger 7)
891
}
892

893
const StorageUsedShort t_StorageUsedShort;
894

895
const Maybe<Grams> t_Maybe_Grams;
896

897
bool StorageInfo::skip(vm::CellSlice& cs) const {
898
  return t_StorageUsed.skip(cs)      // used:StorageUsed
899
         && cs.advance(32)           // last_paid:uint32
900
         && t_Maybe_Grams.skip(cs);  // due_payment:(Maybe Grams)
901
}
902

903
bool StorageInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
904
  return t_StorageUsed.validate_skip(ops, cs, weak)      // used:StorageUsed
905
         && cs.advance(32)                               // last_paid:uint32
906
         && t_Maybe_Grams.validate_skip(ops, cs, weak);  // due_payment:(Maybe Grams)
907
}
908

909
const StorageInfo t_StorageInfo;
910

911
bool AccountState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
912
  switch (get_tag(cs)) {
913
    case account_uninit:
914
      return cs.advance(2);
915
    case account_frozen:
916
      return cs.advance(2 + 256);
917
    case account_active:
918
      return cs.advance(1) && t_StateInit.validate_skip(ops, cs, weak);
919
  }
920
  return false;
921
}
922

923
bool AccountState::get_ticktock(vm::CellSlice& cs, int& ticktock) const {
924
  if (get_tag(cs) != account_active) {
925
    ticktock = 0;
926
    return true;
927
  }
928
  return cs.advance(1) && t_StateInit.get_ticktock(cs, ticktock);
929
}
930

931
const AccountState t_AccountState;
932

933
bool AccountStorage::skip(vm::CellSlice& cs) const {
934
  return cs.advance(64) && t_CurrencyCollection.skip(cs) && t_AccountState.skip(cs);
935
}
936

937
bool AccountStorage::skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const {
938
  return cs.advance(64) && t_CurrencyCollection.skip_copy(cb, cs) && t_AccountState.skip(cs);
939
}
940

941
bool AccountStorage::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
942
  return cs.advance(64) && t_CurrencyCollection.validate_skip(ops, cs, weak) &&
943
         t_AccountState.validate_skip(ops, cs, weak);
944
}
945

946
const AccountStorage t_AccountStorage;
947

948
bool Account::skip(vm::CellSlice& cs) const {
949
  switch (get_tag(cs)) {
950
    case account_none:
951
      return cs.advance(1);
952
    case account:
953
      return cs.advance(1)                  // account$1
954
             && t_MsgAddressInt.skip(cs)    // addr:MsgAddressInt
955
             && t_StorageInfo.skip(cs)      // storage_stat:StorageInfo
956
             && t_AccountStorage.skip(cs);  // storage:AccountStorage
957
  }
958
  return false;
959
}
960

961
bool Account::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
962
  switch (get_tag(cs)) {
963
    case account_none:
964
      return allow_empty && cs.advance(1);
965
    case account:
966
      return cs.advance(1)                                      // account$1
967
             && t_MsgAddressInt.validate_skip(ops, cs, weak)    // addr:MsgAddressInt
968
             && t_StorageInfo.validate_skip(ops, cs, weak)      // storage_stat:StorageInfo
969
             && t_AccountStorage.validate_skip(ops, cs, weak);  // storage:AccountStorage
970
  }
971
  return false;
972
}
973

974
bool Account::skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const {
975
  switch (get_tag(cs)) {
976
    case account_none:
977
      return allow_empty && cs.advance(1) && t_CurrencyCollection.null_value(cb);
978
    case account:
979
      return cs.advance(1)                                   // account$1
980
             && t_MsgAddressInt.skip(cs)                     // addr:MsgAddressInt
981
             && t_StorageInfo.skip(cs)                       // storage_stat:StorageInfo
982
             && t_AccountStorage.skip_copy_balance(cb, cs);  // storage:AccountStorage
983
  }
984
  return false;
985
}
986

987
bool Account::skip_copy_depth_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const {
988
  int depth;
989
  switch (get_tag(cs)) {
990
    case account_none:
991
      return allow_empty && cs.advance(1) && t_DepthBalanceInfo.null_value(cb);
992
    case account:
993
      return cs.advance(1)                                   // account$1
994
             && t_MsgAddressInt.skip_get_depth(cs, depth)    // addr:MsgAddressInt
995
             && cb.store_uint_leq(30, depth)                 // -> store split_depth:(#<= 30)
996
             && t_StorageInfo.skip(cs)                       // storage_stat:StorageInfo
997
             && t_AccountStorage.skip_copy_balance(cb, cs);  // storage:AccountStorage
998
  }
999
  return false;
1000
}
1001

1002
const Account t_Account, t_AccountE{true};
1003
const RefTo<Account> t_Ref_AccountE{true};
1004

1005
bool ShardAccount::extract_account_state(Ref<vm::CellSlice> cs_ref, Ref<vm::Cell>& acc_state) {
1006
  if (cs_ref.is_null()) {
1007
    vm::CellBuilder cb;
1008
    return cb.store_bool_bool(false) && cb.finalize_to(acc_state);
1009
  } else {
1010
    return cs_ref->prefetch_ref_to(acc_state);
1011
  }
1012
}
1013

1014
bool ShardAccount::Record::reset() {
1015
  last_trans_hash.set_zero();
1016
  last_trans_lt = 0;
1017
  is_zero = valid = true;
1018
  vm::CellBuilder cb;
1019
  return (cb.store_bool_bool(false) && cb.finalize_to(account)) || invalidate();
1020
}
1021

1022
bool ShardAccount::Record::unpack(vm::CellSlice& cs) {
1023
  is_zero = false;
1024
  valid = true;
1025
  return (cs.fetch_ref_to(account) && cs.fetch_bits_to(last_trans_hash) && cs.fetch_uint_to(64, last_trans_lt)) ||
1026
         invalidate();
1027
}
1028

1029
bool ShardAccount::Record::unpack(Ref<vm::CellSlice> cs_ref) {
1030
  if (cs_ref.not_null()) {
1031
    return unpack(cs_ref.write()) && (cs_ref->empty_ext() || invalidate());
1032
  } else {
1033
    return reset();
1034
  }
1035
}
1036

1037
const ShardAccount t_ShardAccount;
1038

1039
const AccountStatus t_AccountStatus;
1040

1041
bool HashmapAugNode::skip(vm::CellSlice& cs) const {
1042
  if (n < 0) {
1043
    return false;
1044
  } else if (!n) {
1045
    // ahmn_leaf
1046
    return aug.extra_type.skip(cs) && aug.value_type.skip(cs);
1047
  } else {
1048
    // ahmn_fork
1049
    return cs.advance_refs(2) && aug.extra_type.skip(cs);
1050
  }
1051
}
1052

1053
bool HashmapAugNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1054
  if (n < 0) {
1055
    return false;
1056
  }
1057
  if (!n) {
1058
    // ahmn_leaf
1059
    vm::CellSlice cs_extra{cs};
1060
    if (!aug.extra_type.validate_skip(ops, cs, weak)) {
1061
      return false;
1062
    }
1063
    cs_extra.cut_tail(cs);
1064
    vm::CellSlice cs_value{cs};
1065
    if (!aug.value_type.validate_skip(ops, cs, weak)) {
1066
      return false;
1067
    }
1068
    cs_value.cut_tail(cs);
1069
    return aug.check_leaf(cs_extra, cs_value);
1070
  }
1071
  // ahmn_fork
1072
  if (!cs.have_refs(2)) {
1073
    return false;
1074
  }
1075
  HashmapAug branch_type{n - 1, aug};
1076
  if (!branch_type.validate_ref(ops, cs.prefetch_ref(0), weak) ||
1077
      !branch_type.validate_ref(ops, cs.prefetch_ref(1), weak)) {
1078
    return false;
1079
  }
1080
  auto cs_left = load_cell_slice(cs.fetch_ref());
1081
  auto cs_right = load_cell_slice(cs.fetch_ref());
1082
  vm::CellSlice cs_extra{cs};
1083
  if (!aug.extra_type.validate_skip(ops, cs, weak)) {
1084
    return false;
1085
  }
1086
  cs_extra.cut_tail(cs);
1087
  return branch_type.extract_extra(cs_left) && branch_type.extract_extra(cs_right) &&
1088
         aug.check_fork(cs_extra, cs_left, cs_right);
1089
}
1090

1091
bool HashmapAug::skip(vm::CellSlice& cs) const {
1092
  int l;
1093
  return HmLabel{n}.skip(cs, l) && HashmapAugNode{n - l, aug}.skip(cs);
1094
}
1095

1096
bool HashmapAug::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1097
  int l;
1098
  return HmLabel{n}.validate_skip(cs, weak, l) && HashmapAugNode{n - l, aug}.validate_skip(ops, cs, weak);
1099
}
1100

1101
bool HashmapAug::extract_extra(vm::CellSlice& cs) const {
1102
  int l;
1103
  return HmLabel{n}.skip(cs, l) && (l == n || cs.advance_refs(2)) && aug.extra_type.extract(cs);
1104
}
1105

1106
bool HashmapAugE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1107
  Ref<vm::CellSlice> extra;
1108
  switch (get_tag(cs)) {
1109
    case ahme_empty:
1110
      return cs.advance(1) && (extra = root_type.aug.extra_type.validate_fetch(ops, cs, weak)).not_null() &&
1111
             root_type.aug.check_empty(extra.unique_write());
1112
    case ahme_root:
1113
      if (cs.advance(1) && root_type.validate_ref(ops, cs.prefetch_ref(), weak)) {
1114
        bool special;
1115
        auto cs_root = load_cell_slice_special(cs.fetch_ref(), special);
1116
        if (special) {
1117
          return weak;
1118
        }
1119
        return (extra = root_type.aug.extra_type.validate_fetch(ops, cs, weak)).not_null() &&
1120
               root_type.extract_extra(cs_root) && extra->contents_equal(cs_root);
1121
      }
1122
      break;
1123
  }
1124
  return false;
1125
}
1126

1127
bool HashmapAugE::skip(vm::CellSlice& cs) const {
1128
  int tag = (int)cs.fetch_ulong(1);
1129
  return tag >= 0 && cs.advance_refs(tag) && root_type.aug.extra_type.skip(cs);
1130
}
1131

1132
bool HashmapAugE::extract_extra(vm::CellSlice& cs) const {
1133
  int tag = (int)cs.fetch_ulong(1);
1134
  return tag >= 0 && cs.advance_refs(tag) && root_type.aug.extra_type.extract(cs);
1135
}
1136

1137
bool DepthBalanceInfo::skip(vm::CellSlice& cs) const {
1138
  return cs.advance(5) &&
1139
         t_CurrencyCollection.skip(
1140
             cs);  // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection = DepthBalanceInfo;
1141
}
1142

1143
bool DepthBalanceInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1144
  return cs.fetch_ulong(5) <= 30 &&
1145
         t_CurrencyCollection.validate_skip(ops, cs,
1146
                                            weak);  // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection
1147
}
1148

1149
bool DepthBalanceInfo::null_value(vm::CellBuilder& cb) const {
1150
  return cb.store_zeroes_bool(5) && t_CurrencyCollection.null_value(cb);
1151
}
1152

1153
bool DepthBalanceInfo::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
1154
  unsigned d1, d2;
1155
  return cs1.fetch_uint_leq(30, d1) && cs2.fetch_uint_leq(30, d2) && cb.store_uint_leq(30, std::max(d1, d2)) &&
1156
         t_CurrencyCollection.add_values(cb, cs1, cs2);
1157
}
1158

1159
const DepthBalanceInfo t_DepthBalanceInfo;
1160

1161
bool Aug_ShardAccounts::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
1162
  if (cs.have_refs()) {
1163
    auto cs2 = load_cell_slice(cs.prefetch_ref());
1164
    return t_Account.skip_copy_depth_balance(cb, cs2);
1165
  } else {
1166
    return false;
1167
  }
1168
}
1169

1170
const Aug_ShardAccounts aug_ShardAccounts;
1171

1172
const ShardAccounts t_ShardAccounts;
1173

1174
const AccStatusChange t_AccStatusChange;
1175

1176
bool TrStoragePhase::skip(vm::CellSlice& cs) const {
1177
  return t_Grams.skip(cs)                // storage_fees_collected:Grams
1178
         && t_Maybe_Grams.skip(cs)       // storage_fees_due:Grams
1179
         && t_AccStatusChange.skip(cs);  // status_change:AccStatusChange
1180
}
1181

1182
bool TrStoragePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1183
  return t_Grams.validate_skip(ops, cs, weak)                // storage_fees_collected:Grams
1184
         && t_Maybe_Grams.validate_skip(ops, cs, weak)       // storage_fees_due:Grams
1185
         && t_AccStatusChange.validate_skip(ops, cs, weak);  // status_change:AccStatusChange
1186
}
1187

1188
bool TrStoragePhase::get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
1189
  return t_Grams.as_integer_skip_to(cs, storage_fees);  // storage_fees_collected:Grams
1190
}
1191

1192
bool TrStoragePhase::maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
1193
  auto z = cs.fetch_ulong(1);
1194
  if (!z) {
1195
    storage_fees = td::make_refint(0);
1196
    return true;
1197
  } else {
1198
    return z == 1 && get_storage_fees(cs, storage_fees);
1199
  }
1200
}
1201

1202
const TrStoragePhase t_TrStoragePhase;
1203

1204
bool TrCreditPhase::skip(vm::CellSlice& cs) const {
1205
  return t_Maybe_Grams.skip(cs)             // due_fees_collected:(Maybe Grams)
1206
         && t_CurrencyCollection.skip(cs);  // credit:CurrencyCollection
1207
}
1208

1209
bool TrCreditPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1210
  return t_Maybe_Grams.validate_skip(ops, cs, weak)             // due_fees_collected:(Maybe Grams)
1211
         && t_CurrencyCollection.validate_skip(ops, cs, weak);  // credit:CurrencyCollection
1212
}
1213

1214
const TrCreditPhase t_TrCreditPhase;
1215

1216
bool TrComputeInternal1::skip(vm::CellSlice& cs) const {
1217
  return t_VarUInteger_7.skip(cs)           // gas_used:(VarUInteger 7)
1218
         && t_VarUInteger_7.skip(cs)        // gas_limit:(VarUInteger 7)
1219
         && Maybe<VarUInteger>{3}.skip(cs)  // gas_credit:(Maybe (VarUInteger 3))
1220
         && cs.advance(8 + 32)              // mode:int8 exit_code:int32
1221
         && Maybe<Int>{32}.skip(cs)         // exit_arg:(Maybe int32)
1222
         && cs.advance(32 + 256 + 256);     // vm_steps:uint32
1223
                                            // vm_init_state_hash:uint256
1224
                                            // vm_final_state_hash:uint256
1225
}
1226

1227
bool TrComputeInternal1::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1228
  return t_VarUInteger_7.validate_skip(ops, cs, weak)           // gas_used:(VarUInteger 7)
1229
         && t_VarUInteger_7.validate_skip(ops, cs, weak)        // gas_limit:(VarUInteger 7)
1230
         && Maybe<VarUInteger>{3}.validate_skip(ops, cs, weak)  // gas_credit:(Maybe (VarUInteger 3))
1231
         && cs.advance(8 + 32)                                  // mode:int8 exit_code:int32
1232
         && Maybe<Int>{32}.validate_skip(ops, cs, weak)         // exit_arg:(Maybe int32)
1233
         && cs.advance(32 + 256 + 256);                         // vm_steps:uint32
1234
                                                                // vm_init_state_hash:uint256
1235
                                                                // vm_final_state_hash:uint256
1236
}
1237

1238
const TrComputeInternal1 t_TrComputeInternal1;
1239
const RefTo<TrComputeInternal1> t_Ref_TrComputeInternal1;
1240
const ComputeSkipReason t_ComputeSkipReason;
1241

1242
bool TrComputePhase::skip(vm::CellSlice& cs) const {
1243
  switch (get_tag(cs)) {
1244
    case tr_phase_compute_skipped:
1245
      return cs.advance(1) && t_ComputeSkipReason.skip(cs);
1246
    case tr_phase_compute_vm:
1247
      return cs.advance(1 + 3)    // tr_phase_compute_vm$1 success:Bool msg_state_used:Bool account_activated:Bool
1248
             && t_Grams.skip(cs)  // gas_fees:Grams
1249
             && t_Ref_TrComputeInternal1.skip(cs);  // ^[ gas_used:(..) .. ]
1250
  }
1251
  return false;
1252
}
1253

1254
bool TrComputePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1255
  switch (get_tag(cs)) {
1256
    case tr_phase_compute_skipped:
1257
      return cs.advance(1) && t_ComputeSkipReason.validate_skip(ops, cs, weak);
1258
    case tr_phase_compute_vm:
1259
      return cs.advance(1 + 3)  // tr_phase_compute_vm$1 success:Bool msg_state_used:Bool account_activated:Bool
1260
             && t_Grams.validate_skip(ops, cs, weak)                    // gas_fees:Grams
1261
             && t_Ref_TrComputeInternal1.validate_skip(ops, cs, weak);  // ^[ gas_used:(..) .. ]
1262
  }
1263
  return false;
1264
}
1265

1266
const TrComputePhase t_TrComputePhase;
1267

1268
bool TrActionPhase::skip(vm::CellSlice& cs) const {
1269
  return cs.advance(3)                    // success:Bool valid:Bool no_funds:Bool
1270
         && t_AccStatusChange.skip(cs)    // status_change:AccStatusChange
1271
         && t_Maybe_Grams.skip(cs)        // total_fwd_fees:(Maybe Grams)
1272
         && t_Maybe_Grams.skip(cs)        // total_action_fees:(Maybe Grams)
1273
         && cs.advance(32)                // result_code:int32
1274
         && Maybe<Int>{32}.skip(cs)       // result_arg:(Maybe int32)
1275
         && cs.advance(16 * 4 + 256)      // tot_actions:uint16 spec_actions:uint16
1276
                                          // skipped_actions:uint16 msgs_created:uint16
1277
                                          // action_list_hash:uint256
1278
         && t_StorageUsedShort.skip(cs);  // tot_msg_size:StorageUsedShort
1279
}
1280

1281
bool TrActionPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1282
  return cs.advance(3)                                        // success:Bool valid:Bool no_funds:Bool
1283
         && t_AccStatusChange.validate_skip(ops, cs, weak)    // status_change:AccStatusChange
1284
         && t_Maybe_Grams.validate_skip(ops, cs, weak)        // total_fwd_fees:(Maybe Grams)
1285
         && t_Maybe_Grams.validate_skip(ops, cs, weak)        // total_action_fees:(Maybe Grams)
1286
         && cs.advance(32)                                    // result_code:int32
1287
         && Maybe<Int>{32}.validate_skip(ops, cs, weak)       // result_arg:(Maybe int32)
1288
         && cs.advance(16 * 4 + 256)                          // tot_actions:uint16 spec_actions:uint16
1289
                                                              // skipped_actions:uint16 msgs_created:uint16
1290
                                                              // action_list_hash:uint256
1291
         && t_StorageUsedShort.validate_skip(ops, cs, weak);  // tot_msg_size:StorageUsed
1292
}
1293

1294
const TrActionPhase t_TrActionPhase;
1295

1296
bool TrBouncePhase::skip(vm::CellSlice& cs) const {
1297
  switch (get_tag(cs)) {
1298
    case tr_phase_bounce_negfunds:
1299
      return cs.advance(2);  // tr_phase_bounce_negfunds$00
1300
    case tr_phase_bounce_nofunds:
1301
      return cs.advance(2)                   // tr_phase_bounce_nofunds$01
1302
             && t_StorageUsedShort.skip(cs)  // msg_size:StorageUsedShort
1303
             && t_Grams.skip(cs);            // req_fwd_fees:Grams
1304
    case tr_phase_bounce_ok:
1305
      return cs.advance(1)                   // tr_phase_bounce_ok$1
1306
             && t_StorageUsedShort.skip(cs)  // msg_size:StorageUsedShort
1307
             && t_Grams.skip(cs)             // msg_fees:Grams
1308
             && t_Grams.skip(cs);            // fwd_fees:Grams
1309
  }
1310
  return false;
1311
}
1312

1313
bool TrBouncePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1314
  switch (get_tag(cs)) {
1315
    case tr_phase_bounce_negfunds:
1316
      return cs.advance(2);  // tr_phase_bounce_negfunds$00
1317
    case tr_phase_bounce_nofunds:
1318
      return cs.advance(2)                                       // tr_phase_bounce_nofunds$01
1319
             && t_StorageUsedShort.validate_skip(ops, cs, weak)  // msg_size:StorageUsedShort
1320
             && t_Grams.validate_skip(ops, cs, weak);            // req_fwd_fees:Grams
1321
    case tr_phase_bounce_ok:
1322
      return cs.advance(1)                                       // tr_phase_bounce_ok$1
1323
             && t_StorageUsedShort.validate_skip(ops, cs, weak)  // msg_size:StorageUsedShort
1324
             && t_Grams.validate_skip(ops, cs, weak)             // msg_fees:Grams
1325
             && t_Grams.validate_skip(ops, cs, weak);            // fwd_fees:Grams
1326
  }
1327
  return false;
1328
}
1329

1330
int TrBouncePhase::get_tag(const vm::CellSlice& cs) const {
1331
  if (cs.size() == 1) {
1332
    return (int)cs.prefetch_ulong(1) == 1 ? tr_phase_bounce_ok : -1;
1333
  }
1334
  int v = (int)cs.prefetch_ulong(2);
1335
  return v == 3 ? tr_phase_bounce_ok : v;
1336
};
1337

1338
const TrBouncePhase t_TrBouncePhase;
1339

1340
bool SplitMergeInfo::skip(vm::CellSlice& cs) const {
1341
  // cur_shard_pfx_len:(## 6) acc_split_depth:(##6) this_addr:uint256 sibling_addr:uint256
1342
  return cs.advance(6 + 6 + 256 + 256);
1343
}
1344

1345
bool SplitMergeInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1346
  if (!cs.have(6 + 6 + 256 + 256)) {
1347
    return false;
1348
  }
1349
  int cur_pfx_len = (int)cs.fetch_ulong(6);
1350
  int split_depth = (int)cs.fetch_ulong(6);
1351
  unsigned char this_addr[32], sibling_addr[32];
1352
  if (!cs.fetch_bytes(this_addr, 32) || !cs.fetch_bytes(sibling_addr, 32)) {
1353
    return false;
1354
  }
1355
  // cur_pfx_len < split_depth, addresses match except in bit cur_pfx_len
1356
  if (cur_pfx_len >= split_depth) {
1357
    return false;
1358
  }
1359
  sibling_addr[cur_pfx_len >> 3] ^= (unsigned char)(0x80 >> (cur_pfx_len & 7));
1360
  return !std::memcmp(this_addr, sibling_addr, 32);
1361
}
1362

1363
const SplitMergeInfo t_SplitMergeInfo;
1364

1365
bool TransactionDescr::skip(vm::CellSlice& cs) const {
1366
  switch (get_tag(cs)) {
1367
    case trans_ord:
1368
      return cs.advance(4 + 1)                          // trans_ord$0000 storage_first:Bool
1369
             && Maybe<TrStoragePhase>{}.skip(cs)        // storage_ph:(Maybe TrStoragePhase)
1370
             && Maybe<TrCreditPhase>{}.skip(cs)         // credit_ph:(Maybe TrCreditPhase)
1371
             && t_TrComputePhase.skip(cs)               // compute_ph:TrComputePhase
1372
             && Maybe<RefTo<TrActionPhase>>{}.skip(cs)  // action:(Maybe ^TrActionPhase)
1373
             && cs.advance(1)                           // aborted:Bool
1374
             && Maybe<TrBouncePhase>{}.skip(cs)         // bounce:(Maybe TrBouncePhase)
1375
             && cs.advance(1);                          // destroyed:Bool
1376
    case trans_storage:
1377
      return cs.advance(4)                  // trans_storage$0001
1378
             && t_TrStoragePhase.skip(cs);  // storage_ph:TrStoragePhase
1379
    case trans_tick_tock:
1380
      return cs.advance(4)                              // trans_tick_tock$001 is_tock:Bool
1381
             && t_TrStoragePhase.skip(cs)               // storage_ph:TrStoragePhase
1382
             && t_TrComputePhase.skip(cs)               // compute_ph:TrComputePhase
1383
             && Maybe<RefTo<TrActionPhase>>{}.skip(cs)  // action:(Maybe ^TrActionPhase)
1384
             && cs.advance(2);                          // aborted:Bool destroyed:Bool
1385
    case trans_split_prepare:
1386
      return cs.advance(4)                              // trans_split_prepare$0100
1387
             && t_SplitMergeInfo.skip(cs)               // split_info:SplitMergeInfo
1388
             && Maybe<TrStoragePhase>{}.skip(cs)        // storage_ph:(Maybe TrStoragePhase)
1389
             && t_TrComputePhase.skip(cs)               // compute_ph:TrComputePhase
1390
             && Maybe<RefTo<TrActionPhase>>{}.skip(cs)  // action:(Maybe ^TrActionPhase)
1391
             && cs.advance(2);                          // aborted:Bool destroyed:Bool
1392
    case trans_split_install:
1393
      return cs.advance(4)                  // trans_split_install$0101
1394
             && t_SplitMergeInfo.skip(cs)   // split_info:SplitMergeInfo
1395
             && t_Ref_Transaction.skip(cs)  // prepare_transaction:^Transaction
1396
             && cs.advance(1);              // installed:Bool
1397
    case trans_merge_prepare:
1398
      return cs.advance(4)                 // trans_merge_prepare$0110
1399
             && t_SplitMergeInfo.skip(cs)  // split_info:SplitMergeInfo
1400
             && t_TrStoragePhase.skip(cs)  // storage_ph:TrStoragePhase
1401
             && cs.advance(1);             // aborted:Bool
1402
    case trans_merge_install:
1403
      return cs.advance(4)                              // trans_merge_install$0111
1404
             && t_SplitMergeInfo.skip(cs)               // split_info:SplitMergeInfo
1405
             && t_Ref_Transaction.skip(cs)              // prepare_transaction:^Transaction
1406
             && Maybe<TrStoragePhase>{}.skip(cs)        // storage_ph:(Maybe TrStoragePhase)
1407
             && Maybe<TrCreditPhase>{}.skip(cs)         // credit_ph:(Maybe TrCreditPhase)
1408
             && Maybe<TrComputePhase>{}.skip(cs)        // compute_ph:TrComputePhase
1409
             && Maybe<RefTo<TrActionPhase>>{}.skip(cs)  // action:(Maybe ^TrActionPhase)
1410
             && cs.advance(2);                          // aborted:Bool destroyed:Bool
1411
  }
1412
  return false;
1413
}
1414

1415
bool TransactionDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1416
  switch (get_tag(cs)) {
1417
    case trans_ord:
1418
      return cs.advance(4 + 1)                                              // trans_ord$0000 credit_first:Bool
1419
             && Maybe<TrStoragePhase>{}.validate_skip(ops, cs, weak)        // storage_ph:(Maybe TrStoragePhase)
1420
             && Maybe<TrCreditPhase>{}.validate_skip(ops, cs, weak)         // credit_ph:(Maybe TrCreditPhase)
1421
             && t_TrComputePhase.validate_skip(ops, cs, weak)               // compute_ph:TrComputePhase
1422
             && Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak)  // action:(Maybe ^TrActionPhase)
1423
             && cs.advance(1)                                               // aborted:Bool
1424
             && Maybe<TrBouncePhase>{}.validate_skip(ops, cs, weak)         // bounce:(Maybe TrBouncePhase)
1425
             && cs.advance(1);                                              // destroyed:Bool
1426
    case trans_storage:
1427
      return cs.advance(4)                                      // trans_storage$0001
1428
             && t_TrStoragePhase.validate_skip(ops, cs, weak);  // storage_ph:TrStoragePhase
1429
    case trans_tick_tock:
1430
      return cs.advance(4)                                                  // trans_tick_tock$001 is_tock:Bool
1431
             && t_TrStoragePhase.validate_skip(ops, cs, weak)               // storage_ph:TrStoragePhase
1432
             && t_TrComputePhase.validate_skip(ops, cs, weak)               // compute_ph:TrComputePhase
1433
             && Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak)  // action:(Maybe ^TrActionPhase)
1434
             && cs.advance(2);                                              // aborted:Bool destroyed:Bool
1435
    case trans_split_prepare:
1436
      return cs.advance(4)                                                  // trans_split_prepare$0100
1437
             && t_SplitMergeInfo.validate_skip(ops, cs, weak)               // split_info:SplitMergeInfo
1438
             && Maybe<TrStoragePhase>{}.validate_skip(ops, cs, weak)        // storage_ph:(Maybe TrStoragePhase)
1439
             && t_TrComputePhase.validate_skip(ops, cs, weak)               // compute_ph:TrComputePhase
1440
             && Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak)  // action:(Maybe ^TrActionPhase)
1441
             && cs.advance(2);                                              // aborted:Bool destroyed:Bool
1442
    case trans_split_install:
1443
      return cs.advance(4)                                      // trans_split_install$0101
1444
             && t_SplitMergeInfo.validate_skip(ops, cs, weak)   // split_info:SplitMergeInfo
1445
             && t_Ref_Transaction.validate_skip(ops, cs, weak)  // prepare_transaction:^Transaction
1446
             && cs.advance(1);                                  // installed:Bool
1447
    case trans_merge_prepare:
1448
      return cs.advance(4)                                     // trans_merge_prepare$0110
1449
             && t_SplitMergeInfo.validate_skip(ops, cs, weak)  // split_info:SplitMergeInfo
1450
             && t_TrStoragePhase.validate_skip(ops, cs, weak)  // storage_ph:TrStoragePhase
1451
             && cs.advance(1);                                 // aborted:Bool
1452
    case trans_merge_install:
1453
      return cs.advance(4)                                                  // trans_merge_install$0111
1454
             && t_SplitMergeInfo.validate_skip(ops, cs, weak)               // split_info:SplitMergeInfo
1455
             && t_Ref_Transaction.validate_skip(ops, cs, weak)              // prepare_transaction:^Transaction
1456
             && Maybe<TrStoragePhase>{}.validate_skip(ops, cs, weak)        // storage_ph:(Maybe TrStoragePhase)
1457
             && Maybe<TrCreditPhase>{}.validate_skip(ops, cs, weak)         // credit_ph:(Maybe TrCreditPhase)
1458
             && Maybe<TrComputePhase>{}.validate_skip(ops, cs, weak)        // compute_ph:TrComputePhase
1459
             && Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak)  // action:(Maybe ^TrActionPhase)
1460
             && cs.advance(2);                                              // aborted:Bool destroyed:Bool
1461
  }
1462
  return false;
1463
}
1464

1465
int TransactionDescr::get_tag(const vm::CellSlice& cs) const {
1466
  int t = (int)cs.prefetch_ulong(4);
1467
  return (t >= 0 && t <= 7) ? (t == 3 ? 2 : t) : -1;
1468
}
1469

1470
bool TransactionDescr::skip_to_storage_phase(vm::CellSlice& cs, bool& found) const {
1471
  found = false;
1472
  switch (get_tag(cs)) {
1473
    case trans_ord:
1474
      return cs.advance(4 + 1)            // trans_ord$0000 storage_first:Bool
1475
             && cs.fetch_bool_to(found);  // storage_ph:(Maybe TrStoragePhase)
1476
    case trans_storage:
1477
      return cs.advance(4)       // trans_storage$0001
1478
             && (found = true);  // storage_ph:TrStoragePhase
1479
    case trans_tick_tock:
1480
      return cs.advance(4)       // trans_tick_tock$001 is_tock:Bool
1481
             && (found = true);  // storage_ph:TrStoragePhase
1482
    case trans_split_prepare:
1483
      return cs.advance(4)                 // trans_split_prepare$0100
1484
             && t_SplitMergeInfo.skip(cs)  // split_info:SplitMergeInfo
1485
             && cs.fetch_bool_to(found);   // storage_ph:(Maybe TrStoragePhase)
1486
    case trans_split_install:
1487
      return true;
1488
    case trans_merge_prepare:
1489
      return cs.advance(4)                 // trans_merge_prepare$0110
1490
             && t_SplitMergeInfo.skip(cs)  // split_info:SplitMergeInfo
1491
             && (found = true);            // storage_ph:TrStoragePhase
1492
    case trans_merge_install:
1493
      return cs.advance(4)                  // trans_merge_install$0111
1494
             && t_SplitMergeInfo.skip(cs)   // split_info:SplitMergeInfo
1495
             && t_Ref_Transaction.skip(cs)  // prepare_transaction:^Transaction
1496
             && cs.fetch_bool_to(found);    // storage_ph:(Maybe TrStoragePhase)
1497
  }
1498
  return false;
1499
}
1500

1501
bool TransactionDescr::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
1502
  if (cell.is_null()) {
1503
    return false;
1504
  }
1505
  auto cs = vm::load_cell_slice(std::move(cell));
1506
  bool found;
1507
  if (!skip_to_storage_phase(cs, found)) {
1508
    return false;
1509
  } else if (found) {
1510
    return t_TrStoragePhase.get_storage_fees(cs, storage_fees);
1511
  } else {
1512
    storage_fees = td::make_refint(0);
1513
    return true;
1514
  }
1515
}
1516

1517
const TransactionDescr t_TransactionDescr;
1518

1519
bool Transaction_aux::skip(vm::CellSlice& cs) const {
1520
  return Maybe<RefTo<Message>>{}.skip(cs)          // in_msg:(Maybe ^Message)
1521
         && HashmapE{15, t_Ref_Message}.skip(cs);  // out_msgs:(HashmapE 15 ^Message)
1522
}
1523

1524
bool Transaction_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1525
  return Maybe<RefTo<Message>>{}.validate_skip(ops, cs, weak)          // in_msg:(Maybe ^Message)
1526
         && HashmapE{15, t_Ref_Message}.validate_skip(ops, cs, weak);  // out_msgs:(HashmapE 15 ^Message)
1527
}
1528

1529
const Transaction_aux t_Transaction_aux;
1530

1531
bool Transaction::skip(vm::CellSlice& cs) const {
1532
  return cs.advance(
1533
             4 + 256 + 64 + 256 + 64 + 32 +
1534
             15)  // transaction$0111 account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
1535
         && t_AccountStatus.skip(cs)             // orig_status:AccountStatus
1536
         && t_AccountStatus.skip(cs)             // end_status:AccountStatus
1537
         && cs.advance_refs(1)                   // ^[ in_msg:(Maybe ^Message) out_msgs:(HashmapE 15 ^Message) ]
1538
         && t_CurrencyCollection.skip(cs)        // total_fees:CurrencyCollection
1539
         && cs.advance_refs(1)                   // state_update:^(MERKLE_UPDATE Account)
1540
         && RefTo<TransactionDescr>{}.skip(cs);  // description:^TransactionDescr
1541
}
1542

1543
bool Transaction::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1544
  return cs.fetch_ulong(4) == 7  // transaction$0111
1545
         &&
1546
         cs.advance(
1547
             256 + 64 + 256 + 64 + 32 +
1548
             15)  // account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
1549
         && t_AccountStatus.validate_skip(ops, cs, weak)             // orig_status:AccountStatus
1550
         && t_AccountStatus.validate_skip(ops, cs, weak)             // end_status:AccountStatus
1551
         && RefTo<Transaction_aux>{}.validate_skip(ops, cs, weak)    // ^[ in_msg:... out_msgs:... ]
1552
         && t_CurrencyCollection.validate_skip(ops, cs, weak)        // total_fees:CurrencyCollection
1553
         && t_Ref_HashUpdate.validate_skip(ops, cs, weak)            // state_update:^(HASH_UPDATE Account)
1554
         && RefTo<TransactionDescr>{}.validate_skip(ops, cs, weak);  // description:^TransactionDescr
1555
}
1556

1557
bool Transaction::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
1558
  Ref<vm::Cell> tdescr;
1559
  return get_descr(std::move(cell), tdescr) && t_TransactionDescr.get_storage_fees(std::move(tdescr), storage_fees);
1560
}
1561

1562
bool Transaction::get_descr(Ref<vm::Cell> cell, Ref<vm::Cell>& tdescr) const {
1563
  if (cell.is_null()) {
1564
    return false;
1565
  } else {
1566
    auto cs = vm::load_cell_slice(std::move(cell));
1567
    return cs.is_valid() && get_descr(cs, tdescr) && cs.empty_ext();
1568
  }
1569
}
1570

1571
bool Transaction::get_descr(vm::CellSlice& cs, Ref<vm::Cell>& tdescr) const {
1572
  return cs.advance(
1573
             4 + 256 + 64 + 256 + 64 + 32 +
1574
             15)  // transaction$0111 account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
1575
         && t_AccountStatus.skip(cs)       // orig_status:AccountStatus
1576
         && t_AccountStatus.skip(cs)       // end_status:AccountStatus
1577
         && cs.advance_refs(1)             // ^[ in_msg:(Maybe ^Message) out_msgs:(HashmapE 15 ^Message) ]
1578
         && t_CurrencyCollection.skip(cs)  // total_fees:CurrencyCollection
1579
         && cs.advance_refs(1)             // state_update:^(MERKLE_UPDATE Account)
1580
         && cs.fetch_ref_to(tdescr);       // description:^TransactionDescr
1581
}
1582

1583
bool Transaction::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const {
1584
  return cs.is_valid() && cs.fetch_ulong(4) == 7  // transaction$0111
1585
         &&
1586
         cs.advance(
1587
             256 + 64 + 256 + 64 + 32 +
1588
             15)  // account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
1589
         && t_AccountStatus.skip(cs)  // orig_status:AccountStatus
1590
         && t_AccountStatus.skip(cs)  // end_status:AccountStatus
1591
         && cs.advance_refs(1)        // ^[ in_msg:... out_msg:... ]
1592
         && total_fees.fetch(cs);     // total_fees:CurrencyCollection
1593
}
1594

1595
const Transaction t_Transaction;
1596
const RefTo<Transaction> t_Ref_Transaction;
1597

1598
// leaf evaluation for (HashmapAug 64 ^Transaction CurrencyCollection)
1599
bool Aug_AccountTransactions::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
1600
  auto cell_ref = cs.prefetch_ref();
1601
  block::CurrencyCollection total_fees;
1602
  return cell_ref.not_null() && t_Transaction.get_total_fees(vm::load_cell_slice(std::move(cell_ref)), total_fees) &&
1603
         total_fees.store(cb);
1604
}
1605

1606
const Aug_AccountTransactions aug_AccountTransactions;
1607
const HashmapAug t_AccountTransactions{64, aug_AccountTransactions};
1608

1609
const HashUpdate t_HashUpdate;
1610
const RefTo<HashUpdate> t_Ref_HashUpdate;
1611

1612
bool AccountBlock::skip(vm::CellSlice& cs) const {
1613
  return cs.advance(4 + 256)                // acc_trans#5 account_addr:bits256
1614
         && t_AccountTransactions.skip(cs)  // transactions:(HashmapAug 64 ^Transaction CurrencyCollection)
1615
         && cs.advance_refs(1);             // state_update:^(HASH_UPDATE Account)
1616
}
1617

1618
bool AccountBlock::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1619
  return cs.fetch_ulong(4) == 5  // acc_trans#5
1620
         && cs.advance(256)      // account_addr:bits256
1621
         && t_AccountTransactions.validate_skip(ops, cs,
1622
                                                weak)  // transactions:(HashmapAug 64 ^Transaction CurrencyCollection)
1623
         && t_Ref_HashUpdate.validate_skip(ops, cs, weak);  // state_update:^(HASH_UPDATE Account)
1624
}
1625

1626
bool AccountBlock::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const {
1627
  return cs.advance(4 + 256)                         // acc_trans#5 account_addr:bits256
1628
         && t_AccountTransactions.extract_extra(cs)  // transactions:(HashmapAug 64 ^Transaction Grams)
1629
         && total_fees.fetch(cs);
1630
}
1631

1632
const AccountBlock t_AccountBlock;
1633

1634
bool Aug_ShardAccountBlocks::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
1635
  block::CurrencyCollection total_fees;
1636
  return t_AccountBlock.get_total_fees(std::move(cs), total_fees) && total_fees.store(cb);
1637
}
1638

1639
const Aug_ShardAccountBlocks aug_ShardAccountBlocks;
1640
const HashmapAugE t_ShardAccountBlocks{256,
1641
                                       aug_ShardAccountBlocks};  // (HashmapAugE 256 AccountBlock CurrencyCollection)
1642

1643
bool ImportFees::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1644
  return t_Grams.validate_skip(ops, cs, weak) && t_CurrencyCollection.validate_skip(ops, cs, weak);
1645
}
1646

1647
bool ImportFees::skip(vm::CellSlice& cs) const {
1648
  return t_Grams.skip(cs) && t_CurrencyCollection.skip(cs);
1649
}
1650

1651
bool ImportFees::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
1652
  return t_Grams.add_values(cb, cs1, cs2) && t_CurrencyCollection.add_values(cb, cs1, cs2);
1653
}
1654

1655
const ImportFees t_ImportFees;
1656

1657
bool InMsg::skip(vm::CellSlice& cs) const {
1658
  switch (get_tag(cs)) {
1659
    case msg_import_ext:
1660
      return cs.advance(3)                   // msg_import_ext$000
1661
             && t_Ref_Message.skip(cs)       // msg:^Message
1662
             && t_Ref_Transaction.skip(cs);  // transaction:^Transaction
1663
    case msg_import_ihr:
1664
      return cs.advance(3)                  // msg_import_ihr$010
1665
             && t_Ref_Message.skip(cs)      // msg:^Message
1666
             && t_Ref_Transaction.skip(cs)  // transaction:^Transaction
1667
             && t_Grams.skip(cs)            // ihr_fee:Grams
1668
             && t_RefCell.skip(cs);         // proof_created:^Cell
1669
    case msg_import_imm:
1670
      return cs.advance(3)                  // msg_import_imm$011
1671
             && t_Ref_MsgEnvelope.skip(cs)  // in_msg:^MsgEnvelope
1672
             && t_Ref_Transaction.skip(cs)  // transaction:^Transaction
1673
             && t_Grams.skip(cs);           // fwd_fee:Grams
1674
    case msg_import_fin:
1675
      return cs.advance(3)                  // msg_import_fin$100
1676
             && t_Ref_MsgEnvelope.skip(cs)  // in_msg:^MsgEnvelope
1677
             && t_Ref_Transaction.skip(cs)  // transaction:^Transaction
1678
             && t_Grams.skip(cs);           // fwd_fee:Grams
1679
    case msg_import_tr:
1680
      return cs.advance(3)                  // msg_import_tr$101
1681
             && t_Ref_MsgEnvelope.skip(cs)  // in_msg:^MsgEnvelope
1682
             && t_Ref_MsgEnvelope.skip(cs)  // out_msg:^MsgEnvelope
1683
             && t_Grams.skip(cs);           // transit_fee:Grams
1684
    case msg_discard_fin:
1685
      return cs.advance(3)                  // msg_discard_fin$110
1686
             && t_Ref_MsgEnvelope.skip(cs)  // in_msg:^MsgEnvelope
1687
             && cs.advance(64)              // transaction_id:uint64
1688
             && t_Grams.skip(cs);           // fwd_fee:Grams
1689
    case msg_discard_tr:
1690
      return cs.advance(3)                  // msg_discard_tr$111
1691
             && t_Ref_MsgEnvelope.skip(cs)  // in_msg:^MsgEnvelope
1692
             && cs.advance(64)              // transaction_id:uint64
1693
             && t_Grams.skip(cs)            // fwd_fee:Grams
1694
             && t_RefCell.skip(cs);         // proof_delivered:^Cell
1695
  }
1696
  return false;
1697
}
1698

1699
bool InMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1700
  switch (get_tag(cs)) {
1701
    case msg_import_ext:
1702
      return cs.advance(3)                                       // msg_import_ext$000
1703
             && t_Ref_Message.validate_skip(ops, cs, weak)       // msg:^Message
1704
             && t_Ref_Transaction.validate_skip(ops, cs, weak);  // transaction:^Transaction
1705
    case msg_import_ihr:
1706
      return cs.advance(3)                                      // msg_import_ihr$010
1707
             && t_Ref_Message.validate_skip(ops, cs, weak)      // msg:^Message
1708
             && t_Ref_Transaction.validate_skip(ops, cs, weak)  // transaction:^Transaction
1709
             && t_Grams.validate_skip(ops, cs, weak)            // ihr_fee:Grams
1710
             && t_RefCell.validate_skip(ops, cs, weak);         // proof_created:^Cell
1711
    case msg_import_imm:
1712
      return cs.advance(3)                                      // msg_import_imm$011
1713
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // in_msg:^MsgEnvelope
1714
             && t_Ref_Transaction.validate_skip(ops, cs, weak)  // transaction:^Transaction
1715
             && t_Grams.validate_skip(ops, cs, weak);           // fwd_fee:Grams
1716
    case msg_import_fin:
1717
      return cs.advance(3)                                      // msg_import_fin$100
1718
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // in_msg:^MsgEnvelope
1719
             && t_Ref_Transaction.validate_skip(ops, cs, weak)  // transaction:^Transaction
1720
             && t_Grams.validate_skip(ops, cs, weak);           // fwd_fee:Grams
1721
    case msg_import_tr:
1722
      return cs.advance(3)                                      // msg_import_tr$101
1723
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // in_msg:^MsgEnvelope
1724
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // out_msg:^MsgEnvelope
1725
             && t_Grams.validate_skip(ops, cs, weak);           // transit_fee:Grams
1726
    case msg_discard_fin:
1727
      return cs.advance(3)                                      // msg_discard_fin$110
1728
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // in_msg:^MsgEnvelope
1729
             && cs.advance(64)                                  // transaction_id:uint64
1730
             && t_Grams.validate_skip(ops, cs, weak);           // fwd_fee:Grams
1731
    case msg_discard_tr:
1732
      return cs.advance(3)                                      // msg_discard_tr$111
1733
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // in_msg:^MsgEnvelope
1734
             && cs.advance(64)                                  // transaction_id:uint64
1735
             && t_Grams.validate_skip(ops, cs, weak)            // fwd_fee:Grams
1736
             && t_RefCell.validate_skip(ops, cs, weak);         // proof_delivered:^Cell
1737
  }
1738
  return false;
1739
}
1740

1741
bool InMsg::get_import_fees(vm::CellBuilder& cb, vm::CellSlice& cs) const {
1742
  switch (get_tag(cs)) {
1743
    case msg_import_ext:                   // inbound external message
1744
      return t_ImportFees.null_value(cb);  // external messages have no value and no import fees
1745
    case msg_import_ihr:                   // IHR-forwarded internal message to its final destination
1746
      if (cs.advance(3) && cs.size_refs() >= 3) {
1747
        auto msg_cs = load_cell_slice(cs.fetch_ref());
1748
        CommonMsgInfo::Record_int_msg_info msg_info;
1749
        td::RefInt256 ihr_fee;
1750
        vm::CellBuilder aux;
1751
        // sort of Prolog-style in C++
1752
        return t_Message.extract_info(msg_cs) && t_CommonMsgInfo.unpack(msg_cs, msg_info) &&
1753
               cs.fetch_ref().not_null() && (ihr_fee = t_Grams.as_integer_skip(cs)).not_null() &&
1754
               cs.fetch_ref().not_null() && !cmp(ihr_fee, t_Grams.as_integer(*msg_info.ihr_fee)) &&
1755
               cb.append_cellslice_bool(msg_info.ihr_fee)  // fees_collected := ihr_fee
1756
               && aux.append_cellslice_bool(msg_info.ihr_fee) && t_ExtraCurrencyCollection.null_value(aux) &&
1757
               t_CurrencyCollection.add_values(cb, aux.as_cellslice_ref().write(),
1758
                                               msg_info.value.write());  // value_imported := ihr_fee + value
1759
      }
1760
      return false;
1761
    case msg_import_imm:  // internal message re-imported from this very block
1762
      if (cs.advance(3) && cs.size_refs() >= 2) {
1763
        return cs.fetch_ref().not_null() && cs.fetch_ref().not_null() &&
1764
               cb.append_cellslice_bool(t_Grams.fetch(cs))  // fees_collected := fwd_fees
1765
               && t_CurrencyCollection.null_value(cb);      // value_imported := 0
1766
      }
1767
      return false;
1768
    case msg_import_fin:  // internal message delivered to its final destination in this block
1769
      if (cs.advance(3) && cs.size_refs() >= 2) {
1770
        auto msg_env_cs = load_cell_slice(cs.fetch_ref());
1771
        MsgEnvelope::Record in_msg;
1772
        td::RefInt256 fwd_fee, fwd_fee_remaining, value_grams, ihr_fee;
1773
        if (!(t_MsgEnvelope.unpack(msg_env_cs, in_msg) && cs.fetch_ref().not_null() &&
1774
              t_Grams.as_integer_skip_to(cs, fwd_fee) &&
1775
              (fwd_fee_remaining = t_Grams.as_integer(in_msg.fwd_fee_remaining)).not_null() &&
1776
              !(cmp(fwd_fee, fwd_fee_remaining)))) {
1777
          return false;
1778
        }
1779
        auto msg_cs = load_cell_slice(std::move(in_msg.msg));
1780
        CommonMsgInfo::Record_int_msg_info msg_info;
1781
        return t_Message.extract_info(msg_cs) && t_CommonMsgInfo.unpack(msg_cs, msg_info) &&
1782
               cb.append_cellslice_bool(in_msg.fwd_fee_remaining)  // fees_collected := fwd_fee_remaining
1783
               && t_Grams.as_integer_skip_to(msg_info.value.write(), value_grams) &&
1784
               (ihr_fee = t_Grams.as_integer(std::move(msg_info.ihr_fee))).not_null() &&
1785
               t_Grams.store_integer_ref(cb, value_grams + ihr_fee + fwd_fee_remaining) &&
1786
               cb.append_cellslice_bool(
1787
                   msg_info.value.write());  // value_imported = msg.value + msg.ihr_fee + fwd_fee_remaining
1788
      }
1789
      return false;
1790
    case msg_import_tr:  // transit internal message
1791
      if (cs.advance(3) && cs.size_refs() >= 2) {
1792
        auto msg_env_cs = load_cell_slice(cs.fetch_ref());
1793
        MsgEnvelope::Record in_msg;
1794
        td::RefInt256 transit_fee, fwd_fee_remaining, value_grams, ihr_fee;
1795
        if (!(t_MsgEnvelope.unpack(msg_env_cs, in_msg) && cs.fetch_ref().not_null() &&
1796
              t_Grams.as_integer_skip_to(cs, transit_fee) &&
1797
              (fwd_fee_remaining = t_Grams.as_integer(in_msg.fwd_fee_remaining)).not_null() &&
1798
              cmp(transit_fee, fwd_fee_remaining) <= 0)) {
1799
          return false;
1800
        }
1801
        auto msg_cs = load_cell_slice(in_msg.msg);
1802
        CommonMsgInfo::Record_int_msg_info msg_info;
1803
        return t_Message.extract_info(msg_cs) && t_CommonMsgInfo.unpack(msg_cs, msg_info) &&
1804
               t_Grams.store_integer_ref(cb, std::move(transit_fee))  // fees_collected := transit_fees
1805
               && t_Grams.as_integer_skip_to(msg_info.value.write(), value_grams) &&
1806
               (ihr_fee = t_Grams.as_integer(std::move(msg_info.ihr_fee))).not_null() &&
1807
               t_Grams.store_integer_ref(cb, value_grams + ihr_fee + fwd_fee_remaining) &&
1808
               cb.append_cellslice_bool(
1809
                   msg_info.value.write());  // value_imported = msg.value + msg.ihr_fee + fwd_fee_remaining
1810
      }
1811
      return false;
1812
    case msg_discard_fin:  // internal message discarded at its final destination because of previous IHR delivery
1813
      if (cs.advance(3) && cs.size_refs() >= 1) {
1814
        Ref<vm::CellSlice> fwd_fee;
1815
        return cs.fetch_ref().not_null() && cs.advance(64) && (fwd_fee = t_Grams.fetch(cs)).not_null() &&
1816
               cb.append_cellslice_bool(fwd_fee)  // fees_collected := fwd_fee
1817
               && cb.append_cellslice_bool(std::move(fwd_fee)) &&
1818
               t_ExtraCurrencyCollection.null_value(cb);  // value_imported := fwd_fee
1819
      }
1820
      return false;
1821
    case msg_discard_tr:  // internal message discarded at an intermediate destination
1822
      if (cs.advance(3) && cs.size_refs() >= 2) {
1823
        Ref<vm::CellSlice> fwd_fee;
1824
        return cs.fetch_ref().not_null() && cs.advance(64) && (fwd_fee = t_Grams.fetch(cs)).not_null() &&
1825
               cs.fetch_ref().not_null() && cb.append_cellslice_bool(fwd_fee)  // fees_collected := fwd_fee
1826
               && cb.append_cellslice_bool(std::move(fwd_fee)) &&
1827
               t_ExtraCurrencyCollection.null_value(cb);  // value_imported := fwd_fee
1828
      }
1829
      return false;
1830
  }
1831
  return false;
1832
}
1833

1834
const InMsg t_InMsg;
1835

1836
const Aug_InMsgDescr aug_InMsgDescr;
1837
const InMsgDescr t_InMsgDescr;
1838

1839
bool OutMsg::skip(vm::CellSlice& cs) const {
1840
  switch (get_tag(cs)) {
1841
    case msg_export_ext:
1842
      return cs.advance(3)                   // msg_export_ext$000
1843
             && t_Ref_Message.skip(cs)       // msg:^Message
1844
             && t_Ref_Transaction.skip(cs);  // transaction:^Transaction
1845
    case msg_export_imm:
1846
      return cs.advance(3)                  // msg_export_imm$010
1847
             && t_Ref_MsgEnvelope.skip(cs)  // out_msg:^MsgEnvelope
1848
             && t_Ref_Transaction.skip(cs)  // transaction:^Transaction
1849
             && RefTo<InMsg>{}.skip(cs);    // reimport:^InMsg
1850
    case msg_export_new:
1851
      return cs.advance(3)                   // msg_export_new$001
1852
             && t_Ref_MsgEnvelope.skip(cs)   // out_msg:^MsgEnvelope
1853
             && t_Ref_Transaction.skip(cs);  // transaction:^Transaction
1854
    case msg_export_tr:
1855
      return cs.advance(3)                  // msg_export_tr$011
1856
             && t_Ref_MsgEnvelope.skip(cs)  // out_msg:^MsgEnvelope
1857
             && RefTo<InMsg>{}.skip(cs);    // imported:^InMsg
1858
    case msg_export_deq_imm:
1859
      return cs.advance(3)                  // msg_export_deq_imm$100
1860
             && t_Ref_MsgEnvelope.skip(cs)  // out_msg:^MsgEnvelope
1861
             && RefTo<InMsg>{}.skip(cs);    // reimport:^InMsg
1862
    case msg_export_deq:
1863
      return cs.advance(4)                  // msg_export_deq$1100
1864
             && t_Ref_MsgEnvelope.skip(cs)  // out_msg:^MsgEnvelope
1865
             && cs.advance(63);             // import_block_lt:uint63
1866
    case msg_export_deq_short:
1867
      return cs.advance(
1868
          4 + 256 + 32 + 64 +
1869
          64);  // msg_export_deq_short$1101 msg_env_hash:bits256 next_workchain:int32 next_addr_pfx:uint64 import_block_lt:uint64
1870
    case msg_export_tr_req:
1871
      return cs.advance(3)                  // msg_export_tr_req$111
1872
             && t_Ref_MsgEnvelope.skip(cs)  // out_msg:^MsgEnvelope
1873
             && RefTo<InMsg>{}.skip(cs);    // imported:^InMsg
1874
  }
1875
  return false;
1876
}
1877

1878
bool OutMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1879
  switch (get_tag(cs)) {
1880
    case msg_export_ext:
1881
      return cs.advance(3)                                       // msg_export_ext$000
1882
             && t_Ref_Message.validate_skip(ops, cs, weak)       // msg:^Message
1883
             && t_Ref_Transaction.validate_skip(ops, cs, weak);  // transaction:^Transaction
1884
    case msg_export_imm:
1885
      return cs.advance(3)                                      // msg_export_imm$010
1886
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // out_msg:^MsgEnvelope
1887
             && t_Ref_Transaction.validate_skip(ops, cs, weak)  // transaction:^Transaction
1888
             && RefTo<InMsg>{}.validate_skip(ops, cs, weak);    // reimport:^InMsg
1889
    case msg_export_new:
1890
      return cs.advance(3)                                       // msg_export_new$001
1891
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)   // out_msg:^MsgEnvelope
1892
             && t_Ref_Transaction.validate_skip(ops, cs, weak);  // transaction:^Transaction
1893
    case msg_export_tr:
1894
      return cs.advance(3)                                      // msg_export_tr$011
1895
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // out_msg:^MsgEnvelope
1896
             && RefTo<InMsg>{}.validate_skip(ops, cs, weak);    // imported:^InMsg
1897
    case msg_export_deq_imm:
1898
      return cs.advance(3)                                      // msg_export_deq_imm$100
1899
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // out_msg:^MsgEnvelope
1900
             && RefTo<InMsg>{}.validate_skip(ops, cs, weak);    // reimport:^InMsg
1901
    case msg_export_deq:
1902
      return cs.advance(4)                                      // msg_export_deq$1100
1903
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // out_msg:^MsgEnvelope
1904
             && cs.advance(63);                                 // import_block_lt:uint63
1905
    case msg_export_deq_short:
1906
      return cs.advance(
1907
          4 + 256 + 32 + 64 +
1908
          64);  // msg_export_deq_short$1101 msg_env_hash:bits256 next_workchain:int32 next_addr_pfx:uint64 import_block_lt:uint64
1909
    case msg_export_tr_req:
1910
      return cs.advance(3)                                      // msg_export_tr_req$111
1911
             && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak)  // out_msg:^MsgEnvelope
1912
             && RefTo<InMsg>{}.validate_skip(ops, cs, weak);    // imported:^InMsg
1913
  }
1914
  return false;
1915
}
1916

1917
bool OutMsg::get_export_value(vm::CellBuilder& cb, vm::CellSlice& cs) const {
1918
  switch (get_tag(cs)) {
1919
    case msg_export_ext:  // external outbound message carries no value
1920
      if (cs.have(3, 2)) {
1921
        return t_CurrencyCollection.null_value(cb);
1922
      }
1923
      return false;
1924
    case msg_export_imm:  // outbound internal message delivered in this very block, no value exported
1925
      return cs.have(3, 3) && t_CurrencyCollection.null_value(cb);
1926
    case msg_export_deq_imm:  // dequeuing record for outbound message delivered in this very block, no value exported
1927
      return cs.have(3, 2) && t_CurrencyCollection.null_value(cb);
1928
    case msg_export_deq:  // dequeueing record for outbound message, no exported value
1929
      return cs.have(4 + 63, 1) && t_CurrencyCollection.null_value(cb);
1930
    case msg_export_deq_short:  // dequeueing record for outbound message, no exported value
1931
      return cs.have(4 + 256 + 32 + 64 + 64) && t_CurrencyCollection.null_value(cb);
1932
    case msg_export_new:     // newly-generated outbound internal message, queued
1933
    case msg_export_tr:      // transit internal message, queued
1934
    case msg_export_tr_req:  // transit internal message, re-queued from this shardchain
1935
      if (cs.advance(3) && cs.size_refs() >= 2) {
1936
        auto msg_env_cs = load_cell_slice(cs.fetch_ref());
1937
        MsgEnvelope::Record out_msg;
1938
        if (!(cs.fetch_ref().not_null() && t_MsgEnvelope.unpack(msg_env_cs, out_msg))) {
1939
          return false;
1940
        }
1941
        auto msg_cs = load_cell_slice(std::move(out_msg.msg));
1942
        CommonMsgInfo::Record_int_msg_info msg_info;
1943
        td::RefInt256 value_grams, ihr_fee, fwd_fee_remaining;
1944
        return t_Message.extract_info(msg_cs) && t_CommonMsgInfo.unpack(msg_cs, msg_info) &&
1945
               (value_grams = t_Grams.as_integer_skip(msg_info.value.write())).not_null() &&
1946
               (ihr_fee = t_Grams.as_integer(std::move(msg_info.ihr_fee))).not_null() &&
1947
               (fwd_fee_remaining = t_Grams.as_integer(out_msg.fwd_fee_remaining)).not_null() &&
1948
               t_Grams.store_integer_ref(cb, value_grams + ihr_fee + fwd_fee_remaining) &&
1949
               cb.append_cellslice_bool(std::move(msg_info.value));
1950
        // exported value = msg.value + msg.ihr_fee + fwd_fee_remaining
1951
      }
1952
      return false;
1953
  }
1954
  return false;
1955
}
1956

1957
bool OutMsg::get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const {
1958
  switch (get_tag(cs)) {
1959
    case msg_export_ext:
1960
      if (cs.have(3, 1)) {
1961
        auto msg_cs = load_cell_slice(cs.prefetch_ref());
1962
        return t_Message.get_created_lt(msg_cs, created_lt);
1963
      } else {
1964
        return false;
1965
      }
1966
    case msg_export_imm:
1967
    case msg_export_new:
1968
    case msg_export_tr:
1969
    case msg_export_deq:
1970
    case msg_export_deq_short:
1971
    case msg_export_deq_imm:
1972
    case msg_export_tr_req:
1973
      if (cs.have(3, 1)) {
1974
        auto out_msg_cs = load_cell_slice(cs.prefetch_ref());
1975
        return t_MsgEnvelope.get_created_lt(out_msg_cs, created_lt);
1976
      } else {
1977
        return false;
1978
      }
1979
  }
1980
  return false;
1981
}
1982

1983
const OutMsg t_OutMsg;
1984

1985
const Aug_OutMsgDescr aug_OutMsgDescr;
1986
const OutMsgDescr t_OutMsgDescr;
1987

1988
bool EnqueuedMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
1989
  return cs.advance(64) && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak);
1990
}
1991

1992
const EnqueuedMsg t_EnqueuedMsg;
1993

1994
bool Aug_OutMsgQueue::eval_fork(vm::CellBuilder& cb, vm::CellSlice& left_cs, vm::CellSlice& right_cs) const {
1995
  unsigned long long x, y;
1996
  return left_cs.fetch_ulong_bool(64, x) && right_cs.fetch_ulong_bool(64, y) &&
1997
         cb.store_ulong_rchk_bool(std::min(x, y), 64);
1998
}
1999

2000
bool Aug_OutMsgQueue::eval_empty(vm::CellBuilder& cb) const {
2001
  return cb.store_long_bool(0, 64);
2002
}
2003

2004
bool Aug_OutMsgQueue::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
2005
  Ref<vm::Cell> msg_env;
2006
  unsigned long long created_lt;
2007
  return cs.fetch_ref_to(msg_env) && t_MsgEnvelope.get_created_lt(load_cell_slice(std::move(msg_env)), created_lt) &&
2008
         cb.store_ulong_rchk_bool(created_lt, 64);
2009
}
2010

2011
const Aug_OutMsgQueue aug_OutMsgQueue;
2012
const OutMsgQueue t_OutMsgQueue;
2013

2014
const ProcessedUpto t_ProcessedUpto;
2015
const HashmapE t_ProcessedInfo{96, t_ProcessedUpto};
2016
const HashmapE t_IhrPendingInfo{256, t_uint128};
2017

2018
// _ out_queue:OutMsgQueue proc_info:ProcessedInfo = OutMsgQueueInfo;
2019
bool OutMsgQueueInfo::skip(vm::CellSlice& cs) const {
2020
  return t_OutMsgQueue.skip(cs) && t_ProcessedInfo.skip(cs) && t_IhrPendingInfo.skip(cs);
2021
}
2022

2023
bool OutMsgQueueInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2024
  return t_OutMsgQueue.validate_skip(ops, cs, weak) && t_ProcessedInfo.validate_skip(ops, cs, weak) &&
2025
         t_IhrPendingInfo.validate_skip(ops, cs, weak);
2026
}
2027

2028
const OutMsgQueueInfo t_OutMsgQueueInfo;
2029
const RefTo<OutMsgQueueInfo> t_Ref_OutMsgQueueInfo;
2030

2031
bool ExtBlkRef::unpack(vm::CellSlice& cs, ton::BlockIdExt& blkid, ton::LogicalTime* end_lt) const {
2032
  block::gen::ExtBlkRef::Record data;
2033
  if (!tlb::unpack(cs, data)) {
2034
    blkid.invalidate();
2035
    return false;
2036
  }
2037
  blkid.id = ton::BlockId{ton::masterchainId, ton::shardIdAll, data.seq_no};
2038
  blkid.root_hash = data.root_hash;
2039
  blkid.file_hash = data.file_hash;
2040
  if (end_lt) {
2041
    *end_lt = data.end_lt;
2042
  }
2043
  return true;
2044
}
2045

2046
bool ExtBlkRef::unpack(Ref<vm::CellSlice> cs_ref, ton::BlockIdExt& blkid, ton::LogicalTime* end_lt) const {
2047
  block::gen::ExtBlkRef::Record data;
2048
  if (!tlb::csr_unpack_safe(std::move(cs_ref), data)) {
2049
    blkid.invalidate();
2050
    return false;
2051
  }
2052
  blkid.id = ton::BlockId{ton::masterchainId, ton::shardIdAll, data.seq_no};
2053
  blkid.root_hash = data.root_hash;
2054
  blkid.file_hash = data.file_hash;
2055
  if (end_lt) {
2056
    *end_lt = data.end_lt;
2057
  }
2058
  return true;
2059
}
2060

2061
bool ExtBlkRef::store(vm::CellBuilder& cb, const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const {
2062
  return cb.store_long_bool(end_lt, 64)            // ext_blk_ref$_ end_lt:uint64
2063
         && cb.store_long_bool(blkid.seqno(), 32)  // seq_no:uint32
2064
         && cb.store_bits_bool(blkid.root_hash)    // root_hash:bits256
2065
         && cb.store_bits_bool(blkid.file_hash);   // file_hash:bits256 = ExtBlkRef;
2066
}
2067

2068
Ref<vm::Cell> ExtBlkRef::pack_cell(const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const {
2069
  vm::CellBuilder cb;
2070
  return store(cb, blkid, end_lt) ? cb.finalize() : Ref<vm::Cell>{};
2071
}
2072

2073
bool ExtBlkRef::pack_to(Ref<vm::Cell>& cell, const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const {
2074
  vm::CellBuilder cb;
2075
  return store(cb, blkid, end_lt) && cb.finalize_to(cell);
2076
}
2077

2078
const ExtBlkRef t_ExtBlkRef;
2079
const BlkMasterInfo t_BlkMasterInfo;
2080

2081
bool ShardIdent::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2082
  int shard_pfx_len, workchain_id;
2083
  unsigned long long shard_pfx;
2084
  if (cs.fetch_ulong(2) == 0 && cs.fetch_uint_to(6, shard_pfx_len) && cs.fetch_int_to(32, workchain_id) &&
2085
      workchain_id != ton::workchainInvalid && cs.fetch_uint_to(64, shard_pfx)) {
2086
    auto pow2 = (1ULL << (63 - shard_pfx_len));
2087
    if (!(shard_pfx & (pow2 - 1))) {
2088
      return true;
2089
    }
2090
  }
2091
  return false;
2092
}
2093

2094
bool ShardIdent::Record::check() const {
2095
  return workchain_id != ton::workchainInvalid && !(shard_prefix & ((1ULL << (63 - shard_pfx_bits)) - 1));
2096
}
2097

2098
bool ShardIdent::unpack(vm::CellSlice& cs, ShardIdent::Record& data) const {
2099
  if (cs.fetch_ulong(2) == 0 && cs.fetch_uint_to(6, data.shard_pfx_bits) && cs.fetch_int_to(32, data.workchain_id) &&
2100
      cs.fetch_uint_to(64, data.shard_prefix) && data.check()) {
2101
    return true;
2102
  } else {
2103
    data.invalidate();
2104
    return false;
2105
  }
2106
}
2107

2108
bool ShardIdent::pack(vm::CellBuilder& cb, const Record& data) const {
2109
  return data.check() && cb.store_ulong_rchk_bool(0, 2) && cb.store_ulong_rchk_bool(data.shard_pfx_bits, 6) &&
2110
         cb.store_long_rchk_bool(data.workchain_id, 32) && cb.store_ulong_rchk_bool(data.shard_prefix, 64);
2111
}
2112

2113
bool ShardIdent::unpack(vm::CellSlice& cs, ton::WorkchainId& workchain, ton::ShardId& shard) const {
2114
  int bits;
2115
  unsigned long long pow2;
2116
  auto assign = [](auto& a, auto b) { return a = b; };
2117
  auto assign_or = [](auto& a, auto b) { return a |= b; };
2118
  return cs.fetch_ulong(2) == 0                  // shard_ident$00
2119
         && cs.fetch_uint_leq(60, bits)          // shard_pfx_bits:(#<= 60)
2120
         && assign(pow2, (1ULL << (63 - bits)))  // (power)
2121
         && cs.fetch_int_to(32, workchain)       // workchain_id:int32
2122
         && cs.fetch_uint_to(64, shard)          // shard_prefix:uint64
2123
         && workchain != ton::workchainInvalid && !(shard & (2 * pow2 - 1)) && assign_or(shard, pow2);
2124
}
2125

2126
bool ShardIdent::unpack(vm::CellSlice& cs, ton::ShardIdFull& data) const {
2127
  return unpack(cs, data.workchain, data.shard);
2128
}
2129

2130
bool ShardIdent::pack(vm::CellBuilder& cb, ton::WorkchainId workchain, ton::ShardId shard) const {
2131
  int bits = ton::shard_prefix_length(shard);
2132
  return workchain != ton::workchainInvalid               // check workchain
2133
         && shard                                         // check shard
2134
         && cb.store_long_bool(0, 2)                      // shard_ident$00
2135
         && cb.store_uint_leq(60, bits)                   // shard_pfx_bits:(#<= 60)
2136
         && cb.store_long_bool(workchain, 32)             // workchain_id:int32
2137
         && cb.store_long_bool(shard & (shard - 1), 64);  // shard_prefix:uint64
2138
}
2139

2140
bool ShardIdent::pack(vm::CellBuilder& cb, ton::ShardIdFull data) const {
2141
  return pack(cb, data.workchain, data.shard);
2142
}
2143

2144
const ShardIdent t_ShardIdent;
2145

2146
bool BlockIdExt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2147
  return t_ShardIdent.validate_skip(ops, cs, weak) && cs.advance(32 + 256 * 2);
2148
}
2149

2150
bool BlockIdExt::unpack(vm::CellSlice& cs, ton::BlockIdExt& data) const {
2151
  return t_ShardIdent.unpack(cs, data.id.workchain, data.id.shard)  // block_id_ext$_ shard_id:ShardIdent
2152
         && cs.fetch_uint_to(32, data.id.seqno)                     // seq_no:uint32
2153
         && cs.fetch_bits_to(data.root_hash)                        // root_hash:bits256
2154
         && cs.fetch_bits_to(data.file_hash);                       // file_hash:bits256
2155
}
2156

2157
bool BlockIdExt::pack(vm::CellBuilder& cb, const ton::BlockIdExt& data) const {
2158
  return t_ShardIdent.pack(cb, data.id.workchain, data.id.shard)  // block_id_ext$_ shard_id:ShardIdent
2159
         && cb.store_long_bool(data.id.seqno, 32)                 // seq_no:uint32
2160
         && cb.store_bits_bool(data.root_hash)                    // root_hash:bits256
2161
         && cb.store_bits_bool(data.file_hash);                   // file_hash:bits256
2162
}
2163

2164
const BlockIdExt t_BlockIdExt;
2165

2166
bool ShardState::skip(vm::CellSlice& cs) const {
2167
  return get_tag(cs) == shard_state && cs.advance(64)  // shard_state#9023afe2 blockchain_id:int32
2168
         && t_ShardIdent.skip(cs)                      // shard_id:ShardIdent
2169
         && cs.advance(32 + 32 + 32 + 64 +
2170
                       32)  // seq_no:int32 vert_seq_no:# gen_utime:uint32 gen_lt:uint64 min_ref_mc_seqno:uint32
2171
         && t_Ref_OutMsgQueueInfo.skip(cs)  // out_msg_queue_info:^OutMsgQueueInfo
2172
         && cs.advance(1)                   // before_split:Bool
2173
         && cs.advance_refs(1)              // accounts:^ShardAccounts
2174
         &&
2175
         cs.advance_refs(
2176
             1)  // ^[ total_balance:CurrencyCollection total_validator_fees:CurrencyCollection libraries:(HashmapE 256 LibDescr) master_ref:(Maybe BlkMasterInfo) ]
2177
         && Maybe<RefTo<McStateExtra>>{}.skip(cs);  // custom:(Maybe ^McStateExtra)
2178
}
2179

2180
bool ShardState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2181
  int seq_no;
2182
  return get_tag(cs) == shard_state && cs.advance(64)  // shard_state#9023afe2 blockchain_id:int32
2183
         && t_ShardIdent.validate_skip(ops, cs, weak)  // shard_id:ShardIdent
2184
         && cs.fetch_int_to(32, seq_no)                // seq_no:int32
2185
         && seq_no >= -1                               // { seq_no >= -1 }
2186
         && cs.advance(32 + 32 + 64 + 32)  // vert_seq_no:# gen_utime:uint32 gen_lt:uint64 min_ref_mc_seqno:uint32
2187
         && t_Ref_OutMsgQueueInfo.validate_skip(ops, cs, weak)  // out_msg_queue_info:^OutMsgQueueInfo
2188
         && cs.advance(1)                                       // before_split:Bool
2189
         && t_ShardAccounts.validate_skip_ref(ops, cs, weak)    // accounts:^ShardAccounts
2190
         &&
2191
         t_ShardState_aux.validate_skip_ref(
2192
             ops, cs,
2193
             weak)  // ^[ total_balance:CurrencyCollection total_validator_fees:CurrencyCollection libraries:(HashmapE 256 LibDescr) master_ref:(Maybe BlkMasterInfo) ]
2194
         && Maybe<RefTo<McStateExtra>>{}.validate_skip(ops, cs, weak);  // custom:(Maybe ^McStateExtra)
2195
}
2196

2197
const ShardState t_ShardState;
2198

2199
bool ShardState_aux::skip(vm::CellSlice& cs) const {
2200
  return cs.advance(128)                        // overload_history:uint64 underload_history:uint64
2201
         && t_CurrencyCollection.skip(cs)       // total_balance:CurrencyCollection
2202
         && t_CurrencyCollection.skip(cs)       // total_validator_fees:CurrencyCollection
2203
         && HashmapE{256, t_LibDescr}.skip(cs)  // libraries:(HashmapE 256 LibDescr)
2204
         && Maybe<BlkMasterInfo>{}.skip(cs);    // master_ref:(Maybe BlkMasterInfo)
2205
}
2206

2207
bool ShardState_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2208
  return cs.advance(128)                                            // overload_history:uint64 underload_history:uint64
2209
         && t_CurrencyCollection.validate_skip(ops, cs, weak)       // total_balance:CurrencyCollection
2210
         && t_CurrencyCollection.validate_skip(ops, cs, weak)       // total_validator_fees:CurrencyCollection
2211
         && HashmapE{256, t_LibDescr}.validate_skip(ops, cs, weak)  // libraries:(HashmapE 256 LibDescr)
2212
         && Maybe<BlkMasterInfo>{}.validate_skip(ops, cs, weak);    // master_ref:(Maybe BlkMasterInfo)
2213
}
2214

2215
const ShardState_aux t_ShardState_aux;
2216

2217
bool LibDescr::skip(vm::CellSlice& cs) const {
2218
  return cs.advance(2)                      // shared_lib_descr$00
2219
         && cs.fetch_ref().not_null()       // lib:^Cell
2220
         && Hashmap{256, t_True}.skip(cs);  // publishers:(Hashmap 256 False)
2221
}
2222

2223
bool LibDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2224
  return get_tag(cs) == shared_lib_descr && cs.advance(2)       // shared_lib_descr$00
2225
         && cs.fetch_ref().not_null()                           // lib:^Cell
2226
         && Hashmap{256, t_True}.validate_skip(ops, cs, weak);  // publishers:(Hashmap 256 False)
2227
}
2228

2229
const LibDescr t_LibDescr;
2230

2231
bool BlkPrevInfo::skip(vm::CellSlice& cs) const {
2232
  return t_ExtBlkRef.skip(cs)                   // prev_blk_info$_ {merged:#} prev:ExtBlkRef
2233
         && (!merged || t_ExtBlkRef.skip(cs));  // prev_alt:merged?ExtBlkRef
2234
}
2235

2236
bool BlkPrevInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2237
  return t_ExtBlkRef.validate_skip(ops, cs, weak)                   // prev_blk_info$_ {merged:#} prev:ExtBlkRef
2238
         && (!merged || t_ExtBlkRef.validate_skip(ops, cs, weak));  // prev_alt:merged?ExtBlkRef
2239
}
2240

2241
const BlkPrevInfo t_BlkPrevInfo_0{0};
2242

2243
bool McStateExtra::skip(vm::CellSlice& cs) const {
2244
  return block::gen::t_McStateExtra.skip(cs);
2245
}
2246

2247
bool McStateExtra::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2248
  return block::gen::t_McStateExtra.validate_skip(ops, cs, weak);  // ??
2249
}
2250

2251
const McStateExtra t_McStateExtra;
2252

2253
const KeyExtBlkRef t_KeyExtBlkRef;
2254

2255
bool KeyMaxLt::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
2256
  bool key1, key2;
2257
  unsigned long long lt1, lt2;
2258
  return cs1.fetch_bool_to(key1) && cs1.fetch_ulong_bool(64, lt1)     // cs1 => _ key:Bool max_end_lt:uint64 = KeyMaxLt;
2259
         && cs2.fetch_bool_to(key2) && cs2.fetch_ulong_bool(64, lt2)  // cs2 => _ key:Bool max_end_lt:uint64 = KeyMaxLt;
2260
         && cb.store_bool_bool(key1 | key2) && cb.store_long_bool(std::max(lt1, lt2), 64);
2261
}
2262

2263
const KeyMaxLt t_KeyMaxLt;
2264

2265
bool Aug_OldMcBlocksInfo::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
2266
  return cs.have(65) && cb.append_bitslice(cs.prefetch_bits(65));  // copy first 1+64 bits
2267
};
2268

2269
const Aug_OldMcBlocksInfo aug_OldMcBlocksInfo;
2270

2271
bool ShardFeeCreated::skip(vm::CellSlice& cs) const {
2272
  return t_CurrencyCollection.skip(cs) && t_CurrencyCollection.skip(cs);
2273
}
2274

2275
bool ShardFeeCreated::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
2276
  return t_CurrencyCollection.validate_skip(ops, cs, weak) && t_CurrencyCollection.validate_skip(ops, cs, weak);
2277
}
2278

2279
bool ShardFeeCreated::null_value(vm::CellBuilder& cb) const {
2280
  return t_CurrencyCollection.null_value(cb) && t_CurrencyCollection.null_value(cb);
2281
}
2282

2283
bool ShardFeeCreated::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
2284
  return t_CurrencyCollection.add_values(cb, cs1, cs2) && t_CurrencyCollection.add_values(cb, cs1, cs2);
2285
}
2286

2287
const ShardFeeCreated t_ShardFeeCreated;
2288

2289
bool Aug_ShardFees::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
2290
  return cb.append_cellslice_bool(cs) && t_ShardFeeCreated.skip(cs) && cs.empty_ext();
2291
};
2292

2293
const Aug_ShardFees aug_ShardFees;
2294

2295
bool validate_message_libs(const td::Ref<vm::Cell> &cell) {
2296
  gen::Message::Record rec;
2297
  if (!type_unpack_cell(cell, gen::t_Message_Any, rec)) {
2298
    return false;
2299
  }
2300
  vm::CellSlice& state_init = rec.init.write();
2301
  if (!state_init.fetch_long(1)) {
2302
    return true;
2303
  }
2304
  if (state_init.fetch_long(1)) {
2305
    return gen::t_StateInitWithLibs.validate_ref(state_init.prefetch_ref());
2306
  } else {
2307
    return gen::t_StateInitWithLibs.validate_csr(rec.init);
2308
  }
2309
}
2310

2311
bool validate_message_relaxed_libs(const td::Ref<vm::Cell> &cell) {
2312
  gen::MessageRelaxed::Record rec;
2313
  if (!type_unpack_cell(cell, gen::t_MessageRelaxed_Any, rec)) {
2314
    return false;
2315
  }
2316
  vm::CellSlice& state_init = rec.init.write();
2317
  if (!state_init.fetch_long(1)) {
2318
    return true;
2319
  }
2320
  if (state_init.fetch_long(1)) {
2321
    return gen::t_StateInitWithLibs.validate_ref(state_init.prefetch_ref());
2322
  } else {
2323
    return gen::t_StateInitWithLibs.validate_csr(rec.init);
2324
  }
2325
}
2326

2327
}  // namespace tlb
2328
}  // namespace block
2329

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.