Ton

Форк
0
/
transaction.cpp 
3729 строк · 142.6 Кб
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 "block/transaction.h"
20
#include "block/block.h"
21
#include "block/block-parse.h"
22
#include "block/block-auto.h"
23
#include "crypto/openssl/rand.hpp"
24
#include "td/utils/bits.h"
25
#include "td/utils/uint128.h"
26
#include "ton/ton-shard.h"
27
#include "vm/vm.h"
28
#include "td/utils/Timer.h"
29

30
namespace {
31
/**
32
 * Logger that stores the tail of log messages.
33
 *
34
 * @param max_size The size of the buffer. Default is 256.
35
 */
36
class StringLoggerTail : public td::LogInterface {
37
 public:
38
  explicit StringLoggerTail(size_t max_size = 256) : buf(max_size, '\0') {}
39

40
  /**
41
   * Appends a slice of data to the buffer.
42
   *
43
   * @param slice The slice of data to be appended.
44
   */
45
  void append(td::CSlice slice) override {
46
    if (slice.size() > buf.size()) {
47
      slice.remove_prefix(slice.size() - buf.size());
48
    }
49
    while (!slice.empty()) {
50
      size_t s = std::min(buf.size() - pos, slice.size());
51
      std::copy(slice.begin(), slice.begin() + s, buf.begin() + pos);
52
      pos += s;
53
      if (pos == buf.size()) {
54
        pos = 0;
55
        truncated = true;
56
      }
57
      slice.remove_prefix(s);
58
    }
59
  }
60

61
  /**
62
   * Retrieves the tail of the log.
63
   *
64
   * @returns The log as std::string.
65
   */
66
  std::string get_log() const {
67
    if (truncated) {
68
      std::string res = buf;
69
      std::rotate(res.begin(), res.begin() + pos, res.end());
70
      return res;
71
    } else {
72
      return buf.substr(0, pos);
73
    }
74
  }
75

76
 private:
77
  std::string buf;
78
  size_t pos = 0;
79
  bool truncated = false;
80
};
81
}
82

83
namespace block {
84
using td::Ref;
85

86
/**
87
 * Looks up a library among public libraries.
88
 *
89
 * @param key A constant bit pointer representing the key of the library to lookup.
90
 *
91
 * @returns A reference to the library cell if found, null otherwise.
92
 */
93
Ref<vm::Cell> ComputePhaseConfig::lookup_library(td::ConstBitPtr key) const {
94
  return libraries ? vm::lookup_library_in(key, libraries->get_root_cell()) : Ref<vm::Cell>{};
95
}
96

97
/*
98
 * 
99
 *   ACCOUNTS
100
 * 
101
 */
102

103
/**
104
 * Sets the address of the account.
105
 *
106
 * @param wc The workchain ID of the account.
107
 * @param new_addr The new address of the account.
108
 *
109
 * @returns True if the address was successfully set, false otherwise.
110
 */
111
bool Account::set_address(ton::WorkchainId wc, td::ConstBitPtr new_addr) {
112
  workchain = wc;
113
  addr = new_addr;
114
  return true;
115
}
116

117
/**
118
 * Sets the split depth of the account.
119
 *
120
 * @param new_split_depth The new split depth value to be set.
121
 *
122
 * @returns True if the split depth was successfully set, False otherwise.
123
 */
124
bool Account::set_split_depth(int new_split_depth) {
125
  if (new_split_depth < 0 || new_split_depth > 30) {
126
    return false;  // invalid value for split_depth
127
  }
128
  if (split_depth_set_) {
129
    return split_depth_ == new_split_depth;
130
  } else {
131
    split_depth_ = (unsigned char)new_split_depth;
132
    split_depth_set_ = true;
133
    return true;
134
  }
135
}
136

137
/**
138
 * Checks if the given split depth is valid for the Account.
139
 *
140
 * @param split_depth The split depth to be checked.
141
 *
142
 * @returns True if the split depth is valid, False otherwise.
143
 */
144
bool Account::check_split_depth(int split_depth) const {
145
  return split_depth_set_ ? (split_depth == split_depth_) : (split_depth >= 0 && split_depth <= 30);
146
}
147

148
/**
149
 * Parses anycast data of the account address.
150
 * 
151
 * Initializes split_depth and addr_rewrite.
152
 *
153
 * @param cs The cell slice containing partially-parsed account addressa.
154
 *
155
 * @returns True if parsing was successful, false otherwise.
156
 */
157
bool Account::parse_maybe_anycast(vm::CellSlice& cs) {
158
  int t = (int)cs.fetch_ulong(1);
159
  if (t < 0) {
160
    return false;
161
  } else if (!t) {
162
    return set_split_depth(0);
163
  }
164
  int depth;
165
  return cs.fetch_uint_leq(30, depth)                     // anycast_info$_ depth:(#<= 30)
166
         && depth                                         // { depth >= 1 }
167
         && cs.fetch_bits_to(addr_rewrite.bits(), depth)  // rewrite_pfx:(bits depth)
168
         && set_split_depth(depth);
169
}
170

171
/**
172
 * Stores the anycast information to a serialized account address.
173
 *
174
 * @param cb The vm::CellBuilder object to store the information in.
175
 *
176
 * @returns True if the anycast information was successfully stored, false otherwise.
177
 */
178
bool Account::store_maybe_anycast(vm::CellBuilder& cb) const {
179
  if (!split_depth_set_ || !split_depth_) {
180
    return cb.store_bool_bool(false);
181
  }
182
  return cb.store_bool_bool(true)                                    // just$1
183
         && cb.store_uint_leq(30, split_depth_)                      // depth:(#<= 30)
184
         && cb.store_bits_bool(addr_rewrite.cbits(), split_depth_);  // rewrite_pfx:(bits depth)
185
}
186

187
/**
188
 * Unpacks the address from a given CellSlice.
189
 *
190
 * @param addr_cs The CellSlice containing the address.
191
 *
192
 * @returns True if the address was successfully unpacked, False otherwise.
193
 */
194
bool Account::unpack_address(vm::CellSlice& addr_cs) {
195
  int addr_tag = block::gen::t_MsgAddressInt.get_tag(addr_cs);
196
  int new_wc = ton::workchainInvalid;
197
  switch (addr_tag) {
198
    case block::gen::MsgAddressInt::addr_std:
199
      if (!(addr_cs.advance(2) && parse_maybe_anycast(addr_cs) && addr_cs.fetch_int_to(8, new_wc) &&
200
            addr_cs.fetch_bits_to(addr_orig.bits(), 256) && addr_cs.empty_ext())) {
201
        return false;
202
      }
203
      break;
204
    case block::gen::MsgAddressInt::addr_var:
205
      // cannot appear in masterchain / basechain
206
      return false;
207
    default:
208
      return false;
209
  }
210
  addr_cs.clear();
211
  if (new_wc == ton::workchainInvalid) {
212
    return false;
213
  }
214
  if (workchain == ton::workchainInvalid) {
215
    workchain = new_wc;
216
    addr = addr_orig;
217
    addr.bits().copy_from(addr_rewrite.cbits(), split_depth_);
218
  } else if (split_depth_) {
219
    ton::StdSmcAddress new_addr = addr_orig;
220
    new_addr.bits().copy_from(addr_rewrite.cbits(), split_depth_);
221
    if (new_addr != addr) {
222
      LOG(ERROR) << "error unpacking account " << workchain << ":" << addr.to_hex()
223
                 << " : account header contains different address " << new_addr.to_hex() << " (with splitting depth "
224
                 << (int)split_depth_ << ")";
225
      return false;
226
    }
227
  } else if (addr != addr_orig) {
228
    LOG(ERROR) << "error unpacking account " << workchain << ":" << addr.to_hex()
229
               << " : account header contains different address " << addr_orig.to_hex();
230
    return false;
231
  }
232
  if (workchain != new_wc) {
233
    LOG(ERROR) << "error unpacking account " << workchain << ":" << addr.to_hex()
234
               << " : account header contains different workchain " << new_wc;
235
    return false;
236
  }
237
  addr_rewrite = addr.bits();  // initialize all 32 bits of addr_rewrite
238
  if (!split_depth_) {
239
    my_addr_exact = my_addr;
240
  }
241
  return true;
242
}
243

244
/**
245
 * Unpacks storage information from a CellSlice.
246
 * 
247
 * Storage information is serialized using StorageInfo TLB-scheme.
248
 *
249
 * @param cs The CellSlice containing the storage information.
250
 *
251
 * @returns True if the unpacking is successful, false otherwise.
252
 */
253
bool Account::unpack_storage_info(vm::CellSlice& cs) {
254
  block::gen::StorageInfo::Record info;
255
  block::gen::StorageUsed::Record used;
256
  if (!tlb::unpack_exact(cs, info) || !tlb::csr_unpack(info.used, used)) {
257
    return false;
258
  }
259
  last_paid = info.last_paid;
260
  if (info.due_payment->prefetch_ulong(1) == 1) {
261
    vm::CellSlice& cs2 = info.due_payment.write();
262
    cs2.advance(1);
263
    due_payment = block::tlb::t_Grams.as_integer_skip(cs2);
264
    if (due_payment.is_null() || !cs2.empty_ext()) {
265
      return false;
266
    }
267
  } else {
268
    due_payment = td::zero_refint();
269
  }
270
  unsigned long long u = 0;
271
  u |= storage_stat.cells = block::tlb::t_VarUInteger_7.as_uint(*used.cells);
272
  u |= storage_stat.bits = block::tlb::t_VarUInteger_7.as_uint(*used.bits);
273
  u |= storage_stat.public_cells = block::tlb::t_VarUInteger_7.as_uint(*used.public_cells);
274
  LOG(DEBUG) << "last_paid=" << last_paid << "; cells=" << storage_stat.cells << " bits=" << storage_stat.bits
275
             << " public_cells=" << storage_stat.public_cells;
276
  return (u != std::numeric_limits<td::uint64>::max());
277
}
278

279
/**
280
 * Unpacks the state of an Account from a CellSlice.
281
 *
282
 * State is serialized using StateInit TLB-scheme.
283
 * Initializes split_depth (from account state - StateInit)
284
 *
285
 * @param cs The CellSlice containing the serialized state.
286
 *
287
 * @returns True if the state was successfully unpacked, False otherwise.
288
 */
289
bool Account::unpack_state(vm::CellSlice& cs) {
290
  block::gen::StateInit::Record state;
291
  if (!tlb::unpack_exact(cs, state)) {
292
    return false;
293
  }
294
  int sd = 0;
295
  if (state.split_depth->size() == 6) {
296
    sd = (int)state.split_depth->prefetch_ulong(6) - 32;
297
  }
298
  if (!set_split_depth(sd)) {
299
    return false;
300
  }
301
  if (state.special->size() > 1) {
302
    int z = (int)state.special->prefetch_ulong(3);
303
    if (z < 0) {
304
      return false;
305
    }
306
    tick = z & 2;
307
    tock = z & 1;
308
    LOG(DEBUG) << "tick=" << tick << ", tock=" << tock;
309
  }
310
  code = state.code->prefetch_ref();
311
  data = state.data->prefetch_ref();
312
  library = orig_library = state.library->prefetch_ref();
313
  return true;
314
}
315

316
/**
317
 * Computes the address of the account.
318
 *
319
 * @param force If set to true, the address will be recomputed even if it already exists.
320
 *
321
 * @returns True if the address was successfully computed, false otherwise.
322
 */
323
bool Account::compute_my_addr(bool force) {
324
  if (!force && my_addr.not_null() && my_addr_exact.not_null()) {
325
    return true;
326
  }
327
  if (workchain == ton::workchainInvalid) {
328
    my_addr.clear();
329
    return false;
330
  }
331
  vm::CellBuilder cb;
332
  Ref<vm::Cell> cell, cell2;
333
  if (workchain >= -128 && workchain < 127) {
334
    if (!(cb.store_long_bool(2, 2)                             // addr_std$10
335
          && store_maybe_anycast(cb)                           // anycast:(Maybe Anycast)
336
          && cb.store_long_rchk_bool(workchain, 8)             // workchain_id:int8
337
          && cb.store_bits_bool(addr_orig)                     // addr:bits256
338
          && cb.finalize_to(cell) && cb.store_long_bool(4, 3)  // addr_std$10 anycast:(Maybe Anycast)
339
          && cb.store_long_rchk_bool(workchain, 8)             // workchain_id:int8
340
          && cb.store_bits_bool(addr)                          // addr:bits256
341
          && cb.finalize_to(cell2))) {
342
      return false;
343
    }
344
  } else {
345
    if (!(cb.store_long_bool(3, 2)                             // addr_var$11
346
          && store_maybe_anycast(cb)                           // anycast:(Maybe Anycast)
347
          && cb.store_long_bool(256, 9)                        // addr_len:(## 9)
348
          && cb.store_long_rchk_bool(workchain, 32)            // workchain_id:int32
349
          && cb.store_bits_bool(addr_orig)                     // addr:(bits addr_len)
350
          && cb.finalize_to(cell) && cb.store_long_bool(6, 3)  // addr_var$11 anycast:(Maybe Anycast)
351
          && cb.store_long_bool(256, 9)                        // addr_len:(## 9)
352
          && cb.store_long_rchk_bool(workchain, 32)            // workchain_id:int32
353
          && cb.store_bits_bool(addr)                          // addr:(bits addr_len)
354
          && cb.finalize_to(cell2))) {
355
      return false;
356
    }
357
  }
358
  my_addr = load_cell_slice_ref(std::move(cell));
359
  my_addr_exact = load_cell_slice_ref(std::move(cell2));
360
  return true;
361
}
362

363
/**
364
 * Computes the address of the Account.
365
 *
366
 * @param tmp_addr A reference to the CellSlice for the result.
367
 * @param split_depth The split depth for the address.
368
 * @param orig_addr_rewrite Address prefox of length split_depth.
369
 *
370
 * @returns True if the address was successfully computed, false otherwise.
371
 */
372
bool Account::recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int split_depth,
373
                                 td::ConstBitPtr orig_addr_rewrite) const {
374
  if (!split_depth && my_addr_exact.not_null()) {
375
    tmp_addr = my_addr_exact;
376
    return true;
377
  }
378
  if (split_depth == split_depth_ && my_addr.not_null()) {
379
    tmp_addr = my_addr;
380
    return true;
381
  }
382
  if (split_depth < 0 || split_depth > 30) {
383
    return false;
384
  }
385
  vm::CellBuilder cb;
386
  bool std = (workchain >= -128 && workchain < 128);
387
  if (!cb.store_long_bool(std ? 2 : 3, 2)) {  // addr_std$10 or addr_var$11
388
    return false;
389
  }
390
  if (!split_depth) {
391
    if (!cb.store_bool_bool(false)) {  // anycast:(Maybe Anycast)
392
      return false;
393
    }
394
  } else if (!(cb.store_bool_bool(true)                             // just$1
395
               && cb.store_long_bool(split_depth, 5)                // depth:(#<= 30)
396
               && cb.store_bits_bool(addr.bits(), split_depth))) {  // rewrite_pfx:(bits depth)
397
    return false;
398
  }
399
  if (std) {
400
    if (!cb.store_long_rchk_bool(workchain, 8)) {  // workchain:int8
401
      return false;
402
    }
403
  } else if (!(cb.store_long_bool(256, 9)                // addr_len:(## 9)
404
               && cb.store_long_bool(workchain, 32))) {  // workchain:int32
405
    return false;
406
  }
407
  Ref<vm::Cell> cell;
408
  return cb.store_bits_bool(orig_addr_rewrite, split_depth)  // address:(bits addr_len) or bits256
409
         && cb.store_bits_bool(addr.bits() + split_depth, 256 - split_depth) && cb.finalize_to(cell) &&
410
         (tmp_addr = vm::load_cell_slice_ref(std::move(cell))).not_null();
411
}
412

413
/**
414
 * Sets address rewriting info for a newly-activated account.
415
 *
416
 * @param split_depth The split depth for the account address.
417
 * @param orig_addr_rewrite Address frepix of length split_depth.
418
 *
419
 * @returns True if the rewriting info was successfully set, false otherwise.
420
 */
421
bool Account::init_rewrite_addr(int split_depth, td::ConstBitPtr orig_addr_rewrite) {
422
  if (split_depth_set_ || !set_split_depth(split_depth)) {
423
    return false;
424
  }
425
  addr_orig = addr;
426
  addr_rewrite = addr.bits();
427
  addr_orig.bits().copy_from(orig_addr_rewrite, split_depth);
428
  return compute_my_addr(true);
429
}
430

431
/**
432
 * Unpacks the account information from the provided CellSlice.
433
 * 
434
 * Used to unpack previously existing accounts.
435
 *
436
 * @param shard_account The ShardAccount to unpack.
437
 * @param now The current Unix time.
438
 * @param special Flag indicating if the account is special.
439
 *
440
 * @returns True if the unpacking is successful, false otherwise.
441
 */
442
bool Account::unpack(Ref<vm::CellSlice> shard_account, ton::UnixTime now, bool special) {
443
  LOG(DEBUG) << "unpacking " << (special ? "special " : "") << "account " << addr.to_hex();
444
  if (shard_account.is_null()) {
445
    LOG(ERROR) << "account " << addr.to_hex() << " does not have a valid ShardAccount to unpack";
446
    return false;
447
  }
448
  if (verbosity > 2) {
449
    shard_account->print_rec(std::cerr, 2);
450
    block::gen::t_ShardAccount.print(std::cerr, *shard_account);
451
  }
452
  block::gen::ShardAccount::Record acc_info;
453
  if (!(block::tlb::t_ShardAccount.validate_csr(shard_account) && tlb::unpack_exact(shard_account.write(), acc_info))) {
454
    LOG(ERROR) << "account " << addr.to_hex() << " state is invalid";
455
    return false;
456
  }
457
  last_trans_lt_ = acc_info.last_trans_lt;
458
  last_trans_hash_ = acc_info.last_trans_hash;
459
  now_ = now;
460
  auto account = std::move(acc_info.account);
461
  total_state = orig_total_state = account;
462
  auto acc_cs = load_cell_slice(std::move(account));
463
  if (block::gen::t_Account.get_tag(acc_cs) == block::gen::Account::account_none) {
464
    is_special = special;
465
    return acc_cs.size_ext() == 1 && init_new(now);
466
  }
467
  block::gen::Account::Record_account acc;
468
  block::gen::AccountStorage::Record storage;
469
  if (!(tlb::unpack_exact(acc_cs, acc) && (my_addr = acc.addr).not_null() && unpack_address(acc.addr.write()) &&
470
        compute_my_addr() && unpack_storage_info(acc.storage_stat.write()) &&
471
        tlb::csr_unpack(this->storage = std::move(acc.storage), storage) &&
472
        std::max(storage.last_trans_lt, 1ULL) > acc_info.last_trans_lt && balance.unpack(std::move(storage.balance)))) {
473
    return false;
474
  }
475
  is_special = special;
476
  last_trans_end_lt_ = storage.last_trans_lt;
477
  switch (block::gen::t_AccountState.get_tag(*storage.state)) {
478
    case block::gen::AccountState::account_uninit:
479
      status = orig_status = acc_uninit;
480
      state_hash = addr;
481
      forget_split_depth();
482
      break;
483
    case block::gen::AccountState::account_frozen:
484
      status = orig_status = acc_frozen;
485
      if (!storage.state->have(2 + 256)) {
486
        return false;
487
      }
488
      state_hash = storage.state->data_bits() + 2;
489
      break;
490
    case block::gen::AccountState::account_active:
491
      status = orig_status = acc_active;
492
      if (storage.state.write().fetch_ulong(1) != 1) {
493
        return false;
494
      }
495
      inner_state = storage.state;
496
      if (!unpack_state(storage.state.write())) {
497
        return false;
498
      }
499
      state_hash.clear();
500
      break;
501
    default:
502
      return false;
503
  }
504
  LOG(DEBUG) << "end of Account.unpack() for " << workchain << ":" << addr.to_hex()
505
             << " (balance = " << balance.to_str() << " ; last_trans_lt = " << last_trans_lt_ << ".."
506
             << last_trans_end_lt_ << ")";
507
  return true;
508
}
509

510
/**
511
 * Initializes a new Account object.
512
 *
513
 * @param now The current Unix time.
514
 *
515
 * @returns True if the initialization is successful, false otherwise.
516
 */
517
bool Account::init_new(ton::UnixTime now) {
518
  // only workchain and addr are initialized at this point
519
  if (workchain == ton::workchainInvalid) {
520
    return false;
521
  }
522
  addr_orig = addr;
523
  addr_rewrite = addr.cbits();
524
  last_trans_lt_ = last_trans_end_lt_ = 0;
525
  last_trans_hash_.set_zero();
526
  now_ = now;
527
  last_paid = 0;
528
  storage_stat.clear();
529
  due_payment = td::zero_refint();
530
  balance.set_zero();
531
  if (my_addr_exact.is_null()) {
532
    vm::CellBuilder cb;
533
    if (workchain >= -128 && workchain < 128) {
534
      CHECK(cb.store_long_bool(4, 3)                  // addr_std$10 anycast:(Maybe Anycast)
535
            && cb.store_long_rchk_bool(workchain, 8)  // workchain:int8
536
            && cb.store_bits_bool(addr));             // address:bits256
537
    } else {
538
      CHECK(cb.store_long_bool(0xd00, 12)              // addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
539
            && cb.store_long_rchk_bool(workchain, 32)  // workchain:int32
540
            && cb.store_bits_bool(addr));              // address:(bits addr_len)
541
    }
542
    my_addr_exact = load_cell_slice_ref(cb.finalize());
543
  }
544
  if (my_addr.is_null()) {
545
    my_addr = my_addr_exact;
546
  }
547
  if (total_state.is_null()) {
548
    vm::CellBuilder cb;
549
    CHECK(cb.store_long_bool(0, 1)  // account_none$0 = Account
550
          && cb.finalize_to(total_state));
551
    orig_total_state = total_state;
552
  }
553
  state_hash = addr_orig;
554
  status = orig_status = acc_nonexist;
555
  split_depth_set_ = false;
556
  return true;
557
}
558

