diem_config/config/
execution_config.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use crate::config::{Error, RootPath, SecureBackend};
9use diem_types::transaction::Transaction;
10use serde::{Deserialize, Serialize};
11use std::{
12    fs::File,
13    io::{Read, Write},
14    net::SocketAddr,
15    path::PathBuf,
16};
17
18const GENESIS_DEFAULT: &str = "genesis.blob";
19
20#[derive(Clone, Deserialize, PartialEq, Serialize)]
21#[serde(default, deny_unknown_fields)]
22pub struct ExecutionConfig {
23    #[serde(skip)]
24    pub genesis: Option<Transaction>,
25    pub sign_vote_proposal: bool,
26    pub genesis_file_location: PathBuf,
27    pub service: ExecutionCorrectnessService,
28    pub backend: SecureBackend,
29    pub network_timeout_ms: u64,
30}
31
32impl std::fmt::Debug for ExecutionConfig {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        write!(f, "ExecutionConfig {{ genesis: ")?;
35        if self.genesis.is_some() {
36            write!(f, "Some(...)")?;
37        } else {
38            write!(f, "None")?;
39        }
40        write!(
41            f,
42            ", genesis_file_location: {:?} ",
43            self.genesis_file_location
44        )?;
45        write!(
46            f,
47            ", sign_vote_proposal: {:?}, service: {:?}, backend: {:?} }}",
48            self.sign_vote_proposal, self.service, self.backend
49        )?;
50        self.service.fmt(f)
51    }
52}
53
54impl Default for ExecutionConfig {
55    fn default() -> ExecutionConfig {
56        ExecutionConfig {
57            genesis: None,
58            genesis_file_location: PathBuf::new(),
59            service: ExecutionCorrectnessService::Thread,
60            backend: SecureBackend::InMemoryStorage,
61            sign_vote_proposal: true,
62            // Default value of 30 seconds for the network timeout.
63            network_timeout_ms: 30_000,
64        }
65    }
66}
67
68impl ExecutionConfig {
69    pub fn load(&mut self, root_dir: &RootPath) -> Result<(), Error> {
70        if !self.genesis_file_location.as_os_str().is_empty() {
71            let path = root_dir.full_path(&self.genesis_file_location);
72            let mut file = File::open(&path)
73                .map_err(|e| Error::IO("genesis".into(), e))?;
74            let mut buffer = vec![];
75            file.read_to_end(&mut buffer)
76                .map_err(|e| Error::IO("genesis".into(), e))?;
77            let data = bcs::from_bytes(&buffer)
78                .map_err(|e| Error::BCS("genesis", e))?;
79            self.genesis = Some(data);
80        }
81
82        Ok(())
83    }
84
85    pub fn save(&mut self, root_dir: &RootPath) -> Result<(), Error> {
86        if let Some(genesis) = &self.genesis {
87            if self.genesis_file_location.as_os_str().is_empty() {
88                self.genesis_file_location = PathBuf::from(GENESIS_DEFAULT);
89            }
90            let path = root_dir.full_path(&self.genesis_file_location);
91            let mut file = File::create(&path)
92                .map_err(|e| Error::IO("genesis".into(), e))?;
93            let data = bcs::to_bytes(&genesis)
94                .map_err(|e| Error::BCS("genesis", e))?;
95            file.write_all(&data)
96                .map_err(|e| Error::IO("genesis".into(), e))?;
97        }
98        Ok(())
99    }
100
101    pub fn set_data_dir(&mut self, data_dir: PathBuf) {
102        if let SecureBackend::OnDiskStorage(backend) = &mut self.backend {
103            backend.set_data_dir(data_dir);
104        }
105    }
106}
107
108/// Defines how execution correctness should be run
109#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
110#[serde(rename_all = "snake_case", tag = "type")]
111pub enum ExecutionCorrectnessService {
112    /// This runs execution correctness in the same thread as event processor.
113    Local,
114    /// This is the production, separate service approach
115    Process(RemoteExecutionService),
116    /// This runs safety rules in the same thread as event processor but data
117    /// is passed through the light weight RPC (serializer)
118    Serializer,
119    /// This creates a separate thread to run execution correctness, it is
120    /// similar to a fork / exec style
121    Thread,
122}
123
124#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
125#[serde(deny_unknown_fields)]
126pub struct RemoteExecutionService {
127    pub server_address: SocketAddr,
128}
129
130#[cfg(test)]
131mod test {
132    use super::*;
133    use diem_temppath::TempPath;
134    use diem_types::{
135        transaction::{ChangeSet, Transaction, WriteSetPayload},
136        write_set::WriteSetMut,
137    };
138
139    #[test]
140    fn test_no_genesis() {
141        let (mut config, path) = generate_config();
142        assert_eq!(config.genesis, None);
143        let root_dir = RootPath::new_path(path.path());
144        let result = config.load(&root_dir);
145        assert!(result.is_ok());
146        assert_eq!(config.genesis_file_location, PathBuf::new());
147    }
148
149    #[test]
150    fn test_some_and_load_genesis() {
151        let fake_genesis = Transaction::GenesisTransaction(
152            WriteSetPayload::Direct(ChangeSet::new(
153                WriteSetMut::new(vec![]).freeze().unwrap(),
154                vec![],
155            )),
156        );
157        let (mut config, path) = generate_config();
158        config.genesis = Some(fake_genesis.clone());
159        let root_dir = RootPath::new_path(path.path());
160        config.save(&root_dir).expect("Unable to save");
161        // Verifies some without path
162        assert_eq!(
163            config.genesis_file_location,
164            PathBuf::from(GENESIS_DEFAULT)
165        );
166
167        config.genesis = None;
168        let result = config.load(&root_dir);
169        assert!(result.is_ok());
170        assert_eq!(config.genesis, Some(fake_genesis));
171    }
172
173    fn generate_config() -> (ExecutionConfig, TempPath) {
174        let temp_dir = TempPath::new();
175        temp_dir.create_as_dir().expect("error creating tempdir");
176        let execution_config = ExecutionConfig::default();
177        (execution_config, temp_dir)
178    }
179}