Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved.
3 : * http://soramitsu.co.jp
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <gflags/gflags.h>
19 : #include <grpc++/grpc++.h>
20 : #include <csignal>
21 : #include <fstream>
22 : #include <thread>
23 : #include "common/result.hpp"
24 : #include "crypto/keys_manager_impl.hpp"
25 0 : #include "main/application.hpp"
26 : #include "main/iroha_conf_loader.hpp"
27 : #include "main/raw_block_loader.hpp"
28 :
29 : static const std::string kListenIp = "0.0.0.0";
30 :
31 : /**
32 : * Gflag validator.
33 : * Validator for the configuration file path input argument.
34 : * Path is considered to be valid if it is not empty.
35 : * @param flag_name - flag name. Must be 'config' in this case
36 : * @param path - file name. Should be path to the config file
37 : * @return true if argument is valid
38 : */
39 : bool validate_config(const char *flag_name, std::string const &path) {
40 0 : return not path.empty();
41 : }
42 :
43 : /**
44 : * Gflag validator.
45 : * Validator for the keypair files path input argument.
46 : * Path is considered to be valid if it is not empty.
47 : * @param flag_name - flag name. Must be 'keypair_name' in this case
48 : * @param path - file name. Should be path to the keypair files
49 : * @return true if argument is valid
50 : */
51 : bool validate_keypair_name(const char *flag_name, std::string const &path) {
52 0 : return not path.empty();
53 : }
54 :
55 : /**
56 : * Creating input argument for the configuration file location.
57 : */
58 : DEFINE_string(config, "", "Specify iroha provisioning path.");
59 : /**
60 : * Registering validator for the configuration file location.
61 : */
62 : DEFINE_validator(config, &validate_config);
63 :
64 : /**
65 : * Creating input argument for the genesis block file location.
66 : */
67 : DEFINE_string(genesis_block, "", "Specify file with initial block");
68 :
69 : /**
70 : * Creating input argument for the keypair files location.
71 : */
72 : DEFINE_string(keypair_name, "", "Specify name of .pub and .priv files");
73 : /**
74 : * Registering validator for the keypair files location.
75 : */
76 : DEFINE_validator(keypair_name, &validate_keypair_name);
77 :
78 : /**
79 : * Creating boolean flag for overwriting already existing block storage
80 : */
81 : DEFINE_bool(overwrite_ledger, false, "Overwrite ledger data if existing");
82 :
83 : static bool validateVerbosity(const char *flagname, int32_t val) {
84 0 : if (val >= 0 && val <= 6)
85 0 : return true;
86 :
87 0 : std::cout << "Invalid value for " << flagname << ": should be in range [0, 6]"
88 0 : << std::endl;
89 0 : return false;
90 0 : }
91 :
92 : /// Verbosity flag for spdlog configuration
93 : DEFINE_int32(verbosity, spdlog::level::info, "Log verbosity");
94 : DEFINE_validator(verbosity, validateVerbosity);
95 :
96 : std::promise<void> exit_requested;
97 :
98 : int main(int argc, char *argv[]) {
99 0 : spdlog::set_level(spdlog::level::level_enum(FLAGS_verbosity));
100 :
101 0 : auto log = logger::log("MAIN");
102 : log->info("start");
103 :
104 : // Check if validators are registered.
105 0 : if (not config_validator_registered
106 0 : or not keypair_name_validator_registered) {
107 : // Abort execution if not
108 0 : log->error("Flag validator is not registered");
109 0 : return EXIT_FAILURE;
110 : }
111 :
112 : namespace mbr = config_members;
113 :
114 : // Parsing command line arguments
115 0 : gflags::ParseCommandLineFlags(&argc, &argv, true);
116 0 : gflags::ShutDownCommandLineFlags();
117 :
118 : // Reading iroha configuration file
119 0 : auto config = parse_iroha_config(FLAGS_config);
120 0 : log->info("config initialized");
121 :
122 : // Reading public and private key files
123 0 : iroha::KeysManagerImpl keysManager(FLAGS_keypair_name);
124 0 : auto keypair = keysManager.loadKeys();
125 : // Check if both keys are read properly
126 0 : if (not keypair) {
127 : // Abort execution if not
128 0 : log->error("Failed to load keypair");
129 0 : return EXIT_FAILURE;
130 : }
131 :
132 : // Configuring iroha daemon
133 0 : Irohad irohad(config[mbr::BlockStorePath].GetString(),
134 0 : config[mbr::PgOpt].GetString(),
135 : kListenIp, // TODO(mboldyrev) 17/10/2018: add a parameter in
136 : // config file and/or command-line arguments?
137 0 : config[mbr::ToriiPort].GetUint(),
138 0 : config[mbr::InternalPort].GetUint(),
139 0 : config[mbr::MaxProposalSize].GetUint(),
140 0 : std::chrono::milliseconds(config[mbr::ProposalDelay].GetUint()),
141 0 : std::chrono::milliseconds(config[mbr::VoteDelay].GetUint()),
142 0 : *keypair,
143 0 : boost::make_optional(config[mbr::MstSupport].GetBool(),
144 0 : iroha::GossipPropagationStrategyParams{}));
145 :
146 : // Check if iroha daemon storage was successfully initialized
147 0 : if (not irohad.storage) {
148 : // Abort execution if not
149 0 : log->error("Failed to initialize storage");
150 0 : return EXIT_FAILURE;
151 : }
152 :
153 : /*
154 : * The logic implemented below is reflected in the following truth table.
155 : *
156 : +------------+--------------+------------------+---------------+---------+
157 : | Blockstore | New genesis | Overwrite ledger | Genesis block | Message |
158 : | presence | block is set | flag is set | that is used | |
159 : +------------+--------------+------------------+---------------+---------+
160 : | 0 | 1 | 0 | new | |
161 : | 0 | 1 | 1 | new | warning |
162 : | 1 | 1 | 0 | old | warning |
163 : | 1 | 1 | 1 | new | |
164 : | 0 | 0 | 0 | none | error |
165 : | 0 | 0 | 1 | none | error |
166 : | 1 | 0 | 0 | old | |
167 : | 1 | 0 | 1 | old | warning |
168 : +------------+--------------+------------------+---------------+---------+
169 : */
170 :
171 : /// if there are any blocks in blockstore, then true
172 0 : bool blockstore = irohad.storage->getBlockQuery()->getTopBlockHeight() != 0;
173 :
174 : /// genesis block file is specified as launch parameter
175 0 : bool genesis = not FLAGS_genesis_block.empty();
176 :
177 : /// overwrite ledger flag was set as launch parameter
178 0 : bool overwrite = FLAGS_overwrite_ledger;
179 :
180 0 : if (genesis) { // genesis block file is specified
181 0 : if (blockstore and not overwrite) {
182 0 : log->warn(
183 : "Passed genesis block will be ignored without --overwrite_ledger "
184 : "flag. Restoring existing state.");
185 0 : } else {
186 0 : iroha::main::BlockLoader loader;
187 0 : auto file = loader.loadFile(FLAGS_genesis_block);
188 0 : auto block = loader.parseBlock(file.value());
189 :
190 0 : if (not block) {
191 0 : log->error("Failed to parse genesis block.");
192 0 : return EXIT_FAILURE;
193 : }
194 :
195 0 : if (not blockstore and overwrite) {
196 0 : log->warn(
197 : "Blockstore is empty - there is nothing to overwrite. Inserting "
198 : "new genesis block.");
199 0 : }
200 :
201 : // clear previous storage if any
202 0 : irohad.dropStorage();
203 : // reset ordering service persistent counter
204 0 : irohad.resetOrderingService();
205 :
206 0 : irohad.storage->insertBlock(*block.value());
207 0 : log->info("Genesis block inserted, number of transactions: {}",
208 0 : block.value()->transactions().size());
209 0 : }
210 0 : } else { // genesis block file is not specified
211 0 : if (not blockstore) {
212 0 : log->error(
213 : "Cannot restore nor create new state. Blockstore is empty. No "
214 : "genesis block is provided. Please pecify new genesis block using "
215 : "--genesis_block parameter.");
216 0 : return EXIT_FAILURE;
217 : } else {
218 0 : if (overwrite) {
219 0 : log->warn(
220 : "No new genesis block is specified - blockstore cannot be "
221 : "overwritten. If you want overwrite ledger state, please "
222 : "specify new genesis block using --genesis_block parameter.");
223 0 : }
224 : }
225 : }
226 :
227 : // check if at least one block is available in the ledger
228 0 : auto blocks_exist = irohad.storage->getBlockQuery()->getTopBlock().match(
229 : [](const auto &) { return true; },
230 : [](iroha::expected::Error<std::string> &) { return false; });
231 :
232 0 : if (not blocks_exist) { // may happen only in case of bug or zero disk space
233 0 : log->error(
234 : "You should have never seen this message. There are no blocks in the "
235 : "ledger. Unable to start. Try to specify --genesis_block and "
236 : "--overwrite_ledger parameters at the same time.");
237 0 : return EXIT_FAILURE;
238 : }
239 :
240 : // init pipeline components
241 0 : irohad.init();
242 :
243 : auto handler = [](int s) { exit_requested.set_value(); };
244 0 : std::signal(SIGINT, handler);
245 0 : std::signal(SIGTERM, handler);
246 0 : std::signal(SIGQUIT, handler);
247 :
248 : // runs iroha
249 0 : log->info("Running iroha");
250 0 : irohad.run();
251 0 : exit_requested.get_future().wait();
252 :
253 : // We do not care about shutting down grpc servers
254 : // They do all necessary work in their destructors
255 0 : log->info("shutting down...");
256 :
257 0 : return 0;
258 0 : }
|