diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 204b69154e..fa395ae5c4 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -298,6 +298,9 @@ export default function getBaseConfigFactory(homeDir) { host: '127.0.0.1', port: 8083, }, + proposer: { + txProcessingTimeLimit: null, + }, epochTime: 788400, }, tenderdash: { @@ -341,6 +344,8 @@ export default function getBaseConfigFactory(homeDir) { txSendRateLimit: 10, txRecvRateLimit: 12, maxConcurrentCheckTx: 250, + ttlDuration: '0s', + ttlNumBlocks: 0, }, consensus: { createEmptyBlocks: true, diff --git a/packages/dashmate/configs/defaults/getMainnetConfigFactory.js b/packages/dashmate/configs/defaults/getMainnetConfigFactory.js index 4b15570c22..e6aadafbc4 100644 --- a/packages/dashmate/configs/defaults/getMainnetConfigFactory.js +++ b/packages/dashmate/configs/defaults/getMainnetConfigFactory.js @@ -67,12 +67,19 @@ export default function getMainnetConfigFactory(homeDir, getBaseConfig) { txEnqueueTimeout: '30ms', txSendRateLimit: 100, txRecvRateLimit: 120, + ttlDuration: '24h', + ttlNumBlocks: 0, }, genesis: { chain_id: 'dash-1', validator_quorum_type: 4, }, }, + abci: { + proposer: { + txProcessingTimeLimit: 5000, + }, + }, }, }, }; diff --git a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js index d21310ee2d..ddf5a8ec98 100644 --- a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js +++ b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js @@ -74,6 +74,9 @@ export default function getTestnetConfigFactory(homeDir, getBaseConfig) { rotation: true, }, }, + proposer: { + txProcessingTimeLimit: 5000, + }, }, tenderdash: { p2p: { @@ -91,6 +94,14 @@ export default function getTestnetConfigFactory(homeDir, getBaseConfig) { ], port: 36656, }, + mempool: { + timeoutCheckTx: '3s', + txEnqueueTimeout: '30ms', + txSendRateLimit: 100, + txRecvRateLimit: 120, + ttlDuration: '24h', + ttlNumBlocks: 0, + }, rpc: { port: 36657, timeoutBroadcastTx: '1s', diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index da653161cb..f91237538e 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -790,6 +790,35 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) }); return configFile; }, + '1.1.0-dev.2': (configFile) => { + Object.entries(configFile.configs) + .forEach(([name, options]) => { + if (options.network === NETWORK_TESTNET) { + options.platform.drive.abci.proposer = { + txProcessingTimeLimit: 5000, + }; + options.platform.drive.tenderdash.mempool.timeoutCheckTx = '3s'; + options.platform.drive.tenderdash.mempool.txEnqueueTimeout = '30ms'; + options.platform.drive.tenderdash.mempool.txSendRateLimit = 100; + options.platform.drive.tenderdash.mempool.txRecvRateLimit = 120; + options.platform.drive.tenderdash.mempool.ttlDuration = '24h'; + options.platform.drive.tenderdash.mempool.ttlNumBlocks = 0; + } else if (options.network === NETWORK_MAINNET && name !== 'base') { + options.platform.drive.abci.proposer = { + txProcessingTimeLimit: 5000, + }; + options.platform.drive.tenderdash.mempool.ttlDuration = '24h'; + options.platform.drive.tenderdash.mempool.ttlNumBlocks = 0; + } else { + options.platform.drive.tenderdash.mempool.ttlDuration = '0s'; + options.platform.drive.tenderdash.mempool.ttlNumBlocks = 0; + options.platform.drive.abci.proposer = { + txProcessingTimeLimit: null, + }; + } + }); + return configFile; + }, }; } diff --git a/packages/dashmate/docker-compose.yml b/packages/dashmate/docker-compose.yml index 8afccaa3f1..eddef84057 100644 --- a/packages/dashmate/docker-compose.yml +++ b/packages/dashmate/docker-compose.yml @@ -80,6 +80,7 @@ services: - TOKIO_CONSOLE_RETENTION_SECS=${PLATFORM_DRIVE_ABCI_TOKIO_CONSOLE_RETENTION:?err} - GROVEDB_VISUALIZER_ENABLED=${PLATFORM_DRIVE_ABCI_GROVEDB_VISUALIZER_ENABLED:?err} - GROVEDB_VISUALIZER_ADDRESS=0.0.0.0:${PLATFORM_DRIVE_ABCI_GROVEDB_VISUALIZER_PORT:?err} + - PROPOSER_TX_PROCESSING_TIME_LIMIT=${PLATFORM_DRIVE_ABCI_PROPOSER_TX_PROCESSING_TIME_LIMIT} - NETWORK=${NETWORK:?err} stop_grace_period: 30s expose: diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index 3709cd0ecb..0e9dc266d1 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -895,9 +895,20 @@ export default { grovedbVisualizer: { $ref: '#/definitions/enabledHostPort', }, + proposer: { + type: 'object', + properties: { + txProcessingTimeLimit: { + type: ['null', 'integer'], + minimum: 0, + }, + }, + required: ['txProcessingTimeLimit'], + additionalProperties: false, + }, }, additionalProperties: false, - required: ['docker', 'logs', 'tokioConsole', 'validatorSet', 'chainLock', 'epochTime', 'metrics', 'grovedbVisualizer'], + required: ['docker', 'logs', 'tokioConsole', 'validatorSet', 'chainLock', 'epochTime', 'metrics', 'grovedbVisualizer', 'proposer'], }, tenderdash: { type: 'object', @@ -992,9 +1003,16 @@ export default { type: 'integer', minimum: 0, }, + ttlDuration: { + $ref: '#/definitions/duration', + }, + ttlNumBlocks: { + type: 'integer', + minimum: 0, + }, }, additionalProperties: false, - required: ['size', 'maxTxsBytes', 'cacheSize', 'timeoutCheckTx', 'txEnqueueTimeout', 'txSendRateLimit', 'txRecvRateLimit', 'maxConcurrentCheckTx'], + required: ['size', 'maxTxsBytes', 'cacheSize', 'timeoutCheckTx', 'txEnqueueTimeout', 'txSendRateLimit', 'txRecvRateLimit', 'maxConcurrentCheckTx', 'ttlDuration', 'ttlNumBlocks'], }, consensus: { type: 'object', diff --git a/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot b/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot index a6b43677c9..9caf3e128b 100644 --- a/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot +++ b/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot @@ -395,7 +395,7 @@ max-batch-bytes = 0 # Note, if ttl-num-blocks is also defined, a transaction will be removed if it # has existed in the mempool at least ttl-num-blocks number of blocks or if it's # insertion time into the mempool is beyond ttl-duration. -ttl-duration = "0s" +ttl-duration = "{{=it.platform.drive.tenderdash.mempool.ttlDuration}}" # ttl-num-blocks, if non-zero, defines the maximum number of blocks a transaction # can exist for in the mempool. @@ -403,7 +403,7 @@ ttl-duration = "0s" # Note, if ttl-duration is also defined, a transaction will be removed if it # has existed in the mempool at least ttl-num-blocks number of blocks or if # it's insertion time into the mempool is beyond ttl-duration. -ttl-num-blocks = 0 +ttl-num-blocks = {{=it.platform.drive.tenderdash.mempool.ttlNumBlocks}} ####################################################### ### State Sync Configuration Options ### diff --git a/packages/rs-drive-abci/.env.mainnet b/packages/rs-drive-abci/.env.mainnet index 4cf80e1820..65409c1d0a 100644 --- a/packages/rs-drive-abci/.env.mainnet +++ b/packages/rs-drive-abci/.env.mainnet @@ -89,4 +89,6 @@ TOKIO_CONSOLE_RETENTION_SECS=180 GROVEDB_VISUALIZER_ENABLED=false GROVEDB_VISUALIZER_ADDRESS=127.0.0.1:8083 +PROPOSER_TX_PROCESSING_TIME_LIMIT=5000 + NETWORK=mainnet diff --git a/packages/rs-drive-abci/.env.testnet b/packages/rs-drive-abci/.env.testnet index ed6de0a52e..dccf681adf 100644 --- a/packages/rs-drive-abci/.env.testnet +++ b/packages/rs-drive-abci/.env.testnet @@ -89,4 +89,6 @@ TOKIO_CONSOLE_RETENTION_SECS=180 GROVEDB_VISUALIZER_ENABLED=false GROVEDB_VISUALIZER_ADDRESS=127.0.0.1:8083 +PROPOSER_TX_PROCESSING_TIME_LIMIT=5000 + NETWORK=testnet diff --git a/packages/rs-drive-abci/src/abci/config.rs b/packages/rs-drive-abci/src/abci/config.rs index 966e6cc319..33d150f77d 100644 --- a/packages/rs-drive-abci/src/abci/config.rs +++ b/packages/rs-drive-abci/src/abci/config.rs @@ -1,5 +1,6 @@ //! Configuration of ABCI Application server +use crate::utils::from_opt_str_or_number; use dpp::prelude::TimestampMillis; use serde::{Deserialize, Serialize}; @@ -34,9 +35,9 @@ pub struct AbciConfig { #[serde(default)] pub log: crate::logging::LogConfigs, - /// Maximum time limit (in ms) to process state transitions in block proposals - #[serde(default = "AbciConfig::default_tx_processing_time_limit")] - pub tx_processing_time_limit: TimestampMillis, + /// Maximum time limit (in ms) to process state transitions to prepare proposal + #[serde(default, deserialize_with = "from_opt_str_or_number")] + pub proposer_tx_processing_time_limit: Option, } impl AbciConfig { @@ -47,10 +48,6 @@ impl AbciConfig { pub(crate) fn default_genesis_core_height() -> u32 { 1 } - - pub(crate) fn default_tx_processing_time_limit() -> TimestampMillis { - 8000 - } } impl Default for AbciConfig { @@ -61,7 +58,7 @@ impl Default for AbciConfig { genesis_core_height: AbciConfig::default_genesis_core_height(), chain_id: "chain_id".to_string(), log: Default::default(), - tx_processing_time_limit: AbciConfig::default_tx_processing_time_limit(), + proposer_tx_processing_time_limit: Default::default(), } } } diff --git a/packages/rs-drive-abci/src/config.rs b/packages/rs-drive-abci/src/config.rs index ca2128de5d..0f29f1776f 100644 --- a/packages/rs-drive-abci/src/config.rs +++ b/packages/rs-drive-abci/src/config.rs @@ -1,4 +1,5 @@ use crate::logging::LogConfigs; +use crate::utils::from_str_or_number; use crate::{abci::config::AbciConfig, error::Error}; use bincode::{Decode, Encode}; use dashcore_rpc::json::QuorumType; @@ -113,18 +114,6 @@ pub struct ExecutionConfig { pub epoch_time_length_s: u64, } -fn from_str_or_number<'de, D, T>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + std::str::FromStr, - ::Err: std::fmt::Display, -{ - use serde::de::Error; - - let s = String::deserialize(deserializer)?; - s.parse::().map_err(Error::custom) -} - /// Configuration of Dash Platform. /// /// All fields in this struct can be configured using environment variables. diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs index 7905c4fa23..ee7979595e 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs @@ -19,7 +19,6 @@ use crate::platform_types::state_transitions_processing_result::{ NotExecutedReason, StateTransitionExecutionResult, StateTransitionsProcessingResult, }; use dpp::fee::default_costs::CachedEpochIndexFeeVersions; -use dpp::prelude::TimestampMillis; use dpp::util::hash::hash_single; use dpp::validation::ConsensusValidationResult; use dpp::version::PlatformVersion; @@ -83,10 +82,16 @@ where let mut processing_result = StateTransitionsProcessingResult::default(); for decoded_state_transition in state_transition_container.into_iter() { + // If we propose state transitions, we need to check if we have a time limit for processing + // set and if we have exceeded it. let execution_result = if proposing_state_transitions && timer.map_or(false, |timer| { - timer.elapsed().as_millis() as TimestampMillis - > self.config.abci.tx_processing_time_limit + timer.elapsed().as_millis() + > self + .config + .abci + .proposer_tx_processing_time_limit + .unwrap_or(u16::MAX) as u128 }) { StateTransitionExecutionResult::NotExecuted(NotExecutedReason::ProposerRanOutOfTime) } else { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs index 009d055f83..68ec4de478 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs @@ -233,23 +233,22 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition }; let validation_result = document_transitions - .iter() - .map(|(document_type_name, document_transitions)| { - Self::transform_document_transitions_within_document_type_v0( - platform, - block_info, - validate_against_state, - data_contract_fetch_info.clone(), - document_type_name, - owner_id, - document_transitions, - execution_context, - transaction, - platform_version, - ) - }) - .collect::>>, Error>>( - )?; + .iter() + .map(|(document_type_name, document_transitions)| { + Self::transform_document_transitions_within_document_type_v0( + platform, + block_info, + validate_against_state, + data_contract_fetch_info.clone(), + document_type_name, + owner_id, + document_transitions, + execution_context, + transaction, + platform_version, + ) + }) + .collect::>>, Error>>()?; Ok(ConsensusValidationResult::flatten(validation_result)) } @@ -327,7 +326,7 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition .map(|transition| { // we validate every transition in this document type Self::transform_transition_v0( - &platform.drive, + platform.drive, transaction, validate_against_state, block_info, @@ -376,7 +375,7 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition drive, transaction, document_create_transition, block_info, |_identifier| { Ok(data_contract_fetch_info.clone()) - }, platform_version)?; + }, platform_version)?; execution_context .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); @@ -475,9 +474,9 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition } } DocumentTransition::Delete(document_delete_transition) => { - let action = DocumentDeleteTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(document_delete_transition, |_identifier| { - Ok(data_contract_fetch_info.clone()) - })?; + let action = DocumentDeleteTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(document_delete_transition, |_identifier| { + Ok(data_contract_fetch_info.clone()) + })?; Ok(DocumentTransitionAction::DeleteAction(action).into()) } DocumentTransition::Transfer(document_transfer_transition) => { diff --git a/packages/rs-drive-abci/src/utils/mod.rs b/packages/rs-drive-abci/src/utils/mod.rs index 39d1e40dfd..b7292f50cf 100644 --- a/packages/rs-drive-abci/src/utils/mod.rs +++ b/packages/rs-drive-abci/src/utils/mod.rs @@ -1,3 +1,6 @@ +mod serialization; mod spawn; +pub use serialization::from_opt_str_or_number; +pub use serialization::from_str_or_number; pub use spawn::spawn_blocking_task_with_name_if_supported; diff --git a/packages/rs-drive-abci/src/utils/serialization.rs b/packages/rs-drive-abci/src/utils/serialization.rs new file mode 100644 index 0000000000..8259ff1dce --- /dev/null +++ b/packages/rs-drive-abci/src/utils/serialization.rs @@ -0,0 +1,36 @@ +use serde::Deserialize; + +/// Deserialize a value from a string or a number. +pub fn from_str_or_number<'de, D, T>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, + T: serde::Deserialize<'de> + std::str::FromStr, + ::Err: std::fmt::Display, +{ + use serde::de::Error; + + let s = String::deserialize(deserializer)?; + s.parse::().map_err(Error::custom) +} + +/// Deserialize a value from an optional string or a number +pub fn from_opt_str_or_number<'de, D, T>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, + T: serde::Deserialize<'de> + std::str::FromStr, + ::Err: std::fmt::Display, +{ + use serde::de::Error; + + let s = Option::::deserialize(deserializer)?; + match s { + Some(s) => { + if s.is_empty() { + Ok(None) + } else { + s.parse::().map(Some).map_err(Error::custom) + } + } + None => Ok(None), + } +}