@@ -1027,6 +1027,12 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
10271027 break ;
10281028 case block::gen::OutAction::action_send_msg:
10291029 err_code = try_action_send_msg (cs, ap, cfg);
1030+ if (err_code == -2 ) {
1031+ err_code = try_action_send_msg (cs, ap, cfg, 1 );
1032+ if (err_code == -2 ) {
1033+ err_code = try_action_send_msg (cs, ap, cfg, 2 );
1034+ }
1035+ }
10301036 break ;
10311037 case block::gen::OutAction::action_reserve_currency:
10321038 err_code = try_action_reserve_currency (cs, ap, cfg);
@@ -1240,22 +1246,60 @@ bool Transaction::check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const A
12401246 return true ;
12411247}
12421248
1243- int Transaction::try_action_send_msg (vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) {
1249+ int Transaction::try_action_send_msg (const vm::CellSlice& cs0, ActionPhase& ap, const ActionPhaseConfig& cfg,
1250+ int redoing) {
12441251 block::gen::OutAction::Record_action_send_msg act_rec;
12451252 // mode: +128 = attach all remaining balance, +64 = attach all remaining balance of the inbound message, +1 = pay message fees, +2 = skip if message cannot be sent
1253+ vm::CellSlice cs{cs0};
12461254 if (!tlb::unpack_exact (cs, act_rec) || (act_rec.mode & ~0xc3 ) || (act_rec.mode & 0xc0 ) == 0xc0 ) {
12471255 return -1 ;
12481256 }
12491257 bool skip_invalid = (act_rec.mode & 2 );
1250- auto cs2 = vm::load_cell_slice (act_rec.out_msg );
1251- // try to parse suggested message in cs2
1258+ // try to parse suggested message in act_rec.out_msg
12521259 td::RefInt256 fwd_fee, ihr_fee;
1253- bool ext_msg = cs2.prefetch_ulong (1 );
1260+ block::gen::MessageRelaxed::Record msg;
1261+ if (!tlb::type_unpack_cell (act_rec.out_msg , block::gen::t_MessageRelaxed_Any, msg)) {
1262+ return -1 ;
1263+ }
1264+ if (redoing >= 1 ) {
1265+ if (msg.init ->size_refs () >= 2 ) {
1266+ LOG (DEBUG) << " moving the StateInit of a suggested outbound message into a separate cell" ;
1267+ // init:(Maybe (Either StateInit ^StateInit))
1268+ // transform (just (left z:StateInit)) into (just (right z:^StateInit))
1269+ CHECK (msg.init .write ().fetch_ulong (2 ) == 2 );
1270+ vm::CellBuilder cb;
1271+ Ref<vm::Cell> cell;
1272+ CHECK (cb.append_cellslice_bool (std::move (msg.init )) // StateInit
1273+ && cb.finalize_to (cell) // -> ^StateInit
1274+ && cb.store_long_bool (3 , 2 ) // (just (right ... ))
1275+ && cb.store_ref_bool (std::move (cell)) // z:^StateInit
1276+ && cb.finalize_to (cell));
1277+ msg.init = vm::load_cell_slice_ref (std::move (cell));
1278+ } else {
1279+ redoing = 2 ;
1280+ }
1281+ }
1282+ if (redoing >= 2 && msg.body ->size_ext () > 1 && msg.body ->prefetch_ulong (1 ) == 0 ) {
1283+ LOG (DEBUG) << " moving the body of a suggested outbound message into a separate cell" ;
1284+ // body:(Either X ^X)
1285+ // transform (left x:X) into (right x:^X)
1286+ CHECK (msg.body .write ().fetch_ulong (1 ) == 0 );
1287+ vm::CellBuilder cb;
1288+ Ref<vm::Cell> cell;
1289+ CHECK (cb.append_cellslice_bool (std::move (msg.body )) // X
1290+ && cb.finalize_to (cell) // -> ^X
1291+ && cb.store_long_bool (1 , 1 ) // (right ... )
1292+ && cb.store_ref_bool (std::move (cell)) // x:^X
1293+ && cb.finalize_to (cell));
1294+ msg.body = vm::load_cell_slice_ref (std::move (cell));
1295+ }
1296+
12541297 block::gen::CommonMsgInfoRelaxed::Record_int_msg_info info;
1298+ bool ext_msg = msg.info ->prefetch_ulong (1 );
12551299 if (ext_msg) {
12561300 // ext_out_msg_info$11 constructor of CommonMsgInfoRelaxed
12571301 block::gen::CommonMsgInfoRelaxed::Record_ext_out_msg_info erec;
1258- if (!tlb::unpack (cs2 , erec)) {
1302+ if (!tlb::csr_unpack (msg. info , erec)) {
12591303 return -1 ;
12601304 }
12611305 info.src = std::move (erec.src );
@@ -1267,7 +1311,7 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
12671311 fwd_fee = ihr_fee = td::RefInt256{true , 0 };
12681312 } else {
12691313 // int_msg_info$0 constructor
1270- if (!tlb::unpack (cs2 , info) || !block::tlb::t_CurrencyCollection.validate_csr (info.value )) {
1314+ if (!tlb::csr_unpack (msg. info , info) || !block::tlb::t_CurrencyCollection.validate_csr (info.value )) {
12711315 return -1 ;
12721316 }
12731317 fwd_fee = block::tlb::t_Grams.as_integer (info.fwd_fee );
@@ -1295,12 +1339,11 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
12951339 // compute size of message
12961340 vm::CellStorageStat sstat; // for message size
12971341 // preliminary storage estimation of the resulting message
1298- sstat.compute_used_storage (cs2); // message body
1342+ sstat.add_used_storage (msg.init , true , 3 ); // message init
1343+ sstat.add_used_storage (msg.body , true , 3 ); // message body (the root cell itself is not counted)
12991344 if (!ext_msg) {
13001345 sstat.add_used_storage (info.value ->prefetch_ref ());
13011346 }
1302- sstat.bits -= cs2.size (); // bits in the root cells are free
1303- sstat.cells --; // the root cell itself is not counted as a cell
13041347 LOG (DEBUG) << " storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits" ;
13051348 if (sstat.bits > max_msg_bits || sstat.cells > max_msg_cells) {
13061349 LOG (DEBUG) << " message too large, invalid" ;
@@ -1397,17 +1440,15 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
13971440
13981441 // re-pack message value
13991442 CHECK (req.pack_to (info.value ));
1400- vm::CellBuilder cb;
1401- CHECK (block::tlb::t_Grams.store_integer_ref (cb, fwd_fee_remain) &&
1402- (info.fwd_fee = load_cell_slice_ref (cb.finalize ())).not_null ());
1403- CHECK (block::tlb::t_Grams.store_integer_ref (cb, ihr_fee) &&
1404- (info.ihr_fee = load_cell_slice_ref (cb.finalize ())).not_null ());
1443+ CHECK (block::tlb::t_Grams.pack_integer (info.fwd_fee , fwd_fee_remain));
1444+ CHECK (block::tlb::t_Grams.pack_integer (info.ihr_fee , ihr_fee));
14051445
14061446 // serialize message
1407- CHECK (tlb::pack (cb, info));
1408- if (!cb.append_cellslice_bool (cs2)) {
1447+ CHECK (tlb::csr_pack (msg.info , info));
1448+ vm::CellBuilder cb;
1449+ if (!tlb::type_pack (cb, block::gen::t_MessageRelaxed_Any, msg)) {
14091450 LOG (DEBUG) << " outbound message does not fit into a cell after rewriting" ;
1410- return 39 ;
1451+ return redoing < 2 ? - 2 : (skip_invalid ? 0 : 39 ) ;
14111452 }
14121453
14131454 new_msg_bits = cb.size ();
@@ -1438,11 +1479,11 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
14381479 erec.dest = info.dest ;
14391480 erec.created_at = info.created_at ;
14401481 erec.created_lt = info.created_lt ;
1482+ CHECK (tlb::csr_pack (msg.info , erec));
14411483 vm::CellBuilder cb;
1442- CHECK (tlb::pack (cb, erec));
1443- if (!cb.append_cellslice_bool (cs2)) {
1484+ if (!tlb::type_pack (cb, block::gen::t_MessageRelaxed_Any, msg)) {
14441485 LOG (DEBUG) << " outbound message does not fit into a cell after rewriting" ;
1445- return 39 ;
1486+ return redoing < 2 ? - 2 : (skip_invalid ? 0 : 39 ) ;
14461487 }
14471488
14481489 new_msg_bits = cb.size ();
@@ -1461,6 +1502,8 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
14611502 }
14621503 if (!block::gen::t_Message_Any.validate_ref (new_msg)) {
14631504 LOG (ERROR) << " generated outbound message is not a valid (Message Any) according to automated check" ;
1505+ block::gen::t_Message_Any.print_ref (std::cerr, new_msg);
1506+ vm::load_cell_slice (new_msg).print_rec (std::cerr);
14641507 return -1 ;
14651508 }
14661509 if (verbosity > 2 ) {
0 commit comments