559
/**
560
 * Resets the split depth of the account.
561
 *
562
 * @returns True if the split depth was successfully reset, false otherwise.
563
 */
564
bool Account::forget_split_depth() {
565
  split_depth_set_ = false;
566
  split_depth_ = 0;
567
  addr_orig = addr;
568
  my_addr = my_addr_exact;
569
  addr_rewrite = addr.bits();
570
  return true;
571
}
572

573
/**
574
 * Deactivates the account.
575
 *
576
 * @returns True if the account was successfully deactivated, false otherwise.
577
 */
578
bool Account::deactivate() {
579
  if (status == acc_active) {
580
    return false;
581
  }
582
  // forget special (tick/tock) info
583
  tick = tock = false;
584
  if (status == acc_nonexist || status == acc_uninit) {
585
    // forget split depth and address rewriting info
586
    forget_split_depth();
587
    // forget specific state hash for deleted or uninitialized accounts (revert to addr)
588
    state_hash = addr;
589
  }
590
  // forget code and data (only active accounts remember these)
591
  code.clear();
592
  data.clear();
593
  library.clear();
594
  // if deleted, balance must be zero
595
  if (status == acc_nonexist && !balance.is_zero()) {
596
    return false;
597
  }
598
  return true;
599
}
600

601
/**
602
 * Checks if the account belongs to a specific shard.
603
 *
604
 * @param shard The shard to check against.
605
 *
606
 * @returns True if the account belongs to the shard, False otherwise.
607
 */
608
bool Account::belongs_to_shard(ton::ShardIdFull shard) const {
609
  return workchain == shard.workchain && ton::shard_is_ancestor(shard.shard, addr);
610
}
611

612
/**
613
 * Adds the partial storage payment to the total sum.
614
 *
615
 * @param payment The total sum to be updated.
616
 * @param delta The time delta for which the payment is calculated.
617
 * @param prices The storage prices.
618
 * @param storage Account storage statistics.
619
 * @param is_mc A flag indicating whether the account is in the masterchain.
620
 */
621
void add_partial_storage_payment(td::BigInt256& payment, ton::UnixTime delta, const block::StoragePrices& prices,
622
                                 const vm::CellStorageStat& storage, bool is_mc) {
623
  td::BigInt256 c{(long long)storage.cells}, b{(long long)storage.bits};
624
  if (is_mc) {
625
    // storage.cells * prices.mc_cell_price + storage.bits * prices.mc_bit_price;
626
    c.mul_short(prices.mc_cell_price);
627
    b.mul_short(prices.mc_bit_price);
628
  } else {
629
    // storage.cells * prices.cell_price + storage.bits * prices.bit_price;
630
    c.mul_short(prices.cell_price);
631
    b.mul_short(prices.bit_price);
632
  }
633
  b += c;
634
  b.mul_short(delta).normalize();
635
  CHECK(b.sgn() >= 0);
636
  payment += b;
637
}
638

639
/**
640
 * Computes the storage fees based on the given parameters.
641
 *
642
 * @param now The current Unix time.
643
 * @param pricing The vector of storage prices.
644
 * @param storage_stat Account storage statistics.
645
 * @param last_paid The Unix time when the last payment was made.
646
 * @param is_special A flag indicating if the account is special.
647
 * @param is_masterchain A flag indicating if the account is in the masterchain.
648
 *
649
 * @returns The computed storage fees as RefInt256.
650
 */
651
td::RefInt256 StoragePrices::compute_storage_fees(ton::UnixTime now, const std::vector<block::StoragePrices>& pricing,
652
                                                  const vm::CellStorageStat& storage_stat, ton::UnixTime last_paid,
653
                                                  bool is_special, bool is_masterchain) {
654
  if (now <= last_paid || !last_paid || is_special || pricing.empty() || now <= pricing[0].valid_since) {
655
    return td::zero_refint();
656
  }
657
  std::size_t n = pricing.size(), i = n;
658
  while (i && pricing[i - 1].valid_since > last_paid) {
659
    --i;
660
  }
661
  if (i) {
662
    --i;
663
  }
664
  ton::UnixTime upto = std::max(last_paid, pricing[0].valid_since);
665
  td::RefInt256 total{true, 0};
666
  for (; i < n && upto < now; i++) {
667
    ton::UnixTime valid_until = (i < n - 1 ? std::min(now, pricing[i + 1].valid_since) : now);
668
    if (upto < valid_until) {
669
      assert(upto >= pricing[i].valid_since);
670
      add_partial_storage_payment(total.unique_write(), valid_until - upto, pricing[i], storage_stat, is_masterchain);
671
    }
672
    upto = valid_until;
673
  }
674
  return td::rshift(total, 16, 1);  // divide by 2^16 with ceil rounding to obtain nanograms
675
}
676

677
/**
678
 * Computes the storage fees for the account.
679
 *
680
 * @param now The current Unix time.
681
 * @param pricing The vector of storage prices.
682
 *
683
 * @returns The computed storage fees as RefInt256.
684
 */
685
td::RefInt256 Account::compute_storage_fees(ton::UnixTime now, const std::vector<block::StoragePrices>& pricing) const {
686
  return StoragePrices::compute_storage_fees(now, pricing, storage_stat, last_paid, is_special, is_masterchain());
687
}
688

689
namespace transaction {
690
/**
691
 * Constructs a new Transaction object.
692
 *
693
 * @param _account The Account object.
694
 * @param ttype The type of the transaction (see transaction.cpp#309).
695
 * @param req_start_lt The minimal logical time of the transaction.
696
 * @param _now The current Unix time.
697
 * @param _inmsg The input message that caused the transaction.
698
 *
699
 * @returns None
700
 */
701
Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now,
702
                         Ref<vm::Cell> _inmsg)
703
    : trans_type(ttype)
704
    , is_first(_account.transactions.empty())
705
    , new_tick(_account.tick)
706
    , new_tock(_account.tock)
707
    , now(_now)
708
    , account(_account)
709
    , my_addr(_account.my_addr)
710
    , my_addr_exact(_account.my_addr_exact)
711
    , balance(_account.balance)
712
    , original_balance(_account.balance)
713
    , due_payment(_account.due_payment)
714
    , last_paid(_account.last_paid)
715
    , new_code(_account.code)
716
    , new_data(_account.data)
717
    , new_library(_account.library)
718
    , in_msg(std::move(_inmsg)) {
719
  start_lt = std::max(req_start_lt, account.last_trans_end_lt_);
720
  end_lt = start_lt + 1;
721
  acc_status = (account.status == Account::acc_nonexist ? Account::acc_uninit : account.status);
722
  if (acc_status == Account::acc_frozen) {
723
    frozen_hash = account.state_hash;
724
  }
725
}
726

727
/**
728
 * Unpacks the input message of a transaction.
729
 *
730
 * @param ihr_delivered A boolean indicating whether the message was delivered using IHR (Instant Hypercube Routing).
731
 * @param cfg Action phase configuration.
732
 *
733
 * @returns A boolean indicating whether the unpacking was successful.
734
 */
735
bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg) {
736
  if (in_msg.is_null() || in_msg_type) {
737
    return false;
738
  }
739
  if (verbosity > 2) {
740
    fprintf(stderr, "unpacking inbound message for a new transaction: ");
741
    block::gen::t_Message_Any.print_ref(std::cerr, in_msg);
742
    load_cell_slice(in_msg).print_rec(std::cerr);
743
  }
744
  auto cs = vm::load_cell_slice(in_msg);
745
  int tag = block::gen::t_CommonMsgInfo.get_tag(cs);
746
  Ref<vm::CellSlice> src_addr, dest_addr;
747
  switch (tag) {
748
    case block::gen::CommonMsgInfo::int_msg_info: {
749
      block::gen::CommonMsgInfo::Record_int_msg_info info;
750
      if (!(tlb::unpack(cs, info) && msg_balance_remaining.unpack(std::move(info.value)))) {
751
        return false;
752
      }
753
      if (info.ihr_disabled && ihr_delivered) {
754
        return false;
755
      }
756
      bounce_enabled = info.bounce;
757
      src_addr = std::move(info.src);
758
      dest_addr = std::move(info.dest);
759
      in_msg_type = 1;
760
      td::RefInt256 ihr_fee = block::tlb::t_Grams.as_integer(std::move(info.ihr_fee));
761
      if (ihr_delivered) {
762
        in_fwd_fee = std::move(ihr_fee);
763
      } else {
764
        in_fwd_fee = td::zero_refint();
765
        msg_balance_remaining += std::move(ihr_fee);
766
      }
767
      if (info.created_lt >= start_lt) {
768
        start_lt = info.created_lt + 1;
769
        end_lt = start_lt + 1;
770
      }
771
      // ...
772
      break;
773
    }
774
    case block::gen::CommonMsgInfo::ext_in_msg_info: {
775
      block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
776
      if (!tlb::unpack(cs, info)) {
777
        return false;
778
      }
779
      src_addr = std::move(info.src);
780
      dest_addr = std::move(info.dest);
781
      in_msg_type = 2;
782
      in_msg_extern = true;
783
      // compute forwarding fees for this external message
784
      vm::CellStorageStat sstat;                                     // for message size
785
      auto cell_info = sstat.compute_used_storage(cs).move_as_ok();  // message body
786
      sstat.bits -= cs.size();                                       // bits in the root cells are free
787
      sstat.cells--;                                                 // the root cell itself is not counted as a cell
788
      LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
789
      if (sstat.bits > cfg->size_limits.max_msg_bits || sstat.cells > cfg->size_limits.max_msg_cells) {
790
        LOG(DEBUG) << "inbound external message too large, invalid";
791
        return false;
792
      }
793
      if (cell_info.max_merkle_depth > max_allowed_merkle_depth) {
794
        LOG(DEBUG) << "inbound external message has too big merkle depth, invalid";
795
        return false;
796
      }
797
      // fetch message pricing info
798
      CHECK(cfg);
799
      const MsgPrices& msg_prices = cfg->fetch_msg_prices(account.is_masterchain());
800
      // compute forwarding fees
801
      auto fees_c = msg_prices.compute_fwd_ihr_fees(sstat.cells, sstat.bits, true);
802
      LOG(DEBUG) << "computed fwd fees = " << fees_c.first << " + " << fees_c.second;
803

804
      if (account.is_special) {
805
        LOG(DEBUG) << "computed fwd fees set to zero for special account";
806
        fees_c.first = fees_c.second = 0;
807
      }
808
      in_fwd_fee = td::make_refint(fees_c.first);
809
      if (balance.grams < in_fwd_fee) {
810
        LOG(DEBUG) << "cannot pay for importing this external message";
811
        return false;
812
      }
813
      // (tentatively) debit account for importing this external message
814
      balance -= in_fwd_fee;
815
      msg_balance_remaining.set_zero();  // external messages cannot carry value
816
      // ...
817
      break;
818
    }
819
    default:
820
      return false;
821
  }
822
  // init:(Maybe (Either StateInit ^StateInit))
823
  switch ((int)cs.prefetch_ulong(2)) {
824
    case 2: {  // (just$1 (left$0 _:StateInit ))
825
      Ref<vm::CellSlice> state_init;
826
      vm::CellBuilder cb;
827
      if (!(cs.advance(2) && block::gen::t_StateInit.fetch_to(cs, state_init) &&
828
            cb.append_cellslice_bool(std::move(state_init)) && cb.finalize_to(in_msg_state) &&
829
            block::gen::t_StateInitWithLibs.validate_ref(in_msg_state))) {
830
        LOG(DEBUG) << "cannot parse StateInit in inbound message";
831
        return false;
832
      }
833
      break;
834
    }
835
    case 3: {  // (just$1 (right$1 _:^StateInit ))
836
      if (!(cs.advance(2) && cs.fetch_ref_to(in_msg_state) &&
837
            block::gen::t_StateInitWithLibs.validate_ref(in_msg_state))) {
838
        LOG(DEBUG) << "cannot parse ^StateInit in inbound message";
839
        return false;
840
      }
841
      break;
842
    }
843
    default:  // nothing$0
844
      if (!cs.advance(1)) {
845
        LOG(DEBUG) << "invalid init field in an inbound message";
846
        return false;
847
      }
848
  }
849
  // body:(Either X ^X)
850
  switch ((int)cs.fetch_ulong(1)) {
851
    case 0:  // left$0 _:X
852
      in_msg_body = Ref<vm::CellSlice>{true, cs};
853
      break;
854
    case 1:  // right$1 _:^X
855
      if (cs.size_ext() != 0x10000) {
856
        LOG(DEBUG) << "body of an inbound message is not represented by exactly one reference";
857
        return false;
858
      }
859
      in_msg_body = load_cell_slice_ref(cs.prefetch_ref());
860
      break;
861
    default:
862
      LOG(DEBUG) << "invalid body field in an inbound message";
863
      return false;
864
  }
865
  total_fees += in_fwd_fee;
866
  if (account.workchain == ton::masterchainId && cfg->mc_blackhole_addr &&
867
      cfg->mc_blackhole_addr.value() == account.addr) {
868
    blackhole_burned.grams = msg_balance_remaining.grams;
869
    msg_balance_remaining.grams = td::zero_refint();
870
    LOG(DEBUG) << "Burning " << blackhole_burned.grams << " nanoton (blackhole address)";
871
  }
872
  return true;
873
}
874

875
/**
876
 * Prepares the storage phase of a transaction.
877
 *
878
 * @param cfg The configuration for the storage phase.
879
 * @param force_collect Flag indicating whether to collect fees for frozen accounts.
880
 * @param adjust_msg_value Flag indicating whether to adjust the message value if the account balance becomes less than the message balance.
881
 *
882
 * @returns True if the storage phase was successfully prepared, false otherwise.
883
 */
884
bool Transaction::prepare_storage_phase(const StoragePhaseConfig& cfg, bool force_collect, bool adjust_msg_value) {
885
  if (now < account.last_paid) {
886
    return false;
887
  }
888
  auto to_pay = account.compute_storage_fees(now, *(cfg.pricing)) + due_payment;
889
  if (to_pay.not_null() && sgn(to_pay) < 0) {
890
    return false;
891
  }
892
  auto res = std::make_unique<StoragePhase>();
893
  res->is_special = account.is_special;
894
  last_paid = res->last_paid_updated = (res->is_special ? 0 : now);
895
  if (to_pay.is_null() || sgn(to_pay) == 0) {
896
    res->fees_collected = res->fees_due = td::zero_refint();
897
  } else if (to_pay <= balance.grams) {
898
    res->fees_collected = to_pay;
899
    res->fees_due = td::zero_refint();
900
    balance -= std::move(to_pay);
901
    if (cfg.global_version >= 7) {
902
      due_payment = td::zero_refint();
903
    }
904
  } else if (acc_status == Account::acc_frozen && !force_collect && to_pay < cfg.delete_due_limit) {
905
    // do not collect fee
906
    res->last_paid_updated = (res->is_special ? 0 : account.last_paid);
907
    res->fees_collected = res->fees_due = td::zero_refint();
908
  } else {
909
    res->fees_collected = balance.grams;
910
    res->fees_due = std::move(to_pay) - std::move(balance.grams);
911
    balance.grams = td::zero_refint();
912
    if (!res->is_special) {
913
      auto total_due = res->fees_due;
914
      switch (acc_status) {
915
        case Account::acc_uninit:
916
        case Account::acc_frozen:
917
          if (total_due > cfg.delete_due_limit && balance.extra.is_null()) {
918
            // Keeping accounts with non-null extras is a temporary measure before implementing proper collection of
919
            // extracurrencies from deleted accounts
920
            res->deleted = true;
921
            acc_status = Account::acc_deleted;
922
            if (balance.extra.not_null()) {
923
              // collect extra currencies as a fee
924
              total_fees += block::CurrencyCollection{0, std::move(balance.extra)};
925
              balance.extra.clear();
926
            }
927
          }
928
          break;
929
        case Account::acc_active:
930
          if (total_due > cfg.freeze_due_limit) {
931
            res->frozen = true;
932
            was_frozen = true;
933
            acc_status = Account::acc_frozen;
934
          }
935
          break;
936
      }
937
      if (cfg.enable_due_payment) {
938
        due_payment = total_due;
939
      }
940
    }
941
  }
942
  if (adjust_msg_value && msg_balance_remaining.grams > balance.grams) {
943
    msg_balance_remaining.grams = balance.grams;
944
  }
945
  total_fees += res->fees_collected;
946
  storage_phase = std::move(res);
947
  return true;
948
}
949

950
/**
951
 * Prepares the credit phase of a transaction.
952
 *
953
 * This function creates a CreditPhase object and performs the necessary calculations
954
 * to determine the amount to be credited in the credit phase. It updates the due payment,
955
 * credit, balance, and total fees accordingly.
956
 *
957
 * @returns True if the credit phase is prepared successfully, false otherwise.
958
 */
959
bool Transaction::prepare_credit_phase() {
960
  credit_phase = std::make_unique<CreditPhase>();
961
  // Due payment is only collected in storage phase.
962
  // For messages with bounce flag, contract always receives the amount specified in message
963
  // auto collected = std::min(msg_balance_remaining.grams, due_payment);
964
  // credit_phase->due_fees_collected = collected;
965
  // due_payment -= collected;
966
  // credit_phase->credit = msg_balance_remaining -= collected;
967
  credit_phase->due_fees_collected = td::zero_refint();
968
  credit_phase->credit = msg_balance_remaining;
969
  if (!msg_balance_remaining.is_valid()) {
970
    LOG(ERROR) << "cannot compute the amount to be credited in the credit phase of transaction";
971
    return false;
972
  }
973
  // NB: msg_balance_remaining may be deducted from balance later during bounce phase
974
  balance += msg_balance_remaining;
975
  if (!balance.is_valid()) {
976
    LOG(ERROR) << "cannot credit currency collection to account";
977
    return false;
978
  }
979
  // total_fees += std::move(collected);
980
  return true;
981
}
982
}  // namespace transaction
983

984
/**
985
 * Parses the gas limits and prices from a given cell.
986
 *
987
 * @param cell The cell containing the gas limits and prices serialized using GasLimitsPricing TLB-scheme.
988
 * @param freeze_due_limit Reference to store the freeze due limit.
989
 * @param delete_due_limit Reference to store the delete due limit.
990
 *
991
 * @returns True if the parsing is successful, false otherwise.
992
 */
993
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit,
994
                                               td::RefInt256& delete_due_limit) {
995
  return cell.not_null() &&
996
         parse_GasLimitsPrices(vm::load_cell_slice_ref(std::move(cell)), freeze_due_limit, delete_due_limit);
997
}
998

999
/**
1000
 * Parses the gas limits and prices from a given cell slice.
1001
 *
1002
 * @param cs The cell slice containing the gas limits and prices serialized using GasLimitsPricing TLB-scheme.
1003
 * @param freeze_due_limit Reference to store the freeze due limit.
1004
 * @param delete_due_limit Reference to store the delete due limit.
1005
 *
1006
 * @returns True if the parsing is successful, false otherwise.
1007
 */
1008
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit,
1009
                                               td::RefInt256& delete_due_limit) {
1010
  if (cs.is_null()) {
1011
    return false;
1012
  }
1013
  block::gen::GasLimitsPrices::Record_gas_flat_pfx flat;
1014
  if (tlb::csr_unpack(cs, flat)) {
1015
    return parse_GasLimitsPrices_internal(std::move(flat.other), freeze_due_limit, delete_due_limit,
1016
                                          flat.flat_gas_limit, flat.flat_gas_price);
1017
  } else {
1018
    return parse_GasLimitsPrices_internal(std::move(cs), freeze_due_limit, delete_due_limit);
1019
  }
1020
}
1021

1022
/**
1023
 * Parses the gas limits and prices from a gas limits and prices record.
1024
 *
1025
 * @param cs The cell slice containing the gas limits and prices serialized using GasLimitsPricing TLB-scheme.
1026
 * @param freeze_due_limit A reference to store the freeze due limit.
1027
 * @param delete_due_limit A reference to store the delete due limit.
1028
 * @param _flat_gas_limit The flat gas limit.
1029
 * @param _flat_gas_price The flat gas price.
1030
 *
1031
 * @returns True if the parsing is successful, false otherwise.
1032
 */
1033
bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit,
1034
                                                        td::RefInt256& delete_due_limit, td::uint64 _flat_gas_limit,
1035
                                                        td::uint64 _flat_gas_price) {
1036
  auto f = [&](const auto& r, td::uint64 spec_limit) {
1037
    gas_limit = r.gas_limit;
1038
    special_gas_limit = spec_limit;
1039
    gas_credit = r.gas_credit;
1040
    gas_price = r.gas_price;
1041
    freeze_due_limit = td::make_refint(r.freeze_due_limit);
1042
    delete_due_limit = td::make_refint(r.delete_due_limit);
1043
  };
1044
  block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
1045
  if (tlb::csr_unpack(cs, rec)) {
1046
    f(rec, rec.special_gas_limit);
1047
  } else {
1048
    block::gen::GasLimitsPrices::Record_gas_prices rec0;
1049
    if (tlb::csr_unpack(std::move(cs), rec0)) {
1050
      f(rec0, rec0.gas_limit);
1051
    } else {
1052
      return false;
1053
    }
1054
  }
1055
  flat_gas_limit = _flat_gas_limit;
1056
  flat_gas_price = _flat_gas_price;
1057
  compute_threshold();
1058
  return true;
1059
}
1060

1061
/**
1062
 * Checks if an address is suspended according to the ConfigParam(44).
1063
 *
1064
 * @param wc The workchain ID.
1065
 * @param addr The account address address.
1066
 *
1067
 * @returns True if the address is suspended, False otherwise.
1068
 */
