Ton

Форк
0
/
create-state.cpp 
954 строки · 35.8 Кб
1
/*
2
    This file is part of TON Blockchain source code.
3

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

9
    TON Blockchain 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 General Public License for more details.
13

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

17
    In addition, as a special exception, the copyright holders give permission
18
    to link the code of portions of this program with the OpenSSL library.
19
    You must obey the GNU General Public License in all respects for all
20
    of the code used other than OpenSSL. If you modify file(s) with this
21
    exception, you may extend this exception to your version of the file(s),
22
    but you are not obligated to do so. If you do not wish to do so, delete this
23
    exception statement from your version. If you delete this exception statement
24
    from all source files in the program, then also delete it here.
25

26
    Copyright 2017-2020 Telegram Systems LLP
27
*/
28
#include <cassert>
29
#include <algorithm>
30
#include <string>
31
#include <vector>
32
#include <iostream>
33
#include <sstream>
34
#include <fstream>
35
#include <memory>
36
#include <cstring>
37
#include <cstdlib>
38
#include <cmath>
39
#include <map>
40
#include <functional>
41
#include <limits>
42
#include <getopt.h>
43

44
#include "vm/stack.hpp"
45
#include "vm/boc.h"
46

47
#include "fift/Fift.h"
48
#include "fift/Dictionary.h"
49
#include "fift/SourceLookup.h"
50
#include "fift/IntCtx.h"
51
#include "fift/words.h"
52

53
#include "td/utils/logging.h"
54
#include "td/utils/misc.h"
55
#include "td/utils/Parser.h"
56
#include "td/utils/port/path.h"
57
#include "td/utils/port/signals.h"
58

59
#include "block.h"
60
#include "block-parse.h"
61
#include "block-auto.h"
62
#include "mc-config.h"
63
#include "git.h"
64

65
#if defined(_INTERNAL_COMPILE) || defined(_TONLIB_COMPILE)
66
#define WITH_TONLIB
67
#include "tonlib/keys/Mnemonic.h"
68
#endif
69

70
#define PDO(__op) \
71
  if (!(__op)) {  \
72
    ok = false;   \
73
  }
74
#define THRERR(__msg)            \
75
  if (!ok) {                     \
76
    throw fift::IntError{__msg}; \
77
  }
78
#define RETERR    \
79
  if (!ok) {      \
80
    return false; \
81
  }
82

83
using td::Ref;
84

85
int verbosity;
86

87
enum { wc_master = -1, wc_base = 0 };
88
constexpr int wc_undef = std::numeric_limits<int>::min();
89

90
int workchain_id = wc_undef;
91
int global_id = 0;
92

93
typedef td::BitArray<256> hash_t;
94

95
struct SmcDescr {
96
  hash_t addr;
97
  int split_depth;
98
  bool preinit_only;
99
  td::RefInt256 gram_balance;
100
  Ref<vm::DataCell> state_init;  // StateInit
101
  Ref<vm::DataCell> account;     // Account
102
  SmcDescr(const hash_t& _addr) : addr(_addr), split_depth(0), preinit_only(false) {
103
  }
104
};
105

106
std::map<hash_t, SmcDescr> smart_contracts;
107
td::RefInt256 total_smc_balance{true, 0}, max_total_smc_balance;
108

109
struct PublicLibDescr {
110
  Ref<vm::Cell> root;
111
  std::set<hash_t> publishers;
112
  PublicLibDescr(Ref<vm::Cell> _root) : root(std::move(_root)) {
113
  }
114
};
115

116
std::map<hash_t, PublicLibDescr> public_libraries;
117

118
hash_t config_addr;
119
Ref<vm::Cell> config_param_root;
120
bool config_addr_set;
121
vm::Dictionary config_dict{32};
122

123
ton::UnixTime now;
124

125
bool set_config_smc(const SmcDescr& smc) {
126
  if (config_addr_set || smc.preinit_only || workchain_id != wc_master || smc.split_depth) {
127
    return false;
128
  }
129
  vm::CellSlice cs = load_cell_slice(smc.state_init);
130
  bool ok = true;
131
  PDO(block::gen::t_Maybe_natwidth_5.skip(cs) && block::gen::t_Maybe_TickTock.skip(cs) &&
132
      block::gen::t_Maybe_Ref_Cell.skip(cs));
133
  RETERR;
134
  Ref<vm::Cell> data;
135
  PDO(cs.fetch_ulong(1) == 1 && cs.fetch_ref_to(data));
136
  THRERR("config smart contract must have non-empty data");
137
  vm::CellSlice cs2 = load_cell_slice(data);
138
  PDO(cs2.fetch_ref_to(data));
139
  THRERR("first reference in config smart contract data must point to initial configuration");
140
  PDO(block::valid_config_data(data, smc.addr));
141
  THRERR("invalid smart contract configuration data");
142
  config_addr = smc.addr;
143
  config_param_root = std::move(data);
144
  config_addr_set = true;
145
  if (verbosity > 2) {
146
    std::cerr << "set smart contract " << config_addr << " as the configuration smart contract with configuration:\n";
147
    load_cell_slice(config_param_root).print_rec(std::cerr);
148
  }
149
  return true;
150
}
151

152
void interpret_set_workchain(vm::Stack& stack) {
153
  workchain_id = stack.pop_smallint_range(0x7fffffff, -0x7fffffff);
154
}
155

156
void interpret_get_workchain(vm::Stack& stack) {
157
  stack.push_smallint(workchain_id);
158
}
159

160
void interpret_set_global_id(vm::Stack& stack) {
161
  global_id = stack.pop_smallint_range(0x7fffffff, -0x7fffffff);
162
}
163

