@@ -1290,11 +1290,13 @@ int output_actions_count(Ref<vm::Cell> list) {
1290
1290
/* *
1291
1291
* Unpacks the message StateInit.
1292
1292
*
1293
+ * @param cfg The configuration for the compute phase.
1293
1294
* @param lib_only If true, only unpack libraries from the state.
1295
+ * @param forbid_public_libs Don't allow public libraries in initstate.
1294
1296
*
1295
1297
* @returns True if the unpacking is successful, false otherwise.
1296
1298
*/
1297
- bool Transaction::unpack_msg_state (bool lib_only) {
1299
+ bool Transaction::unpack_msg_state (const ComputePhaseConfig& cfg, bool lib_only, bool forbid_public_libs ) {
1298
1300
block::gen::StateInit::Record state;
1299
1301
if (in_msg_state.is_null () || !tlb::unpack_cell (in_msg_state, state)) {
1300
1302
LOG (ERROR) << " cannot unpack StateInit from an inbound message" ;
@@ -1318,9 +1320,22 @@ bool Transaction::unpack_msg_state(bool lib_only) {
1318
1320
new_tock = z & 1 ;
1319
1321
LOG (DEBUG) << " tick=" << new_tick << " , tock=" << new_tock;
1320
1322
}
1323
+ td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
1321
1324
new_code = state.code ->prefetch_ref ();
1322
1325
new_data = state.data ->prefetch_ref ();
1323
1326
new_library = state.library ->prefetch_ref ();
1327
+ auto size_limits = cfg.size_limits ;
1328
+ if (forbid_public_libs) {
1329
+ size_limits.max_acc_public_libraries = 0 ;
1330
+ }
1331
+ auto S = check_state_limits (size_limits, false );
1332
+ if (S.is_error ()) {
1333
+ LOG (DEBUG) << " Cannot unpack msg state: " << S.move_as_error ();
1334
+ new_code = old_code;
1335
+ new_data = old_data;
1336
+ new_library = old_library;
1337
+ return false ;
1338
+ }
1324
1339
return true ;
1325
1340
}
1326
1341
@@ -1408,7 +1423,9 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
1408
1423
return true ;
1409
1424
}
1410
1425
use_msg_state = true ;
1411
- if (!(unpack_msg_state () && account.check_split_depth (new_split_depth))) {
1426
+ bool forbid_public_libs =
1427
+ acc_status == Account::acc_uninit && account.is_masterchain (); // Forbid for deploying, allow for unfreezing
1428
+ if (!(unpack_msg_state (cfg, false , forbid_public_libs) && account.check_split_depth (new_split_depth))) {
1412
1429
LOG (DEBUG) << " cannot unpack in_msg_state, or it has bad split_depth; cannot init account state" ;
1413
1430
cp.skip_reason = ComputePhase::sk_bad_state;
1414
1431
return true ;
@@ -1423,7 +1440,7 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
1423
1440
cp.skip_reason = in_msg_state.not_null () ? ComputePhase::sk_bad_state : ComputePhase::sk_no_state;
1424
1441
return true ;
1425
1442
} else if (in_msg_state.not_null ()) {
1426
- unpack_msg_state (true ); // use only libraries
1443
+ unpack_msg_state (cfg, true ); // use only libraries
1427
1444
}
1428
1445
if (in_msg_extern && in_msg_state.not_null () && account.addr != in_msg_state->get_hash ().bits ()) {
1429
1446
LOG (DEBUG) << " in_msg_state hash mismatch in external message" ;
@@ -1560,7 +1577,7 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
1560
1577
if (account.is_special ) {
1561
1578
return true ;
1562
1579
}
1563
- auto S = check_state_limits (cfg);
1580
+ auto S = check_state_limits (cfg. size_limits );
1564
1581
if (S.is_error ()) {
1565
1582
// Rollback changes to state, fail action phase
1566
1583
LOG (INFO) << " Account state size exceeded limits: " << S.move_as_error ();
@@ -2523,13 +2540,14 @@ static td::uint32 get_public_libraries_count(const td::Ref<vm::Cell>& libraries)
2523
2540
* Checks that the new account state fits in the limits.
2524
2541
* This function is not called for special accounts.
2525
2542
*
2526
- * @param cfg The configuration for the action phase.
2543
+ * @param size_limits The size limits configuration.
2544
+ * @param update_storage_stat Store storage stat in the Transaction's CellStorageStat.
2527
2545
*
2528
2546
* @returns A `td::Status` indicating the result of the check.
2529
2547
* - If the state limits are within the allowed range, returns OK.
2530
2548
* - If the state limits exceed the maximum allowed range, returns an error.
2531
2549
*/
2532
- td::Status Transaction::check_state_limits (const ActionPhaseConfig& cfg ) {
2550
+ td::Status Transaction::check_state_limits (const SizeLimitsConfig& size_limits, bool update_storage_stat ) {
2533
2551
auto cell_equal = [](const td::Ref<vm::Cell>& a, const td::Ref<vm::Cell>& b) -> bool {
2534
2552
if (a.is_null ()) {
2535
2553
return b.is_null ();
@@ -2543,13 +2561,13 @@ td::Status Transaction::check_state_limits(const ActionPhaseConfig& cfg) {
2543
2561
cell_equal (account.library , new_library)) {
2544
2562
return td::Status::OK ();
2545
2563
}
2546
- // new_storage_stat is used here beause these stats will be reused in compute_state()
2547
- new_storage_stat .limit_cells = cfg. size_limits .max_acc_state_cells ;
2548
- new_storage_stat .limit_bits = cfg. size_limits .max_acc_state_bits ;
2564
+ vm::CellStorageStat storage_stat;
2565
+ storage_stat .limit_cells = size_limits.max_acc_state_cells ;
2566
+ storage_stat .limit_bits = size_limits.max_acc_state_bits ;
2549
2567
td::Timer timer;
2550
2568
auto add_used_storage = [&](const td::Ref<vm::Cell>& cell) -> td::Status {
2551
2569
if (cell.not_null ()) {
2552
- TRY_RESULT (res, new_storage_stat .add_used_storage (cell));
2570
+ TRY_RESULT (res, storage_stat .add_used_storage (cell));
2553
2571
if (res.max_merkle_depth > max_allowed_merkle_depth) {
2554
2572
return td::Status::Error (" too big merkle depth" );
2555
2573
}
@@ -2563,19 +2581,24 @@ td::Status Transaction::check_state_limits(const ActionPhaseConfig& cfg) {
2563
2581
LOG (INFO) << " Compute used storage took " << timer.elapsed () << " s" ;
2564
2582
}
2565
2583
if (acc_status == Account::acc_active) {
2566
- new_storage_stat .clear_limit ();
2584
+ storage_stat .clear_limit ();
2567
2585
} else {
2568
- new_storage_stat.clear ();
2569
- }
2570
- if (new_storage_stat.cells > cfg.size_limits .max_acc_state_cells ||
2571
- new_storage_stat.bits > cfg.size_limits .max_acc_state_bits ) {
2572
- return td::Status::Error (" account state is too big" );
2586
+ storage_stat.clear ();
2587
+ }
2588
+ td::Status res;
2589
+ if (storage_stat.cells > size_limits.max_acc_state_cells || storage_stat.bits > size_limits.max_acc_state_bits ) {
2590
+ res = td::Status::Error (PSTRING () << " account state is too big" );
2591
+ } else if (account.is_masterchain () && !cell_equal (account.library , new_library) &&
2592
+ get_public_libraries_count (new_library) > size_limits.max_acc_public_libraries ) {
2593
+ res = td::Status::Error (" too many public libraries" );
2594
+ } else {
2595
+ res = td::Status::OK ();
2573
2596
}
2574
- if (account. is_masterchain () && ! cell_equal (account. library , new_library) &&
2575
- get_public_libraries_count (new_library) > cfg. size_limits . max_acc_public_libraries ) {
2576
- return td::Status::Error ( " too many public libraries " );
2597
+ if (update_storage_stat) {
2598
+ // storage_stat will be reused in compute_state()
2599
+ new_storage_stat = std::move (storage_stat );
2577
2600
}
2578
- return td::Status::OK () ;
2601
+ return res ;
2579
2602
}
2580
2603
2581
2604
/* *
@@ -3407,6 +3430,7 @@ td::Status FetchConfigParams::fetch_config_params(
3407
3430
compute_phase_cfg->prev_blocks_info = std::move (prev_blocks_info);
3408
3431
}
3409
3432
compute_phase_cfg->suspended_addresses = config.get_suspended_addresses (now);
3433
+ compute_phase_cfg->size_limits = size_limits;
3410
3434
}
3411
3435
{
3412
3436
// compute action_phase_cfg
0 commit comments