1069
bool ComputePhaseConfig::is_address_suspended(ton::WorkchainId wc, td::Bits256 addr) const {
1070
  if (!suspended_addresses) {
1071
    return false;
1072
  }
1073
  try {
1074
    vm::CellBuilder key;
1075
    key.store_long_bool(wc, 32);
1076
    key.store_bits_bool(addr);
1077
    return !suspended_addresses->lookup(key.data_bits(), 288).is_null();
1078
  } catch (vm::VmError) {
1079
    return false;
1080
  }
1081
}
1082

1083
/**
1084
 * Computes the maximum gas fee based on the gas prices and limits.
1085
 *
1086
 * @param gas_price256 The gas price from config as RefInt256
1087
 * @param gas_limit The gas limit from config
1088
 * @param flat_gas_limit The flat gas limit from config
1089
 * @param flat_gas_price The flat gas price from config
1090
 *
1091
 * @returns The maximum gas fee.
1092
 */
1093
static td::RefInt256 compute_max_gas_threshold(const td::RefInt256& gas_price256, td::uint64 gas_limit,
1094
                                               td::uint64 flat_gas_limit, td::uint64 flat_gas_price) {
1095
  if (gas_limit > flat_gas_limit) {
1096
    return td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_bigint(flat_gas_price);
1097
  } else {
1098
    return td::make_refint(flat_gas_price);
1099
  }
1100
}
1101

1102
/**
1103
 * Computes the maximum for gas fee based on the gas prices and limits.
1104
 *
1105
 * Updates max_gas_threshold.
1106
 */
1107
void ComputePhaseConfig::compute_threshold() {
1108
  gas_price256 = td::make_refint(gas_price);
1109
  max_gas_threshold = compute_max_gas_threshold(gas_price256, gas_limit, flat_gas_limit, flat_gas_price);
1110
}
1111

1112
/**
1113
 * Computes the amount of gas that can be bought for a given amount of nanograms.
1114
 *
1115
 * @param nanograms The amount of nanograms to compute gas for.
1116
 *
1117
 * @returns The amount of gas.
1118
 */
1119
td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const {
1120
  if (nanograms.is_null() || sgn(nanograms) < 0) {
1121
    return 0;
1122
  }
1123
  if (nanograms >= max_gas_threshold) {
1124
    return gas_limit;
1125
  }
1126
  if (nanograms < flat_gas_price) {
1127
    return 0;
1128
  }
1129
  auto res = td::div((std::move(nanograms) - flat_gas_price) << 16, gas_price256);
1130
  return res->to_long() + flat_gas_limit;
1131
}
1132

1133
/**
1134
 * Computes the gas price.
1135
 *
1136
 * @param gas_used The amount of gas used.
1137
 *
1138
 * @returns The computed gas price.
1139
 */
1140
td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
1141
  return gas_used <= flat_gas_limit ? td::make_refint(flat_gas_price)
1142
                                    : td::rshift(gas_price256 * (gas_used - flat_gas_limit), 16, 1) + flat_gas_price;
1143
}
1144

1145
namespace transaction {
1146

1147
/**
1148
 * Checks if it is required to increase gas_limit (from GasLimitsPrices config) to special_gas_limit * 2
1149
 * from masterchain GasLimitsPrices config for the transaction.
1150
 *
1151
 * In January 2024 a highload wallet of @wallet Telegram bot in mainnet was stuck because current gas limit (1M) is
1152
 * not enough to clean up old queires, thus locking funds inside.
1153
 * See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened.
1154
 * Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu
1155
 * It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-29).
1156
 * It is activated by setting global version to 5 in ConfigParam 8.
1157
 * This config change also activates new behavior for special accounts in masterchain.
1158
 *
1159
 * @param cfg The compute phase configuration.
1160
 * @param now The Unix time of the transaction.
1161
 * @param account The account of the transaction.
1162
 *
1163
 * @returns True if gas_limit override is required, false otherwise
1164
 */
1165
static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) {
1166
  if (!cfg.special_gas_full) {
1167
    return false;
1168
  }
1169
  ton::UnixTime until = 1709164800;  // 2024-02-29 00:00:00 UTC
1170
  ton::WorkchainId wc = 0;
1171
  const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD";
1172
  return now < until && account.workchain == wc && account.addr.to_hex() == addr_hex;
1173
}
1174

1175
/**
1176
 * Computes the amount of gas that can be bought for a given amount of nanograms.
1177
 * Usually equal to `cfg.gas_bought_for(nanograms)`
1178
 * However, it overrides gas_limit from config in special cases.
1179
 *
1180
 * @param cfg The compute phase configuration.
1181
 * @param nanograms The amount of nanograms to compute gas for.
1182
 *
1183
 * @returns The amount of gas.
1184
 */
1185
td::uint64 Transaction::gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms) {
1186
  if (override_gas_limit(cfg, now, account)) {
1187
    gas_limit_overridden = true;
1188
    // Same as ComputePhaseConfig::gas_bought for, but with other gas_limit and max_gas_threshold
1189
    auto gas_limit = cfg.mc_gas_prices.special_gas_limit * 2;
1190
    auto max_gas_threshold =
1191
        compute_max_gas_threshold(cfg.gas_price256, gas_limit, cfg.flat_gas_limit, cfg.flat_gas_price);
1192
    if (nanograms.is_null() || sgn(nanograms) < 0) {
1193
      return 0;
1194
    }
1195
    if (nanograms >= max_gas_threshold) {
1196
      return gas_limit;
1197
    }
1198
    if (nanograms < cfg.flat_gas_price) {
1199
      return 0;
1200
    }
1201
    auto res = td::div((std::move(nanograms) - cfg.flat_gas_price) << 16, cfg.gas_price256);
1202
    return res->to_long() + cfg.flat_gas_limit;
1203
  }
1204
  return cfg.gas_bought_for(nanograms);
1205
}
1206

1207
/**
1208
 * Computes the gas limits for a transaction.
1209
 *
1210
 * @param cp The ComputePhase object to store the computed gas limits.
1211
 * @param cfg The compute phase configuration.
1212
 *
1213
 * @returns True if the gas limits were successfully computed, false otherwise.
1214
 */
1215
bool Transaction::compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig& cfg) {
1216
  // Compute gas limits
1217
  if (account.is_special) {
1218
    cp.gas_max = cfg.special_gas_limit;
1219
  } else {
1220
    cp.gas_max = gas_bought_for(cfg, balance.grams);
1221
  }
1222
  if (trans_type != tr_ord || (account.is_special && cfg.special_gas_full)) {
1223
    // may use all gas that can be bought using remaining balance
1224
    cp.gas_limit = cp.gas_max;
1225
  } else {
1226
    // originally use only gas bought using remaining message balance
1227
    // if the message is "accepted" by the smart contract, the gas limit will be set to gas_max
1228
    cp.gas_limit = std::min(gas_bought_for(cfg, msg_balance_remaining.grams), cp.gas_max);
1229
  }
1230
  if (trans_type == tr_ord && !block::tlb::t_Message.is_internal(in_msg)) {
1231
    // external messages carry no balance, give them some credit to check whether they are accepted
1232
    cp.gas_credit = std::min(cfg.gas_credit, cp.gas_max);
1233
  } else {
1234
    cp.gas_credit = 0;
1235
  }
1236
  LOG(DEBUG) << "gas limits: max=" << cp.gas_max << ", limit=" << cp.gas_limit << ", credit=" << cp.gas_credit;
1237
  return true;
1238
}
1239

1240
/**
1241
 * Prepares a TVM stack for a transaction.
1242
 *
1243
 * @param cp The compute phase object.
1244
 *
1245
 * @returns A reference to the prepared virtual machine stack.
1246
 *          Returns an empty reference if the transaction type is invalid.
1247
 */
1248
Ref<vm::Stack> Transaction::prepare_vm_stack(ComputePhase& cp) {
1249
  Ref<vm::Stack> stack_ref{true};
1250
  td::RefInt256 acc_addr{true};
1251
  CHECK(acc_addr.write().import_bits(account.addr.cbits(), 256));
1252
  vm::Stack& stack = stack_ref.write();
1253
  switch (trans_type) {
1254
    case tr_tick:
1255
    case tr_tock:
1256
      stack.push_int(balance.grams);
1257
      stack.push_int(std::move(acc_addr));
1258
      stack.push_bool(trans_type == tr_tock);
1259
      stack.push_smallint(-2);
1260
      return stack_ref;
1261
    case tr_ord:
1262
      stack.push_int(balance.grams);
1263
      stack.push_int(msg_balance_remaining.grams);
1264
      stack.push_cell(in_msg);
1265
      stack.push_cellslice(in_msg_body);
1266
      stack.push_bool(in_msg_extern);
1267
      return stack_ref;
1268
    default:
1269
      LOG(ERROR) << "cannot initialize stack for a transaction of type " << trans_type;
1270
      return {};
1271
  }
1272
}
1273

1274
/**
1275
 * Prepares a random seed for a transaction.
1276
 *
1277
 * @param rand_seed The output random seed.
1278
 * @param cfg The configuration for the compute phase.
1279
 *
1280
 * @returns True if the random seed was successfully prepared, false otherwise.
1281
 */
1282
bool Transaction::prepare_rand_seed(td::BitArray<256>& rand_seed, const ComputePhaseConfig& cfg) const {
1283
  // we might use SHA256(block_rand_seed . addr . trans_lt)
1284
  // instead, we use SHA256(block_rand_seed . addr)
1285
  // if the smart contract wants to randomize further, it can use RANDOMIZE instruction
1286
  td::BitArray<256 + 256> data;
1287
  data.bits().copy_from(cfg.block_rand_seed.cbits(), 256);
1288
  (data.bits() + 256).copy_from(account.addr_rewrite.cbits(), 256);
1289
  rand_seed.clear();
1290
  data.compute_sha256(rand_seed);
1291
  return true;
1292
}
1293

1294
/**
1295
 * Prepares the c7 tuple (virtual machine context) for a compute phase of a transaction.
1296
 *
1297
 * @param cfg The configuration for the compute phase.
1298
 *
1299
 * @returns A reference to a Tuple object.
1300
 *
1301
 * @throws CollatorError if the rand_seed cannot be computed for the transaction.
1302
 */
1303
Ref<vm::Tuple> Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const {
1304
  td::BitArray<256> rand_seed;
1305
  td::RefInt256 rand_seed_int{true};
1306
  if (!(prepare_rand_seed(rand_seed, cfg) && rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false))) {
1307
    LOG(ERROR) << "cannot compute rand_seed for transaction";
1308
    throw CollatorError{"cannot generate valid SmartContractInfo"};
1309
    return {};
1310
  }
1311
  std::vector<vm::StackEntry> tuple = {
1312
      td::make_refint(0x076ef1ea),                // [ magic:0x076ef1ea
1313
      td::zero_refint(),                          //   actions:Integer
1314
      td::zero_refint(),                          //   msgs_sent:Integer
1315
      td::make_refint(now),                       //   unixtime:Integer
1316
      td::make_refint(account.block_lt),          //   block_lt:Integer
1317
      td::make_refint(start_lt),                  //   trans_lt:Integer
1318
      std::move(rand_seed_int),                   //   rand_seed:Integer
1319
      balance.as_vm_tuple(),                      //   balance_remaining:[Integer (Maybe Cell)]
1320
      my_addr,                                    //   myself:MsgAddressInt
1321
      vm::StackEntry::maybe(cfg.global_config)    //   global_config:(Maybe Cell) ] = SmartContractInfo;
1322
  };
1323
  if (cfg.global_version >= 4) {
1324
    tuple.push_back(vm::StackEntry::maybe(new_code));  // code:Cell
1325
    if (msg_balance_remaining.is_valid()) {
1326
      tuple.push_back(msg_balance_remaining.as_vm_tuple());  // in_msg_value:[Integer (Maybe Cell)]
1327
    } else {
1328
      tuple.push_back(block::CurrencyCollection::zero().as_vm_tuple());
1329
    }
1330
    tuple.push_back(storage_phase->fees_collected);       // storage_fees:Integer
1331

1332
    // See crypto/block/mc-config.cpp#2223 (get_prev_blocks_info)
1333
    // [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
1334
    // [ last_mc_blocks:[BlockId...]
1335
    //   prev_key_block:BlockId ] : PrevBlocksInfo
1336
    // The only context where PrevBlocksInfo (13 parameter of c7) is null is inside emulator
1337
    // where it need to be set via transaction_emulator_set_prev_blocks_info (see emulator/emulator-extern.cpp)
1338
    // Inside validator, collator and liteserver checking external message  contexts
1339
    // prev_blocks_info is always not null, since get_prev_blocks_info()  
1340
    // may only return tuple or raise Error (See crypto/block/mc-config.cpp#2223)
1341
    tuple.push_back(vm::StackEntry::maybe(cfg.prev_blocks_info));
1342
  }
1343
  if (cfg.global_version >= 6) {
1344
    tuple.push_back(vm::StackEntry::maybe(cfg.unpacked_config_tuple));          // unpacked_config_tuple:[...]
1345
    tuple.push_back(due_payment.not_null() ? due_payment : td::zero_refint());  // due_payment:Integer
1346
    tuple.push_back(compute_phase->precompiled_gas_usage
1347
                        ? vm::StackEntry(td::make_refint(compute_phase->precompiled_gas_usage.value()))
1348
                        : vm::StackEntry());  // precompiled_gas_usage:Integer
1349
  }
1350
  auto tuple_ref = td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
1351
  LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple_ref).to_string();
1352
  return vm::make_tuple_ref(std::move(tuple_ref));
1353
}
1354

1355
/**
1356
 * Computes the number of output actions in a list.
1357
 *
1358
 * @param list c5 cell.
1359
 *
1360
 * @returns The number of output actions.
1361
 */
1362
int output_actions_count(Ref<vm::Cell> list) {
1363
  int i = -1;
1364
  do {
1365
    ++i;
1366
    bool special = true;
1367
    auto cs = load_cell_slice_special(std::move(list), special);
1368
    if (special) {
1369
      break;
1370
    }
1371
    list = cs.prefetch_ref();
1372
  } while (list.not_null());
1373
  return i;
1374
}
1375

1376
/**
1377
 * Unpacks the message StateInit.
1378
 *
1379
 * @param cfg The configuration for the compute phase.
1380
 * @param lib_only If true, only unpack libraries from the state.
1381
 * @param forbid_public_libs Don't allow public libraries in initstate.
1382
 *
1383
 * @returns True if the unpacking is successful, false otherwise.
1384
 */
1385
bool Transaction::unpack_msg_state(const ComputePhaseConfig& cfg, bool lib_only, bool forbid_public_libs) {
1386
  block::gen::StateInit::Record state;
1387
  if (in_msg_state.is_null() || !tlb::unpack_cell(in_msg_state, state)) {
1388
    LOG(ERROR) << "cannot unpack StateInit from an inbound message";
1389
    return false;
1390
  }
1391
  if (lib_only) {
1392
    in_msg_library = state.library->prefetch_ref();
1393
    return true;
1394
  }
1395
  if (state.split_depth->size() == 6) {
1396
    new_split_depth = (signed char)(state.split_depth->prefetch_ulong(6) - 32);
1397
  } else {
1398
    new_split_depth = 0;
1399
  }
1400
  if (state.special->size() > 1) {
1401
    int z = (int)state.special->prefetch_ulong(3);
1402
    if (z < 0) {
1403
      return false;
1404
    }
1405
    new_tick = z & 2;
1406
    new_tock = z & 1;
1407
    LOG(DEBUG) << "tick=" << new_tick << ", tock=" << new_tock;
1408
  }
1409
  td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
1410
  new_code = state.code->prefetch_ref();
1411
  new_data = state.data->prefetch_ref();
1412
  new_library = state.library->prefetch_ref();
1413
  auto size_limits = cfg.size_limits;
1414
  if (forbid_public_libs) {
1415
    size_limits.max_acc_public_libraries = 0;
1416
  }
1417
  auto S = check_state_limits(size_limits, false);
1418
  if (S.is_error()) {
1419
    LOG(DEBUG) << "Cannot unpack msg state: " << S.move_as_error();
1420
    new_code = old_code;
1421
    new_data = old_data;
1422
    new_library = old_library;
1423
    return false;
1424
  }
1425
  return true;
1426
}
1427

1428
/**
1429
 * Computes the set of libraries to be used during TVM execution.
1430
 *
1431
 * @param cfg The configuration for the compute phase.
1432
 *
1433
 * @returns A vector of hashmaps with libraries.
1434
 */
1435
std::vector<Ref<vm::Cell>> Transaction::compute_vm_libraries(const ComputePhaseConfig& cfg) {
1436
  std::vector<Ref<vm::Cell>> lib_set;
1437
  if (in_msg_library.not_null()) {
1438
    lib_set.push_back(in_msg_library);
1439
  }
1440
  if (new_library.not_null()) {
1441
    lib_set.push_back(new_library);
1442
  }
1443
  auto global_libs = cfg.get_lib_root();
1444
  if (global_libs.not_null()) {
1445
    lib_set.push_back(std::move(global_libs));
1446
  }
1447
  return lib_set;
1448
}
1449

1450
/**
1451
 * Checks if the input message StateInit hash corresponds to the account address.
1452
 *
1453
 * @returns True if the input message state hash is valid, False otherwise.
1454
 */
1455
bool Transaction::check_in_msg_state_hash() {
1456
  CHECK(in_msg_state.not_null());
1457
  CHECK(new_split_depth >= 0 && new_split_depth < 32);
1458
  td::Bits256 in_state_hash = in_msg_state->get_hash().bits();
1459
  int d = new_split_depth;
1460
  if ((in_state_hash.bits() + d).compare(account.addr.bits() + d, 256 - d)) {
1461
    return false;
1462
  }
1463
  orig_addr_rewrite = in_state_hash.bits();
1464
  orig_addr_rewrite_set = true;
1465
  return account.recompute_tmp_addr(my_addr, d, orig_addr_rewrite.bits());
1466
}
1467

1468
/**
1469
 * Runs the precompiled smart contract and prepares the compute phase.
1470
 *
1471
 * @param cfg The configuration for the compute phase.
1472
 * @param impl Implementation of the smart contract
1473
 *
1474
 * @returns True if the contract was successfully executed, false otherwise.
1475
 */
1476
bool Transaction::run_precompiled_contract(const ComputePhaseConfig& cfg, precompiled::PrecompiledSmartContract& impl) {
1477
  ComputePhase& cp = *compute_phase;
1478
  CHECK(cp.precompiled_gas_usage);
1479
  td::uint64 gas_usage = cp.precompiled_gas_usage.value();
1480
  td::Timer timer;
1481
  auto result =
1482
      impl.run(my_addr, now, start_lt, balance, new_data, *in_msg_body, in_msg, msg_balance_remaining, in_msg_extern,
1483
               compute_vm_libraries(cfg), cfg.global_version, cfg.max_vm_data_depth, new_code,
1484
               cfg.unpacked_config_tuple, due_payment.not_null() ? due_payment : td::zero_refint(), gas_usage);
1485
  double elapsed = timer.elapsed();
1486
  cp.vm_init_state_hash = td::Bits256::zero();
1487
  cp.exit_code = result.exit_code;
1488
  cp.out_of_gas = false;
1489
  cp.vm_final_state_hash = td::Bits256::zero();
1490
  cp.vm_steps = 0;
1491
  cp.gas_used = gas_usage;
1492
  cp.accepted = result.accepted;
1493
  cp.success = (cp.accepted && result.committed);
1494
  LOG(INFO) << "Running precompiled smart contract " << impl.get_name() << ": exit_code=" << result.exit_code
1495
            << " accepted=" << result.accepted << " success=" << cp.success << " gas_used=" << gas_usage
1496
            << " time=" << elapsed << "s";
1497
  if (cp.accepted & use_msg_state) {
1498
    was_activated = true;
1499
    acc_status = Account::acc_active;
1500
  }
1501
  if (cfg.with_vm_log) {
1502
    cp.vm_log = PSTRING() << "Running precompiled smart contract " << impl.get_name()
1503
                          << ": exit_code=" << result.exit_code << " accepted=" << result.accepted
1504
                          << " success=" << cp.success << " gas_used=" << gas_usage << " time=" << elapsed << "s";
1505
  }
1506
  if (cp.success) {
1507
    cp.new_data = impl.get_c4();
1508
    cp.actions = impl.get_c5();
1509
    int out_act_num = output_actions_count(cp.actions);
1510
    if (verbosity > 2) {
1511
      std::cerr << "new smart contract data: ";
1512
      bool can_be_special = true;
1513
      load_cell_slice_special(cp.new_data, can_be_special).print_rec(std::cerr);
1514
      std::cerr << "output actions: ";
1515
      block::gen::OutList{out_act_num}.print_ref(std::cerr, cp.actions);
1516
    }
1517
  }
1518
  cp.mode = 0;
1519
  cp.exit_arg = 0;
1520
  if (!cp.success && result.exit_arg) {
1521
    auto value = td::narrow_cast_safe<td::int32>(result.exit_arg.value());
1522
    if (value.is_ok()) {
1523
      cp.exit_arg = value.ok();
1524
    }
1525
  }
1526
  if (cp.accepted) {
1527
    if (account.is_special) {
1528
      cp.gas_fees = td::zero_refint();
1529
    } else {
1530
      cp.gas_fees = cfg.compute_gas_price(cp.gas_used);
1531
      total_fees += cp.gas_fees;
1532
      balance -= cp.gas_fees;
1533
    }
1534
    LOG(DEBUG) << "gas fees: " << cp.gas_fees->to_dec_string() << " = " << cfg.gas_price256->to_dec_string() << " * "
1535
               << cp.gas_used << " /2^16 ; price=" << cfg.gas_price << "; flat rate=[" << cfg.flat_gas_price << " for "
1536
               << cfg.flat_gas_limit << "]; remaining balance=" << balance.to_str();
1537
    CHECK(td::sgn(balance.grams) >= 0);
1538
  }
1539
  return true;
1540
}
1541

