LCOV - code coverage report
Current view: top level - irohad/ametsuchi/impl - postgres_wsv_command.cpp (source / functions) Hit Total Coverage
Test: coverage_cleared.info Lines: 118 218 54.1 %
Date: 2018-12-05 17:11:35 Functions: 29 57 50.9 %

          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/postgres_wsv_command.hpp"
       7             : 
       8             : #include <numeric>
       9             : 
      10             : #include <boost/format.hpp>
      11             : #include "backend/protobuf/permissions.hpp"
      12             : #include "cryptography/public_key.hpp"
      13             : #include "interfaces/common_objects/account.hpp"
      14             : #include "interfaces/common_objects/account_asset.hpp"
      15             : #include "interfaces/common_objects/asset.hpp"
      16             : #include "interfaces/common_objects/domain.hpp"
      17             : #include "interfaces/common_objects/peer.hpp"
      18             : 
      19             : namespace iroha {
      20             :   namespace ametsuchi {
      21             : 
      22             :     template <typename Function>
      23             :     WsvCommandResult execute(soci::statement &st, Function &&error) {
      24          27 :       st.define_and_bind();
      25             :       try {
      26          27 :         st.execute(true);
      27          25 :         return {};
      28           2 :       } catch (const std::exception &e) {
      29           2 :         return expected::makeError(error());
      30           2 :       }
      31          27 :     }
      32             : 
      33             :     PostgresWsvCommand::PostgresWsvCommand(soci::session &sql) : sql_(sql) {}
      34             : 
      35             :     WsvCommandResult PostgresWsvCommand::insertRole(
      36             :         const shared_model::interface::types::RoleIdType &role_name) {
      37          27 :       soci::statement st = sql_.prepare
      38          27 :           << "INSERT INTO role(role_id) VALUES (:role_id)";
      39          27 :       st.exchange(soci::use(role_name));
      40             :       auto msg = [&] {
      41          27 :         return (boost::format("failed to insert role: '%s'") % role_name).str();
      42           0 :       };
      43          27 :       return execute(st, msg);
      44          27 :     }
      45             : 
      46             :     WsvCommandResult PostgresWsvCommand::insertAccountRole(
      47             :         const shared_model::interface::types::AccountIdType &account_id,
      48             :         const shared_model::interface::types::RoleIdType &role_name) {
      49           6 :       soci::statement st = sql_.prepare
      50           6 :           << "INSERT INTO account_has_roles(account_id, role_id) VALUES "
      51             :              "(:account_id, :role_id)";
      52           6 :       st.exchange(soci::use(account_id));
      53           6 :       st.exchange(soci::use(role_name));
      54             : 
      55             :       auto msg = [&] {
      56           2 :         return (boost::format("failed to insert account role, account: '%s', "
      57             :                               "role name: '%s'")
      58           6 :                 % account_id % role_name)
      59           2 :             .str();
      60           0 :       };
      61           6 :       return execute(st, msg);
      62           6 :     }
      63             : 
      64             :     WsvCommandResult PostgresWsvCommand::deleteAccountRole(
      65             :         const shared_model::interface::types::AccountIdType &account_id,
      66             :         const shared_model::interface::types::RoleIdType &role_name) {
      67           3 :       soci::statement st = sql_.prepare
      68           3 :           << "DELETE FROM account_has_roles WHERE account_id=:account_id "
      69             :              "AND role_id=:role_id";
      70           3 :       st.exchange(soci::use(account_id));
      71           3 :       st.exchange(soci::use(role_name));
      72             : 
      73             :       auto msg = [&] {
      74           0 :         return (boost::format(
      75             :                     "failed to delete account role, account id: '%s', "
      76             :                     "role name: '%s'")
      77           3 :                 % account_id % role_name)
      78           0 :             .str();
      79           0 :       };
      80           3 :       return execute(st, msg);
      81           3 :     }
      82             : 
      83             :     WsvCommandResult PostgresWsvCommand::insertRolePermissions(
      84             :         const shared_model::interface::types::RoleIdType &role_id,
      85             :         const shared_model::interface::RolePermissionSet &permissions) {
      86           2 :       auto perm_str = permissions.toBitstring();
      87           2 :       soci::statement st = sql_.prepare
      88           2 :           << "INSERT INTO role_has_permissions(role_id, permission) VALUES "
      89             :              "(:id, :perm)";
      90           2 :       st.exchange(soci::use(role_id));
      91           2 :       st.exchange(soci::use(perm_str));
      92             : 
      93             :       auto msg = [&] {
      94           1 :         const auto &str =
      95           2 :             shared_model::proto::permissions::toString(permissions);
      96           1 :         std::string perm_debug_str = std::accumulate(
      97           1 :             str.begin(),
      98           1 :             str.end(),
      99           1 :             std::string(),
     100             :             [](auto acc, const auto &elem) { return acc + " " + elem; });
     101           1 :         return (boost::format("failed to insert role permissions, role "
     102             :                               "id: '%s', permissions: [%s]")
     103           2 :                 % role_id % perm_debug_str)
     104           1 :             .str();
     105           1 :       };
     106           2 :       return execute(st, msg);
     107           2 :     }
     108             : 
     109             :     WsvCommandResult PostgresWsvCommand::insertAccountGrantablePermission(
     110             :         const shared_model::interface::types::AccountIdType
     111             :             &permittee_account_id,
     112             :         const shared_model::interface::types::AccountIdType &account_id,
     113             :         shared_model::interface::permissions::Grantable permission) {
     114             :       const auto perm_str =
     115           3 :           shared_model::interface::GrantablePermissionSet({permission})
     116           3 :               .toBitstring();
     117           3 :       soci::statement st = sql_.prepare
     118           3 :           << "INSERT INTO account_has_grantable_permissions as "
     119             :              "has_perm(permittee_account_id, account_id, permission) VALUES "
     120             :              "(:permittee_account_id, :account_id, :perm) ON CONFLICT "
     121             :              "(permittee_account_id, account_id) DO UPDATE SET "
     122             :              // SELECT will end up with a error, if the permission exists
     123             :              "permission=(SELECT has_perm.permission | :perm WHERE "
     124             :              "(has_perm.permission & :perm) <> :perm);";
     125           3 :       st.exchange(soci::use(permittee_account_id, "permittee_account_id"));
     126           3 :       st.exchange(soci::use(account_id, "account_id"));
     127           3 :       st.exchange(soci::use(perm_str, "perm"));
     128             : 
     129             :       auto msg = [&] {
     130           2 :         return (boost::format("failed to insert account grantable permission, "
     131             :                               "permittee account id: '%s', "
     132             :                               "account id: '%s', "
     133             :                               "permission: '%s'")
     134           3 :                 % permittee_account_id
     135           3 :                 % account_id
     136             :                 // TODO(@l4l) 26/06/18 need to be simplified at IR-1479
     137           2 :                 % shared_model::proto::permissions::toString(permission))
     138           2 :             .str();
     139           0 :       };
     140           3 :       return execute(st, msg);
     141           3 :     }
     142             : 
     143             :     WsvCommandResult PostgresWsvCommand::deleteAccountGrantablePermission(
     144             :         const shared_model::interface::types::AccountIdType
     145             :             &permittee_account_id,
     146             :         const shared_model::interface::types::AccountIdType &account_id,
     147             :         shared_model::interface::permissions::Grantable permission) {
     148           1 :       const auto perm_str = shared_model::interface::GrantablePermissionSet()
     149           1 :                                 .set()
     150           1 :                                 .unset(permission)
     151           1 :                                 .toBitstring();
     152           1 :       soci::statement st = sql_.prepare
     153           1 :           << "UPDATE account_has_grantable_permissions as has_perm SET "
     154             :              // SELECT will end up with a error, if the permission doesn't
     155             :              // exists
     156             :              "permission=(SELECT has_perm.permission & :perm WHERE "
     157             :              "has_perm.permission & :perm = :perm) WHERE "
     158             :              "permittee_account_id=:permittee_account_id AND "
     159             :              "account_id=:account_id;";
     160             : 
     161           1 :       st.exchange(soci::use(permittee_account_id, "permittee_account_id"));
     162           1 :       st.exchange(soci::use(account_id, "account_id"));
     163           1 :       st.exchange(soci::use(perm_str, "perm"));
     164             : 
     165             :       auto msg = [&] {
     166           0 :         return (boost::format("failed to delete account grantable permission, "
     167             :                               "permittee account id: '%s', "
     168             :                               "account id: '%s', "
     169             :                               "permission id: '%s'")
     170           1 :                 % permittee_account_id % account_id
     171           0 :                 % shared_model::proto::permissions::toString(permission))
     172           0 :             .str();
     173           0 :       };
     174           1 :       return execute(st, msg);
     175           1 :     }
     176             : 
     177             :     WsvCommandResult PostgresWsvCommand::insertAccount(
     178             :         const shared_model::interface::Account &account) {
     179          23 :       soci::statement st = sql_.prepare
     180          23 :           << "INSERT INTO account(account_id, domain_id, quorum,"
     181             :              "data) VALUES (:id, :domain_id, :quorum, :data)";
     182          23 :       uint32_t quorum = account.quorum();
     183          23 :       st.exchange(soci::use(account.accountId()));
     184          23 :       st.exchange(soci::use(account.domainId()));
     185          23 :       st.exchange(soci::use(quorum));
     186          23 :       st.exchange(soci::use(account.jsonData()));
     187             : 
     188             :       auto msg = [&] {
     189           0 :         return (boost::format("failed to insert account, "
     190             :                               "account id: '%s', "
     191             :                               "domain id: '%s', "
     192             :                               "quorum: '%d', "
     193             :                               "json_data: %s")
     194          23 :                 % account.accountId() % account.domainId() % account.quorum()
     195           0 :                 % account.jsonData())
     196           0 :             .str();
     197           0 :       };
     198          23 :       return execute(st, msg);
     199          23 :     }
     200             : 
     201             :     WsvCommandResult PostgresWsvCommand::insertAsset(
     202             :         const shared_model::interface::Asset &asset) {
     203           0 :       auto precision = asset.precision();
     204           0 :       soci::statement st = sql_.prepare
     205           0 :           << "INSERT INTO asset(asset_id, domain_id, \"precision\", data) "
     206             :              "VALUES (:id, :domain_id, :precision, NULL)";
     207           0 :       st.exchange(soci::use(asset.assetId()));
     208           0 :       st.exchange(soci::use(asset.domainId()));
     209           0 :       st.exchange(soci::use(precision));
     210             : 
     211             :       auto msg = [&] {
     212           0 :         return (boost::format("failed to insert asset, asset id: '%s', "
     213             :                               "domain id: '%s', precision: %d")
     214           0 :                 % asset.assetId() % asset.domainId() % asset.precision())
     215           0 :             .str();
     216           0 :       };
     217           0 :       return execute(st, msg);
     218           0 :     }
     219             : 
     220             :     WsvCommandResult PostgresWsvCommand::upsertAccountAsset(
     221             :         const shared_model::interface::AccountAsset &asset) {
     222           0 :       auto balance = asset.balance().toStringRepr();
     223           0 :       soci::statement st = sql_.prepare
     224           0 :           << "INSERT INTO account_has_asset(account_id, asset_id, amount) "
     225             :              "VALUES (:account_id, :asset_id, :amount) ON CONFLICT "
     226             :              "(account_id, asset_id) DO UPDATE SET "
     227             :              "amount = EXCLUDED.amount";
     228             : 
     229           0 :       st.exchange(soci::use(asset.accountId()));
     230           0 :       st.exchange(soci::use(asset.assetId()));
     231           0 :       st.exchange(soci::use(balance));
     232             : 
     233             :       auto msg = [&] {
     234           0 :         return (boost::format("failed to upsert account, account id: '%s', "
     235             :                               "asset id: '%s', balance: %s")
     236           0 :                 % asset.accountId() % asset.assetId()
     237           0 :                 % asset.balance().toString())
     238           0 :             .str();
     239           0 :       };
     240           0 :       return execute(st, msg);
     241           0 :     }
     242             : 
     243             :     WsvCommandResult PostgresWsvCommand::insertSignatory(
     244             :         const shared_model::interface::types::PubkeyType &signatory) {
     245           0 :       soci::statement st = sql_.prepare
     246           0 :           << "INSERT INTO signatory(public_key) VALUES (:pk) ON CONFLICT DO "
     247             :              "NOTHING;";
     248           0 :       st.exchange(soci::use(signatory.hex()));
     249             : 
     250             :       auto msg = [&] {
     251           0 :         return (boost::format(
     252             :                     "failed to insert signatory, signatory hex string: '%s'")
     253           0 :                 % signatory.hex())
     254           0 :             .str();
     255           0 :       };
     256           0 :       return execute(st, msg);
     257           0 :     }
     258             : 
     259             :     WsvCommandResult PostgresWsvCommand::insertAccountSignatory(
     260             :         const shared_model::interface::types::AccountIdType &account_id,
     261             :         const shared_model::interface::types::PubkeyType &signatory) {
     262           0 :       soci::statement st = sql_.prepare
     263           0 :           << "INSERT INTO account_has_signatory(account_id, public_key) "
     264             :              "VALUES (:account_id, :pk)";
     265           0 :       st.exchange(soci::use(account_id));
     266           0 :       st.exchange(soci::use(signatory.hex()));
     267             : 
     268             :       auto msg = [&] {
     269           0 :         return (boost::format("failed to insert account signatory, account id: "
     270             :                               "'%s', signatory hex string: '%s")
     271           0 :                 % account_id % signatory.hex())
     272           0 :             .str();
     273           0 :       };
     274           0 :       return execute(st, msg);
     275           0 :     }
     276             : 
     277             :     WsvCommandResult PostgresWsvCommand::deleteAccountSignatory(
     278             :         const shared_model::interface::types::AccountIdType &account_id,
     279             :         const shared_model::interface::types::PubkeyType &signatory) {
     280           0 :       soci::statement st = sql_.prepare
     281           0 :           << "DELETE FROM account_has_signatory WHERE account_id = "
     282             :              ":account_id AND public_key = :pk";
     283           0 :       st.exchange(soci::use(account_id));
     284           0 :       st.exchange(soci::use(signatory.hex()));
     285             : 
     286             :       auto msg = [&] {
     287           0 :         return (boost::format("failed to delete account signatory, account id: "
     288             :                               "'%s', signatory hex string: '%s'")
     289           0 :                 % account_id % signatory.hex())
     290           0 :             .str();
     291           0 :       };
     292           0 :       return execute(st, msg);
     293           0 :     }
     294             : 
     295             :     WsvCommandResult PostgresWsvCommand::deleteSignatory(
     296             :         const shared_model::interface::types::PubkeyType &signatory) {
     297           0 :       soci::statement st = sql_.prepare
     298           0 :           << "DELETE FROM signatory WHERE public_key = :pk AND NOT EXISTS "
     299             :              "(SELECT 1 FROM account_has_signatory "
     300             :              "WHERE public_key = :pk) AND NOT EXISTS (SELECT 1 FROM peer "
     301             :              "WHERE public_key = :pk)";
     302           0 :       st.exchange(soci::use(signatory.hex(), "pk"));
     303             : 
     304             :       auto msg = [&] {
     305           0 :         return (boost::format(
     306             :                     "failed to delete signatory, signatory hex string: '%s'")
     307           0 :                 % signatory.hex())
     308           0 :             .str();
     309           0 :       };
     310           0 :       return execute(st, msg);
     311           0 :     }
     312             : 
     313             :     WsvCommandResult PostgresWsvCommand::insertPeer(
     314             :         const shared_model::interface::Peer &peer) {
     315           1 :       soci::statement st = sql_.prepare
     316           1 :           << "INSERT INTO peer(public_key, address) VALUES (:pk, :address)";
     317           1 :       st.exchange(soci::use(peer.pubkey().hex()));
     318           1 :       st.exchange(soci::use(peer.address()));
     319             : 
     320             :       auto msg = [&] {
     321           0 :         return (boost::format(
     322             :                     "failed to insert peer, public key: '%s', address: '%s'")
     323           1 :                 % peer.pubkey().hex() % peer.address())
     324           0 :             .str();
     325           0 :       };
     326           1 :       return execute(st, msg);
     327           1 :     }
     328             : 
     329             :     WsvCommandResult PostgresWsvCommand::deletePeer(
     330             :         const shared_model::interface::Peer &peer) {
     331           1 :       soci::statement st = sql_.prepare
     332           1 :           << "DELETE FROM peer WHERE public_key = :pk AND address = :address";
     333           1 :       st.exchange(soci::use(peer.pubkey().hex()));
     334           1 :       st.exchange(soci::use(peer.address()));
     335             : 
     336             :       auto msg = [&] {
     337           0 :         return (boost::format(
     338             :                     "failed to delete peer, public key: '%s', address: '%s'")
     339           1 :                 % peer.pubkey().hex() % peer.address())
     340           0 :             .str();
     341           0 :       };
     342           1 :       return execute(st, msg);
     343           1 :     }
     344             : 
     345             :     WsvCommandResult PostgresWsvCommand::insertDomain(
     346             :         const shared_model::interface::Domain &domain) {
     347          21 :       soci::statement st = sql_.prepare
     348          21 :           << "INSERT INTO domain(domain_id, default_role) VALUES (:id, "
     349             :              ":role)";
     350          21 :       st.exchange(soci::use(domain.domainId()));
     351          21 :       st.exchange(soci::use(domain.defaultRole()));
     352             : 
     353             :       auto msg = [&] {
     354           0 :         return (boost::format("failed to insert domain, domain id: '%s', "
     355             :                               "default role: '%s'")
     356          21 :                 % domain.domainId() % domain.defaultRole())
     357           0 :             .str();
     358           0 :       };
     359          21 :       return execute(st, msg);
     360          21 :     }
     361             : 
     362             :     WsvCommandResult PostgresWsvCommand::updateAccount(
     363             :         const shared_model::interface::Account &account) {
     364           0 :       soci::statement st = sql_.prepare
     365           0 :           << "UPDATE account SET quorum=:quorum WHERE account_id=:account_id";
     366           0 :       uint32_t quorum = account.quorum();
     367           0 :       st.exchange(soci::use(quorum));
     368           0 :       st.exchange(soci::use(account.accountId()));
     369             : 
     370             :       auto msg = [&] {
     371           0 :         return (boost::format(
     372             :                     "failed to update account, account id: '%s', quorum: '%s'")
     373           0 :                 % account.accountId() % account.quorum())
     374           0 :             .str();
     375           0 :       };
     376           0 :       return execute(st, msg);
     377           0 :     }
     378             : 
     379             :     WsvCommandResult PostgresWsvCommand::setAccountKV(
     380             :         const shared_model::interface::types::AccountIdType &account_id,
     381             :         const shared_model::interface::types::AccountIdType &creator_account_id,
     382             :         const std::string &key,
     383             :         const std::string &val) {
     384          13 :       soci::statement st = sql_.prepare
     385          13 :           << "UPDATE account SET data = jsonb_set("
     386             :              "CASE WHEN data ?:creator_account_id THEN data ELSE "
     387             :              "jsonb_set(data, :json, :empty_json) END, "
     388             :              " :filled_json, :val) WHERE account_id=:account_id";
     389          13 :       std::string json = "{" + creator_account_id + "}";
     390          13 :       std::string empty_json = "{}";
     391          13 :       std::string filled_json = "{" + creator_account_id + ", " + key + "}";
     392          13 :       std::string value = "\"" + val + "\"";
     393          13 :       st.exchange(soci::use(creator_account_id));
     394          13 :       st.exchange(soci::use(json));
     395          13 :       st.exchange(soci::use(empty_json));
     396          13 :       st.exchange(soci::use(filled_json));
     397          13 :       st.exchange(soci::use(value));
     398          13 :       st.exchange(soci::use(account_id));
     399             : 
     400             :       auto msg = [&] {
     401           0 :         return (boost::format(
     402             :                     "failed to set account key-value, account id: '%s', "
     403             :                     "creator account id: '%s',\n key: '%s', value: '%s'")
     404          13 :                 % account_id % creator_account_id % key % val)
     405           0 :             .str();
     406           0 :       };
     407             : 
     408          13 :       return execute(st, msg);
     409          13 :     }
     410             :   }  // namespace ametsuchi
     411             : }  // namespace iroha

Generated by: LCOV version 1.13