From 1bf8625e558dabf41622109a9f241435117b904d Mon Sep 17 00:00:00 2001 From: Egor Komarov Date: Thu, 26 Jun 2025 13:14:49 +0200 Subject: [PATCH] feat: add cached state support to contract subscriptions and related components --- src/core/contract_subscription/mod.rs | 17 +++++++++++++++-- src/core/generic_contract/mod.rs | 7 ++++++- src/core/jetton_wallet/mod.rs | 4 +++- src/core/mod.rs | 4 +++- src/core/nft_wallet/mod.rs | 1 + src/core/token_wallet/mod.rs | 4 +++- src/core/ton_wallet/mod.rs | 8 +++++++- 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/core/contract_subscription/mod.rs b/src/core/contract_subscription/mod.rs index 6a9aa14f2..960a94f9c 100644 --- a/src/core/contract_subscription/mod.rs +++ b/src/core/contract_subscription/mod.rs @@ -32,15 +32,21 @@ impl ContractSubscription { clock: Arc, transport: Arc, address: MsgAddressInt, + cached_state: Option, on_contract_state: OnContractState<'_>, on_transactions_found: Option>, ) -> Result { + let (contract_state, latest_known_lt) = match cached_state { + Some(cached) => (cached.contract_state, cached.latest_known_lt), + None => (Default::default(), None), + }; + let mut result = Self { clock, transport, address, - contract_state: Default::default(), - latest_known_lt: None, + contract_state, + latest_known_lt, pending_transactions: Vec::new(), transactions_synced: false, }; @@ -488,6 +494,13 @@ pub struct TransactionExecutionOptions { pub override_balance: Option, } +#[derive(Debug, Clone, Default, Serialize, Deserialize, Copy)] +#[serde(rename_all = "camelCase")] +pub struct ContractSubscriptionCachedState { + contract_state: ContractState, + latest_known_lt: Option, +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/core/generic_contract/mod.rs b/src/core/generic_contract/mod.rs index 5936949e7..2448b3c52 100644 --- a/src/core/generic_contract/mod.rs +++ b/src/core/generic_contract/mod.rs @@ -7,7 +7,10 @@ use ton_block::{GetRepresentationHash, MsgAddressInt}; use nekoton_utils::Clock; use super::models::{ContractState, PendingTransaction, Transaction, TransactionsBatchInfo}; -use super::{ContractSubscription, PollingMethod, TransactionExecutionOptions}; +use super::{ + ContractSubscription, ContractSubscriptionCachedState, PollingMethod, + TransactionExecutionOptions, +}; use crate::core::utils; use crate::transport::models::{RawContractState, RawTransaction}; use crate::transport::Transport; @@ -24,6 +27,7 @@ impl GenericContract { address: MsgAddressInt, handler: Arc, preload_transactions: bool, + cached_state: Option, ) -> Result { let contract_subscription = { let handler = handler.as_ref(); @@ -47,6 +51,7 @@ impl GenericContract { clock, transport, address, + cached_state, &mut make_contract_state_handler(handler), on_transactions_found, ) diff --git a/src/core/jetton_wallet/mod.rs b/src/core/jetton_wallet/mod.rs index bd433e3da..ebebb7bea 100644 --- a/src/core/jetton_wallet/mod.rs +++ b/src/core/jetton_wallet/mod.rs @@ -14,7 +14,7 @@ use num_bigint::{BigInt, BigUint, ToBigInt}; use ton_block::{MsgAddressInt, Serializable}; use ton_types::{BuilderData, IBitstring, SliceData}; -use super::{utils, ContractSubscription, InternalMessage}; +use super::{utils, ContractSubscription, ContractSubscriptionCachedState, InternalMessage}; pub const JETTON_TRANSFER_OPCODE: u32 = 0x0f8a7ea5; pub const JETTON_INTERNAL_TRANSFER_OPCODE: u32 = 0x178d4519; @@ -36,6 +36,7 @@ impl JettonWallet { root_token_contract: MsgAddressInt, handler: Arc, preload_transactions: bool, + cached_state: Option, ) -> Result { let state = match transport.get_contract_state(&root_token_contract).await? { RawContractState::Exists(state) => state, @@ -69,6 +70,7 @@ impl JettonWallet { clock.clone(), transport, address, + cached_state, &mut make_contract_state_handler(clock.clone(), &mut balance), on_transactions_found, ) diff --git a/src/core/mod.rs b/src/core/mod.rs index a5dbd07c9..ecd66b2f8 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -2,7 +2,9 @@ use anyhow::Result; use nekoton_utils::*; use serde::{Deserialize, Serialize}; -pub use self::contract_subscription::{ContractSubscription, TransactionExecutionOptions}; +pub use self::contract_subscription::{ + ContractSubscription, ContractSubscriptionCachedState, TransactionExecutionOptions, +}; use self::models::PollingMethod; use crate::transport::Transport; diff --git a/src/core/nft_wallet/mod.rs b/src/core/nft_wallet/mod.rs index b853f7e22..4f69a5210 100644 --- a/src/core/nft_wallet/mod.rs +++ b/src/core/nft_wallet/mod.rs @@ -159,6 +159,7 @@ impl Nft { clock.clone(), transport, nft_address.clone(), + None, &mut make_contract_state_handler( clock.as_ref(), &mut info.owner, diff --git a/src/core/token_wallet/mod.rs b/src/core/token_wallet/mod.rs index 710adbb7c..1eea8b602 100644 --- a/src/core/token_wallet/mod.rs +++ b/src/core/token_wallet/mod.rs @@ -16,7 +16,7 @@ use num_bigint::{BigInt, BigUint, ToBigInt}; use ton_block::MsgAddressInt; use ton_executor::BlockchainConfig; -use super::{ContractSubscription, InternalMessage}; +use super::{ContractSubscription, ContractSubscriptionCachedState, InternalMessage}; pub struct TokenWallet { clock: Arc, @@ -36,6 +36,7 @@ impl TokenWallet { root_token_contract: MsgAddressInt, handler: Arc, preload_transactions: bool, + cached_state: Option, ) -> Result { let state = match transport.get_contract_state(&root_token_contract).await? { RawContractState::Exists(state) => state, @@ -77,6 +78,7 @@ impl TokenWallet { clock.clone(), transport, address, + cached_state, &mut make_contract_state_handler(clock.clone(), version, &mut balance), on_transactions_found, ) diff --git a/src/core/ton_wallet/mod.rs b/src/core/ton_wallet/mod.rs index c27cce458..82c82e705 100644 --- a/src/core/ton_wallet/mod.rs +++ b/src/core/ton_wallet/mod.rs @@ -19,7 +19,7 @@ use super::models::{ PendingTransaction, Transaction, TransactionAdditionalInfo, TransactionWithData, TransactionsBatchInfo, }; -use super::{ContractSubscription, PollingMethod}; +use super::{ContractSubscription, ContractSubscriptionCachedState, PollingMethod}; use crate::core::parsing::*; use crate::core::InternalMessage; use crate::crypto::UnsignedMessage; @@ -52,6 +52,7 @@ impl TonWallet { public_key: PublicKey, wallet_type: WalletType, handler: Arc, + cached_state: Option, ) -> Result { let address = compute_address(&public_key, wallet_type, workchain); @@ -61,6 +62,7 @@ impl TonWallet { clock.clone(), transport, address, + cached_state, &mut make_contract_state_handler( clock.as_ref(), handler.as_ref(), @@ -90,6 +92,7 @@ impl TonWallet { transport: Arc, address: MsgAddressInt, handler: Arc, + cached_state: Option, ) -> Result { let (public_key, wallet_type) = match transport.get_contract_state(&address).await? { RawContractState::Exists(contract) => extract_wallet_init_data(&contract)?, @@ -104,6 +107,7 @@ impl TonWallet { clock.clone(), transport, address, + cached_state, &mut make_contract_state_handler( clock.as_ref(), handler.as_ref(), @@ -133,6 +137,7 @@ impl TonWallet { transport: Arc, existing_wallet: ExistingWalletInfo, handler: Arc, + cached_state: Option, ) -> Result { let mut wallet_data = WalletData::default(); @@ -140,6 +145,7 @@ impl TonWallet { clock.clone(), transport, existing_wallet.address, + cached_state, &mut make_contract_state_handler( clock.as_ref(), handler.as_ref(),