164
void interpret_get_global_id(vm::Stack& stack) {
165
  stack.push_smallint(global_id);
166
}
167

168
void interpret_get_verbosity(vm::Stack& stack) {
169
  stack.push_smallint(GET_VERBOSITY_LEVEL());
170
}
171

172
void interpret_set_verbosity(vm::Stack& stack) {
173
  int x = stack.pop_smallint_range(15);
174
  SET_VERBOSITY_LEVEL(x);
175
}
176

177
void interpret_set_config_smartcontract(vm::Stack& stack) {
178
  if (workchain_id != wc_master) {
179
    throw fift::IntError{"configuration smart contract may be selected in masterchain only"};
180
  }
181
  if (config_addr_set) {
182
    throw fift::IntError{"configuration smart contract already selected"};
183
  }
184
  td::RefInt256 int_addr = stack.pop_int_finite();
185
  hash_t addr;
186
  if (!int_addr->export_bits(addr.bits(), 256, false)) {
187
    throw fift::IntError{"not a valid smart-contract address"};
188
  }
189
  auto it = smart_contracts.find(addr);
190
  if (it == smart_contracts.end()) {
191
    throw fift::IntError{"unknown smart contract"};
192
  }
193
  const SmcDescr& smc = it->second;
194
  assert(smc.addr == addr);
195
  if (smc.preinit_only) {
196
    throw fift::IntError{"configuration smart contract must be completely initialized"};
197
  }
198
  if (!set_config_smc(smc)) {
199
    throw fift::IntError{"invalid configuration smart contract"};
200
  }
201
}
202

203
bool is_empty_cell(Ref<vm::Cell> cell) {
204
  bool is_special;
205
  auto cs = load_cell_slice_special(std::move(cell), is_special);
206
  return !is_special && cs.empty_ext();
207
}
208

209
bool add_public_library(hash_t lib_addr, hash_t smc_addr, Ref<vm::Cell> lib_root) {
210
  if (lib_root.is_null() || lib_root->get_hash().as_array() != lib_addr.as_array()) {
211
    return false;
212
  }
213
  auto ins = public_libraries.emplace(lib_addr, lib_root);
214
  PublicLibDescr& lib = ins.first->second;
215
  lib.publishers.insert(smc_addr);
216
  if (verbosity > 2) {
217
    std::cerr << "added " << (ins.second ? "new " : "") << "public library " << lib_addr << " with publisher "
218
              << smc_addr << std::endl;
219
  }
220
  return true;
221
}
222

223
td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, Ref<vm::Cell> data,
224
                                   Ref<vm::Cell> library, td::RefInt256 balance, int special, int split_depth,