1542
/**
1543
 * Prepares the compute phase of a transaction, which includes running TVM.
1544
 *
1545
 * @param cfg The configuration for the compute phase.
1546
 *
1547
 * @returns True if the compute phase was successfully prepared and executed, false otherwise.
1548
 */
1549
bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
1550
  // TODO: add more skip verifications + sometimes use state from in_msg to re-activate
1551
  // ...
1552
  compute_phase = std::make_unique<ComputePhase>();
1553
  ComputePhase& cp = *(compute_phase.get());
1554
  original_balance -= total_fees;
1555
  if (td::sgn(balance.grams) <= 0) {
1556
    // no gas
1557
    cp.skip_reason = ComputePhase::sk_no_gas;
1558
    return true;
1559
  }
1560
  // Compute gas limits
1561
  if (!compute_gas_limits(cp, cfg)) {
1562
    compute_phase.reset();
1563
    return false;
1564
  }
1565
  if (!cp.gas_limit && !cp.gas_credit) {
1566
    // no gas
1567
    cp.skip_reason = ComputePhase::sk_no_gas;
1568
    return true;
1569
  }
1570
  if (in_msg_state.not_null()) {
1571
    LOG(DEBUG) << "HASH(in_msg_state) = " << in_msg_state->get_hash().bits().to_hex(256)
1572
               << ", account_state_hash = " << account.state_hash.to_hex();
1573
    // vm::load_cell_slice(in_msg_state).print_rec(std::cerr);
1574
  } else {
1575
    LOG(DEBUG) << "in_msg_state is null";
1576
  }
1577
  if (in_msg_state.not_null() &&
1578
      (acc_status == Account::acc_uninit ||
1579
       (acc_status == Account::acc_frozen && account.state_hash == in_msg_state->get_hash().bits()))) {
1580
    if (acc_status == Account::acc_uninit && cfg.is_address_suspended(account.workchain, account.addr)) {
1581
      LOG(DEBUG) << "address is suspended, skipping compute phase";
1582
      cp.skip_reason = ComputePhase::sk_suspended;
1583
      return true;
1584
    }
1585
    use_msg_state = true;
1586
    bool forbid_public_libs =
1587
        acc_status == Account::acc_uninit && account.is_masterchain();  // Forbid for deploying, allow for unfreezing
1588
    if (!(unpack_msg_state(cfg, false, forbid_public_libs) && account.check_split_depth(new_split_depth))) {
1589
      LOG(DEBUG) << "cannot unpack in_msg_state, or it has bad split_depth; cannot init account state";
1590
      cp.skip_reason = ComputePhase::sk_bad_state;
1591
      return true;
1592
    }
1593
    if (acc_status == Account::acc_uninit && !check_in_msg_state_hash()) {
1594
      LOG(DEBUG) << "in_msg_state hash mismatch, cannot init account state";
1595
      cp.skip_reason = ComputePhase::sk_bad_state;
1596
      return true;
1597
    }
1598
  } else if (acc_status != Account::acc_active) {
1599
    // no state, cannot perform transactions
1600
    cp.skip_reason = in_msg_state.not_null() ? ComputePhase::sk_bad_state : ComputePhase::sk_no_state;
1601
    return true;
1602
  } else if (in_msg_state.not_null()) {
1603
    unpack_msg_state(cfg, true);  // use only libraries
1604
  }
1605
  if (in_msg_extern && in_msg_state.not_null() && account.addr != in_msg_state->get_hash().bits()) {
1606
    LOG(DEBUG) << "in_msg_state hash mismatch in external message";
1607
    cp.skip_reason = ComputePhase::sk_bad_state;
1608
    return true;
1609
  }
1610

1611
  td::optional<PrecompiledContractsConfig::Contract> precompiled;
1612
  if (new_code.not_null() && trans_type == tr_ord) {
1613
    precompiled = cfg.precompiled_contracts.get_contract(new_code->get_hash().bits());
1614
  }
1615

1616
  vm::GasLimits gas{(long long)cp.gas_limit, (long long)cp.gas_max, (long long)cp.gas_credit};
1617
  if (precompiled) {
1618
    td::uint64 gas_usage = precompiled.value().gas_usage;
1619
    cp.precompiled_gas_usage = gas_usage;
1620
    if (gas_usage > cp.gas_limit) {
1621
      cp.skip_reason = ComputePhase::sk_no_gas;
1622
      return true;
1623
    }
1624
    auto impl = precompiled::get_implementation(new_code->get_hash().bits());
1625
    if (impl != nullptr && !cfg.dont_run_precompiled_ && impl->required_version() <= cfg.global_version) {
1626
      return run_precompiled_contract(cfg, *impl);
1627
    }
1628

1629
    // Contract is marked as precompiled in global config, but implementation is not available
1630
    // In this case we run TVM and override gas_used
1631
    LOG(INFO) << "Unknown precompiled contract (code_hash=" << new_code->get_hash().to_hex()
1632
              << ", gas_usage=" << gas_usage << "), running VM";
1633
    long long limit = account.is_special ? cfg.special_gas_limit : cfg.gas_limit;
1634
    gas = vm::GasLimits{limit, limit, gas.gas_credit ? limit : 0};
1635
  }
1636

1637
  // initialize VM
1638
  Ref<vm::Stack> stack = prepare_vm_stack(cp);
1639
  if (stack.is_null()) {
1640
    compute_phase.reset();
1641
    return false;
1642
  }
1643
  // OstreamLogger ostream_logger(error_stream);
1644
  // auto log = create_vm_log(error_stream ? &ostream_logger : nullptr);
1645
  LOG(DEBUG) << "creating VM";
1646

1647
  std::unique_ptr<StringLoggerTail> logger;
1648
  auto vm_log = vm::VmLog();
1649
  if (cfg.with_vm_log) {
1650
    size_t log_max_size = cfg.vm_log_verbosity > 0 ? 1024 * 1024 : 256;
1651
    logger = std::make_unique<StringLoggerTail>(log_max_size);
1652
    vm_log.log_interface = logger.get();
1653
    vm_log.log_options = td::LogOptions(VERBOSITY_NAME(DEBUG), true, false);
1654
    if (cfg.vm_log_verbosity > 1) {
1655
      vm_log.log_mask |= vm::VmLog::ExecLocation;
1656
      if (cfg.vm_log_verbosity > 2) {
1657
        vm_log.log_mask |= vm::VmLog::GasRemaining;
1658
        if (cfg.vm_log_verbosity > 3) {
1659
          vm_log.log_mask |= vm::VmLog::DumpStack;
1660
          if (cfg.vm_log_verbosity > 4) {
1661
            vm_log.log_mask |= vm::VmLog::DumpStackVerbose;
1662
          }
1663
        }
1664
      }
1665
    }
1666
  }
1667
  vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
1668
  vm.set_max_data_depth(cfg.max_vm_data_depth);
1669
  vm.set_global_version(cfg.global_version);
1670
  vm.set_c7(prepare_vm_c7(cfg));  // tuple with SmartContractInfo
1671
  vm.set_chksig_always_succeed(cfg.ignore_chksig);
1672
  vm.set_stop_on_accept_message(cfg.stop_on_accept_message);
1673
  // vm.incr_stack_trace(1);    // enable stack dump after each step
1674

1675
  LOG(DEBUG) << "starting VM";
1676
  cp.vm_init_state_hash = vm.get_state_hash();
1677
  td::Timer timer;
1678
  cp.exit_code = ~vm.run();
1679
  double elapsed = timer.elapsed();
1680
  LOG(DEBUG) << "VM terminated with exit code " << cp.exit_code;
1681
  cp.out_of_gas = (cp.exit_code == ~(int)vm::Excno::out_of_gas);
1682
  cp.vm_final_state_hash = vm.get_final_state_hash(cp.exit_code);
1683
  stack = vm.get_stack_ref();
1684
  cp.vm_steps = (int)vm.get_steps_count();
1685
  gas = vm.get_gas_limits();
1686
  cp.gas_used = std::min<long long>(gas.gas_consumed(), gas.gas_limit);
1687
  cp.accepted = (gas.gas_credit == 0);
1688
  cp.success = (cp.accepted && vm.committed());
1689
  if (cp.accepted & use_msg_state) {
1690
    was_activated = true;
1691
    acc_status = Account::acc_active;
1692
  }
1693
  if (precompiled) {
1694
    cp.gas_used = precompiled.value().gas_usage;
1695
    cp.vm_steps = 0;
1696
    cp.vm_init_state_hash = cp.vm_final_state_hash = td::Bits256::zero();
1697
    if (cp.out_of_gas) {
1698
      LOG(ERROR) << "Precompiled smc got out_of_gas in TVM";
1699
      return false;
1700
    }
1701
  }
1702
  LOG(INFO) << "steps: " << vm.get_steps_count() << " gas: used=" << gas.gas_consumed() << ", max=" << gas.gas_max
1703
            << ", limit=" << gas.gas_limit << ", credit=" << gas.gas_credit;
1704
  LOG(INFO) << "out_of_gas=" << cp.out_of_gas << ", accepted=" << cp.accepted << ", success=" << cp.success
1705
            << ", time=" << elapsed << "s";
1706
  if (logger != nullptr) {
1707
    cp.vm_log = logger->get_log();
1708
  }
1709
  if (cp.success) {
1710
    cp.new_data = vm.get_committed_state().c4;  // c4 -> persistent data
1711
    cp.actions = vm.get_committed_state().c5;   // c5 -> action list
1712
    int out_act_num = output_actions_count(cp.actions);
1713
    if (verbosity > 2) {
1714
      std::cerr << "new smart contract data: ";
1715
      bool can_be_special = true;
1716
      load_cell_slice_special(cp.new_data, can_be_special).print_rec(std::cerr);
1717
      std::cerr << "output actions: ";
1718
      block::gen::OutList{out_act_num}.print_ref(std::cerr, cp.actions);
1719
    }
1720
  }
1721
  cp.mode = 0;
1722
  cp.exit_arg = 0;
1723
  if (!cp.success && stack->depth() > 0) {
1724
    td::RefInt256 tos = stack->tos().as_int();
1725
    if (tos.not_null() && tos->signed_fits_bits(32)) {
1726
      cp.exit_arg = (int)tos->to_long();
1727
    }
1728
  }
1729
  if (cp.accepted) {
1730
    if (account.is_special) {
1731
      cp.gas_fees = td::zero_refint();
1732
    } else {
1733
      cp.gas_fees = cfg.compute_gas_price(cp.gas_used);
1734
      total_fees += cp.gas_fees;
1735
      balance -= cp.gas_fees;
1736
    }
1737
    LOG(DEBUG) << "gas fees: " << cp.gas_fees->to_dec_string() << " = " << cfg.gas_price256->to_dec_string() << " * "
1738
               << cp.gas_used << " /2^16 ; price=" << cfg.gas_price << "; flat rate=[" << cfg.flat_gas_price << " for "
1739
               << cfg.flat_gas_limit << "]; remaining balance=" << balance.to_str();
1740
    CHECK(td::sgn(balance.grams) >= 0);
1741
  }
1742
  return true;
1743
}
1744

1745
/**
1746
 * Prepares the action phase of a transaction.
1747
 *
1748
 * @param cfg The configuration for the action phase.
1749
 *
1750
 * @returns True if the action phase was prepared successfully, false otherwise.
1751
 */
1752
bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
1753
  if (!compute_phase || !compute_phase->success) {
1754
    return false;
1755
  }
1756
  action_phase = std::make_unique<ActionPhase>();
1757
  ActionPhase& ap = *(action_phase.get());
1758
  ap.result_code = -1;
1759
  ap.result_arg = 0;
1760
  ap.tot_actions = ap.spec_actions = ap.skipped_actions = ap.msgs_created = 0;
1761
  Ref<vm::Cell> list = compute_phase->actions;
1762
  assert(list.not_null());
1763
  ap.action_list_hash = list->get_hash().bits();
1764
  ap.remaining_balance = balance;
1765
  ap.end_lt = end_lt;
1766
  ap.total_fwd_fees = td::zero_refint();
1767
  ap.total_action_fees = td::zero_refint();
1768
  ap.reserved_balance.set_zero();
1769
  ap.action_fine = td::zero_refint();
1770

1771
  td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
1772
  auto enforce_state_limits = [&]() {
1773
    if (account.is_special) {
1774
      return true;
1775
    }
1776
    auto S = check_state_limits(cfg.size_limits);
1777
    if (S.is_error()) {
1778
      // Rollback changes to state, fail action phase
1779
      LOG(INFO) << "Account state size exceeded limits: " << S.move_as_error();
1780
      new_storage_stat.clear();
1781
      new_code = old_code;
1782
      new_data = old_data;
1783
      new_library = old_library;
1784
      ap.result_code = 50;
1785
      ap.state_exceeds_limits = true;
1786
      return false;
1787
    }
1788
    return true;
1789
  };
1790

1791
  int n = 0;
1792
  while (true) {
1793
    ap.action_list.push_back(list);
1794
    bool special = true;
1795
    auto cs = load_cell_slice_special(std::move(list), special);
1796
    if (special) {
1797
      ap.result_code = 32;  // action list invalid
1798
      ap.result_arg = n;
1799
      ap.action_list_invalid = true;
1800
      LOG(DEBUG) << "action list invalid: special cell";
1801
      return true;
1802
    }
1803
    if (!cs.size_ext()) {
1804
      break;
1805
    }
1806
    if (!cs.have_refs()) {
1807
      ap.result_code = 32;  // action list invalid
1808
      ap.result_arg = n;
1809
      ap.action_list_invalid = true;
1810
      LOG(DEBUG) << "action list invalid: entry found with data but no next reference";
1811
      return true;
1812
    }
1813
    list = cs.prefetch_ref();
1814
    n++;
1815
    if (n > cfg.max_actions) {
1816
      ap.result_code = 33;  // too many actions
1817
      ap.result_arg = n;
1818
      ap.action_list_invalid = true;
1819
      LOG(DEBUG) << "action list too long: more than " << cfg.max_actions << " actions";
1820
      return true;
1821
    }
1822
  }
1823

1824
  ap.tot_actions = n;
1825
  ap.spec_actions = ap.skipped_actions = 0;
1826
  for (int i = n - 1; i >= 0; --i) {
1827
    ap.result_arg = n - 1 - i;
1828
    if (!block::gen::t_OutListNode.validate_ref(ap.action_list[i])) {
1829
      ap.result_code = 34;  // action #i invalid or unsupported
1830
      ap.action_list_invalid = true;
1831
      LOG(DEBUG) << "invalid action " << ap.result_arg << " found while preprocessing action list: error code "
1832
                 << ap.result_code;
1833
      return true;
1834
    }
1835
  }
1836
  ap.valid = true;
1837
  for (int i = n - 1; i >= 0; --i) {
1838
    ap.result_arg = n - 1 - i;
1839
    vm::CellSlice cs = load_cell_slice(ap.action_list[i]);
1840
    CHECK(cs.fetch_ref().not_null());
1841
    int tag = block::gen::t_OutAction.get_tag(cs);
1842
    CHECK(tag >= 0);
1843
    int err_code = 34;
1844
    ap.need_bounce_on_fail = false;
1845
    switch (tag) {
1846
      case block::gen::OutAction::action_set_code:
1847
        err_code = try_action_set_code(cs, ap, cfg);
1848
        break;
1849
      case block::gen::OutAction::action_send_msg:
1850
        err_code = try_action_send_msg(cs, ap, cfg);
1851
        if (err_code == -2) {
1852
          err_code = try_action_send_msg(cs, ap, cfg, 1);
1853
          if (err_code == -2) {
1854
            err_code = try_action_send_msg(cs, ap, cfg, 2);
1855
          }
1856
        }
1857
        break;
1858
      case block::gen::OutAction::action_reserve_currency:
1859
        err_code = try_action_reserve_currency(cs, ap, cfg);
1860
        break;
1861
      case block::gen::OutAction::action_change_library:
1862
        err_code = try_action_change_library(cs, ap, cfg);
1863
        break;
1864
    }
1865
    if (err_code) {
1866
      ap.result_code = (err_code == -1 ? 34 : err_code);
1867
      ap.end_lt = end_lt;
1868
      if (err_code == -1 || err_code == 34) {
1869
        ap.action_list_invalid = true;
1870
      }
1871
      if (err_code == 37 || err_code == 38) {
1872
        ap.no_funds = true;
1873
      }
1874
      LOG(DEBUG) << "invalid action " << ap.result_arg << " in action list: error code " << ap.result_code;
1875
      // This is reuqired here because changes to libraries are applied even if actipn phase fails
1876
      enforce_state_limits();
1877
      if (cfg.action_fine_enabled) {
1878
        ap.action_fine = std::min(ap.action_fine, balance.grams);
1879
        ap.total_action_fees = ap.action_fine;
1880
        balance.grams -= ap.action_fine;
1881
        total_fees += ap.action_fine;
1882
      }
1883
      if (ap.need_bounce_on_fail) {
1884
        ap.bounce = true;
1885
      }
1886
      return true;
1887
    }
1888
  }
1889

1890
  if (cfg.action_fine_enabled) {
1891
    ap.total_action_fees += ap.action_fine;
1892
  }
1893
  end_lt = ap.end_lt;
1894
  if (ap.new_code.not_null()) {
1895
    new_code = ap.new_code;
1896
  }
1897
  new_data = compute_phase->new_data;  // tentative persistent data update applied
1898
  if (!enforce_state_limits()) {
1899
    return true;
1900
  }
1901

1902
  ap.result_arg = 0;
1903
  ap.result_code = 0;
1904
  CHECK(ap.remaining_balance.grams->sgn() >= 0);
1905
  CHECK(ap.reserved_balance.grams->sgn() >= 0);
1906
  ap.remaining_balance += ap.reserved_balance;
1907
  CHECK(ap.remaining_balance.is_valid());
1908
  if (ap.acc_delete_req) {
1909
    CHECK(ap.remaining_balance.is_zero());
1910
    ap.acc_status_change = ActionPhase::acst_deleted;
1911
    acc_status = Account::acc_deleted;
1912
    was_deleted = true;
1913
  }
1914
  ap.success = true;
1915
  out_msgs = std::move(ap.out_msgs);
1916
  total_fees +=
1917
      ap.total_action_fees;  // NB: forwarding fees are not accounted here (they are not collected by the validators in this transaction)
1918
  balance = ap.remaining_balance;
1919
  return true;
1920
}
1921

1922
/**
1923
 * Tries to set the code for an account.
1924
 *
1925
 * @param cs The CellSlice containing the action data serialized as action_set_code TLB-scheme.
1926
 * @param ap The action phase object.
1927
 * @param cfg The action phase configuration.
1928
 *
1929
 * @returns 0 if the code was successfully set, -1 otherwise.
1930
 */
1931
int Transaction::try_action_set_code(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) {
1932
  block::gen::OutAction::Record_action_set_code rec;
1933
  if (!tlb::unpack_exact(cs, rec)) {
1934
    return -1;
1935
  }
1936
  ap.new_code = std::move(rec.new_code);
1937
  ap.code_changed = true;
1938
  ap.spec_actions++;
1939
  return 0;
1940
}
1941

1942
/**
1943
 * Tries to change the library in the transaction.
1944
 *
1945
 * @param cs The cell slice containing the action data serialized as action_change_library TLB-scheme.
1946
 * @param ap The action phase object.
1947
 * @param cfg The action phase configuration.
1948
 *
1949
 * @returns 0 if the action was successfully performed,
1950
 *          -1 if there was an error unpacking the data or the mode is invalid,
1951
 *          41 if the library reference is required but is null,
1952
 *          43 if the number of cells in the library exceeds the limit,
1953
 *          42 if there was a VM error during the operation.
1954
 */
1955
int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) {
1956
  block::gen::OutAction::Record_action_change_library rec;
1957
  if (!tlb::unpack_exact(cs, rec)) {
1958
    return -1;
1959
  }
1960
  // mode: +0 = remove library, +1 = add private library, +2 = add public library, +16 - bounce on fail
1961
  if (rec.mode & 16) {
1962
    if (!cfg.bounce_on_fail_enabled) {
1963
      return -1;
1964
    }
1965
    ap.need_bounce_on_fail = true;
1966
    rec.mode &= ~16;
1967
  }
1968
  if (rec.mode > 2) {
1969
    return -1;
1970
  }
1971
  Ref<vm::Cell> lib_ref = rec.libref->prefetch_ref();
1972
  ton::Bits256 hash;
1973
  if (lib_ref.not_null()) {
1974
    hash = lib_ref->get_hash().bits();
1975
  } else {
1976
    CHECK(rec.libref.write().fetch_ulong(1) == 0 && rec.libref.write().fetch_bits_to(hash));
1977
  }
1978
  try {
1979
    vm::Dictionary dict{new_library, 256};
1980
    if (!rec.mode) {
1981
      // remove library
1982
      dict.lookup_delete(hash);
1983
      LOG(DEBUG) << "removed " << ((rec.mode >> 1) ? "public" : "private") << " library with hash " << hash.to_hex();
1984
    } else {
1985
      auto val = dict.lookup(hash);
1986
      if (val.not_null()) {
1987
        bool is_public = val->prefetch_ulong(1);
1988
        auto ref = val->prefetch_ref();
1989
        if (hash == ref->get_hash().bits()) {
1990
          lib_ref = ref;
1991
          if (is_public == (rec.mode >> 1)) {
1992
            // library already in required state
1993
            ap.spec_actions++;
1994
            return 0;
1995
          }
1996
        }
1997
      }
1998
      if (lib_ref.is_null()) {
1999
        // library code not found
2000
        return 41;
2001
      }
2002
      vm::CellStorageStat sstat;
2003
      auto cell_info = sstat.compute_used_storage(lib_ref).move_as_ok();
2004
      if (sstat.cells > cfg.size_limits.max_library_cells || cell_info.max_merkle_depth > max_allowed_merkle_depth) {
2005
        return 43;
2006
      }
2007
      vm::CellBuilder cb;
2008
      CHECK(cb.store_bool_bool(rec.mode >> 1) && cb.store_ref_bool(std::move(lib_ref)));
2009
      CHECK(dict.set_builder(hash, cb));
2010
      LOG(DEBUG) << "added " << ((rec.mode >> 1) ? "public" : "private") << " library with hash " << hash.to_hex();
2011
    }
2012
    new_library = std::move(dict).extract_root_cell();
2013
  } catch (vm::VmError& vme) {
2014
    return 42;
2015
  }
2016
  ap.spec_actions++;
2017
  return 0;
2018
}
2019
}  // namespace transaction
2020

