From 74a7d12009b0afbcf30e3860577420d0c373630b Mon Sep 17 00:00:00 2001 From: Sergei Blinov Date: Sun, 28 Jan 2024 23:24:43 +0100 Subject: [PATCH] cargo fmt --all --- src/blockchain_config.rs | 726 +++++++++++++++++------------------ src/error.rs | 22 +- src/lib.rs | 22 +- src/ordinary_transaction.rs | 225 ++++++----- src/tick_tock_transaction.rs | 82 ++-- src/transaction_executor.rs | 483 ++++++++++------------- src/vmsetup.rs | 63 ++- 7 files changed, 789 insertions(+), 834 deletions(-) diff --git a/src/blockchain_config.rs b/src/blockchain_config.rs index dee3e23..8e718ae 100644 --- a/src/blockchain_config.rs +++ b/src/blockchain_config.rs @@ -1,369 +1,357 @@ -/* -* Copyright (C) 2019-2023 EverX. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ - -use tvm_block::{ - ConfigParam18, ConfigParams, FundamentalSmcAddresses, GasLimitsPrices, GlobalCapabilities, - Grams, MsgAddressInt, MsgForwardPrices, StorageInfo, StoragePrices, StorageUsedShort, -}; -use tvm_types::{Cell, Result, UInt256}; - -pub const VERSION_BLOCK_REVERT_MESSAGES_WITH_ANYCAST_ADDRESSES: u32 = 8; -pub const VERSION_BLOCK_NEW_CALCULATION_BOUNCED_STORAGE: u32 = 30; - -pub(crate) trait TONDefaultConfig { - /// Get default value for masterchain - fn default_mc() -> Self; - /// Get default value for workchains - fn default_wc() -> Self; -} - -impl TONDefaultConfig for MsgForwardPrices { - fn default_mc() -> Self { - MsgForwardPrices { - lump_price: 10000000, - bit_price: 655360000, - cell_price: 65536000000, - ihr_price_factor: 98304, - first_frac: 21845, - next_frac: 21845, - } - } - - fn default_wc() -> Self { - MsgForwardPrices { - lump_price: 1000000, - bit_price: 65536000, - cell_price: 6553600000, - ihr_price_factor: 98304, - first_frac: 21845, - next_frac: 21845, - } - } -} - -pub trait CalcMsgFwdFees { - fn fwd_fee(&self, msg_cell: &Cell) -> u128; - fn ihr_fee_checked(&self, fwd_fee: &Grams) -> Result; - fn mine_fee_checked(&self, fwd_fee: &Grams) -> Result; - fn next_fee_checked(&self, fwd_fee: &Grams) -> Result; -} - -impl CalcMsgFwdFees for MsgForwardPrices { - /// Calculate message forward fee - /// Forward fee is calculated according to the following formula: - /// `fwd_fee = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16))`. - /// `msg.bits` and `msg.cells` are calculated from message represented as tree of cells. Root cell is not counted. - fn fwd_fee(&self, msg_cell: &Cell) -> u128 { - let mut storage = StorageUsedShort::default(); - storage.append(msg_cell); - let mut bits = storage.bits() as u128; - let mut cells = storage.cells() as u128; - bits -= msg_cell.bit_length() as u128; - cells -= 1; - - // All prices except `lump_price` are presented in `0xffff * price` form. - // It is needed because `ihr_factor`, `first_frac` and `next_frac` are not integer values - // but calculations are performed in integers, so prices are multiplied to some big - // number (0xffff) and fee calculation uses such values. At the end result is divided by - // 0xffff with ceil rounding to obtain nanograms (add 0xffff and then `>> 16`) - self.lump_price as u128 - + ((cells * self.cell_price as u128 + bits * self.bit_price as u128 + 0xffff) >> 16) - } - - /// Calculate message IHR fee - /// IHR fee is calculated as `(msg_forward_fee * ihr_factor) >> 16` - fn ihr_fee_checked(&self, fwd_fee: &Grams) -> Result { - Grams::new((fwd_fee.as_u128() * self.ihr_price_factor as u128) >> 16) - } - - /// Calculate mine part of forward fee - /// Forward fee for internal message is splited to `int_msg_mine_fee` and `int_msg_remain_fee`: - /// `msg_forward_fee = int_msg_mine_fee + int_msg_remain_fee` - /// `int_msg_mine_fee` is a part of transaction `total_fees` and will go validators of account's shard - /// `int_msg_remain_fee` is placed in header of internal message and will go to validators - /// of shard to which message destination address is belong. - fn mine_fee_checked(&self, fwd_fee: &Grams) -> Result { - Grams::new((fwd_fee.as_u128() * self.first_frac as u128) >> 16) - } - fn next_fee_checked(&self, fwd_fee: &Grams) -> Result { - Grams::new((fwd_fee.as_u128() * self.next_frac as u128) >> 16) - } -} - -#[derive(Clone)] -pub struct AccStoragePrices { - prices: Vec, -} - -impl Default for AccStoragePrices { - fn default() -> Self { - AccStoragePrices { - prices: vec![StoragePrices { - utime_since: 0, - bit_price_ps: 1, - cell_price_ps: 500, - mc_bit_price_ps: 1000, - mc_cell_price_ps: 500000, - }], - } - } -} - -impl AccStoragePrices { - /// Calculate storage fee for provided data - pub fn calc_storage_fee( - &self, - cells: u128, - bits: u128, - mut last_paid: u32, - now: u32, - is_masterchain: bool, - ) -> u128 { - if now <= last_paid - || last_paid == 0 - || self.prices.is_empty() - || now <= self.prices[0].utime_since - { - return 0; - } - let mut fee = 0u128; - // storage prices config contains prices array for some time intervals - // to calculate account storage fee we need to sum fees for all intervals since last - // storage fee pay calculated by formula `(cells * cell_price + bits * bits_price) * interval` - for i in 0..self.prices.len() { - let prices = &self.prices[i]; - let end = if i < self.prices.len() - 1 { - self.prices[i + 1].utime_since - } else { - now - }; - - if end >= last_paid { - let delta = end - std::cmp::max(prices.utime_since, last_paid); - fee += if is_masterchain { - (cells * prices.mc_cell_price_ps as u128 - + bits * prices.mc_bit_price_ps as u128) - * delta as u128 - } else { - (cells * prices.cell_price_ps as u128 + bits * prices.bit_price_ps as u128) - * delta as u128 - }; - last_paid = end; - } - } - - // stirage fee is calculated in pseudo values (like forward fee and gas fee) - multiplied - // to 0xffff, so divide by this value with ceil rounding - (fee + 0xffff) >> 16 - } - - fn with_config(config: &ConfigParam18) -> Result { - let mut prices = vec![]; - for i in 0..config.len()? { - prices.push(config.get(i as u32)?); - } - - Ok(AccStoragePrices { prices }) - } -} - -impl TONDefaultConfig for GasLimitsPrices { - fn default_mc() -> Self { - GasLimitsPrices { - gas_price: 655360000, - flat_gas_limit: 100, - flat_gas_price: 1000000, - gas_limit: 1000000, - special_gas_limit: 10000000, - gas_credit: 10000, - block_gas_limit: 10000000, - freeze_due_limit: 100000000, - delete_due_limit: 1000000000, - max_gas_threshold: 10000000000, - } - } - - fn default_wc() -> Self { - GasLimitsPrices { - gas_price: 65536000, - flat_gas_limit: 100, - flat_gas_price: 100000, - gas_limit: 1000000, - special_gas_limit: 1000000, - gas_credit: 10000, - block_gas_limit: 10000000, - freeze_due_limit: 100000000, - delete_due_limit: 1000000000, - max_gas_threshold: 1000000000, - } - } -} - -/// Blockchain configuration parameters -#[derive(Clone)] -pub struct BlockchainConfig { - gas_prices_mc: GasLimitsPrices, - gas_prices_wc: GasLimitsPrices, - fwd_prices_mc: MsgForwardPrices, - fwd_prices_wc: MsgForwardPrices, - storage_prices: AccStoragePrices, - special_contracts: FundamentalSmcAddresses, - capabilities: u64, - global_version: u32, - raw_config: ConfigParams, -} - -impl Default for BlockchainConfig { - fn default() -> Self { - BlockchainConfig { - gas_prices_mc: GasLimitsPrices::default_mc(), - gas_prices_wc: GasLimitsPrices::default_wc(), - fwd_prices_mc: MsgForwardPrices::default_mc(), - fwd_prices_wc: MsgForwardPrices::default_wc(), - storage_prices: AccStoragePrices::default(), - special_contracts: Self::get_default_special_contracts(), - raw_config: Self::get_defult_raw_config(), - global_version: 0, - capabilities: 0x2e, - } - } -} - -impl BlockchainConfig { - fn get_default_special_contracts() -> FundamentalSmcAddresses { - let mut map = FundamentalSmcAddresses::default(); - map.add_key(&UInt256::with_array([0x33u8; 32])).unwrap(); - map.add_key(&UInt256::with_array([0x66u8; 32])).unwrap(); - map.add_key( - &"34517C7BDF5187C55AF4F8B61FDC321588C7AB768DEE24B006DF29106458D7CF" - .parse::() - .unwrap(), - ) - .unwrap(); - map - } - - fn get_defult_raw_config() -> ConfigParams { - ConfigParams { - config_addr: [0x55; 32].into(), - ..ConfigParams::default() - } - } - - /// Create `BlockchainConfig` struct with `ConfigParams` taken from blockchain - pub fn with_config(config: ConfigParams) -> Result { - Ok(BlockchainConfig { - gas_prices_mc: config.gas_prices(true)?, - gas_prices_wc: config.gas_prices(false)?, - fwd_prices_mc: config.fwd_prices(true)?, - fwd_prices_wc: config.fwd_prices(false)?, - storage_prices: AccStoragePrices::with_config(&config.storage_prices()?)?, - special_contracts: config.fundamental_smc_addr()?, - capabilities: config.capabilities(), - global_version: config.global_version(), - raw_config: config, - }) - } - - /// Get `MsgForwardPrices` for message forward fee calculation - pub fn get_fwd_prices(&self, is_masterchain: bool) -> &MsgForwardPrices { - if is_masterchain { - &self.fwd_prices_mc - } else { - &self.fwd_prices_wc - } - } - - /// Calculate gas fee for account - pub fn calc_gas_fee(&self, gas_used: u64, address: &MsgAddressInt) -> u128 { - self.get_gas_config(address.is_masterchain()) - .calc_gas_fee(gas_used) - } - - /// Get `GasLimitsPrices` for account gas fee calculation - pub fn get_gas_config(&self, is_masterchain: bool) -> &GasLimitsPrices { - if is_masterchain { - &self.gas_prices_mc - } else { - &self.gas_prices_wc - } - } - - /// Calculate forward fee - pub fn calc_fwd_fee(&self, is_masterchain: bool, msg_cell: &Cell) -> Result { - let mut in_fwd_fee = self.get_fwd_prices(is_masterchain).fwd_fee(msg_cell); - if self - .raw_config - .has_capability(GlobalCapabilities::CapFeeInGasUnits) - { - in_fwd_fee = self - .get_gas_config(is_masterchain) - .calc_gas_fee(in_fwd_fee.try_into()?) - } - Grams::new(in_fwd_fee) - } - - /// Calculate account storage fee - pub fn calc_storage_fee( - &self, - storage: &StorageInfo, - is_masterchain: bool, - now: u32, - ) -> Result { - let mut storage_fee = self.storage_prices.calc_storage_fee( - storage.used().cells().into(), - storage.used().bits().into(), - storage.last_paid(), - now, - is_masterchain, - ); - if self - .raw_config - .has_capability(GlobalCapabilities::CapFeeInGasUnits) - { - storage_fee = self - .get_gas_config(is_masterchain) - .calc_gas_fee(storage_fee.try_into()?) - } - Grams::new(storage_fee) - } - - /// Check if account is special TON account - pub fn is_special_account(&self, address: &MsgAddressInt) -> Result { - if address.is_masterchain() { - let account_id = address.get_address(); - // special account adresses are stored in hashmap - // config account is special too - Ok(self.raw_config.config_addr == account_id - || self.special_contracts.get_raw(account_id)?.is_some()) - } else { - Ok(false) - } - } - - pub fn global_version(&self) -> u32 { - self.global_version - } - - pub fn raw_config(&self) -> &ConfigParams { - &self.raw_config - } - - pub fn has_capability(&self, capability: GlobalCapabilities) -> bool { - (self.capabilities & (capability as u64)) != 0 - } - - pub fn capabilites(&self) -> u64 { - self.capabilities - } -} +// Copyright (C) 2019-2023 EverX. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. + +use tvm_block::ConfigParam18; +use tvm_block::ConfigParams; +use tvm_block::FundamentalSmcAddresses; +use tvm_block::GasLimitsPrices; +use tvm_block::GlobalCapabilities; +use tvm_block::Grams; +use tvm_block::MsgAddressInt; +use tvm_block::MsgForwardPrices; +use tvm_block::StorageInfo; +use tvm_block::StoragePrices; +use tvm_block::StorageUsedShort; +use tvm_types::Cell; +use tvm_types::Result; +use tvm_types::UInt256; + +pub const VERSION_BLOCK_REVERT_MESSAGES_WITH_ANYCAST_ADDRESSES: u32 = 8; +pub const VERSION_BLOCK_NEW_CALCULATION_BOUNCED_STORAGE: u32 = 30; + +pub(crate) trait TONDefaultConfig { + /// Get default value for masterchain + fn default_mc() -> Self; + /// Get default value for workchains + fn default_wc() -> Self; +} + +impl TONDefaultConfig for MsgForwardPrices { + fn default_mc() -> Self { + MsgForwardPrices { + lump_price: 10000000, + bit_price: 655360000, + cell_price: 65536000000, + ihr_price_factor: 98304, + first_frac: 21845, + next_frac: 21845, + } + } + + fn default_wc() -> Self { + MsgForwardPrices { + lump_price: 1000000, + bit_price: 65536000, + cell_price: 6553600000, + ihr_price_factor: 98304, + first_frac: 21845, + next_frac: 21845, + } + } +} + +pub trait CalcMsgFwdFees { + fn fwd_fee(&self, msg_cell: &Cell) -> u128; + fn ihr_fee_checked(&self, fwd_fee: &Grams) -> Result; + fn mine_fee_checked(&self, fwd_fee: &Grams) -> Result; + fn next_fee_checked(&self, fwd_fee: &Grams) -> Result; +} + +impl CalcMsgFwdFees for MsgForwardPrices { + /// Calculate message forward fee + /// Forward fee is calculated according to the following formula: + /// `fwd_fee = (lump_price + ceil((bit_price * msg.bits + cell_price * + /// msg.cells)/2^16))`. `msg.bits` and `msg.cells` are calculated from + /// message represented as tree of cells. Root cell is not counted. + fn fwd_fee(&self, msg_cell: &Cell) -> u128 { + let mut storage = StorageUsedShort::default(); + storage.append(msg_cell); + let mut bits = storage.bits() as u128; + let mut cells = storage.cells() as u128; + bits -= msg_cell.bit_length() as u128; + cells -= 1; + + // All prices except `lump_price` are presented in `0xffff * price` form. + // It is needed because `ihr_factor`, `first_frac` and `next_frac` are not + // integer values but calculations are performed in integers, so prices + // are multiplied to some big number (0xffff) and fee calculation uses + // such values. At the end result is divided by 0xffff with ceil + // rounding to obtain nanograms (add 0xffff and then `>> 16`) + self.lump_price as u128 + + ((cells * self.cell_price as u128 + bits * self.bit_price as u128 + 0xffff) >> 16) + } + + /// Calculate message IHR fee + /// IHR fee is calculated as `(msg_forward_fee * ihr_factor) >> 16` + fn ihr_fee_checked(&self, fwd_fee: &Grams) -> Result { + Grams::new((fwd_fee.as_u128() * self.ihr_price_factor as u128) >> 16) + } + + /// Calculate mine part of forward fee + /// Forward fee for internal message is splited to `int_msg_mine_fee` and + /// `int_msg_remain_fee`: `msg_forward_fee = int_msg_mine_fee + + /// int_msg_remain_fee` `int_msg_mine_fee` is a part of transaction + /// `total_fees` and will go validators of account's shard + /// `int_msg_remain_fee` is placed in header of internal message and will go + /// to validators of shard to which message destination address is + /// belong. + fn mine_fee_checked(&self, fwd_fee: &Grams) -> Result { + Grams::new((fwd_fee.as_u128() * self.first_frac as u128) >> 16) + } + + fn next_fee_checked(&self, fwd_fee: &Grams) -> Result { + Grams::new((fwd_fee.as_u128() * self.next_frac as u128) >> 16) + } +} + +#[derive(Clone)] +pub struct AccStoragePrices { + prices: Vec, +} + +impl Default for AccStoragePrices { + fn default() -> Self { + AccStoragePrices { + prices: vec![StoragePrices { + utime_since: 0, + bit_price_ps: 1, + cell_price_ps: 500, + mc_bit_price_ps: 1000, + mc_cell_price_ps: 500000, + }], + } + } +} + +impl AccStoragePrices { + /// Calculate storage fee for provided data + pub fn calc_storage_fee( + &self, + cells: u128, + bits: u128, + mut last_paid: u32, + now: u32, + is_masterchain: bool, + ) -> u128 { + if now <= last_paid + || last_paid == 0 + || self.prices.is_empty() + || now <= self.prices[0].utime_since + { + return 0; + } + let mut fee = 0u128; + // storage prices config contains prices array for some time intervals + // to calculate account storage fee we need to sum fees for all intervals since + // last storage fee pay calculated by formula `(cells * cell_price + + // bits * bits_price) * interval` + for i in 0..self.prices.len() { + let prices = &self.prices[i]; + let end = if i < self.prices.len() - 1 { self.prices[i + 1].utime_since } else { now }; + + if end >= last_paid { + let delta = end - std::cmp::max(prices.utime_since, last_paid); + fee += if is_masterchain { + (cells * prices.mc_cell_price_ps as u128 + + bits * prices.mc_bit_price_ps as u128) + * delta as u128 + } else { + (cells * prices.cell_price_ps as u128 + bits * prices.bit_price_ps as u128) + * delta as u128 + }; + last_paid = end; + } + } + + // stirage fee is calculated in pseudo values (like forward fee and gas fee) - + // multiplied to 0xffff, so divide by this value with ceil rounding + (fee + 0xffff) >> 16 + } + + fn with_config(config: &ConfigParam18) -> Result { + let mut prices = vec![]; + for i in 0..config.len()? { + prices.push(config.get(i as u32)?); + } + + Ok(AccStoragePrices { prices }) + } +} + +impl TONDefaultConfig for GasLimitsPrices { + fn default_mc() -> Self { + GasLimitsPrices { + gas_price: 655360000, + flat_gas_limit: 100, + flat_gas_price: 1000000, + gas_limit: 1000000, + special_gas_limit: 10000000, + gas_credit: 10000, + block_gas_limit: 10000000, + freeze_due_limit: 100000000, + delete_due_limit: 1000000000, + max_gas_threshold: 10000000000, + } + } + + fn default_wc() -> Self { + GasLimitsPrices { + gas_price: 65536000, + flat_gas_limit: 100, + flat_gas_price: 100000, + gas_limit: 1000000, + special_gas_limit: 1000000, + gas_credit: 10000, + block_gas_limit: 10000000, + freeze_due_limit: 100000000, + delete_due_limit: 1000000000, + max_gas_threshold: 1000000000, + } + } +} + +/// Blockchain configuration parameters +#[derive(Clone)] +pub struct BlockchainConfig { + gas_prices_mc: GasLimitsPrices, + gas_prices_wc: GasLimitsPrices, + fwd_prices_mc: MsgForwardPrices, + fwd_prices_wc: MsgForwardPrices, + storage_prices: AccStoragePrices, + special_contracts: FundamentalSmcAddresses, + capabilities: u64, + global_version: u32, + raw_config: ConfigParams, +} + +impl Default for BlockchainConfig { + fn default() -> Self { + BlockchainConfig { + gas_prices_mc: GasLimitsPrices::default_mc(), + gas_prices_wc: GasLimitsPrices::default_wc(), + fwd_prices_mc: MsgForwardPrices::default_mc(), + fwd_prices_wc: MsgForwardPrices::default_wc(), + storage_prices: AccStoragePrices::default(), + special_contracts: Self::get_default_special_contracts(), + raw_config: Self::get_defult_raw_config(), + global_version: 0, + capabilities: 0x2e, + } + } +} + +impl BlockchainConfig { + fn get_default_special_contracts() -> FundamentalSmcAddresses { + let mut map = FundamentalSmcAddresses::default(); + map.add_key(&UInt256::with_array([0x33u8; 32])).unwrap(); + map.add_key(&UInt256::with_array([0x66u8; 32])).unwrap(); + map.add_key( + &"34517C7BDF5187C55AF4F8B61FDC321588C7AB768DEE24B006DF29106458D7CF" + .parse::() + .unwrap(), + ) + .unwrap(); + map + } + + fn get_defult_raw_config() -> ConfigParams { + ConfigParams { config_addr: [0x55; 32].into(), ..ConfigParams::default() } + } + + /// Create `BlockchainConfig` struct with `ConfigParams` taken from + /// blockchain + pub fn with_config(config: ConfigParams) -> Result { + Ok(BlockchainConfig { + gas_prices_mc: config.gas_prices(true)?, + gas_prices_wc: config.gas_prices(false)?, + fwd_prices_mc: config.fwd_prices(true)?, + fwd_prices_wc: config.fwd_prices(false)?, + storage_prices: AccStoragePrices::with_config(&config.storage_prices()?)?, + special_contracts: config.fundamental_smc_addr()?, + capabilities: config.capabilities(), + global_version: config.global_version(), + raw_config: config, + }) + } + + /// Get `MsgForwardPrices` for message forward fee calculation + pub fn get_fwd_prices(&self, is_masterchain: bool) -> &MsgForwardPrices { + if is_masterchain { &self.fwd_prices_mc } else { &self.fwd_prices_wc } + } + + /// Calculate gas fee for account + pub fn calc_gas_fee(&self, gas_used: u64, address: &MsgAddressInt) -> u128 { + self.get_gas_config(address.is_masterchain()).calc_gas_fee(gas_used) + } + + /// Get `GasLimitsPrices` for account gas fee calculation + pub fn get_gas_config(&self, is_masterchain: bool) -> &GasLimitsPrices { + if is_masterchain { &self.gas_prices_mc } else { &self.gas_prices_wc } + } + + /// Calculate forward fee + pub fn calc_fwd_fee(&self, is_masterchain: bool, msg_cell: &Cell) -> Result { + let mut in_fwd_fee = self.get_fwd_prices(is_masterchain).fwd_fee(msg_cell); + if self.raw_config.has_capability(GlobalCapabilities::CapFeeInGasUnits) { + in_fwd_fee = self.get_gas_config(is_masterchain).calc_gas_fee(in_fwd_fee.try_into()?) + } + Grams::new(in_fwd_fee) + } + + /// Calculate account storage fee + pub fn calc_storage_fee( + &self, + storage: &StorageInfo, + is_masterchain: bool, + now: u32, + ) -> Result { + let mut storage_fee = self.storage_prices.calc_storage_fee( + storage.used().cells().into(), + storage.used().bits().into(), + storage.last_paid(), + now, + is_masterchain, + ); + if self.raw_config.has_capability(GlobalCapabilities::CapFeeInGasUnits) { + storage_fee = self.get_gas_config(is_masterchain).calc_gas_fee(storage_fee.try_into()?) + } + Grams::new(storage_fee) + } + + /// Check if account is special TON account + pub fn is_special_account(&self, address: &MsgAddressInt) -> Result { + if address.is_masterchain() { + let account_id = address.get_address(); + // special account adresses are stored in hashmap + // config account is special too + Ok(self.raw_config.config_addr == account_id + || self.special_contracts.get_raw(account_id)?.is_some()) + } else { + Ok(false) + } + } + + pub fn global_version(&self) -> u32 { + self.global_version + } + + pub fn raw_config(&self) -> &ConfigParams { + &self.raw_config + } + + pub fn has_capability(&self, capability: GlobalCapabilities) -> bool { + (self.capabilities & (capability as u64)) != 0 + } + + pub fn capabilites(&self) -> u64 { + self.capabilities + } +} diff --git a/src/error.rs b/src/error.rs index 3d4d8bb..bf0f9eb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,15 +1,13 @@ -/* -* Copyright (C) 2019-2021 TON Labs. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ +// Copyright (C) 2019-2021 TON Labs. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. use tvm_block::ComputeSkipReason; use tvm_types::types::ExceptionCode; diff --git a/src/lib.rs b/src/lib.rs index 81b2165..2aa9546 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,13 @@ -/* -* Copyright (C) 2019-2021 TON Labs. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ +// Copyright (C) 2019-2021 TON Labs. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. #![cfg_attr(feature = "ci_run", deny(warnings))] diff --git a/src/ordinary_transaction.rs b/src/ordinary_transaction.rs index 633ceb1..b8f56e8 100644 --- a/src/ordinary_transaction.rs +++ b/src/ordinary_transaction.rs @@ -1,40 +1,58 @@ -/* -* Copyright (C) 2019-2023 EverX. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ +// Copyright (C) 2019-2023 EverX. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. -use crate::{ - ActionPhaseResult, blockchain_config::BlockchainConfig, error::ExecutorError, - ExecuteParams, TransactionExecutor, VERSION_BLOCK_REVERT_MESSAGES_WITH_ANYCAST_ADDRESSES -}; #[cfg(feature = "timings")] use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; #[cfg(feature = "timings")] use std::time::Instant; -use tvm_block::{ - AccStatusChange, Account, AccountStatus, AddSub, CommonMsgInfo, Grams, Message, - Serializable, TrBouncePhase, TrComputePhase, Transaction, TransactionDescr, - TransactionDescrOrdinary, MASTERCHAIN_ID, GlobalCapabilities -}; -use tvm_types::{error, fail, Result, HashmapType, SliceData}; -use tvm_vm::{ - boolean, int, - stack::{integer::IntegerData, Stack, StackItem}, SmartContractInfo, -}; + +use tvm_block::AccStatusChange; +use tvm_block::Account; +use tvm_block::AccountStatus; +use tvm_block::AddSub; +use tvm_block::CommonMsgInfo; +use tvm_block::GlobalCapabilities; +use tvm_block::Grams; +use tvm_block::Message; +use tvm_block::Serializable; +use tvm_block::TrBouncePhase; +use tvm_block::TrComputePhase; +use tvm_block::Transaction; +use tvm_block::TransactionDescr; +use tvm_block::TransactionDescrOrdinary; +use tvm_block::MASTERCHAIN_ID; +use tvm_types::error; +use tvm_types::fail; +use tvm_types::HashmapType; +use tvm_types::Result; +use tvm_types::SliceData; +use tvm_vm::boolean; +use tvm_vm::int; +use tvm_vm::stack::integer::IntegerData; +use tvm_vm::stack::Stack; +use tvm_vm::stack::StackItem; +use tvm_vm::SmartContractInfo; + +use crate::blockchain_config::BlockchainConfig; +use crate::error::ExecutorError; +use crate::ActionPhaseResult; +use crate::ExecuteParams; +use crate::TransactionExecutor; +use crate::VERSION_BLOCK_REVERT_MESSAGES_WITH_ANYCAST_ADDRESSES; pub struct OrdinaryTransactionExecutor { config: BlockchainConfig, - #[cfg(feature="timings")] + #[cfg(feature = "timings")] timings: [AtomicU64; 3], // 0 - preparation, 1 - compute, 2 - after compute } @@ -43,19 +61,18 @@ impl OrdinaryTransactionExecutor { Self { config, - #[cfg(feature="timings")] + #[cfg(feature = "timings")] timings: [AtomicU64::new(0), AtomicU64::new(0), AtomicU64::new(0)], } } - #[cfg(feature="timings")] + #[cfg(feature = "timings")] pub fn timing(&self, kind: usize) -> u64 { self.timings[kind].load(Ordering::Relaxed) } } impl TransactionExecutor for OrdinaryTransactionExecutor { - /// /// Create end execute transaction from message for account fn execute_with_params( &self, @@ -63,29 +80,33 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { account: &mut Account, params: ExecuteParams, ) -> Result { - #[cfg(feature="timings")] + #[cfg(feature = "timings")] let mut now = Instant::now(); - let revert_anycast = + let revert_anycast = self.config.global_version() >= VERSION_BLOCK_REVERT_MESSAGES_WITH_ANYCAST_ADDRESSES; - let in_msg = in_msg.ok_or_else(|| error!("Ordinary transaction must have input message"))?; + let in_msg = + in_msg.ok_or_else(|| error!("Ordinary transaction must have input message"))?; let in_msg_cell = in_msg.serialize()?; // TODO: get from outside let is_masterchain = in_msg.dst_workchain_id() == Some(MASTERCHAIN_ID); log::debug!( - target: "executor", - "Ordinary transaction executing, in message id: {:x}", + target: "executor", + "Ordinary transaction executing, in message id: {:x}", in_msg_cell.repr_hash() ); let (bounce, is_ext_msg) = match in_msg.header() { CommonMsgInfo::ExtOutMsgInfo(_) => fail!(ExecutorError::InvalidExtMessage), CommonMsgInfo::IntMsgInfo(ref hdr) => (hdr.bounce, false), - CommonMsgInfo::ExtInMsgInfo(_) => (false, true) + CommonMsgInfo::ExtInMsgInfo(_) => (false, true), }; - let account_address = in_msg.dst_ref().ok_or_else(|| ExecutorError::TrExecutorError( - format!("Input message {:x} has no dst address", in_msg_cell.repr_hash()) - ))?; + let account_address = in_msg.dst_ref().ok_or_else(|| { + ExecutorError::TrExecutorError(format!( + "Input message {:x} has no dst address", + in_msg_cell.repr_hash() + )) + })?; let account_id = match account.get_id() { Some(account_id) => { log::debug!(target: "executor", "Account = {:x}", account_id); @@ -99,7 +120,7 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { let mut acc_balance = account.balance().cloned().unwrap_or_default(); let mut msg_balance = in_msg.get_value().cloned().unwrap_or_default(); - let ihr_delivered = false; // ihr is disabled because it does not work + let ihr_delivered = false; // ihr is disabled because it does not work if !ihr_delivered { if let Some(h) = in_msg.int_header() { msg_balance.grams += h.ihr_fee; @@ -110,8 +131,8 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { let is_special = self.config.is_special_account(account_address)?; let lt = std::cmp::max( - account.last_tr_time().unwrap_or(0), - std::cmp::max(params.last_tr_lt.load(Ordering::Relaxed), in_msg.lt().unwrap_or(0) + 1) + account.last_tr_time().unwrap_or(0), + std::cmp::max(params.last_tr_lt.load(Ordering::Relaxed), in_msg.lt().unwrap_or(0) + 1), ); let mut tr = Transaction::with_address_and_status(account_id, account.status()); tr.set_logical_time(lt); @@ -144,13 +165,17 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { } if description.credit_first && !is_ext_msg { - description.credit_ph = match self.credit_phase(account, &mut tr, &mut msg_balance, &mut acc_balance) { + description.credit_ph = match self.credit_phase( + account, + &mut tr, + &mut msg_balance, + &mut acc_balance, + ) { Ok(credit_ph) => Some(credit_ph), - Err(e) => fail!( - ExecutorError::TrExecutorError( - format!("cannot create credit phase of a new transaction for smart contract for reason {}", e) - ) - ) + Err(e) => fail!(ExecutorError::TrExecutorError(format!( + "cannot create credit phase of a new transaction for smart contract for reason {}", + e + ))), }; } let due_before_storage = account.due_payment().map(|due| due.as_u128()); @@ -160,7 +185,7 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { &mut acc_balance, &mut tr, is_masterchain, - is_special + is_special, ) { Ok(storage_ph) => { storage_fee = storage_ph.storage_fees_collected.as_u128(); @@ -171,12 +196,11 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { storage_fee -= due; } Some(storage_ph) - }, - Err(e) => fail!( - ExecutorError::TrExecutorError( - format!("cannot create storage phase of a new transaction for smart contract for reason {}", e) - ) - ) + } + Err(e) => fail!(ExecutorError::TrExecutorError(format!( + "cannot create storage phase of a new transaction for smart contract for reason {}", + e + ))), }; if description.credit_first && msg_balance.grams > acc_balance.grams { @@ -189,21 +213,26 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { original_acc_balance.sub(tr.total_fees())?; if !description.credit_first && !is_ext_msg { - description.credit_ph = match self.credit_phase(account, &mut tr, &mut msg_balance, &mut acc_balance) { + description.credit_ph = match self.credit_phase( + account, + &mut tr, + &mut msg_balance, + &mut acc_balance, + ) { Ok(credit_ph) => Some(credit_ph), - Err(e) => fail!( - ExecutorError::TrExecutorError( - format!("cannot create credit phase of a new transaction for smart contract for reason {}", e) - ) - ) + Err(e) => fail!(ExecutorError::TrExecutorError(format!( + "cannot create credit phase of a new transaction for smart contract for reason {}", + e + ))), }; } log::debug!(target: "executor", "credit_phase: {}", if description.credit_ph.is_some() {"present"} else {"none"}); - let last_paid = if !is_special {params.block_unixtime} else {0}; + let last_paid = if !is_special { params.block_unixtime } else { 0 }; account.set_last_paid(last_paid); - #[cfg(feature="timings")] { + #[cfg(feature = "timings")] + { self.timings[0].fetch_add(now.elapsed().as_micros() as u64, Ordering::SeqCst); now = Instant::now(); } @@ -211,7 +240,10 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { let config_params = self.config().raw_config().config_params.data().cloned(); let mut smc_info = SmartContractInfo { capabilities: self.config().raw_config().capabilities(), - myself: SliceData::load_builder(account_address.write_to_new_cell().unwrap_or_default()).unwrap(), + myself: SliceData::load_builder( + account_address.write_to_new_cell().unwrap_or_default(), + ) + .unwrap(), block_lt: params.block_lt, trans_lt: lt, unix_time: params.block_unixtime, @@ -220,7 +252,10 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { config_params, ..Default::default() }; - smc_info.calc_rand_seed(params.seed_block.clone(), &account_address.address().get_bytestring(0)); + smc_info.calc_rand_seed( + params.seed_block.clone(), + &account_address.address().get_bytestring(0), + ); let mut stack = Stack::new(); stack .push(int!(acc_balance.grams.as_u128())) @@ -246,7 +281,7 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { log::debug!(target: "executor", "compute_phase error: {}", e); match e.downcast_ref::() { Some(ExecutorError::NoAcceptError(_, _)) => return Err(e), - _ => fail!(ExecutorError::TrExecutorError(e.to_string())) + _ => fail!(ExecutorError::TrExecutorError(e.to_string())), } } }; @@ -274,9 +309,9 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { actions.unwrap_or_default(), new_data, account_address, - is_special + is_special, ) { - Ok(ActionPhaseResult{phase, messages, copyleft_reward}) => { + Ok(ActionPhaseResult { phase, messages, copyleft_reward }) => { out_msgs = messages; if let Some(copyleft_reward) = ©left_reward { tr.total_fees_mut().grams.sub(©left_reward.reward)?; @@ -284,11 +319,10 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { copyleft = copyleft_reward; Some(phase) } - Err(e) => fail!( - ExecutorError::TrExecutorError( - format!("cannot create action phase of a new transaction for smart contract for reason {}", e) - ) - ) + Err(e) => fail!(ExecutorError::TrExecutorError(format!( + "cannot create action phase of a new transaction for smart contract for reason {}", + e + ))), } } else { log::debug!(target: "executor", "compute_phase: failed"); @@ -304,7 +338,8 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { } }; - #[cfg(feature="timings")] { + #[cfg(feature = "timings")] + { self.timings[1].fetch_add(now.elapsed().as_micros() as u64, Ordering::SeqCst); now = Instant::now(); } @@ -332,13 +367,15 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { log::debug!(target: "executor", "Desciption.aborted {}", description.aborted); if description.aborted && !is_ext_msg && bounce { - if !action_phase_processed || self.config().has_capability(GlobalCapabilities::CapBounceAfterFailedAction) { + if !action_phase_processed + || self.config().has_capability(GlobalCapabilities::CapBounceAfterFailedAction) + { log::debug!(target: "executor", "bounce_phase"); description.bounce = match self.bounce_phase( msg_balance.clone(), - &mut acc_balance, - &compute_phase_gas_fees, - in_msg, + &mut acc_balance, + &compute_phase_gas_fees, + in_msg, &mut tr, account_address, params.block_version, @@ -348,11 +385,10 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { Some(bounce_ph) } Ok((bounce_ph, None)) => Some(bounce_ph), - Err(e) => fail!( - ExecutorError::TrExecutorError( - format!("cannot create bounce phase of a new transaction for smart contract for reason {}", e) - ) - ) + Err(e) => fail!(ExecutorError::TrExecutorError(format!( + "cannot create bounce phase of a new transaction for smart contract for reason {}", + e + ))), }; } // if money can be returned to sender @@ -361,12 +397,8 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { log::debug!(target: "executor", "restore balance {} => {}", acc_balance.grams, original_acc_balance.grams); acc_balance = original_acc_balance; } else if account.is_none() && !acc_balance.is_zero()? { - *account = Account::uninit( - account_address.clone(), - 0, - last_paid, - acc_balance.clone() - ); + *account = + Account::uninit(account_address.clone(), 0, last_paid, acc_balance.clone()); } } if (account.status() == AccountStatus::AccStateUninit) && acc_balance.is_zero()? { @@ -380,18 +412,25 @@ impl TransactionExecutor for OrdinaryTransactionExecutor { let lt = self.add_messages(&mut tr, out_msgs, params.last_tr_lt)?; account.set_last_tr_time(lt); tr.write_description(&TransactionDescr::Ordinary(description))?; - #[cfg(feature="timings")] + #[cfg(feature = "timings")] self.timings[2].fetch_add(now.elapsed().as_micros() as u64, Ordering::SeqCst); tr.set_copyleft_reward(copyleft); Ok(tr) } - fn ordinary_transaction(&self) -> bool { true } - fn config(&self) -> &BlockchainConfig { &self.config } + + fn ordinary_transaction(&self) -> bool { + true + } + + fn config(&self) -> &BlockchainConfig { + &self.config + } + fn build_stack(&self, in_msg: Option<&Message>, account: &Account) -> Stack { let mut stack = Stack::new(); let in_msg = match in_msg { Some(in_msg) => in_msg, - None => return stack + None => return stack, }; let acc_balance = int!(account.balance().map_or(0, |value| value.grams.as_u128())); let msg_balance = int!(in_msg.get_value().map_or(0, |value| value.grams.as_u128())); diff --git a/src/tick_tock_transaction.rs b/src/tick_tock_transaction.rs index 696b894..1dff1b2 100644 --- a/src/tick_tock_transaction.rs +++ b/src/tick_tock_transaction.rs @@ -1,32 +1,43 @@ -/* -* Copyright (C) 2019-2022 TON Labs. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ - -use crate::{ - blockchain_config::BlockchainConfig, error::ExecutorError, ActionPhaseResult, ExecuteParams, - TransactionExecutor, -}; +// Copyright (C) 2019-2022 TON Labs. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. use std::sync::atomic::Ordering; -use tvm_block::{ - Account, CurrencyCollection, Grams, Message, Serializable, TrComputePhase, Transaction, - TransactionDescr, TransactionDescrTickTock, TransactionTickTock, -}; -use tvm_types::{error, fail, HashmapType, Result, SliceData}; -use tvm_vm::{ - boolean, int, - stack::{integer::IntegerData, Stack, StackItem}, - SmartContractInfo, -}; + +use tvm_block::Account; +use tvm_block::CurrencyCollection; +use tvm_block::Grams; +use tvm_block::Message; +use tvm_block::Serializable; +use tvm_block::TrComputePhase; +use tvm_block::Transaction; +use tvm_block::TransactionDescr; +use tvm_block::TransactionDescrTickTock; +use tvm_block::TransactionTickTock; +use tvm_types::error; +use tvm_types::fail; +use tvm_types::HashmapType; +use tvm_types::Result; +use tvm_types::SliceData; +use tvm_vm::boolean; +use tvm_vm::int; +use tvm_vm::stack::integer::IntegerData; +use tvm_vm::stack::Stack; +use tvm_vm::stack::StackItem; +use tvm_vm::SmartContractInfo; + +use crate::blockchain_config::BlockchainConfig; +use crate::error::ExecutorError; +use crate::ActionPhaseResult; +use crate::ExecuteParams; +use crate::TransactionExecutor; pub struct TickTockTransactionExecutor { pub config: BlockchainConfig, @@ -40,7 +51,6 @@ impl TickTockTransactionExecutor { } impl TransactionExecutor for TickTockTransactionExecutor { - /// /// Create end execute tick or tock transaction for special account fn execute_with_params( &self, @@ -61,10 +71,7 @@ impl TransactionExecutor for TickTockTransactionExecutor { fail!("wrong type of account's tick tock flag") } } - None => fail!( - "Account {:x} is not special account for tick tock", - account_id - ), + None => fail!("Account {:x} is not special account for tick tock", account_id), } let account_address = account.get_addr().cloned().unwrap_or_default(); log::debug!(target: "executor", "tick tock transation account {:x}", account_id); @@ -132,9 +139,7 @@ impl TransactionExecutor for TickTockTransactionExecutor { ); let mut stack = Stack::new(); stack - .push(int!(account - .balance() - .map_or(0, |value| value.grams.as_u128()))) + .push(int!(account.balance().map_or(0, |value| value.grams.as_u128()))) .push(StackItem::integer(IntegerData::from_unsigned_bytes_be( account_id.get_bytestring(0), ))) @@ -182,9 +187,7 @@ impl TransactionExecutor for TickTockTransactionExecutor { &account_address, is_special, ) { - Ok(ActionPhaseResult { - phase, messages, .. - }) => { + Ok(ActionPhaseResult { phase, messages, .. }) => { out_msgs = messages; // ignore copyleft reward because account is special Some(phase) @@ -231,12 +234,15 @@ impl TransactionExecutor for TickTockTransactionExecutor { tr.write_description(&TransactionDescr::TickTock(description))?; Ok(tr) } + fn ordinary_transaction(&self) -> bool { false } + fn config(&self) -> &BlockchainConfig { &self.config } + fn build_stack(&self, _in_msg: Option<&Message>, account: &Account) -> Stack { let account_balance = account.balance().unwrap().grams.as_u128(); let account_id = account.get_id().unwrap(); diff --git a/src/transaction_executor.rs b/src/transaction_executor.rs index fb2b677..f38dcfc 100644 --- a/src/transaction_executor.rs +++ b/src/transaction_executor.rs @@ -1,54 +1,89 @@ -/* -* Copyright (C) 2019-2023 Everx. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ +// Copyright (C) 2019-2023 Everx. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. #![allow(clippy::too_many_arguments)] -use crate::{ - blockchain_config::{BlockchainConfig, CalcMsgFwdFees}, - error::ExecutorError, - vmsetup::{VMSetup, VMSetupContext}, - VERSION_BLOCK_NEW_CALCULATION_BOUNCED_STORAGE, -}; -use std::{cmp::min, collections::LinkedList}; - -use std::{ - convert::TryInto, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, - }, -}; -use tvm_block::{ - AccStatusChange, Account, AccountStatus, AddSub, CommonMsgInfo, ComputeSkipReason, - CopyleftReward, CurrencyCollection, Deserializable, ExtraCurrencyCollection, GasLimitsPrices, - GetRepresentationHash, GlobalCapabilities, Grams, HashUpdate, Message, MsgAddressInt, - OutAction, OutActions, Serializable, StateInit, StorageUsedShort, TrActionPhase, TrBouncePhase, - TrComputePhase, TrComputePhaseVm, TrCreditPhase, TrStoragePhase, Transaction, WorkchainFormat, - BASE_WORKCHAIN_ID, MASTERCHAIN_ID, RESERVE_ALL_BUT, RESERVE_IGNORE_ERROR, RESERVE_PLUS_ORIG, - RESERVE_REVERSE, RESERVE_VALID_MODES, SENDMSG_ALL_BALANCE, SENDMSG_DELETE_IF_EMPTY, - SENDMSG_IGNORE_ERROR, SENDMSG_PAY_FEE_SEPARATELY, SENDMSG_REMAINING_MSG_BALANCE, - SENDMSG_VALID_FLAGS, -}; -use tvm_types::{ - error, fail, AccountId, Cell, ExceptionCode, HashmapE, HashmapType, IBitstring, Result, - SliceData, UInt256, -}; +use std::cmp::min; +use std::collections::LinkedList; +use std::convert::TryInto; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering; +use std::sync::Arc; + +use tvm_block::AccStatusChange; +use tvm_block::Account; +use tvm_block::AccountStatus; +use tvm_block::AddSub; +use tvm_block::CommonMsgInfo; +use tvm_block::ComputeSkipReason; +use tvm_block::CopyleftReward; +use tvm_block::CurrencyCollection; +use tvm_block::Deserializable; +use tvm_block::ExtraCurrencyCollection; +use tvm_block::GasLimitsPrices; +use tvm_block::GetRepresentationHash; +use tvm_block::GlobalCapabilities; +use tvm_block::Grams; +use tvm_block::HashUpdate; +use tvm_block::Message; +use tvm_block::MsgAddressInt; +use tvm_block::OutAction; +use tvm_block::OutActions; +use tvm_block::Serializable; +use tvm_block::StateInit; +use tvm_block::StorageUsedShort; +use tvm_block::TrActionPhase; +use tvm_block::TrBouncePhase; +use tvm_block::TrComputePhase; +use tvm_block::TrComputePhaseVm; +use tvm_block::TrCreditPhase; +use tvm_block::TrStoragePhase; +use tvm_block::Transaction; +use tvm_block::WorkchainFormat; +use tvm_block::BASE_WORKCHAIN_ID; +use tvm_block::MASTERCHAIN_ID; +use tvm_block::RESERVE_ALL_BUT; +use tvm_block::RESERVE_IGNORE_ERROR; +use tvm_block::RESERVE_PLUS_ORIG; +use tvm_block::RESERVE_REVERSE; +use tvm_block::RESERVE_VALID_MODES; +use tvm_block::SENDMSG_ALL_BALANCE; +use tvm_block::SENDMSG_DELETE_IF_EMPTY; +use tvm_block::SENDMSG_IGNORE_ERROR; +use tvm_block::SENDMSG_PAY_FEE_SEPARATELY; +use tvm_block::SENDMSG_REMAINING_MSG_BALANCE; +use tvm_block::SENDMSG_VALID_FLAGS; +use tvm_types::error; +use tvm_types::fail; +use tvm_types::AccountId; +use tvm_types::Cell; +use tvm_types::ExceptionCode; +use tvm_types::HashmapE; +use tvm_types::HashmapType; +use tvm_types::IBitstring; +use tvm_types::Result; +use tvm_types::SliceData; +use tvm_types::UInt256; +use tvm_vm::error::tvm_exception; +use tvm_vm::executor::gas::gas_state::Gas; use tvm_vm::executor::BehaviorModifiers; -use tvm_vm::{ - error::tvm_exception, - executor::{gas::gas_state::Gas, IndexProvider}, - smart_contract_info::SmartContractInfo, - stack::Stack, -}; +use tvm_vm::executor::IndexProvider; +use tvm_vm::smart_contract_info::SmartContractInfo; +use tvm_vm::stack::Stack; + +use crate::blockchain_config::BlockchainConfig; +use crate::blockchain_config::CalcMsgFwdFees; +use crate::error::ExecutorError; +use crate::vmsetup::VMSetup; +use crate::vmsetup::VMSetupContext; +use crate::VERSION_BLOCK_NEW_CALCULATION_BOUNCED_STORAGE; const RESULT_CODE_ACTIONLIST_INVALID: i32 = 32; const RESULT_CODE_TOO_MANY_ACTIONS: i32 = 33; @@ -102,11 +137,7 @@ impl ActionPhaseResult { messages: Vec, copyleft_reward: Option, ) -> ActionPhaseResult { - ActionPhaseResult { - phase, - messages, - copyleft_reward, - } + ActionPhaseResult { phase, messages, copyleft_reward } } fn from_phase(phase: TrActionPhase) -> ActionPhaseResult { @@ -151,10 +182,7 @@ pub trait TransactionExecutor { let old_hash = account_root.repr_hash(); let mut account = Account::construct_from_cell(account_root.clone())?; let mut transaction = self.execute_with_params(in_msg, &mut account, params)?; - if self - .config() - .has_capability(GlobalCapabilities::CapFastStorageStat) - { + if self.config().has_capability(GlobalCapabilities::CapFastStorageStat) { account.update_storage_stat_fast()?; } else { account.update_storage_stat()?; @@ -223,8 +251,7 @@ pub trait TransactionExecutor { } let mut fee = match acc.storage_info() { Some(storage_info) => { - self.config() - .calc_storage_fee(storage_info, is_masterchain, tr.now())? + self.config().calc_storage_fee(storage_info, is_masterchain, tr.now())? } None => { log::debug!(target: "executor", "Account::None"); @@ -240,30 +267,17 @@ pub trait TransactionExecutor { log::debug!(target: "executor", "acc_balance: {}, storage fee: {}", acc_balance.grams, fee); acc_balance.grams.sub(&fee)?; tr.add_fee_grams(&fee)?; - Ok(TrStoragePhase::with_params( - fee, - None, - AccStatusChange::Unchanged, - )) + Ok(TrStoragePhase::with_params(fee, None, AccStatusChange::Unchanged)) } else { log::debug!(target: "executor", "acc_balance: {} is storage fee from total: {}", acc_balance.grams, fee); let storage_fees_collected = std::mem::take(&mut acc_balance.grams); tr.add_fee_grams(&storage_fees_collected)?; fee.sub(&storage_fees_collected)?; - let need_freeze = fee - > Grams::from( - self.config() - .get_gas_config(is_masterchain) - .freeze_due_limit, - ); + let need_freeze = + fee > Grams::from(self.config().get_gas_config(is_masterchain).freeze_due_limit); let need_delete = (acc.status() == AccountStatus::AccStateUninit || acc.status() == AccountStatus::AccStateFrozen) - && fee - > Grams::from( - self.config() - .get_gas_config(is_masterchain) - .delete_due_limit, - ); + && fee > Grams::from(self.config().get_gas_config(is_masterchain).delete_due_limit); if need_delete { tr.total_fees_mut().add(acc_balance)?; @@ -302,8 +316,8 @@ pub trait TransactionExecutor { } /// Implementation of transaction's credit phase. - /// Increases account balance by the amount that appears in the internal message header. - /// If account does not exist - phase skipped. + /// Increases account balance by the amount that appears in the internal + /// message header. If account does not exist - phase skipped. /// If message is not internal - phase skipped. fn credit_phase( &self, @@ -323,11 +337,7 @@ pub trait TransactionExecutor { Some(due_payment_remaining) }); tr.total_fees_mut().grams.add(&collected)?; - if collected.is_zero() { - None - } else { - Some(collected) - } + if collected.is_zero() { None } else { Some(collected) } } else { None }; @@ -338,7 +348,7 @@ pub trait TransactionExecutor { ); acc_balance.add(msg_balance)?; Ok(TrCreditPhase::with_params(collected, msg_balance.clone())) - //TODO: Is it need to credit with ihr_fee value in internal messages? + // TODO: Is it need to credit with ihr_fee value in internal messages? } /// Implementation of transaction's computing phase. @@ -358,12 +368,8 @@ pub trait TransactionExecutor { ) -> Result<(TrComputePhase, Option, Option)> { let mut result_acc = acc.clone(); let mut vm_phase = TrComputePhaseVm::default(); - let init_code_hash = self - .config() - .has_capability(GlobalCapabilities::CapInitCodeHash); - let libs_disabled = !self - .config() - .has_capability(GlobalCapabilities::CapSetLibCode); + let init_code_hash = self.config().has_capability(GlobalCapabilities::CapInitCodeHash); + let libs_disabled = !self.config().has_capability(GlobalCapabilities::CapSetLibCode); let is_external = if let Some(msg) = msg { if let Some(header) = msg.int_header() { log::debug!(target: "executor", "msg internal, bounce: {}", header.bounce); @@ -378,7 +384,8 @@ pub trait TransactionExecutor { 0 }); - // if there was a balance in message (not bounce), then account state at least become uninit + // if there was a balance in message (not bounce), then account state at + // least become uninit *acc = result_acc.clone(); acc.uninit_account(); } @@ -397,11 +404,7 @@ pub trait TransactionExecutor { let is_ordinary = self.ordinary_transaction(); if acc_balance.grams.is_zero() { log::debug!(target: "executor", "skip computing phase no gas"); - return Ok(( - TrComputePhase::skipped(ComputeSkipReason::NoGas), - None, - None, - )); + return Ok((TrComputePhase::skipped(ComputeSkipReason::NoGas), None, None)); } let gas_config = self.config().get_gas_config(is_masterchain); let gas = init_gas( @@ -414,11 +417,7 @@ pub trait TransactionExecutor { ); if gas.get_gas_limit() == 0 && gas.get_gas_credit() == 0 { log::debug!(target: "executor", "skip computing phase no gas"); - return Ok(( - TrComputePhase::skipped(ComputeSkipReason::NoGas), - None, - None, - )); + return Ok((TrComputePhase::skipped(ComputeSkipReason::NoGas), None, None)); } let mut libs = vec![]; @@ -449,11 +448,8 @@ pub trait TransactionExecutor { } else { vm_phase.exit_arg = None; vm_phase.success = false; - vm_phase.gas_fees = Grams::new(if is_special { - 0 - } else { - gas_config.calc_gas_fee(0) - })?; + vm_phase.gas_fees = + Grams::new(if is_special { 0 } else { gas_config.calc_gas_fee(0) })?; if !acc_balance.grams.sub(&vm_phase.gas_fees)? { log::debug!(target: "executor", "can't sub funds: {} from acc_balance: {}", vm_phase.gas_fees, acc_balance.grams); fail!("can't sub funds: from acc_balance") @@ -493,7 +489,7 @@ pub trait TransactionExecutor { vm.modify_behavior(modifiers); } - //TODO: set vm_init_state_hash + // TODO: set vm_init_state_hash if let Some(trace_callback) = params.trace_callback.clone() { vm.set_trace_callback(move |engine, info| trace_callback(engine, info)); @@ -510,7 +506,7 @@ pub trait TransactionExecutor { code } else { match exception.exception_code() { - Some(ExceptionCode::OutOfGas) => !(ExceptionCode::OutOfGas as i32), // correct error code according cpp code + Some(ExceptionCode::OutOfGas) => !(ExceptionCode::OutOfGas as i32), /* correct error code according cpp code */ Some(error_code) => error_code as i32, None => ExceptionCode::UnknownError as i32, } @@ -533,24 +529,18 @@ pub trait TransactionExecutor { // calc gas fees let gas = vm.get_gas(); let credit = gas.get_gas_credit() as u32; - //for external messages gas will not be exacted if VM throws the exception and gas_credit != 0 + // for external messages gas will not be exacted if VM throws the exception and + // gas_credit != 0 let used = gas.get_gas_used() as u64; vm_phase.gas_used = used.try_into()?; if credit != 0 { if is_external { - fail!(ExecutorError::NoAcceptError( - vm_phase.exit_code, - raw_exit_arg - )) + fail!(ExecutorError::NoAcceptError(vm_phase.exit_code, raw_exit_arg)) } vm_phase.gas_fees = Grams::zero(); } else { // credit == 0 means contract accepted - let gas_fees = if is_special { - 0 - } else { - gas_config.calc_gas_fee(used) - }; + let gas_fees = if is_special { 0 } else { gas_config.calc_gas_fee(used) }; vm_phase.gas_fees = gas_fees.try_into()?; }; @@ -560,10 +550,10 @@ pub trait TransactionExecutor { gas.get_gas_limit() as u64, credit, used, vm_phase.gas_fees ); - //set mode + // set mode vm_phase.mode = 0; vm_phase.vm_steps = vm.steps(); - //TODO: vm_final_state_hash + // TODO: vm_final_state_hash log::debug!(target: "executor", "acc_balance: {}, gas fees: {}", acc_balance.grams, vm_phase.gas_fees); if !acc_balance.grams.sub(&vm_phase.gas_fees)? { log::error!(target: "executor", "This situation is unreachable: can't sub funds: {} from acc_balance: {}", vm_phase.gas_fees, acc_balance.grams); @@ -704,13 +694,12 @@ pub trait TransactionExecutor { // 1) by the SETLIBCODE and CHANGELIB insns, // 2) manually by modifying the c5 register. // - // In the case of CapSetLibCode is not set, (1) is denied by VM but (2) is still available. - // To deny (2) too, CapSetLibCode needs to be checked here in executor. However, since the - // executor's behavior gets modified, an additional capability must be checked beforehand. + // In the case of CapSetLibCode is not set, (1) is denied by VM but (2) is still + // available. To deny (2) too, CapSetLibCode needs to be checked here in + // executor. However, since the executor's behavior gets modified, an + // additional capability must be checked beforehand. let is_change_library_denied = self.config().has_capability(GlobalCapabilities::CapTvmV19) - && !self - .config() - .has_capability(GlobalCapabilities::CapSetLibCode); + && !self.config().has_capability(GlobalCapabilities::CapSetLibCode); for (i, action) in actions.iter_mut().enumerate() { log::debug!(target: "executor", "\nAction #{}\nType: {}\nInitial balance: {}", @@ -833,7 +822,7 @@ pub trait TransactionExecutor { } } - //calc new account balance + // calc new account balance log::debug!(target: "executor", "\nReturn reserved balance:\nInitial: {}\nReserved: {}", balance_to_string(&acc_remaining_balance), balance_to_string(&total_reserved_value) @@ -866,9 +855,10 @@ pub trait TransactionExecutor { /// Implementation of transaction's bounce phase. /// Bounce phase occurs only if transaction 'aborted' flag is set and /// if inbound message is internal message with field 'bounce=true'. - /// Generates outbound internal message for original message sender, with value equal - /// to value of original message minus gas payments and forwarding fees - /// and empty body. Generated message is added to transaction's output message list. + /// Generates outbound internal message for original message sender, with + /// value equal to value of original message minus gas payments and + /// forwarding fees and empty body. Generated message is added to + /// transaction's output message list. fn bounce_phase( &self, mut remaining_msg_balance: CurrencyCollection, @@ -879,28 +869,21 @@ pub trait TransactionExecutor { my_addr: &MsgAddressInt, block_version: u32, ) -> Result<(TrBouncePhase, Option)> { - let header = msg - .int_header() - .ok_or_else(|| error!("Not found msg internal header"))?; + let header = msg.int_header().ok_or_else(|| error!("Not found msg internal header"))?; if !header.bounce { fail!("Bounce flag not set") } // create bounced message and swap src and dst addresses let mut header = header.clone(); - let msg_src = header - .src_ref() - .ok_or_else(|| error!("Not found src in message header"))? - .clone(); + let msg_src = + header.src_ref().ok_or_else(|| error!("Not found src in message header"))?.clone(); let msg_dst = std::mem::replace(&mut header.dst, msg_src); header.set_src(msg_dst); match check_rewrite_dest_addr(&header.dst, self.config(), my_addr) { Ok(new_dst) => header.dst = new_dst, Err(_) => { log::warn!(target: "executor", "Incorrect destination address in a bounced message {}", header.dst); - fail!( - "Incorrect destination address in a bounced message {}", - header.dst - ) + fail!("Incorrect destination address in a bounced message {}", header.dst) } } @@ -913,27 +896,18 @@ pub trait TransactionExecutor { header.ihr_fee = Grams::zero(); let mut bounce_msg = Message::with_int_header(header); - if self - .config() - .has_capability(GlobalCapabilities::CapBounceMsgBody) - { + if self.config().has_capability(GlobalCapabilities::CapBounceMsgBody) { let mut builder = (-1i32).write_to_new_cell()?; if let Some(body) = msg.body() { let mut body_copy = body.clone(); body_copy.shrink_data(0..256); builder.append_bytestring(&body_copy)?; - if self - .config() - .has_capability(GlobalCapabilities::CapFullBodyInBounced) - { + if self.config().has_capability(GlobalCapabilities::CapFullBodyInBounced) { builder.checked_append_reference(body.into_cell())?; } } bounce_msg.set_body(SliceData::load_builder(builder)?); - if self - .config() - .has_capability(GlobalCapabilities::CapFullBodyInBounced) - { + if self.config().has_capability(GlobalCapabilities::CapFullBodyInBounced) { if let Some(init) = msg.state_init() { bounce_msg.set_state_init(init.clone()); } @@ -942,25 +916,19 @@ pub trait TransactionExecutor { // calculated storage for bounced message is empty let serialized_message = bounce_msg.serialize()?; - let (storage, fwd_full_fees) = - if block_version >= VERSION_BLOCK_NEW_CALCULATION_BOUNCED_STORAGE { - let mut storage = StorageUsedShort::default(); - storage.append(&serialized_message); - let storage_bits = storage.bits() - serialized_message.bit_length() as u64; - let storage_cells = storage.cells() - 1; - let fwd_full_fees = self - .config() - .calc_fwd_fee(is_masterchain, &serialized_message)?; - ( - StorageUsedShort::with_values_checked(storage_cells, storage_bits)?, - fwd_full_fees, - ) - } else { - let fwd_full_fees = self - .config() - .calc_fwd_fee(is_masterchain, &Cell::default())?; - (StorageUsedShort::with_values_checked(0, 0)?, fwd_full_fees) - }; + let (storage, fwd_full_fees) = if block_version + >= VERSION_BLOCK_NEW_CALCULATION_BOUNCED_STORAGE + { + let mut storage = StorageUsedShort::default(); + storage.append(&serialized_message); + let storage_bits = storage.bits() - serialized_message.bit_length() as u64; + let storage_cells = storage.cells() - 1; + let fwd_full_fees = self.config().calc_fwd_fee(is_masterchain, &serialized_message)?; + (StorageUsedShort::with_values_checked(storage_cells, storage_bits)?, fwd_full_fees) + } else { + let fwd_full_fees = self.config().calc_fwd_fee(is_masterchain, &Cell::default())?; + (StorageUsedShort::with_values_checked(0, 0)?, fwd_full_fees) + }; let fwd_prices = self.config().get_fwd_prices(is_masterchain); let fwd_mine_fees = fwd_prices.mine_fee_checked(&fwd_full_fees)?; let fwd_fees = fwd_full_fees - fwd_mine_fees; @@ -992,10 +960,7 @@ pub trait TransactionExecutor { fwd_mine_fees, bounce_msg.get_value().unwrap().grams ); tr.add_fee_grams(&fwd_mine_fees)?; - Ok(( - TrBouncePhase::ok(storage, fwd_mine_fees, fwd_fees), - Some(bounce_msg), - )) + Ok((TrBouncePhase::ok(storage, fwd_mine_fees, fwd_fees), Some(bounce_msg))) } fn copyleft_action_handler( @@ -1041,10 +1006,7 @@ pub trait TransactionExecutor { } if was_copyleft_instruction && !copyleft_reward.is_zero() { - Ok(Some(CopyleftReward { - reward: copyleft_reward, - address: copyleft_address, - })) + Ok(Some(CopyleftReward { reward: copyleft_reward, address: copyleft_address })) } else { Ok(None) } @@ -1067,9 +1029,9 @@ pub trait TransactionExecutor { } } -/// Calculate new account state according to inbound message and current account state. -/// If account does not exist - it can be created with uninitialized state. -/// If account is uninitialized - it can be created with active state. +/// Calculate new account state according to inbound message and current account +/// state. If account does not exist - it can be created with uninitialized +/// state. If account is uninitialized - it can be created with active state. /// If account exists - it can be frozen. /// Returns computed initial phase. fn compute_new_state( @@ -1090,13 +1052,12 @@ fn compute_new_state( ComputeSkipReason::BadState })) } - //Account exists, but can be in different states. + // Account exists, but can be in different states. AccountStatus::AccStateActive => { if config.has_capability(GlobalCapabilities::CapSuspendedList) { if let Some(suspended_addresses) = config.raw_config().suspended_addresses()? { - let addr = acc - .get_addr() - .ok_or_else(|| error!("active account must have address"))?; + let addr = + acc.get_addr().ok_or_else(|| error!("active account must have address"))?; let wc = addr.workchain_id(); let addr = UInt256::construct_from(&mut addr.address())?; @@ -1107,7 +1068,7 @@ fn compute_new_state( } } - //account is active, just return it + // account is active, just return it log::debug!(target: "executor", "account state: AccountActive"); Ok(None) } @@ -1135,8 +1096,9 @@ fn compute_new_state( } AccountStatus::AccStateFrozen => { log::debug!(target: "executor", "AccountFrozen"); - //account balance was credited and if it positive after that - //and inbound message bear code and data then make some check and unfreeze account + // account balance was credited and if it positive after that + // and inbound message bear code and data then make some check and unfreeze + // account if !acc_balance.grams.is_zero() { // This check is redundant if let Some(state_init) = in_msg.state_init() { @@ -1154,7 +1116,7 @@ fn compute_new_state( }; } } - //skip computing phase, because account is frozen (bad state) + // skip computing phase, because account is frozen (bad state) log::debug!(target: "executor", "account is frozen (bad state): skip computing phase"); Ok(Some(ComputeSkipReason::NoState)) } @@ -1218,9 +1180,7 @@ fn check_rewrite_dest_addr( } } - let cap_workchains = config - .raw_config() - .has_capability(GlobalCapabilities::CapWorkchains); + let cap_workchains = config.raw_config().has_capability(GlobalCapabilities::CapWorkchains); let is_masterchain = workchain_id == MASTERCHAIN_ID; if !is_masterchain { if !cap_workchains @@ -1291,32 +1251,30 @@ fn check_rewrite_dest_addr( if anycast_opt.is_some() { log::debug!(target: "executor", "address cannot be anycast"); return Err(IncorrectCheckRewrite::Anycast); - /* - if is_masterchain { - log::debug!(target: "executor", "masterchain address cannot be anycast"); - return None - } - match src.address().get_slice(0, anycast.depth.as_usize()) { - Ok(pfx) => { - if pfx != anycast.rewrite_pfx { - match AnycastInfo::with_rewrite_pfx(pfx) { - Ok(anycast) => { - repack = true; - anycast_opt = Some(anycast) - } - Err(err) => { - log::debug!(target: "executor", "Incorrect anycast prefix {}", err); - return None - } - } - } - } - Err(err) => { - log::debug!(target: "executor", "Incorrect src address {}", err); - return None - } - } - */ + // if is_masterchain { + // log::debug!(target: "executor", "masterchain address cannot be + // anycast"); return None + // } + // match src.address().get_slice(0, anycast.depth.as_usize()) { + // Ok(pfx) => { + // if pfx != anycast.rewrite_pfx { + // match AnycastInfo::with_rewrite_pfx(pfx) { + // Ok(anycast) => { + // repack = true; + // anycast_opt = Some(anycast) + // } + // Err(err) => { + // log::debug!(target: "executor", "Incorrect anycast prefix {}", err); + // return None + // } + // } + // } + // } + // Err(err) => { + // log::debug!(target: "executor", "Incorrect src address {}", err); + // return None + // } + // } } if !repack { @@ -1354,11 +1312,7 @@ fn outmsg_action_handler( log::error!(target: "executor", "outmsg mode has unsupported flags"); return Err(RESULT_CODE_UNSUPPORTED); } - let skip = if (mode & SENDMSG_IGNORE_ERROR) != 0 { - None - } else { - Some(()) - }; + let skip = if (mode & SENDMSG_IGNORE_ERROR) != 0 { None } else { Some(()) }; let (fwd_mine_fee, total_fwd_fees); let mut result_value; // to sub from acc_balance @@ -1415,27 +1369,24 @@ fn outmsg_action_handler( int_header.ihr_fee = Grams::zero(); } let fwd_fee = *std::cmp::max(&int_header.fwd_fee, &compute_fwd_fee); - fwd_mine_fee = fwd_prices - .mine_fee_checked(&fwd_fee) - .map_err(|_| RESULT_CODE_UNSUPPORTED)?; + fwd_mine_fee = + fwd_prices.mine_fee_checked(&fwd_fee).map_err(|_| RESULT_CODE_UNSUPPORTED)?; total_fwd_fees = fwd_fee + int_header.ihr_fee; let fwd_remain_fee = fwd_fee - fwd_mine_fee; if (mode & SENDMSG_ALL_BALANCE) != 0 { - //send all remaining account balance + // send all remaining account balance result_value = acc_balance.clone(); int_header.value = acc_balance.clone(); mode &= !SENDMSG_PAY_FEE_SEPARATELY; } if (mode & SENDMSG_REMAINING_MSG_BALANCE) != 0 { - //send all remainig balance of inbound message + // send all remainig balance of inbound message result_value.add(msg_balance).ok(); if (mode & SENDMSG_PAY_FEE_SEPARATELY) == 0 { if &result_value.grams < compute_phase_fees { - return Err(skip - .map(|_| RESULT_CODE_NOT_ENOUGH_GRAMS) - .unwrap_or_default()); + return Err(skip.map(|_| RESULT_CODE_NOT_ENOUGH_GRAMS).unwrap_or_default()); } result_value.grams.sub(compute_phase_fees).map_err(|err| { log::error!(target: "executor", "cannot subtract msg balance : {}", err); @@ -1445,24 +1396,22 @@ fn outmsg_action_handler( int_header.value = result_value.clone(); } if (mode & SENDMSG_PAY_FEE_SEPARATELY) != 0 { - //we must pay the fees, sum them with msg value + // we must pay the fees, sum them with msg value result_value.grams += total_fwd_fees; } else if int_header.value.grams < total_fwd_fees { - //msg value is too small, reciever cannot pay the fees + // msg value is too small, reciever cannot pay the fees log::warn!( target: "executor", "msg balance {} is too small, cannot pay fwd+ihr fees: {}", int_header.value.grams, total_fwd_fees ); - return Err(skip - .map(|_| RESULT_CODE_NOT_ENOUGH_GRAMS) - .unwrap_or_default()); + return Err(skip.map(|_| RESULT_CODE_NOT_ENOUGH_GRAMS).unwrap_or_default()); } else { - //reciever will pay the fees + // reciever will pay the fees int_header.value.grams -= total_fwd_fees; } - //set evaluated fees and value back to msg + // set evaluated fees and value back to msg int_header.fwd_fee = fwd_remain_fee; } else if msg.ext_out_header().is_some() { fwd_mine_fee = compute_fwd_fee; @@ -1477,9 +1426,7 @@ fn outmsg_action_handler( target: "executor", "account balance {} is too small, cannot send {}", acc_balance.grams, result_value.grams ); - return Err(skip - .map(|_| RESULT_CODE_NOT_ENOUGH_GRAMS) - .unwrap_or_default()); + return Err(skip.map(|_| RESULT_CODE_NOT_ENOUGH_GRAMS).unwrap_or_default()); } match acc_balance.sub(&result_value) { Ok(false) | Err(_) => { @@ -1487,26 +1434,20 @@ fn outmsg_action_handler( target: "executor", "account balance {} is too small, cannot send {}", acc_balance, result_value ); - return Err(skip - .map(|_| RESULT_CODE_NOT_ENOUGH_EXTRA) - .unwrap_or_default()); + return Err(skip.map(|_| RESULT_CODE_NOT_ENOUGH_EXTRA).unwrap_or_default()); } _ => (), } let mut acc_balance_copy = ExtraCurrencyCollection::default(); - match acc_balance - .other - .iterate_with_keys(|key: u32, b| -> Result { - if !b.is_zero() { - acc_balance_copy.set(&key, &b)?; - } - Ok(true) - }) { + match acc_balance.other.iterate_with_keys(|key: u32, b| -> Result { + if !b.is_zero() { + acc_balance_copy.set(&key, &b)?; + } + Ok(true) + }) { Ok(false) | Err(_) => { log::warn!(target: "executor", "Cannot reduce account extra balance"); - return Err(skip - .map(|_| RESULT_CODE_INVALID_BALANCE) - .unwrap_or_default()); + return Err(skip.map(|_| RESULT_CODE_INVALID_BALANCE).unwrap_or_default()); } _ => (), } @@ -1582,9 +1523,7 @@ fn reserve_action_handler( } } else { reserved = val.clone(); - reserved - .add(original_acc_balance) - .or(Err(RESULT_CODE_INVALID_BALANCE))?; + reserved.add(original_acc_balance).or(Err(RESULT_CODE_INVALID_BALANCE))?; } } else { if mode & RESERVE_REVERSE != 0 { @@ -1729,8 +1668,10 @@ fn check_libraries(init: &StateInit, disable_set_lib: bool, text: &str, msg: &Me /// Calculate new account according to inbound message. /// If message has no value, account will not created. -/// If hash of state_init is equal to account address (or flag check address is false), account will be active. -/// Otherwise, account will be nonexist or uninit according bounce flag: if bounce, account will be uninit that save money. +/// If hash of state_init is equal to account address (or flag check address is +/// false), account will be active. Otherwise, account will be nonexist or +/// uninit according bounce flag: if bounce, account will be uninit that save +/// money. fn account_from_message( msg: &Message, msg_remaining_balance: &CurrencyCollection, @@ -1771,12 +1712,7 @@ fn account_from_message( ); None } else { - Some(Account::uninit( - hdr.dst.clone(), - 0, - 0, - msg_remaining_balance.clone(), - )) + Some(Account::uninit(hdr.dst.clone(), 0, 0, msg_remaining_balance.clone())) } } @@ -1794,17 +1730,10 @@ fn balance_to_string(balance: &CurrencyCollection) -> String { fn action_type(action: &OutAction) -> String { match action { - OutAction::SendMsg { - mode: _, - out_msg: _, - } => "SendMsg".to_string(), + OutAction::SendMsg { mode: _, out_msg: _ } => "SendMsg".to_string(), OutAction::SetCode { new_code: _ } => "SetCode".to_string(), OutAction::ReserveCurrency { mode: _, value: _ } => "ReserveCurrency".to_string(), - OutAction::ChangeLibrary { - mode: _, - code: _, - hash: _, - } => "ChangeLibrary".to_string(), + OutAction::ChangeLibrary { mode: _, code: _, hash: _ } => "ChangeLibrary".to_string(), _ => "Unknown".to_string(), } } diff --git a/src/vmsetup.rs b/src/vmsetup.rs index b63ff3a..e894cc0 100644 --- a/src/vmsetup.rs +++ b/src/vmsetup.rs @@ -1,24 +1,27 @@ -/* -* Copyright (C) 2019-2023 TON Labs. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ +// Copyright (C) 2019-2023 TON Labs. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific TON DEV software governing permissions and +// limitations under the License. -use crate::BlockchainConfig; use tvm_block::GlobalCapabilities; -use tvm_types::{Cell, HashmapE, Result, SliceData}; -use tvm_vm::{ - executor::{gas::gas_state::Gas, Engine}, - smart_contract_info::SmartContractInfo, - stack::{savelist::SaveList, Stack, StackItem}, -}; +use tvm_types::Cell; +use tvm_types::HashmapE; +use tvm_types::Result; +use tvm_types::SliceData; +use tvm_vm::executor::gas::gas_state::Gas; +use tvm_vm::executor::Engine; +use tvm_vm::smart_contract_info::SmartContractInfo; +use tvm_vm::stack::savelist::SaveList; +use tvm_vm::stack::Stack; +use tvm_vm::stack::StackItem; + +use crate::BlockchainConfig; pub struct VMSetupContext { pub capabilities: u64, @@ -123,21 +126,15 @@ impl VMSetup { pub fn create(self) -> Engine { if cfg!(debug_assertions) { // account balance is duplicated in stack and in c7 - so check - let balance_in_smc = self.ctrls.get(7).unwrap().as_tuple().unwrap()[0] - .as_tuple() - .unwrap()[7] - .as_tuple() - .unwrap()[0] - .as_integer() - .unwrap(); + let balance_in_smc = + self.ctrls.get(7).unwrap().as_tuple().unwrap()[0].as_tuple().unwrap()[7] + .as_tuple() + .unwrap()[0] + .as_integer() + .unwrap(); let stack_depth = self.stack.as_ref().unwrap().depth(); - let balance_in_stack = self - .stack - .as_ref() - .unwrap() - .get(stack_depth - 1) - .as_integer() - .unwrap(); + let balance_in_stack = + self.stack.as_ref().unwrap().get(stack_depth - 1).as_integer().unwrap(); assert_eq!(balance_in_smc, balance_in_stack); } let mut vm = self.vm.setup_with_libraries(