225
                                   int mode) {
226
  if (is_empty_cell(code)) {
227
    code.clear();
228
  }
229
  if (is_empty_cell(data)) {
230
    data.clear();
231
  }
232
  if (is_empty_cell(library)) {
233
    library.clear();
234
  }
235
  bool ok = true;
236
  if (library.not_null()) {
237
    PDO(block::valid_library_collection(library, false));
238
    THRERR("not a valid library collection");
239
  }
240
  vm::CellBuilder cb;
241
  if (!split_depth) {
242
    PDO(cb.store_long_bool(0, 1));
243
  } else {
244
    PDO(cb.store_long_bool(1, 1) && cb.store_ulong_rchk_bool(split_depth, 5));
245
  }
246
  THRERR("invalid split_depth for a smart contract");
247
  if (!special) {
248
    PDO(cb.store_long_bool(0, 1));
249
  } else {
250
    PDO(cb.store_long_bool(1, 1) && cb.store_ulong_rchk_bool(special, 2));
251
  }
252
  THRERR("invalid special TickTock argument for a smart contract");
253
  PDO(cb.store_maybe_ref(std::move(code)) && cb.store_maybe_ref(std::move(data)) && cb.store_maybe_ref(library));
254
  THRERR("cannot store smart-contract code, data or library");
255
  Ref<vm::DataCell> state_init = cb.finalize();
256
  hash_t addr;
257
  if (smc_addr.is_null()) {
258
    addr = state_init->get_hash().as_array();
259
    smc_addr = td::RefInt256{true};
260
    PDO(smc_addr.write().import_bits(addr.data(), 0, 256, false));
261
  } else if (mode == 1) {
262
    throw fift::IntError{"cannot create uninitialized smart contracts with specified addresses"};
263
  } else {
264
    PDO(smc_addr->export_bits(addr.data(), 0, 256, false));
265
  }
266
  THRERR("cannot initialize smart-contract address");
267
  if (verbosity > 2) {
268
    std::cerr << "smart-contract address is ";
269
    std::cerr << addr << " = " << smc_addr << std::endl;
270
  }
271
  PDO(mode || !sgn(balance));
272
  THRERR("cannot set non-zero balance to smart contract unless it is initialized");
273
  PDO(sgn(balance) >= 0);
274
  THRERR("balance cannot be negative");
275
  if (!mode) {
276
    if (verbosity > 2) {
277
      std::cerr << "StateInit used for computing address: ";
278
      block::gen::t_StateInit.print_ref(std::cerr, state_init);
279
    }
280
    return smc_addr;  // compute address only
281
  }
282
  auto it = smart_contracts.find(addr);
283
  if (it != smart_contracts.end()) {
284
    std::cerr << "smart contract " << addr << " already defined\n";
285
    throw fift::IntError{"smart contract already exists"};
286
  }
287
  auto ins = smart_contracts.emplace(addr, addr);
288
  assert(ins.second);
289
  SmcDescr& smc = ins.first->second;
290
  smc.split_depth = split_depth;
291
  smc.preinit_only = (mode == 1);
292
  smc.gram_balance = balance;
293
  total_smc_balance += balance;
294
  if (mode > 1) {
295
    smc.state_init = std::move(state_init);
296
  }
297
  if (max_total_smc_balance.not_null() && total_smc_balance > max_total_smc_balance) {
298
    throw fift::IntError{"total smart-contract balance exceeds limit"};
299
  }
300
  cb.reset();
301
  PDO(cb.store_long_bool(0, 64)                                 // account_storage$_ last_trans_lt:uint64
302
      && block::tlb::t_Grams.store_integer_value(cb, *balance)  // balance.grams:Grams
303
      && cb.store_long_bool(0, 1));                             // balance.other:ExtraCurrencyCollection
304
  if (mode == 1) {
305
    PDO(block::gen::t_AccountState.pack_account_uninit(cb));
306
  } else {
307
    PDO(block::gen::t_AccountState.pack_account_active(cb, vm::load_cell_slice_ref(smc.state_init)));
308
  }
309
  THRERR("cannot create smart-contract AccountStorage");
310
  Ref<vm::DataCell> storage = cb.finalize();
311
  vm::CellStorageStat stats;
312
  PDO(stats.compute_used_storage(Ref<vm::Cell>(storage)).is_ok());
313
  if (verbosity > 2) {
314
    std::cerr << "storage is:\n";
315
    vm::load_cell_slice(storage).print_rec(std::cerr);
316
    std::cerr << "stats: bits=" << stats.bits << ", cells=" << stats.cells << std::endl;
317
    std::cerr << "block::gen::AccountStorage.validate_ref() = " << block::gen::t_AccountStorage.validate_ref(storage)
318
              << std::endl;
319
    std::cerr << "block::tlb::AccountStorage.validate_ref() = " << block::tlb::t_AccountStorage.validate_ref(storage)
320
              << std::endl;
321
  }
322
  PDO(block::gen::t_AccountStorage.validate_ref(storage));
323
  THRERR("AccountStorage of created smart-contract is invalid (?)");
324
  cb.reset();                     // build Account
325
  PDO(cb.store_long_bool(1, 1));  // account$1
326
  int ctor = 3;                   // addr_var$11
327
  if (workchain_id >= -128 && workchain_id <= 127) {
328
    ctor = 2;  // addr_std$10
329
  }
330
  PDO(cb.store_long_bool(ctor, 2));  // addr_std$10 or addr_var$11
331
  if (split_depth) {
332
    PDO(cb.store_long_bool(1, 1)                            // just$1
333
        && cb.store_ulong_rchk_bool(split_depth, 5)         // depth:(## 5)
334
        && cb.store_bits_bool(addr.cbits(), split_depth));  // rewrite pfx:(depth * Bit)
335
  } else {
336
    PDO(cb.store_long_bool(0, 1));  // nothing$0
337
  }
338
  PDO(cb.store_long_rchk_bool(workchain_id, ctor == 2 ? 8 : 32) && cb.store_bits_bool(addr.cbits(), 256));
339
  THRERR("Cannot serialize addr:MsgAddressInt of the new smart contract");
340
  // storage_stat:StorageInfo -> storage_stat.used:StorageUsed
341
  PDO(block::store_UInt7(cb, stats.cells)              // cells:(VarUInteger 7)
342
      && block::store_UInt7(cb, stats.bits)            // bits:(VarUInteger 7)
343
      && block::store_UInt7(cb, stats.public_cells));  // public_cells:(VarUInteger 7)
344
  THRERR("Cannot serialize used:StorageUsed of the new smart contract");
345
  PDO(cb.store_long_bool(0, 33));          // last_paid:uint32 due_payment:(Maybe Grams)
346
  PDO(cb.append_data_cell_bool(storage));  // storage:AccountStorage
347
  THRERR("Cannot create Account of the new smart contract");
348
  smc.account = cb.finalize();
349
  if (verbosity > 2) {
350
    std::cerr << "account is:\n";
351
    vm::load_cell_slice(smc.account).print_rec(std::cerr);
352
    std::cerr << "block::gen::Account.validate_ref() = " << block::gen::t_Account.validate_ref(smc.account)
353
              << std::endl;
354
    std::cerr << "block::tlb::Account.validate_ref() = " << block::tlb::t_Account.validate_ref(smc.account)
355
              << std::endl;
356
  }
357
  PDO(block::gen::t_Account.validate_ref(smc.account));
358
  THRERR("Account of created smart contract is invalid (?)");
359
  if (library.not_null()) {
360
    vm::Dictionary dict{std::move(library), 256};
361
    ok &= dict.check_for_each([addr](Ref<vm::CellSlice> cs, td::ConstBitPtr key, int n) -> bool {
362
      return !cs->prefetch_ulong(1) || add_public_library(key, addr, cs->prefetch_ref());
363
    });
364
    THRERR("Error processing libraries published by new smart contract");
365
  }
366
  return smc_addr;
367
}
368

369
// stores accounts:ShardAccounts
370
bool store_accounts(vm::CellBuilder& cb) {
371
  vm::AugmentedDictionary dict{256, block::tlb::aug_ShardAccounts};
372
  for (const auto& smc_pair : smart_contracts) {
373
    const SmcDescr& smc = smc_pair.second;
374
    CHECK(smc_pair.first == smc.addr);
375
    vm::CellBuilder cb;
376
    bool ok = cb.store_ref_bool(smc.account)     // account_descr$_ acc:^Account
377
              && cb.store_zeroes_bool(256 + 64)  // last_trans_hash:bits256 last_trans_lt:uint64
378
              && dict.set_builder(smc.addr.cbits(), 256, cb, vm::Dictionary::SetMode::Add);
379
    CHECK(ok);
380
  }
381
  return std::move(dict).append_dict_to_bool(cb);
382
}
383