2021
/**
2022
 * Computes the forward fees for a message based on the number of cells and bits.
2023
 * 
2024
 * msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
2025
 * ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms
2026
 * bits in the root cell of a message are not included in msg.bits (lump_price pays for them)
2027
 *
2028
 * @param cells The number of cells in the message.
2029
 * @param bits The number of bits in the message.
2030
 *
2031
 * @returns The computed forward fees for the message.
2032
 */
2033
td::uint64 MsgPrices::compute_fwd_fees(td::uint64 cells, td::uint64 bits) const {
2034
  return lump_price + td::uint128(bit_price)
2035
                          .mult(bits)
2036
                          .add(td::uint128(cell_price).mult(cells))
2037
                          .add(td::uint128(0xffffu))
2038
                          .shr(16)
2039
                          .lo();
2040
}
2041

2042
/**
2043
 * Computes the forward fees for a message based on the number of cells and bits.
2044
 * Return the result as td::RefInt256
2045
 *
2046
 * msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
2047
 * ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms
2048
 * bits in the root cell of a message are not included in msg.bits (lump_price pays for them)
2049
 *
2050
 * @param cells The number of cells in the message.
2051
 * @param bits The number of bits in the message.
2052
 *
2053
 * @returns The computed forward fees for the message as td::RefInt256j.
2054
 */
2055
td::RefInt256 MsgPrices::compute_fwd_fees256(td::uint64 cells, td::uint64 bits) const {
2056
  return td::make_refint(lump_price) +
2057
         td::rshift(td::make_refint(bit_price) * bits + td::make_refint(cell_price) * cells, 16,
2058
                    1);  // divide by 2^16 with ceil rounding
2059
}
2060

2061
/**
2062
 * Computes the forward fees and IHR fees for a message with the given number of cells and bits.
2063
 *
2064
 * @param cells The number of cells.
2065
 * @param bits The number of bits.
2066
 * @param ihr_disabled Flag indicating whether IHR is disabled.
2067
 *
2068
 * @returns A pair of values representing the forward fees and IHR fees.
2069
 */
2070
std::pair<td::uint64, td::uint64> MsgPrices::compute_fwd_ihr_fees(td::uint64 cells, td::uint64 bits,
2071
                                                                  bool ihr_disabled) const {
2072
  td::uint64 fwd = compute_fwd_fees(cells, bits);
2073
  if (ihr_disabled) {
2074
    return std::pair<td::uint64, td::uint64>(fwd, 0);
2075
  }
2076
  return std::pair<td::uint64, td::uint64>(fwd, td::uint128(fwd).mult(ihr_factor).shr(16).lo());
2077
}
2078

2079
/**
2080
 * Computes the part of the fees that go to the total fees of the current block.
2081
 *
2082
 * @param total The amount of fees.
2083
 *
2084
 * @returns The the part of the fees that go to the total fees of the current block.
2085
 */
2086
td::RefInt256 MsgPrices::get_first_part(td::RefInt256 total) const {
2087
  return (std::move(total) * first_frac) >> 16;
2088
}
2089

2090
/**
2091
 * Computes the part of the fees that go to the total fees of the current block.
2092
 *
2093
 * @param total The amount of fees.
2094
 *
2095
 * @returns The the part of the fees that go to the total fees of the current block.
2096
 */
2097
td::uint64 MsgPrices::get_first_part(td::uint64 total) const {
2098
  return td::uint128(total).mult(first_frac).shr(16).lo();
2099
}
2100

2101
/**
2102
 * Computes the part of the fees that go to the total fees of the transit block.
2103
 *
2104
 * @param total The amount of fees.
2105
 *
2106
 * @returns The the part of the fees that go to the total fees of the transit block.
2107
 */
2108
td::RefInt256 MsgPrices::get_next_part(td::RefInt256 total) const {
2109
  return (std::move(total) * next_frac) >> 16;
2110
}
2111

2112
namespace transaction {
2113
/**
2114
 * Checks if the source address is addr_none and replaces is with the account address.
2115
 *
2116
 * @param src_addr A reference to the source address of the message.
2117
 *
2118
 * @returns True if the source address is addr_none or is equal to the account address.
2119
 */
2120
bool Transaction::check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const {
2121
  int t = (int)src_addr->prefetch_ulong(2);
2122
  if (!t && src_addr->size_ext() == 2) {
2123
    // addr_none$00  --> replace with the address of current smart contract
2124
    src_addr = my_addr;
2125
    return true;
2126
  }
2127
  if (t != 2) {
2128
    // invalid address (addr_extern and addr_var cannot be source addresses)
2129
    return false;
2130
  }
2131
  if (src_addr->contents_equal(*my_addr) || src_addr->contents_equal(*my_addr_exact)) {
2132
    // source address matches that of the current account
2133
    return true;
2134
  }
2135
  // only one valid case remaining: rewritten source address used, replace with the complete one
2136
  // (are we sure we want to allow this?)
2137
  return false;
2138
}
2139

2140
/**
2141
 * Checks the destination address of a message, rewrites it if it is an anycast address.
2142
 *
2143
 * @param dest_addr A reference to the destination address of the transaction.
2144
 * @param cfg The configuration for the action phase.
2145
 * @param is_mc A pointer to a boolean where it will be stored whether the destination is in the masterchain.
2146
 *
2147
 * @returns True if the destination address is valid, false otherwise.
2148
 */
2149
bool Transaction::check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const ActionPhaseConfig& cfg,
2150
                                          bool* is_mc) const {
2151
  if (!dest_addr->prefetch_ulong(1)) {
2152
    // all external addresses allowed
2153
    if (is_mc) {
2154
      *is_mc = false;
2155
    }
2156
    return true;
2157
  }
2158
  bool repack = false;
2159
  int tag = block::gen::t_MsgAddressInt.get_tag(*dest_addr);
2160

2161
  block::gen::MsgAddressInt::Record_addr_var rec;
2162

2163
  if (tag == block::gen::MsgAddressInt::addr_var) {
2164
    if (!tlb::csr_unpack(dest_addr, rec)) {
2165
      // cannot unpack addr_var
2166
      LOG(DEBUG) << "cannot unpack addr_var in a destination address";
2167
      return false;
2168
    }
2169
    if (rec.addr_len == 256 && rec.workchain_id >= -128 && rec.workchain_id < 128) {
2170
      LOG(DEBUG) << "destination address contains an addr_var to be repacked into addr_std";
2171
      repack = true;
2172
    }
2173
  } else if (tag == block::gen::MsgAddressInt::addr_std) {
2174
    block::gen::MsgAddressInt::Record_addr_std recs;
2175
    if (!tlb::csr_unpack(dest_addr, recs)) {
2176
      // cannot unpack addr_std
2177
      LOG(DEBUG) << "cannot unpack addr_std in a destination address";
2178
      return false;
2179
    }
2180
    rec.anycast = std::move(recs.anycast);
2181
    rec.addr_len = 256;
2182
    rec.workchain_id = recs.workchain_id;
2183
    rec.address = td::make_bitstring_ref(recs.address);
2184
  } else {
2185
    // unknown address format (not a MsgAddressInt)
2186
    LOG(DEBUG) << "destination address does not have a MsgAddressInt tag";
2187
    return false;
2188
  }
2189
  if (rec.workchain_id != ton::masterchainId) {
2190
    // recover destination workchain info from configuration
2191
    auto it = cfg.workchains->find(rec.workchain_id);
2192
    if (it == cfg.workchains->end()) {
2193
      // undefined destination workchain
2194
      LOG(DEBUG) << "destination address contains unknown workchain_id " << rec.workchain_id;
2195
      return false;
2196
    }
2197
    if (!it->second->accept_msgs) {
2198
      // workchain does not accept new messages
2199
      LOG(DEBUG) << "destination address belongs to workchain " << rec.workchain_id << " not accepting new messages";
2200
      return false;
2201
    }
2202
    if (!it->second->is_valid_addr_len(rec.addr_len)) {
2203
      // invalid address length for specified workchain
2204
      LOG(DEBUG) << "destination address has length " << rec.addr_len << " invalid for destination workchain "
2205
                 << rec.workchain_id;
2206
      return false;
2207
    }
2208
  }
2209
  if (rec.anycast->size() > 1) {
2210
    // destination address is an anycast
2211
    vm::CellSlice cs{*rec.anycast};
2212
    int d = (int)cs.fetch_ulong(6) - 32;
2213
    if (d <= 0 || d > 30) {
2214
      // invalid anycast prefix length
2215
      return false;
2216
    }
2217
    unsigned pfx = (unsigned)cs.fetch_ulong(d);
2218
    unsigned my_pfx = (unsigned)account.addr.cbits().get_uint(d);
2219
    if (pfx != my_pfx) {
2220
      // rewrite destination address
2221
      vm::CellBuilder cb;
2222
      CHECK(cb.store_long_bool(32 + d, 6)     // just$1 depth:(#<= 30)
2223
            && cb.store_long_bool(my_pfx, d)  // rewrite_pfx:(bits depth)
2224
            && (rec.anycast = load_cell_slice_ref(cb.finalize())).not_null());
2225
      repack = true;
2226
    }
2227
  }
2228
  if (is_mc) {
2229
    *is_mc = (rec.workchain_id == ton::masterchainId);
2230
  }
2231
  if (!repack) {
2232
    return true;
2233
  }
2234
  if (rec.addr_len == 256 && rec.workchain_id >= -128 && rec.workchain_id < 128) {
2235
    // repack as an addr_std
2236
    vm::CellBuilder cb;
2237
    CHECK(cb.store_long_bool(2, 2)                             // addr_std$10
2238
          && cb.append_cellslice_bool(std::move(rec.anycast))  // anycast:(Maybe Anycast) ...
2239
          && cb.store_long_bool(rec.workchain_id, 8)           // workchain_id:int8
2240
          && cb.append_bitstring(std::move(rec.address))       // address:bits256
2241
          && (dest_addr = load_cell_slice_ref(cb.finalize())).not_null());
2242
  } else {
2243
    // repack as an addr_var
2244
    CHECK(tlb::csr_pack(dest_addr, std::move(rec)));
2245
  }
2246
  CHECK(block::gen::t_MsgAddressInt.validate_csr(dest_addr));
2247
  return true;
2248
}
2249

2250
/**
2251
 * Tries to send a message.
2252
 *
2253
 * @param cs0 The cell slice containing the action data serialized as action_send_msg TLB-scheme.
2254
 * @param ap The action phase.
2255
 * @param cfg The action phase configuration.
2256
 * @param redoing The index of the attempt, starting from 0. On later attempts tries to move message body and StateInit to separate cells.
2257
 *
2258
 * @returns 0 if the message is successfully sent or if the error may be ignored, error code otherwise.
2259
 *          Returns -2 if the action should be attempted again.
2260
 */
2261
int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, const ActionPhaseConfig& cfg,
2262
                                     int redoing) {
2263
  block::gen::OutAction::Record_action_send_msg act_rec;
2264
  // mode:
2265
  // +128 = attach all remaining balance
2266
  // +64 = attach all remaining balance of the inbound message
2267
  // +32 = delete smart contract if balance becomes zero
2268
  // +1 = pay message fees
2269
  // +2 = skip if message cannot be sent
2270
  // +16 = bounce if action fails
2271
  vm::CellSlice cs{cs0};
2272
  if (!tlb::unpack_exact(cs, act_rec)) {
2273
    return -1;
2274
  }
2275
  if ((act_rec.mode & 16) && cfg.bounce_on_fail_enabled) {
2276
    act_rec.mode &= ~16;
2277
    ap.need_bounce_on_fail = true;
2278
  }
2279
  if ((act_rec.mode & ~0xe3) || (act_rec.mode & 0xc0) == 0xc0) {
2280
    return -1;
2281
  }
2282
  bool skip_invalid = (act_rec.mode & 2);
2283
  // try to parse suggested message in act_rec.out_msg
2284
  td::RefInt256 fwd_fee, ihr_fee;
2285
  block::gen::MessageRelaxed::Record msg;
2286
  if (!tlb::type_unpack_cell(act_rec.out_msg, block::gen::t_MessageRelaxed_Any, msg)) {
2287
    return -1;
2288
  }
2289
  if (!block::tlb::validate_message_relaxed_libs(act_rec.out_msg)) {
2290
    LOG(DEBUG) << "outbound message has invalid libs in StateInit";
2291
    return -1;
2292
  }
2293
  if (redoing >= 1) {
2294
    if (msg.init->size_refs() >= 2) {
2295
      LOG(DEBUG) << "moving the StateInit of a suggested outbound message into a separate cell";
2296
      // init:(Maybe (Either StateInit ^StateInit))
2297
      // transform (just (left z:StateInit)) into (just (right z:^StateInit))
2298
      CHECK(msg.init.write().fetch_ulong(2) == 2);
2299
      vm::CellBuilder cb;
2300
      Ref<vm::Cell> cell;
2301
      CHECK(cb.append_cellslice_bool(std::move(msg.init))  // StateInit
2302
            && cb.finalize_to(cell)                        // -> ^StateInit
2303
            && cb.store_long_bool(3, 2)                    // (just (right ... ))
2304
            && cb.store_ref_bool(std::move(cell))          // z:^StateInit
2305
            && cb.finalize_to(cell));
2306
      msg.init = vm::load_cell_slice_ref(cell);
2307
    } else {
2308
      redoing = 2;
2309
    }
2310
  }
2311
  if (redoing >= 2 && msg.body->size_ext() > 1 && msg.body->prefetch_ulong(1) == 0) {
2312
    LOG(DEBUG) << "moving the body of a suggested outbound message into a separate cell";
2313
    // body:(Either X ^X)
2314
    // transform (left x:X) into (right x:^X)
2315
    CHECK(msg.body.write().fetch_ulong(1) == 0);
2316
    vm::CellBuilder cb;
2317
    Ref<vm::Cell> cell;
2318
    CHECK(cb.append_cellslice_bool(std::move(msg.body))  // X
2319
          && cb.finalize_to(cell)                        // -> ^X
2320
          && cb.store_long_bool(1, 1)                    // (right ... )
2321
          && cb.store_ref_bool(std::move(cell))          // x:^X
2322
          && cb.finalize_to(cell));
2323
    msg.body = vm::load_cell_slice_ref(cell);
2324
  }
2325

2326
  block::gen::CommonMsgInfoRelaxed::Record_int_msg_info info;
2327
  bool ext_msg = msg.info->prefetch_ulong(1);
2328
  if (ext_msg) {
2329
    // ext_out_msg_info$11 constructor of CommonMsgInfoRelaxed
2330
    block::gen::CommonMsgInfoRelaxed::Record_ext_out_msg_info erec;
2331
    if (!tlb::csr_unpack(msg.info, erec)) {
2332
      return -1;
2333
    }
2334
    if (act_rec.mode & ~3) {
2335
      return -1;  // invalid mode for an external message
2336
    }
2337
    info.src = std::move(erec.src);
2338
    info.dest = std::move(erec.dest);
2339
    // created_lt and created_at are ignored
2340
    info.ihr_disabled = true;
2341
    info.bounce = false;
2342
    info.bounced = false;
2343
    fwd_fee = ihr_fee = td::zero_refint();
2344
  } else {
2345
    // int_msg_info$0 constructor
2346
    if (!tlb::csr_unpack(msg.info, info) || !block::tlb::t_CurrencyCollection.validate_csr(info.value)) {
2347
      return -1;
2348
    }
2349
    fwd_fee = block::tlb::t_Grams.as_integer(info.fwd_fee);
2350
    ihr_fee = block::tlb::t_Grams.as_integer(info.ihr_fee);
2351
  }
2352
  // set created_at and created_lt to correct values
2353
  info.created_at = now;
2354
  info.created_lt = ap.end_lt;
2355
  // always clear bounced flag
2356
  info.bounced = false;
2357
  // have to check source address
2358
  // it must be either our source address, or empty
2359
  if (!check_replace_src_addr(info.src)) {
2360
    LOG(DEBUG) << "invalid source address in a proposed outbound message";
2361
    return 35;  // invalid source address
2362
  }
2363
  bool to_mc = false;
2364
  if (!check_rewrite_dest_addr(info.dest, cfg, &to_mc)) {
2365
    LOG(DEBUG) << "invalid destination address in a proposed outbound message";
2366
    return skip_invalid ? 0 : 36;  // invalid destination address
2367
  }
2368

2369
  // fetch message pricing info
2370
  const MsgPrices& msg_prices = cfg.fetch_msg_prices(to_mc || account.is_masterchain());
2371
  // If action fails, account is required to pay fine_per_cell for every visited cell
2372
  // Number of visited cells is limited depending on available funds
2373
  unsigned max_cells = cfg.size_limits.max_msg_cells;
2374
  td::uint64 fine_per_cell = 0;
2375
  if (cfg.action_fine_enabled && !account.is_special) {
2376
    fine_per_cell = (msg_prices.cell_price >> 16) / 4;
2377
    td::RefInt256 funds = ap.remaining_balance.grams;
2378
    if (!ext_msg && !(act_rec.mode & 0x80) && !(act_rec.mode & 1)) {
2379
      if (!block::tlb::t_CurrencyCollection.validate_csr(info.value)) {
2380
        LOG(DEBUG) << "invalid value:CurrencyCollection in proposed outbound message";
2381
        return skip_invalid ? 0 : 37;
2382
      }
2383
      block::CurrencyCollection value;
2384
      CHECK(value.unpack(info.value));
2385
      CHECK(value.grams.not_null());
2386
      td::RefInt256 new_funds = value.grams;
2387
      if (act_rec.mode & 0x40) {
2388
        if (msg_balance_remaining.is_valid()) {
2389
          new_funds += msg_balance_remaining.grams;
2390
        }
2391
        if (compute_phase) {
2392
          new_funds -= compute_phase->gas_fees;
2393
        }
2394
        new_funds -= ap.action_fine;
2395
        if (new_funds->sgn() < 0) {
2396
          LOG(DEBUG)
2397
              << "not enough value to transfer with the message: all of the inbound message value has been consumed";
2398
          return skip_invalid ? 0 : 37;
2399
        }
2400
      }
2401
      funds = std::min(funds, new_funds);
2402
    }
2403
    if (funds->cmp(max_cells * fine_per_cell) < 0) {
2404
      max_cells = static_cast<unsigned>((funds / td::make_refint(fine_per_cell))->to_long());
2405
    }
2406
  }
2407
  // compute size of message
2408
  vm::CellStorageStat sstat(max_cells);  // for message size
2409
  // preliminary storage estimation of the resulting message
2410
  unsigned max_merkle_depth = 0;
2411
  auto add_used_storage = [&](const auto& x, unsigned skip_root_count) -> td::Status {
2412
    if (x.not_null()) {
2413
      TRY_RESULT(res, sstat.add_used_storage(x, true, skip_root_count));
2414
      max_merkle_depth = std::max(max_merkle_depth, res.max_merkle_depth);
2415
    }
2416
    return td::Status::OK();
2417
  };
2418
  add_used_storage(msg.init, 3);  // message init
2419
  add_used_storage(msg.body, 3);  // message body (the root cell itself is not counted)
2420
  if (!ext_msg) {
2421
    add_used_storage(info.value->prefetch_ref(), 0);
2422
  }
2423
  auto collect_fine = [&] {
2424
    if (cfg.action_fine_enabled && !account.is_special) {
2425
      td::uint64 fine = fine_per_cell * std::min<td::uint64>(max_cells, sstat.cells);
2426
      if (ap.remaining_balance.grams->cmp(fine) < 0) {
2427
        fine = ap.remaining_balance.grams->to_long();
2428
      }
2429
      ap.action_fine += fine;
2430
      ap.remaining_balance.grams -= fine;
2431
    }
2432
  };
2433
  if (sstat.cells > max_cells && max_cells < cfg.size_limits.max_msg_cells) {
2434
    LOG(DEBUG) << "not enough funds to process a message (max_cells=" << max_cells << ")";
2435
    collect_fine();
2436
    return skip_invalid ? 0 : 40;
2437
  }
2438
  if (sstat.bits > cfg.size_limits.max_msg_bits || sstat.cells > max_cells) {
2439
    LOG(DEBUG) << "message too large, invalid";
2440
    collect_fine();
2441
    return skip_invalid ? 0 : 40;
2442
  }
2443
  if (max_merkle_depth > max_allowed_merkle_depth) {
2444
    LOG(DEBUG) << "message has too big merkle depth, invalid";
2445
    collect_fine();
2446
    return skip_invalid ? 0 : 40;
2447
  }
2448
  LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
2449

2450
  // compute forwarding fees
2451
  auto fees_c = msg_prices.compute_fwd_ihr_fees(sstat.cells, sstat.bits, info.ihr_disabled);
2452
  LOG(DEBUG) << "computed fwd fees = " << fees_c.first << " + " << fees_c.second;
2453

2454
  if (account.is_special) {
2455
    LOG(DEBUG) << "computed fwd fees set to zero for special account";
2456
    fees_c.first = fees_c.second = 0;
2457
  }
2458

2459
  // set fees to computed values
2460
  if (fwd_fee->unsigned_fits_bits(63) && fwd_fee->to_long() < (long long)fees_c.first) {
2461
    fwd_fee = td::make_refint(fees_c.first);
2462
  }
2463
  if (fees_c.second && ihr_fee->unsigned_fits_bits(63) && ihr_fee->to_long() < (long long)fees_c.second) {
2464
    ihr_fee = td::make_refint(fees_c.second);
2465
  }
2466

2467
  Ref<vm::Cell> new_msg;
2468
  td::RefInt256 fees_collected, fees_total;
2469
  unsigned new_msg_bits;
2470

2471
  if (!ext_msg) {
2472
    // Process outbound internal message
2473
    // check value, check/compute ihr_fees, fwd_fees
2474
    // ...
2475
    if (!block::tlb::t_CurrencyCollection.validate_csr(info.value)) {
2476
      LOG(DEBUG) << "invalid value:CurrencyCollection in proposed outbound message";
2477
      collect_fine();
2478
      return skip_invalid ? 0 : 37;
2479
    }
2480
    if (info.ihr_disabled) {
2481
      // if IHR is disabled, IHR fees will be always zero
2482
      ihr_fee = td::zero_refint();
2483
    }
2484
    // extract value to be carried by the message
2485
    block::CurrencyCollection req;
2486
    CHECK(req.unpack(info.value));
2487
    CHECK(req.grams.not_null());
2488

2489
    if (act_rec.mode & 0x80) {
2490
      // attach all remaining balance to this message
2491
      req = ap.remaining_balance;
2492
      act_rec.mode &= ~1;  // pay fees from attached value
2493
    } else if (act_rec.mode & 0x40) {
2494
      // attach all remaining balance of the inbound message (in addition to the original value)
2495
      req += msg_balance_remaining;
2496
      if (!(act_rec.mode & 1)) {
2497
        req -= ap.action_fine;
2498
        if (compute_phase) {
2499
          req -= compute_phase->gas_fees;
2500
        }
2501
        if (!req.is_valid()) {
2502
          LOG(DEBUG)
2503
              << "not enough value to transfer with the message: all of the inbound message value has been consumed";
2504
          collect_fine();
2505
          return skip_invalid ? 0 : 37;
2506
        }
2507
      }
2508
    }
2509

2510
    // compute req_grams + fees
2511
    td::RefInt256 req_grams_brutto = req.grams;
2512
    fees_total = fwd_fee + ihr_fee;
2513
    if (act_rec.mode & 1) {
2514
      // we are going to pay the fees
2515
      req_grams_brutto += fees_total;
2516
    } else if (req.grams < fees_total) {
2517
      // receiver pays the fees (but cannot)
2518
      LOG(DEBUG) << "not enough value attached to the message to pay forwarding fees : have " << req.grams << ", need "
2519
                 << fees_total;
2520
      collect_fine();
2521
      return skip_invalid ? 0 : 37;  // not enough grams
2522
    } else {
2523
      // decrease message value
2524
      req.grams -= fees_total;
2525
    }
2526

2527
    // check that we have at least the required value
2528
    if (ap.remaining_balance.grams < req_grams_brutto) {
2529
      LOG(DEBUG) << "not enough grams to transfer with the message : remaining balance is "
2530
                 << ap.remaining_balance.to_str() << ", need " << req_grams_brutto << " (including forwarding fees)";
2531
      collect_fine();
2532
      return skip_invalid ? 0 : 37;  // not enough grams
2533
    }
2534

2535
    Ref<vm::Cell> new_extra;
2536

2537
    if (!block::sub_extra_currency(ap.remaining_balance.extra, req.extra, new_extra)) {
2538
      LOG(DEBUG) << "not enough extra currency to send with the message: "
2539
                 << block::CurrencyCollection{0, req.extra}.to_str() << " required, only "
2540
                 << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " available";
2541
      collect_fine();
2542
      return skip_invalid ? 0 : 38;  // not enough (extra) funds
2543
    }
2544
    if (ap.remaining_balance.extra.not_null() || req.extra.not_null()) {
2545
      LOG(DEBUG) << "subtracting extra currencies: "
2546
                 << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus "
2547
                 << block::CurrencyCollection{0, req.extra}.to_str() << " equals "
2548
                 << block::CurrencyCollection{0, new_extra}.to_str();
2549
    }
2550

2551
    auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee);
2552
    auto fwd_fee_remain = fwd_fee - fwd_fee_mine;
2553

2554
    // re-pack message value
2555
    CHECK(req.pack_to(info.value));
2556
    CHECK(block::tlb::t_Grams.pack_integer(info.fwd_fee, fwd_fee_remain));
2557
    CHECK(block::tlb::t_Grams.pack_integer(info.ihr_fee, ihr_fee));
2558

2559
    // serialize message
2560
    CHECK(tlb::csr_pack(msg.info, info));
2561
    vm::CellBuilder cb;
2562
    if (!tlb::type_pack(cb, block::gen::t_MessageRelaxed_Any, msg)) {
2563
      LOG(DEBUG) << "outbound message does not fit into a cell after rewriting";
2564
      if (redoing == 2) {
2565
        collect_fine();
2566
        return skip_invalid ? 0 : 39;
2567
      }
2568
      return -2;
2569
    }
2570

2571
    new_msg_bits = cb.size();
2572
    new_msg = cb.finalize();
2573

2574
    // clear msg_balance_remaining if it has been used
2575
    if (act_rec.mode & 0xc0) {
2576
      msg_balance_remaining.set_zero();
2577
    }
2578

2579
    // update balance
2580
    ap.remaining_balance -= req_grams_brutto;
2581
    ap.remaining_balance.extra = std::move(new_extra);
2582
    CHECK(ap.remaining_balance.is_valid());
2583
    CHECK(ap.remaining_balance.grams->sgn() >= 0);
2584
    fees_total = fwd_fee + ihr_fee;
2585
    fees_collected = fwd_fee_mine;
2586
  } else {
2587
    // external messages also have forwarding fees
2588
    if (ap.remaining_balance.grams < fwd_fee) {
2589
      LOG(DEBUG) << "not enough funds to pay for an outbound external message";
2590
      collect_fine();
2591
      return skip_invalid ? 0 : 37;  // not enough grams
2592
    }
2593
    // repack message
2594
    // ext_out_msg_info$11 constructor of CommonMsgInfo
2595
    block::gen::CommonMsgInfo::Record_ext_out_msg_info erec;
2596
    erec.src = info.src;
2597
    erec.dest = info.dest;
2598
    erec.created_at = info.created_at;
2599
    erec.created_lt = info.created_lt;
2600
    CHECK(tlb::csr_pack(msg.info, erec));
2601
    vm::CellBuilder cb;
2602
    if (!tlb::type_pack(cb, block::gen::t_MessageRelaxed_Any, msg)) {
2603
      LOG(DEBUG) << "outbound message does not fit into a cell after rewriting";
2604
      if (redoing == 2) {
2605
        collect_fine();
2606
        return (skip_invalid ? 0 : 39);
2607
      }
2608
      return -2;
2609
    }
2610

2611
    new_msg_bits = cb.size();
2612
    new_msg = cb.finalize();
2613

2614
    // update balance
2615
    ap.remaining_balance -= fwd_fee;
2616
    CHECK(ap.remaining_balance.is_valid());
2617
    CHECK(td::sgn(ap.remaining_balance.grams) >= 0);
2618
    fees_collected = fees_total = fwd_fee;
2619
  }
