Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #include <csignal>
7 : #include <fstream>
8 : #include <thread>
9 :
10 : #include <gflags/gflags.h>
11 : #include <grpc++/grpc++.h>
12 : #include "ametsuchi/storage.hpp"
13 : #include "common/result.hpp"
14 : #include "crypto/keys_manager_impl.hpp"
15 : #include "logger/logger.hpp"
16 : #include "logger/logger_manager.hpp"
17 : #include "main/application.hpp"
18 : #include "main/iroha_conf_literals.hpp"
19 : #include "main/iroha_conf_loader.hpp"
20 : #include "main/raw_block_loader.hpp"
21 :
22 : static const std::string kListenIp = "0.0.0.0";
23 : static const std::string kLogSettingsFromConfigFile = "config_file";
24 : static const uint32_t kMstExpirationTimeDefault = 1440;
25 0 : static const uint32_t kMaxRoundsDelayDefault = 3000;
26 : static const uint32_t kStaleStreamMaxRoundsDefault = 2;
27 :
28 : /**
29 : * Gflag validator.
30 : * Validator for the configuration file path input argument.
31 : * Path is considered to be valid if it is not empty.
32 : * @param flag_name - flag name. Must be 'config' in this case
33 : * @param path - file name. Should be path to the config file
34 : * @return true if argument is valid
35 : */
36 : bool validate_config(const char *flag_name, std::string const &path) {
37 0 : return not path.empty();
38 : }
39 :
40 : /**
41 : * Gflag validator.
42 : * Validator for the keypair files path input argument.
43 : * Path is considered to be valid if it is not empty.
44 : * @param flag_name - flag name. Must be 'keypair_name' in this case
45 : * @param path - file name. Should be path to the keypair files
46 : * @return true if argument is valid
47 : */
48 : bool validate_keypair_name(const char *flag_name, std::string const &path) {
49 0 : return not path.empty();
50 : }
51 :
52 : /**
53 : * Creating input argument for the configuration file location.
54 : */
55 : DEFINE_string(config, "", "Specify iroha provisioning path.");
56 : /**
57 : * Registering validator for the configuration file location.
58 : */
59 : DEFINE_validator(config, &validate_config);
60 :
61 : /**
62 : * Creating input argument for the genesis block file location.
63 : */
64 : DEFINE_string(genesis_block, "", "Specify file with initial block");
65 :
66 : /**
67 : * Creating input argument for the keypair files location.
68 : */
69 : DEFINE_string(keypair_name, "", "Specify name of .pub and .priv files");
70 : /**
71 : * Registering validator for the keypair files location.
72 : */
73 : DEFINE_validator(keypair_name, &validate_keypair_name);
74 :
75 : /**
76 : * Creating boolean flag for overwriting already existing block storage
77 : */
78 : DEFINE_bool(overwrite_ledger, false, "Overwrite ledger data if existing");
79 :
80 : static bool validateVerbosity(const char *flagname, const std::string &val) {
81 0 : if (val == kLogSettingsFromConfigFile) {
82 0 : return true;
83 : }
84 0 : const auto it = config_members::LogLevels.find(val);
85 0 : if (it == config_members::LogLevels.end()) {
86 0 : std::cerr << "Invalid value for " << flagname << ": should be one of '"
87 0 : << kLogSettingsFromConfigFile;
88 0 : for (const auto &level : config_members::LogLevels) {
89 0 : std::cerr << "', '" << level.first;
90 : }
91 0 : std::cerr << "'." << std::endl;
92 0 : return false;
93 : }
94 0 : return true;
95 0 : }
96 :
97 : /// Verbosity flag for spdlog configuration
98 : DEFINE_string(verbosity, kLogSettingsFromConfigFile, "Log verbosity");
99 : DEFINE_validator(verbosity, &validateVerbosity);
100 :
101 : std::promise<void> exit_requested;
102 :
103 : logger::LoggerManagerTreePtr getDefaultLogManager() {
104 0 : return std::make_shared<logger::LoggerManagerTree>(logger::LoggerConfig{
105 0 : logger::LogLevel::kInfo, logger::getDefaultLogPatterns()});
106 0 : }
107 :
108 : int main(int argc, char *argv[]) {
109 : // Parsing command line arguments
110 0 : gflags::ParseCommandLineFlags(&argc, &argv, true);
111 :
112 0 : logger::LoggerManagerTreePtr log_manager;
113 0 : logger::LoggerPtr log;
114 :
115 : // If the global log level override was set in the command line arguments,
116 : // create a logger manager with the given log level for all subsystems:
117 0 : if (FLAGS_verbosity != kLogSettingsFromConfigFile) {
118 0 : logger::LoggerConfig cfg;
119 0 : cfg.log_level = config_members::LogLevels.at(FLAGS_verbosity);
120 0 : log_manager = std::make_shared<logger::LoggerManagerTree>(std::move(cfg));
121 0 : log = log_manager->getChild("Init")->getLogger();
122 0 : }
123 :
124 : // Check if validators are registered.
125 0 : if (not config_validator_registered
126 0 : or not keypair_name_validator_registered) {
127 : // Abort execution if not
128 0 : if (log) {
129 0 : log->error("Flag validator is not registered");
130 0 : }
131 0 : return EXIT_FAILURE;
132 : }
133 :
134 : // Reading iroha configuration file
135 0 : const auto config = parse_iroha_config(FLAGS_config);
136 0 : if (not log_manager) {
137 0 : log_manager = config.logger_manager.value_or(getDefaultLogManager());
138 0 : log = log_manager->getChild("Init")->getLogger();
139 0 : }
140 0 : log->info("config initialized");
141 :
142 : // Reading public and private key files
143 0 : iroha::KeysManagerImpl keysManager(
144 0 : FLAGS_keypair_name, log_manager->getChild("KeysManager")->getLogger());
145 0 : auto keypair = keysManager.loadKeys();
146 : // Check if both keys are read properly
147 0 : if (not keypair) {
148 : // Abort execution if not
149 0 : log->error("Failed to load keypair");
150 0 : return EXIT_FAILURE;
151 : }
152 :
153 : // Configuring iroha daemon
154 0 : Irohad irohad(
155 0 : config.block_store_path,
156 0 : config.pg_opt,
157 : kListenIp, // TODO(mboldyrev) 17/10/2018: add a parameter in
158 : // config file and/or command-line arguments?
159 0 : config.torii_port,
160 0 : config.internal_port,
161 0 : config.max_proposal_size,
162 0 : std::chrono::milliseconds(config.proposal_delay),
163 0 : std::chrono::milliseconds(config.vote_delay),
164 0 : std::chrono::minutes(
165 0 : config.mst_expiration_time.value_or(kMstExpirationTimeDefault)),
166 0 : *keypair,
167 0 : std::chrono::milliseconds(
168 0 : config.max_round_delay_ms.value_or(kMaxRoundsDelayDefault)),
169 0 : config.stale_stream_max_rounds.value_or(kStaleStreamMaxRoundsDefault),
170 0 : log_manager->getChild("Irohad"),
171 0 : boost::make_optional(config.mst_support,
172 0 : iroha::GossipPropagationStrategyParams{}));
173 :
174 : // Check if iroha daemon storage was successfully initialized
175 0 : if (not irohad.storage) {
176 : // Abort execution if not
177 0 : log->error("Failed to initialize storage");
178 0 : return EXIT_FAILURE;
179 : }
180 :
181 : /*
182 : * The logic implemented below is reflected in the following truth table.
183 : *
184 : +------------+--------------+------------------+---------------+---------+
185 : | Blockstore | New genesis | Overwrite ledger | Genesis block | Message |
186 : | presence | block is set | flag is set | that is used | |
187 : +------------+--------------+------------------+---------------+---------+
188 : | 0 | 1 | 0 | new | |
189 : | 0 | 1 | 1 | new | warning |
190 : | 1 | 1 | 0 | old | warning |
191 : | 1 | 1 | 1 | new | |
192 : | 0 | 0 | 0 | none | error |
193 : | 0 | 0 | 1 | none | error |
194 : | 1 | 0 | 0 | old | |
195 : | 1 | 0 | 1 | old | warning |
196 : +------------+--------------+------------------+---------------+---------+
197 : */
198 :
199 : /// if there are any blocks in blockstore, then true
200 0 : bool blockstore = irohad.storage->getBlockQuery()->getTopBlockHeight() != 0;
201 :
202 : /// genesis block file is specified as launch parameter
203 0 : bool genesis = not FLAGS_genesis_block.empty();
204 :
205 : /// overwrite ledger flag was set as launch parameter
206 0 : bool overwrite = FLAGS_overwrite_ledger;
207 :
208 0 : if (genesis) { // genesis block file is specified
209 0 : if (blockstore and not overwrite) {
210 0 : log->warn(
211 0 : "Passed genesis block will be ignored without --overwrite_ledger "
212 : "flag. Restoring existing state.");
213 0 : } else {
214 0 : iroha::main::BlockLoader loader(
215 0 : log_manager->getChild("GenesisBlockLoader")->getLogger());
216 0 : auto file = loader.loadFile(FLAGS_genesis_block);
217 0 : auto block = loader.parseBlock(file.value());
218 :
219 0 : if (not block) {
220 0 : log->error("Failed to parse genesis block.");
221 0 : return EXIT_FAILURE;
222 : }
223 :
224 0 : if (not blockstore and overwrite) {
225 0 : log->warn(
226 0 : "Blockstore is empty - there is nothing to overwrite. Inserting "
227 : "new genesis block.");
228 0 : }
229 :
230 : // clear previous storage if any
231 0 : irohad.dropStorage();
232 :
233 0 : irohad.storage->insertBlock(*block.value());
234 0 : log->info("Genesis block inserted, number of transactions: {}",
235 0 : block.value()->transactions().size());
236 0 : }
237 0 : } else { // genesis block file is not specified
238 0 : if (not blockstore) {
239 0 : log->error(
240 0 : "Cannot restore nor create new state. Blockstore is empty. No "
241 : "genesis block is provided. Please pecify new genesis block using "
242 : "--genesis_block parameter.");
243 0 : return EXIT_FAILURE;
244 : } else {
245 0 : if (overwrite) {
246 0 : log->warn(
247 0 : "No new genesis block is specified - blockstore cannot be "
248 : "overwritten. If you want overwrite ledger state, please "
249 : "specify new genesis block using --genesis_block parameter.");
250 0 : }
251 : }
252 : }
253 :
254 : // check if at least one block is available in the ledger
255 0 : auto blocks_exist = irohad.storage->getBlockQuery()->getTopBlock().match(
256 : [](const auto &) { return true; },
257 : [](iroha::expected::Error<std::string> &) { return false; });
258 :
259 0 : if (not blocks_exist) {
260 0 : log->error(
261 0 : "Unable to start the ledger. There are no blocks in the ledger. Please "
262 : "ensure that you are not trying to start the newer version of "
263 : "the ledger over incompatible version of the storage or there is "
264 : "enough disk space. Try to specify --genesis_block and "
265 : "--overwrite_ledger parameters at the same time.");
266 0 : return EXIT_FAILURE;
267 : }
268 :
269 : // init pipeline components
270 0 : irohad.init();
271 :
272 : auto handler = [](int s) { exit_requested.set_value(); };
273 0 : std::signal(SIGINT, handler);
274 0 : std::signal(SIGTERM, handler);
275 : #ifdef SIGQUIT
276 0 : std::signal(SIGQUIT, handler);
277 : #endif
278 :
279 : // runs iroha
280 0 : log->info("Running iroha");
281 0 : irohad.run();
282 0 : exit_requested.get_future().wait();
283 :
284 : // We do not care about shutting down grpc servers
285 : // They do all necessary work in their destructors
286 0 : log->info("shutting down...");
287 :
288 0 : gflags::ShutDownCommandLineFlags();
289 :
290 0 : return 0;
291 0 : }
|