384
// stores libraries:(HashmapE 256 LibDescr)
385
bool store_public_libraries(vm::CellBuilder& cb) {
386
  vm::Dictionary dict{256};
387
  bool ok = true;
388
  vm::CellBuilder empty_cb;
389
  for (const auto& lib_pair : public_libraries) {
390
    const PublicLibDescr pl = lib_pair.second;
391
    PDO(pl.root->get_hash().as_array() == lib_pair.first.as_array());
392
    vm::Dictionary publishers{256};
393
    for (const auto& publisher : pl.publishers) {
394
      PDO(publishers.set_builder(publisher.cbits(), 256, empty_cb, vm::Dictionary::SetMode::Add));
395
    }
396
    Ref<vm::Cell> root = std::move(publishers).extract_root_cell();
397
    PDO(root.not_null());
398
    THRERR("public library has an empty or invalid set of publishers");
399
    vm::CellBuilder value_cb;  // LibDescr
400
    PDO(value_cb.store_long_bool(0, 2) && value_cb.store_ref_bool(pl.root) &&
401
        value_cb.append_cellslice_bool(vm::load_cell_slice(std::move(root))));
402
    THRERR("cannot create LibDescr for a public library");
403
    PDO(dict.set_builder(lib_pair.first.cbits(), 256, value_cb, vm::Dictionary::SetMode::Add));
404
    THRERR("cannot insert LibDescr of a public library into the public library collection");
405
  }
406
  PDO(std::move(dict).append_dict_to_bool(cb));
407
  return ok;
408
}
409

410
// stores config:ConfigParams
411
bool store_config_params(vm::CellBuilder& cb) {
412
  return config_addr_set && config_param_root.not_null() &&
413
         cb.store_bits_bool(config_addr.cbits(), 256)  // _ config_addr:bits256
414
         && cb.store_ref_bool(config_param_root);      // config:^(Hashmap 32 ^Cell)
415
}
416

417
// stores hash of initial masterchain validator set computed from configuration parameter 34
418
bool store_validator_list_hash(vm::CellBuilder& cb) {
419
  Ref<vm::Cell> vset_cell = config_dict.lookup_ref(td::BitArray<32>{34});
420
  auto res = block::Config::unpack_validator_set(std::move(vset_cell));
421
  if (res.is_error()) {
422
    LOG(ERROR) << "cannot unpack current validator set: " << res.move_as_error().to_string();
423
    return false;
424
  }
425
  auto vset = res.move_as_ok();
426
  LOG_CHECK(vset) << "unpacked validator set is empty";
427
  auto ccvc = block::Config::unpack_catchain_validators_config(config_dict.lookup_ref(td::BitArray<32>{28}));
428
  ton::ShardIdFull shard{ton::masterchainId};
429
  auto nodes = block::Config::do_compute_validator_set(ccvc, shard, *vset, now, 0);
430
  LOG_CHECK(!nodes.empty()) << "validator node list in unpacked validator set is empty";
431
  auto vset_hash = block::compute_validator_set_hash(0, shard, std::move(nodes));
432
  LOG(DEBUG) << "initial validator set hash is " << vset_hash;
433
  return cb.store_long_bool(vset_hash, 32);
434
}
435

436
// stores custom:(Maybe ^McStateExtra)
437
bool store_custom(vm::CellBuilder& cb) {
438
  if (workchain_id != wc_master) {
439
    return cb.store_long_bool(0, 1);  // nothing
440
  }
441
  vm::CellBuilder cb2, cb3;
442
  bool ok = true;
443
  PDO(cb2.store_long_bool(0xcc26, 16)        // masterchain_state_extra#cc26
444
      && cb2.store_long_bool(0, 1)           // shard_hashes:ShardHashes = (HashmapE 32 ^(BinTree ShardDescr))
445
      && store_config_params(cb2)            // config:ConfigParams
446
      && cb3.store_long_bool(0, 16)          // ^[ flags:(## 16) { flags = 0 }
447
      && store_validator_list_hash(cb3)      //   validator_list_hash_short:uint32
448
      && cb3.store_long_bool(0, 32)          //   catchain_seqno:uint32
449
      && cb3.store_bool_bool(true)           //   nx_cc_updated:Bool
450
      && cb3.store_zeroes_bool(1 + 65)       //   prev_blocks:OldMcBlocksInfo
451
      && cb3.store_long_bool(2, 1 + 1)       //   after_key_block:Bool last_key_block:(Maybe ...)
452
      && cb2.store_ref_bool(cb3.finalize())  // ]
453
      && block::CurrencyCollection{total_smc_balance}.store(cb2)  // global_balance:CurrencyCollection
454
      && cb.store_long_bool(1, 1)                                 // just
455
      && cb.store_ref_bool(cb2.finalize()));
456
  return ok;
457
}
458