2620

2621
  if (!block::tlb::t_Message.validate_ref(new_msg)) {
2622
    LOG(ERROR) << "generated outbound message is not a valid (Message Any) according to hand-written check";
2623
    collect_fine();
2624
    return -1;
2625
  }
2626
  if (!block::gen::t_Message_Any.validate_ref(new_msg)) {
2627
    LOG(ERROR) << "generated outbound message is not a valid (Message Any) according to automated check";
2628
    block::gen::t_Message_Any.print_ref(std::cerr, new_msg);
2629
    vm::load_cell_slice(new_msg).print_rec(std::cerr);
2630
    collect_fine();
2631
    return -1;
2632
  }
2633
  if (verbosity > 2) {
2634
    std::cerr << "converted outbound message: ";
2635
    block::gen::t_Message_Any.print_ref(std::cerr, new_msg);
2636
  }
2637

2638
  ap.msgs_created++;
2639
  ap.end_lt++;
2640

2641
  ap.out_msgs.push_back(std::move(new_msg));
2642
  ap.total_action_fees += fees_collected;
2643
  ap.total_fwd_fees += fees_total;
2644

2645
  if ((act_rec.mode & 0xa0) == 0xa0) {
2646
    CHECK(ap.remaining_balance.is_zero());
2647
    ap.acc_delete_req = ap.reserved_balance.is_zero();
2648
  }
2649

2650
  ap.tot_msg_bits += sstat.bits + new_msg_bits;
2651
  ap.tot_msg_cells += sstat.cells + 1;
2652

2653
  return 0;
2654
}
2655

2656
/**
2657
 * Tries to reserve a currency an action phase.
2658
 *
2659
 * @param cs The cell slice containing the action data serialized as action_reserve_currency TLB-scheme.
2660
 * @param ap The action phase.
2661
 * @param cfg The action phase configuration.
2662
 *
2663
 * @returns 0 if the currency is successfully reserved, error code otherwise.
2664
 */
2665
int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) {
2666
  block::gen::OutAction::Record_action_reserve_currency rec;
2667
  if (!tlb::unpack_exact(cs, rec)) {
2668
    return -1;
2669
  }
2670
  if ((rec.mode & 16) && cfg.bounce_on_fail_enabled) {
2671
    rec.mode &= ~16;
2672
    ap.need_bounce_on_fail = true;
2673
  }
2674
  if (rec.mode & ~15) {
2675
    return -1;
2676
  }
2677
  int mode = rec.mode;
2678
  LOG(INFO) << "in try_action_reserve_currency(" << mode << ")";
2679
  CurrencyCollection reserve, newc;
2680
  if (!reserve.validate_unpack(std::move(rec.currency))) {
2681
    LOG(DEBUG) << "cannot parse currency field in action_reserve_currency";
2682
    return -1;
2683
  }
2684
  LOG(DEBUG) << "action_reserve_currency: mode=" << mode << ", reserve=" << reserve.to_str()
2685
             << ", balance=" << ap.remaining_balance.to_str() << ", original balance=" << original_balance.to_str();
2686
  if (mode & 4) {
2687
    if (mode & 8) {
2688
      reserve = original_balance - reserve;
2689
    } else {
2690
      reserve += original_balance;
2691
    }
2692
  } else if (mode & 8) {
2693
    LOG(DEBUG) << "invalid reserve mode " << mode;
2694
    return -1;
2695
  }
2696
  if (!reserve.is_valid() || td::sgn(reserve.grams) < 0) {
2697
    LOG(DEBUG) << "cannot reserve a negative amount: " << reserve.to_str();
2698
    return -1;
2699
  }
2700
  if (reserve.grams > ap.remaining_balance.grams) {
2701
    if (mode & 2) {
2702
      reserve.grams = ap.remaining_balance.grams;
2703
    } else {
2704
      LOG(DEBUG) << "cannot reserve " << reserve.grams << " nanograms : only " << ap.remaining_balance.grams
2705
                 << " available";
2706
      return 37;  // not enough grams
2707
    }
2708
  }
2709
  if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) {
2710
    LOG(DEBUG) << "not enough extra currency to reserve: " << block::CurrencyCollection{0, reserve.extra}.to_str()
2711
               << " required, only " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str()
2712
               << " available";
2713
    if (mode & 2) {
2714
      // TODO: process (mode & 2) correctly by setting res_extra := inf (reserve.extra, ap.remaining_balance.extra)
2715
    }
2716
    return 38;  // not enough (extra) funds
2717
  }
2718
  newc.grams = ap.remaining_balance.grams - reserve.grams;
2719
  if (mode & 1) {
2720
    // leave only res_grams, reserve everything else
2721
    std::swap(newc, reserve);
2722
  }
2723
  // set remaining_balance to new_grams and new_extra
2724
  ap.remaining_balance = std::move(newc);
2725
  // increase reserved_balance by res_grams and res_extra
2726
  ap.reserved_balance += std::move(reserve);
2727
  CHECK(ap.reserved_balance.is_valid());
2728
  CHECK(ap.remaining_balance.is_valid());
2729
  LOG(INFO) << "changed remaining balance to " << ap.remaining_balance.to_str() << ", reserved balance to "
2730
            << ap.reserved_balance.to_str();
2731
  ap.spec_actions++;
2732
  return 0;
2733
}
2734

2735
/**
2736
 * Calculates the number of public libraries in the dictionary.
2737
 *
2738
 * @param libraries The dictionary of account libraries.
2739
 *
2740
 * @returns The number of public libraries in the dictionary.
2741
 */
2742
static td::uint32 get_public_libraries_count(const td::Ref<vm::Cell>& libraries) {
2743
  td::uint32 count = 0;
2744
  vm::Dictionary dict{libraries, 256};
2745
  dict.check_for_each([&](td::Ref<vm::CellSlice> value, td::ConstBitPtr key, int) {
2746
    if (block::is_public_library(key, std::move(value))) {
2747
      ++count;
2748
    }
2749
    return true;
2750
  });
2751
  return count;
2752
}
2753

2754
/**
2755
 * Calculates the number of changes of public libraries in the dictionary.
2756
 *
2757
 * @param old_libraries The dictionary of account libraries before the transaction.
2758
 * @param new_libraries The dictionary of account libraries after the transaction.
2759
 *
2760
 * @returns The number of changed public libraries.
2761
 */
2762
static td::uint32 get_public_libraries_diff_count(const td::Ref<vm::Cell>& old_libraries,
2763
                                                  const td::Ref<vm::Cell>& new_libraries) {
2764
  td::uint32 count = 0;
2765
  vm::Dictionary dict1{old_libraries, 256};
2766
  vm::Dictionary dict2{new_libraries, 256};
2767
  dict1.scan_diff(dict2, [&](td::ConstBitPtr key, int n, Ref<vm::CellSlice> val1, Ref<vm::CellSlice> val2) -> bool {
2768
    CHECK(n == 256);
2769
    bool is_public1 = val1.not_null() && block::is_public_library(key, val1);
2770
    bool is_public2 = val2.not_null() && block::is_public_library(key, val2);
2771
    if (is_public1 != is_public2) {
2772
      ++count;
2773
    }
2774
    return true;
2775
  });
2776
  return count;
2777
}
2778

2779
/**
2780
 * Checks that the new account state fits in the limits.
2781
 * This function is not called for special accounts.
2782
 *
2783
 * @param size_limits The size limits configuration.
2784
 * @param update_storage_stat Store storage stat in the Transaction's CellStorageStat.
2785
 *
2786
 * @returns A `td::Status` indicating the result of the check.
2787
 *          - If the state limits are within the allowed range, returns OK.
2788
 *          - If the state limits exceed the maximum allowed range, returns an error.
2789
 */
2790
td::Status Transaction::check_state_limits(const SizeLimitsConfig& size_limits, bool update_storage_stat) {
2791
  auto cell_equal = [](const td::Ref<vm::Cell>& a, const td::Ref<vm::Cell>& b) -> bool {
2792
    if (a.is_null()) {
2793
      return b.is_null();
2794
    }
2795
    if (b.is_null()) {
2796
      return false;
2797
    }
2798
    return a->get_hash() == b->get_hash();
2799
  };
2800
  if (cell_equal(account.code, new_code) && cell_equal(account.data, new_data) &&
2801
      cell_equal(account.library, new_library)) {
2802
    return td::Status::OK();
2803
  }
2804
  vm::CellStorageStat storage_stat;
2805
  storage_stat.limit_cells = size_limits.max_acc_state_cells;
2806
  storage_stat.limit_bits = size_limits.max_acc_state_bits;
2807
  td::Timer timer;
2808
  auto add_used_storage = [&](const td::Ref<vm::Cell>& cell) -> td::Status {
2809
    if (cell.not_null()) {
2810
      TRY_RESULT(res, storage_stat.add_used_storage(cell));
2811
      if (res.max_merkle_depth > max_allowed_merkle_depth) {
2812
        return td::Status::Error("too big merkle depth");
2813
      }
2814
    }
2815
    return td::Status::OK();
2816
  };
2817
  TRY_STATUS(add_used_storage(new_code));
2818
  TRY_STATUS(add_used_storage(new_data));
2819
  TRY_STATUS(add_used_storage(new_library));
2820
  if (timer.elapsed() > 0.1) {
2821
    LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
2822
  }
2823
  if (acc_status == Account::acc_active) {
2824
    storage_stat.clear_limit();
2825
  } else {
2826
    storage_stat.clear();
2827
  }
2828
  td::Status res;
2829
  if (storage_stat.cells > size_limits.max_acc_state_cells || storage_stat.bits > size_limits.max_acc_state_bits) {
2830
    res = td::Status::Error(PSTRING() << "account state is too big");
2831
  } else if (account.is_masterchain() && !cell_equal(account.library, new_library) &&
2832
             get_public_libraries_count(new_library) > size_limits.max_acc_public_libraries) {
2833
    res = td::Status::Error("too many public libraries");
2834
  } else {
2835
    res = td::Status::OK();
2836
  }
2837
  if (update_storage_stat) {
2838
    // storage_stat will be reused in compute_state()
2839
    new_storage_stat = std::move(storage_stat);
2840
  }
2841
  return res;
2842
}
2843

2844
/**
2845
 * Prepares the bounce phase of a transaction.
2846
 *
2847
 * @param cfg The configuration for the action phase.
2848
 *
2849
 * @returns True if the bounce phase was successfully prepared, false otherwise.
2850
 */
2851
bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
2852
  if (in_msg.is_null() || !bounce_enabled) {
2853
    return false;
2854
  }
2855
  bounce_phase = std::make_unique<BouncePhase>();
2856
  BouncePhase& bp = *bounce_phase;
2857
  block::gen::Message::Record msg;
2858
  block::gen::CommonMsgInfo::Record_int_msg_info info;
2859
  auto cs = vm::load_cell_slice(in_msg);
2860
  if (!(tlb::unpack(cs, info) && gen::t_Maybe_Either_StateInit_Ref_StateInit.skip(cs) && cs.have(1) &&
2861
        cs.have_refs((int)cs.prefetch_ulong(1)))) {
2862
    bounce_phase.reset();
2863
    return false;
2864
  }
2865
  if (cs.fetch_ulong(1)) {
2866
    cs = vm::load_cell_slice(cs.prefetch_ref());
2867
  }
2868
  info.ihr_disabled = true;
2869
  info.bounce = false;
2870
  info.bounced = true;
2871
  std::swap(info.src, info.dest);
2872
  bool to_mc = false;
2873
  if (!check_rewrite_dest_addr(info.dest, cfg, &to_mc)) {
2874
    LOG(DEBUG) << "invalid destination address in a bounced message";
2875
    bounce_phase.reset();
2876
    return false;
2877
  }
2878
  // fetch message pricing info
2879
  const MsgPrices& msg_prices = cfg.fetch_msg_prices(to_mc || account.is_masterchain());
2880
  // compute size of message
2881
  vm::CellStorageStat sstat;  // for message size
2882
  // preliminary storage estimation of the resulting message
2883
  sstat.compute_used_storage(info.value->prefetch_ref());
2884
  bp.msg_bits = sstat.bits;
2885
  bp.msg_cells = sstat.cells;
2886
  // compute forwarding fees
2887
  bp.fwd_fees = msg_prices.compute_fwd_fees(sstat.cells, sstat.bits);
2888
  // check whether the message has enough funds
2889
  auto msg_balance = msg_balance_remaining;
2890
  if (compute_phase && compute_phase->gas_fees.not_null()) {
2891
    msg_balance.grams -= compute_phase->gas_fees;
2892
  }
2893
  if (action_phase && action_phase->action_fine.not_null()) {
2894
    msg_balance.grams -= action_phase->action_fine;
2895
  }
2896
  if ((msg_balance.grams < 0) ||
2897
      (msg_balance.grams->signed_fits_bits(64) && msg_balance.grams->to_long() < (long long)bp.fwd_fees)) {
2898
    // not enough funds
2899
    bp.nofunds = true;
2900
    return true;
2901
  }
2902
  // debit msg_balance_remaining from account's (tentative) balance
2903
  balance -= msg_balance;
2904
  CHECK(balance.is_valid());
2905
  // debit total forwarding fees from the message's balance, then split forwarding fees into our part and remaining part
2906
  msg_balance -= td::make_refint(bp.fwd_fees);
2907
  bp.fwd_fees_collected = msg_prices.get_first_part(bp.fwd_fees);
2908
  bp.fwd_fees -= bp.fwd_fees_collected;
2909
  total_fees += td::make_refint(bp.fwd_fees_collected);
2910
  // serialize outbound message
2911
  info.created_lt = end_lt++;
2912
  info.created_at = now;
2913
  vm::CellBuilder cb;
2914
  CHECK(cb.store_long_bool(5, 4)                            // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
2915
        && cb.append_cellslice_bool(info.src)               // src:MsgAddressInt
2916
        && cb.append_cellslice_bool(info.dest)              // dest:MsgAddressInt
2917
        && msg_balance.store(cb)                            // value:CurrencyCollection
2918
        && block::tlb::t_Grams.store_long(cb, 0)            // ihr_fee:Grams
2919
        && block::tlb::t_Grams.store_long(cb, bp.fwd_fees)  // fwd_fee:Grams
2920
        && cb.store_long_bool(info.created_lt, 64)          // created_lt:uint64
2921
        && cb.store_long_bool(info.created_at, 32)          // created_at:uint32
2922
        && cb.store_bool_bool(false));                      // init:(Maybe ...)
