From 8de17a40bad90ff68640cd82587d0db00d405dea Mon Sep 17 00:00:00 2001 From: Ivan Kalinin Date: Mon, 10 Feb 2025 17:43:43 +0100 Subject: [PATCH] feat(collator): use `tycho-executor` --- Cargo.lock | 37 ++- Cargo.toml | 7 +- block-util/src/block/block_proof_stuff.rs | 4 +- block-util/src/block/block_stuff.rs | 1 + block-util/src/dict.rs | 4 +- block-util/src/message/ext_msg_repr.rs | 2 +- block-util/src/queue/queue_diff.rs | 5 +- block-util/src/state/shard_state_stuff.rs | 5 +- cli/src/cmd/tools/gen_account.rs | 2 - cli/src/cmd/tools/gen_zerostate.rs | 6 +- cli/src/util/jrpc_client.rs | 5 - cli/src/util/mod.rs | 3 - collator/Cargo.toml | 2 +- .../collator/do_collate/execution_wrapper.rs | 50 ++-- collator/src/collator/do_collate/finalize.rs | 5 +- collator/src/collator/do_collate/prepare.rs | 38 ++- collator/src/collator/execution_manager.rs | 268 +++++++++--------- collator/src/collator/types.rs | 45 ++- collator/src/manager/blocks_cache.rs | 3 +- collator/src/manager/types.rs | 3 +- collator/src/mempool/impls/std_impl/parser.rs | 2 +- collator/src/types/processed_upto.rs | 5 +- collator/tests/internal_queue.rs | 4 +- control/src/server.rs | 5 +- rpc/src/models.rs | 3 - storage/src/store/persistent_state/tests.rs | 8 +- storage/src/store/rpc/mod.rs | 3 +- 27 files changed, 257 insertions(+), 268 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0086972e..86cd40a80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -947,7 +947,7 @@ dependencies = [ [[package]] name = "everscale-types" version = "0.1.2" -source = "git+https://github.com/broxus/everscale-types.git?rev=adada6e6539abd798dbbc5a7fc1d17cc31fa7eff#adada6e6539abd798dbbc5a7fc1d17cc31fa7eff" +source = "git+https://github.com/broxus/everscale-types.git?rev=9dcfe1aa2ebeca82428cc860267653ec8036725e#9dcfe1aa2ebeca82428cc860267653ec8036725e" dependencies = [ "ahash", "anyhow", @@ -976,7 +976,7 @@ dependencies = [ [[package]] name = "everscale-types-proc" version = "0.1.5" -source = "git+https://github.com/broxus/everscale-types.git?rev=adada6e6539abd798dbbc5a7fc1d17cc31fa7eff#adada6e6539abd798dbbc5a7fc1d17cc31fa7eff" +source = "git+https://github.com/broxus/everscale-types.git?rev=9dcfe1aa2ebeca82428cc860267653ec8036725e#9dcfe1aa2ebeca82428cc860267653ec8036725e" dependencies = [ "proc-macro2", "quote", @@ -3250,20 +3250,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "ton_executor" -version = "2.0.0" -source = "git+https://github.com/broxus/ton-labs-executor.git?rev=de566312176aa524d4afc26a04c931f97079b77f#de566312176aa524d4afc26a04c931f97079b77f" -dependencies = [ - "ahash", - "anyhow", - "everscale-types", - "num-bigint", - "thiserror 2.0.11", - "tracing", - "tycho-vm", -] - [[package]] name = "tower" version = "0.5.1" @@ -3556,7 +3542,6 @@ dependencies = [ "tl-proto", "tokio", "tokio-util", - "ton_executor", "tracing", "tracing-subscriber", "trait-variant", @@ -3564,6 +3549,7 @@ dependencies = [ "tycho-collator", "tycho-consensus", "tycho-core", + "tycho-executor", "tycho-network", "tycho-storage", "tycho-util", @@ -3663,6 +3649,19 @@ dependencies = [ "tycho-util", ] +[[package]] +name = "tycho-executor" +version = "0.1.0" +source = "git+https://github.com/broxus/tycho-vm.git?rev=b1e08e7e082ae66561ba14c7f9753ce1b168b5ff#b1e08e7e082ae66561ba14c7f9753ce1b168b5ff" +dependencies = [ + "ahash", + "anyhow", + "everscale-types", + "num-bigint", + "thiserror 2.0.11", + "tycho-vm", +] + [[package]] name = "tycho-gen-protos" version = "0.2.3" @@ -3858,7 +3857,7 @@ dependencies = [ [[package]] name = "tycho-vm" version = "0.1.0" -source = "git+https://github.com/broxus/tycho-vm.git#2660562fd78d310e5aa4bae3b6aefbe90295e219" +source = "git+https://github.com/broxus/tycho-vm.git?rev=b1e08e7e082ae66561ba14c7f9753ce1b168b5ff#b1e08e7e082ae66561ba14c7f9753ce1b168b5ff" dependencies = [ "ahash", "anyhow", @@ -3879,7 +3878,7 @@ dependencies = [ [[package]] name = "tycho-vm-proc" version = "0.1.0" -source = "git+https://github.com/broxus/tycho-vm.git#2660562fd78d310e5aa4bae3b6aefbe90295e219" +source = "git+https://github.com/broxus/tycho-vm.git?rev=b1e08e7e082ae66561ba14c7f9753ce1b168b5ff#b1e08e7e082ae66561ba14c7f9753ce1b168b5ff" dependencies = [ "darling", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 2804d0eeb..fef776b0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,9 +118,8 @@ weedb = "0.4.1" zstd-safe = "7.2" zstd-sys = "2.0" -# TODO: RIIR -ton_executor = { git = "https://github.com/broxus/ton-labs-executor.git", rev = "de566312176aa524d4afc26a04c931f97079b77f" } -tycho-vm = { git = "https://github.com/broxus/tycho-vm.git" } +tycho-executor = { git = "https://github.com/broxus/tycho-vm.git", rev = "b1e08e7e082ae66561ba14c7f9753ce1b168b5ff" } +tycho-vm = { git = "https://github.com/broxus/tycho-vm.git", rev = "b1e08e7e082ae66561ba14c7f9753ce1b168b5ff" } # local deps tycho-block-util = { path = "./block-util", version = "0.2.3" } @@ -134,7 +133,7 @@ tycho-storage = { path = "./storage", version = "0.2.3" } tycho-util = { path = "./util", version = "0.2.3" } [patch.crates-io] -everscale-types = { git = "https://github.com/broxus/everscale-types.git", rev = "adada6e6539abd798dbbc5a7fc1d17cc31fa7eff" } +everscale-types = { git = "https://github.com/broxus/everscale-types.git", rev = "9dcfe1aa2ebeca82428cc860267653ec8036725e" } [workspace.lints.rust] future_incompatible = "warn" diff --git a/block-util/src/block/block_proof_stuff.rs b/block-util/src/block/block_proof_stuff.rs index 6375d0fb4..3494be7f8 100644 --- a/block-util/src/block/block_proof_stuff.rs +++ b/block-util/src/block/block_proof_stuff.rs @@ -20,6 +20,8 @@ pub struct BlockProofStuff { impl BlockProofStuff { #[cfg(any(test, feature = "test"))] pub fn new_empty(block_id: &BlockId) -> Self { + use everscale_types::cell::Lazy; + let block_info = BlockInfo { shard: block_id.shard, seqno: block_id.seqno, @@ -101,7 +103,7 @@ impl BlockProofStuff { } pub fn virtualize_block_root(&self) -> Result<&DynCell> { - let merkle_proof = self.inner.proof.root.parse::>()?; + let merkle_proof = self.inner.proof.root.parse_exotic::>()?; let block_virt_root = merkle_proof.cell.virtualize(); anyhow::ensure!( diff --git a/block-util/src/block/block_stuff.rs b/block-util/src/block/block_stuff.rs index a0bae6568..404a161d6 100644 --- a/block-util/src/block/block_stuff.rs +++ b/block-util/src/block/block_stuff.rs @@ -38,6 +38,7 @@ impl BlockStuff { #[cfg(any(test, feature = "test"))] pub fn new_empty(shard: ShardIdent, seqno: u32) -> Self { + use everscale_types::cell::Lazy; use everscale_types::merkle::MerkleUpdate; const DATA_SIZE: usize = 1024; // ~1 KB of data for an empty block. diff --git a/block-util/src/dict.rs b/block-util/src/dict.rs index 011ecff95..99bbcec6a 100644 --- a/block-util/src/dict.rs +++ b/block-util/src/dict.rs @@ -1,9 +1,9 @@ +use everscale_types::cell::Lazy; use everscale_types::dict::{ aug_dict_insert, aug_dict_remove_owned, build_aug_dict_from_sorted_iter, AugDictExtra, DictKey, SetMode, }; use everscale_types::error::Error; -use everscale_types::models::Lazy; use everscale_types::prelude::*; pub struct RelaxedAugDict { @@ -56,7 +56,7 @@ where dict_root: build_aug_dict_from_sorted_iter( iter.into_iter().map(|(k, a, v)| { // SAFETY: We know that this cell is not a library cell. - let value = v.inner().as_slice_allow_pruned(); + let value = v.inner().as_slice_allow_exotic(); (k, a, value) }), K::BITS, diff --git a/block-util/src/message/ext_msg_repr.rs b/block-util/src/message/ext_msg_repr.rs index f04e8358c..18d4dd8d8 100644 --- a/block-util/src/message/ext_msg_repr.rs +++ b/block-util/src/message/ext_msg_repr.rs @@ -54,7 +54,7 @@ impl ExtMsgRepr { } // Start parsing the message (we are sure now that it is an ordinary cell). - let mut cs = msg_root.as_slice_allow_pruned(); + let mut cs = msg_root.as_slice_allow_exotic(); // Parse info first. let info = MsgInfo::load_from(&mut cs)?; diff --git a/block-util/src/queue/queue_diff.rs b/block-util/src/queue/queue_diff.rs index 4c232de62..7147e6fde 100644 --- a/block-util/src/queue/queue_diff.rs +++ b/block-util/src/queue/queue_diff.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use std::sync::Arc; use anyhow::Result; +use everscale_types::cell::Lazy; use everscale_types::error::Error; use everscale_types::models::*; use everscale_types::prelude::*; @@ -247,7 +248,7 @@ impl Iterator for QueueDiffMessagesIter { let ref_count = out_msg.descriptor().reference_count(); if ref_count > 0 { if let Some(cell) = out_msg.reference_cloned(ref_count - 1) { - return Some(Ok(Lazy::from_raw(cell))); + return Some(Lazy::from_raw(cell)); } } @@ -282,7 +283,7 @@ mod tests { fn queue_diff_messages_iter() -> Result<()> { let mut out_messages = Dict::::new(); - let dummy_tx = Lazy::from_raw(Cell::default()); + let dummy_tx = Lazy::from_raw(Cell::default())?; // Fill with external messages for i in 0..10 { diff --git a/block-util/src/state/shard_state_stuff.rs b/block-util/src/state/shard_state_stuff.rs index 056908ad3..50d929e05 100644 --- a/block-util/src/state/shard_state_stuff.rs +++ b/block-util/src/state/shard_state_stuff.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use anyhow::Result; +use everscale_types::cell::Lazy; use everscale_types::models::*; use everscale_types::prelude::*; @@ -16,8 +17,8 @@ pub struct ShardStateStuff { impl ShardStateStuff { pub fn construct_split_root(left: Cell, right: Cell) -> Result { CellBuilder::build_from(ShardStateSplit { - left: Lazy::from_raw(left), - right: Lazy::from_raw(right), + left: Lazy::from_raw(left)?, + right: Lazy::from_raw(right)?, }) .map_err(From::from) } diff --git a/cli/src/cmd/tools/gen_account.rs b/cli/src/cmd/tools/gen_account.rs index da8595b0c..5864b845b 100644 --- a/cli/src/cmd/tools/gen_account.rs +++ b/cli/src/cmd/tools/gen_account.rs @@ -179,7 +179,6 @@ impl WalletBuilder { last_trans_lt: 0, balance: self.balance.into(), state: AccountState::Active(state_init), - init_code_hash: None, }; account.storage_stat.used = compute_storage_used(&account)?; @@ -332,7 +331,6 @@ impl MultisigBuilder { last_trans_lt: 0, balance: self.balance.into(), state: AccountState::Active(state_init), - init_code_hash: None, }; account.storage_stat.used = compute_storage_used(&account)?; diff --git a/cli/src/cmd/tools/gen_zerostate.rs b/cli/src/cmd/tools/gen_zerostate.rs index f7065f67e..46179f57d 100644 --- a/cli/src/cmd/tools/gen_zerostate.rs +++ b/cli/src/cmd/tools/gen_zerostate.rs @@ -3,6 +3,7 @@ use std::sync::OnceLock; use anyhow::{Context, Result}; use everscale_crypto::ed25519; +use everscale_types::cell::Lazy; use everscale_types::models::*; use everscale_types::num::Tokens; use everscale_types::prelude::*; @@ -410,8 +411,6 @@ impl ZerostateConfig { split_merge_at: None, fees_collected: CurrencyCollection::ZERO, funds_created: CurrencyCollection::ZERO, - copyleft_rewards: Dict::new(), - proof_chain: None, })); } @@ -446,7 +445,6 @@ impl ZerostateConfig { last_key_block: None, block_create_stats: None, global_balance: state.total_balance.clone(), - copyleft_rewards: Dict::new(), })?); Ok(state) @@ -852,7 +850,6 @@ fn build_config_account( data: Some(data), libraries: Dict::new(), }), - init_code_hash: None, }; account.storage_stat.used = compute_storage_used(&account)?; @@ -887,7 +884,6 @@ fn build_elector_code(address: &HashBytes, balance: Tokens) -> Result { data: Some(data), libraries: Dict::new(), }), - init_code_hash: None, }; account.storage_stat.used = compute_storage_used(&account)?; diff --git a/cli/src/util/jrpc_client.rs b/cli/src/util/jrpc_client.rs index 49bc4a4f6..f2c394ecf 100644 --- a/cli/src/util/jrpc_client.rs +++ b/cli/src/util/jrpc_client.rs @@ -123,11 +123,6 @@ where last_trans_lt: <_>::load_from(s)?, balance: <_>::load_from(s)?, state: <_>::load_from(s)?, - init_code_hash: if s.is_data_empty() { - None - } else { - Some(<_>::load_from(s)?) - }, })) } diff --git a/cli/src/util/mod.rs b/cli/src/util/mod.rs index 9508657bd..9a8e8cef1 100644 --- a/cli/src/util/mod.rs +++ b/cli/src/util/mod.rs @@ -41,9 +41,6 @@ pub fn compute_storage_used(account: &Account) -> Result { storage.store_u64(account.last_trans_lt)?; account.balance.store_into(&mut storage, cx)?; account.state.store_into(&mut storage, cx)?; - if account.init_code_hash.is_some() { - account.init_code_hash.store_into(&mut storage, cx)?; - } storage.build_ext(cx)? }; diff --git a/collator/Cargo.toml b/collator/Cargo.toml index 1295ecaea..743a66254 100644 --- a/collator/Cargo.toml +++ b/collator/Cargo.toml @@ -36,7 +36,6 @@ thiserror = { workspace = true } tl-proto = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal"] } tokio-util = { workspace = true } -ton_executor = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } trait-variant = { workspace = true } @@ -45,6 +44,7 @@ trait-variant = { workspace = true } tycho-block-util = { workspace = true } tycho-consensus = { workspace = true } tycho-core = { workspace = true } +tycho-executor = { workspace = true } tycho-network = { workspace = true } tycho-storage = { workspace = true } tycho-util = { workspace = true } diff --git a/collator/src/collator/do_collate/execution_wrapper.rs b/collator/src/collator/do_collate/execution_wrapper.rs index 145202889..781bde33c 100644 --- a/collator/src/collator/do_collate/execution_wrapper.rs +++ b/collator/src/collator/do_collate/execution_wrapper.rs @@ -1,19 +1,19 @@ use std::sync::Arc; -use anyhow::{bail, Result}; -use everscale_types::cell::{CellBuilder, CellSlice, HashBytes}; +use anyhow::{bail, Context, Result}; +use everscale_types::cell::{CellBuilder, CellSlice, HashBytes, Lazy}; use everscale_types::models::{ BaseMessage, BlockchainConfig, CurrencyCollection, ImportFees, InMsg, InMsgExternal, - InMsgFinal, IntAddr, IntMsgInfo, IntermediateAddr, Lazy, MsgEnvelope, MsgInfo, OutMsg, + InMsgFinal, IntAddr, IntMsgInfo, IntermediateAddr, MsgEnvelope, MsgInfo, OutMsg, OutMsgDequeueImmediate, OutMsgExternal, OutMsgImmediate, OutMsgNew, ShardIdent, TickTock, Transaction, }; -use ton_executor::ExecutedTransaction; use tycho_block_util::queue::QueueKey; use crate::collator::execution_manager::MessagesExecutor; use crate::collator::types::{ - BlockCollationData, ParsedMessage, PreparedInMsg, PreparedOutMsg, SpecialOrigin, + BlockCollationData, ExecutedTransaction, ParsedMessage, PreparedInMsg, PreparedOutMsg, + SpecialOrigin, }; use crate::internal_queue::types::EnqueuedMessage; use crate::tracing_targets; @@ -159,7 +159,9 @@ impl ExecutorWrapper { .executor .execute_ordinary_transaction(account_stuff, in_message)?; - let executor_output = executed.result?; + let executor_output = executed + .result + .context("special transactions can't be skipped")?; self.process_transaction(executor_output, Some(executed.in_message), collation_data) } @@ -196,29 +198,32 @@ impl ExecutorWrapper { fn create_ticktock_transaction( &mut self, account_id: &HashBytes, - tick_tock: TickTock, + kind: TickTock, collation_data: &mut BlockCollationData, ) -> Result>> { tracing::trace!( target: tracing_targets::COLLATOR, account_addr = %account_id, - kind = ?tick_tock, + ?kind, "create_ticktock_transaction", ); let Some(account_stuff) = self.executor - .take_account_stuff_if(account_id, |stuff| match tick_tock { + .take_account_stuff_if(account_id, |stuff| match kind { TickTock::Tick => stuff.special.tick, TickTock::Tock => stuff.special.tock, })? else { - return Ok(vec![]); + return Ok(Vec::new()); }; - let executor_output = self + let Some(executor_output) = self .executor - .execute_ticktock_transaction(account_stuff, tick_tock)?; + .execute_ticktock_transaction(account_stuff, kind)? + else { + return Ok(Vec::new()); + }; self.process_transaction(executor_output, None, collation_data) } @@ -250,10 +255,9 @@ fn new_transaction( let mut out_messages = vec![]; - for out_msg_cell in executed.out_msgs.values() { - let out_msg_cell = out_msg_cell?; - let out_msg_hash = *out_msg_cell.repr_hash(); - let out_msg_info = out_msg_cell.parse::()?; + for out_msg_cell in executed.out_msgs { + let out_msg_hash = *out_msg_cell.inner().repr_hash(); + let out_msg_info = out_msg_cell.inner().parse::()?; tracing::trace!( target: tracing_targets::COLLATOR, @@ -279,7 +283,7 @@ fn new_transaction( IntermediateAddr::FULL_SRC_SAME_WORKCHAIN }, fwd_fee_remaining: *fwd_fee, - message: Lazy::from_raw(out_msg_cell.clone()), + message: out_msg_cell.clone(), })?, transaction: executed.transaction.clone(), }); @@ -295,7 +299,7 @@ fn new_transaction( out_messages.push(Box::new(ParsedMessage { info: out_msg_info, dst_in_current_shard, - cell: out_msg_cell, + cell: out_msg_cell.into_inner(), special_origin: None, block_seqno: Some(collation_data.block_id_short.seqno), from_same_shard: Some(true), @@ -303,7 +307,7 @@ fn new_transaction( } MsgInfo::ExtOut(_) => { let out_msg = OutMsg::External(OutMsgExternal { - out_msg: Lazy::from_raw(out_msg_cell), + out_msg: out_msg_cell, transaction: executed.transaction.clone(), }); @@ -337,7 +341,7 @@ fn process_in_message( cur_addr: IntermediateAddr::FULL_SRC_SAME_WORKCHAIN, next_addr: IntermediateAddr::FULL_SRC_SAME_WORKCHAIN, fwd_fee_remaining: Default::default(), - message: Lazy::from_raw(in_msg.cell), + message: Lazy::from_raw(in_msg.cell)?, })?, transaction, fwd_fee: Default::default(), @@ -362,7 +366,7 @@ fn process_in_message( import_fees = ImportFees::default(); Lazy::new(&InMsg::External(InMsgExternal { - in_msg: Lazy::from_raw(in_msg.cell), + in_msg: Lazy::from_raw(in_msg.cell)?, transaction, }))? } @@ -384,7 +388,7 @@ fn process_in_message( }, next_addr: IntermediateAddr::FULL_DEST_SAME_WORKCHAIN, fwd_fee_remaining: fwd_fee, - message: Lazy::from_raw(in_msg.cell), + message: Lazy::from_raw(in_msg.cell)?, })?; let in_msg = InMsg::Final(InMsgFinal { @@ -421,7 +425,7 @@ fn process_in_message( cur_addr: IntermediateAddr::FULL_SRC_SAME_WORKCHAIN, next_addr: IntermediateAddr::FULL_SRC_SAME_WORKCHAIN, fwd_fee_remaining: fwd_fee, - message: Lazy::from_raw(in_msg.cell), + message: Lazy::from_raw(in_msg.cell)?, }; let in_msg = InMsg::Immediate(InMsgFinal { in_msg_envelope: Lazy::new(&msg_envelope)?, diff --git a/collator/src/collator/do_collate/finalize.rs b/collator/src/collator/do_collate/finalize.rs index 9bc59fb92..583774d1a 100644 --- a/collator/src/collator/do_collate/finalize.rs +++ b/collator/src/collator/do_collate/finalize.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use std::time::Duration; use anyhow::{anyhow, Context, Result}; +use everscale_types::cell::Lazy; use everscale_types::merkle::*; use everscale_types::models::{ShardIdent, *}; use everscale_types::prelude::*; @@ -228,7 +229,7 @@ impl Phase { let executor = self.extra.executor; // update shard accounts tree and prepare accounts blocks - let mut global_libraries = executor.executor_params().state_libs.clone(); + let mut global_libraries = executor.executor_params().libraries.clone(); let is_masterchain = shard.is_masterchain(); let config_address = &self.state.mc_data.config.address; @@ -537,7 +538,6 @@ impl Phase { .as_ref() .map(Lazy::new) .transpose()?, - copyleft_msgs: Default::default(), config: if mc_state_extra.after_key_block { Some(mc_state_extra.config.clone()) } else { @@ -990,7 +990,6 @@ impl Phase { last_key_block, block_create_stats, global_balance, - copyleft_rewards: Default::default(), }; Ok((mc_state_extra, min_ref_mc_seqno)) diff --git a/collator/src/collator/do_collate/prepare.rs b/collator/src/collator/do_collate/prepare.rs index 54c9631dc..a6ed44347 100644 --- a/collator/src/collator/do_collate/prepare.rs +++ b/collator/src/collator/do_collate/prepare.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use anyhow::Result; use everscale_types::models::GlobalCapability; -use ton_executor::{ExecuteParams, PreloadedBlockchainConfig}; +use tycho_executor::{ExecutorParams, ParsedConfig}; use super::execute::ExecuteState; use super::execution_wrapper::ExecutorWrapper; @@ -48,38 +48,32 @@ impl Phase { ); // init executor - let preloaded_bc_config = Arc::new(PreloadedBlockchainConfig::with_config( - self.state.mc_data.config.clone(), - self.state.mc_data.global_id, + let preloaded_bc_config = Arc::new(ParsedConfig::parse( + self.state.mc_data.config.params.clone(), + self.state.collation_data.gen_utime, )?); - let block_version = preloaded_bc_config.global_version().version; - let signature_with_id = if preloaded_bc_config - .global_version() - .capabilities - .contains(GlobalCapability::CapSignatureWithId) - { - Some(self.state.mc_data.global_id) - } else { - None - }; + let capabilities = preloaded_bc_config.global.capabilities; let executor = MessagesExecutor::new( self.state.shard_id, self.state.collation_data.next_lt, preloaded_bc_config, - Arc::new(ExecuteParams { - state_libs: self.state.mc_data.libraries.clone(), + Arc::new(ExecutorParams { + libraries: self.state.mc_data.libraries.clone(), // generated unix time block_unixtime: self.state.collation_data.gen_utime, // block's start logical time block_lt: self.state.collation_data.start_lt, // block random seed - seed_block: self.state.collation_data.rand_seed, - block_version, - behavior_modifiers: Some(tycho_vm::BehaviourModifiers { - signature_with_id, + rand_seed: self.state.collation_data.rand_seed, + disable_delete_frozen_accounts: true, + full_body_in_bounced: capabilities.contains(GlobalCapability::CapFullBodyInBounced), + charge_action_fees_on_fail: true, + vm_modifiers: tycho_vm::BehaviourModifiers { + signature_with_id: capabilities + .contains(GlobalCapability::CapSignatureWithId) + .then_some(self.state.mc_data.global_id), ..Default::default() - }), - debug: false, + }, }), self.state.prev_shard_data.observable_accounts().clone(), self.state diff --git a/collator/src/collator/execution_manager.rs b/collator/src/collator/execution_manager.rs index d3caef393..cf31ecb5a 100644 --- a/collator/src/collator/execution_manager.rs +++ b/collator/src/collator/execution_manager.rs @@ -8,16 +8,12 @@ use everscale_types::cell::HashBytes; use everscale_types::models::*; use humantime::format_duration; use rayon::prelude::*; -use ton_executor::{ - ExecuteParams, ExecutedTransaction, ExecutorOutput, OrdinaryTransactionExecutor, - PreloadedBlockchainConfig, TickTockTransactionExecutor, TransactionExecutor, -}; +use tycho_executor::{Executor, ExecutorParams, ParsedConfig, TxError}; use tycho_util::metrics::HistogramGuard; use tycho_util::FastHashMap; -use tycho_vm::{SafeRc, SmcInfoTonV6, Tuple}; use super::messages_buffer::MessageGroup; -use super::types::{AccountId, ParsedMessage, ShardAccountStuff}; +use super::types::{AccountId, ExecutedTransaction, ParsedMessage, ShardAccountStuff}; use crate::tracing_targets; pub(super) struct MessagesExecutor { @@ -25,9 +21,9 @@ pub(super) struct MessagesExecutor { // this time is used if account's lt is smaller min_next_lt: u64, /// blockchain config - config: Arc, + config: Arc, /// vm execution params related to current block - params: Arc, + params: Arc, /// shard accounts accounts_cache: AccountsCache, /// Params to calculate messages execution work in work units @@ -38,8 +34,8 @@ impl MessagesExecutor { pub fn new( shard_id: ShardIdent, min_next_lt: u64, - config: Arc, - params: Arc, + config: Arc, + params: Arc, shard_accounts: ShardAccounts, wu_params_execute: WorkUnitsParamsExecute, ) -> Self { @@ -49,6 +45,8 @@ impl MessagesExecutor { config, params, accounts_cache: AccountsCache { + // TODO: Better handle workchains out of range. + workchain_id: shard_id.workchain().try_into().unwrap(), shard_accounts, items: Default::default(), }, @@ -60,7 +58,7 @@ impl MessagesExecutor { self.min_next_lt } - pub fn executor_params(&self) -> &Arc { + pub fn executor_params(&self) -> &Arc { &self.params } @@ -73,6 +71,7 @@ impl MessagesExecutor { let AccountsCache { shard_accounts, items, + .. } = self.accounts_cache; (items.into_values(), shard_accounts) } @@ -118,34 +117,16 @@ impl MessagesExecutor { let accounts_cache = Arc::new(&self.accounts_cache); let result = msg_group .into_par_iter() - .map_init( - move || { - // TEMP: There will be a per-thread executor state. - let unpacked = SmcInfoTonV6::unpack_config( - &config.raw_config().params, - params.block_unixtime, - ) - .ok(); - - ( - config.clone(), - params.clone(), - accounts_cache.clone(), - unpacked, - ) - }, - |(config, params, accounts_cache, unpacked), (account_id, msgs)| { - Self::execute_subgroup( - account_id, - msgs, - accounts_cache, - min_next_lt, - config, - unpacked.clone().unwrap_or_default(), - params, - ) - }, - ) + .map(|(account_id, msgs)| { + Self::execute_subgroup( + account_id, + msgs, + &accounts_cache, + min_next_lt, + &config, + ¶ms, + ) + }) .collect_vec_list(); for result in result { @@ -219,19 +200,11 @@ impl MessagesExecutor { msgs: Vec>, accounts_cache: &AccountsCache, min_next_lt: u64, - config: &Arc, - unpacked_config: SafeRc, - params: &Arc, + config: &ParsedConfig, + params: &ExecutorParams, ) -> Result { let shard_account_stuff = accounts_cache.get_account_stuff(&account_id)?; - Self::execute_messages( - shard_account_stuff, - msgs, - min_next_lt, - config, - unpacked_config, - params, - ) + Self::execute_messages(shard_account_stuff, msgs, min_next_lt, config, params) } #[allow(clippy::too_many_arguments)] @@ -255,20 +228,16 @@ impl MessagesExecutor { *group_max_vert_size = cmp::max(*group_max_vert_size, executed.transactions.len()); for tx in executed.transactions { - if matches!(&tx.in_message.info, MsgInfo::ExtIn(_)) { - if let Err(e) = &tx.result { - tracing::warn!( - target: tracing_targets::EXEC_MANAGER, - account_addr = %executed.account_state.account_addr, - message_hash = %tx.in_message.cell.repr_hash(), - "failed to execute external message: {e:?}", - ); - *ext_msgs_error_count += 1; - continue; - } - } - - let executed = tx.result?; + let Some(executed) = tx.result else { + tracing::warn!( + target: tracing_targets::EXEC_MANAGER, + account_addr = %executed.account_state.account_addr, + message_hash = %tx.in_message.cell.repr_hash(), + "skipped external message", + ); + *ext_msgs_error_count += 1; + continue; + }; self.min_next_lt = cmp::max(self.min_next_lt, executed.next_lt); @@ -300,9 +269,8 @@ impl MessagesExecutor { mut account_state: Box, msgs: Vec>, min_next_lt: u64, - config: &Arc, - unpacked_config: SafeRc, - params: &Arc, + config: &ParsedConfig, + params: &ExecutorParams, ) -> Result { let mut ext_msgs_skipped = 0; let timer = std::time::Instant::now(); @@ -320,7 +288,6 @@ impl MessagesExecutor { msg, min_next_lt, config, - unpacked_config.clone(), params, )?); } @@ -343,21 +310,16 @@ impl MessagesExecutor { let config = self.config.clone(); let params = self.params.clone(); - // TEMP: There will be a per-thread cached state for a new executor. - let unpacked_config = - SmcInfoTonV6::unpack_config(&config.raw_config().params, params.block_unixtime)?; - let (account_stuff, executed) = execute_ordinary_transaction_impl( &mut account_stuff, in_message, min_next_lt, &config, - unpacked_config, ¶ms, ) .map(|executed| (account_stuff, executed))?; - if let Ok(tx) = &executed.result { + if let Some(tx) = &executed.result { self.min_next_lt = cmp::max(min_next_lt, tx.next_lt); } self.accounts_cache.add_account_stuff(account_stuff); @@ -369,32 +331,30 @@ impl MessagesExecutor { &mut self, mut account_stuff: Box, tick_tock: TickTock, - ) -> Result { + ) -> Result> { let min_next_lt = self.min_next_lt; let config = self.config.clone(); let params = self.params.clone(); - // TEMP: There will be a per-thread cached state for a new executor. - let unpacked_config = - SmcInfoTonV6::unpack_config(&config.raw_config().params, params.block_unixtime)?; - - let (account_stuff, executed) = execute_ticktock_transaction( + let Some(executed) = execute_ticktock_transaction( &mut account_stuff, tick_tock, min_next_lt, &config, - unpacked_config, ¶ms, - ) - .map(|executed| (account_stuff, executed))?; + )? + else { + return Ok(None); + }; self.min_next_lt = cmp::max(min_next_lt, executed.next_lt); self.accounts_cache.add_account_stuff(account_stuff); - Ok(executed) + Ok(Some(executed)) } } struct AccountsCache { + workchain_id: i8, shard_accounts: ShardAccounts, items: FastHashMap>, } @@ -416,7 +376,9 @@ impl AccountsCache { } Entry::Vacant(entry) => { if let Some((_, state)) = self.shard_accounts.get(account_id)? { - let account_stuff = ShardAccountStuff::new(account_id, state).map(Box::new)?; + let account_stuff = + ShardAccountStuff::new(self.workchain_id, account_id, state) + .map(Box::new)?; if f(&account_stuff) { return Ok(Some(account_stuff)); } @@ -434,9 +396,12 @@ impl AccountsCache { if let Some(account) = self.items.get(account_id) { Ok(account.clone()) } else if let Some((_depth, shard_account)) = self.shard_accounts.get(account_id)? { - ShardAccountStuff::new(account_id, shard_account).map(Box::new) + ShardAccountStuff::new(self.workchain_id, account_id, shard_account).map(Box::new) } else { - Ok(Box::new(ShardAccountStuff::new_empty(account_id))) + Ok(Box::new(ShardAccountStuff::new_empty( + self.workchain_id, + account_id, + ))) } } @@ -471,7 +436,7 @@ pub struct ExecutedTransactions { } pub struct ExecutedOrdinaryTransaction { - pub result: Result, + pub result: Option, pub in_message: Box, } @@ -479,9 +444,8 @@ fn execute_ordinary_transaction_impl( account_stuff: &mut ShardAccountStuff, in_message: Box, min_lt: u64, - config: &PreloadedBlockchainConfig, - unpacked_config: SafeRc, - params: &ExecuteParams, + config: &ParsedConfig, + params: &ExecutorParams, ) -> Result { tracing::trace!( target: tracing_targets::EXEC_MANAGER, @@ -493,71 +457,93 @@ fn execute_ordinary_transaction_impl( let _histogram = HistogramGuard::begin("tycho_collator_execute_ordinary_time"); - let shard_account = &mut account_stuff.shard_account; - let result = OrdinaryTransactionExecutor::new().execute_with_libs_and_params( - Some(&in_message.cell), - shard_account, - min_lt, - params, - config, - unpacked_config, - ); + let is_external = matches!(in_message.info, MsgInfo::ExtIn(_)); - let result = match result { - Ok(( - total_fees, - ExecutorOutput { - account, - transaction, - }, - )) => { - let tx_lt = shard_account.last_trans_lt; - account_stuff.apply_transaction(tx_lt, total_fees, account, &transaction); - Ok(transaction) + let uncommited = Executor::new(params, config) + .with_min_lt(min_lt) + .begin_ordinary( + &account_stuff.make_std_addr(), + matches!(in_message.info, MsgInfo::ExtIn(_)), + in_message.cell.clone(), + &account_stuff.shard_account, + ); + + let output = match uncommited { + Ok(uncommited) => uncommited.commit()?, + Err(TxError::Skipped) if is_external => { + return Ok(ExecutedOrdinaryTransaction { + result: None, + in_message, + }) } - Err(e) => Err(e), + Err(e) => return Err(e.into()), }; - Ok(ExecutedOrdinaryTransaction { result, in_message }) + let tx_lt = output.new_state.last_trans_lt; + + account_stuff.shard_account = output.new_state; + account_stuff.apply_transaction( + tx_lt, + output.transaction_meta.total_fees, + output.new_state_meta, + output.transaction.clone(), + ); + + Ok(ExecutedOrdinaryTransaction { + result: Some(ExecutedTransaction { + transaction: output.transaction, + out_msgs: output.transaction_meta.out_msgs, + gas_used: output.transaction_meta.gas_used, + next_lt: output.transaction_meta.next_lt, + }), + in_message, + }) } fn execute_ticktock_transaction( account_stuff: &mut ShardAccountStuff, - tick_tock: TickTock, + kind: TickTock, min_lt: u64, - config: &PreloadedBlockchainConfig, - unpacked_config: SafeRc, - params: &ExecuteParams, -) -> Result { + config: &ParsedConfig, + params: &ExecutorParams, +) -> Result> { tracing::trace!( target: tracing_targets::EXEC_MANAGER, account_addr = %account_stuff.account_addr, - kind = ?tick_tock, + ?kind, "executing ticktock", ); let _histogram = HistogramGuard::begin("tycho_collator_execute_ticktock_time"); - let shard_account = &mut account_stuff.shard_account; - - // NOTE: Failed (without tx) ticktock execution is considered as a fatal error - let ( - total_fees, - ExecutorOutput { - account, - transaction, - }, - ) = TickTockTransactionExecutor::new(tick_tock).execute_with_libs_and_params( - None, - shard_account, - min_lt, - params, - config, - unpacked_config, - )?; - - let tx_lt = shard_account.last_trans_lt; - account_stuff.apply_transaction(tx_lt, total_fees, account, &transaction); - - Ok(transaction) + let uncommited = Executor::new(params, config) + .with_min_lt(min_lt) + .begin_tick_tock( + &account_stuff.make_std_addr(), + kind, + &account_stuff.shard_account, + ); + + let output = match uncommited { + Ok(uncommited) => uncommited.commit()?, + Err(TxError::Skipped) => return Ok(None), + Err(TxError::Fatal(e)) => return Err(e), + }; + + let tx_lt = output.new_state.last_trans_lt; + + account_stuff.shard_account = output.new_state; + account_stuff.apply_transaction( + tx_lt, + output.transaction_meta.total_fees, + output.new_state_meta, + output.transaction.clone(), + ); + + Ok(Some(ExecutedTransaction { + transaction: output.transaction, + out_msgs: output.transaction_meta.out_msgs, + gas_used: output.transaction_meta.gas_used, + next_lt: output.transaction_meta.next_lt, + })) } diff --git a/collator/src/collator/types.rs b/collator/src/collator/types.rs index 04e91f931..19e1134f2 100644 --- a/collator/src/collator/types.rs +++ b/collator/src/collator/types.rs @@ -3,20 +3,21 @@ use std::sync::{Arc, OnceLock}; use std::time::Duration; use anyhow::{anyhow, bail, Result}; -use everscale_types::cell::{Cell, HashBytes, UsageTree, UsageTreeMode}; +use everscale_types::cell::{Cell, HashBytes, Lazy, UsageTree, UsageTreeMode}; use everscale_types::dict::Dict; use everscale_types::models::{ AccountState, BlockId, BlockIdShort, BlockInfo, BlockLimits, BlockParamLimits, BlockRef, - CollationConfig, CurrencyCollection, HashUpdate, ImportFees, InMsg, Lazy, LibDescr, MsgInfo, - MsgsExecutionParams, OptionalAccount, OutMsg, PrevBlockRef, ShardAccount, ShardAccounts, - ShardDescription, ShardFeeCreated, ShardFees, ShardIdent, ShardIdentFull, ShardStateUnsplit, - SimpleLib, SpecialFlags, StateInit, Transaction, ValueFlow, + CollationConfig, CurrencyCollection, HashUpdate, ImportFees, InMsg, LibDescr, MsgInfo, + MsgsExecutionParams, OptionalAccount, OutMsg, OwnedMessage, PrevBlockRef, ShardAccount, + ShardAccounts, ShardDescription, ShardFeeCreated, ShardFees, ShardIdent, ShardIdentFull, + ShardStateUnsplit, SimpleLib, SpecialFlags, StateInit, StdAddr, Transaction, ValueFlow, }; +use everscale_types::num::Tokens; use tl_proto::TlWrite; -use ton_executor::{AccountMeta, ExecutedTransaction}; use tycho_block_util::queue::{QueuePartitionIdx, SerializedQueueDiff}; use tycho_block_util::state::{RefMcStateHandle, ShardStateStuff}; use tycho_core::global_config::MempoolGlobalConfig; +use tycho_executor::AccountMeta; use tycho_network::PeerId; use tycho_util::FastHashMap; @@ -554,6 +555,7 @@ pub(super) type AccountId = HashBytes; #[derive(Clone)] pub(super) struct ShardAccountStuff { + pub workchain_id: i8, pub account_addr: AccountId, pub shard_account: ShardAccount, pub special: SpecialFlags, @@ -566,7 +568,11 @@ pub(super) struct ShardAccountStuff { } impl ShardAccountStuff { - pub fn new(account_addr: &AccountId, shard_account: ShardAccount) -> Result { + pub fn new( + workchain_id: i8, + account_addr: &AccountId, + shard_account: ShardAccount, + ) -> Result { let initial_state_hash = *shard_account.account.inner().repr_hash(); let mut libraries = Dict::new(); @@ -592,6 +598,7 @@ impl ShardAccountStuff { } Ok(Self { + workchain_id, account_addr: *account_addr, shard_account, special, @@ -604,7 +611,7 @@ impl ShardAccountStuff { }) } - pub fn new_empty(account_addr: &AccountId) -> Self { + pub fn new_empty(workchain_id: i8, account_addr: &AccountId) -> Self { static EMPTY_SHARD_ACCOUNT: OnceLock = OnceLock::new(); let shard_account = EMPTY_SHARD_ACCOUNT @@ -618,6 +625,7 @@ impl ShardAccountStuff { let initial_state_hash = *shard_account.account.inner().repr_hash(); Self { + workchain_id, account_addr: *account_addr, shard_account, special: Default::default(), @@ -634,6 +642,10 @@ impl ShardAccountStuff { Ok(self.shard_account.load_account()?.is_none()) } + pub fn make_std_addr(&self) -> StdAddr { + StdAddr::new(self.workchain_id, self.account_addr) + } + pub fn build_hash_update(&self) -> Lazy { Lazy::new(&HashUpdate { old: self.initial_state_hash, @@ -645,12 +657,11 @@ impl ShardAccountStuff { pub fn apply_transaction( &mut self, lt: u64, - total_fees: CurrencyCollection, + total_fees: Tokens, account_meta: AccountMeta, - tx: &ExecutedTransaction, + tx: Lazy, ) { - self.transactions - .insert(lt, (total_fees, tx.transaction.clone())); + self.transactions.insert(lt, (total_fees.into(), tx)); self.balance = account_meta.balance; self.libraries = account_meta.libraries; self.exists = account_meta.exists; @@ -818,12 +829,18 @@ impl ShardDescriptionExt for ShardDescription { split_merge_at: None, // TODO: check if we really should not use it here fees_collected: value_flow.fees_collected.clone(), funds_created: value_flow.created.clone(), - copyleft_rewards: Default::default(), - proof_chain: None, } } } +#[derive(Clone, Debug)] +pub struct ExecutedTransaction { + pub transaction: Lazy, + pub out_msgs: Vec>, + pub gas_used: u64, + pub next_lt: u64, +} + pub struct ParsedMessage { pub info: MsgInfo, pub dst_in_current_shard: bool, diff --git a/collator/src/manager/blocks_cache.rs b/collator/src/manager/blocks_cache.rs index 944056677..5aa863815 100644 --- a/collator/src/manager/blocks_cache.rs +++ b/collator/src/manager/blocks_cache.rs @@ -2,8 +2,9 @@ use std::collections::{btree_map, BTreeMap, VecDeque}; use std::sync::{Arc, OnceLock}; use anyhow::{bail, Result}; +use everscale_types::cell::Lazy; use everscale_types::models::{ - BlockId, BlockIdShort, ConsensusInfo, Lazy, OutMsgDescr, ShardIdent, ValueFlow, + BlockId, BlockIdShort, ConsensusInfo, OutMsgDescr, ShardIdent, ValueFlow, }; use parking_lot::Mutex; use tycho_block_util::queue::QueueDiffStuff; diff --git a/collator/src/manager/types.rs b/collator/src/manager/types.rs index 4bc3cd63e..82e000cce 100644 --- a/collator/src/manager/types.rs +++ b/collator/src/manager/types.rs @@ -2,7 +2,8 @@ use std::fmt::{Debug, Display}; use std::sync::Arc; use anyhow::{anyhow, Result}; -use everscale_types::models::{BlockId, BlockIdShort, BlockInfo, Lazy, OutMsgDescr, ShardIdent}; +use everscale_types::cell::Lazy; +use everscale_types::models::{BlockId, BlockIdShort, BlockInfo, OutMsgDescr, ShardIdent}; use tokio::sync::Notify; use tycho_block_util::queue::QueueDiffStuff; use tycho_block_util::state::ShardStateStuff; diff --git a/collator/src/mempool/impls/std_impl/parser.rs b/collator/src/mempool/impls/std_impl/parser.rs index faf77c51c..ee5fba253 100644 --- a/collator/src/mempool/impls/std_impl/parser.rs +++ b/collator/src/mempool/impls/std_impl/parser.rs @@ -111,7 +111,7 @@ impl Parser { return None; } - let mut cs = cell.as_slice_allow_pruned(); + let mut cs = cell.as_slice_allow_exotic(); let MsgInfo::ExtIn(info) = MsgInfo::load_from(&mut cs).ok()? else { return None; }; diff --git a/collator/src/types/processed_upto.rs b/collator/src/types/processed_upto.rs index 552525139..08da4240e 100644 --- a/collator/src/types/processed_upto.rs +++ b/collator/src/types/processed_upto.rs @@ -1,9 +1,10 @@ use std::collections::BTreeMap; use anyhow::Result; +use everscale_types::cell::Lazy; use everscale_types::models::{ - ExternalsRange, InternalsRange, Lazy, MsgsExecutionParams, ProcessedUptoInfo, - ProcessedUptoPartition, ShardIdent, ShardIdentFull, ShardRange, + ExternalsRange, InternalsRange, MsgsExecutionParams, ProcessedUptoInfo, ProcessedUptoPartition, + ShardIdent, ShardIdentFull, ShardRange, }; use tycho_block_util::queue::QueuePartitionIdx; diff --git a/collator/tests/internal_queue.rs b/collator/tests/internal_queue.rs index 608fd7e8a..99682ee4e 100644 --- a/collator/tests/internal_queue.rs +++ b/collator/tests/internal_queue.rs @@ -2,10 +2,10 @@ use std::collections::{BTreeMap, BTreeSet}; use std::sync::Arc; use std::time::Duration; -use everscale_types::cell::{Cell, CellSliceRange, HashBytes}; +use everscale_types::cell::{Cell, CellSliceRange, HashBytes, Lazy}; use everscale_types::models::{ AccountStatus, BlockId, BlockIdShort, ComputePhase, ComputePhaseSkipReason, CurrencyCollection, - HashUpdate, IntAddr, IntMsgInfo, IntermediateAddr, Lazy, MsgEnvelope, MsgInfo, OrdinaryTxInfo, + HashUpdate, IntAddr, IntMsgInfo, IntermediateAddr, MsgEnvelope, MsgInfo, OrdinaryTxInfo, OutMsg, OutMsgDescr, OutMsgNew, OwnedMessage, ShardIdent, SkippedComputePhase, StdAddr, Transaction, TxInfo, }; diff --git a/control/src/server.rs b/control/src/server.rs index 20cf23400..a5d913b8e 100644 --- a/control/src/server.rs +++ b/control/src/server.rs @@ -7,10 +7,9 @@ use anyhow::{Context as _, Result}; use arc_swap::ArcSwapOption; use bytes::Bytes; use everscale_crypto::ed25519; -use everscale_types::cell::Load; +use everscale_types::cell::Lazy; use everscale_types::models::{ - AccountState, DepthBalanceInfo, Lazy, Message, OptionalAccount, ShardAccount, ShardIdent, - StdAddr, + AccountState, DepthBalanceInfo, Message, OptionalAccount, ShardAccount, ShardIdent, StdAddr, }; use everscale_types::num::Tokens; use everscale_types::prelude::*; diff --git a/rpc/src/models.rs b/rpc/src/models.rs index 0a7209fe9..68b35f8ad 100644 --- a/rpc/src/models.rs +++ b/rpc/src/models.rs @@ -59,8 +59,5 @@ pub fn serialize_account(account: &Account) -> Result Result<()> { cur_addr: IntermediateAddr::FULL_SRC_SAME_WORKCHAIN, next_addr: IntermediateAddr::FULL_DEST_SAME_WORKCHAIN, fwd_fee_remaining: Tokens::ZERO, - message: Lazy::from_raw(cell), + message: Lazy::from_raw(cell)?, })?, - transaction: Lazy::from_raw(Cell::default()), + transaction: Lazy::from_raw(Cell::default())?, }), )); } diff --git a/storage/src/store/rpc/mod.rs b/storage/src/store/rpc/mod.rs index 1dc9fa278..a8e432418 100644 --- a/storage/src/store/rpc/mod.rs +++ b/storage/src/store/rpc/mod.rs @@ -4,6 +4,7 @@ use std::time::Instant; use anyhow::{Context, Result}; use arc_swap::ArcSwapOption; +use everscale_types::cell::Lazy; use everscale_types::models::*; use everscale_types::prelude::*; use tycho_block_util::block::BlockStuff; @@ -582,7 +583,7 @@ impl RpcStorage { if old_accounts.repr_hash() == new_accounts.repr_hash() { Dict::new() } else { - let accounts = Lazy::::from_raw(new_accounts).load()?; + let accounts = Lazy::::from_raw(new_accounts)?.load()?; let (accounts, _) = accounts.into_parts(); accounts }