459
Ref<vm::Cell> create_state() {
460
  vm::CellBuilder cb, cb2;
461
  now = static_cast<ton::UnixTime>(time(0));
462
  bool ok = true;
463
  PDO(workchain_id != wc_undef);
464
  THRERR("workchain_id is unset, cannot generate state");
465
  PDO(workchain_id != wc_master || config_addr_set);
466
  THRERR("configuration smart contract must be selected");
467
  PDO(cb.store_long_bool(0x9023afe2, 32)      // shard_state#9023afe2
468
      && cb.store_long_bool(global_id, 32));  // global_id:int32
469
  PDO(cb.store_long_bool(0, 8) && cb.store_long_bool(workchain_id, 32) &&
470
      cb.store_long_bool(0, 64)                                   // shard_id:ShardIdent
471
      && cb.store_long_bool(0, 32)                                // seq_no:#
472
      && cb.store_zeroes_bool(32)                                 // vert_seq_no:#
473
      && cb.store_long_bool(now, 32)                              // gen_utime:uint32
474
      && cb.store_zeroes_bool(64)                                 // gen_lt:uint64
475
      && cb.store_ones_bool(32)                                   // min_ref_mc_seqno:uint32
476
      && cb2.store_zeroes_bool(1 + 64 + 2)                        // OutMsgQueueInfo
477
      && cb.store_ref_bool(cb2.finalize())                        // out_msg_queue_info:^OutMsgQueueInfo
478
      && cb.store_long_bool(0, 1)                                 // before_split:Bool
479
      && store_accounts(cb2)                                      // accounts:^ShardAccounts
480
      && cb.store_ref_bool(cb2.finalize())                        // ...
481
      && cb2.store_zeroes_bool(128)                               // ^[ overload_history:uint64 underload_history:uint64
482
      && block::CurrencyCollection{total_smc_balance}.store(cb2)  //   total_balance:CurrencyCollection
483
      && block::tlb::t_CurrencyCollection.null_value(cb2)         //   total_validator_fees:CurrencyCollection
484
      && store_public_libraries(cb2)                              //   libraries:(Hashmap 256 LibDescr)
485
      && cb2.store_long_bool(0, 1)                                //   master_ref:(Maybe BlkMasterInfo)
486
      && cb.store_ref_bool(cb2.finalize())                        // ]
487
      && store_custom(cb));                                       // custom:(Maybe ^McStateExtra)
488
  THRERR("cannot create blockchain state");
489
  Ref<vm::Cell> cell = cb.finalize();
490
  if (verbosity > 2) {
491
    std::cerr << "shard_state is:\n";
492
    vm::load_cell_slice(cell).print_rec(std::cerr);
493
    std::cerr << "pretty-printed shard_state is:\n";
494
    block::gen::t_ShardState.print_ref(std::cerr, cell);
495
    std::cerr << "\n";
496
    std::cerr << "block::gen::ShardState.validate_ref() = " << block::gen::t_ShardState.validate_ref(cell) << std::endl;
497
    std::cerr << "block::tlb::ShardState.validate_ref() = " << block::tlb::t_ShardState.validate_ref(cell) << std::endl;
498
    block::gen::ShardStateUnsplit::Record data;
499
    bool ok1 = tlb::unpack_cell(cell, data);
500
    std::cerr << "block::gen::ShardState.unpack_cell() = " << ok1 << std::endl;
501
    if (ok1) {
502
      std::cerr << "shard_id = " << data.shard_id
503
                << "; out_msg_queue_info = " << load_cell_slice(data.out_msg_queue_info)
504
                << "; total_balance = " << data.r1.total_balance << std::endl;
505
    }
506
  }
507
  PDO(block::gen::t_ShardState.validate_ref(cell));
508
  PDO(block::tlb::t_ShardState.validate_ref(cell));
509
  THRERR("created an invalid ShardState record");
510
  return cell;
511
}
512

513
// code (cell)
514
// data (cell)
515
// library (cell)
516
// balance (int)
517
// split_depth (int 0..32)
518
// special (int 0..3, +2 = tick, +1 = tock)
519
// [ address (uint256) ]
520
// mode (0 = compute address only, 1 = create uninit, 2 = create complete; +4 = with specified address)
521
// --> 256-bit address
522
void interpret_register_smartcontract(vm::Stack& stack) {
523
  if (workchain_id == wc_undef) {
524
    throw fift::IntError{"cannot register a smartcontract unless the workchain is specified first"};
525
  }
526
  td::RefInt256 spec_addr;
527
  int mode = stack.pop_smallint_range(2 + 4);  // allowed modes: 0 1 2 4 5 6
528
  if (mode == 3) {
529
    throw fift::IntError{"invalid mode"};
530
  }
531
  if (mode & 4) {
532
    spec_addr = stack.pop_int_finite();
533
    mode &= ~4;
534
  }
535
  int special = stack.pop_smallint_range(3);
536
  if (special && workchain_id != wc_master) {
537
    throw fift::IntError{"cannot create special smartcontracts outside of the masterchain"};
538
  }
539
  int split_depth = stack.pop_smallint_range(32);
540
  td::RefInt256 balance = stack.pop_int_finite();
541
  if (sgn(balance) < 0) {
542
    throw fift::IntError{"initial balance of a smartcontract cannot be negative"};
543
  }
544
  if (sgn(balance) > 0 && !mode) {
545
    throw fift::IntError{"cannot set non-zero balance if an account is not created"};
546
  }
547
  Ref<vm::Cell> library = stack.pop_cell();
548
  Ref<vm::Cell> data = stack.pop_cell();
549
  Ref<vm::Cell> code = stack.pop_cell();
550
  td::RefInt256 addr = create_smartcontract(std::move(spec_addr), std::move(code), std::move(data), std::move(library),
551
                                            std::move(balance), special, split_depth, mode);
552
  if (addr.is_null()) {
553
    throw fift::IntError{"internal error while creating smartcontract"};
554
  }
555
  stack.push(std::move(addr));
556
}
557

558
void interpret_create_state(vm::Stack& stack) {
559
  if (!global_id) {
560
    throw fift::IntError{
561
        "(global) blockchain id must be set to a non-zero value: negative for test chains, positive for production"};
562
  }
563
  Ref<vm::Cell> state = create_state();
564
  if (state.is_null()) {
565
    throw fift::IntError{"could not create blockchain state"};
566
  }
567
  stack.push(std::move(state));
568
}
569