2923
  if (cfg.bounce_msg_body) {
2924
    int body_bits = std::min((int)cs.size(), cfg.bounce_msg_body);
2925
    if (cb.remaining_bits() >= body_bits + 33u) {
2926
      CHECK(cb.store_bool_bool(false)                             // body:(Either X ^X) -> left X
2927
            && cb.store_long_bool(-1, 32)                         // int = -1 ("message type")
2928
            && cb.append_bitslice(cs.prefetch_bits(body_bits)));  // truncated message body
2929
    } else {
2930
      vm::CellBuilder cb2;
2931
      CHECK(cb.store_bool_bool(true)                             // body:(Either X ^X) -> right ^X
2932
            && cb2.store_long_bool(-1, 32)                       // int = -1 ("message type")
2933
            && cb2.append_bitslice(cs.prefetch_bits(body_bits))  // truncated message body
2934
            && cb.store_builder_ref_bool(std::move(cb2)));       // ^X
2935
    }
2936
  } else {
2937
    CHECK(cb.store_bool_bool(false));  // body:(Either ..)
2938
  }
2939
  CHECK(cb.finalize_to(bp.out_msg));
2940
  if (verbosity > 2) {
2941
    LOG(INFO) << "generated bounced message: ";
2942
    block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg);
2943
  }
2944
  out_msgs.push_back(bp.out_msg);
2945
  bp.ok = true;
2946
  return true;
2947
}
2948
}  // namespace transaction
2949

2950
/*
2951
 * 
2952
 *  SERIALIZE PREPARED TRANSACTION
2953
 * 
2954
 */
2955

2956
/**
2957
 * Stores the account status in a CellBuilder object.
2958
 *
2959
 * @param cb The CellBuilder object to store the account status in.
2960
 * @param acc_status The account status to store.
2961
 *
2962
 * @returns True if the account status was successfully stored, false otherwise.
2963
 */
2964
bool Account::store_acc_status(vm::CellBuilder& cb, int acc_status) const {
2965
  int v;
2966
  switch (acc_status) {
2967
    case acc_nonexist:
2968
    case acc_deleted:
2969
      v = 3;  // acc_state_nonexist$11
2970
      break;
2971
    case acc_uninit:
2972
      v = 0;  // acc_state_uninit$00
2973
      break;
2974
    case acc_frozen:
2975
      v = 1;  // acc_state_frozen$01
2976
      break;
2977
    case acc_active:
2978
      v = 2;  // acc_state_active$10
2979
      break;
2980
    default:
2981
      return false;
2982
  }
2983
  return cb.store_long_bool(v, 2);
2984
}
2985

2986
/**
2987
 * Tries to update the storage statistics based on the old storage statistics and old account state without fully recomputing it.
2988
 * 
2989
 * It succeeds if only root cell of AccountStorage is changed.
2990
 *
2991
 * @param old_stat The old storage statistics.
2992
 * @param old_cs The old AccountStorage.
2993
 * @param new_cell The new AccountStorage.
2994
 *
2995
 * @returns An optional value of type vm::CellStorageStat. If the update is successful, it returns the new storage statistics. Otherwise, it returns an empty optional.
2996
 */
2997
static td::optional<vm::CellStorageStat> try_update_storage_stat(const vm::CellStorageStat& old_stat,
2998
                                                                 td::Ref<vm::CellSlice> old_cs,
2999
                                                                 td::Ref<vm::Cell> new_cell) {
3000
  if (old_stat.cells == 0 || old_cs.is_null()) {
3001
    return {};
3002
  }
3003
  vm::CellSlice new_cs = vm::CellSlice(vm::NoVm(), new_cell);
3004
  if (old_cs->size_refs() != new_cs.size_refs()) {
3005
    return {};
3006
  }
3007
  for (unsigned i = 0; i < old_cs->size_refs(); ++i) {
3008
    if (old_cs->prefetch_ref(i)->get_hash() != new_cs.prefetch_ref(i)->get_hash()) {
3009
      return {};
3010
    }
3011
  }
3012
  if (old_stat.bits < old_cs->size()) {
3013
    return {};
3014
  }
3015

3016
  vm::CellStorageStat new_stat;
3017
  new_stat.cells = old_stat.cells;
3018
  new_stat.bits = old_stat.bits - old_cs->size() + new_cs.size();
3019
  new_stat.public_cells = old_stat.public_cells;
3020
  return new_stat;
3021
}
3022

3023
namespace transaction {
3024
/**
3025
 * Computes the new state of the account.
3026
 *
3027
 * @returns True if the state computation is successful, false otherwise.
3028
 */
3029
bool Transaction::compute_state() {
3030
  if (new_total_state.not_null()) {
3031
    return true;
3032
  }
3033
  if (acc_status == Account::acc_uninit && !was_activated && balance.is_zero()) {
3034
    LOG(DEBUG) << "account is uninitialized and has zero balance, deleting it back";
3035
    acc_status = Account::acc_nonexist;
3036
    was_created = false;
3037
  }
3038
  if (acc_status == Account::acc_nonexist || acc_status == Account::acc_deleted) {
3039
    CHECK(balance.is_zero());
3040
    vm::CellBuilder cb;
3041
    CHECK(cb.store_long_bool(0, 1)  // account_none$0
3042
          && cb.finalize_to(new_total_state));
3043
    return true;
3044
  }
3045
  vm::CellBuilder cb;
3046
  CHECK(cb.store_long_bool(end_lt, 64)  // account_storage$_ last_trans_lt:uint64
3047
        && balance.store(cb));          // balance:CurrencyCollection
3048
  int ticktock = new_tick * 2 + new_tock;
3049
  unsigned si_pos = 0;
3050
  if (acc_status == Account::acc_uninit) {
3051
    CHECK(cb.store_long_bool(0, 2));  // account_uninit$00 = AccountState
3052
  } else if (acc_status == Account::acc_frozen) {
3053
    if (was_frozen) {
3054
      vm::CellBuilder cb2;
3055
      CHECK(account.split_depth_ ? cb2.store_long_bool(account.split_depth_ + 32, 6)  // _ ... = StateInit
3056
                                 : cb2.store_long_bool(0, 1));                        // ... split_depth:(Maybe (## 5))
3057
      CHECK(ticktock ? cb2.store_long_bool(ticktock | 4, 3) : cb2.store_long_bool(0, 1));  // special:(Maybe TickTock)
3058
      CHECK(cb2.store_maybe_ref(new_code) && cb2.store_maybe_ref(new_data) && cb2.store_maybe_ref(new_library));
3059
      // code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib)
3060
      auto frozen_state = cb2.finalize();
3061
      frozen_hash = frozen_state->get_hash().bits();
3062
      if (verbosity >= 3 * 1) {  // !!!DEBUG!!!
3063
        std::cerr << "freezing state of smart contract: ";
3064
        block::gen::t_StateInit.print_ref(std::cerr, frozen_state);
3065
        CHECK(block::gen::t_StateInit.validate_ref(frozen_state));
3066
        CHECK(block::tlb::t_StateInit.validate_ref(frozen_state));
3067
        std::cerr << "with hash " << frozen_hash.to_hex() << std::endl;
3068
      }
3069
    }
3070
    new_code.clear();
3071
    new_data.clear();
3072
    new_library.clear();
3073
    if (frozen_hash == account.addr_orig) {
3074
      // if frozen_hash equals account's "original" address (before rewriting), do not need storing hash
3075
      CHECK(cb.store_long_bool(0, 2));  // account_uninit$00 = AccountState
3076
    } else {
3077
      CHECK(cb.store_long_bool(1, 2)              // account_frozen$01
3078
            && cb.store_bits_bool(frozen_hash));  // state_hash:bits256
3079
    }
3080
  } else {
3081
    CHECK(acc_status == Account::acc_active && !was_frozen && !was_deleted);
3082
    si_pos = cb.size_ext() + 1;
3083
    CHECK(account.split_depth_ ? cb.store_long_bool(account.split_depth_ + 96, 7)      // account_active$1 _:StateInit
3084
                               : cb.store_long_bool(2, 2));                            // ... split_depth:(Maybe (## 5))
3085
    CHECK(ticktock ? cb.store_long_bool(ticktock | 4, 3) : cb.store_long_bool(0, 1));  // special:(Maybe TickTock)
3086
    CHECK(cb.store_maybe_ref(new_code) && cb.store_maybe_ref(new_data) && cb.store_maybe_ref(new_library));
3087
    // code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib)
3088
  }
3089
  auto storage = cb.finalize();
3090
  new_storage = td::Ref<vm::CellSlice>(true, vm::NoVm(), storage);
3091
  if (si_pos) {
3092
    auto cs_ref = load_cell_slice_ref(storage);
3093
    CHECK(cs_ref.unique_write().skip_ext(si_pos));
3094
    new_inner_state = std::move(cs_ref);
3095
  } else {
3096
    new_inner_state.clear();
3097
  }
3098
  vm::CellStorageStat& stats = new_storage_stat;
3099
  auto new_stats = try_update_storage_stat(account.storage_stat, account.storage, storage);
3100
  if (new_stats) {
3101
    stats = new_stats.unwrap();
3102
  } else {
3103
    td::Timer timer;
3104
    stats.add_used_storage(Ref<vm::Cell>(storage)).ensure();
3105
    if (timer.elapsed() > 0.1) {
3106
      LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
3107
    }
3108
  }
3109
  CHECK(cb.store_long_bool(1, 1)                       // account$1
3110
        && cb.append_cellslice_bool(account.my_addr)   // addr:MsgAddressInt
3111
        && block::store_UInt7(cb, stats.cells)         // storage_used$_ cells:(VarUInteger 7)
3112
        && block::store_UInt7(cb, stats.bits)          //   bits:(VarUInteger 7)
3113
        && block::store_UInt7(cb, stats.public_cells)  //   public_cells:(VarUInteger 7)
3114
        && cb.store_long_bool(last_paid, 32));         // last_paid:uint32
3115
  if (due_payment.not_null() && td::sgn(due_payment) != 0) {
3116
    CHECK(cb.store_long_bool(1, 1) && block::tlb::t_Grams.store_integer_ref(cb, due_payment));
3117
    // due_payment:(Maybe Grams)
3118
  } else {
3119
    CHECK(cb.store_long_bool(0, 1));
3120
  }
3121
  CHECK(cb.append_data_cell_bool(std::move(storage)));
3122
  new_total_state = cb.finalize();
3123
  if (verbosity > 2) {
3124
    std::cerr << "new account state: ";
3125
    block::gen::t_Account.print_ref(std::cerr, new_total_state);
3126
  }
3127
  CHECK(block::tlb::t_Account.validate_ref(new_total_state));
3128
  return true;
3129
}
3130

3131
/**
3132
 * Serializes the transaction object using Transaction TLB-scheme.
3133
 * 
3134
 * Updates root.
3135
 *
3136
 * @returns True if the serialization is successful, False otherwise.
3137
 */
3138
bool Transaction::serialize() {
3139
  if (root.not_null()) {
3140
    return true;
3141
  }
3142
  if (!compute_state()) {
3143
    return false;
3144
  }
3145
  vm::Dictionary dict{15};
3146
  for (unsigned i = 0; i < out_msgs.size(); i++) {
3147
    td::BitArray<15> key{i};
3148
    if (!dict.set_ref(key, out_msgs[i], vm::Dictionary::SetMode::Add)) {
3149
      return false;
3150
    }
3151
  }
3152
  vm::CellBuilder cb, cb2;
3153
  if (!(cb.store_long_bool(7, 4)                                             // transaction$0111
3154
        && cb.store_bits_bool(account.addr)                                  // account_addr:bits256
3155
        && cb.store_long_bool(start_lt)                                      // lt:uint64
3156
        && cb.store_bits_bool(account.last_trans_hash_)                      // prev_trans_hash:bits256
3157
        && cb.store_long_bool(account.last_trans_lt_, 64)                    // prev_trans_lt:uint64
3158
        && cb.store_long_bool(account.now_, 32)                              // now:uint32
3159
        && cb.store_ulong_rchk_bool(out_msgs.size(), 15)                     // outmsg_cnt:uint15
3160
        && account.store_acc_status(cb)                                      // orig_status:AccountStatus
3161
        && account.store_acc_status(cb, acc_status)                          // end_status:AccountStatus
3162
        && cb2.store_maybe_ref(in_msg)                                       // ^[ in_msg:(Maybe ^(Message Any)) ...
3163
        && std::move(dict).append_dict_to_bool(cb2)                          //    out_msgs:(HashmapE 15 ^(Message Any))
3164
        && cb.store_ref_bool(cb2.finalize())                                 // ]
3165
        && total_fees.store(cb)                                              // total_fees:CurrencyCollection
3166
        && cb2.store_long_bool(0x72, 8)                                      //   update_hashes#72
3167
        && cb2.store_bits_bool(account.total_state->get_hash().bits(), 256)  //   old_hash:bits256
3168
        && cb2.store_bits_bool(new_total_state->get_hash().bits(), 256)      //   new_hash:bits256
3169
        && cb.store_ref_bool(cb2.finalize()))) {                             // state_update:^(HASH_UPDATE Account)
3170
    return false;
3171
  }
3172

3173
  switch (trans_type) {
3174
    case tr_tick:  // fallthrough
3175
    case tr_tock: {
3176
      vm::CellBuilder cb3;
3177
      bool act = compute_phase->success;
3178
      bool act_ok = act && action_phase->success;
3179
      CHECK(cb2.store_long_bool(trans_type == tr_tick ? 2 : 3, 4)  // trans_tick_tock$000 is_tock:Bool
3180
            && serialize_storage_phase(cb2)                        // storage:TrStoragePhase
3181
            && serialize_compute_phase(cb2)                        // compute_ph:TrComputePhase
3182
            && cb2.store_bool_bool(act)                            // action:(Maybe
3183
            && (!act || (serialize_action_phase(cb3)               //   ^TrActionPhase)
3184
                         && cb2.store_ref_bool(cb3.finalize()))) &&
3185
            cb2.store_bool_bool(!act_ok)         // aborted:Bool
3186
            && cb2.store_bool_bool(was_deleted)  // destroyed:Bool
3187
            && cb.store_ref_bool(cb2.finalize()) && cb.finalize_to(root));
3188
      break;
3189
    }
3190
    case tr_ord: {
3191
      vm::CellBuilder cb3;
3192
      bool have_storage = (bool)storage_phase;
3193
      bool have_credit = (bool)credit_phase;
3194
      bool have_bounce = (bool)bounce_phase;
3195
      bool act = compute_phase->success;
3196
      bool act_ok = act && action_phase->success;
3197
      CHECK(cb2.store_long_bool(0, 4)                           // trans_ord$0000
3198
            && cb2.store_long_bool(!bounce_enabled, 1)          // credit_first:Bool
3199
            && cb2.store_bool_bool(have_storage)                // storage_ph:(Maybe
3200
            && (!have_storage || serialize_storage_phase(cb2))  //   TrStoragePhase)
3201
            && cb2.store_bool_bool(have_credit)                 // credit_ph:(Maybe
3202
            && (!have_credit || serialize_credit_phase(cb2))    //   TrCreditPhase)
3203
            && serialize_compute_phase(cb2)                     // compute_ph:TrComputePhase
3204
            && cb2.store_bool_bool(act)                         // action:(Maybe
3205
            && (!act || (serialize_action_phase(cb3) && cb2.store_ref_bool(cb3.finalize())))  //   ^TrActionPhase)
3206
            && cb2.store_bool_bool(!act_ok)                                                   // aborted:Bool
3207
            && cb2.store_bool_bool(have_bounce)                                               // bounce:(Maybe
3208
            && (!have_bounce || serialize_bounce_phase(cb2))                                  //   TrBouncePhase
3209
            && cb2.store_bool_bool(was_deleted)                                               // destroyed:Bool
3210
            && cb.store_ref_bool(cb2.finalize()) && cb.finalize_to(root));
3211
      break;
3212
    }
3213
    default:
3214
      return false;
3215
  }
3216
  if (verbosity >= 3 * 1) {
3217
    std::cerr << "new transaction: ";
3218
    block::gen::t_Transaction.print_ref(std::cerr, root);
3219
    vm::load_cell_slice(root).print_rec(std::cerr);
3220
  }
3221

3222
  if (!block::gen::t_Transaction.validate_ref(4096, root)) {
3223
    LOG(ERROR) << "newly-generated transaction failed to pass automated validation:";
3224
    vm::load_cell_slice(root).print_rec(std::cerr);
3225
    block::gen::t_Transaction.print_ref(std::cerr, root);
3226
    root.clear();
3227
    return false;
3228
  }
3229
  if (!block::tlb::t_Transaction.validate_ref(4096, root)) {
3230
    LOG(ERROR) << "newly-generated transaction failed to pass hand-written validation:";
3231
    vm::load_cell_slice(root).print_rec(std::cerr);
3232
    block::gen::t_Transaction.print_ref(std::cerr, root);
3233
    root.clear();
3234
    return false;
3235
  }
3236

3237
  return true;
3238
}
3239

3240
/**
3241
 * Serializes the storage phase of a transaction.
3242
 *
3243
 * @param cb The CellBuilder to store the serialized data.
3244
 *
3245
 * @returns True if the serialization is successful, false otherwise.
3246
 */
3247
bool Transaction::serialize_storage_phase(vm::CellBuilder& cb) {
3248
  if (!storage_phase) {
3249
    return false;
3250
  }
3251
  StoragePhase& sp = *storage_phase;
3252
  bool ok;
3253
  // tr_phase_storage$_ storage_fees_collected:Grams
3254
  if (sp.fees_collected.not_null()) {
3255
    ok = block::tlb::t_Grams.store_integer_ref(cb, sp.fees_collected);
3256
  } else {
3257
    ok = block::tlb::t_Grams.null_value(cb);
3258
  }
3259
  // storage_fees_due:(Maybe Grams)
3260
  ok &= block::store_Maybe_Grams_nz(cb, sp.fees_due);
3261
  // status_change:AccStatusChange
3262
  if (sp.deleted || sp.frozen) {
3263
    ok &= cb.store_long_bool(sp.deleted ? 3 : 2, 2);  // acst_frozen$10 acst_deleted$11
3264
  } else {
3265
    ok &= cb.store_long_bool(0, 1);  // acst_unchanged$0 = AccStatusChange
3266
  }
3267
  return ok;
3268
}
3269

3270
/**
3271
 * Serializes the credit phase of a transaction.
3272
 *
3273
 * @param cb The CellBuilder to store the serialized data.
3274
 *
3275
 * @returns True if the credit phase was successfully serialized, false otherwise.
3276
 */
3277
bool Transaction::serialize_credit_phase(vm::CellBuilder& cb) {
3278
  if (!credit_phase) {
3279
    return false;
3280
  }
3281
  CreditPhase& cp = *credit_phase;
3282
  // tr_phase_credit$_ due_fees_collected:(Maybe Grams) credit:CurrencyCollection
3283
  return block::store_Maybe_Grams_nz(cb, cp.due_fees_collected) && cp.credit.store(cb);
3284
}
3285

3286
/**
3287
 * Serializes the compute phase of a transaction.
3288
 *
3289
 * @param cb The CellBuilder to store the serialized data.
3290
 *
3291
 * @returns True if the serialization was successful, false otherwise.
3292
 */
3293
bool Transaction::serialize_compute_phase(vm::CellBuilder& cb) {
3294
  if (!compute_phase) {
3295
    return false;
3296
  }
3297
  ComputePhase& cp = *compute_phase;
3298
  switch (cp.skip_reason) {
3299
    // tr_compute_phase_skipped$0 reason:ComputeSkipReason;
3300
    case ComputePhase::sk_no_state:
3301
      return cb.store_long_bool(0, 3);  // cskip_no_state$00 = ComputeSkipReason;
3302
    case ComputePhase::sk_bad_state:
3303
      return cb.store_long_bool(1, 3);  // cskip_bad_state$01 = ComputeSkipReason;
3304
    case ComputePhase::sk_no_gas:
3305
      return cb.store_long_bool(2, 3);  // cskip_no_gas$10 = ComputeSkipReason;
3306
    case ComputePhase::sk_suspended:
3307
      return cb.store_long_bool(0b0110, 4);  // cskip_suspended$110 = ComputeSkipReason;
3308
    case ComputePhase::sk_none:
3309
      break;
3310
    default:
3311
      return false;
3312
  }
3313
  vm::CellBuilder cb2;
3314
  bool ok, credit = (cp.gas_credit != 0), exarg = (cp.exit_arg != 0);
3315
  ok = cb.store_long_bool(1, 1)                                   // tr_phase_compute_vm$1
3316
       && cb.store_long_bool(cp.success, 1)                       // success:Bool
3317
       && cb.store_long_bool(cp.msg_state_used, 1)                // msg_state_used:Bool
3318
       && cb.store_long_bool(cp.account_activated, 1)             // account_activated:Bool
3319
       && block::tlb::t_Grams.store_integer_ref(cb, cp.gas_fees)  // gas_fees:Grams
3320
       && block::store_UInt7(cb2, cp.gas_used)                    // ^[ gas_used:(VarUInteger 7)
3321
       && block::store_UInt7(cb2, cp.gas_limit)                   //    gas_limit:(VarUInteger 7)
3322
       && cb2.store_long_bool(credit, 1)                          //    gas_credit:(Maybe (VarUInteger 3))
3323
       && (!credit || block::tlb::t_VarUInteger_3.store_long(cb2, cp.gas_credit)) &&
3324
       cb2.store_long_rchk_bool(cp.mode, 8)      //    mode:int8
3325
       && cb2.store_long_bool(cp.exit_code, 32)  //    exit_code:int32
3326
       && cb2.store_long_bool(exarg, 1)          //    exit_arg:(Maybe int32)
3327
       && (!exarg || cb2.store_long_bool(cp.exit_arg, 32)) &&
3328
       cb2.store_ulong_rchk_bool(cp.vm_steps, 32)      //    vm_steps:uint32
3329
       && cb2.store_bits_bool(cp.vm_init_state_hash)   //    vm_init_state_hash:bits256
3330
       && cb2.store_bits_bool(cp.vm_final_state_hash)  //    vm_final_state_hash:bits256
3331
       && cb.store_ref_bool(cb2.finalize());           // ] = TrComputePhase
3332
  return ok;
3333
}
3334

3335
/**
3336
 * Serializes the action phase of a transaction.
3337
 *
3338
 * @param cb The CellBuilder to store the serialized data.
3339
 *
3340
 * @returns True if the serialization is successful, false otherwise.
3341
 */
3342
bool Transaction::serialize_action_phase(vm::CellBuilder& cb) {
3343
  if (!action_phase) {
3344
    return false;
3345
  }
3346
  ActionPhase& ap = *action_phase;
3347
  bool ok, arg = (ap.result_arg != 0);
3348
  ok = cb.store_long_bool(ap.success, 1)                                             // tr_phase_action$_ success:Bool
3349
       && cb.store_long_bool(ap.valid, 1)                                            // valid:Bool
3350
       && cb.store_long_bool(ap.no_funds, 1)                                         // no_funds:Bool
3351
       && cb.store_long_bool(ap.acc_status_change, (ap.acc_status_change >> 1) + 1)  // status_change:AccStatusChange
3352
       && block::store_Maybe_Grams_nz(cb, ap.total_fwd_fees)                         // total_fwd_fees:(Maybe Grams)
3353
       && block::store_Maybe_Grams_nz(cb, ap.total_action_fees)                      // total_action_fees:(Maybe Grams)
3354
       && cb.store_long_bool(ap.result_code, 32)                                     // result_code:int32
3355
       && cb.store_long_bool(arg, 1)                                                 // result_arg:(Maybe
3356
       && (!arg || cb.store_long_bool(ap.result_arg, 32))                            //    uint32)
3357
       && cb.store_ulong_rchk_bool(ap.tot_actions, 16)                               // tot_actions:uint16
3358
       && cb.store_ulong_rchk_bool(ap.spec_actions, 16)                              // spec_actions:uint16
3359
       && cb.store_ulong_rchk_bool(ap.skipped_actions, 16)                           // skipped_actions:uint16
3360
       && cb.store_ulong_rchk_bool(ap.msgs_created, 16)                              // msgs_created:uint16
3361
       && cb.store_bits_bool(ap.action_list_hash)                                    // action_list_hash:bits256
3362
       && block::store_UInt7(cb, ap.tot_msg_cells, ap.tot_msg_bits);                 // tot_msg_size:StorageUsed
3363
  return ok;
3364
}
3365

3366
/**
3367
 * Serializes the bounce phase of a transaction.
3368
 *
3369
 * @param cb The CellBuilder to store the serialized data.
3370
 *
3371
 * @returns True if the bounce phase was successfully serialized, false otherwise.
3372
 */
3373
bool Transaction::serialize_bounce_phase(vm::CellBuilder& cb) {
3374
  if (!bounce_phase) {
3375
    return false;
3376
  }
3377
  BouncePhase& bp = *bounce_phase;
3378
  if (!(bp.ok ^ bp.nofunds)) {
3379
    return false;
3380
  }
3381
  if (bp.nofunds) {
3382
    return cb.store_long_bool(1, 2)                              // tr_phase_bounce_nofunds$01
3383
           && block::store_UInt7(cb, bp.msg_cells, bp.msg_bits)  // msg_size:StorageUsed
3384
           && block::tlb::t_Grams.store_long(cb, bp.fwd_fees);   // req_fwd_fees:Grams
3385
  } else {
3386
    return cb.store_long_bool(1, 1)                                      // tr_phase_bounce_ok$1
3387
           && block::store_UInt7(cb, bp.msg_cells, bp.msg_bits)          // msg_size:StorageUsed
3388
           && block::tlb::t_Grams.store_long(cb, bp.fwd_fees_collected)  // msg_fees:Grams
3389
           && block::tlb::t_Grams.store_long(cb, bp.fwd_fees);           // fwd_fees:Grams
3390
  }
3391
}
3392

3393
/**
3394
 * Estimates the block storage profile increment if the transaction is added to the block.
3395
 *
3396
 * @param store_stat The current storage statistics of the block.
3397
 * @param usage_tree The usage tree of the block.
3398
 *
3399
 * @returns The estimated block storage profile increment.
3400
 *          Returns Error if the transaction is not serialized or if its new state is not computed.
3401
 */
3402
td::Result<vm::NewCellStorageStat::Stat> Transaction::estimate_block_storage_profile_incr(
3403
    const vm::NewCellStorageStat& store_stat, const vm::CellUsageTree* usage_tree) const {
3404
  if (root.is_null()) {
3405
    return td::Status::Error("Cannot estimate the size profile of a transaction before it is serialized");
3406
  }
3407
  if (new_total_state.is_null()) {
3408
    return td::Status::Error("Cannot estimate the size profile of a transaction before its new state is computed");
3409
  }
3410
  return store_stat.tentative_add_proof(new_total_state, usage_tree) + store_stat.tentative_add_cell(root);
3411
}
3412

3413
/**
3414
 * Updates the limits status of a block.
3415
 *
3416
 * @param blimst The block limit status object to update.
3417
 * @param with_size Flag indicating whether to update the size limits.
3418
 *
3419
 * @returns True if the limits were successfully updated, False otherwise.
3420
 */
3421
bool Transaction::update_limits(block::BlockLimitStatus& blimst, bool with_gas, bool with_size) const {
3422
  if (!(blimst.update_lt(end_lt) && blimst.update_gas(with_gas ? gas_used() : 0))) {
3423
    return false;
3424
  }
3425
  if (with_size) {
3426
    if (!(blimst.add_proof(new_total_state) && blimst.add_cell(root) && blimst.add_transaction() &&
3427
          blimst.add_account(is_first))) {
3428
      return false;
3429
    }
3430
    if (account.is_masterchain()) {
3431
      if (was_frozen || was_deleted) {
3432
        blimst.public_library_diff += get_public_libraries_count(account.orig_library);
3433
      } else {
3434
        blimst.public_library_diff += get_public_libraries_diff_count(account.orig_library, new_library);
3435
      }
3436
    }
3437
  }
3438
  return true;
3439
}
3440

3441
/*
3442
 * 
3443
 *  COMMIT TRANSACTION
3444
 * 
3445
 */
3446

3447
/**
3448
 * Commits a transaction for a given account.
3449
 *
3450
 * @param acc The account to commit the transaction for.
3451
 *
3452
 * @returns A reference to the root cell of the serialized transaction.
3453
 */
3454
Ref<vm::Cell> Transaction::commit(Account& acc) {
3455
  CHECK(account.last_trans_end_lt_ <= start_lt && start_lt < end_lt);
3456
  CHECK(root.not_null());
3457
  CHECK(new_total_state.not_null());
3458
  CHECK((const void*)&acc == (const void*)&account);
3459
  // export all fields modified by the Transaction into original account
3460
  // NB: this is the only method that modifies account
3461
  if (orig_addr_rewrite_set && new_split_depth >= 0 && acc.status != Account::acc_active &&
3462
      acc_status == Account::acc_active) {
3463
    LOG(DEBUG) << "setting address rewriting info for newly-activated account " << acc.addr.to_hex()
3464
               << " with split_depth=" << new_split_depth
3465
               << ", orig_addr_rewrite=" << orig_addr_rewrite.bits().to_hex(new_split_depth);
3466
    CHECK(acc.init_rewrite_addr(new_split_depth, orig_addr_rewrite.bits()));
3467
  }
3468
  acc.status = (acc_status == Account::acc_deleted ? Account::acc_nonexist : acc_status);
3469
  acc.last_trans_lt_ = start_lt;
3470
  acc.last_trans_end_lt_ = end_lt;
3471
  acc.last_trans_hash_ = root->get_hash().bits();
3472
  acc.last_paid = last_paid;
3473
  acc.storage_stat = new_storage_stat;
3474
  acc.storage = new_storage;
3475
  acc.balance = std::move(balance);
3476
  acc.due_payment = std::move(due_payment);
3477
  acc.total_state = std::move(new_total_state);
3478
  acc.inner_state = std::move(new_inner_state);
3479
  if (was_frozen) {
3480
    acc.state_hash = frozen_hash;
3481
  }
3482
  acc.my_addr = std::move(my_addr);
3483
  // acc.my_addr_exact = std::move(my_addr_exact);
3484
  acc.code = std::move(new_code);
3485
  acc.data = std::move(new_data);
3486
  acc.library = std::move(new_library);
3487
  if (acc.status == Account::acc_active) {
3488
    acc.tick = new_tick;
3489
    acc.tock = new_tock;
3490
  } else {
3491
    CHECK(acc.deactivate());
3492
  }
3493
  end_lt = 0;
3494
  acc.push_transaction(root, start_lt);
3495
  return root;
3496
}
3497

3498
/**
3499
 * Extracts the output message at the specified index from the transaction.
3500
 *
3501
 * @param i The index of the output message to extract.
3502
 *
3503
 * @returns A pair of the logical time and the extracted output message.
3504
 */
3505
LtCellRef Transaction::extract_out_msg(unsigned i) {
3506
  return {start_lt + i + 1, std::move(out_msgs.at(i))};
3507
}
3508

3509
/**
3510
 * Extracts the output message at index i from the transaction.
3511
 *
3512
 * @param i The index of the output message to extract.
3513
 *
3514
 * @returns A triple of the logical time, the extracted output message and the transaction root.
3515
 */
3516
NewOutMsg Transaction::extract_out_msg_ext(unsigned i) {
3517
  return {start_lt + i + 1, std::move(out_msgs.at(i)), root};
3518
}
3519

3520
/**
3521
 * Extracts the outgoing messages from the transaction and adds them to the given list.
3522
 *
3523
 * @param list The list to which the outgoing messages will be added.
3524
 */
3525
void Transaction::extract_out_msgs(std::vector<LtCellRef>& list) {
3526
  for (unsigned i = 0; i < out_msgs.size(); i++) {
3527
    list.emplace_back(start_lt + i + 1, std::move(out_msgs[i]));
3528
  }
3529
}
3530
}  // namespace transaction
3531

