diff --git a/common/neon_rpc/api.py b/common/neon_rpc/api.py index 64e55df1..36e1ef80 100644 --- a/common/neon_rpc/api.py +++ b/common/neon_rpc/api.py @@ -249,6 +249,7 @@ class EvmConfigModel(BaseModel): evm_step_cnt: DecIntField holder_msg_size: DecIntField gas_limit_multiplier_wo_chain_id: DecIntField + cancel_timeout: DecIntField evm_param_dict: dict[str, str] = Field(validation_alias=AliasChoices("config", "evm_param_dict")) token_list: list[TokenModel] = Field(validation_alias=AliasChoices("chains", "token_list")) @@ -380,6 +381,7 @@ def _option_convertor(cls, src_dict: dict[str, Any], dst_dict: dict[str, Any]) - ("NEON_HOLDER_MSG_SIZE", "holder_msg_size", -1), ("NEON_ACCOUNT_SEED_VERSION", "account_seed_version", -1), ("NEON_GAS_LIMIT_MULTIPLIER_NO_CHAINID", "gas_limit_multiplier_wo_chain_id", -1), + ("NEON_CANCEL_TIMEOUT", "cancel_timeout", -1), ) for src_key, dst_key, default in key_list: @@ -479,6 +481,7 @@ class HolderAccountModel(BaseModel): chain_id: int = Field(default=0) evm_step_cnt: int = Field(default=0, validation_alias="steps_executed") account_key_list: list[SolPubKeyField] = Field(default_factory=list, validation_alias="accounts") + last_used_slot: int = Field(default=0, validation_alias="last_used_slot") tx_type: int = Field(default=0) max_fee_per_gas: HexUIntField = Field(default=0) @@ -515,7 +518,6 @@ def is_active(self) -> bool: def is_finalized(self) -> bool: return self.status == HolderAccountStatus.Finalized - class _CrateModel(BaseModel): name: str version: str diff --git a/proxy/executor/strategy_iterative.py b/proxy/executor/strategy_iterative.py index 67bbd81b..be526303 100644 --- a/proxy/executor/strategy_iterative.py +++ b/proxy/executor/strategy_iterative.py @@ -8,6 +8,7 @@ from common.neon.neon_program import NeonEvmIxCode, NeonIxMode from common.neon_rpc.api import HolderAccountModel +from common.solana.commit_level import SolCommit from common.solana.transaction import SolTx from common.solana.transaction_legacy import SolLegacyTx from common.solana_rpc.errors import ( @@ -49,7 +50,6 @@ async def is_finalized(self) -> bool: return self.is_valid and self._holder_acct.is_finalized - class _SolTxListSender(SolTxListSender): def __init__(self, *args, holder_account_validator: _HolderAccountValidator) -> None: super().__init__(*args) @@ -136,6 +136,9 @@ async def cancel(self) -> ExecTxRespCode | None: elif await self._recheck_tx_list(self._cancel_name): # cancel is completed return ExecTxRespCode.Failed + current_slot = await self._ctx._sol_client.get_slot(SolCommit.Confirmed) + if (current_slot - self._holder_acct.last_used_slot) < self._ctx._cancel_timeout: + return ExecTxRespCode.Failed # generate cancel tx with the default CU budget self._reset_to_def() diff --git a/proxy/executor/transaction_executor_ctx.py b/proxy/executor/transaction_executor_ctx.py index 3dc62123..f2487c4a 100644 --- a/proxy/executor/transaction_executor_ctx.py +++ b/proxy/executor/transaction_executor_ctx.py @@ -106,6 +106,7 @@ def __init__( def init_neon_prog(self, evm_cfg: EvmConfigModel) -> Self: self._evm_step_cnt_per_iter = evm_cfg.evm_step_cnt + self._cancel_timeout = evm_cfg.cancel_timeout NeonProg.init_prog(evm_cfg.treasury_pool_cnt, evm_cfg.treasury_pool_seed, evm_cfg.version) return self