570
void interpret_get_config_dict(vm::Stack& stack) {
571
  Ref<vm::Cell> value = config_dict.get_root_cell();
572
  if (value.is_null()) {
573
    stack.push_bool(false);
574
  } else {
575
    stack.push_cell(std::move(value));
576
    stack.push_bool(true);
577
  }
578
}
579

580
void interpret_get_config_param(vm::Stack& stack) {
581
  int x = stack.pop_smallint_range(0x7fffffff, 0x80000000);
582
  Ref<vm::Cell> value = config_dict.lookup_ref(td::BitArray<32>{x});
583
  if (value.is_null()) {
584
    stack.push_bool(false);
585
  } else {
586
    stack.push_cell(std::move(value));
587
    stack.push_bool(true);
588
  }
589
}
590

591
void interpret_set_config_param(vm::Stack& stack) {
592
  int x = stack.pop_smallint_range(0x7fffffff, 0x80000000);
593
  Ref<vm::Cell> value = stack.pop_cell();
594
  if (verbosity > 2 && x >= 0) {
595
    std::cerr << "setting configuration parameter #" << x << " to ";
596
    // vm::load_cell_slice(value).print_rec(std::cerr);
597
    block::gen::ConfigParam{x}.print_ref(std::cerr, value);
598
    std::cerr << std::endl;
599
  }
600
  if (x >= 0 && !block::gen::ConfigParam{x}.validate_ref(value)) {
601
    throw fift::IntError{"invalid value for indicated configuration parameter"};
602
  }
603
  if (!config_dict.set_ref(td::BitArray<32>{x}, std::move(value))) {
604
    throw fift::IntError{"cannot set value of configuration parameter (value too long?)"};
605
  }
606
}
607

608
void interpret_check_config_param(vm::Stack& stack) {
609
  int x = stack.pop_smallint_range(0x7fffffff, 0x80000000);
610
  Ref<vm::Cell> value = stack.pop_cell();
611
  if (verbosity > 2 && x >= 0) {
612
    std::cerr << "checking validity as configuration parameter #" << x << " of ";
613
    // vm::load_cell_slice(value).print_rec(std::cerr);
614
    block::gen::ConfigParam{x}.print_ref(std::cerr, value);
615
    std::cerr << std::endl;
616
  }
617
  stack.push_bool(x < 0 || block::gen::ConfigParam{x}.validate_ref(value));
618
}
619

620
void interpret_is_shard_state(vm::Stack& stack) {
621
  Ref<vm::Cell> cell = stack.pop_cell();
622
  if (verbosity > 4) {
623
    std::cerr << "custom shard state is:\n";
624
    vm::load_cell_slice(cell).print_rec(std::cerr);
625
    std::cerr << "pretty-printed custom shard state is:\n";
626
    block::gen::t_ShardState.print_ref(std::cerr, cell);
627
  }
628
  stack.push_bool(block::gen::t_ShardState.validate_ref(std::move(cell)));
629
}
630

631
void interpret_is_workchain_descr(vm::Stack& stack) {
632
  Ref<vm::Cell> cell = stack.pop_cell();
633
  if (verbosity > 4) {
634
    std::cerr << "WorkchainDescr is:\n";
635
    vm::load_cell_slice(cell).print_rec(std::cerr);
636
    std::cerr << "pretty-printed WorkchainDescr is:\n";
637
    block::gen::t_WorkchainDescr.print_ref(std::cerr, cell);
638
  }
639
  stack.push_bool(block::gen::t_WorkchainDescr.validate_ref(std::move(cell)));
640
}
641

642
void interpret_add_extra_currencies(vm::Stack& stack) {
643
  Ref<vm::Cell> y = stack.pop_maybe_cell(), x = stack.pop_maybe_cell(), res;
644
  bool ok = block::add_extra_currency(std::move(x), std::move(y), res);
645
  if (ok) {
646
    stack.push_maybe_cell(std::move(res));
647
  }
648
  stack.push_bool(ok);
649
}
650

651
void interpret_sub_extra_currencies(vm::Stack& stack) {
652
  Ref<vm::Cell> y = stack.pop_maybe_cell(), x = stack.pop_maybe_cell(), res;
653
  bool ok = block::sub_extra_currency(std::move(x), std::move(y), res);
654
  if (ok) {
655
    stack.push_maybe_cell(std::move(res));
656
  }
657
  stack.push_bool(ok);
658
}
659

660
void interpret_allocated_balance(vm::Stack& stack) {
661
  stack.push_int(total_smc_balance);
662
}
663

664
#ifdef WITH_TONLIB
665
void interpret_mnemonic_to_privkey(vm::Stack& stack, int mode) {
666
  td::SecureString str{td::Slice{stack.pop_string()}};
667
  auto res = tonlib::Mnemonic::create(std::move(str), td::SecureString());
668
  if (res.is_error()) {
669
    throw fift::IntError{res.move_as_error().to_string()};
670
  }
671
  auto privkey = res.move_as_ok().to_private_key();
672
  td::SecureString key;
673
  if (mode & 1) {
674
    auto pub = privkey.get_public_key();
675
    key = pub.move_as_ok().as_octet_string();
676
  } else {
677
    key = privkey.as_octet_string();
678
  }
679
  stack.push_bytes(key.as_slice());
680
}
681
#endif
682

