use crate::emulators::emul_utils::{convert_emulator_response, make_b64_c_str, set_param_failed};
use crate::emulators::tvm::tvm_c7::TVMEmulatorC7;
use crate::emulators::tvm::tvm_method_id::TVMGetMethodID;
use crate::emulators::tvm::tvm_response::{
TVMGetMethodResponse, TVMGetMethodSuccess, TVMSendMsgResponse, TVMSendMsgSuccess,
};
use crate::error::TLError;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use std::ffi::CString;
use tonlib_sys::{
tvm_emulator_create, tvm_emulator_destroy, tvm_emulator_run_get_method, tvm_emulator_send_external_message,
tvm_emulator_send_internal_message, tvm_emulator_set_c7, tvm_emulator_set_debug_enabled,
tvm_emulator_set_gas_limit, tvm_emulator_set_libraries,
};
#[derive(Debug)]
pub struct TVMEmulator {
ptr: *mut std::os::raw::c_void,
}
const DEFAULT_TVM_LOG_VERBOSITY: u32 = 1;
impl TVMEmulator {
pub fn new(code_boc: &[u8], data_boc: &[u8], c7: &TVMEmulatorC7) -> Result<Self, TLError> {
let code = CString::new(STANDARD.encode(code_boc.as_ref()))?;
let data = CString::new(STANDARD.encode(data_boc.as_ref()))?;
let ptr = unsafe { tvm_emulator_create(code.as_ptr(), data.as_ptr(), DEFAULT_TVM_LOG_VERBOSITY) };
if ptr.is_null() {
return Err(TLError::EmulatorCreationFailed);
}
let mut emulator = TVMEmulator { ptr };
emulator.set_c7(c7)?;
Ok(emulator)
}
pub fn set_c7(&mut self, c7: &TVMEmulatorC7) -> Result<(), TLError> {
let address = CString::new(c7.address.to_hex().as_bytes())?;
let seed = CString::new(c7.rand_seed.to_hex().as_bytes())?;
let success = unsafe {
tvm_emulator_set_c7(self.ptr, address.as_ptr(), c7.unix_time, c7.balance, seed.as_ptr(), c7.config.as_ptr())
};
match success {
true => Ok(()),
false => set_param_failed("c7"),
}
}
pub fn set_debug_enabled(&mut self, enabled: bool) -> Result<(), TLError> {
let success = unsafe { tvm_emulator_set_debug_enabled(self.ptr, enabled as i32) };
match success {
true => Ok(()),
false => set_param_failed("debug_enabled"),
}
}
pub fn set_gas_limit(&mut self, limit: u64) -> Result<(), TLError> {
let success = unsafe { tvm_emulator_set_gas_limit(self.ptr, limit) };
match success {
true => Ok(()),
false => set_param_failed("gas_limit"),
}
}
pub fn set_libs(&mut self, libs_boc: &[u8]) -> Result<(), TLError> {
let libs = CString::new(STANDARD.encode(libs_boc))?;
let success = unsafe { tvm_emulator_set_libraries(self.ptr, libs.as_ptr()) };
match success {
true => Ok(()),
false => set_param_failed("libs"),
}
}
pub fn run_get_method<T>(&mut self, method: T, stack_boc: &[u8]) -> Result<TVMGetMethodSuccess, TLError>
where
T: Into<TVMGetMethodID>,
{
let tvm_method = method.into();
log::trace!("[TVMEmulator][run_get_method]: method: {tvm_method}, stack: {stack_boc:?}");
let stack = make_b64_c_str(stack_boc)?;
let response_ptr = unsafe { tvm_emulator_run_get_method(self.ptr, tvm_method.to_id(), stack.as_ptr()) };
let json_str = convert_emulator_response(response_ptr)?;
log::trace!("[TVMEmulator][run_get_method]: method: {tvm_method}, stack_boc: {stack_boc:?}, rsp: {json_str}");
TVMGetMethodResponse::from_json(json_str)?.into_success()
}
pub fn send_int_msg(&mut self, msg_boc: &[u8], amount: u64) -> Result<TVMSendMsgSuccess, TLError> {
log::trace!("[TVMEmulator][send_int_msg]: msg_boc: {msg_boc:?}, amount: {amount}");
let msg = CString::new(STANDARD.encode(msg_boc))?;
let c_str = unsafe { tvm_emulator_send_internal_message(self.ptr, msg.as_ptr(), amount) };
let json_str = convert_emulator_response(c_str)?;
log::trace!("[TVMEmulator][send_int_msg]: msg_boc: {msg_boc:?}, amount: {amount}, rsp: {json_str}");
TVMSendMsgResponse::from_json(json_str)?.into_success()
}
pub fn send_ext_msg(&mut self, msg_boc: &[u8]) -> Result<TVMSendMsgSuccess, TLError> {
log::trace!("[TVMEmulator][send_ext_msg]: msg_boc: {msg_boc:?}");
let msg = make_b64_c_str(msg_boc)?;
let response_ptr = unsafe { tvm_emulator_send_external_message(self.ptr, msg.as_ptr()) };
let json_str = convert_emulator_response(response_ptr)?;
log::trace!("[TVMEmulator][send_ext_msg]: msg_boc: {msg_boc:?}, rsp: {json_str}");
TVMSendMsgResponse::from_json(json_str)?.into_success()
}
}
impl Drop for TVMEmulator {
fn drop(&mut self) { unsafe { tvm_emulator_destroy(self.ptr) }; }
}
unsafe impl Send for TVMEmulator {}
unsafe impl Sync for TVMEmulator {}
#[cfg(test)]
mod tests {
use crate::block_tlb::TVMStack;
use crate::emulators::emul_bc_config::EmulBCConfig;
use crate::emulators::tvm::tvm_c7::TVMEmulatorC7;
use crate::emulators::tvm::tvm_emulator::TVMEmulator;
use crate::error::TLError;
use crate::libs_dict::LibsDict;
use crate::sys_utils::sys_tonlib_set_verbosity_level;
use crate::tep::jetton::JettonTransferMsg;
use num_bigint::BigInt;
use std::ops::{Deref, Neg};
use std::str::FromStr;
use std::sync::LazyLock;
use tokio_test::{assert_err, assert_ok};
use ton_lib_core::cell::{TonCell, TonCellRef};
use ton_lib_core::traits::tlb::TLB;
use ton_lib_core::types::TonAddress;
static BC_CONFIG: LazyLock<EmulBCConfig> = LazyLock::new(|| {
EmulBCConfig::from_boc_hex(include_str!("../../../../resources/tests/bc_config_key_block_42123611.hex"))
.unwrap()
});
#[test]
fn test_tvm_emulator_get_wallet_address() -> anyhow::Result<()> {
sys_tonlib_set_verbosity_level(0);
let owner_address = TonAddress::from_str("EQB2BtXDXaQuIcMYW7JEWhHmwHfPPwa-eoCdefiAxOhU3pQg")?;
// Monsoon
let master_address = TonAddress::from_str("EQDk2VTvn04SUKJrW7rXahzdF8_Qi6utb0wj43InCu9vdjrR")?;
let master_code = hex::decode("b5ee9c7201020b010001ed000114ff00f4a413f4bcf2c80b0102016202030202cc040502037a60090a03efd9910e38048adf068698180b8d848adf07d201800e98fe99ff6a2687d007d206a6a18400aa9385d47181a9aa8aae382f9702480fd207d006a18106840306b90fd001812881a28217804502a906428027d012c678b666664f6aa7041083deecbef29385d71811a92e001f1811802600271812f82c207f97840607080093dfc142201b82a1009aa0a01e428027d012c678b00e78b666491646580897a007a00658064907c80383a6465816503e5ffe4e83bc00c646582ac678b28027d0109e5b589666664b8fd80400fe3603fa00fa40f82854120870542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c9f9007074c8cb02ca07cbffc9d05008c705f2e04a12a1035024c85004fa0258cf16ccccc9ed5401fa403020d70b01c3008e1f8210d53276db708010c8cb055003cf1622fa0212cb6acb1fcb3fc98042fb00915be200303515c705f2e049fa403059c85004fa0258cf16ccccc9ed54002e5143c705f2e049d43001c85004fa0258cf16ccccc9ed54007dadbcf6a2687d007d206a6a183618fc1400b82a1009aa0a01e428027d012c678b00e78b666491646580897a007a00658064fc80383a6465816503e5ffe4e840001faf16f6a2687d007d206a6a183faa9040")?;
let master_data = hex::decode("b5ee9c720102140100037c0002517038f504e10a000801bf6feee5bff07f3238df435d6c58addbe0b3a94bb05cec14a6241566cb3e61750102004a0168747470733a2f2f746172616e74696e692e6465762f73746f6e2f6d6f6f6e2e6a736f6e0114ff00f4a413f4bcf2c80b0302016204050202cc0607001ba0f605da89a1f401f481f481a8610201d408090201480a0b00bb0831c02497c138007434c0c05c6c2544d7c0fc02f83e903e900c7e800c5c75c87e800c7e800c00b4c7e08403e29fa954882ea54c4d167c0238208405e3514654882ea58c511100fc02780d60841657c1ef2ea4d67c02b817c12103fcbc2000113e910c1c2ebcb853600201200c0d020120121301f500f4cffe803e90087c007b51343e803e903e90350c144da8548ab1c17cb8b04a30bffcb8b0950d109c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c032483e401c1d3232c0b281f2fff274013e903d010c7e801de0063232c1540233c59c3e8085f2dac4f3208405e351467232c7c6600e03f73b51343e803e903e90350c0234cffe80145468017e903e9014d6f1c1551cdb5c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c0327e401c1d3232c0b281f2fff274140371c1472c7cb8b0c2be80146a2860822625a020822625a004ad822860822625a028062849f8c3c975c2c070c008e00f1011009acb3f5007fa0222cf165006cf1625fa025003cf16c95005cc2391729171e25008a813a08208989680aa008208989680a0a014bcf2e2c504c98040fb001023c85004fa0258cf1601cf16ccc9ed5400705279a018a182107362d09cc8cb1f5230cb3f58fa025007cf165007cf16c9718018c8cb0524cf165006fa0215cb6a14ccc971fb0010241023000e10491038375f040076c200b08e218210d53276db708010c8cb055008cf165004fa0216cb6a12cb1f12cb3fc972fb0093356c21e203c85004fa0258cf1601cf16ccc9ed5400db3b51343e803e903e90350c01f4cffe803e900c145468549271c17cb8b049f0bffcb8b0a0822625a02a8005a805af3cb8b0e0841ef765f7b232c7c572cfd400fe8088b3c58073c5b25c60063232c14933c59c3e80b2dab33260103ec01004f214013e809633c58073c5b3327b55200083200835c87b51343e803e903e90350c0134c7e08405e3514654882ea0841ef765f784ee84ac7cb8b174cfcc7e800c04e81408f214013e809633c58073c5b3327b5520")?;
let c7 = TVMEmulatorC7::new(master_address, BC_CONFIG.clone())?;
let mut emulator = TVMEmulator::new(&master_code, &master_data, &c7)?;
let mut stack = TVMStack::default();
stack.push_cell_slice(owner_address.to_cell_ref()?);
let emulated = emulator.run_get_method("get_wallet_address", &stack.to_boc()?)?;
// check stack_boc() works well
let stack_boc = emulated.stack_boc()?;
let stack = TVMStack::from_boc(&stack_boc)?;
assert_eq!(stack.len(), emulated.stack_parsed()?.len());
let emulated_addr = TonAddress::from_cell(emulated.stack_parsed()?.pop_cell()?.deref())?;
assert_eq!(emulated_addr, TonAddress::from_str("EQCGY3OVLtD9KRcOsP2ldQDtuY0FMzV7wPoxjrFbayBXc23c")?);
// USDT
let master_address = TonAddress::from_str("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs")?;
let master_code = hex::decode("b5ee9c72010218010005bb000114ff00f4a413f4bcf2c80b0102016202030202cb0405020120141502f3d0cb434c0c05c6c238ecc200835c874c7c0608405e351466ea44c38601035c87e800c3b51343e803e903e90353534541168504d3214017e809400f3c58073c5b333327b55383e903e900c7e800c7d007e800c7e80004c5c3e0e80b4c7c04074cfc044bb51343e803e903e9035353449a084190adf41eeb8c089a0607001da23864658380e78b64814183fa0bc0019635355161c705f2e04904fa4021fa4430c000f2e14dfa00d4d120d0d31f018210178d4519baf2e0488040d721fa00fa4031fa4031fa0020d70b009ad74bc00101c001b0f2b19130e254431b0803fa82107bdd97deba8ee7363805fa00fa40f82854120a70546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c9f9007074c8cb02ca07cbffc9d05008c705f2e04a12a14414506603c85005fa025003cf1601cf16ccccc9ed54fa40d120d70b01c000b3915be30de02682102c76b973bae30235250a0b0c018e2191729171e2f839206e938124279120e2216e94318128739101e25023a813a0738103a370f83ca00270f83612a00170f836a07381040982100966018070f837a0bcf2b025597f0900ec82103b9aca0070fb02f828450470546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c920f9007074c8cb02ca07cbffc9d0c8801801cb0501cf1658fa02029858775003cb6bcccc9730017158cb6acce2c98011fb005005a04314c85005fa025003cf1601cf16ccccc9ed540044c8801001cb0501cf1670fa027001cb6a8210d53276db01cb1f0101cb3fc98042fb0001fc145f04323401fa40d2000101d195c821cf16c9916de2c8801001cb055004cf1670fa027001cb6a8210d173540001cb1f500401cb3f23fa4430c0008e35f828440470546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c9f9007074c8cb02ca07cbffc9d012cf1697316c127001cb01e2f400c90d04f882106501f354ba8e223134365145c705f2e04902fa40d1103402c85005fa025003cf1601cf16ccccc9ed54e0258210fb88e119ba8e2132343603d15131c705f2e0498b025512c85005fa025003cf1601cf16ccccc9ed54e034248210235caf52bae30237238210cb862902bae302365b2082102508d66abae3026c310e0f101100088050fb0002ec3031325033c705f2e049fa40fa00d4d120d0d31f01018040d7212182100f8a7ea5ba8e4d36208210595f07bcba8e2c3004fa0031fa4031f401d120f839206e943081169fde718102f270f8380170f836a0811a7770f836a0bcf2b08e138210eed236d3ba9504d30331d19434f2c048e2e2e30d50037012130044335142c705f2e049c85003cf16c9134440c85005fa025003cf1601cf16ccccc9ed54001e3002c705f2e049d4d4d101ed54fb0400188210d372158cbadc840ff2f000ce31fa0031fa4031fa4031f401fa0020d70b009ad74bc00101c001b0f2b19130e25442162191729171e2f839206e938124279120e2216e94318128739101e25023a813a0738103a370f83ca00270f83612a00170f836a07381040982100966018070f837a0bcf2b000c082103b9aca0070fb02f828450470546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c920f9007074c8cb02ca07cbffc9d0c8801801cb0501cf1658fa02029858775003cb6bcccc9730017158cb6acce2c98011fb000025bd9adf6a2687d007d207d206a6a6888122f82402027116170085adbcf6a2687d007d207d206a6a688a2f827c1400b82a3002098a81e46581ac7d0100e78b00e78b6490e4658089fa00097a00658064fc80383a6465816503e5ffe4e84000cfaf16f6a2687d007d207d206a6a68bf99e836c1783872ebdb514d9c97c283b7f0ae5179029e2b6119c39462719e4f46ed8f7413e62c780a417877407e978f01a40711411b1acb773a96bdd93fa83bb5ca8435013c8c4b3ac91f4589b4780a38646583fa0064a18040")?;
let master_data = hex::decode("b5ee9c72010104010075000253705148e3baabcb0800c881fc78d28207072c728a2e7896228f37e17369ae121cb0eef7b4b0385f33304001020842028f452d7a4dfd74066b682365177259ed05734435be76b5fd4bd5d8af2b7c3d68010003003e68747470733a2f2f7465746865722e746f2f757364742d746f6e2e6a736f6e")?;
let c7 = TVMEmulatorC7::new(master_address, BC_CONFIG.clone())?;
let mut emulator = TVMEmulator::new(&master_code, &master_data, &c7)?;
let mut stack = TVMStack::default();
stack.push_cell_slice(owner_address.to_cell_ref()?);
let emulated = emulator.run_get_method("get_wallet_address", &stack.to_boc()?)?;
let emulated_addr = TonAddress::from_cell(emulated.stack_parsed()?.pop_cell()?.deref())?;
assert_eq!(
emulated_addr,
TonAddress::from_str("0:89c154a4225ebfa810891236ba01975f1f8860d2b090be3036fa05c36b53c77c")?
);
Ok(())
}
#[test]
fn test_tvm_emulator_get_pool_full_data() -> anyhow::Result<()> {
sys_tonlib_set_verbosity_level(0);
let address = TonAddress::from_str("EQCkWxfyhAkim3g2DjKQQg8T5P4g-Q1-K_jErGcDJZ4i-vqR")?;
let master_code = hex::decode("b5ee9c7201026301001413000114ff00f4a413f4bcf2c80b0102016202030202c904050201204d4e02012006070201481415048fd7b68bb7ec07434c0fe900c36cf005c6c2386c0600835c874c7f4cfd648608405a431812ea5e08437f7289eccb7a58074c7f4cfd67888608404e686d3aea3a1840d57c176cf38c3a602b2c2d02014808090201580a0b0201480c0d00675c8706f008e175143a90c20c20992a65792a630e2156f8c01a424c00012e63333229c22a552206f8101cb0702a502e46c21c9d08006b570547000c8cb077001ca007001ca0021fa022101cb2fcbffcb072101cb2f2101cb2f21fa022101cb2fcb017001cb2f7001cb17ccc98002347001f027f84522c8cb01f400f400cb00c9803f14326d229a8b84465706f7369742089d8bb5769746864726177616c208e28b75061796f7574238037af02513c858cf1601cf16c9d012c858cf1601cf16c9d070c8cb0701cf16c982f082a3537ff0dbce7eec35d69edc3a189ee6f17d82f353a553f9aa96cb0be3ce89588307f41701e30f8b6e28fb2efb88f880e0f1000b08d0990dbdb9d995c9d1cc819195c1bdcda5d1959081513d3881d1bc8141bdbdb0812995d1d1bdb9ce070c8cb0701cf16c982f0c9046f7a37ad0ea7cee73355984fa5428982f8b37c8f7bcec91f7ac71a7cd104588307f41700aa8d08d0dbdb9d995c9d1cc8189d5c9b995908141bdbdb0812995d1d1bdb9cc81d1bc81513d3a070c8cb0701cf16c982f0c9046f7a37ad0ea7cee73355984fa5428982f8b37c8f7bcec91f7ac71a7cd104588307f41702fa70c8cb0701cf16c982f0b76a7ca153c24671658335bbd08946350ffc621fa1c516e7123095d4ffd5c581588307f4178d06db5e4b58dd5cdd1bdb4b5cdd185ad94b5859191c995cdccb9d1bdba070c8cb0701cf16c982f070e5d7b6a29b392f85076fe15ca2f2053c56c2338728c4e33c9e8ddb1ee827cc588307f41789111200486d792d637573746f6d2d7374616b652d616464726573732e746f6e2f69636f6e2e696d6701f070c8cb0701cf16c982f06105d6cc76af400325e94d588ce511be5bfdbb73b437dc51eca43917d7a43e3d588307f4178b668696464656e870c8cb0701cf16c982f0d33ae06043036d0d1c3be27201ac15ee4c73da8cdb7c8f3462ce308026095ac0588307f417f825f815ed44f900f810ab07c8cbffcbffc913009482f07b491face15c5be43df3affe42e6e4aab48522a3b564043de464e8de50184a5d588307f41770c8cb07f400c96dc870fa02f828cf16f400ccc970f84621c8cb01f40012f400cb00c90201201617020162292a020120181902012025260201201a1b0201201e1f006f571c85003cf1601fa02830771800cc8cb03cb01cb0812cbff21cf3181028ebc9ac858cf17c97158cb61cc977001cb6101cf17e2c970fb0080201201c1d00891cb2140133c5963e808048304004807280006d82fe80a0c1dc60033232c0f2c072c204b2ffc873cc6040a3af26b21633c5f25c5632d87325dc0072d84073c5f8b25c3ec020009d1cc1b232c7d4017e809400fe808048304004807280006d82fe80807e80807e80a0c1dc60033232c0f2c072c204b2ffc873cc6040a3af26b21633c5f25c5632d87325dc0072d84073c5f8b25c3ec0200201202021020120232400671d007232c7e0c1dc60033232c0f2c072c204b2ffc873cc6040a3af26b21633c5f25c5632d87325dc0072d84073c5f8b25c3ec02002ef005bc9e0803d4001db85fcbd20803d40013000053cbd0120840ee6b280287e14c86a6d05dc2d8259a87e12e8ed827e12c8683e1ac860824c4b402f23a77e1748a83e1f7e16b220841534dd21fe0940b2c7f2cfd04c20041c36cf244c78be1760824c4b40283e1f7e16a0824c4b40322084304d12403e09604322017e02cb1fcb3f24fa025007fa0224fa022220c1001201ca0001b60bfa02f84bfa024160801070db3cf84bf8552410344666f04366f0466d705470002010566f0743000b19bc13fc142000b500dbc9c23e9120803d0000b03fc4bcbd1c151c05e0c1fd039be865db087e803e800c250c01a901b89446681446e81456681426e804e8320a3e8094013e809001a0c1fd10e0803d004875d970433cbd01840d4409040dc49bc1c060020148272800d1f187c2cc89870fc2cfc25fc2ad4c27c2c10c1092a05f2005009dcca2dbffc31707c2afc2cd0fc3ab87c3cb6fc3c7c2590d0fc35fc2e90c10802faf08050507c3ee4400c00e582ac678b00c10802faf080507d013800e5b5410808a05327fc1281658fe59fe4b87d8040089089bc9ca3e9120803d0000b03fc4bcbd1401e0c1fd199be86517c29c1c384e827e800c14dc2845e81445e80129545da852183c10890419c40d540d11dc1bc1c070001fc0600069323e16f3c5be12b3c5b2721400c072c7c073c5be0a33c5be1233c5b332483c0a1fc0bc0a04be401d3232c096007281f2fff27400600167430f857ddf85598f857f855f84bf05292f857e2f85d821011e1a300a0f87df856f8251270db3cf84bf857a0f86b6df87670f877844001145cba915b92a984e28001ef84a018200928302c705f2f47ff862033a218210319b0cdcba8f11218210270695fbba8e855b6c22db3ce30ee30d2e2f300104db3c4a0048f84312018200928302c705f2f48200a000f823f84482015180a0bcf2f4d307d43001fb00034621821096e7f528ba8e855b6c22db3c8f1121821079e7c016ba8e855b6c22db3ce30ee2313233028a31f85413018200928302c705f2f4fa00fa40fa40315475435354ed44ed45ed478e915b5043a170fb02f85523a1f875127fdb3ced67ed65ed64757fed118aed41edf101f2ff44450082f84312018200928302c705f2f48200a000f823f84482015180a0bcf2f4f404f404f40430226e91329302ed54e2206e913092fb04e2206e913094d0ed1ed8e2f201002cf84812018200928302c705f2f4f823f864fa4030f86303482182107247e7a5ba8e8610355f05db3c8f112182109971881cba8e855b6c22db3ce30ee2343536001ef848018200928302c705f2f470f8620046f84812018200928302c705f2f4d32f0131f8698200a001f849f823a182015180bcf2f401fc2182105e517f36ba8e4a5b6c22f84812018200928302c705f2f4d200018e14fa4001f8688200a003f849f823b9f2f4842ff869ded2000195fa4001f87aded2000195fa4001f86aded2000195fa4030f87b9130e28ea72182109bf5561cba8e1b5b6c22f84812018200928302c705f2f4d20001f86dd2000131f86ee30ee23703e62182102aaa96a0ba8e165b6c22f84812018200928302c705f2f4d3170131f8738fd0218210c9f04485ba8e215b6c227082009284f84158baf2f4f85a12018200928302c705f2f4d3170131f86c8fa2f8276f1025a1db3c82009285f842f2f221821047d54391bae302218210e642c965bae2e25e383904b66c217082009284f84158baf2f48200f201f84ef2f40382103b9aca00a1f85da170fb020182103b9aca00a18200f20021c200f2f4f84d8f2158f8566ee300f856821005f5e1007053041046104755208306db3cf85701a0f877e30d3a493b3c03788f38218210dfdca27bba8eac5f0332f8515321f04802f871926c218e1130f85059f04802f870968200f402f2f0dfe28e86f8276f10db3cdee30ee30d5e3f4001fcf828f8506f117ff02a7021f90074c8cb025801ca07cbffc9d020f87670f854f85c1023705470002410351047103659c85006fa025004cf1658cf16cc01fa020101cb2fc922c8cb0112f400f400cb00c9f90074c8cb025801ca07cbffc9d0c87001ca007f01ca0070fa0201cf16c9c8801801cb05f856cf16821005f5e1003d017ef8516f275b6c2232a182103b9aca00a1f85321a9b41770b609a1f84b01a070b609f85522025cba915b92a984e28200f20221f2f450037fdb3cf84b01a0f86b440108db3cdb313e0034fa02587658cb6bcc8210f5aa8943f82502cb1fcb3fccc970fb0001f4f85f6e8e82db3ce0f841c8cb07f84201ca00f84bfa02c8f854cf16f855fa02f8566e947001ca008e107f01ca007001ca00f856cf16f857fa02e2f8586e947001ca008e2b7f01ca0020cf31810278bc8e10c8f858cf16f859fa02c9017f01ca00cc9c7001ca00f858cf16f859fa02e2e2c901ccf85fcf16c9ed544a01f42182104bc7c2dfba925f068eec218210b27edcadba8e6032821073affe21ba8e4e7082009284f84158baf2f42282103b9aca00a18200f20021c200f2f4f84b21a0f86b5043a158a0f85da170fb02c8801001cb0501cf1670fa027001cb6a8210d53276db5802cb1fcb3fc98306fb00965f04840ff2f0e2e30de24101fe31337082009284f84158baf2f48200f104f85ef2f2fa00fa00d3170101d74cd0d31f0101fa4030f049305240018200928302c705f2f48200f100f84c5220bef2f4f859f84bf8555cba915b92a984e216a18212540be400a1f8506f2710365f0681011ef84ba9b40801a1b608f8526f225044b6095123b6088200f1015331bb4200725b6c227082009284f84158baf2f4d31f013101f049c8801801cb0558cf1670fa02017658cb6bcc8210d372158cf82502cb1fcb3fc98040fb0001f6f2f466b6088200f1025313bef2f4f84c5210a9b417c8801801cb0526cf1622fa027001cb6a82101690c604580802cb1fcb3f5316a0fa02c970fb005340f041f850405526f04701f870028200f10305a012bb13f2f4f85a8209312d00c88210b1ebae06f82502cb1fcb3f5004fa0258fa02500301cb17801070db3c430072226e91709322cf31e2c8500301cb055005cf165003fa0220cf3113a0810394bc9ac801cf17c97158cb6acc98017001cb6a01cf17e2c901fb0002748e95f854821005f5e1007053041046104755208306db3c8e9af854821005f5e100705304104610474313821011e1a30001db3ce2f85501a0f875494904ee8200f3002582101dcd6500bcf2f4d20001b301d2000131f8276f1026a1db3c82009285f842f2f2f84bf8552559a9845376a18212540be400a1f85da1f84d5004b0f841c000b05331bcb08e9630f2d0698200f20223f2f45054a1f85da170fb024300e30df8516f2710365f06a082103b9aca00a170b6095e46474801e6f8586e8e52f828f8506f1170f02a7021f90074c8cb025801ca07cbffc9d0f878c87001ca007001ca0070fa02c9c8801801cb05f858cf16821005f5e100fa02587658cb6bcc8210f5aa8943f82502cb1fcb3fccc970fb00def858821005f5e1007053041046104755208306db3cf85901a0f87949008c318200f20221c200f2f4f84b21a1f86bf8555004a1f8755054a121a1f85da170fb0212a1c8801001cb055003cf1670fa027001cb6a82100a77535c5802cb1fcb3fc98306fb000064f8516f275b6c2232a182103b9aca00a1f85321a9b41770b609a1f84b01a070b609f855f859595cba915b92a984e2bef2e0640068c882101674b0a0580802cb1fcb3f5005cf165003fa0201fa0201fa02c8801801cb055004cf1601fa027001cb6a58cf17c901fb0001c8f8526f22c8f8506f2706c8f40015cb1f13cb1f01fa0201fa0201fa020120c1001201ca0001b60bfa02c901ccf8516f2706c8f40015cb1f13cb1f01fa0201fa0201fa020120c1001201ca0001b60bfa02c901ccc9f84ff841c8cb07f84201ca00f84bfa024b01f4c8f854cf16f855fa02f8566e947001ca008e107f01ca007001ca00f856cf16f857fa02e2f8586e947001ca008e2b7f01ca0020cf31810278bc8e10c8f858cf16f859fa02c9017f01ca00cc9c7001ca00f858cf16f859fa02e2e2c901ccf84c01cb17f84d01ca00f84e01ca00cbffcc58fa0201fa02f85301cb174c006ac8f84acf16f85bcf16c9c8f843cf16f84401cb2ff848cf16f84901cb2ff85acf16ccc901ccf846f85cf845c8ccccccc901ccc9ed540201204f5002012056570201205152010bba8457fdb3c8550201665354010fb63cfb679e09261060010aab9a70db3c5502a6aa90eda2edfbdb3cf8276f10db3c92f85192f850e26f2710255f057f708e2b51138307f47c6fa5208e1a02fa00fa0030a05316ba9b355b3301ab0012a001db31e013a0029132e201b312e65f05840ff2f06d6d605e02ccdb3c8e86f8276f10db3cdef841f842f84bf84cf84df84ef84ff851f850f8526f22f853f854f855f856f857f858f859f843f844f848f849f85af84af85bf845f85cf846f8516f275b6c2232a182103b9aca00a1f85321a9b41770b609a1f84b01a070b609f855605e0201585859000bbb362f0493080201485a5b0201205c5d0030aa1d829035d676f6ac6e35e755ea3c4d7d7cf577627b1cf00260ab22db3c8e86f8276f10db3cde92f85192f850e26f275f0659f04930fa4431018307f40e6fa193307020e1fa00fa0030605e02d7adf76d9e7c13b7886d9e7c2f49af81bff07c265cc92dbff07c13b7887c2cfc25fc2aae5d48adc954c27150c1092a05f20050fc283793881b2f8340808f7c25d4da0400d0db047c29379128225b04a811db0429905e49af81bff05b0429015cc9183ff07c26290854da0bd040605e012bacfc6d9e3a6465812c00e503e5ffe4e87824987d22406001beeda2edfb70f87df8429130e0db3c6c21f900f84f21bd8e41f8516f2710455f05016eb301c200b1965b7ff87edb31e06df87ff85158f045f871f86ff8506f11a420f044f8506d7054700020105610576f0701f871f87070f87e945b70f87ee25f00268022f83320d0d30701c012f289d31fd31f305801f6ed44d0d30701f861d20001f862fa0001f86bd401d0fa4001f874fa0001f8756df87670f877d200018e1dd200019dd401d0fa4001f876fa0030f8779afa4001f876fa0001f877e2de6df87870f879d200018e1dd200019dd430d0fa4001f878fa0030f8799afa4001f878fa0030f879e29130e220f87fd31701f86c6101bed20001f86dd20001f86ed3ff01f86fd401d0d401d0f404d31fd31ffa00fa00fa00d20001aa00a401fa0002a8316f07f870d401d0f404d31fd31ffa00fa00fa00d20001aa00a401fa0002a8316f0731f871fa00fa00596f02f872d31701f873620072d401d0fa4001f863d32f01f864fa4001f868d32f01f869fa4001f87ad430d0fa4001f86afa4030f87bd401d0d401f865d401f87cd430f86630")?;
let master_data = hex::decode("b5ee9c720102f80100230d000479003f43e0325fa5b460005e07009977f3d6d2c07d9dc3b6ae967c1d106e2754d2a70759816e6fa40beac7b0d4c12309ce54000e1550f7dca7000051eb870102030400a18017be7f50131a2536a969ee76b758ba3c3fb23d60a82d38722dbf9199aa6da2000fb60013e784829aa00211d1b63230a79d3000e55751b2e9e2057297ec94a4b8bf7d60a81a971d2724d29d92d52c6d400200191a01e18003c88369fc91c04497d77e0bbd0fd0592beb4b691097cdc4ed6243c42ef03352c0000ce37e97500224991811c5c95012ccd211ecd7937387f845fb4122f8f3189f15fe2bf4a31133fffffffffffe0060a320e4ae24df48f29e3421a3282d004215e5122caed585b4d866c26094acf44005030006070800858016745d8491611777d8edabbf935ad3fe33a3804b2ad7c4eb59ddb608f63c2ebef003051907257126fa4794f1a10d1941680210af28916576ac2da6c3361304a567a20114ff00f4a413f4bcf2c80b0908420212bebb0dc8e202b7e26f721e2547e16bb9ebaec934f657d19f22e76d62bec8780114ff00f4a413f4bcf2c80b160201620a0b0202ca9d9e0201200c0d0201200e0f02012010110243b8408db3cf8276f105320a0db3c5aa9b417f84f13a1821809c765240058a058a00189fb80109b8916db3c8b8020120121302cdbbd35eda2edfbdb3cf841c000917fe1f8276f10821809502f900001821077359400a101a182103d648d80a12082202d79883d2000b992307fe0f84f8ea8800ff833d0d31f31d31fd31fd70b1f0132f86edb3c30f85058bc01f82303a112b9b094307fdb31e0de89fbe0141b6681b679f083f085f091f093f095f097f099f09bf09df09ff0a1f0a9f0abf08709f02016214150030aa1d829035d676f6ac6e35e755ea3c4d7d7cf577627b1cf00138ab05800ff833d0d31f31d31fd31fd70b1f0131db3c30315203a159a1be02016217180202cbc1c2020120d1d201318000019a800000103b80317ed8760003b805aa11e086ed00203a01318000019a000000113bb614792e362ef3bb63e9dc8b23e580201b0201201c1d0201201e1f020120797a0201202021020120303102012022230201202627005bbf0086c4e96b8d260c5716e1aa020d7500acc74c401193ac12126112bdc7dc5705c0d83b7c4b9c00149976b7c6ea0201202425005bbefaf0f8d4bd66d6aaf1e5e521d133a19c6ce95254e63443ef63346c8c6e295f3b81b076f89738002932ed6f8dd4005bbee0556bad023f80bc6806f85e5a33a27b492721e2bf5de920eaedc9c52dac91a381b076f89738002932ed6f8dd402012028290201582a2b005bbec370e08cdd4d42b21dc0d143c541c18617f04a2c7ae5cb761db883015d93258381b076f89738002932ed6f8dd4005bbed7358a75fe83ba8d4450525ab0d8b7e960937f0d9175018b5b91a0f4c7d42cb381b076f89738002932ed6f8dd40201202c2d005bbe86745a88779a1c5af4f6892b8c51eedbf53678435f9a057ec11f7a4218c75ac70360edf12e70005265dadf1ba80201202e2f005bbe4c229f8777e2292354a3a635011bbc459b3f7fa90d0ef03c438bff60d18acb2e06c1dbe25ce000a4cbb5be3750005bbe34edc7d3d0e4fdd16cb762158177615cfa750e306ea6253a257f5b68edaf2a5c0d83b7c4b9c00149976b7c6ea0005bbe2a72662b1630c2f776b516240e0318f46187f80d571ca70e34a4eb074d4bc0dc0d83b7c4b9c00149976b7c6ea002012032330201203637005bbf0c4f499810f6d72c3517e60b418cc918f795db6b68dfac49f99e1a67b7aef7c9c0d83b7c4b9c00149976b7c6ea0201203435005bbed51a9fe983d826ececc4752e527c07265c978fd8092379111673c41fbb8adc8b81b076f89738002932ed6f8dd4005bbefa250bafd08238994ffac841b58eaf0e6cf50cdf3396b97f760ddd8d00510e5382a7d51a14faef29e27d0df2c4005bbf1bbedf7dd19d70af3c0b0654707bfbac7fe7350ba66bb7fbc306229c46aa7875c0d83b7c4b9c00149976b7c6ea0201483839005bbea5d84f8a9f594098ffc67cda3adcf2768c21e7b6e9846054311e7b2b80ed16670360edf12e70005265dadf1ba8005bbe8b5166bb5837d9d31d96930100ea2bf48e4bbbbcb1bcff50015e8acc14a180270360edf12e70005265dadf1ba80201203b3c0201203d3e02012055560201203f400201204f500201204142020158494a02015843440201204748005bbe96ac3a99e0570e135ef62eddb0d7b6385cd21170d0dc06b19e90285802854d270360edf12e7000527b2ebd1e180201204546005bbe6f14a4a59ff5fa8511d94a9f2ac758033bb189937b4499820db30fd37e428aae06c1dbe25ce000a4f65d7a3c30005bbe596e0d72934350e89c60d10056395938983bedb3397326d0f3cb27902133d40e06c1dbe25ce000a4f65d7a3c30005bbec9563092270681f4cf8304c4de135f8ab01ea7a0b8ff52d92e36bed20e82297381b076f8973800293d975e8f0c005bbee04f1c4728400ec78b678c6c8178f3b8c110ed50568f64250082e6cc56a905c381b076f8973800293d975e8f0c0201204b4c0201584d4e005bbe9b2c4ba5cd9534dce9e7acd704c0e3cd2b55bac6d88295a1165bbc006f0adfd70360edf12e7000527b2ebd1e18005bbeabe98693a87b7f0fbc4d06a60f1e82f9dcb3f18b224bb67f579afd0d044919370360edf12e7000527b2ebd1e18005bbe6f0896fc3f9cb89d302a052dcab38f98132d154b073110d9f1a1b4bcebcf2cee06c1dbe25ce000a4f65d7a3c30005bbe76594ce54be912a2a5ca5255acaa44af0ac479dd36e3fedd7bbce0dccc84c6ae06c1dbe25ce000a4f65d7a3c3002012051520201205354005bbf32435e3878a0b9164da6374624486387cecb43f5f3dd9523e33d2c6378f65929c0d83b7c4b9c00149ecbaf4786005bbf05c6492f191f7fbf35ece9a2c2e081b6639cf749dd6e0f33ebb528e7ffdb65bdc0d83b7c4b9c00149ecbaf4786005bbf0c3c8680d7c55404311f8c50c10ddb6144273362715990146e5c4e81d92ad255c0d83b7c4b9c00149ecbaf4786005bbf3790fae505986c932c6894b905ecdada5552f205c764c59da789d9abd916c341c0d83b7c4b9c00149ecbaf478602012057580201206b6c020120595a0201205d5e0201205b5c005bbf05ede21f824c0c441cd8562b6287524d55f23c609708390466cce7116d15550dc15549b2f3b40014faa21f6afa005bbeea74c50c7a408081fc1c15f00ea73e9abcba3789896b5c696a9aa5b84242936381b076f8973800293d975e8f0c005bbec4ca7fa192aaa17bf55b4afcf9ec4449421693007f4e6e08da80f7204866321b81b076f8973800293d975e8f0c0201485f600201206364005bbeb5e7c2e8428bf1a724a216f5b67fe9775c65c6dd397fdc228e01e3251950fdd70360edf12e7000527b2ebd1e180201206162005bbe7bdbb49bb31c374d71ee189e7e8237d1ee2bb0fe9cace79c8f90c877404b07ee06c1dbe25ce000a4f65d7a3c30005bbe4abaf47fdf11dda9aaacb7d6bd24332b21b4bf8fb66bfb14a83c3de6ee606fae06c1dbe25ce000a4f65d7a3c30005bbefbfa43f9b776cb81c34701f05d2d44412e5ead0902af353d1bbff208f7fbcd4b81b076f8973800293d975e8f0c02012065660201486768020120696a005bbe0a3a56aeb63d44b8bf790e5a9c5a56c8d76aa7e7aacbd6bedac4f8515b60c2dc0d83b7c4b9c00149ecbaf47860005bbe138fe5e3cfd58347db497bea702cc0eb5233e9d491ef685eb73664e76836be9c0d83b7c4b9c00149ecbaf47860005bbe60987548dfe2346ecf288760a8f3ec99315608961875af8b17791faa69164dae06c1dbe25ce000a4f65d7a3c30005bbe5fdab6b985972f429c50684d6088044275db6dce94d52b6c9729e0a2d529aa2e06c1dbe25ce000a4f65d7a3c300201486d6e020120717202016a6f70005bbefd7b0dcb5d930cba3851409bb83a8c966cbf53839990a03372f619a6e5c1c64b81b076f8973800293d975e8f0c005bbe2737b149298c5afacd769da0d095e52316c1773ef96ca762cb9cb048757ec59c0d83b7c4b9c00149ecbaf47860005bbe094edcd9c7ef5f265b468327a97a333da9b90dd648ab6f5b0d0025850ffbeadc0d83b7c4b9c00149ecbaf478600201207374005bbf3badc2beba279d23af8e22d19d5a18ed68124a3b414bfdf103fbe153c740098dc0d83b7c4b9c00149ecbaf4786005bbec43db1c99b7759d2a35657d2558dade17a67dbf66c44f75b8be74f63e904019b82aa9365e7680029f5443ed5f402012075760201487778005bbebcef2850a954d37a2cdfbb060b552acd61cc8187f33ab165c60da204480d70870360edf12e7000527b2ebd1e18005bbe3520ddc8d10506259b59689912562b40acc422a2f65522bfdaef59a69257d4dc0d83b7c4b9c00149ecbaf47860005bbe21eb41e5e203feee5703341d05dd755bc4f1ba55ad68fc7fed27b22b566e79dc0d83b7c4b9c00149ecbaf478600201207b7c0201208b8c0201207d7e02012081820201587f80005bbf0a34574b02b0f0621f1a1362b6fd29ee00adcf7c3ade5ffe62d3847e541a2401c0d83b7c4b9c00149976b7c6ea005bbea2e3195054fc16b236c7062dac0a9f294053fe8c7a2c5f5e5ad8108ae2bd4b570360edf12e70005265dadf1ba8005bbe9a1efe210596d7428922c8520176a2e935ca3ff0db448553603c34600c9dc3170360edf12e70005265dadf1ba802012083840201628788005bbee162328bfef52aea737cd73fcd7ab333c974f77a9df9d115daa12984f7ee63eb81b076f89738002932ed6f8dd40201488586005bbe58dc36f43ee517e39e67a5240bcaf2f113a91241b0703df325a2ffd5a4e6228e06c1dbe25ce000a4cbb5be3750005bbe65a0c0951603a87a1c83123ea4058a085d49aa316381542124f0d728e605324e06c1dbe25ce000a4cbb5be375002016a898a005bbe71a27ffd9438ef5c87053811ce2eaba1581bcd1f442cd65d0224a99da49e1a0e06c1dbe25ce000a4cbb5be3750005abd9c2955eacf0d86ad4a230b843f36be031973dd7145720ae084939a604e8ffa70360edf12e70005265dadf1ba005abdb67bfc8a804671ebd681019a321c2bb4ca8ebaad4ab862e3a3ddf5695fd53570360edf12e70005265dadf1ba0201208d8e0201209394005bbf3c7343dbd5e7212ce999d2329fd3d69a7503d35e8964465453ee717079564239c0d83b7c4b9c00149976b7c6ea0201208f900201209192005bbed81f24acb3386193cfe14a2140757062447f560a43dc0ee81dd65d8146f8504381b076f89738002932ed6f8dd4005bbeaa679ab93ce46a109383203c1db09dd26cd5ef69ae79572c18dcda0ff3c5e9c70360edf12e70005265dadf1ba8005bbea5b6eea326f42192c131b94322750779b474eb6b5dd8009202aa7184a4ba3bc70360edf12e70005265dadf1ba802012095960201589b9c0201589798005bbef080c966f748c6cdf29c2f46f27755794ebff29fe9c8be6b7182054f6149050382aa9365e7680029e46f7c62ac005bbe561b065b72bbf9cbd1d32298b6d57b64239307c6a6711b88909aeb1156471e2e06c1dbe25ce000a4cbb5be3750020158999a005bbdec40d58b68097d5b1a0eb89f0a70c4aef58c41ba5767c04696ca9ceaa2dae9381b076f89738002932ed6f8dd40005bbdde9abb8d538589f4a53592caec9c61ebb423a000645714c538e00789af266b381b076f89738002932ed6f8dd40005bbea96c3e4c9d8ea2309f14819a16496eb2d7812ea2a5dc88d4fd9c1e068bb0b0770360edf12e70005265dadf1ba8005bbe89c829fae4581c191cbfdf704b75e5da9197e9213a1e4e01d71b731d3b4da9a70360edf12e70005265dadf1ba804f7d407434c0fe900c36cf005c6c23db4cc835d2708fe3b7e00835c874c7c04c482084139cdd12ee88f6cf2c27d7c0fe107000a4dc3e1864dffe18b8a38e3e1544f1c1638b88608437f7289eeea6cc7e13c0683e1bfe08fe1c2385cc20843990b2596ea77e10700064dc3e1864dffe18b8b7b8a456f8b8a497c0f8b6cf29fa1bfa00103aca0c000e0ed44d0d30701f861d20001f862d20001f868fa0001f869d32f01f86ad3ff01f86bd30701f86cd32f01f86dd32f01f86efa0001f86fd32f01f870fa4001f863d32f01f864d31701f87120f872d430d0d31f01f873fa4001f874fa4001f875fa4001f865d430d0fa4001f876fa4030f8670476e001d31fd33f5923db3c8ead218210d372158cba8e215f05f841c0058e168212cb417800f84fa082100ee6b280a0bc9370f861de9130e2e30ee30da1a2a3a40108db3cc705ba03ba2182101690c604ba8f512182107b4b42e6ba8e1310355f05f856018200928302c705f2f47ff8688f31218210e8a0abfeba8e1310355f05f856018200928302c705f2f470f8688f11218210270695fbba8e855b6c22db3ce30ee2e2e30da5a6a702f46c2232f800208210f96f7324ba8ec370f861f84f8eb8821077359400f84fa013be8ea5f855f84fc88210dfdca27b580402cb1fcb3fc912801871db3c70f86f70f87070f86970f86a943075f861e2926c21e28e1d6c21208210fffffffeba8e10f841c004967ff86275f861937ff862e2dee2f841c0029130e30dbcbd0104db3cbf0048f84312018200928302c705f2f48200a000f823f84482015180a0bcf2f4d307d43001fb00034821821079e7c016ba8e855b6c22db3c8f122182107247e7a5ba8e8610355f05db3ce30ee2a8a9aa00865b33f855018200928302c705f2f4f85094f823f870df01fa00f84f22a0f86fd18200fa05f8518317a013a9b41782103b9aca00a0b9f2f470f871f841c0019370f861de002cf84512018200928302c705f2f4f823f864fa4030f863001ef845018200928302c705f2f470f86203ec21821055c26cd5ba8ed7345b7582009284f84158baf2f4f845018200928302c705f2f401821077359400a182100ee6b280a1f84fb608f855c88210dfdca27b580402cb1fcb3fc9542220801871db3cf84f01a1f86ff84fc0009670f87070f861de8f12218210139a1b4eba8e8610355f05db3ce30ee2bcabac001ef847018200928302c705f2f47ff862033c82009285f842f2f2218210eb373a05ba8f0a218210f0fd2250bae30fe30dadaeaf03dc5b327382009284f84158baf2f401d18200f700f84cc103f2f4db3c31f9008200f701f84b22bdf2f4f86bf84ca4f86cf823f86d800ff833d0d31f31d31fd31fd70b1f013031f84e01b609f86ef82301a1810258b9f84fc000b18e9131f8545210018200928302c705f2f4db3ce30ebeb7b003ca2182108efed779ba8ece3133337082009284f84158baf2f48200f800f84ff2f2f854018200928302c705f2f401fa00d18200f80121c200f2f482107735940072fb02f854c8821030026327580402cb1fcb3fc9801070db3c8f0a2182104e73744bbae30fe2bcb1b203e4317382009284f84158baf2f401d18200f600f84cc201f2f4f823f84da1f84ea18200f601f84cc20222c23cb1f2f48200f6022482103d648d80bef2f4c8821047657424580302cb1fcb3fc9db3c705880188040db3c74f861810258b9f84fc000b19e6c21f854018200928302c705f2f4e30ebabcbb0156018212540be400a1821077359400be8e97f8545210c70591308e8c8212540be4006d801072db3ce29130e2bc03f4317082009284f84158baf2f4f85413018200928302c705f2f48200f90022f2f48200f9010382103d648d80be13f2f401fa0020db3cf86a2182103d648d80a1f8698200f9022282202d79883d2000bef2f4821809c76524008200f9035353a122bef2f4800ff833d0d31f31d31fd31fd70b1f0132f86edb3cf84fb3beb403b02182106335b11aba8f4c34318210ed7378a6ba8f397082009284f84158baf2f48200fb00f84ff2f4db3c5b8200fb01f8505220bcf2f4f82301a1821077359400f84fa05240be955f0475f861e30d965f03840ff2f0e2e30dbeb5b60026d3ff31d31f01f86ad31f31d3ff31d431d1f84a03a88e148200f904f85024bc03f82306a115b912b013f2f4923330e2f84f17a158a18200f905f849db3c12bef2f472f861f900f86b70f86c03f86ddb3cc882104e73744b580402cb1fcb3f5003cf16c912801871db3cb8babc03d2f855f84fc88210dfdca27b580602cb1fcb3fc94140801871db3c70f86f70f87001810258b98e9131f8545210018200928302c705f2f4db3c8eae821077359400f84fa08212540be400a012be8e97f8545210c70591308e8c8212540be4006d801072db3ce29130e2e2bcb7bc03fc317082009284f84158baf2f4f85413018200928302c705f2f48200f6040382103b9aca00be13f2f421fa0031fa00d3170101d120f8718200fa00f848f2f48200fa01f84ff2f2800ff833d0d31f31d31fd31fd70b1f0131db3c30318200fa0221f82305a114bc13f2f48200fa0302f82302a1b9f2f45314a0db3c59a9b417beb8b90110706d80108042db3cbc00848028f833206e985b8218178411b200e0d0d30731fa00d31fd30fd30fd30f31d30f31d30fd30f305053a8ab075033a8ab075023a8ab0759a8ab075220a9b41fa0b608017af84f15a18200fa04821809c76524005003a05005a014be13f2f4c88210e642c965580302cb1fcb3f01cf16f852cf16c9f855705880188040db3c71f861bc001671f833d0d70bff7f01f032015859a18212540be400a1821077359400be8e97f8545210c70591308e8c8212540be4006d801072db3ce29130e2bc0046226eb3c8500301cb055005cf165003fa0202957158cb6acc95307001cb6ae2c901fb000152208210ee6f454cba943070f8618e998210f374484cba8e8b73f861db3c6c21f900f86b937ff862e2e2be00268022f83320d0d30701c012f289d31fd31f30580090f84cf84bf841c8cb07f84201ca00f84801ca00f849fa02f84a01cb2fcbffcb07f84d01cb2ff84e01cb2ff84ffa02f85001cb2ff843cf16f84401cb2ff85101cb17f852cf16c9ed54001874c8cb025801ca07cbffc9d004e5d0831c02497c0f8007434c0c05c6c2497c0f83e900c0074c7f4cfd67b51343e803e903d01350835d2a775d33434cffe903e903e90350c260c22c09c150c401b788aa0843d6aa250eeb8c0899bacfcb810c9b43480004b2084059d2c282eb8c08e0ae0841cd8b4272eb8c08ae08404502993eeac3c4c5c6020120cacb00963638383a840f5194c70519f2f406d43020d0d749f2e14d1038471645155044c85009fa025007cf1615f40013cc21c2008e1201c8cb3f58cf1658cf1658cf1612ccc901cc926c51e2c9ed5403e031343a3c51a5c705f2e049f2d04807fa40fa0030276e8e8d3739885270f01920f01a50aa07de08a45158a0885260f01920f01ac88210132f9a4501cb1f500901cb3f5003cf165009fa0226cf1629cf16c9778018c8cb052ccf1670fa02cb6b18cc17ccc98040fb001068476510344130dcdcd001de3b3d05f2d04408d20001f2e045fa0031fa403051aac705f2e04708fa00fa40305305c70501d70b01c000b1f2e04fc87f01ca007f01ca0001fa025009cf16c9c8801801cb0527cf168208989680fa027001cb6a8210f127fe4e01cb1f500601cb3fc971fb0010381027104645150403d002dc8ed93b3b51b6c705f2e05004f2d04407d2000131f2d046c87f01ca007001ca000a8208989680a11afa02c9c8801801cb0523cf168208989680fa027001cb6a8210f127fe4e01cb1f500601cb3fc971fb0010381027104605035024e0353d098210ed58b0b2bae3025f0c840ff2f0d0c704e604f2e04208fa00fa40d33f30885210f019f01a500cc705f2e04a02d2000101fa00547318a984c87f01ca002401ca005131a113fa02038e2630c8801001cb055004cf165003fa027001cb6a8210db3b8abd01cb1f2701cb3fc98040fb0001e30dc929c0009136e30d14a1471810461035414013dcc8c9d0009efa4030c8801801cb0521cf1670fa026dc882100f8a7ea501cb1f2c01cb3f5004fa0226cf165006cf1612f4008208989680fa027001ca008210db3b8abd01cb1fc9147158cb6accc98040fb0058cf160046c8801001cb0525cf1670fa027001cb6a82104bc7c2df01cb1f500701cb3fc98306fb0002016acccd020148cecf003b1c081c638500deaa43298c092a04a800ea81c0a9087000110c398c1b04a0005920840ee6b2802a43007c05006a80904c33c0600b8072c1c07c051e48a865e00c1400f2c1c0b9006a8084b3c06000355c87001ca00f828cf1612cb3fc97020c8cb0113f400f400cb00c98001d4f90074c8cb027001ca07cbffc9d080058c85009fa025007cf1615f40013cc21c2008e1201c8cb3f58cf1658cf1658cf1612ccc901cc926c51e2c9ed54020120d3d4020120f4f502f9b8b5d31ed44d0fa00fa40f404d420d74a9dd74cd0d33ffa40fa40fa40d43098308b02705431006de25f056c2202d0fa003001d071d721d200013102d078d721f4043082f082a3537ff0dbce7eec35d69edc3a189ee6f17d82f353a553f9aa96cb0be3ce89218307f40f6fa130d078d72170c8cb0789cf165003f015238d5d6020120dadb001242696c6c20666f722002b49c8b820544f4e20696e208cf168e158d0408141bdbdb0812995d1d1bdb881a5b8820cf16e258cf16c982f082a3537ff0dbce7eec35d69edc3a189ee6f17d82f353a553f9aa96cb0be3ce89588307f41701e30f70c8cb07f400c9d7d801c88d165113c81393d50814d153910813d38810d3d395149050d514ce88105d5d1bdb585d1a58d85b1b1e4818dbdb9d995c9d1cc819195c1bdcda5d1959081513d3881d1bc8141bdbdb0812995d1d1bdb9cc81dda195b881c9958591e6070c8cb0701cf16c9d900f48d121113c81393d50814d153910813d38810d3d395149050d514ce8810dbdb9d995c9d1cc8189d5c9b995908141bdbdb0812995d1d1bdb9cc81d1bc81513d3881dda195b881c9958591e6070c8cb0701cf16c982f0c9046f7a37ad0ea7cee73355984fa5428982f8b37c8f7bcec91f7ac71a7cd104588307f417004e82f0c9046f7a37ad0ea7cee73355984fa5428982f8b37c8f7bcec91f7ac71a7cd104588307f4170057b48a5da89a1f401f481e809a841ae953bae99a1a67ff481f481f481a86130611604e0a86200dbc420d0be110010fb4f4711e033e0350dc0114ff00f4a413f4bcf2c80bdd020162dedf0202cbe0e1020120f1f2020120e2e3020148ebec04b1d9910e380492f81f068698180b8d8492f81f07d207d2018fd0018fa0218fd0018fd001839d4da0001698fe99facf80980d9f1811141082fe61e8a5d7181199a1a11c1087893ff275d47421980ed9e701801410817e593515d4e4e5e6e70011bbf488618001e5c29b00c230313333840ff84258c705f2f401fa40fa00fa40fa4030235520f0168210055d4a8072fb0270821005138d9121c8cb017001ca0010344130810082c8801001cb055006cf165004fa027001cb6a5902cb1fcb3f216eb39301cf179131e2c901fb0002a23240045134c705f2e191fa4021f00dfa40d20031fa0020d749c200f2e2c4078210055d4a80a121945315a0a1de22d70b01c300209206a19136e220c2fff2e19221941027365be30d0293135f03e30df015e8e901cef0145262c7055164c70516b1f2e19124d70b01c3008e350482089896808210f127fe4e256d71c8801001cb055006cf165004fa027001cb6a5902cb1fcb3f216eb39301cf179131e2c901fb009134e2708210ed58b0b2c85006fa025006cf16cb3f1443308100a0ea00888e3df0145f037082108b77173502c8cbff5003cf1641308040c8801001cb055006cf165004fa027001cb6a5902cb1fcb3f216eb39301cf179131e2c901fb00e05bf2c196007c821005138d91c85008cf165008cf1671244814544690c8801001cb055006cf165004fa027001cb6a5902cb1fcb3f216eb39301cf179131e2c901fb001034006823f00d43308210d53276db016d71c8801001cb055006cf165004fa027001cb6a5902cb1fcb3f216eb39301cf179131e2c901fb00004cc8801001cb055006cf165004fa027001cb6a5902cb1fcb3f216eb39301cf179131e2c901fb00002bf76a268690010ca7d207c30f0107c30fd20187c3136c020120edee020120eff000394c801cf16c9c87f01ca005004cf16f841cf1658fa0201cf16ccc9ed54800213e107e9034cffe803e9035d3343e900c20001f321fc072800073c5be1073c5b27b55200017bfce0f809adf80a08122f824020148f3f7001bb5f9fe027e028b79003f40592270020120f6f70057ba1e6ed44d0fa00fa40f404d420d74a9dd74cd0d33ffa40fa40fa40d43098308b02705431006de210475f0780059b60b7da89a1f401f481e809a841ae953bae99a1a67ff481f481f481a86130611604e0a86200dbc4be0868620300031b443b05206baceded58dc6bceabd4789afaf9eaeec4f639e10")?;
let c7 = TVMEmulatorC7::new(address, BC_CONFIG.clone())?;
let mut emulator = TVMEmulator::new(&master_code, &master_data, &c7)?;
let emulated = assert_ok!(emulator.run_get_method("get_pool_full_data", TVMStack::EMPTY_BOC));
assert_eq!(emulated.vm_exit_code, 0);
Ok(())
}
#[test]
fn test_tvm_emulator_with_libs() -> anyhow::Result<()> {
sys_tonlib_set_verbosity_level(0);
// stonfi pton https://tonviewer.com/EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs
let owner_address = TonAddress::from_str("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs")?;
let expected_address =
TonAddress::from_str("0:2671da62fc5e6e970e198e05bbf3304136df8203cc3f0b7172827a3b0c4a24e3")?;
// stonfi pton https://tonviewer.com/EQBnGWMCf3-FZZq1W4IWcWiGAc3PHuZ0_H-7sad2oY00o83S
let master_address = TonAddress::from_str("EQBnGWMCf3-FZZq1W4IWcWiGAc3PHuZ0_H-7sad2oY00o83S")?;
let code_boc = hex::decode(
"b5ee9c7201010101002300084202d29017573b8132be742e9c02dabe2311fb3df9f077e661d3ee24d431058b8830",
)?;
let data_boc = hex::decode("b5ee9c7201010301005d000208000000000102084202cd88e6f3c2a9cf01bb003a2837ec0d92c19685ed1dbfffd94a545dcfdf0a14d900600168747470733a2f2f7374617469632e73746f6e2e66692f6a6574746f6e2f746f6e2d70726f78792d76322e6a736f6e")?;
let c7 = TVMEmulatorC7::new(master_address, BC_CONFIG.clone())?;
let mut emulator = TVMEmulator::new(&code_boc, &data_boc, &c7)?;
let mut stack = TVMStack::default();
stack.push_cell_slice(owner_address.to_cell_ref()?);
// no libs - should fail
let emulator_error = assert_err!(emulator.run_get_method("get_wallet_address", &stack.to_boc()?));
if let TLError::EmulatorEmulationError {
vm_exit_code,
response_raw,
} = emulator_error
{
assert_eq!(vm_exit_code, Some(9));
assert!(response_raw.contains("D29017573B8132BE742E9C02DABE2311FB3DF9F077E661D3EE24D431058B8830"));
} else {
panic!("Expected TVMGetMethodError, got: {emulator_error:?}");
}
// add required lib
let lib_cell = TonCellRef::from_boc_hex("b5ee9c7201022501000a0e000114ff00f4a413f4bcf2c80b0102016202030202c90405020120060701cbd8831c02497c138087434c0dc009c6c260c5fc0a00835c85677be903e900c7e800c5c75c87e800c7e800c1cea6d0000f4c7f4cfc412040dc415914110c4dbc27e187e105bc4373e105bc45c007e910c006ebcb8157b513434c7c07e18b5007e18f5007e1934608020148090a001bbe0c83938c5bb932b632b0b9b2c40202710b0c024ef8416f17f8416f1382104f5f4313ba8e8ff8416f1382102c76b973bae3023070e30ddc840ff2f00d0e0145a610411806f05b59d3b200005cc708c11806f05b59d3b20000290154c2782651f187400f0137a410411806f05b59d3b200005d4d98411812dca375e059b0b9f187401000f5adbcf6a268698f80fc316a00fc31ea00fc3268903800fd221800dd79702afc1400e4387d0100e78b00e78b64fc2180b6b6b7823810b7921037471a2d81b79210b7470918b810646580a9207a0029187a0065806480ef2198291837820098907c803a6465810a650389e5ffe4e82009c91a1a712a8111b7820098c00037af16f6a268698f80fc316a00fc31ea00fc3268b83fc5817c227c21c001fefa40d200d195c821cf16c9916de2f82822c870fa0201cf1601cf16c9f843016d6d6f04027001fa443001ba8e480170216f24206e8e345b036f24216e8e12317020c8cb015240f4005230f400cb00c901de433052306f04013120f90074c8cb0214ca0713cbffc9d04013923434e25502236f04013193318b02e282089896801101daf8416f16f8416f12a7038208989680a08208989680a08208989680a08208989680a0bcf2e053fa40fa40d1217001fa443001ba217001fa443001bab0f2e055f82858c870fa0201cf1601cf16c9f843016d6d6f048208989680f8416f15f82ca0f8416f16a101b60970fb0270661201fe702182b05803bcc5cb9634ba4cfb2213f784019318ed4dcb6017880faa35be8e23308288195e54c5dd42177f53a27172fa9ec630262827aa23a904821b782dace9d9aa18de2182708bcc0026baae9e45e470190267a230cfaa18be8e1c0182501425982cf597cd205cef7380a90401821b782dace9d9aa17a0dea76401a7641302fc8200c354218235c702bd3a30fc0000be228238070c1cc73b00c80000bbb0f2f420c1008e1282300de0b6b3a76400005202a3f05812a984e020821b782dace9d9aa18be8e2820821b782dace9d9aa17be8e18821b782dace9d9aa17a182501425982cf597cd205cef73809171e2e30d01a7648238056bc75e2d631000002114150096f8416f15f82ca0f8416f16a101b60970fb0270f8416f1150238210d1735400f8416f1401c8cb1fcb3f58cf16f40012810090708018c8cb055004cf165004fa0212cb6a01cf17c901fb007f01fe216f24206e8e345b036f24216e8e12317020c8cb015240f4005230f400cb00c901de433052306f04013120f90074c8cb0214ca0713cbffc9d04013923434e25502236f0401016f24216e8e12317020c8cb015240f4005230f400cb00c901de433052306f0401310382106540cf85f8416f1401c8cb1fcb3f01cf16413083061601f2208261855144814a7ff805980ff0084000be8e2a8238056bc75e2d631000008261855144814a7ff805980ff0084000a98401822056bc75e2d631aa18a001de20824adf0ab5a80a22c61ab5a700be8e278238056bc75e2d63100000824adf0ab5a80a22c61ab5a700a98401822056bc75e2d631aa17a001de20170042821b782dace9d9aa18a18288195e54c5dd42177f53a27172fa9ec630262827aa2303fc822056bc75e2d631aa18be8e1c30822056bc75e2d631aa18a18261855144814a7ff805980ff0084000de21822056bc75e2d631aa17be8e2701822056bc75e2d631aa17a101824adf0ab5a80a22c61ab5a7008238056bc75e2d63100000a984de21822056bc75e2d631aa16bee30021823815af1d78b58c400000bee3002118191a0034768018c8cb055005cf165005fa0213cb6bcc01cf17c901fb007f02f882403f1fce3da636ea5cf850be8e268238056bc75e2d6310000082403f1fce3da636ea5cf850a98401822056bc75e2d631aa16a001de20823927fa27722cc06cc5e2be8e268238056bc75e2d63100000823927fa27722cc06cc5e2a98401823815af1d78b58c400000a001de208238280e60114edb805d03bee300201b1c004c01822056bc75e2d631aa16a10182403f1fce3da636ea5cf8508238056bc75e2d63100000a984004c01823815af1d78b58c400000a101823927fa27722cc06cc5e28238056bc75e2d63100000a98402f482380ad78ebc5ac6200000be8e260182380ad78ebc5ac6200000a1018238280e60114edb805d038238056bc75e2d63100000a984de218238056bc75e2d63100000be8e26018238056bc75e2d63100000a10182380ebc5fb417461211108238056bc75e2d63100000a984de218232b5e3af16b1880000bee300211d1e004c8238056bc75e2d631000008238280e60114edb805d03a9840182380ad78ebc5ac6200000a00102f482380ebc5fb41746121110be8e268238056bc75e2d6310000082380ebc5fb41746121110a984018238056bc75e2d63100000a001de20823808f00f760a4b2db55dbe8e258238056bc75e2d63100000823808f00f760a4b2db55da984018232b5e3af16b1880000a001de20823806f5f1775788937937bee300201f20004a018232b5e3af16b1880000a101823808f00f760a4b2db55d8238056bc75e2d63100000a98401ec82315af1d78b58c40000be8e250182315af1d78b58c40000a101823806f5f17757889379378238056bc75e2d63100000a984de218238056bc75e2d6310000021a0511382380ad78ebc5ac6200000a98466a0511382381043561a8829300000a98466a05113823815af1d78b58c400000a98466a0511321004a8238056bc75e2d63100000823806f5f1775788937937a9840182315af1d78b58c40000a00101ec823806248f33704b286603be8e258238056bc75e2d63100000823806248f33704b286603a984018230ad78ebc5ac620000a001de20823805c548670b9510e7acbe8e258238056bc75e2d63100000823805c548670b9510e7aca98401823056bc75e2d6310000a001de208238056bc75e2d63100000a12201ea82381b1ae4d6e2ef500000a98466a0511382382086ac351052600000a98466a05113823825f273933db5700000a98466a05113822056bc75e2d631aa16a98466a05113823830ca024f987b900000a98466a0511382383635c9adc5dea00000a98466a0511382383ba1910bf341b00000a98466a0032301fe8238056bc75e2d631000005122a012a98453008238056bc75e2d63100000a9845c8238056bc75e2d63100000a9842073a90413a051218238056bc75e2d63100000a9842075a90413a051218238056bc75e2d63100000a9842077a90413a051218238056bc75e2d63100000a9842079a90413a0598238056bc75e2d631000002400428238410d586a20a4c00000a98412a08238056bc75e2d63100000a984018064a984001ca984800ba904a0aa00a08064a904")?;
let emulator_libs_boc = LibsDict::new([lib_cell.clone()])?.to_boc()?;
emulator.set_libs(&emulator_libs_boc)?;
let emulated_result = emulator.run_get_method("get_wallet_address", &stack.to_boc()?)?;
let emulated_addr = TonAddress::from_cell(emulated_result.stack_parsed()?.pop_cell()?.deref())?;
assert_eq!(emulated_addr, expected_address);
Ok(())
}
#[test]
fn test_usdt_get_wallet_data() -> anyhow::Result<()> {
sys_tonlib_set_verbosity_level(0);
let code = hex::decode(
"b5ee9c72010101010023000842028f452d7a4dfd74066b682365177259ed05734435be76b5fd4bd5d8af2b7c3d68",
)?;
let data = hex::decode("b5ee9c72010101010046000087008002c3ee8d5843cc6c087de8532a8dad964b352086a4ac814d0bb1853db786e9967002c44ea652d4092859c67da44e4ca3add6565b0e2897d640a2c51bfb370d8877fa")?;
let c7 = TVMEmulatorC7::new(
TonAddress::from_str("EQCFjWfR2q-usR_WKfSkr8C2qQlpn02ZOFd0zclmJvzVzgIx")?,
BC_CONFIG.clone(),
)?;
let mut emulator = TVMEmulator::new(&code, &data, &c7)?;
// add required lib
let lib_cell = TonCellRef::from_boc_hex("b5ee9c7201020f010003d1000114ff00f4a413f4bcf2c80b01020162020302f8d001d0d3030171b08e48135f038020d721ed44d0d303fa00fa40fa40d104d31f01840f218210178d4519ba0282107bdd97deba12b1f2f48040d721fa003012a0401303c8cb0358fa0201cf1601cf16c9ed54e0fa40fa4031fa0031f401fa0031fa00013170f83a02d31f012082100f8a7ea5ba8e85303459db3ce0330405020120060701f203d33f0101fa00fa4021fa4430c000f2e14ded44d0d303fa00fa40fa40d15309c7052471b0c00021b1f2ad522bc705500ab1f2e0495115a120c2fff2aff82a54259070546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c920f9007074c8cb02ca07cbffc9d004fa40f401fa00200802d0228210178d4519ba8e84325adb3ce034218210595f07bcba8e843101db3ce032208210eed236d3ba8e2f30018040d721d303d1ed44d0d303fa00fa40fa40d1335142c705f2e04a403303c8cb0358fa0201cf1601cf16c9ed54e06c218210d372158cbadc840ff2f0090a0027bfd8176a2686981fd007d207d206899fc15209840021bc508f6a2686981fd007d207d2068af81c019820d70b009ad74bc00101c001b0f2b19130e2c88210178d451901cb1f500a01cb3f5008fa0223cf1601cf1626fa025007cf16c9c8801801cb055004cf1670fa024063775003cb6bccccc945370b03f4ed44d0d303fa00fa40fa40d12372b0c002f26d07d33f0101fa005141a004fa40fa4053bac705f82a5464e070546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c9f9007074c8cb02ca07cbffc9d0500cc7051bb1f2e04a09fa0021925f04e30d26d70b01c000b393306c33e30d55020c0d0e01f2ed44d0d303fa00fa40fa40d106d33f0101fa00fa40f401d15141a15288c705f2e04926c2fff2afc882107bdd97de01cb1f5801cb3f01fa0221cf1658cf16c9c8801801cb0526cf1670fa02017158cb6accc903f839206e943081169fde718102f270f8380170f836a0811a7770f836a0bcf2b0028050fb00030e00b42191729171e2f839206e938124279120e2216e94318128739101e25023a813a0738103a370f83ca00270f83612a00170f836a07381040982100966018070f837a0bcf2b0048050fb005803c8cb0358fa0201cf1601cf16c9ed540060c882107362d09c01cb1f2501cb3f5004fa0258cf1658cf16c9c8801001cb0524cf1658fa02017158cb6accc98011fb00007a5054a1f82fa07381040982100966018070f837b60972fb02c8801001cb055005cf1670fa027001cb6a8210d53276db01cb1f5801cb3fc9810082fb0059002003c8cb0358fa0201cf1601cf16c9ed54")?;
let emulator_libs_boc = LibsDict::new([lib_cell.clone()])?.to_boc()?;
emulator.set_libs(&emulator_libs_boc)?;
let emulated = assert_ok!(emulator.run_get_method("get_wallet_data", TVMStack::EMPTY_BOC));
assert_eq!(emulated.stack_parsed()?.len(), 4);
assert_eq!(emulated.vm_exit_code, 0);
Ok(())
}
#[test]
fn test_tvm_emulator_send_int_ext_msg() -> anyhow::Result<()> {
sys_tonlib_set_verbosity_level(0);
let code = hex::decode("b5ee9c7201021301000463000114ff00f4a413f4bcf2c80b0102016202030202cb040502037a600f1004f7d0831c02497c0f8007434c0c05c6c2497c0f83e903e900c7e800c5c75c87e800c7e800c00b4c7f4cffb51343500743e903e903e900c00fe8034c034e7f5350c0411cab00578c08aa0841657c1ef2ea3854d57c0cd4d56cd04b1c17cb812407e90350c04bc04780aa0841ef765f7aeb8c08aa0840b1dae5ceeb8c08e6060708090201ce0d0e008a39393a5181c705f2e04904fa40d43020d08060d721fa00304bb0527cf0105028a00744655023c85007cf165005cf165003cf16c9c85006fa02cb00cb9f13cc12ccccc9ed5401fe3a3b3b05fa00fa40f82854120a70542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c9f9007074c8cb02ca07cbffc9d0500ac705f2e04a14a145465412034a99c85007cf165005cf165003cf16c9c85006fa02cb00cb9f13cc12ccccc9ed54f40482103afd461c708018c8cb055005cf1624fa02140a01fe3a5f07048208989680a015bcf2e04b02fa40d3003095c821cf16c9916de28210d1735400708018c8cb055005cf1624fa0214cb6a13cb1f14cb3f23fa443070ba8e33f828440370542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c9f9007074c8cb02ca07cbffc9d0cf16966c227001cb01e2f4000b01fe3b3b27821062dd86f1ba8e3032365161c705f2e04902fa403046755023c85007cf165005cf165003cf16c9c85006fa02cb00cb9f13cc12ccccc9ed54e027821066447dadba8e363334355154c705f2e04970c8cb01c9d017104644155023c85007cf165005cf165003cf16c9c85006fa02cb00cb9f13cc12ccccc9ed54e0270c007acb6a13cb1f5230cb3ff400c98040fb00fa403020d70b01c3008e1f8210d53276db708010c8cb055003cf1622fa0212cb6acb1fcb3fc98042fb00915be2000ac98040fb0000fc821011db408aba8e3031365161c705f2e04902fa403046745023c85007cf165005cf165003cf16c9c85006fa02cb00cb9f13cc12ccccc9ed54e039068210743f8e58ba8e325161c70507c00017b1f2e0497102d430470703c85007cf165005cf165003cf16c9c85006fa02cb00cb9f13cc12ccccc9ed54e05f09840ff2f000950cfe0a005c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c032483e401c1d3232c0b281f2fff2741de0063232c15633c5a082bebc203e80b2daf333325c7ec020008b0cfe0a005c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c0327e401c1d3232c0b281f2fff2741c60063232c15633c59c3e80b2dab33260103ec020009badbcf6a2686a00e87d207d207d201801fd00698069cfea6a180823b638fc1400b82a1009aa0a01e428027d012c678b00e78b666491646580897a007a00658064fc80383a6465816503e5ffe4e8400201201112003cab46ed44d0d401d0fa40fa40fa403003fa00d300d39fd4d43010475b6c240040aa2ded44d0d401d0fa40fa40fa403003fa00d300d39fd4d43010476c427f5520")?;
let data = hex::decode("b5ee9c720102230100050b00033b90684aff1b327c3906d800000000000000000000000000000000000000040102030086801bc72bea2cb2070ee096fea5a30b20dcd60823f1e2427d8ba030e52ac9d45fb184009570aa1bb7d78ae8a80a769915a7fc4adb7332ed4d031c952b928fd6b87e5d9b010300c0040114ff00f4a413f4bcf2c80b1202012005060143bff082eb663b57a00192f4a6ac467288df2dfeddb9da1bee28f6521c8bebd21f1ec007020120080900a40068747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6f726269742d636861696e2f6272696467652d746f6b656e2d696d6167652f6d61696e2f746f6e2f6574682e706e670201200a0b0201200e0f0141bf4546a6ffe1b79cfdd86bad3db874313dcde2fb05e6a74aa7f3552d9617c79d130c0141bf6ed4f942a7848ce2cb066b77a1128c6a1ff8c43f438a2dce24612ba9ffab8b030d0034004f726269742042726964676520546f6e20457468657265756d000a006f4554480141bf5208def46f5a1d4f9dce66ab309f4a851305f166f91ef79d923ef58e34f9a209100141bf5d01fa5e3c06901c45046c6b2ddcea5af764fea0eed72a10d404f2312ceb247d11004c004f726269742042726964676520546f6b656e206f6e20544f4e20626c6f636b636861696e21000600313802016213140202cb1516001ba0f605da89a1f401f481f481a86102012017180201621c1d020148191a01f1f81e99ffd007d2010f801f6a2687d007d207d206a18289b50a9156382f9716094617ff971612a1a21382a1009aa0a01e428027d012c678b00e78b666491646580897a007a00658064907c80383a6465816503e5ffe4e8027d207a0218fd00106ba4e1007971623bc00c646582a804678b387d010be5b589e641b00b7420c700925f04e001d0d3030171b095135f03f012e0fa40fa4031fa003171d721fa0031fa003002d31f2182100f8a7ea5ba95313459f00fe0218210178d4519ba9631444403f010e0358210595f07bcba9359f011e05f04840ff2f0800115fa443070baf2e14d800ae8210178d4519c8cb1f19cb3f5007fa0222cf165006cf1625fa025003cf16c95005cc2391729171e25008a813a08208989680aa008208989680a0a014bcf2e2c504c98040fb001023c85004fa0258cf1601cf16ccc9ed540201201e1f008148020d721ed44d0fa00fa40fa40d43004d31f218210178d4519ba0282107bdd97deba12b1f2e2c5d33f31fa003013a05023c85004fa0258cf1601cf16ccc9ed54803f73b51343e803e903e90350c0234cffe80145468017e903e9014d6f1c1551cdb5c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c0327e401c1d3232c0b281f2fff274140371c1472c7cb8b0c2be80146a2860822625a020822625a004ad822860822625a028062849f8c3c975c2c070c008e020212200e33b51343e803e903e90350c01f4cffe803e903d010c1458a85492b1c17cb8b04a30bffcb8b0a0822625a02a8005e805ef3cb8b0e0841ef765f7b232c7f2cfd4017e808873c59400f3c5bd00325c60063232c14933c59c3e80b2dab33260103ec01004f214013e809633c58073c5b3327b552000705279a018a182107362d09cc8cb1f5230cb3f58fa025007cf165007cf16c9718010c8cb0524cf165006fa0215cb6a14ccc971fb0010241023000e10491038375f040076c200b08e218210d53276db708010c8cb055008cf165004fa0216cb6a12cb1f12cb3fc972fb0093356c21e203c85004fa0258cf1601cf16ccc9ed54")?;
let dst_address = TonAddress::from_str("Ef8CmPZLxWB-9ypeGdGhEqA6ZNLBFUwnqXPH2eUQd_MzbGh_")?;
let msg = JettonTransferMsg::new(dst_address.to_msg_address_int(), 1u32);
// send_int_msg
let c7 = TVMEmulatorC7::new(dst_address, BC_CONFIG.clone())?;
let mut emulator = TVMEmulator::new(&code, &data, &c7)?;
let tvm_result = emulator.send_int_msg(&msg.to_boc()?, 300)?;
assert_eq!(tvm_result.gas_used, 2779);
assert_eq!(tvm_result.vm_exit_code, 65535);
// send_ext_msg
let tvm_result = emulator.send_ext_msg(&msg.to_boc()?)?;
assert_eq!(tvm_result.gas_used, 270);
assert_eq!(tvm_result.vm_exit_code, 11);
Ok(())
}
#[test]
fn test_multiplier_contract() -> anyhow::Result<()> {
let code = hex::decode(include_str!("../../../resources/tests/test_multiplier_code.hex"))?;
let c7 = TVMEmulatorC7::new(
TonAddress::from_str("Ef8CmPZLxWB-9ypeGdGhEqA6ZNLBFUwnqXPH2eUQd_MzbGh_")?,
BC_CONFIG.clone(),
)?;
let mut emulator = TVMEmulator::new(&code, &TonCell::EMPTY.to_boc()?, &c7)?;
let mut run_test_case = |arg1: &BigInt, arg2: &BigInt| {
let expected = arg1 * arg2;
let mut stack = TVMStack::default();
stack.push_int(arg1.clone());
stack.push_int(arg2.clone());
let emulator_result = assert_ok!(emulator.run_get_method("get_val", &stack.to_boc()?));
let mut res_stack = emulator_result.stack_parsed()?;
assert_eq!(emulator_result.vm_exit_code, 0);
if expected > BigInt::from(i64::MAX) {
assert_eq!(res_stack.pop_int()?, expected);
} else {
assert_eq!(BigInt::from(res_stack.pop_tiny_int()?), expected);
}
Ok::<(), anyhow::Error>(())
};
run_test_case(&BigInt::from(1), &BigInt::from(0x1234567890ABCDEFu64))?;
run_test_case(&BigInt::from(1), &BigInt::from(0x1234567890ABCDEFu64).neg())?;
run_test_case(&BigInt::from(10_000_000_000_i64), &BigInt::from(0x1234567890ABCDEFu64))?;
Ok(())
}
}