3532
/**
3533
 * Adds a transaction to the account's transaction list.
3534
 *
3535
 * @param trans_root The root of the transaction cell.
3536
 * @param trans_lt The logical time of the transaction.
3537
 */
3538
void Account::push_transaction(Ref<vm::Cell> trans_root, ton::LogicalTime trans_lt) {
3539
  transactions.emplace_back(trans_lt, std::move(trans_root));
3540
}
3541

3542
/**
3543
 * Serializes an account block for the account using AccountBlock TLB-scheme.
3544
 *
3545
 * @param cb The CellBuilder used to store the serialized data.
3546
 *
3547
 * @returns True if the account block was successfully created, false otherwise.
3548
 */
3549
bool Account::create_account_block(vm::CellBuilder& cb) {
3550
  if (transactions.empty()) {
3551
    return false;
3552
  }
3553
  if (!(cb.store_long_bool(5, 4)         // acc_trans#5
3554
        && cb.store_bits_bool(addr))) {  // account_addr:bits256
3555
    return false;
3556
  }
3557
  vm::AugmentedDictionary dict{64, block::tlb::aug_AccountTransactions};
3558
  for (auto& z : transactions) {
3559
    if (!dict.set_ref(td::BitArray<64>{(long long)z.first}, z.second, vm::Dictionary::SetMode::Add)) {
3560
      LOG(ERROR) << "error creating the list of transactions for account " << addr.to_hex()
3561
                 << " : cannot add transaction with lt=" << z.first;
3562
      return false;
3563
    }
3564
  }
3565
  Ref<vm::Cell> dict_root = std::move(dict).extract_root_cell();
3566
  // transactions:(HashmapAug 64 ^Transaction Grams)
3567
  if (dict_root.is_null() || !cb.append_cellslice_bool(vm::load_cell_slice(std::move(dict_root)))) {
3568
    return false;
3569
  }
3570
  vm::CellBuilder cb2;
3571
  return cb2.store_long_bool(0x72, 8)                                      // update_hashes#72
3572
         && cb2.store_bits_bool(orig_total_state->get_hash().bits(), 256)  // old_hash:bits256
3573
         && cb2.store_bits_bool(total_state->get_hash().bits(), 256)       // new_hash:bits256
3574
         && cb.store_ref_bool(cb2.finalize());                             // state_update:^(HASH_UPDATE Account)
3575
}
3576

3577
/**
3578
 * Checks if the libraries stored in the account object have changed.
3579
 *
3580
 * @returns True if the libraries have changed, False otherwise.
3581
 */
3582
bool Account::libraries_changed() const {
3583
  bool s = orig_library.not_null();
3584
  bool t = library.not_null();
3585
  if (s & t) {
3586
    return orig_library->get_hash() != library->get_hash();
3587
  } else {
3588
    return s != t;
3589
  }
3590
}
3591

3592
/**
3593
 * Fetches and initializes various configuration parameters from masterchain config for transaction processing.
3594
 *
3595
 * @param config The masterchain configuration.
3596
 * @param old_mparams Pointer to store a dictionary of mandatory parameters (ConfigParam 9).
3597
 * @param storage_prices Pointer to store the storage prices.
3598
 * @param storage_phase_cfg Pointer to store the storage phase configuration.
3599
 * @param rand_seed Pointer to the random seed. Generates a new seed if the value is `td::Bits256::zero()`.
3600
 * @param compute_phase_cfg Pointer to store the compute phase configuration.
3601
 * @param action_phase_cfg Pointer to store the action phase configuration.
3602
 * @param masterchain_create_fee Pointer to store the masterchain create fee.
3603
 * @param basechain_create_fee Pointer to store the basechain create fee.
3604
 * @param wc The workchain ID.
3605
 * @param now The current Unix time.
3606
 */
3607
td::Status FetchConfigParams::fetch_config_params(
3608
    const block::ConfigInfo& config, Ref<vm::Cell>* old_mparams, std::vector<block::StoragePrices>* storage_prices,
3609
    StoragePhaseConfig* storage_phase_cfg, td::BitArray<256>* rand_seed, ComputePhaseConfig* compute_phase_cfg,
3610
    ActionPhaseConfig* action_phase_cfg, td::RefInt256* masterchain_create_fee, td::RefInt256* basechain_create_fee,
3611
    ton::WorkchainId wc, ton::UnixTime now) {
3612
  auto prev_blocks_info = config.get_prev_blocks_info();
3613
  if (prev_blocks_info.is_error()) {
3614
    return prev_blocks_info.move_as_error_prefix(
3615
        td::Status::Error(-668, "cannot fetch prev blocks info from masterchain configuration: "));
3616
  }
3617
  return fetch_config_params(config, prev_blocks_info.move_as_ok(), old_mparams, storage_prices, storage_phase_cfg,
3618
                             rand_seed, compute_phase_cfg, action_phase_cfg, masterchain_create_fee,
3619
                             basechain_create_fee, wc, now);
3620
}
3621

3622
/**
3623
 * Fetches and initializes various configuration parameters from masterchain config for transaction processing.
3624
 *
3625
 * @param config The masterchain configuration.
3626
 * @param prev_blocks_info The tuple with information about previous blocks.
3627
 * @param old_mparams Pointer to store a dictionary of mandatory parameters (ConfigParam 9).
3628
 * @param storage_prices Pointer to store the storage prices.
3629
 * @param storage_phase_cfg Pointer to store the storage phase configuration.
3630
 * @param rand_seed Pointer to the random seed. Generates a new seed if the value is `td::Bits256::zero()`.
3631
 * @param compute_phase_cfg Pointer to store the compute phase configuration.
3632
 * @param action_phase_cfg Pointer to store the action phase configuration.
3633
 * @param masterchain_create_fee Pointer to store the masterchain create fee.
3634
 * @param basechain_create_fee Pointer to store the basechain create fee.
3635
 * @param wc The workchain ID.
3636
 * @param now The current Unix time.
3637
 */
3638
td::Status FetchConfigParams::fetch_config_params(
3639
    const block::Config& config, td::Ref<vm::Tuple> prev_blocks_info, Ref<vm::Cell>* old_mparams,
3640
    std::vector<block::StoragePrices>* storage_prices, StoragePhaseConfig* storage_phase_cfg,
3641
    td::BitArray<256>* rand_seed, ComputePhaseConfig* compute_phase_cfg, ActionPhaseConfig* action_phase_cfg,
3642
    td::RefInt256* masterchain_create_fee, td::RefInt256* basechain_create_fee, ton::WorkchainId wc,
3643
    ton::UnixTime now) {
3644
  *old_mparams = config.get_config_param(9);
3645
  {
3646
    auto res = config.get_storage_prices();
3647
    if (res.is_error()) {
3648
      return res.move_as_error();
3649
    }
3650
    *storage_prices = res.move_as_ok();
3651
  }
3652
  if (rand_seed->is_zero()) {
3653
    // generate rand seed
3654
    prng::rand_gen().strong_rand_bytes(rand_seed->data(), 32);
3655
    LOG(DEBUG) << "block random seed set to " << rand_seed->to_hex();
3656
  }
3657
  TRY_RESULT(size_limits, config.get_size_limits_config());
3658
  {
3659
    // compute compute_phase_cfg / storage_phase_cfg
3660
    auto cell = config.get_config_param(wc == ton::masterchainId ? 20 : 21);
3661
    if (cell.is_null()) {
3662
      return td::Status::Error(-668, "cannot fetch current gas prices and limits from masterchain configuration");
3663
    }
3664
    if (!compute_phase_cfg->parse_GasLimitsPrices(std::move(cell), storage_phase_cfg->freeze_due_limit,
3665
                                                  storage_phase_cfg->delete_due_limit)) {
3666
      return td::Status::Error(-668, "cannot unpack current gas prices and limits from masterchain configuration");
3667
    }
3668
    TRY_RESULT_PREFIX(mc_gas_prices, config.get_gas_limits_prices(true),
3669
                      "cannot unpack masterchain gas prices and limits: ");
3670
    compute_phase_cfg->mc_gas_prices = std::move(mc_gas_prices);
3671
    compute_phase_cfg->special_gas_full = config.get_global_version() >= 5;
3672
    storage_phase_cfg->enable_due_payment = config.get_global_version() >= 4;
3673
    storage_phase_cfg->global_version = config.get_global_version();
3674
    compute_phase_cfg->block_rand_seed = *rand_seed;
3675
    compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth;
3676
    compute_phase_cfg->global_config = config.get_root_cell();
3677
    compute_phase_cfg->global_version = config.get_global_version();
3678
    if (compute_phase_cfg->global_version >= 4) {
3679
      compute_phase_cfg->prev_blocks_info = std::move(prev_blocks_info);
3680
    }
3681
    if (compute_phase_cfg->global_version >= 6) {
3682
      compute_phase_cfg->unpacked_config_tuple = config.get_unpacked_config_tuple(now);
3683
    }
3684
    compute_phase_cfg->suspended_addresses = config.get_suspended_addresses(now);
3685
    compute_phase_cfg->size_limits = size_limits;
3686
    compute_phase_cfg->precompiled_contracts = config.get_precompiled_contracts_config();
3687
  }
3688
  {
3689
    // compute action_phase_cfg
3690
    block::gen::MsgForwardPrices::Record rec;
3691
    auto cell = config.get_config_param(24);
3692
    if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
3693
      return td::Status::Error(-668, "cannot fetch masterchain message transfer prices from masterchain configuration");
3694
    }
3695
    action_phase_cfg->fwd_mc =
3696
        block::MsgPrices{rec.lump_price,           rec.bit_price,          rec.cell_price, rec.ihr_price_factor,
3697
                         (unsigned)rec.first_frac, (unsigned)rec.next_frac};
3698
    cell = config.get_config_param(25);
3699
    if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
3700
      return td::Status::Error(-668, "cannot fetch standard message transfer prices from masterchain configuration");
3701
    }
3702
    action_phase_cfg->fwd_std =
3703
        block::MsgPrices{rec.lump_price,           rec.bit_price,          rec.cell_price, rec.ihr_price_factor,
3704
                         (unsigned)rec.first_frac, (unsigned)rec.next_frac};
3705
    action_phase_cfg->workchains = &config.get_workchain_list();
3706
    action_phase_cfg->bounce_msg_body = (config.has_capability(ton::capBounceMsgBody) ? 256 : 0);
3707
    action_phase_cfg->size_limits = size_limits;
3708
    action_phase_cfg->action_fine_enabled = config.get_global_version() >= 4;
3709
    action_phase_cfg->bounce_on_fail_enabled = config.get_global_version() >= 4;
3710
    action_phase_cfg->mc_blackhole_addr = config.get_burning_config().blackhole_addr;
3711
  }
3712
  {
3713
    // fetch block_grams_created
3714
    auto cell = config.get_config_param(14);
3715
    if (cell.is_null()) {
3716
      *basechain_create_fee = *masterchain_create_fee = td::zero_refint();
3717
    } else {
3718
      block::gen::BlockCreateFees::Record create_fees;
3719
      if (!(tlb::unpack_cell(cell, create_fees) &&
3720
            block::tlb::t_Grams.as_integer_to(create_fees.masterchain_block_fee, *masterchain_create_fee) &&
3721
            block::tlb::t_Grams.as_integer_to(create_fees.basechain_block_fee, *basechain_create_fee))) {
3722
        return td::Status::Error(-668, "cannot unpack BlockCreateFees from configuration parameter #14");
3723
      }
3724
    }
3725
  }
3726
  return td::Status::OK();
3727
}
3728

3729
}  // namespace block
3730

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

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

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

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