683
void init_words_custom(fift::Dictionary& d) {
684
  using namespace std::placeholders;
685
  d.def_stack_word("verb@ ", interpret_get_verbosity);
686
  d.def_stack_word("verb! ", interpret_set_verbosity);
687
  d.def_stack_word("wcid@ ", interpret_get_workchain);
688
  d.def_stack_word("wcid! ", interpret_set_workchain);
689
  d.def_stack_word("globalid@ ", interpret_get_global_id);
690
  d.def_stack_word("globalid! ", interpret_set_global_id);
691
  d.def_stack_word("config@ ", interpret_get_config_param);
692
  d.def_stack_word("config! ", interpret_set_config_param);
693
  d.def_stack_word("config-valid? ", interpret_check_config_param);
694
  d.def_stack_word("(configdict) ", interpret_get_config_dict);
695
  d.def_stack_word("register_smc ", interpret_register_smartcontract);
696
  d.def_stack_word("set_config_smc ", interpret_set_config_smartcontract);
697
  d.def_stack_word("create_state ", interpret_create_state);
698
  d.def_stack_word("isShardState? ", interpret_is_shard_state);
699
  d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr);
700
  d.def_stack_word("CC+? ", interpret_add_extra_currencies);
701
  d.def_stack_word("CC-? ", interpret_sub_extra_currencies);
702
  d.def_stack_word("allocated-balance ", interpret_allocated_balance);
703
#ifdef WITH_TONLIB
704
  d.def_stack_word("mnemo>priv ", std::bind(interpret_mnemonic_to_privkey, _1, 0));
705
  d.def_stack_word("mnemo>pub ", std::bind(interpret_mnemonic_to_privkey, _1, 1));
706
#endif
707
}
708

709
tlb::TypenameLookup tlb_dict;
710

711
// ( S -- T -1 or 0 )  Looks up TLB type by name
712
void interpret_tlb_type_lookup(vm::Stack& stack) {
713
  auto ptr = tlb_dict.lookup(stack.pop_string());
714
  if (ptr) {
715
    stack.push_make_object<tlb::TlbTypeHolder>(ptr);
716
  }
717
  stack.push_bool(ptr);
718
}
719

720
td::Ref<tlb::TlbTypeHolder> pop_tlb_type(vm::Stack& stack) {
721
  auto res = stack.pop_object<tlb::TlbTypeHolder>();
722
  if (res.is_null()) {
723
    throw vm::VmError{vm::Excno::type_chk, "not a TLB type"};
724
  }
725
  return res;
726
}
727

728
// ( T -- S )  Gets TLB type name
729
void interpret_tlb_type_name(vm::Stack& stack) {
730
  stack.push_string((*pop_tlb_type(stack))->get_type_name());
731
}
732

733
// ( T -- )  Prints TLB type name
734
void interpret_print_tlb_type(vm::Stack& stack) {
735
  std::cout << (*pop_tlb_type(stack))->get_type_name();
736
}
737

738
// ( s T -- )  Dumps (part of) slice s as a value of TLB type T
739
void interpret_tlb_dump_as(vm::Stack& stack) {
740
  auto tp = pop_tlb_type(stack);
741
  (*tp)->print(std::cout, stack.pop_cellslice());
742
}
743

744
// ( s T -- s' S -1 or 0 )
745
// Detects prefix of slice s that is a value of TLB type T, returns the remainder as s', and prints the value into String S.
746
void interpret_tlb_dump_to_str(vm::Stack& stack) {
747
  auto tp = pop_tlb_type(stack);
748
  auto cs = stack.pop_cellslice();
749
  std::ostringstream os;
750
  bool ok = (*tp)->print_skip(os, cs.write());
751
  if (ok) {
752
    stack.push(std::move(cs));
753
    stack.push_string(os.str());
754
  }
755
  stack.push_bool(ok);
756
}
757

758
// ( s T -- s' -1 or 0 )   Skips the only prefix of slice s that can be a value of TLB type T
759
void interpret_tlb_skip(vm::Stack& stack) {
760
  auto tp = pop_tlb_type(stack);
761
  auto cs = stack.pop_cellslice();
762
  bool ok = (*tp)->skip(cs.write());
763
  if (ok) {
764
    stack.push(std::move(cs));
765
  }
766
  stack.push_bool(ok);
767
}
768

769
// ( s T -- s' -1 or 0 )  Checks whether a prefix of slice s is a valid value of TLB type T, and skips it
770
void interpret_tlb_validate_skip(vm::Stack& stack) {
771
  auto tp = pop_tlb_type(stack);
772
  auto cs = stack.pop_cellslice();
773
  bool ok = (*tp)->validate_skip_upto(1048576, cs.write());
774
  if (ok) {
775
    stack.push(std::move(cs));
776
  }
777
  stack.push_bool(ok);
778
}
779

780
void interpret_tlb_type_const(vm::Stack& stack, const tlb::TLB* ptr) {
781
  stack.push_make_object<tlb::TlbTypeHolder>(ptr);
782
}
783

784
void init_words_tlb(fift::Dictionary& d) {
785
  using namespace std::placeholders;
786
  tlb_dict.register_types(block::gen::register_simple_types);
787
  d.def_stack_word("tlb-type-lookup ", interpret_tlb_type_lookup);
788
  d.def_stack_word("tlb-type-name ", interpret_tlb_type_name);
789
  d.def_stack_word("tlb. ", interpret_print_tlb_type);
790
  d.def_stack_word("tlb-dump-as ", interpret_tlb_dump_as);
791
  d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str);
792
  d.def_stack_word("tlb-skip ", interpret_tlb_skip);
793
  d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip);
794
  d.def_stack_word("ExtraCurrencyCollection",
795
                   std::bind(interpret_tlb_type_const, _1, &block::tlb::t_ExtraCurrencyCollection));
796
}
797

