Skip to content

Commit f1c4ce4

Browse files
committed
Add v11 c7 message construction in executor. Add test for v11 opcodes. Use DisplayConfigOpsArgs for long opcodes.
# Conflicts: # Cargo.toml
1 parent d0ded84 commit f1c4ce4

File tree

3 files changed

+181
-19
lines changed

3 files changed

+181
-19
lines changed

executor/src/phase/compute.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ impl ExecutorState<'_> {
147147
});
148148
return Ok(res);
149149
}
150-
151150
// Apply internal message state.
152151
let state_libs;
153152
let msg_libs;
@@ -263,7 +262,9 @@ impl ExecutorState<'_> {
263262
.with_storage_fees(ctx.storage_fee)
264263
.require_ton_v6()
265264
.with_unpacked_config(self.config.unpacked.as_tuple())
266-
.require_ton_v9();
265+
.require_ton_v9()
266+
.require_ton_v11()
267+
.with_in_message(ctx.input.in_msg().map(|x| &x.root))?;
267268

268269
let libraries = (msg_libs, state_libs, &self.params.libraries);
269270
let mut vm = VmState::builder()

vm/src/instr/configops.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,7 @@ impl ConfigOps {
2727
Ok(0)
2828
}
2929

30-
#[op(code = "f88111", fmt = "INMSGPARAMS")]
31-
fn exec_get_in_msg_params(st: &mut VmState) -> VmResult<i32> {
32-
ok!(st.version.require_ton(11..));
33-
let stack = SafeRc::make_mut(&mut st.stack);
34-
ok!(get_and_push_param(
35-
&mut st.cr,
36-
stack,
37-
SmcInfoTonV11::IN_MSG_PARAMS_IDX
38-
));
39-
Ok(0)
40-
}
41-
42-
#[op(code = "f8ssss @ f88100..f88111", fmt = "GETPARAMLONG {s}", args(s = args & 255))]
43-
#[op(code = "f8ssss @ f88112..f881ff", fmt = "GETPARAMLONG {s}", args(s = args & 255))]
30+
#[op(code = "f881ss", fmt = DisplayConfigOpsArgs(s))]
4431
fn exec_get_param_long(st: &mut VmState, s: u32) -> VmResult<i32> {
4532
ok!(st.version.require_ton(11..));
4633
let stack = SafeRc::make_mut(&mut st.stack);
@@ -392,6 +379,7 @@ impl std::fmt::Display for DisplayConfigOpsArgs {
392379
13 => "PREVBLOCKSINFOTUPLE",
393380
14 => "UNPACKEDCONFIGTUPLE",
394381
15 => "DUEPAYMENT",
382+
17 => "INMSGPARAMS",
395383
i => return write!(f, "GETPARAM {i}"),
396384
};
397385
write!(f, "{}", code)
@@ -480,8 +468,38 @@ mod test {
480468
use everscale_types::models::{CurrencyCollection, ExtraCurrencyCollection};
481469
use everscale_types::num::VarUint248;
482470
use tracing_test::traced_test;
471+
use tycho_vm::smc_info::SmcInfoTonV11;
472+
473+
use crate::{RcStackValue, SmcInfoBase, Stack, VmState};
483474

484-
use crate::{SmcInfoBase, VmState};
475+
#[test]
476+
#[traced_test]
477+
pub fn in_msg_params_works() {
478+
let params = tuple![int 0, int 1,int 2,int 3,int 4,int 5,int 6,int 7,int 8,int 9];
479+
let mut c7 = Vec::<RcStackValue>::with_capacity(17);
480+
let params = RcStackValue::from(params);
481+
482+
for i in 0..=SmcInfoTonV11::IN_MSG_PARAMS_IDX {
483+
if i == SmcInfoTonV11::IN_MSG_PARAMS_IDX {
484+
c7.push(params.clone());
485+
} else {
486+
c7.push(Stack::make_null());
487+
}
488+
}
489+
let c7 = tuple![raw RcStackValue::from(c7)];
490+
491+
assert_run_vm!("INMSGPARAMS", c7: c7.clone(), [] => [raw params]);
492+
assert_run_vm!("INMSG_BOUNCE", c7: c7.clone(), [] => [int 0]);
493+
assert_run_vm!("INMSG_BOUNCED", c7: c7.clone(), [] => [int 1]);
494+
assert_run_vm!("INMSG_SRC", c7: c7.clone(), [] => [int 2]);
495+
assert_run_vm!("INMSG_FWDFEE", c7: c7.clone(), [] => [int 3]);
496+
assert_run_vm!("INMSG_LT", c7: c7.clone(), [] => [int 4]);
497+
assert_run_vm!("INMSG_UTIME", c7: c7.clone(), [] => [int 5]);
498+
assert_run_vm!("INMSG_ORIGVALUE", c7: c7.clone(), [] => [int 6]);
499+
assert_run_vm!("INMSG_VALUE", c7: c7.clone(), [] => [int 7]);
500+
assert_run_vm!("INMSG_VALUEEXTRA", c7: c7.clone(), [] => [int 8]);
501+
assert_run_vm!("INMSG_STATEINIT", c7: c7.clone(), [] => [int 9]);
502+
}
485503

486504
#[test]
487505
#[traced_test]

vm/src/smc_info.rs

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ use std::rc::Rc;
22
use std::sync::Arc;
33

44
use everscale_types::error::Error;
5-
use everscale_types::models::{BlockchainConfigParams, CurrencyCollection, IntAddr};
5+
use everscale_types::error::Error::InvalidData;
6+
use everscale_types::models::{
7+
BlockchainConfigParams, CurrencyCollection, ExtInMsgInfo, IntAddr, IntMsgInfo, MsgInfo,
8+
OwnedMessage,
9+
};
610
use everscale_types::num::Tokens;
711
use everscale_types::prelude::*;
812
use num_bigint::{BigInt, Sign};
@@ -480,6 +484,13 @@ impl SmcInfoTonV9 {
480484
// ..base:SmcInfoTonV6
481485
self.base.write_items(items);
482486
}
487+
488+
pub fn require_ton_v11(self) -> SmcInfoTonV11 {
489+
SmcInfoTonV11 {
490+
base: self,
491+
in_msg: None,
492+
}
493+
}
483494
}
484495

485496
impl SmcInfo for SmcInfoTonV9 {
@@ -495,9 +506,9 @@ impl SmcInfo for SmcInfoTonV9 {
495506
}
496507

497508
#[derive(Default, Debug, Clone)]
498-
#[repr(transparent)]
499509
pub struct SmcInfoTonV11 {
500510
pub base: SmcInfoTonV9,
511+
pub in_msg: Option<SafeRc<Tuple>>,
501512
}
502513

503514
impl SmcInfoTonV11 {
@@ -507,6 +518,138 @@ impl SmcInfoTonV11 {
507518
fn write_items(&self, items: &mut Tuple) {
508519
// ..base:SmcInfoTonV9
509520
self.base.write_items(items);
521+
let message_value = match &self.in_msg {
522+
Some(message) => message.clone().into_dyn_value(),
523+
None => Self::prepare_empty_msg_tuple().into_dyn_value(),
524+
};
525+
526+
items.push(message_value);
527+
}
528+
529+
pub fn with_in_message(mut self, msg_cell_opt: Option<&Cell>) -> Result<Self, Error> {
530+
let Some(msg) = msg_cell_opt else {
531+
return Ok(self);
532+
};
533+
534+
let message = OwnedMessage::load_from(&mut msg.as_slice()?)?;
535+
536+
if message.info.is_external_out() {
537+
return Err(InvalidData);
538+
}
539+
540+
let state_init_opt = match message.init {
541+
Some(init) => Some(CellBuilder::build_from(init)?),
542+
None => None,
543+
};
544+
545+
let balance = self.base.base.base.message_balance.clone();
546+
let params_tuple = match message.info {
547+
MsgInfo::Int(info) => {
548+
Self::prepare_internal_in_msg_tuple(info, state_init_opt, balance)?
549+
}
550+
MsgInfo::ExtIn(info) => {
551+
Self::prepare_external_in_msg_tuple(info, state_init_opt, balance)?
552+
}
553+
_ => unreachable!(),
554+
};
555+
556+
self.in_msg = Some(params_tuple);
557+
Ok(self)
558+
}
559+
560+
fn prepare_internal_in_msg_tuple(
561+
msg: IntMsgInfo,
562+
state_init: Option<Cell>,
563+
msg_balance_remaining: CurrencyCollection,
564+
) -> Result<SafeRc<Tuple>, Error> {
565+
let address = OwnedCellSlice::new_allow_exotic(CellBuilder::build_from(msg.src)?);
566+
let extra_currency = if msg_balance_remaining.other.is_empty() {
567+
Stack::make_null()
568+
} else {
569+
SafeRc::new_dyn_value(CellBuilder::build_from(msg_balance_remaining.other)?)
570+
};
571+
572+
let state_init = match state_init {
573+
Some(state_init) => SafeRc::new_dyn_value(state_init),
574+
None => Stack::make_null(),
575+
};
576+
577+
let tuple = tuple![
578+
int if msg.bounce { -1 } else { 0 },
579+
int if msg.bounced { -1 } else { 0 },
580+
slice address,
581+
int msg.fwd_fee.into_inner(),
582+
int msg.created_lt,
583+
int msg.created_at,
584+
int msg.value.tokens.into_inner(),
585+
int msg_balance_remaining.tokens.into_inner(),
586+
raw extra_currency,
587+
raw state_init
588+
];
589+
590+
Ok(SafeRc::new(tuple))
591+
}
592+
593+
fn prepare_external_in_msg_tuple(
594+
msg: ExtInMsgInfo,
595+
state_init: Option<Cell>,
596+
msg_balance_remaining: CurrencyCollection,
597+
) -> Result<SafeRc<Tuple>, Error> {
598+
let src_address = Self::make_none_addr_slice();
599+
let extra_currency = if msg_balance_remaining.other.is_empty() {
600+
Stack::make_null()
601+
} else {
602+
SafeRc::new_dyn_value(CellBuilder::build_from(msg_balance_remaining.other)?)
603+
};
604+
605+
let state_init = match state_init {
606+
Some(state_init) => SafeRc::new_dyn_value(state_init),
607+
None => Stack::make_null(),
608+
};
609+
610+
let tuple = tuple![
611+
int 0,
612+
int 0,
613+
slice src_address,
614+
int msg.import_fee.into_inner(),
615+
int 0,
616+
int 0,
617+
int 0,
618+
int msg_balance_remaining.tokens.into_inner(),
619+
raw extra_currency,
620+
raw state_init
621+
];
622+
623+
Ok(SafeRc::new(tuple))
624+
}
625+
626+
fn prepare_empty_msg_tuple() -> SafeRc<Tuple> {
627+
let src_address = Self::make_none_addr_slice();
628+
629+
let tuple = tuple![
630+
int 0, //bounce
631+
int 0, //bounced
632+
slice src_address, //src_addr
633+
int 0, //fwd fee
634+
int 0, //created lt
635+
int 0, //created at,
636+
int 0, //original value,
637+
int 0, // value,
638+
null, //extra currency
639+
null //state init
640+
];
641+
642+
SafeRc::new(tuple)
643+
}
644+
645+
fn make_none_addr_slice() -> OwnedCellSlice {
646+
let mut addr_builder = CellBuilder::new();
647+
addr_builder.store_zeros(2).expect("can't fail");
648+
OwnedCellSlice::new_allow_exotic(
649+
addr_builder
650+
.build()
651+
.expect("2 bits are valid input for empty builder"),
652+
)
510653
}
511654
}
512655

0 commit comments

Comments
 (0)