1use crate::logging::LogConfigs;
2use crate::utils::from_str_or_number;
3use crate::{abci::config::AbciConfig, error::Error};
4use bincode::{Decode, Encode};
5use dpp::dashcore::Network;
6use dpp::dashcore_rpc::json::QuorumType;
7use dpp::util::deserializer::ProtocolVersion;
8use dpp::version::INITIAL_PROTOCOL_VERSION;
9use drive::config::DriveConfig;
10use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize};
11use std::path::PathBuf;
12
13#[derive(Clone, Debug, Serialize, Deserialize, Default)]
15pub struct ConsensusCoreRpcConfig {
16 #[serde(rename = "core_consensus_json_rpc_host")]
18 pub host: String,
19
20 #[serde(
22 rename = "core_consensus_json_rpc_port",
23 deserialize_with = "from_str_or_number"
24 )]
25 pub port: u16,
26
27 #[serde(rename = "core_consensus_json_rpc_username")]
29 pub username: String,
30
31 #[serde(rename = "core_consensus_json_rpc_password")]
33 pub password: String,
34}
35
36impl ConsensusCoreRpcConfig {
37 pub fn url(&self) -> String {
39 format!("{}:{}", self.host, self.port)
40 }
41}
42
43#[derive(Clone, Debug, Serialize, Deserialize, Default)]
45pub struct CheckTxCoreRpcConfig {
46 #[serde(rename = "core_check_tx_json_rpc_host")]
48 pub host: String,
49
50 #[serde(
52 rename = "core_check_tx_json_rpc_port",
53 deserialize_with = "from_str_or_number"
54 )]
55 pub port: u16,
56
57 #[serde(rename = "core_check_tx_json_rpc_username")]
59 pub username: String,
60
61 #[serde(rename = "core_check_tx_json_rpc_password")]
63 pub password: String,
64}
65
66impl CheckTxCoreRpcConfig {
67 pub fn url(&self) -> String {
69 format!("{}:{}", self.host, self.port)
70 }
71}
72
73#[derive(Clone, Debug, Serialize, Deserialize)]
75#[serde(default)]
76#[derive(Default)]
77pub struct CoreConfig {
78 #[serde(flatten)]
80 pub consensus_rpc: ConsensusCoreRpcConfig,
81 #[serde(flatten)]
83 pub check_tx_rpc: CheckTxCoreRpcConfig,
84}
85
86#[derive(Clone, Debug, Serialize, Deserialize)]
88pub struct ExecutionConfig {
91 #[serde(default = "ExecutionConfig::default_use_document_triggers")]
93 pub use_document_triggers: bool,
94
95 #[serde(default = "ExecutionConfig::default_verify_sum_trees")]
97 pub verify_sum_trees: bool,
98
99 #[serde(default = "ExecutionConfig::default_verify_token_sum_trees")]
101 pub verify_token_sum_trees: bool,
102
103 #[serde(
106 default = "ExecutionConfig::default_epoch_time_length_s",
107 deserialize_with = "from_str_or_number"
108 )]
109 pub epoch_time_length_s: u64,
110}
111
112#[derive(Clone, Debug, Serialize)]
128pub struct PlatformConfig {
131 pub network: Network,
133 #[serde(flatten)]
135 pub drive: DriveConfig,
136
137 #[serde(flatten)]
139 pub core: CoreConfig,
140
141 #[serde(flatten)]
143 pub abci: AbciConfig,
144
145 pub prometheus_bind_address: Option<String>,
154
155 pub grpc_bind_address: String,
157
158 #[serde(flatten)]
160 pub execution: ExecutionConfig,
161
162 #[serde(flatten)]
164 pub validator_set: ValidatorSetConfig,
165
166 #[serde(flatten)]
168 pub chain_lock: ChainLockConfig,
169
170 #[serde(flatten)]
172 pub instant_lock: InstantLockConfig,
173
174 pub block_spacing_ms: u64,
177
178 pub db_path: PathBuf,
180
181 pub rejections_path: Option<PathBuf>,
186
187 #[cfg(feature = "testing-config")]
188 #[serde(skip)]
190 pub testing_configs: PlatformTestConfig,
191
192 pub tokio_console_enabled: bool,
194
195 pub tokio_console_address: String,
198
199 pub tokio_console_retention_secs: u64,
201}
202
203#[derive(Deserialize)]
205struct PlatformConfigIntermediate {
206 #[serde(
208 default = "PlatformConfig::default_network",
209 deserialize_with = "from_str_to_network_with_aliases"
210 )]
211 pub network: Network,
212 #[serde(flatten)]
214 pub drive: DriveConfig,
215 #[serde(flatten)]
217 pub core: CoreConfig,
218 #[serde(flatten)]
219 pub abci: AbciConfig,
220 pub prometheus_bind_address: Option<String>,
221 pub grpc_bind_address: String,
222 #[serde(flatten)]
223 pub execution: ExecutionConfig,
224 #[serde(flatten)]
225 pub validator_set: ValidatorSetConfig,
226 #[serde(flatten)]
227 pub chain_lock: ChainLockConfig,
228 #[serde(flatten)]
229 pub instant_lock: InstantLockConfig,
230 pub block_spacing_ms: u64,
231 #[serde(default = "PlatformConfig::default_initial_protocol_version")]
232 #[allow(dead_code)]
234 pub initial_protocol_version: ProtocolVersion,
235 pub db_path: PathBuf,
236 #[serde(default)]
237 pub rejections_path: Option<PathBuf>,
238 #[cfg(feature = "testing-config")]
239 #[serde(skip)]
240 pub testing_configs: PlatformTestConfig,
241 pub tokio_console_enabled: bool,
242 #[serde(default = "PlatformConfig::default_tokio_console_address")]
243 pub tokio_console_address: String,
244 #[serde(default = "PlatformConfig::default_tokio_console_retention_secs")]
245 pub tokio_console_retention_secs: u64,
246}
247
248impl<'de> Deserialize<'de> for PlatformConfig {
249 fn deserialize<D>(deserializer: D) -> Result<PlatformConfig, D::Error>
250 where
251 D: Deserializer<'de>,
252 {
253 let mut config = PlatformConfigIntermediate::deserialize(deserializer)?;
255
256 config.drive.network = config.network;
258
259 Ok(PlatformConfig {
261 network: config.network,
262 drive: config.drive,
263 core: config.core,
265 abci: config.abci,
266 prometheus_bind_address: config.prometheus_bind_address,
267 grpc_bind_address: config.grpc_bind_address,
268 execution: config.execution,
269 validator_set: config.validator_set,
270 chain_lock: config.chain_lock,
271 instant_lock: config.instant_lock,
272 block_spacing_ms: config.block_spacing_ms,
273 db_path: config.db_path,
274 rejections_path: config.rejections_path,
275 #[cfg(feature = "testing-config")]
276 testing_configs: config.testing_configs,
277 tokio_console_enabled: config.tokio_console_enabled,
278 tokio_console_address: config.tokio_console_address,
279 tokio_console_retention_secs: config.tokio_console_retention_secs,
280 })
281 }
282}
283
284fn from_str_to_network_with_aliases<'de, D>(deserializer: D) -> Result<Network, D::Error>
285where
286 D: serde::Deserializer<'de>,
287{
288 let network_name = String::deserialize(deserializer)?;
289
290 match network_name.to_lowercase().as_str() {
291 "dash" | "mainnet" | "main" => Ok(Network::Mainnet),
292 "local" | "regtest" => Ok(Network::Regtest),
293 "testnet" | "test" => Ok(Network::Testnet),
294 "devnet" | "dev" => Ok(Network::Devnet),
295 _ => Err(serde::de::Error::custom(format!(
296 "can't parse network name: unknown network '{network_name}'"
297 ))),
298 }
299}
300
301pub trait QuorumLikeConfig: Sized {
303 fn quorum_type(&self) -> QuorumType;
305
306 fn quorum_size(&self) -> u16;
308
309 fn quorum_window(&self) -> u32;
311
312 fn quorum_active_signers(&self) -> u16;
314
315 fn quorum_rotation(&self) -> bool;
317}
318
319#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
321pub struct ValidatorSetConfig {
322 #[serde(
324 rename = "validator_set_quorum_type",
325 serialize_with = "serialize_quorum_type",
326 deserialize_with = "deserialize_quorum_type"
327 )]
328 pub quorum_type: QuorumType,
329
330 #[serde(
332 rename = "validator_set_quorum_size",
333 deserialize_with = "from_str_or_number"
334 )]
335 pub quorum_size: u16,
336
337 #[serde(
341 rename = "validator_set_quorum_window",
342 deserialize_with = "from_str_or_number"
343 )]
344 pub quorum_window: u32,
345
346 #[serde(
348 rename = "validator_set_quorum_active_signers",
349 deserialize_with = "from_str_or_number"
350 )]
351 pub quorum_active_signers: u16,
352
353 #[serde(
355 rename = "validator_set_quorum_rotation",
356 deserialize_with = "from_str_or_number"
357 )]
358 pub quorum_rotation: bool,
359}
360
361impl Default for ValidatorSetConfig {
362 fn default() -> Self {
363 Self::default_100_67()
365 }
366}
367
368impl ValidatorSetConfig {
369 pub fn default_100_67() -> Self {
371 Self {
372 quorum_type: QuorumType::Llmq100_67,
373 quorum_size: 100,
374 quorum_window: 24,
375 quorum_active_signers: 24,
376 quorum_rotation: false,
377 }
378 }
379}
380
381impl QuorumLikeConfig for ValidatorSetConfig {
382 fn quorum_type(&self) -> QuorumType {
383 self.quorum_type
384 }
385
386 fn quorum_size(&self) -> u16 {
387 self.quorum_size
388 }
389
390 fn quorum_window(&self) -> u32 {
391 self.quorum_window
392 }
393
394 fn quorum_active_signers(&self) -> u16 {
395 self.quorum_active_signers
396 }
397
398 fn quorum_rotation(&self) -> bool {
399 self.quorum_rotation
400 }
401}
402
403#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
405pub struct ChainLockConfig {
406 #[serde(
408 rename = "chain_lock_quorum_type",
409 serialize_with = "serialize_quorum_type",
410 deserialize_with = "deserialize_quorum_type"
411 )]
412 pub quorum_type: QuorumType,
413
414 #[serde(
416 rename = "chain_lock_quorum_size",
417 deserialize_with = "from_str_or_number"
418 )]
419 pub quorum_size: u16,
420
421 #[serde(
425 rename = "chain_lock_quorum_window",
426 deserialize_with = "from_str_or_number"
427 )]
428 pub quorum_window: u32,
429
430 #[serde(
432 rename = "chain_lock_quorum_active_signers",
433 deserialize_with = "from_str_or_number"
434 )]
435 pub quorum_active_signers: u16,
436
437 #[serde(
439 rename = "chain_lock_quorum_rotation",
440 deserialize_with = "from_str_or_number"
441 )]
442 pub quorum_rotation: bool,
443}
444
445impl Default for ChainLockConfig {
446 fn default() -> Self {
447 Self {
449 quorum_type: QuorumType::Llmq400_60,
450 quorum_size: 400,
451 quorum_window: 24 * 12,
452 quorum_active_signers: 4,
453 quorum_rotation: false,
454 }
455 }
456}
457
458impl QuorumLikeConfig for ChainLockConfig {
459 fn quorum_type(&self) -> QuorumType {
460 self.quorum_type
461 }
462
463 fn quorum_size(&self) -> u16 {
464 self.quorum_size
465 }
466
467 fn quorum_window(&self) -> u32 {
468 self.quorum_window
469 }
470
471 fn quorum_active_signers(&self) -> u16 {
472 self.quorum_active_signers
473 }
474
475 fn quorum_rotation(&self) -> bool {
476 self.quorum_rotation
477 }
478}
479
480impl ChainLockConfig {
481 pub fn default_100_67() -> Self {
483 Self {
484 quorum_type: QuorumType::Llmq100_67,
485 quorum_size: 100,
486 quorum_window: 24,
487 quorum_active_signers: 24,
488 quorum_rotation: false,
489 }
490 }
491}
492
493#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
495pub struct InstantLockConfig {
496 #[serde(
498 rename = "instant_lock_quorum_type",
499 serialize_with = "serialize_quorum_type",
500 deserialize_with = "deserialize_quorum_type"
501 )]
502 pub quorum_type: QuorumType,
503
504 #[serde(
506 rename = "instant_lock_quorum_size",
507 deserialize_with = "from_str_or_number"
508 )]
509 pub quorum_size: u16,
510
511 #[serde(
515 rename = "instant_lock_quorum_window",
516 deserialize_with = "from_str_or_number"
517 )]
518 pub quorum_window: u32,
519
520 #[serde(
522 rename = "instant_lock_quorum_active_signers",
523 deserialize_with = "from_str_or_number"
524 )]
525 pub quorum_active_signers: u16,
526
527 #[serde(
529 rename = "instant_lock_quorum_rotation",
530 deserialize_with = "from_str_or_number"
531 )]
532 pub quorum_rotation: bool,
533}
534
535impl Default for InstantLockConfig {
536 fn default() -> Self {
537 Self {
539 quorum_type: QuorumType::Llmq60_75,
540 quorum_active_signers: 32,
541 quorum_size: 60,
542 quorum_window: 24 * 12,
543 quorum_rotation: true,
544 }
545 }
546}
547
548impl InstantLockConfig {
549 pub fn default_100_67() -> Self {
551 Self {
552 quorum_type: QuorumType::Llmq100_67,
553 quorum_size: 100,
554 quorum_window: 24,
555 quorum_active_signers: 24,
556 quorum_rotation: false,
557 }
558 }
559}
560
561impl QuorumLikeConfig for InstantLockConfig {
562 fn quorum_type(&self) -> QuorumType {
563 self.quorum_type
564 }
565
566 fn quorum_size(&self) -> u16 {
567 self.quorum_size
568 }
569
570 fn quorum_window(&self) -> u32 {
571 self.quorum_window
572 }
573
574 fn quorum_active_signers(&self) -> u16 {
575 self.quorum_active_signers
576 }
577
578 fn quorum_rotation(&self) -> bool {
579 self.quorum_rotation
580 }
581}
582
583fn serialize_quorum_type<S>(quorum_type: &QuorumType, serializer: S) -> Result<S::Ok, S::Error>
584where
585 S: serde::Serializer,
586{
587 serializer.serialize_str(quorum_type.to_string().as_str())
588}
589
590fn deserialize_quorum_type<'de, D>(deserializer: D) -> Result<QuorumType, D::Error>
591where
592 D: serde::Deserializer<'de>,
593{
594 let quorum_type_name = String::deserialize(deserializer)?;
595
596 let quorum_type = if let Ok(t) = quorum_type_name.trim().parse::<u32>() {
597 QuorumType::from(t)
598 } else {
599 QuorumType::from(quorum_type_name.as_str())
600 };
601
602 if quorum_type == QuorumType::UNKNOWN {
603 return Err(serde::de::Error::custom(format!(
604 "unsupported QUORUM_TYPE: {}",
605 quorum_type_name
606 )));
607 };
608
609 Ok(quorum_type)
610}
611
612impl ExecutionConfig {
613 fn default_verify_sum_trees() -> bool {
614 true
615 }
616
617 fn default_verify_token_sum_trees() -> bool {
618 true
619 }
620
621 fn default_use_document_triggers() -> bool {
622 true
623 }
624
625 fn default_epoch_time_length_s() -> u64 {
626 788400
627 }
628}
629
630impl PlatformConfig {
631 fn default_initial_protocol_version() -> ProtocolVersion {
632 INITIAL_PROTOCOL_VERSION
633 }
634
635 fn default_network() -> Network {
636 Network::Mainnet
637 }
638
639 fn default_tokio_console_address() -> String {
640 String::from("127.0.0.1:6669")
641 }
642
643 fn default_tokio_console_retention_secs() -> u64 {
644 60 * 3
645 }
646}
647
648pub trait FromEnv {
650 fn from_env() -> Result<Self, Error>
652 where
653 Self: Sized + DeserializeOwned,
654 {
655 envy::from_env::<Self>().map_err(Error::from)
656 }
657}
658
659impl FromEnv for PlatformConfig {
660 fn from_env() -> Result<Self, Error>
661 where
662 Self: Sized + DeserializeOwned,
663 {
664 let mut me = envy::from_env::<Self>().map_err(Error::from)?;
665 me.abci.log = LogConfigs::from_env()?;
666
667 Ok(me)
668 }
669}
670
671impl Default for ExecutionConfig {
672 fn default() -> Self {
673 Self {
674 use_document_triggers: ExecutionConfig::default_use_document_triggers(),
675 verify_sum_trees: ExecutionConfig::default_verify_sum_trees(),
676 verify_token_sum_trees: ExecutionConfig::default_verify_token_sum_trees(),
677 epoch_time_length_s: ExecutionConfig::default_epoch_time_length_s(),
678 }
679 }
680}
681
682impl Default for PlatformConfig {
683 fn default() -> Self {
684 Self::default_mainnet()
685 }
686}
687
688impl PlatformConfig {
690 pub fn default_for_network(network: Network) -> Self {
692 match network {
693 Network::Mainnet => Self::default_mainnet(),
694 Network::Testnet => Self::default_testnet(),
695 Network::Devnet => Self::default_devnet(),
696 Network::Regtest => Self::default_local(),
697 _ => Self::default_testnet(),
698 }
699 }
700
701 pub fn default_local() -> Self {
703 Self {
704 network: Network::Regtest,
705 validator_set: ValidatorSetConfig {
706 quorum_type: QuorumType::LlmqTestPlatform,
707 quorum_size: 3,
708 quorum_window: 24,
709 quorum_active_signers: 2,
710 quorum_rotation: false,
711 },
712 chain_lock: ChainLockConfig {
713 quorum_type: QuorumType::LlmqTest,
714 quorum_active_signers: 2,
715 quorum_size: 3,
716 quorum_window: 24,
717 quorum_rotation: false,
718 },
719 instant_lock: InstantLockConfig {
720 quorum_type: QuorumType::LlmqTest,
721 quorum_active_signers: 2,
722 quorum_size: 3,
723 quorum_window: 24,
724 quorum_rotation: false,
725 },
726 block_spacing_ms: 5000,
727 drive: Default::default(),
728 abci: Default::default(),
729 core: Default::default(),
730 execution: Default::default(),
731 db_path: PathBuf::from("/var/lib/dash-platform/data"),
732 rejections_path: Some(PathBuf::from("/var/log/dash/rejected")),
733 #[cfg(feature = "testing-config")]
734 testing_configs: PlatformTestConfig::default(),
735 tokio_console_enabled: false,
736 tokio_console_address: PlatformConfig::default_tokio_console_address(),
737 tokio_console_retention_secs: PlatformConfig::default_tokio_console_retention_secs(),
738 prometheus_bind_address: None,
739 grpc_bind_address: "127.0.0.1:26670".to_string(),
740 }
741 }
742
743 pub fn default_devnet() -> Self {
745 Self {
746 network: Network::Regtest,
747 validator_set: ValidatorSetConfig {
748 quorum_type: QuorumType::LlmqDevnetPlatform,
749 quorum_size: 12,
750 quorum_window: 24,
751 quorum_active_signers: 8,
752 quorum_rotation: false,
753 },
754 chain_lock: ChainLockConfig {
755 quorum_type: QuorumType::LlmqDevnetPlatform,
756 quorum_size: 12,
757 quorum_window: 24,
758 quorum_active_signers: 8,
759 quorum_rotation: false,
760 },
761 instant_lock: InstantLockConfig {
762 quorum_type: QuorumType::LlmqDevnetDip0024,
763 quorum_active_signers: 4,
764 quorum_size: 8,
765 quorum_window: 48,
766 quorum_rotation: true,
767 },
768 block_spacing_ms: 5000,
769 drive: Default::default(),
770 abci: Default::default(),
771 core: Default::default(),
772 execution: Default::default(),
773 db_path: PathBuf::from("/var/lib/dash-platform/data"),
774 rejections_path: Some(PathBuf::from("/var/log/dash/rejected")),
775 #[cfg(feature = "testing-config")]
776 testing_configs: PlatformTestConfig::default(),
777 tokio_console_enabled: false,
778 tokio_console_address: PlatformConfig::default_tokio_console_address(),
779 tokio_console_retention_secs: PlatformConfig::default_tokio_console_retention_secs(),
780 prometheus_bind_address: None,
781 grpc_bind_address: "127.0.0.1:26670".to_string(),
782 }
783 }
784
785 pub fn default_testnet() -> Self {
787 Self {
788 network: Network::Testnet,
789 validator_set: ValidatorSetConfig {
790 quorum_type: QuorumType::Llmq25_67,
791 quorum_size: 25,
792 quorum_window: 24,
793 quorum_active_signers: 24,
794 quorum_rotation: false,
795 },
796 chain_lock: ChainLockConfig {
797 quorum_type: QuorumType::Llmq50_60,
798 quorum_active_signers: 24,
799 quorum_size: 50,
800 quorum_window: 24,
801 quorum_rotation: false,
802 },
803 instant_lock: InstantLockConfig {
804 quorum_type: QuorumType::Llmq60_75,
805 quorum_active_signers: 32,
806 quorum_size: 60,
807 quorum_window: 24 * 12,
808 quorum_rotation: true,
809 },
810 block_spacing_ms: 5000,
811 drive: DriveConfig::default_testnet(),
812 abci: Default::default(),
813 core: Default::default(),
814 execution: Default::default(),
815 db_path: PathBuf::from("/var/lib/dash-platform/data"),
816 rejections_path: Some(PathBuf::from("/var/log/dash/rejected")),
817 #[cfg(feature = "testing-config")]
818 testing_configs: PlatformTestConfig::default(),
819 prometheus_bind_address: None,
820 grpc_bind_address: "127.0.0.1:26670".to_string(),
821 tokio_console_enabled: false,
822 tokio_console_address: PlatformConfig::default_tokio_console_address(),
823 tokio_console_retention_secs: PlatformConfig::default_tokio_console_retention_secs(),
824 }
825 }
826
827 pub fn default_mainnet() -> Self {
829 Self {
830 network: Network::Mainnet,
831 validator_set: ValidatorSetConfig {
832 quorum_type: QuorumType::Llmq100_67,
833 quorum_size: 100,
834 quorum_window: 24,
835 quorum_active_signers: 24,
836 quorum_rotation: false,
837 },
838 chain_lock: ChainLockConfig {
839 quorum_type: QuorumType::Llmq400_60,
840 quorum_active_signers: 4,
841 quorum_size: 400,
842 quorum_window: 24 * 12,
843 quorum_rotation: false,
844 },
845 instant_lock: InstantLockConfig {
846 quorum_type: QuorumType::Llmq60_75,
847 quorum_active_signers: 32,
848 quorum_size: 60,
849 quorum_window: 24 * 12,
850 quorum_rotation: true,
851 },
852 block_spacing_ms: 5000,
853 drive: Default::default(),
854 abci: Default::default(),
855 core: Default::default(),
856 execution: Default::default(),
857 db_path: PathBuf::from("/var/lib/dash-platform/data"),
858 rejections_path: Some(PathBuf::from("/var/log/dash/rejected")),
859 #[cfg(feature = "testing-config")]
860 testing_configs: PlatformTestConfig::default(),
861 prometheus_bind_address: None,
862 grpc_bind_address: "127.0.0.1:26670".to_string(),
863 tokio_console_enabled: false,
864 tokio_console_address: PlatformConfig::default_tokio_console_address(),
865 tokio_console_retention_secs: PlatformConfig::default_tokio_console_retention_secs(),
866 }
867 }
868}
869
870#[cfg(feature = "testing-config")]
871#[derive(Clone, Debug)]
873pub struct PlatformTestConfig {
874 pub block_signing: bool,
876 pub store_platform_state: bool,
878 pub block_commit_signature_verification: bool,
880 pub disable_instant_lock_signature_verification: bool,
882 pub disable_contested_documents_is_allowed_validation: bool,
884 pub disable_checkpoints: bool,
886}
887
888#[cfg(feature = "testing-config")]
889impl PlatformTestConfig {
890 pub fn default_minimal_verifications() -> Self {
892 Self {
893 block_signing: false,
894 store_platform_state: false,
895 block_commit_signature_verification: false,
896 disable_instant_lock_signature_verification: true,
897 disable_contested_documents_is_allowed_validation: true,
898 disable_checkpoints: true,
899 }
900 }
901}
902
903#[cfg(feature = "testing-config")]
904impl Default for PlatformTestConfig {
905 fn default() -> Self {
906 Self {
907 block_signing: true,
908 store_platform_state: true,
909 block_commit_signature_verification: true,
910 disable_instant_lock_signature_verification: false,
911 disable_contested_documents_is_allowed_validation: true,
912 disable_checkpoints: true,
913 }
914 }
915}
916
917#[cfg(test)]
918mod tests {
919 use super::FromEnv;
920 use crate::logging::LogDestination;
921 use dpp::dashcore::Network;
922 use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType;
923 use std::env;
924
925 #[test]
926 fn test_config_from_env() {
927 let vectors = &[
930 ("STDOUT", "pretty"),
931 ("UPPERCASE", "json"),
932 ("lowercase", "pretty"),
933 ("miXedC4s3", "full"),
934 ("123", "compact"),
935 ];
936 for vector in vectors {
937 env::set_var(format!("ABCI_LOG_{}_DESTINATION", vector.0), "bytes");
938 env::set_var(format!("ABCI_LOG_{}_FORMAT", vector.0), vector.1);
939 }
940
941 let envfile = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".env.local");
942
943 dotenvy::from_path(envfile.as_path()).expect("cannot load .env file");
944 assert_eq!("/tmp/db", env::var("DB_PATH").unwrap());
945 assert_eq!("/tmp/rejected", env::var("REJECTIONS_PATH").unwrap());
946
947 let config = super::PlatformConfig::from_env().expect("expected config from env");
948 assert!(config.execution.verify_sum_trees);
949 assert_ne!(config.validator_set.quorum_type, QuorumType::UNKNOWN);
950 for id in vectors {
951 matches!(config.abci.log[id.0].destination, LogDestination::Bytes);
952 }
953 }
954
955 #[test]
956 #[ignore]
957 fn test_config_from_testnet_propagates_network() {
959 let envfile = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".env.testnet");
963
964 dotenvy::from_path(envfile.as_path()).expect("cannot load .env file");
965
966 let config = super::PlatformConfig::from_env().expect("expected config from env");
967 assert!(config.execution.verify_sum_trees);
968 assert_eq!(config.validator_set.quorum_type, QuorumType::Llmq25_67);
969 assert_eq!(config.network, config.drive.network);
970 assert_eq!(config.network, Network::Testnet);
971 }
972}