798
void usage(const char* progname) {
799
  std::cerr
800
      << "Creates initial state for a TON blockchain, using configuration defined by Fift-language source files\n";
801
  std::cerr
802
      << "usage: " << progname
803
      << " [-i] [-n] [-I <source-include-path>] {-L <library-fif-file>} <source-file1-fif> <source-file2-fif> ...\n";
804
  std::cerr << "\t-n\tDo not preload preamble files `Fift.fif` and `CreateState.fif`\n"
805
               "\t-i\tForce interactive mode even if explicit source file names are indicated\n"
806
               "\t-I<source-search-path>\tSets colon-separated library source include path. If not indicated, "
807
               "$FIFTPATH is used instead.\n"
808
               "\t-L<library-fif-file>\tPre-loads a library source file\n"
809
               "\t-v<verbosity-level>\tSet verbosity level\n"
810
               "\t-V<version>\tShow create-state build information\n";
811
  std::exit(2);
812
}
813

814
void parse_include_path_set(std::string include_path_set, std::vector<std::string>& res) {
815
  td::Parser parser(include_path_set);
816
  while (!parser.empty()) {
817
    #if TD_WINDOWS
818
    auto path_separator = '@';
819
    #else
820
    auto path_separator = ':';
821
    #endif
822
    auto path = parser.read_till_nofail(path_separator);
823
    if (!path.empty()) {
824
      res.push_back(path.str());
825
    }
826
    parser.skip_nofail(path_separator);
827
  }
828
}
829

830
void preload_preamble(fift::Fift& fift, std::string filename, bool standard = true) {
831
  auto status = fift.interpret_file(filename, "");
832
  if (status.is_error()) {
833
    LOG(ERROR) << "Error interpreting " << (standard ? "standard" : "application-specific") << " preamble file `"
834
               << filename << "`: " << status.error().message()
835
               << "\nCheck that correct include path is set by -I or by FIFTPATH environment variable, or disable "
836
                  "standard preamble by -n.\n";
837
    std::exit(2);
838
  }
839
}
840

841
int main(int argc, char* const argv[]) {
842
  td::set_default_failure_signal_handler().ensure();
843
  bool interactive = false;
844
  bool fift_preload = true, no_env = false, script_mode = false;
845
  std::vector<std::string> library_source_files, source_list;
846
  std::vector<std::string> source_include_path;
847
  std::string ton_db_path;
848

849
  fift::Fift::Config config;
850

851
  int i;
852
  int new_verbosity_level = VERBOSITY_NAME(INFO);
853
  while (!script_mode && (i = getopt(argc, argv, "hinsI:L:v:V")) != -1) {
854
    switch (i) {
855
      case 'i':
856
        interactive = true;
857
        break;
858
      case 'n':
859
        fift_preload = false;
860
        break;
861
      case 'I':
862
        LOG(ERROR) << source_include_path;
863
        parse_include_path_set(optarg, source_include_path);
864
        no_env = true;
865
        break;
866
      case 's':
867
        script_mode = true;
868
        break;
869
      case 'L':
870
        library_source_files.emplace_back(optarg);
871
        break;
872
      case 'v':
873
        new_verbosity_level = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer<int>(td::Slice(optarg)));
874
        break;
875
      case 'V':
876
        std::cout << "create-state build information: [ Commit: " << GitMetadata::CommitSHA1()
877
                  << ", Date: " << GitMetadata::CommitDate() << "]\n";
878
        std::exit(0);
879
        break;
880
      case 'h':
881
      default:
882
        usage(argv[0]);
883
    }
884
  }
885
  SET_VERBOSITY_LEVEL(new_verbosity_level);
886

887
  while (optind < argc) {
888
    source_list.emplace_back(argv[optind++]);
889
    if (script_mode) {
890
      break;
891
    }
892
  }
893

894
  if (!no_env) {
895
    const char* path = std::getenv("FIFTPATH");
896
    if (path) {
897
      parse_include_path_set(path ? path : "/usr/lib/fift", source_include_path);
898
    }
899
  }
900
  std::string current_dir;
901
  auto r_current_dir = td::realpath(".");
902
  if (r_current_dir.is_ok()) {
903
    current_dir = r_current_dir.move_as_ok();
904
    source_include_path.push_back(current_dir);
905
  }
906
  config.source_lookup = fift::SourceLookup(std::make_unique<fift::OsFileLoader>());
907
  for (auto& path : source_include_path) {
908
    config.source_lookup.add_include_path(path);
909
  }
910

911
  fift::init_words_common(config.dictionary);
912
  fift::init_words_vm(config.dictionary);
913
  fift::init_words_ton(config.dictionary);
914
  init_words_custom(config.dictionary);
915
  init_words_tlb(config.dictionary);
916

917
  if (script_mode) {
918
    fift::import_cmdline_args(config.dictionary, source_list.empty() ? "" : source_list[0], argc - optind,
919
                              argv + optind);
920
  }
921

922
  fift::Fift fift(std::move(config));
923

924
  if (fift_preload) {
925
    preload_preamble(fift, "Fift.fif", true);
926
    preload_preamble(fift, "CreateState.fif", false);
927
  }
928

929
  for (auto source : library_source_files) {
930
    auto status = fift.interpret_file(source, "");
931
    if (status.is_error()) {
932
      std::cerr << "Error interpreting preloaded file `" << source << "`: " << status.error().to_string() << std::endl;
933
      std::exit(2);
934
    }
935
  }
936

937
  if (source_list.empty() && !interactive) {
938
    std::cerr << "No Fift source files specified" << std::endl;
939
    std::exit(2);
940
  }
941

942
  for (const auto& source : source_list) {
943
    auto status = fift.interpret_file(source, current_dir);
944
    if (status.is_error()) {
945
      std::cerr << "Error interpreting file `" << source << "`: " << status.error().to_string() << std::endl;
946
      std::exit(2);
947
    }
948
  }
949

950
  if (interactive) {
951
    fift.interpret_istream(std::cin, current_dir).ensure();
952
  }
953
  // show_total_cells();
954
}
955

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

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

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

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