Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #include "ametsuchi/impl/storage_impl.hpp"
7 :
8 : #include <soci/postgresql/soci-postgresql.h>
9 : #include <boost/format.hpp>
10 : #include "ametsuchi/impl/flat_file/flat_file.hpp"
11 : #include "ametsuchi/impl/mutable_storage_impl.hpp"
12 : #include "ametsuchi/impl/peer_query_wsv.hpp"
13 : #include "ametsuchi/impl/postgres_block_index.hpp"
14 : #include "ametsuchi/impl/postgres_block_query.hpp"
15 : #include "ametsuchi/impl/postgres_command_executor.hpp"
16 : #include "ametsuchi/impl/postgres_query_executor.hpp"
17 : #include "ametsuchi/impl/postgres_wsv_query.hpp"
18 : #include "ametsuchi/impl/temporary_wsv_impl.hpp"
19 : #include "backend/protobuf/permissions.hpp"
20 : #include "common/bind.hpp"
21 : #include "common/byteutils.hpp"
22 : #include "converters/protobuf/json_proto_converter.hpp"
23 : #include "logger/logger.hpp"
24 : #include "logger/logger_manager.hpp"
25 :
26 : namespace {
27 : void prepareStatements(soci::connection_pool &connections, size_t pool_size) {
28 3135 : for (size_t i = 0; i != pool_size; i++) {
29 2850 : soci::session &session = connections.at(i);
30 2850 : iroha::ametsuchi::PostgresCommandExecutor::prepareStatements(session);
31 2850 : }
32 285 : }
33 :
34 : /**
35 : * Verify whether postgres supports prepared transactions
36 : */
37 : bool preparedTransactionsAvailable(soci::session &sql) {
38 285 : int prepared_txs_count = 0;
39 : try {
40 285 : sql << "SHOW max_prepared_transactions;", soci::into(prepared_txs_count);
41 285 : return prepared_txs_count != 0;
42 0 : } catch (std::exception &e) {
43 0 : return false;
44 0 : }
45 285 : }
46 :
47 : } // namespace
48 :
49 : namespace iroha {
50 : namespace ametsuchi {
51 : const char *kCommandExecutorError = "Cannot create CommandExecutorFactory";
52 : const char *kPsqlBroken = "Connection to PostgreSQL broken: %s";
53 : const char *kTmpWsv = "TemporaryWsv";
54 :
55 : ConnectionContext::ConnectionContext(
56 : std::unique_ptr<KeyValueStorage> block_store)
57 285 : : block_store(std::move(block_store)) {}
58 :
59 : StorageImpl::StorageImpl(
60 : std::string block_store_dir,
61 : PostgresOptions postgres_options,
62 : std::unique_ptr<KeyValueStorage> block_store,
63 : std::shared_ptr<soci::connection_pool> connection,
64 : std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory,
65 : std::shared_ptr<shared_model::interface::BlockJsonConverter> converter,
66 : std::shared_ptr<shared_model::interface::PermissionToString>
67 : perm_converter,
68 : size_t pool_size,
69 : bool enable_prepared_blocks,
70 : logger::LoggerManagerTreePtr log_manager)
71 285 : : block_store_dir_(std::move(block_store_dir)),
72 285 : postgres_options_(std::move(postgres_options)),
73 285 : block_store_(std::move(block_store)),
74 285 : connection_(std::move(connection)),
75 285 : factory_(std::move(factory)),
76 285 : converter_(std::move(converter)),
77 285 : perm_converter_(std::move(perm_converter)),
78 285 : log_manager_(std::move(log_manager)),
79 285 : log_(log_manager_->getLogger()),
80 285 : pool_size_(pool_size),
81 285 : prepared_blocks_enabled_(enable_prepared_blocks),
82 285 : block_is_prepared(false) {
83 285 : prepared_block_name_ =
84 285 : "prepared_block" + postgres_options_.dbname().value_or("");
85 285 : soci::session sql(*connection_);
86 : // rollback current prepared transaction
87 : // if there exists any since last session
88 285 : if (prepared_blocks_enabled_) {
89 285 : rollbackPrepared(sql);
90 285 : }
91 : try {
92 285 : sql << init_;
93 285 : prepareStatements(*connection_, pool_size_);
94 285 : } catch (std::exception &e) {
95 0 : log_->error("Storage was not initialized. Reason: {}", e.what());
96 0 : }
97 285 : }
98 :
99 : expected::Result<std::unique_ptr<TemporaryWsv>, std::string>
100 : StorageImpl::createTemporaryWsv() {
101 727 : std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
102 727 : if (connection_ == nullptr) {
103 0 : return expected::makeError("Connection was closed");
104 : }
105 727 : auto sql = std::make_unique<soci::session>(*connection_);
106 : // if we create temporary storage, then we intend to validate a new
107 : // proposal. this means that any state prepared before that moment is not
108 : // needed and must be removed to prevent locking
109 727 : if (block_is_prepared) {
110 1 : rollbackPrepared(*sql);
111 1 : }
112 :
113 727 : return expected::makeValue<std::unique_ptr<TemporaryWsv>>(
114 727 : std::make_unique<TemporaryWsvImpl>(
115 727 : std::move(sql),
116 727 : factory_,
117 727 : perm_converter_,
118 727 : log_manager_->getChild("TemporaryWorldStateView")));
119 727 : }
120 :
121 : expected::Result<std::unique_ptr<MutableStorage>, std::string>
122 : StorageImpl::createMutableStorage() {
123 554 : boost::optional<shared_model::interface::types::HashType> top_hash;
124 :
125 554 : std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
126 554 : if (connection_ == nullptr) {
127 4 : return expected::makeError("Connection was closed");
128 : }
129 :
130 550 : auto sql = std::make_unique<soci::session>(*connection_);
131 : // if we create mutable storage, then we intend to mutate wsv
132 : // this means that any state prepared before that moment is not needed
133 : // and must be removed to prevent locking
134 550 : if (block_is_prepared) {
135 2 : rollbackPrepared(*sql);
136 2 : }
137 550 : auto block_result = getBlockQuery()->getTopBlock();
138 550 : return expected::makeValue<std::unique_ptr<MutableStorage>>(
139 550 : std::make_unique<MutableStorageImpl>(
140 550 : block_result.match(
141 : [](expected::Value<
142 : std::shared_ptr<shared_model::interface::Block>> &block) {
143 20 : return block.value->hash();
144 : },
145 : [](expected::Error<std::string> &) {
146 530 : return shared_model::interface::types::HashType("");
147 0 : }),
148 550 : std::make_shared<PostgresCommandExecutor>(*sql, perm_converter_),
149 550 : std::move(sql),
150 550 : factory_,
151 550 : log_manager_->getChild("MutableStorageImpl")));
152 554 : }
153 :
154 : boost::optional<std::shared_ptr<PeerQuery>> StorageImpl::createPeerQuery()
155 : const {
156 4598 : auto wsv = getWsvQuery();
157 4598 : if (not wsv) {
158 317 : return boost::none;
159 : }
160 4281 : return boost::make_optional<std::shared_ptr<PeerQuery>>(
161 4281 : std::make_shared<PeerQueryWsv>(wsv));
162 4598 : }
163 :
164 : boost::optional<std::shared_ptr<BlockQuery>> StorageImpl::createBlockQuery()
165 : const {
166 1936 : auto block_query = getBlockQuery();
167 1936 : if (not block_query) {
168 0 : return boost::none;
169 : }
170 1936 : return boost::make_optional(block_query);
171 1936 : }
172 :
173 : boost::optional<std::shared_ptr<QueryExecutor>>
174 : StorageImpl::createQueryExecutor(
175 : std::shared_ptr<PendingTransactionStorage> pending_txs_storage,
176 : std::shared_ptr<shared_model::interface::QueryResponseFactory>
177 : response_factory) const {
178 192 : std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
179 192 : if (not connection_) {
180 0 : log_->info("connection to database is not initialised");
181 0 : return boost::none;
182 : }
183 192 : return boost::make_optional<std::shared_ptr<QueryExecutor>>(
184 192 : std::make_shared<PostgresQueryExecutor>(
185 190 : std::make_unique<soci::session>(*connection_),
186 192 : *block_store_,
187 192 : std::move(pending_txs_storage),
188 192 : converter_,
189 192 : std::move(response_factory),
190 192 : perm_converter_,
191 192 : log_manager_->getChild("QueryExecutor")));
192 192 : }
193 :
194 : bool StorageImpl::insertBlock(const shared_model::interface::Block &block) {
195 247 : log_->info("create mutable storage");
196 247 : auto storageResult = createMutableStorage();
197 247 : bool inserted = false;
198 247 : storageResult.match(
199 : [&](expected::Value<std::unique_ptr<ametsuchi::MutableStorage>>
200 : &storage) {
201 247 : inserted = storage.value->apply(block);
202 247 : log_->info("block inserted: {}", inserted);
203 247 : commit(std::move(storage.value));
204 247 : },
205 : [&](expected::Error<std::string> &error) {
206 0 : log_->error(error.error);
207 0 : });
208 :
209 247 : return inserted;
210 247 : }
211 :
212 : bool StorageImpl::insertBlocks(
213 : const std::vector<std::shared_ptr<shared_model::interface::Block>>
214 : &blocks) {
215 248 : log_->info("create mutable storage");
216 248 : bool inserted = true;
217 248 : auto storageResult = createMutableStorage();
218 248 : storageResult.match(
219 : [&](iroha::expected::Value<std::unique_ptr<MutableStorage>>
220 : &mutableStorage) {
221 : std::for_each(blocks.begin(), blocks.end(), [&](auto block) {
222 249 : inserted &= mutableStorage.value->apply(*block);
223 249 : });
224 248 : commit(std::move(mutableStorage.value));
225 248 : },
226 : [&](iroha::expected::Error<std::string> &error) {
227 0 : log_->error(error.error);
228 0 : inserted = false;
229 0 : });
230 :
231 248 : log_->info("insert blocks finished");
232 248 : return inserted;
233 248 : }
234 :
235 : void StorageImpl::reset() {
236 657 : log_->info("drop wsv records from db tables");
237 : try {
238 657 : soci::session sql(*connection_);
239 : // rollback possible prepared transaction
240 657 : if (block_is_prepared) {
241 2 : rollbackPrepared(sql);
242 2 : }
243 657 : sql << reset_;
244 657 : log_->info("drop blocks from disk");
245 657 : block_store_->dropAll();
246 657 : } catch (std::exception &e) {
247 0 : log_->warn("Drop wsv was failed. Reason: {}", e.what());
248 0 : }
249 657 : }
250 :
251 : void StorageImpl::dropStorage() {
252 294 : log_->info("drop storage");
253 294 : if (connection_ == nullptr) {
254 11 : log_->warn("Tried to drop storage without active connection");
255 11 : return;
256 : }
257 :
258 283 : if (auto dbname = postgres_options_.dbname()) {
259 283 : auto &db = dbname.value();
260 283 : std::unique_lock<std::shared_timed_mutex> lock(drop_mutex);
261 283 : log_->info("Drop database {}", db);
262 283 : freeConnections();
263 283 : soci::session sql(*soci::factory_postgresql(),
264 283 : postgres_options_.optionsStringWithoutDbName());
265 : // perform dropping
266 : try {
267 283 : sql << "DROP DATABASE " + db;
268 283 : } catch (std::exception &e) {
269 0 : log_->warn("Drop database was failed. Reason: {}", e.what());
270 0 : }
271 283 : } else {
272 0 : soci::session(*connection_) << drop_;
273 : }
274 :
275 : // erase blocks
276 283 : log_->info("drop block store");
277 283 : block_store_->dropAll();
278 294 : }
279 :
280 : void StorageImpl::freeConnections() {
281 568 : if (connection_ == nullptr) {
282 283 : log_->warn("Tried to free connections without active connection");
283 283 : return;
284 : }
285 : // rollback possible prepared transaction
286 285 : if (block_is_prepared) {
287 4 : soci::session sql(*connection_);
288 4 : rollbackPrepared(sql);
289 4 : }
290 285 : std::vector<std::shared_ptr<soci::session>> connections;
291 3135 : for (size_t i = 0; i < pool_size_; i++) {
292 2850 : connections.push_back(std::make_shared<soci::session>(*connection_));
293 2850 : connections[i]->close();
294 2850 : log_->debug("Closed connection {}", i);
295 2850 : }
296 285 : connections.clear();
297 285 : connection_.reset();
298 568 : }
299 :
300 : expected::Result<bool, std::string> StorageImpl::createDatabaseIfNotExist(
301 : const std::string &dbname,
302 : const std::string &options_str_without_dbname) {
303 : try {
304 286 : soci::session sql(*soci::factory_postgresql(),
305 286 : options_str_without_dbname);
306 :
307 : int size;
308 285 : std::string name = dbname;
309 :
310 285 : sql << "SELECT count(datname) FROM pg_catalog.pg_database WHERE "
311 285 : "datname = :dbname",
312 285 : soci::into(size), soci::use(name);
313 :
314 285 : if (size == 0) {
315 283 : std::string query = "CREATE DATABASE ";
316 283 : query += dbname;
317 283 : sql << query;
318 283 : return expected::makeValue(true);
319 283 : }
320 2 : return expected::makeValue(false);
321 285 : } catch (std::exception &e) {
322 1 : return expected::makeError<std::string>(
323 1 : std::string("Connection to PostgreSQL broken: ") + e.what());
324 1 : }
325 286 : }
326 :
327 : expected::Result<ConnectionContext, std::string>
328 : StorageImpl::initConnections(std::string block_store_dir,
329 : logger::LoggerPtr log) {
330 285 : log->info("Start storage creation");
331 :
332 285 : auto block_store = FlatFile::create(block_store_dir, log);
333 285 : if (not block_store) {
334 0 : return expected::makeError(
335 0 : (boost::format("Cannot create block store in %s") % block_store_dir)
336 0 : .str());
337 : }
338 285 : log->info("block store created");
339 :
340 285 : return expected::makeValue(ConnectionContext(std::move(*block_store)));
341 285 : }
342 :
343 : expected::Result<std::shared_ptr<soci::connection_pool>, std::string>
344 : StorageImpl::initPostgresConnection(std::string &options_str,
345 : size_t pool_size) {
346 285 : auto pool = std::make_shared<soci::connection_pool>(pool_size);
347 :
348 : try {
349 3135 : for (size_t i = 0; i != pool_size; i++) {
350 2850 : soci::session &session = pool->at(i);
351 2850 : session.open(*soci::factory_postgresql(), options_str);
352 2850 : }
353 285 : } catch (const std::exception &e) {
354 0 : return expected::makeError(e.what());
355 0 : }
356 285 : return expected::makeValue(pool);
357 285 : }
358 :
359 : expected::Result<std::shared_ptr<StorageImpl>, std::string>
360 : StorageImpl::create(
361 : std::string block_store_dir,
362 : std::string postgres_options,
363 : std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory,
364 : std::shared_ptr<shared_model::interface::BlockJsonConverter> converter,
365 : std::shared_ptr<shared_model::interface::PermissionToString>
366 : perm_converter,
367 : logger::LoggerManagerTreePtr log_manager,
368 : size_t pool_size) {
369 286 : boost::optional<std::string> string_res = boost::none;
370 :
371 286 : PostgresOptions options(postgres_options);
372 :
373 : // create database if
374 : options.dbname() | [&options, &string_res](const std::string &dbname) {
375 286 : createDatabaseIfNotExist(dbname, options.optionsStringWithoutDbName())
376 : .match([](expected::Value<bool> &val) {},
377 : [&string_res](expected::Error<std::string> &error) {
378 1 : string_res = error.error;
379 1 : });
380 286 : };
381 :
382 286 : if (string_res) {
383 1 : return expected::makeError(string_res.value());
384 : }
385 :
386 : auto ctx_result =
387 285 : initConnections(block_store_dir, log_manager->getLogger());
388 285 : auto db_result = initPostgresConnection(postgres_options, pool_size);
389 285 : expected::Result<std::shared_ptr<StorageImpl>, std::string> storage;
390 285 : ctx_result.match(
391 : [&](expected::Value<ConnectionContext> &ctx) {
392 285 : db_result.match(
393 : [&](expected::Value<std::shared_ptr<soci::connection_pool>>
394 : &connection) {
395 285 : soci::session sql(*connection.value);
396 285 : bool enable_prepared_transactions =
397 285 : preparedTransactionsAvailable(sql);
398 285 : storage = expected::makeValue(std::shared_ptr<StorageImpl>(
399 285 : new StorageImpl(block_store_dir,
400 285 : options,
401 285 : std::move(ctx.value.block_store),
402 285 : connection.value,
403 285 : factory,
404 285 : converter,
405 285 : perm_converter,
406 285 : pool_size,
407 285 : enable_prepared_transactions,
408 285 : std::move(log_manager))));
409 285 : },
410 : [&](expected::Error<std::string> &error) { storage = error; });
411 285 : },
412 : [&](expected::Error<std::string> &error) { storage = error; });
413 285 : return storage;
414 286 : }
415 :
416 : boost::optional<std::unique_ptr<LedgerState>> StorageImpl::commit(
417 : std::unique_ptr<MutableStorage> mutableStorage) {
418 546 : auto storage_ptr = std::move(mutableStorage); // get ownership of storage
419 546 : auto storage = static_cast<MutableStorageImpl *>(storage_ptr.get());
420 1095 : for (const auto &block : storage->block_store_) {
421 549 : storeBlock(*block.second);
422 : }
423 : try {
424 546 : *(storage->sql_) << "COMMIT";
425 546 : storage->committed = true;
426 546 : return PostgresWsvQuery(*(storage->sql_),
427 546 : factory_,
428 546 : log_manager_->getChild("WsvQuery")->getLogger())
429 546 : .getPeers()
430 546 : |
431 : [](auto &&peers) {
432 546 : return boost::optional<std::unique_ptr<LedgerState>>(
433 546 : std::make_unique<LedgerState>(
434 546 : std::make_shared<PeerList>(std::move(peers))));
435 0 : };
436 0 : } catch (std::exception &e) {
437 0 : storage->committed = false;
438 0 : log_->warn("Mutable storage is not committed. Reason: {}", e.what());
439 0 : return boost::none;
440 0 : }
441 546 : }
442 :
443 : boost::optional<std::unique_ptr<LedgerState>> StorageImpl::commitPrepared(
444 : const shared_model::interface::Block &block) {
445 723 : if (not prepared_blocks_enabled_) {
446 0 : log_->warn("prepared blocks are not enabled");
447 0 : return boost::none;
448 : }
449 :
450 723 : if (not block_is_prepared) {
451 4 : log_->info("there are no prepared blocks");
452 4 : return boost::none;
453 : }
454 719 : log_->info("applying prepared block");
455 :
456 : try {
457 719 : std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
458 719 : if (not connection_) {
459 1 : log_->info("connection to database is not initialised");
460 1 : return boost::none;
461 : }
462 718 : soci::session sql(*connection_);
463 718 : sql << "COMMIT PREPARED '" + prepared_block_name_ + "';";
464 718 : PostgresBlockIndex block_index(
465 718 : sql, log_manager_->getChild("BlockIndex")->getLogger());
466 718 : block_index.index(block);
467 718 : block_is_prepared = false;
468 718 : return PostgresWsvQuery(sql,
469 718 : factory_,
470 718 : log_manager_->getChild("WsvQuery")->getLogger())
471 718 : .getPeers()
472 : | [this, &block](auto &&peers)
473 : -> boost::optional<std::unique_ptr<LedgerState>> {
474 718 : if (this->storeBlock(block)) {
475 718 : return boost::optional<std::unique_ptr<LedgerState>>(
476 718 : std::make_unique<LedgerState>(
477 718 : std::make_shared<PeerList>(std::move(peers))));
478 : }
479 0 : return boost::none;
480 718 : };
481 719 : } catch (const std::exception &e) {
482 0 : log_->warn("failed to apply prepared block {}: {}",
483 0 : block.hash().hex(),
484 0 : e.what());
485 0 : return boost::none;
486 0 : }
487 723 : }
488 :
489 : std::shared_ptr<WsvQuery> StorageImpl::getWsvQuery() const {
490 4602 : std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
491 4602 : if (not connection_) {
492 317 : log_->info("connection to database is not initialised");
493 317 : return nullptr;
494 : }
495 4285 : return std::make_shared<PostgresWsvQuery>(
496 4285 : std::make_unique<soci::session>(*connection_),
497 4285 : factory_,
498 4285 : log_manager_->getChild("WsvQuery")->getLogger());
499 4602 : }
500 :
501 : std::shared_ptr<BlockQuery> StorageImpl::getBlockQuery() const {
502 8152 : std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
503 8152 : if (not connection_) {
504 86 : log_->info("connection to database is not initialised");
505 86 : return nullptr;
506 : }
507 8064 : return std::make_shared<PostgresBlockQuery>(
508 8006 : std::make_unique<soci::session>(*connection_),
509 8067 : *block_store_,
510 8053 : converter_,
511 8053 : log_manager_->getChild("PostgresBlockQuery")->getLogger());
512 8138 : }
513 :
514 : rxcpp::observable<std::shared_ptr<shared_model::interface::Block>>
515 : StorageImpl::on_commit() {
516 249 : return notifier_.get_observable();
517 0 : }
518 :
519 : void StorageImpl::prepareBlock(std::unique_ptr<TemporaryWsv> wsv) {
520 727 : auto &wsv_impl = static_cast<TemporaryWsvImpl &>(*wsv);
521 727 : if (not prepared_blocks_enabled_) {
522 0 : log_->warn("prepared block are not enabled");
523 0 : return;
524 : }
525 727 : if (not block_is_prepared) {
526 727 : soci::session &sql = *wsv_impl.sql_;
527 : try {
528 727 : sql << "PREPARE TRANSACTION '" + prepared_block_name_ + "';";
529 727 : block_is_prepared = true;
530 727 : } catch (const std::exception &e) {
531 0 : log_->warn("failed to prepare state: {}", e.what());
532 0 : }
533 :
534 727 : log_->info("state prepared successfully");
535 727 : }
536 727 : }
537 :
538 : StorageImpl::~StorageImpl() {
539 285 : freeConnections();
540 285 : }
541 :
542 : void StorageImpl::rollbackPrepared(soci::session &sql) {
543 : try {
544 294 : sql << "ROLLBACK PREPARED '" + prepared_block_name_ + "';";
545 9 : block_is_prepared = false;
546 285 : } catch (const std::exception &e) {
547 285 : log_->info(e.what());
548 285 : }
549 294 : }
550 :
551 : bool StorageImpl::storeBlock(const shared_model::interface::Block &block) {
552 1267 : auto json_result = converter_->serialize(block);
553 1267 : return json_result.match(
554 : [this, &block](const expected::Value<std::string> &v) {
555 1267 : block_store_->add(block.height(), stringToBytes(v.value));
556 1267 : notifier_.get_subscriber().on_next(clone(block));
557 1267 : return true;
558 0 : },
559 : [this](const expected::Error<std::string> &e) {
560 0 : log_->error(e.error);
561 0 : return false;
562 : });
563 1267 : }
564 :
565 : const std::string &StorageImpl::drop_ = R"(
566 : DROP TABLE IF EXISTS account_has_signatory;
567 : DROP TABLE IF EXISTS account_has_asset;
568 : DROP TABLE IF EXISTS role_has_permissions CASCADE;
569 : DROP TABLE IF EXISTS account_has_roles;
570 : DROP TABLE IF EXISTS account_has_grantable_permissions CASCADE;
571 : DROP TABLE IF EXISTS account;
572 : DROP TABLE IF EXISTS asset;
573 : DROP TABLE IF EXISTS domain;
574 : DROP TABLE IF EXISTS signatory;
575 : DROP TABLE IF EXISTS peer;
576 : DROP TABLE IF EXISTS role;
577 : DROP TABLE IF EXISTS height_by_hash;
578 : DROP INDEX IF EXISTS tx_status_by_hash_hash_index;
579 : DROP TABLE IF EXISTS tx_status_by_hash;
580 : DROP TABLE IF EXISTS height_by_account_set;
581 : DROP TABLE IF EXISTS index_by_creator_height;
582 : DROP TABLE IF EXISTS position_by_account_asset;
583 : )";
584 :
585 : const std::string &StorageImpl::reset_ = R"(
586 : DELETE FROM account_has_signatory;
587 : DELETE FROM account_has_asset;
588 : DELETE FROM role_has_permissions CASCADE;
589 : DELETE FROM account_has_roles;
590 : DELETE FROM account_has_grantable_permissions CASCADE;
591 : DELETE FROM account;
592 : DELETE FROM asset;
593 : DELETE FROM domain;
594 : DELETE FROM signatory;
595 : DELETE FROM peer;
596 : DELETE FROM role;
597 : DELETE FROM position_by_hash;
598 : DELETE FROM tx_status_by_hash;
599 : DELETE FROM height_by_account_set;
600 : DELETE FROM index_by_creator_height;
601 : DELETE FROM position_by_account_asset;
602 : )";
603 :
604 : const std::string &StorageImpl::init_ =
605 41 : R"(
606 : CREATE TABLE IF NOT EXISTS role (
607 : role_id character varying(32),
608 : PRIMARY KEY (role_id)
609 : );
610 : CREATE TABLE IF NOT EXISTS domain (
611 : domain_id character varying(255),
612 : default_role character varying(32) NOT NULL REFERENCES role(role_id),
613 : PRIMARY KEY (domain_id)
614 : );
615 : CREATE TABLE IF NOT EXISTS signatory (
616 : public_key varchar NOT NULL,
617 : PRIMARY KEY (public_key)
618 : );
619 : CREATE TABLE IF NOT EXISTS account (
620 : account_id character varying(288),
621 : domain_id character varying(255) NOT NULL REFERENCES domain,
622 : quorum int NOT NULL,
623 : data JSONB,
624 : PRIMARY KEY (account_id)
625 : );
626 : CREATE TABLE IF NOT EXISTS account_has_signatory (
627 : account_id character varying(288) NOT NULL REFERENCES account,
628 : public_key varchar NOT NULL REFERENCES signatory,
629 : PRIMARY KEY (account_id, public_key)
630 : );
631 : CREATE TABLE IF NOT EXISTS peer (
632 : public_key varchar NOT NULL,
633 : address character varying(261) NOT NULL UNIQUE,
634 : PRIMARY KEY (public_key)
635 : );
636 : CREATE TABLE IF NOT EXISTS asset (
637 : asset_id character varying(288),
638 : domain_id character varying(255) NOT NULL REFERENCES domain,
639 : precision int NOT NULL,
640 : data json,
641 : PRIMARY KEY (asset_id)
642 : );
643 : CREATE TABLE IF NOT EXISTS account_has_asset (
644 : account_id character varying(288) NOT NULL REFERENCES account,
645 : asset_id character varying(288) NOT NULL REFERENCES asset,
646 : amount decimal NOT NULL,
647 : PRIMARY KEY (account_id, asset_id)
648 : );
649 : CREATE TABLE IF NOT EXISTS role_has_permissions (
650 : role_id character varying(32) NOT NULL REFERENCES role,
651 : permission bit()"
652 41 : + std::to_string(shared_model::interface::RolePermissionSet::size())
653 41 : + R"() NOT NULL,
654 : PRIMARY KEY (role_id)
655 : );
656 : CREATE TABLE IF NOT EXISTS account_has_roles (
657 : account_id character varying(288) NOT NULL REFERENCES account,
658 : role_id character varying(32) NOT NULL REFERENCES role,
659 : PRIMARY KEY (account_id, role_id)
660 : );
661 : CREATE TABLE IF NOT EXISTS account_has_grantable_permissions (
662 : permittee_account_id character varying(288) NOT NULL REFERENCES account,
663 : account_id character varying(288) NOT NULL REFERENCES account,
664 : permission bit()"
665 41 : + std::to_string(
666 41 : shared_model::interface::GrantablePermissionSet::size())
667 41 : + R"() NOT NULL,
668 : PRIMARY KEY (permittee_account_id, account_id)
669 : );
670 : CREATE TABLE IF NOT EXISTS position_by_hash (
671 : hash varchar,
672 : height text,
673 : index text
674 : );
675 :
676 : CREATE TABLE IF NOT EXISTS tx_status_by_hash (
677 : hash varchar,
678 : status boolean
679 : );
680 : CREATE INDEX IF NOT EXISTS tx_status_by_hash_hash_index ON tx_status_by_hash USING hash (hash);
681 :
682 : CREATE TABLE IF NOT EXISTS height_by_account_set (
683 : account_id text,
684 : height text
685 : );
686 : CREATE TABLE IF NOT EXISTS index_by_creator_height (
687 : id serial,
688 : creator_id text,
689 : height text,
690 : index text
691 : );
692 : CREATE TABLE IF NOT EXISTS position_by_account_asset (
693 : account_id text,
694 : asset_id text,
695 : height text,
696 : index text
697 : );
698 : )";
699 : } // namespace ametsuchi
700 : } // namespace iroha
|