diff --git a/.github/TESTS_ALLOWED_TO_FAIL b/.github/TESTS_ALLOWED_TO_FAIL index ef466b3fc03..a67e6a18cb4 100644 --- a/.github/TESTS_ALLOWED_TO_FAIL +++ b/.github/TESTS_ALLOWED_TO_FAIL @@ -1 +1,4 @@ system_irohad_test +integration_add_peer_test +regression_regression_test +integration_remove_peer_test diff --git a/README.md b/README.md index be3d92d055a..5152b70698b 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ It is based on JS Wallet but is up-to-date. [Iroha Explorer](https://codeberg.org/diva.exchange/iroha-explorer) [Iroha Docker container with Postgres 10](https://hub.docker.com/r/divax/iroha) and it's [source code](https://codeberg.org/diva.exchange/iroha) +[Tool to deploy Iroha instances](https://github.com/kuvaldini/iroha-swarm) ### Want to help us develop Iroha? diff --git a/docs/source/build/index.rst b/docs/source/build/index.rst index 0ef4119fe25..9666db84bca 100644 --- a/docs/source/build/index.rst +++ b/docs/source/build/index.rst @@ -263,13 +263,13 @@ The cmake parameters such as ``-DUSE_BURROW=ON`` are exactly the parameters you .. code-block:: shell - cmake --build . --target irohad + cmake --build ./build --target irohad .. warning:: If you want to use tests later, instead of building `irohad` target, you need to use this: .. code-block:: shell - cmake --build . --target all + cmake --build ./build --target all 3. Check the result by running the help: diff --git a/docs/source/configure/db.rst b/docs/source/configure/db.rst new file mode 100644 index 00000000000..fb1345eb6f6 --- /dev/null +++ b/docs/source/configure/db.rst @@ -0,0 +1,25 @@ +====================== +PostgreSQL vs. RocksDB +====================== + +When you use Iroha, you have a choice of building and using it with either PostgreSQL (relational database) or RocksDB (key-value). + +Both options are reliable and can be used in production environment but there are some key differences we would like to tell you about that might help you make your choice. + +Specific features of PostgreSQL: +******************************** + +- Classic database option -- which means that there are many tools to work with it; +- When Iroha is working in Docker, PostgreSQL runs in a separate container; +- With a lot of data PostgreSQL might become slower + +.. tip:: You can learn more about this database in its documentation: https://www.postgresql.org/docs/ + +Specific features of RocksDB: +***************************** + +- Fast (see `performance testing results `_); +- RocksDB is embedded -- both WSV and blockstore are in the same database which means more consistency, but there is a possibility of manually adding a hash with access to the database which might cause some security-related concerns; +- Takes less space on the disk and there is no information that it could grow too big + +.. tip:: You can learn more about this database in its documentation: https://rocksdb.org/docs/getting-started.html diff --git a/docs/source/configure/index.rst b/docs/source/configure/index.rst old mode 100755 new mode 100644 index ee653aa2046..7b471648c4b --- a/docs/source/configure/index.rst +++ b/docs/source/configure/index.rst @@ -8,6 +8,7 @@ Configure :maxdepth: 1 torii-tls.rst + db.rst In this section we will understand how to configure Iroha. Some configuration parameters must be the same in all the nodes (they are marked with \*) and some can differ. @@ -43,10 +44,11 @@ Deployment-specific parameters - ``utility_service`` (optional) endpoint for maintenance tasks. If present, must include ``ip`` address and ``port`` to bind to. See `shepherd docs <../maintenance/shepherd.html>`_ for an example usage of maintenance endpoint. -- ``metrics`` (optional) endpoint to monitor iroha's metrics. Prometheus HTTP server listens on this endpoint. +- ``metrics`` (optional) endpoint to monitor Iroha's metrics. Prometheus HTTP server listens on this endpoint. If present, must correspond format "[addr]:" and could be for example "127.0.0.1:8080", "9090", or ":1234". Wrong values implicitly disables Prometheus metrics server. There are also cmdline options ```--metrics_port`` and ``--metrics_addr`` to override this parameter. +- ``healthcheck_port`` (optional) endpoint for Iroha healthcheck. Sending a request to this endpoint in the form of ``http://:/healthcheck`` will return you information about the status of the node: current memory consumption (``memory_consumption``), current number of blocks (``last_block_round``), current count of reject rounds (``last_reject_round``), if the node is syncing information with a remote node at the moment (``is_syncing``), if the node is currently up (``status``). There is also an optional ``torii_tls_params`` parameter, which could be included in the config to enable TLS support for client communication. @@ -85,13 +87,7 @@ Environment-specific parameters ``10``. However, we recommend to increase this number if you have a lot of transactions per second. - **This parameter affects performance.** Increase this parameter, if your network has a big number of transactions going. If you increase ``max_proposal_size`` due to an inreased throughput, you can increase it independently. But if the speed stays approximately the same, you need to also increase ``proposal_delay`` to allow all these transactions to get into this one big proposal. By increasing this parameter you can improve the performance but note that at some point increasing this value can lead to degradation of the performance. - - -- ``proposal_delay`` is a timeout in milliseconds that a peer waits a response - from the orderding service with a proposal. **Important: proposal_delay must be bigger than proposal_creation_timeout. Not following this rule will lead to unstable system.** - - **This parameter affects performance.** If you want bigger proposal size, you will need to give the system time to collect this increased number of transactions into one proposal. + **This parameter affects performance.** Increase this parameter, if your network has a big number of transactions going. If you increase ``max_proposal_size`` due to an inreased throughput, you can increase it independently. By increasing this parameter you can improve the performance but note that at some point increasing this value can lead to degradation of the performance. - ``vote_delay`` \* is a waiting time in milliseconds before sending vote to the next peer. Optimal value depends heavily on the amount of Iroha peers in the @@ -121,7 +117,6 @@ Environment-specific parameters long idle time. This parameter allows users to find an optimal value in a tradeoff between resource consumption and the delay of getting back to work after an idle - period. **Important: proposal_delay must be bigger than proposal_creation_timeout. Not following this rule will lead to unstable system.** **This parameter affects resource consumption.** When you can expect Iroha to stay idle for longer periods of time and would like to save some resources, increase this value - it will make Iroha check for new transactions more rarely. NB: the first transaction after idle period might be a little delayed due to that. Second and further blocks will be processed quicker. @@ -163,7 +158,6 @@ Here is the configuration we used: .. code-block:: javascript "max_proposal_size" : 10000, - "proposal_delay" : 1000, "vote_delay" : 1000, "mst_enable" : true, "mst_expiration_time": 1440, @@ -190,7 +184,6 @@ Unix export IROHA_INTERNAL_PORT=10001 export IROHA_PG_OPT="host=172.19.0.2 port=5432 user=iroha password=helloworld" export IROHA_MAX_PROPOSAL_SIZE=10 - export IROHA_PROPOSAL_DELAY=5000 export IROHA_VOTE_DELAY=5000 export IROHA_MST_ENABLE=false export IROHA_MST_EXPIRATION_TIME=1440 diff --git a/docs/source/deploy/multiple.rst b/docs/source/deploy/multiple.rst index 2ba1395d333..ac60d21c319 100644 --- a/docs/source/deploy/multiple.rst +++ b/docs/source/deploy/multiple.rst @@ -16,4 +16,7 @@ In order to form a block, which includes more than a single peer, or requires cu Automated --------- -Follow `this guide `__ \ No newline at end of file +Here is a `community provided tool `_ to easily deploy Iroha instances. + + +Here is also `a guide `__ that might be outdated but could provide some helpful information. \ No newline at end of file diff --git a/docs/source/maintenance/index.rst b/docs/source/maintenance/index.rst index 18c2c23bd18..20c6703d8d9 100644 --- a/docs/source/maintenance/index.rst +++ b/docs/source/maintenance/index.rst @@ -15,4 +15,5 @@ Hardware requirements, deployment process in details, aspects related to securit troubleshooting.rst metrics.rst migration-rocksdb.rst - \ No newline at end of file + migration-practice.rst + diff --git a/docs/source/maintenance/migration-practice.rst b/docs/source/maintenance/migration-practice.rst new file mode 100644 index 00000000000..d2b6c16ff43 --- /dev/null +++ b/docs/source/maintenance/migration-practice.rst @@ -0,0 +1,21 @@ +======================== +Good Migration Practices +======================== + +Iroha maintainers often receive questions about the best ways to migrate projects to new versions of Iroha, so we decided to share our practices that worked the best for us and our projects. + +**On an example of a 4 peer network we will go through a migration procedure (also moving from PostgeSQL database to RocksDB) that turned out to be the most stable and reliable in our projects.** + +Here are the steps: +******************* + +1. You have the 4 nodes running Iroha with the old version on Postgres +2. Follow the instructions on `Iroha Database migration `_. Copy the RocksDB folder. *Skip this step if you do not need to switch between Postgres and RocksDB* +3. Add a new peer running the new version of Iroha using the `Add Peer command `_ and with the RocksDB folder on it. +4. Add similar nodes 2 more times +5. Now you have 7 nodes -- 4 running the old version and 3 running the new one +6. Switch off the first node with the old version and update this node with the same key pair to the new version (with RocksDB, if that is your goal) +7. Repeat this for every node with the old Iroha version +8. Now you can remove the "new" nodes and continue the work on your project! + + \ No newline at end of file diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt index adbcaaeabaa..7768f40a7fd 100644 --- a/docs/source/requirements.txt +++ b/docs/source/requirements.txt @@ -8,7 +8,7 @@ docopt==0.6.2 docutils==0.14 idna==2.6 imagesize==0.7.1 -Jinja2==2.11.3 +Jinja2 livereload==2.5.1 MarkupSafe pathtools==0.1.2 diff --git a/example/config-win.sample b/example/config-win.sample index 8a4d3ab0e0b..9fd417f81f4 100644 --- a/example/config-win.sample +++ b/example/config-win.sample @@ -4,7 +4,6 @@ "internal_port" : 10001, "pg_opt" : "host=localhost port=5432 user=postgres password=mysecretpassword", "max_proposal_size" : 10, - "proposal_delay" : 5000, "vote_delay" : 5000, "mst_enable" : false, "mst_expiration_time" : 1440 diff --git a/example/config.docker b/example/config.docker index 8be860ddc7e..181ab1fa785 100644 --- a/example/config.docker +++ b/example/config.docker @@ -12,7 +12,6 @@ "maintenance database": "postgres" }, "max_proposal_size" : 10, - "proposal_delay" : 5000, "vote_delay" : 5000, "mst_enable" : false, "mst_expiration_time" : 1440, diff --git a/example/config.postgres.sample b/example/config.postgres.sample index 0ffd91cdbb8..c04c8a8d449 100644 --- a/example/config.postgres.sample +++ b/example/config.postgres.sample @@ -12,7 +12,6 @@ "maintenance database": "postgres" }, "max_proposal_size" : 10, - "proposal_delay" : 5000, "vote_delay" : 5000, "mst_enable" : false, "mst_expiration_time" : 1440, diff --git a/example/config.sample b/example/config.sample index e9e4f50d327..7e4ee6661b3 100644 --- a/example/config.sample +++ b/example/config.sample @@ -6,7 +6,6 @@ "path": "/path/to/wsv/folder" }, "max_proposal_size": 10, - "proposal_delay": 5000, "vote_delay": 5000, "mst_enable": false, "mst_expiration_time": 1440, diff --git a/irohad/CMakeLists.txt b/irohad/CMakeLists.txt index 483fd893999..a18c405ed34 100644 --- a/irohad/CMakeLists.txt +++ b/irohad/CMakeLists.txt @@ -13,7 +13,6 @@ add_subdirectory(network) add_subdirectory(model) add_subdirectory(simulator) add_subdirectory(synchronizer) -add_subdirectory(multi_sig_transactions) add_subdirectory(pending_txs_storage) add_subdirectory(util) add_subdirectory(maintenance) diff --git a/irohad/ametsuchi/CMakeLists.txt b/irohad/ametsuchi/CMakeLists.txt index bee6e31d2c1..7626d703512 100644 --- a/irohad/ametsuchi/CMakeLists.txt +++ b/irohad/ametsuchi/CMakeLists.txt @@ -185,15 +185,31 @@ target_link_libraries(rocksdb_indexer RocksDB::rocksdb ) +add_library(common_burrow_storage + impl/burrow_storage.cpp + ) +target_link_libraries(common_burrow_storage + common + ) + +add_library(rocksdb_burrow_storage + impl/rocksdb_burrow_storage.cpp + ) +target_link_libraries(rocksdb_burrow_storage + common_burrow_storage + RocksDB::rocksdb + ) + target_compile_definitions(postgres_indexer PRIVATE SOCI_USE_BOOST HAVE_BOOST ) add_library(postgres_burrow_storage - impl/burrow_storage.cpp impl/postgres_burrow_storage.cpp ) -target_link_libraries(postgres_burrow_storage common) +target_link_libraries(postgres_burrow_storage + common_burrow_storage + ) add_library(default_vm_call INTERFACE) if(USE_BURROW) @@ -222,6 +238,7 @@ target_link_libraries(ametsuchi libs_files common postgres_burrow_storage + rocksdb_burrow_storage postgres_options shared_model_interfaces shared_model_plain_backend diff --git a/irohad/ametsuchi/impl/postgres_specific_query_executor.cpp b/irohad/ametsuchi/impl/postgres_specific_query_executor.cpp index 87105ddc92c..7e9dd3baab8 100644 --- a/irohad/ametsuchi/impl/postgres_specific_query_executor.cpp +++ b/irohad/ametsuchi/impl/postgres_specific_query_executor.cpp @@ -1498,7 +1498,7 @@ namespace iroha { for (const auto &row : range) { iroha::ametsuchi::apply( row, - [this, &peers]( + [&peers]( auto &peer_key, auto &address, auto &tls_certificate) { if (peer_key and address) { peers.push_back( diff --git a/irohad/ametsuchi/impl/rocksdb_burrow_storage.cpp b/irohad/ametsuchi/impl/rocksdb_burrow_storage.cpp new file mode 100644 index 00000000000..2fec2c4b408 --- /dev/null +++ b/irohad/ametsuchi/impl/rocksdb_burrow_storage.cpp @@ -0,0 +1,165 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ametsuchi/impl/rocksdb_burrow_storage.hpp" + +#include +#include + +#include "ametsuchi/impl/rocksdb_common.hpp" +#include "common/obj_utils.hpp" +#include "common/result.hpp" +#include "common/to_lower.hpp" + +using namespace iroha::ametsuchi; +using namespace iroha::expected; + +#define MAKE_LOWER_ON_STACK(name, source, sz) \ + static_assert(sz > 0ull, "Unexpected size " #sz); \ + assert(source.size() <= sz); \ + char name##_buffer[sz]; \ + auto name = toLower(source, name##_buffer); + +RocksdbBurrowStorage::RocksdbBurrowStorage( + RocksDbCommon &common, + std::string_view tx_hash, + shared_model::interface::types::CommandIndexType cmd_index) + : common_(common), tx_hash_(tx_hash), cmd_index_(cmd_index) {} + +Result, std::string> +RocksdbBurrowStorage::getAccount(std::string_view address) { + MAKE_LOWER_ON_STACK(address_lc, address, 128); + RDB_TRY_GET_VALUE_OR_STR_ERR( + opt_data, + forCallEngineAccount( + common_, address_lc)); + if (opt_data) + return expected::makeValue(std::string(opt_data->data(), opt_data->size())); + + return std::nullopt; +} + +Result RocksdbBurrowStorage::updateAccount( + std::string_view address, std::string_view account) { + MAKE_LOWER_ON_STACK(address_lc, address, 128); + common_.valueBuffer().assign(account.data(), account.size()); + RDB_ERROR_CHECK_TO_STR( + forCallEngineAccount(common_, address_lc)); + return {}; +} + +Result RocksdbBurrowStorage::removeAccount( + std::string_view address) { + MAKE_LOWER_ON_STACK(address_lc, address, 128); + RDB_ERROR_CHECK_TO_STR( + forCallEngineAccount( + common_, address_lc)); + + auto const &[_, status] = + common_.filterDelete(std::numeric_limits::max(), + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineStorage, + address_lc); + + if (!status.ok() && !status.IsNotFound()) + return expected::makeError(fmt::format( + "Delete CallEngine storage with address '{}' failed.", address_lc)); + + return {}; +} + +Result, std::string> +RocksdbBurrowStorage::getStorage(std::string_view address, + std::string_view key) { + MAKE_LOWER_ON_STACK(address_lc, address, 128); + + std::string key_lc; + toLowerAppend(key, key_lc); + + RDB_TRY_GET_VALUE_OR_STR_ERR( + opt_value, + forCallEngineStorage( + common_, address_lc, key_lc)); + if (opt_value) + return expected::makeValue( + std::string(opt_value->data(), opt_value->size())); + + return std::nullopt; +} + +Result RocksdbBurrowStorage::setStorage( + std::string_view address, std::string_view key, std::string_view value) { + MAKE_LOWER_ON_STACK(address_lc, address, 128); + + std::string key_lc; + toLowerAppend(key, key_lc); + + common_.valueBuffer().assign(value.data(), value.size()); + RDB_ERROR_CHECK_TO_STR( + forCallEngineStorage(common_, address_lc, key_lc)); + return {}; +} + +Result RocksdbBurrowStorage::initCallId() { + if (!call_id_cache_) { + RDB_ERROR_CHECK_TO_STR( + forCallEngineCallIds( + common_, tx_hash_, cmd_index_)); + RDB_TRY_GET_VALUE_OR_STR_ERR( + opt_call_id, + forCallEngineNextCallIds( + common_)); + if (opt_call_id) + call_id_cache_ = std::make_pair(*opt_call_id, 0ull); + else + call_id_cache_ = std::make_pair(0ull, 0ull); + + common_.encode(call_id_cache_->first); + RDB_ERROR_CHECK_TO_STR(forCallEngineCallIds( + common_, tx_hash_, cmd_index_)); + + common_.encode(call_id_cache_->first + 1ull); + RDB_ERROR_CHECK_TO_STR( + forCallEngineNextCallIds(common_)); + } + return {}; +} + +Result RocksdbBurrowStorage::storeLog( + std::string_view address, + std::string_view data, + std::vector topics) { + if (!call_id_cache_) { + RDB_ERROR_CHECK(initCallId()); + } + + uint64_t log_idx = 0ull; + RDB_TRY_GET_VALUE_OR_STR_ERR( + opt_log_idx, + forCallEngineNextLogIx(common_)); + if (opt_log_idx) + log_idx = *opt_log_idx; + + common_.encode(log_idx + 1ull); + RDB_ERROR_CHECK_TO_STR(forCallEngineNextLogIx(common_)); + + MAKE_LOWER_ON_STACK(address_lc, address, 128); + common_.valueBuffer() = std::to_string(log_idx); + common_.valueBuffer() += '#'; + common_.valueBuffer() += address_lc; + common_.valueBuffer() += '#'; + common_.valueBuffer() += data; + RDB_ERROR_CHECK_TO_STR(forCallEngineLogs( + common_, call_id_cache_->first, call_id_cache_->second++)); + + for (uint64_t ix = 0; ix < topics.size(); ++ix) { + auto const &topic = topics[ix]; + common_.valueBuffer().assign(topic.data(), topic.size()); + RDB_ERROR_CHECK_TO_STR( + forCallEngineTopics(common_, log_idx, ix)); + } + + return {}; +} diff --git a/irohad/ametsuchi/impl/rocksdb_burrow_storage.hpp b/irohad/ametsuchi/impl/rocksdb_burrow_storage.hpp new file mode 100644 index 00000000000..e40bd0bad5c --- /dev/null +++ b/irohad/ametsuchi/impl/rocksdb_burrow_storage.hpp @@ -0,0 +1,65 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef IROHA_RDB_BURROW_STORAGE_HPP +#define IROHA_RDB_BURROW_STORAGE_HPP + +#include "ametsuchi/burrow_storage.hpp" + +#include +#include + +#include "interfaces/common_objects/types.hpp" + +namespace iroha::ametsuchi { + class RocksDbCommon; + + class RocksdbBurrowStorage : public BurrowStorage { + public: + RocksdbBurrowStorage( + RocksDbCommon &common, + std::string_view tx_hash, + shared_model::interface::types::CommandIndexType cmd_index); + + expected::Result, std::string> getAccount( + std::string_view address) override; + + expected::Result updateAccount( + std::string_view address, std::string_view account) override; + + expected::Result removeAccount( + std::string_view address) override; + + expected::Result, std::string> getStorage( + std::string_view address, std::string_view key) override; + + expected::Result setStorage( + std::string_view address, + std::string_view key, + std::string_view value) override; + + expected::Result storeLog( + std::string_view address, + std::string_view data, + std::vector topics) override; + + std::optional getCallId() const { + if (call_id_cache_) + return call_id_cache_->first; + return std::nullopt; + } + + expected::Result initCallId(); + + private: + RocksDbCommon &common_; + std::string_view tx_hash_; + shared_model::interface::types::CommandIndexType cmd_index_; + std::optional> call_id_cache_; + }; + +} // namespace iroha::ametsuchi + +#endif // IROHA_RDB_BURROW_STORAGE_HPP diff --git a/irohad/ametsuchi/impl/rocksdb_command_executor.cpp b/irohad/ametsuchi/impl/rocksdb_command_executor.cpp index 5e943272490..215aaa9c4c5 100644 --- a/irohad/ametsuchi/impl/rocksdb_command_executor.cpp +++ b/irohad/ametsuchi/impl/rocksdb_command_executor.cpp @@ -10,6 +10,8 @@ #include #include #include "ametsuchi/impl/executor_common.hpp" +#include "ametsuchi/impl/rocksdb_burrow_storage.hpp" +#include "ametsuchi/impl/rocksdb_specific_query_executor.hpp" #include "ametsuchi/setting_query.hpp" #include "ametsuchi/vm_caller.hpp" #include "common/to_lower.hpp" @@ -34,6 +36,7 @@ #include "interfaces/commands/set_setting_value.hpp" #include "interfaces/commands/subtract_asset_quantity.hpp" #include "interfaces/commands/transfer_asset.hpp" +#include "interfaces/common_objects/string_view_types.hpp" #include "main/rdb_status.hpp" #include "main/subscription.hpp" @@ -49,9 +52,11 @@ using shared_model::interface::RolePermissionSet; RocksDbCommandExecutor::RocksDbCommandExecutor( std::shared_ptr db_context, std::shared_ptr perm_converter, + std::shared_ptr specific_query_executor, std::optional> vm_caller) : db_context_(std::move(db_context)), perm_converter_{std::move(perm_converter)}, + specific_query_executor_{std::move(specific_query_executor)}, vm_caller_{vm_caller}, db_transaction_(db_context_) { assert(db_context_); @@ -342,10 +347,85 @@ RocksDbCommandExecutor::ExecutionResult RocksDbCommandExecutor::operator()( const shared_model::interface::CallEngine &command, const shared_model::interface::types::AccountIdType &creator_account_id, const std::string &tx_hash, - shared_model::interface::types::CommandIndexType /*cmd_index*/, - bool /*do_validation*/, + shared_model::interface::types::CommandIndexType cmd_index, + bool do_validation, shared_model::interface::RolePermissionSet const &creator_permissions) { - return makeError(ErrorCodes::kNoImplementation, "Not implemented"); + if (!vm_caller_) + return makeError(ErrorCodes::kNotConfigured, + "Engine is not configured."); + + auto const &[creator_account_name, creator_domain_id] = + staticSplitId<2>(creator_account_id); + + GrantablePermissionSet granted_account_permissions; + RDB_TRY_GET_VALUE( + opt_permissions, + forGrantablePermissions( + common, creator_account_name, creator_domain_id, command.caller())); + if (opt_permissions) + granted_account_permissions = *opt_permissions; + + if (do_validation) + RDB_ERROR_CHECK(checkPermissions(creator_permissions, + granted_account_permissions, + Role::kCallEngine, + Grantable::kCallEngineOnMyBehalf)); + + RocksdbBurrowStorage burrow_storage(common, tx_hash, cmd_index); + return vm_caller_->get() + .call( + tx_hash, + cmd_index, + shared_model::interface::types::EvmCodeHexStringView{command.input()}, + command.caller(), + command.callee() + ? std::optional{command.callee() + ->get()} + : std::optional{std::nullopt}, + burrow_storage, + *this, + *specific_query_executor_) + .match( + [&](const auto &value) -> RocksDbCommandExecutor::ExecutionResult { + if (!burrow_storage.getCallId()) + if (auto result = burrow_storage.initCallId(); + expected::hasError(result)) + return makeError(ErrorCodes::kNotConfigured, + "initCallId error: {}", + result.assumeError()); + + assert(burrow_storage.getCallId()); + if (command.callee()) { + common.valueBuffer() = *command.callee(); + common.valueBuffer() += '|'; + if (value.value) + common.valueBuffer() += *value.value; + if (auto result = forCallEngineCallResponse( + common, *burrow_storage.getCallId()); + expected::hasError(result)) + return makeError( + result.template assumeError().code, + "CallEngineResponse: {}", + result.template assumeError().description); + } else { + if (value.value) + common.valueBuffer() = *value.value; + if (auto result = forCallEngineDeploy( + common, *burrow_storage.getCallId()); + expected::hasError(result)) + return makeError( + result.template assumeError().code, + "CallEngineDeploy: {}", + result.template assumeError().description); + } + + return {}; + }, + [](auto &&error) -> RocksDbCommandExecutor::ExecutionResult { + return makeError(3, "CallEngine: {}", std::move(error.error)); + }); } RocksDbCommandExecutor::ExecutionResult RocksDbCommandExecutor::operator()( diff --git a/irohad/ametsuchi/impl/rocksdb_command_executor.hpp b/irohad/ametsuchi/impl/rocksdb_command_executor.hpp index b272c73b526..366f708a4e5 100644 --- a/irohad/ametsuchi/impl/rocksdb_command_executor.hpp +++ b/irohad/ametsuchi/impl/rocksdb_command_executor.hpp @@ -44,6 +44,7 @@ namespace shared_model::interface { namespace iroha::ametsuchi { + class RocksDbSpecificQueryExecutor; class VmCaller; class RocksDbCommandExecutor final : public CommandExecutor { @@ -51,6 +52,7 @@ namespace iroha::ametsuchi { using ExecutionResult = expected::Result; enum ErrorCodes { + kNotConfigured = 1, kNoPermissions = 2, kNoAccount = 3, kInvalidAmount = 3, @@ -74,6 +76,7 @@ namespace iroha::ametsuchi { std::shared_ptr db_context, std::shared_ptr perm_converter, + std::shared_ptr specific_query_executor, std::optional> vm_caller); ~RocksDbCommandExecutor(); @@ -273,6 +276,7 @@ namespace iroha::ametsuchi { std::shared_ptr db_context_; std::shared_ptr perm_converter_; + std::shared_ptr specific_query_executor_; std::optional> vm_caller_; RocksDbTransaction db_transaction_; }; diff --git a/irohad/ametsuchi/impl/rocksdb_common.hpp b/irohad/ametsuchi/impl/rocksdb_common.hpp index c7bfa050eb7..cdae2bc4cb8 100644 --- a/irohad/ametsuchi/impl/rocksdb_common.hpp +++ b/irohad/ametsuchi/impl/rocksdb_common.hpp @@ -115,6 +115,29 @@ * | +- * | +- * | + * +-|EVM_STORAGE|-+-|ENGINE_CALLS|-+- + * | | +- + * | | +- + * | | + * | +-|EC_DEPLOYS|-+- + * | | +- + * | | + * | +-|EC_CON_CALLS|-+- + * | | +- + * | | + * | +-|ACCOUNT|-+- + * | | +- + * | | + * | +-|LOGS|-+- + * | | +- + * | | +- + * | | + * | +-|TOPICS|-+- + * | | +- + * | | + * | +-|ACCOUNT_KV|-+- + * | +- + * | * +- * * @@ -147,6 +170,13 @@ * ### OPTIONS ## O ### * ### ADDRESS ## M ### * ### TLS ## N ### + * ### ENGINE_CALLS ## e ### + * ### ACCOUNT_KV ## A ### + * ### EVM_STORAGE ## E ### + * ### EC_DEPLOYS ## W ### + * ### EC_CON_CALLS ## R ### + * ### LOGS ## y ### + * ### TOPICS ## Y ### * ###################################### * * ###################################### @@ -158,6 +188,7 @@ * ### F_PEERS COUNT ## Z ### * ### F_TOTAL COUNT ## V ### * ### F_VERSION ## v ### + * ### F_NEXT_ID ## X ### * ###################################### * * ###################################### @@ -193,6 +224,13 @@ #define RDB_OPTIONS "O" #define RDB_ADDRESS "M" #define RDB_TLS "N" +#define RDB_ENGINE_CALLS "e" +#define RDB_ACCOUNT_KV "A" +#define RDB_EVM_STORAGE "E" +#define RDB_EC_DEPLOYS "W" +#define RDB_EC_CON_CALLS "R" +#define RDB_LOGS "y" +#define RDB_TOPICS "Y" #define RDB_F_QUORUM "q" #define RDB_F_ASSET_SIZE "I" @@ -200,6 +238,7 @@ #define RDB_F_PEERS_COUNT "Z" #define RDB_F_TOTAL_COUNT "V" #define RDB_F_VERSION "v" +#define RDB_F_NEXT_ID "X" #define RDB_PATH_DOMAIN RDB_ROOT /**/ RDB_WSV /**/ RDB_DOMAIN /**/ RDB_XXX #define RDB_PATH_ACCOUNT RDB_PATH_DOMAIN /**/ RDB_ACCOUNTS /**/ RDB_XXX @@ -237,6 +276,11 @@ namespace iroha::ametsuchi::fmtstrings { FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_NETWORK /**/ RDB_S_PEERS /**/ RDB_ADDRESS)}; + // hash ➡️ call_id + static auto constexpr kPathEngineCallIds{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_ENGINE_CALLS /**/ RDB_XXX)}; + // domain_id/account_name static auto constexpr kPathSignatories{ FMT_STRING(RDB_PATH_ACCOUNT /**/ RDB_SIGNATORIES)}; @@ -245,11 +289,21 @@ namespace iroha::ametsuchi::fmtstrings { static auto constexpr kPathRoles{ FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_ROLES)}; + // call_id ➡️ log_ix/address/data + static auto constexpr kPathEngineLogs{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_LOGS /**/ RDB_XXX)}; + // account static auto constexpr kPathTransactionByTs{ FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_TRANSACTIONS /**/ RDB_ACCOUNTS /**/ RDB_XXX /**/ RDB_TIMESTAMP)}; + // address + static auto constexpr kPathEngineStorage{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_ACCOUNT_KV /**/ RDB_XXX)}; + // account static auto constexpr kPathTransactionByPosition{ FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_TRANSACTIONS /**/ @@ -263,6 +317,11 @@ namespace iroha::ametsuchi::fmtstrings { static auto constexpr kPathAccountAssets{ FMT_STRING(RDB_PATH_ACCOUNT /**/ RDB_ASSETS)}; + // log_ix ➡️ topic + static auto constexpr kPathEngineTopics{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_TOPICS /**/ RDB_XXX)}; + /** * ###################################### * ############# FOLDERS ################ @@ -272,6 +331,41 @@ namespace iroha::ametsuchi::fmtstrings { static auto constexpr kBlockDataInStore{ FMT_STRING(RDB_ROOT /**/ RDB_STORE /**/ RDB_XXX)}; + // hash/index ➡️ call_id + static auto constexpr kEngineCallId{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_ENGINE_CALLS /**/ RDB_XXX /**/ RDB_XXX)}; + + // address ➡️ account + static auto constexpr kEngineAccount{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_ACCOUNTS /**/ RDB_XXX)}; + + // address/key ➡️ value + static auto constexpr kEngineStorage{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_ACCOUNT_KV /**/ RDB_XXX /**/ RDB_XXX)}; + + // call_id ➡️ contract address + static auto constexpr kEngineDeploy{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_EC_DEPLOYS /**/ RDB_XXX)}; + + // call_id ➡️ callee/response + static auto constexpr kEngineCallResponse{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_EC_CON_CALLS /**/ RDB_XXX)}; + + // call_id/ix ➡️ log_ix/address/data + static auto constexpr kEngineCallLogs{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_LOGS /**/ RDB_XXX /**/ RDB_XXX)}; + + // log_ix/ix ➡️ topic + static auto constexpr kEngineCallTopics{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_TOPICS /**/ RDB_XXX /**/ RDB_XXX)}; + // account/height/index/ts ➡️ tx_hash static auto constexpr kTransactionByPosition{FMT_STRING( RDB_ROOT /**/ RDB_WSV /**/ RDB_TRANSACTIONS /**/ RDB_ACCOUNTS /**/ @@ -360,6 +454,16 @@ namespace iroha::ametsuchi::fmtstrings { // domain_id ➡️ default role static auto constexpr kDomain{FMT_STRING(RDB_PATH_DOMAIN)}; + // "" ➡️ next_call_id + static auto constexpr kEngineNextCallId{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_ENGINE_CALLS /**/ RDB_F_NEXT_ID)}; + + // "" ➡️ next_log_id + static auto constexpr kEngineNextLogId{ + FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_EVM_STORAGE /**/ + RDB_LOGS /**/ RDB_F_NEXT_ID)}; + // "" ➡️ height # hash static auto constexpr kTopBlock{ FMT_STRING(RDB_ROOT /**/ RDB_WSV /**/ RDB_NETWORK /**/ RDB_STORE /**/ @@ -675,7 +779,7 @@ namespace iroha::ametsuchi { #define RDB_ERROR_CHECK_TO_STR(...) \ if (auto _tmp_gen_var = (__VA_ARGS__); \ iroha::expected::hasError(_tmp_gen_var)) \ - return _tmp_gen_var.assumeError().description + return iroha::expected::makeError(_tmp_gen_var.assumeError().description) #define RDB_TRY_GET_VALUE(name, ...) \ typename decltype(__VA_ARGS__)::ValueInnerType name; \ @@ -685,12 +789,12 @@ namespace iroha::ametsuchi { else \ name = std::move(_tmp_gen_var.assumeValue()) -#define RDB_TRY_GET_VALUE_OR_STR_ERR(name, ...) \ - typename decltype(__VA_ARGS__)::ValueInnerType name; \ - if (auto _tmp_gen_var = (__VA_ARGS__); \ - iroha::expected::hasError(_tmp_gen_var)) \ - return _tmp_gen_var.assumeError().description; \ - else \ +#define RDB_TRY_GET_VALUE_OR_STR_ERR(name, ...) \ + typename decltype(__VA_ARGS__)::ValueInnerType name; \ + if (auto _tmp_gen_var = (__VA_ARGS__); \ + iroha::expected::hasError(_tmp_gen_var)) \ + return iroha::expected::makeError(_tmp_gen_var.assumeError().description); \ + else \ name = std::move(_tmp_gen_var.assumeValue()) /** @@ -1218,8 +1322,17 @@ namespace iroha::ametsuchi { kOp != kDbOperation::kDel || kSc != kDbEntry::kMustExist, "Delete operation does not report if key existed before deletion!"); - RDB_ERROR_CHECK(checkStatus( - status, std::forward(op_formatter))); + if constexpr (kOp == kDbOperation::kPut) { + RDB_ERROR_CHECK(checkStatus( + status, std::forward(op_formatter))); + } else if constexpr (kOp == kDbOperation::kDel) { + RDB_ERROR_CHECK(checkStatus( + status, std::forward(op_formatter))); + } else { + RDB_ERROR_CHECK(checkStatus( + status, std::forward(op_formatter))); + } + return status; } @@ -1602,6 +1715,182 @@ namespace iroha::ametsuchi { tx_hash.blob().size())); } + /** + * Access to Call Engine Account data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param address is internal evm address with relative account + * @return operation result + */ + template + inline expected::Result, DbError> + forCallEngineAccount(RocksDbCommon &common, std::string_view address) { + return dbCall( + common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineAccount, + address); + } + + /** + * Access to Call Engine Storage data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param address is internal evm address with relative account + * @param key for the storage + * @return operation result + */ + template + inline expected::Result, DbError> + forCallEngineStorage(RocksDbCommon &common, + std::string_view address, + std::string_view key) { + return dbCall( + common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineStorage, + address, + key); + } + + /** + * Access to Call Engine Call Ids data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param hash of the tx + * @param cmd_index of the command inside the tx + * @return call_id operation result + */ + template + inline expected::Result, DbError> + forCallEngineCallIds(RocksDbCommon &common, + std::string_view hash, + uint32_t cmd_index) { + return dbCall(common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineCallId, + hash, + cmd_index); + } + + /** + * Access to Call Engine Deploy data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param call_id of the CallEngine with contract deploy + * @return address of the contract + */ + template + inline expected::Result, DbError> + forCallEngineDeploy(RocksDbCommon &common, uint64_t call_id) { + return dbCall( + common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineDeploy, + call_id); + } + + /** + * Access to Call Engine Call Responses data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param call_id of the CallEngine with contract call + * @return callee + engine response + */ + template + inline expected::Result, DbError> + forCallEngineCallResponse(RocksDbCommon &common, uint64_t call_id) { + return dbCall( + common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineCallResponse, + call_id); + } + + /** + * Access to Call Engine Topics data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param log_ix of the topic + * @param ix is increment + * @return topic data + */ + template + inline expected::Result, DbError> + forCallEngineTopics(RocksDbCommon &common, uint64_t log_ix, uint64_t ix) { + return dbCall( + common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineCallTopics, + log_ix, + ix); + } + + /** + * Access to Call Engine Logs data + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @param call_id of the topic + * @param ix is increment + * @return logs data + */ + template + inline expected::Result, DbError> + forCallEngineLogs(RocksDbCommon &common, uint64_t call_id, uint64_t ix) { + return dbCall( + common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineCallLogs, + call_id, + ix); + } + + /** + * Access to Call Engine Next Call Id + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @return next call_id operation result + */ + template + inline expected::Result, DbError> + forCallEngineNextCallIds(RocksDbCommon &common) { + return dbCall(common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineNextCallId); + } + + /** + * Access to Call Engine Next Log Id + * @tparam kOp @see kDbOperation + * @tparam kSc @see kDbEntry + * @param common @see RocksDbCommon + * @return next log_ix operation result + */ + template + inline expected::Result, DbError> + forCallEngineNextLogIx(RocksDbCommon &common) { + return dbCall(common, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kEngineNextLogId); + } + /** * Access to transactions by position * @tparam kOp @see kDbOperation diff --git a/irohad/ametsuchi/impl/rocksdb_specific_query_executor.cpp b/irohad/ametsuchi/impl/rocksdb_specific_query_executor.cpp index 4943098d1a5..b9150ba1d78 100644 --- a/irohad/ametsuchi/impl/rocksdb_specific_query_executor.cpp +++ b/irohad/ametsuchi/impl/rocksdb_specific_query_executor.cpp @@ -13,6 +13,7 @@ #include "ametsuchi/impl/executor_common.hpp" #include "ametsuchi/impl/rocksdb_common.hpp" #include "backend/plain/account_detail_record_id.hpp" +#include "backend/plain/engine_receipt.hpp" #include "backend/plain/peer.hpp" #include "common/bind.hpp" #include "common/common.hpp" @@ -994,5 +995,123 @@ operator()( const shared_model::interface::types::AccountIdType &creator_id, const shared_model::interface::types::HashType &query_hash, shared_model::interface::RolePermissionSet const &creator_permissions) { - throw std::runtime_error(fmt::format("Not implemented")); + auto const &[_, creator_domain_id] = staticSplitId<2ull>(creator_id); + + RDB_ERROR_CHECK(checkPermissions(creator_domain_id, + creator_domain_id, + creator_id, + creator_id, + creator_permissions, + Role::kGetAllEngineReceipts, + Role::kGetDomainEngineReceipts, + Role::kGetMyEngineReceipts)); + + std::vector> records; + + std::optional error; + auto status = enumerateKeysAndValues( + common, + [&](auto, auto cid) { + uint64_t call_id; + std::from_chars(cid.data(), cid.data() + cid.size(), call_id); + + std::optional callee; + std::optional + cantract_address; + std::optional + engine_response; + + if (auto result = + forCallEngineCallResponse(common, call_id); + expected::hasError(result)) { + error = fmt::format("CallEngineResponse code: {}, failed: {}", + result.template assumeError().code, + result.template assumeError().description); + return false; + } else if (result.assumeValue()) { + auto const &[callee_, response_] = + staticSplitId<2ull>(*result.assumeValue(), "|"); + callee = callee_; + engine_response = response_; + } + + if (auto result = + forCallEngineDeploy( + common, call_id); + expected::hasError(result)) { + error = fmt::format("CallEngineDeploy code: {}, failed: {}", + result.template assumeError().code, + result.template assumeError().description); + return false; + } else if (result.assumeValue()) { + cantract_address = *result.assumeValue(); + } + + auto record = std::make_unique( + 0ull, //*cmd_index + "", // caller + callee, + cantract_address, + engine_response); + + auto logs_status = enumerateKeysAndValues( + common, + [&](auto, auto l) { + auto const &[log_ix_str, address, data] = + staticSplitId<3ull>(l.ToStringView(), "#"); + uint64_t log_id = std::stoull( + std::string(log_ix_str.data(), log_ix_str.size())); + + auto log = std::make_unique( + shared_model::interface::types::EvmAddressHexString( + address.data(), address.size()), + shared_model::interface::types::EvmDataHexString( + data.data(), data.size())); + + auto topics_status = enumerateKeysAndValues( + common, + [&](auto, auto t) { + auto tstr = t.ToStringView(); + log->addTopic( + shared_model::interface::types::EvmTopicsHexString( + tstr.data(), tstr.size())); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineTopics, + log_id); + if (!topics_status.ok()) { + error = fmt::format("enumerate CallEngineTopics failed."); + return false; + } + + record->getMutableLogs().emplace_back(std::move(log)); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineLogs, + call_id); + if (!logs_status.ok()) { + error = fmt::format("enumerate CallEngineLogs failed."); + return false; + } + + records.emplace_back(std::move(record)); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineCallIds, + query.txHash()); + RDB_ERROR_CHECK(canExist(status, [&] { + return fmt::format("PathEngineCallsIds enumeration failed: {}", + query.txHash()); + })); + + if (error) + return makeError( + ErrorCodes::kGetReceipts, "GetEngineReceipts failed: {}", *error); + + return query_response_factory_->createEngineReceiptsResponse(records, + query_hash); } diff --git a/irohad/ametsuchi/impl/rocksdb_specific_query_executor.hpp b/irohad/ametsuchi/impl/rocksdb_specific_query_executor.hpp index f4b26d9ac8e..38c3cdb193a 100644 --- a/irohad/ametsuchi/impl/rocksdb_specific_query_executor.hpp +++ b/irohad/ametsuchi/impl/rocksdb_specific_query_executor.hpp @@ -52,6 +52,7 @@ namespace iroha::ametsuchi { kQueryHeightOverflow = 3, kAssetNotFound = 4, kNoTransaction = 4, + kGetReceipts = 5, kRetrieveTransactionsFailed = 1010, }; diff --git a/irohad/ametsuchi/impl/rocksdb_storage_impl.cpp b/irohad/ametsuchi/impl/rocksdb_storage_impl.cpp index 7ebba4dea19..63c329fb833 100644 --- a/irohad/ametsuchi/impl/rocksdb_storage_impl.cpp +++ b/irohad/ametsuchi/impl/rocksdb_storage_impl.cpp @@ -99,7 +99,14 @@ namespace iroha::ametsuchi { expected::Result, std::string> RocksDbStorageImpl::createCommandExecutor() { return std::make_unique( - db_context_, permConverter(), vmCaller()); + db_context_, + permConverter(), + std::make_shared(db_context_, + *blockStore(), + pendingTxStorage(), + queryResponseFactory(), + permConverter()), + vmCaller()); } expected::Result, std::string> diff --git a/irohad/main/CMakeLists.txt b/irohad/main/CMakeLists.txt index e9a503b0745..3039cdcd6b9 100644 --- a/irohad/main/CMakeLists.txt +++ b/irohad/main/CMakeLists.txt @@ -88,7 +88,6 @@ target_link_libraries(application simulator block_loader block_loader_service - mst_processor torii_service pending_txs_storage common diff --git a/irohad/main/application.cpp b/irohad/main/application.cpp index a130e8cbe03..3da37cb95f9 100644 --- a/irohad/main/application.cpp +++ b/irohad/main/application.cpp @@ -47,13 +47,7 @@ #include "main/iroha_status.hpp" #include "main/server_runner.hpp" #include "main/subscription.hpp" -#include "multi_sig_transactions/gossip_propagation_strategy.hpp" -#include "multi_sig_transactions/mst_processor_impl.hpp" -#include "multi_sig_transactions/mst_propagation_strategy_stub.hpp" -#include "multi_sig_transactions/mst_time_provider_impl.hpp" -#include "multi_sig_transactions/storage/mst_storage_impl.hpp" -#include "multi_sig_transactions/transport/mst_transport_grpc.hpp" -#include "multi_sig_transactions/transport/mst_transport_stub.hpp" +#include "network/impl/async_grpc_client.hpp" #include "network/impl/block_loader_impl.hpp" #include "network/impl/channel_factory.hpp" #include "network/impl/channel_pool.hpp" @@ -106,6 +100,7 @@ static constexpr iroha::consensus::yac::ConsistencyModel static constexpr uint32_t kStaleStreamMaxRoundsDefault = 2; static constexpr uint32_t kMstExpirationTimeDefault = 1440; static constexpr uint32_t kMaxRoundsDelayDefault = 3000; +static constexpr uint32_t kProposalDelayMultiplier = 2; /** * Configuring iroha daemon @@ -121,15 +116,12 @@ Irohad::Irohad( StartupWsvSynchronizationPolicy startup_wsv_sync_policy, std::optional> maybe_grpc_channel_params, - const boost::optional - &opt_mst_gossip_params, boost::optional inter_peer_tls_config) : config_(config), listen_ip_(listen_ip), keypair_(keypair), startup_wsv_sync_policy_(startup_wsv_sync_policy), maybe_grpc_channel_params_(std::move(maybe_grpc_channel_params)), - opt_mst_gossip_params_(opt_mst_gossip_params), inter_peer_tls_config_(std::move(inter_peer_tls_config)), pg_opt_(std::move(pg_opt)), rdb_opt_(std::move(rdb_opt)), @@ -207,7 +199,6 @@ Irohad::RunResult Irohad::init() { IROHA_EXPECTED_ERROR_CHECK(initSynchronizer()); IROHA_EXPECTED_ERROR_CHECK(initPeerCommunicationService()); IROHA_EXPECTED_ERROR_CHECK(initStatusBus()); - IROHA_EXPECTED_ERROR_CHECK(initMstProcessor()); IROHA_EXPECTED_ERROR_CHECK(initPendingTxsStorageWithCache()); // Torii IROHA_EXPECTED_ERROR_CHECK(initTransactionCommandService()); @@ -395,18 +386,15 @@ Irohad::RunResult Irohad::initStorage( auto process_block = [this](std::shared_ptr block) { iroha::getSubscription()->notify(EventTypes::kOnBlock, block); - if (ordering_init and tx_processor and pending_txs_storage_ - and mst_storage) { + if (ordering_init and tx_processor and pending_txs_storage_) { ordering_init->processCommittedBlock(block); tx_processor->processCommit(block); for (auto const &completed_tx : block->transactions()) { pending_txs_storage_->removeTransaction(completed_tx.hash()); - mst_storage->processFinalizedTransaction(completed_tx.hash()); } for (auto const &rejected_tx_hash : block->rejected_transactions_hashes()) { pending_txs_storage_->removeTransaction(rejected_tx_hash); - mst_storage->processFinalizedTransaction(rejected_tx_hash); } } }; @@ -756,7 +744,9 @@ Irohad::RunResult Irohad::initOrderingGate() { ordering_gate = ordering_init->initOrderingGate( config_.max_proposal_size, - std::chrono::milliseconds(config_.proposal_delay), + std::chrono::milliseconds( + config_.proposal_creation_timeout.value_or(kMaxRoundsDelayDefault) + * kProposalDelayMultiplier), transaction_factory, batch_parser, transaction_batch_factory_, @@ -921,52 +911,6 @@ Irohad::RunResult Irohad::initStatusBus() { return {}; } -Irohad::RunResult Irohad::initMstProcessor() { - auto mst_logger_manager = - log_manager_->getChild("MultiSignatureTransactions"); - auto mst_state_logger = mst_logger_manager->getChild("State")->getLogger(); - auto mst_completer = std::make_shared(std::chrono::minutes( - config_.mst_expiration_time.value_or(kMstExpirationTimeDefault))); - mst_storage = std::make_shared( - mst_completer, - mst_state_logger, - mst_logger_manager->getChild("Storage")->getLogger()); - std::shared_ptr mst_propagation; - if (config_.mst_support) { - mst_transport = std::make_shared( - async_call_, - transaction_factory, - batch_parser, - transaction_batch_factory_, - persistent_cache, - mst_completer, - PublicKeyHexStringView{keypair_->publicKey()}, - std::move(mst_state_logger), - mst_logger_manager->getChild("Transport")->getLogger(), - std::make_unique>( - inter_peer_client_factory_)); - mst_propagation = std::make_shared( - storage, rxcpp::observe_on_new_thread(), *opt_mst_gossip_params_); - } else { - mst_transport = std::make_shared(); - mst_propagation = std::make_shared(); - } - - auto mst_time = std::make_shared(); - auto fair_mst_processor = std::make_shared( - mst_transport, - mst_storage, - mst_propagation, - mst_time, - mst_logger_manager->getChild("Processor")->getLogger()); - mst_processor = fair_mst_processor; - mst_transport->subscribe(fair_mst_processor); - - log_->info("[Init] => MST processor"); - return {}; -} - Irohad::RunResult Irohad::initPendingTxsStorage() { pending_txs_storage_ = std::make_shared(); log_->info("[Init] => pending transactions storage"); @@ -983,45 +927,64 @@ Irohad::RunResult Irohad::initTransactionCommandService() { auto cs_cache = std::make_shared<::torii::CommandServiceImpl::CacheType>(); tx_processor = std::make_shared( pcs, - mst_processor, status_bus_, status_factory, command_service_log_manager->getChild("Processor")->getLogger()); - mst_processor->onStateUpdate().subscribe( - [tx_processor(utils::make_weak(tx_processor)), - pending_txs_storage(utils::make_weak(pending_txs_storage_))]( - std::shared_ptr const &state) { - auto maybe_tx_processor = tx_processor.lock(); - auto maybe_pending_txs_storage = pending_txs_storage.lock(); - if (maybe_tx_processor and maybe_pending_txs_storage) { - maybe_tx_processor->processStateUpdate(state); - maybe_pending_txs_storage->updatedBatchesHandler(state); - } - }); - mst_processor->onPreparedBatches().subscribe( - [tx_processor(utils::make_weak(tx_processor)), - pending_txs_storage(utils::make_weak(pending_txs_storage_))]( - std::shared_ptr const - &batch) { - auto maybe_tx_processor = tx_processor.lock(); - auto maybe_pending_txs_storage = pending_txs_storage.lock(); - if (maybe_tx_processor and maybe_pending_txs_storage) { - maybe_tx_processor->processPreparedBatch(batch); - maybe_pending_txs_storage->removeBatch(batch); - } - }); - mst_processor->onExpiredBatches().subscribe( - [tx_processor(utils::make_weak(tx_processor)), - pending_txs_storage(utils::make_weak(pending_txs_storage_))]( - std::shared_ptr const - &batch) { - auto maybe_tx_processor = tx_processor.lock(); - auto maybe_pending_txs_storage = pending_txs_storage.lock(); - if (maybe_tx_processor and maybe_pending_txs_storage) { - maybe_tx_processor->processExpiredBatch(batch); - maybe_pending_txs_storage->removeBatch(batch); - } - }); + + mst_state_update_ = SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + SubscriptionEngineHandlers::kNotifications, + [tx_processor(utils::make_weak(tx_processor)), + pending_txs_storage(utils::make_weak(pending_txs_storage_))]( + auto &, + std::shared_ptr + batch) { + auto maybe_tx_processor = tx_processor.lock(); + auto maybe_pending_txs_storage = pending_txs_storage.lock(); + if (maybe_tx_processor && maybe_pending_txs_storage) { + maybe_tx_processor->processStateUpdate(batch); + maybe_pending_txs_storage->updatedBatchesHandler(batch); + } + }); + + mst_state_prepared_ = SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + SubscriptionEngineHandlers::kNotifications, + [tx_processor(utils::make_weak(tx_processor)), + pending_txs_storage(utils::make_weak(pending_txs_storage_))]( + auto &, + std::shared_ptr + batch) { + auto maybe_tx_processor = tx_processor.lock(); + auto maybe_pending_txs_storage = pending_txs_storage.lock(); + if (maybe_tx_processor && maybe_pending_txs_storage) { + maybe_tx_processor->processPreparedBatch(batch); + maybe_pending_txs_storage->removeBatch(batch); + } + }); + + mst_state_expired_ = SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + SubscriptionEngineHandlers::kNotifications, + [tx_processor(utils::make_weak(tx_processor)), + pending_txs_storage(utils::make_weak(pending_txs_storage_))]( + auto &, + std::shared_ptr + batch) { + auto maybe_tx_processor = tx_processor.lock(); + auto maybe_pending_txs_storage = pending_txs_storage.lock(); + if (maybe_tx_processor && maybe_pending_txs_storage) { + maybe_tx_processor->processExpiredBatch(batch); + maybe_pending_txs_storage->removeBatch(batch); + } + }); + command_service = std::make_shared<::torii::CommandServiceImpl>( tx_processor, status_bus_, @@ -1123,11 +1086,6 @@ namespace { * Run iroha daemon */ Irohad::RunResult Irohad::run() { - if (config_.proposal_delay - <= config_.proposal_creation_timeout.value_or(kMaxRoundsDelayDefault)) { - return expected::makeError( - "proposal_delay must be more than proposal_creation_timeout"); - } ordering_init->subscribe([simulator(utils::make_weak(simulator)), consensus_gate(utils::make_weak(consensus_gate)), tx_processor(utils::make_weak(tx_processor)), @@ -1209,10 +1167,6 @@ Irohad::RunResult Irohad::run() { } // Run internal server - if (config_.mst_support) { - internal_server->append( - std::static_pointer_cast(mst_transport)); - } IROHA_EXPECTED_TRY_GET_VALUE(internal_port, internal_server->append(ordering_init->service) .append(yac_init->getConsensusNetwork()) diff --git a/irohad/main/application.hpp b/irohad/main/application.hpp index af275efae63..41bc4ea7d08 100644 --- a/irohad/main/application.hpp +++ b/irohad/main/application.hpp @@ -23,7 +23,6 @@ #include "main/server_runner.hpp" #include "main/startup_params.hpp" #include "main/subscription_fwd.hpp" -#include "multi_sig_transactions/gossip_propagation_strategy_params.hpp" #include "torii/tls_params.hpp" namespace google::protobuf { @@ -63,7 +62,6 @@ namespace iroha { class ChannelPool; class GenericClientFactory; class ConsensusGate; - class MstTransport; class OrderingGate; class PeerCommunicationService; class PeerTlsCertificatesProvider; @@ -110,6 +108,7 @@ namespace shared_model { class QueryResponseFactory; class TransactionBatchFactory; class TransactionBatchParser; + class TransactionBatch; } // namespace interface namespace validation { struct Settings; @@ -146,8 +145,6 @@ class Irohad { iroha::StartupWsvSynchronizationPolicy startup_wsv_sync_policy, std::optional> maybe_grpc_channel_params, - const boost::optional - &opt_mst_gossip_params, boost::optional inter_peer_tls_config = boost::none); @@ -226,8 +223,6 @@ class Irohad { virtual RunResult initStatusBus(); - virtual RunResult initMstProcessor(); - virtual RunResult initPendingTxsStorage(); virtual RunResult initTransactionCommandService(); @@ -254,8 +249,6 @@ class Irohad { iroha::StartupWsvSynchronizationPolicy startup_wsv_sync_policy_; std::optional> maybe_grpc_channel_params_; - boost::optional - opt_mst_gossip_params_; boost::optional inter_peer_tls_config_; boost::optional> @@ -377,11 +370,6 @@ class Irohad { // status bus std::shared_ptr status_bus_; - // mst - std::shared_ptr mst_storage; - std::shared_ptr mst_transport; - std::shared_ptr mst_processor; - // transaction service std::shared_ptr tx_processor; std::shared_ptr command_service; @@ -389,6 +377,13 @@ class Irohad { command_service_transport; // subscriptions + using MstStateSubscriber = iroha::BaseSubscriber< + bool, + std::shared_ptr>; + std::shared_ptr mst_state_update_; + std::shared_ptr mst_state_prepared_; + std::shared_ptr mst_state_expired_; + std::shared_ptr, iroha::IrohaStatus>> diff --git a/irohad/main/impl/on_demand_ordering_init.cpp b/irohad/main/impl/on_demand_ordering_init.cpp index c5b88c17002..4637c9fad0f 100644 --- a/irohad/main/impl/on_demand_ordering_init.cpp +++ b/irohad/main/impl/on_demand_ordering_init.cpp @@ -56,10 +56,6 @@ auto createNotificationFactory( std::make_unique>( std::move(client_factory)), - [](iroha::ordering::ProposalEvent event) { - iroha::getSubscription()->notify(iroha::EventTypes::kOnProposalResponse, - std::move(event)); - }, std::move(os_execution_keepers)); } @@ -87,7 +83,7 @@ auto OnDemandOrderingInit::createGate( size_t max_number_of_transactions, const logger::LoggerManagerTreePtr &ordering_log_manager, bool syncing_mode) { - return std::make_shared( + auto og = std::make_shared( std::move(ordering_service), std::move(network_client), std::move(proposal_factory), @@ -95,6 +91,8 @@ auto OnDemandOrderingInit::createGate( max_number_of_transactions, ordering_log_manager->getChild("Gate")->getLogger(), syncing_mode); + og->initialize(); + return og; } auto OnDemandOrderingInit::createService( @@ -260,7 +258,7 @@ iroha::ordering::RoundSwitch OnDemandOrderingInit::processSynchronizationEvent( peers.peers.at(OnDemandConnectionManager::kIssuer) = getOsPeer(kCurrentRound, current_round.reject_round); - connection_manager_->initializeConnections(peers); + connection_manager_->initializeConnections(peers, current_peers); return {std::move(current_round), event.ledger_state}; } diff --git a/irohad/main/iroha_conf_literals.cpp b/irohad/main/iroha_conf_literals.cpp index bf7752486ab..a66df7e4a7c 100644 --- a/irohad/main/iroha_conf_literals.cpp +++ b/irohad/main/iroha_conf_literals.cpp @@ -29,7 +29,6 @@ namespace config_members { const char *DbPath = "path"; const char *DbType = "type"; const char *MaxProposalSize = "max_proposal_size"; - const char *ProposalDelay = "proposal_delay"; const char *ProposalCreationTimeout = "proposal_creation_timeout"; const char *HealthcheckPort = "healthcheck_port"; const char *VoteDelay = "vote_delay"; diff --git a/irohad/main/iroha_conf_literals.hpp b/irohad/main/iroha_conf_literals.hpp index 308091ec2c4..b8912714c9b 100644 --- a/irohad/main/iroha_conf_literals.hpp +++ b/irohad/main/iroha_conf_literals.hpp @@ -35,7 +35,6 @@ namespace config_members { extern const char *DbPath; extern const char *DbType; extern const char *MaxProposalSize; - extern const char *ProposalDelay; extern const char *ProposalCreationTimeout; extern const char *HealthcheckPort; extern const char *VoteDelay; diff --git a/irohad/main/iroha_conf_loader.cpp b/irohad/main/iroha_conf_loader.cpp index 03aab5f1c8a..be362df386c 100644 --- a/irohad/main/iroha_conf_loader.cpp +++ b/irohad/main/iroha_conf_loader.cpp @@ -689,7 +689,6 @@ inline bool JsonDeserializerImpl::loadInto(IrohadConfig &dest) { and getDictChild(DbConfig).loadInto(dest.database_config) and (dest.database_config or getDictChild(PgOpt).loadInto(dest.pg_opt)) and getDictChild(MaxProposalSize).loadInto(dest.max_proposal_size) - and getDictChild(ProposalDelay).loadInto(dest.proposal_delay) and getDictChild(ProposalCreationTimeout) .loadInto(dest.proposal_creation_timeout) and getDictChild(HealthcheckPort).loadInto(dest.healthcheck_port) diff --git a/irohad/main/iroha_conf_loader.hpp b/irohad/main/iroha_conf_loader.hpp index 67b5e3827ef..404c7baf090 100644 --- a/irohad/main/iroha_conf_loader.hpp +++ b/irohad/main/iroha_conf_loader.hpp @@ -61,9 +61,8 @@ struct IrohadConfig { boost::optional database_config; // TODO 2019.06.26 mboldyrev IR-556 make required uint32_t max_proposal_size; - uint32_t proposal_delay; uint32_t vote_delay; - bool mst_support; + [[deprecated]] bool mst_support; bool syncing_mode; boost::optional mst_expiration_time; boost::optional max_round_delay_ms; diff --git a/irohad/main/irohad.cpp b/irohad/main/irohad.cpp index 5d506f3bb36..d4e9be85574 100644 --- a/irohad/main/irohad.cpp +++ b/irohad/main/irohad.cpp @@ -328,8 +328,6 @@ int main(int argc, char *argv[]) { ? iroha::StartupWsvSynchronizationPolicy::kWaitForNewBlocks : iroha::StartupWsvSynchronizationPolicy::kSyncUpAndGo, std::nullopt, - boost::make_optional(config.mst_support, - iroha::GossipPropagationStrategyParams{}), boost::none); // Check if iroha daemon storage was successfully initialized diff --git a/irohad/main/subscription.hpp b/irohad/main/subscription.hpp index d1644271511..0b1968d210a 100644 --- a/irohad/main/subscription.hpp +++ b/irohad/main/subscription.hpp @@ -17,6 +17,15 @@ namespace iroha { std::shared_ptr getDispatcher(); std::shared_ptr getSubscription(); + template + constexpr void notifyEngine(std::tuple &&data) { + std::apply( + [](auto &... x) { + (..., getSubscription()->notify(x.first, x.second)); + }, + data); + } + template struct SubscriberCreator { template diff --git a/irohad/main/subscription_fwd.hpp b/irohad/main/subscription_fwd.hpp index b2bd7d11261..f699d72fd81 100644 --- a/irohad/main/subscription_fwd.hpp +++ b/irohad/main/subscription_fwd.hpp @@ -13,7 +13,9 @@ namespace iroha { kYac = 0, kRequestProposal, kVoteProcess, + kProposalProcessing, kMetrics, + kNotifications, //--------------- kTotalCount }; @@ -39,10 +41,13 @@ namespace iroha { kOnTxsEnoughForProposal, kOnPackProposal, kOnProposalResponse, + kOnProposalResponseFailed, kOnTransactionResponse, kOnConsensusGateEvent, kSendBatchComplete, + kRemoteProposalDiff, + // RDB kOnRdbStats, diff --git a/irohad/multi_sig_transactions/CMakeLists.txt b/irohad/multi_sig_transactions/CMakeLists.txt deleted file mode 100644 index 6a3442ce606..00000000000 --- a/irohad/multi_sig_transactions/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Soramitsu Co., Ltd. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -add_subdirectory(state) -add_subdirectory(storage) -add_subdirectory(transport) - - -add_library(mst_processor - impl/gossip_propagation_strategy.cpp - impl/mst_propagation_strategy_stub.cpp - impl/mst_processor_impl.cpp - impl/mst_processor.cpp - ) - -target_link_libraries(mst_processor - mst_storage - mst_transport - rxcpp - logger - common - ) - -add_library(mst_hash - impl/hash.cpp - ) - -target_link_libraries(mst_hash - shared_model_interfaces - ) diff --git a/irohad/multi_sig_transactions/gossip_propagation_strategy.hpp b/irohad/multi_sig_transactions/gossip_propagation_strategy.hpp deleted file mode 100644 index 93e07b92bec..00000000000 --- a/irohad/multi_sig_transactions/gossip_propagation_strategy.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_GOSSIP_PROPAGATION_STRATEGY_HPP -#define IROHA_GOSSIP_PROPAGATION_STRATEGY_HPP - -#include -#include -#include - -#include -#include "ametsuchi/peer_query_factory.hpp" -#include "multi_sig_transactions/gossip_propagation_strategy_params.hpp" -#include "multi_sig_transactions/mst_propagation_strategy.hpp" - -#include - -namespace iroha { - - /** - * This class provides strategy for propagation states in network - * Emits exactly (or zero if provider is empty) amount of peers - * at some period - * note: it can be inconsistent with the peer provider - */ - class GossipPropagationStrategy : public PropagationStrategy { - public: - using PeerProviderFactory = std::shared_ptr; - using OptPeer = boost::optional; - /** - * Initialize strategy with - * @param peer_factory is a provider of peer list - * @param emit_worker is the coordinator for the data emitting - * @param params configuration parameters - */ - GossipPropagationStrategy( - // TODO 30.01.2019 lebdron: IR-266 Remove PeerQueryFactory - PeerProviderFactory peer_factory, - rxcpp::observe_on_one_worker emit_worker, - const GossipPropagationStrategyParams ¶ms); - - ~GossipPropagationStrategy(); - - // ------------------| PropagationStrategy override |------------------ - - rxcpp::observable emitter() override; - - // --------------------------| end override |--------------------------- - private: - /** - * Source of peers for propagation - */ - PeerProviderFactory peer_factory; - - /** - * Cache of peer provider's data - */ - PropagationData last_data; - - /** - * Queue that contains non-emitted indexes of peers - */ - std::vector non_visited; - - /** - * Worker that performs internal loop handling - */ - rxcpp::observe_on_one_worker emit_worker; - - /* - * Observable for the emitting propagated data - */ - rxcpp::observable emitent; - - /* - * Mutex for handling observable stopping - */ - std::mutex m; - - /** - * Fill a queue with a random ordered list of peers - * @return true if query to PeerProvider was successful - */ - bool initQueue(); - - /** - * Visit next element of non_visited - * @return following peer - */ - OptPeer visit(); - }; -} // namespace iroha - -#endif // IROHA_GOSSIP_PROPAGATION_STRATEGY_HPP diff --git a/irohad/multi_sig_transactions/gossip_propagation_strategy_params.hpp b/irohad/multi_sig_transactions/gossip_propagation_strategy_params.hpp deleted file mode 100644 index 2c4b528675b..00000000000 --- a/irohad/multi_sig_transactions/gossip_propagation_strategy_params.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_GOSSIP_PROPAGATION_STRATEGY_PARAMS_HPP -#define IROHA_GOSSIP_PROPAGATION_STRATEGY_PARAMS_HPP - -#include - -#include - -// TODO: IR-1317 @l4l (02/05/18) magics should be replaced with options via -// cli parameters -static constexpr std::chrono::milliseconds kDefaultPeriod = - std::chrono::seconds(5); -static constexpr uint32_t kDefaultAmount = 2; - -namespace iroha { - /** - * This structure provides configuration parameters for propagation strategy - */ - struct GossipPropagationStrategyParams { - /// period of emitting data in ms - std::chrono::milliseconds emission_period{kDefaultPeriod}; - - /// amount of data (peers) emitted per once - uint32_t amount_per_once{kDefaultAmount}; - }; - -} // namespace iroha - -#endif // IROHA_GOSSIP_PROPAGATION_STRATEGY_PARAMS_HPP diff --git a/irohad/multi_sig_transactions/hash.hpp b/irohad/multi_sig_transactions/hash.hpp deleted file mode 100644 index 36a0c6c9403..00000000000 --- a/irohad/multi_sig_transactions/hash.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_HASH_HPP -#define IROHA_HASH_HPP - -#include "multi_sig_transactions/mst_types.hpp" - -namespace iroha { - namespace model { - /** - * Hash calculation factory for batch - */ - class PointerBatchHasher { - public: - size_t operator()(const DataType &batch) const; - }; - } // namespace model -} // namespace iroha - -#endif // IROHA_HASH_HPP diff --git a/irohad/multi_sig_transactions/impl/gossip_propagation_strategy.cpp b/irohad/multi_sig_transactions/impl/gossip_propagation_strategy.cpp deleted file mode 100644 index 1a6e942d645..00000000000 --- a/irohad/multi_sig_transactions/impl/gossip_propagation_strategy.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/gossip_propagation_strategy.hpp" - -#include -#include - -#include -#include -#include -#include "common/bind.hpp" - -namespace iroha { - - using PropagationData = PropagationStrategy::PropagationData; - using OptPeer = GossipPropagationStrategy::OptPeer; - using PeerProviderFactory = GossipPropagationStrategy::PeerProviderFactory; - using std::chrono::steady_clock; - - GossipPropagationStrategy::GossipPropagationStrategy( - PeerProviderFactory peer_factory, - rxcpp::observe_on_one_worker emit_worker, - const GossipPropagationStrategyParams ¶ms) - : peer_factory(peer_factory), - non_visited({}), - emit_worker(emit_worker), - emitent(rxcpp::observable<>::interval( - steady_clock::now(), params.emission_period, emit_worker) - .map([this, params](int) { - PropagationData vec; - auto range = boost::irange(0u, params.amount_per_once); - // push until find empty element - std::find_if_not( - range.begin(), range.end(), [this, &vec](int) { - return this->visit() | [&vec](auto e) -> bool { - vec.push_back(e); - return true; // proceed - }; - }); - return vec; - })) {} - - rxcpp::observable GossipPropagationStrategy::emitter() { - return emitent; - } - - GossipPropagationStrategy::~GossipPropagationStrategy() { - // Make sure that emitent callback have finish and haven't started yet - std::lock_guard lock(m); - peer_factory.reset(); - } - - bool GossipPropagationStrategy::initQueue() { - return peer_factory->createPeerQuery() | [](const auto &query) { - return query->getLedgerPeers(false); - } | [](auto &&data) -> boost::optional { - if (data.size() == 0) { - return {}; - } - return std::move(data); - } | [this](auto &&data) -> bool { // nullopt implicitly casts to false - this->last_data = std::move(data); - this->non_visited.resize(this->last_data.size()); - std::iota(this->non_visited.begin(), this->non_visited.end(), 0); - std::shuffle(this->non_visited.begin(), - this->non_visited.end(), - std::default_random_engine{}); - return true; - }; - } - - OptPeer GossipPropagationStrategy::visit() { - std::lock_guard lock(m); - if (not peer_factory or (non_visited.empty() and not initQueue())) { - // either PeerProvider doesn't gives peers / dtor have been called - return {}; - } - // or non_visited non-empty - BOOST_ASSERT(not non_visited.empty()); - BOOST_ASSERT(non_visited.back() < last_data.size()); - - auto el = last_data[non_visited.back()]; - non_visited.pop_back(); - return el; - } - -} // namespace iroha diff --git a/irohad/multi_sig_transactions/impl/hash.cpp b/irohad/multi_sig_transactions/impl/hash.cpp deleted file mode 100644 index 41ecdde36ab..00000000000 --- a/irohad/multi_sig_transactions/impl/hash.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/hash.hpp" - -#include -#include - -#include -#include "cryptography/blob.hpp" -#include "interfaces/common_objects/peer.hpp" -#include "interfaces/iroha_internal/transaction_batch.hpp" - -namespace iroha { - namespace model { - - size_t PointerBatchHasher::operator()(const DataType &batch) const { - return std::hash{}(batch->reducedHash().hex()); - } - - } // namespace model -} // namespace iroha diff --git a/irohad/multi_sig_transactions/impl/mst_processor.cpp b/irohad/multi_sig_transactions/impl/mst_processor.cpp deleted file mode 100644 index 08b1644d970..00000000000 --- a/irohad/multi_sig_transactions/impl/mst_processor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/mst_processor.hpp" - -#include - -namespace iroha { - - MstProcessor::MstProcessor(logger::LoggerPtr log) : log_(std::move(log)) {} - - void MstProcessor::propagateBatch(const DataType &batch) { - this->propagateBatchImpl(batch); - } - - rxcpp::observable> MstProcessor::onStateUpdate() - const { - return this->onStateUpdateImpl(); - } - - rxcpp::observable MstProcessor::onPreparedBatches() const { - return this->onPreparedBatchesImpl(); - } - - rxcpp::observable MstProcessor::onExpiredBatches() const { - return this->onExpiredBatchesImpl(); - } - - bool MstProcessor::batchInStorage(const DataType &batch) const { - return this->batchInStorageImpl(batch); - } - -} // namespace iroha diff --git a/irohad/multi_sig_transactions/impl/mst_processor_impl.cpp b/irohad/multi_sig_transactions/impl/mst_processor_impl.cpp deleted file mode 100644 index ffa8abb6846..00000000000 --- a/irohad/multi_sig_transactions/impl/mst_processor_impl.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/mst_processor_impl.hpp" - -#include -#include -#include -#include -#include -#include - -#include "logger/logger.hpp" -#include "main/subscription.hpp" - -using shared_model::interface::types::PublicKeyHexStringView; - -namespace { - using namespace iroha; - - auto sendState(std::weak_ptr log, - std::weak_ptr transport, - std::weak_ptr storage, - std::weak_ptr time_provider) { - return - [log_ = std::move(log), - transport_ = std::move(transport), - storage_ = std::move(storage), - time_provider_ = std::move(time_provider)](auto tpl) - -> rxcpp::observable, // to this peer - MstState // this state - >> { - auto &[dst_peer, size] = tpl; - - auto log = log_.lock(); - auto transport = transport_.lock(); - auto storage = storage_.lock(); - auto time_provider = time_provider_.lock(); - - if (log and transport and storage and time_provider) { - auto current_time = time_provider->getCurrentTime(); - auto diff = storage->getDiffState( - PublicKeyHexStringView{dst_peer->pubkey()}, current_time); - if (not diff.isEmpty()) { - log->info("Propagate new data[{}]", size); - return transport->sendState(dst_peer, diff) - .take(1) - .filter([](auto is_ok) { return is_ok; }) - .map([dst_peer = std::move(dst_peer), - diff = std::move(diff)](auto) { - return std::make_tuple(std::move(dst_peer), - std::move(diff)); - }); - } - } - - return rxcpp::observable<>::empty< - std::tuple, - MstState>>(); - }; - } - - auto onSendStateResponse(std::weak_ptr storage) { - return [storage_ = std::move(storage)](auto tpl) { - auto &[dst_peer, diff] = tpl; - - auto storage = storage_.lock(); - if (storage) { - storage->apply(PublicKeyHexStringView{dst_peer->pubkey()}, diff); - } - }; - } - - auto notifyMstMetrics(MstStorage const &storage) { - auto number_of_batches_and_txs = - dynamic_cast(&storage)->countBatchesTxs(); - iroha::getSubscription()->notify(kOnMstMetrics, number_of_batches_and_txs); - } -} // namespace - -namespace iroha { - - FairMstProcessor::FairMstProcessor( - std::shared_ptr transport, - std::shared_ptr storage, - std::shared_ptr strategy, - std::shared_ptr time_provider, - logger::LoggerPtr log) - : MstProcessor(log), // use the same logger in base class - log_(std::move(log)), - transport_(std::move(transport)), - storage_(std::move(storage)), - strategy_(std::move(strategy)), - time_provider_(std::move(time_provider)), - propagation_subscriber_( - strategy_->emitter() - .flat_map([](auto data) { - return rxcpp::observable<>::iterate(data).map( - [size = data.size()](auto dst_peer) { - return std::make_tuple(std::move(dst_peer), size); - }); - }) - .flat_map(sendState(log_, transport_, storage_, time_provider_)) - .subscribe(onSendStateResponse(storage_))), - expirator_thread_([this]() { - using namespace std::chrono_literals; - do { - assert(storage_); - assert(time_provider_); - expiredBatchesNotify(storage_->extractExpiredTransactions( - time_provider_->getCurrentTime())); - notifyMstMetrics(*storage_); - } while (not expiration_thread_stopper_waiter_.wait(10s)); - }) {} - - FairMstProcessor::~FairMstProcessor() { - propagation_subscriber_.unsubscribe(); - expiration_thread_stopper_waiter_.set(); // notify thread to stop working - if (expirator_thread_.joinable()) - expirator_thread_.join(); - } - - // -------------------------| MstProcessor override |------------------------- - - auto FairMstProcessor::propagateBatchImpl(const iroha::DataType &batch) - -> decltype(propagateBatch(batch)) { - auto state_update = storage_->updateOwnState(batch); - completedBatchesNotify(*state_update.completed_state_); - updatedBatchesNotify(*state_update.updated_state_); - expiredBatchesNotify( - storage_->extractExpiredTransactions(time_provider_->getCurrentTime())); - notifyMstMetrics(*storage_); - } - - auto FairMstProcessor::onStateUpdateImpl() const - -> decltype(onStateUpdate()) { - return state_subject_.get_observable(); - } - - auto FairMstProcessor::onPreparedBatchesImpl() const - -> decltype(onPreparedBatches()) { - return batches_subject_.get_observable(); - } - - auto FairMstProcessor::onExpiredBatchesImpl() const - -> decltype(onExpiredBatches()) { - return expired_subject_.get_observable(); - } - - bool FairMstProcessor::batchInStorageImpl(const DataType &batch) const { - return storage_->batchInStorage(batch); - } - - // -------------------| MstTransportNotification override |------------------- - - void FairMstProcessor::onNewState(PublicKeyHexStringView from, - MstState &&new_state) { - log_->info("Applying new state"); - auto current_time = time_provider_->getCurrentTime(); - - // no need to add already expired batches to local state - new_state.eraseExpired(current_time); - auto state_update = storage_->apply(from, new_state); - - // updated batches - updatedBatchesNotify(*state_update.updated_state_); - log_->info("New batches size: {}", - state_update.updated_state_->getBatches().size()); - - // completed batches - completedBatchesNotify(*state_update.completed_state_); - - // expired batches - // not nesessary to do it right here, just use the occasion to clean storage - expiredBatchesNotify(storage_->extractExpiredTransactions(current_time)); - - notifyMstMetrics(*storage_); - } - - // -----------------------------| private api |----------------------------- - - // TODO [IR-1687] Akvinikym 10.09.18: three methods below should be one - void FairMstProcessor::completedBatchesNotify(MstState const &state) const { - if (not state.isEmpty()) { - state.iterateBatches([this](const auto &batch) { - batches_subject_.get_subscriber().on_next(batch); - }); - } - } - - void FairMstProcessor::updatedBatchesNotify(MstState const &state) const { - if (not state.isEmpty()) { - state_subject_.get_subscriber().on_next( - std::make_shared(state)); - } - } - - void FairMstProcessor::expiredBatchesNotify(MstState const &state) const { - if (not state.isEmpty()) { - state.iterateBatches([this](const auto &batch) { - expired_subject_.get_subscriber().on_next(batch); - }); - } - } - -} // namespace iroha diff --git a/irohad/multi_sig_transactions/impl/mst_propagation_strategy_stub.cpp b/irohad/multi_sig_transactions/impl/mst_propagation_strategy_stub.cpp deleted file mode 100644 index c42641b8778..00000000000 --- a/irohad/multi_sig_transactions/impl/mst_propagation_strategy_stub.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/mst_propagation_strategy_stub.hpp" - -#include - -namespace iroha { - rxcpp::observable - PropagationStrategyStub::emitter() { - return rxcpp::observable<>::empty(); - } -} // namespace iroha diff --git a/irohad/multi_sig_transactions/mst_processor.hpp b/irohad/multi_sig_transactions/mst_processor.hpp deleted file mode 100644 index 6468cf802df..00000000000 --- a/irohad/multi_sig_transactions/mst_processor.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_PROPAGATOR_HPP -#define IROHA_MST_PROPAGATOR_HPP - -#include -#include - -#include -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/mst_types.hpp" - -namespace iroha { - - /** - * MstProcessor is responsible for organization of sharing multi-signature - * transactions in network - */ - class MstProcessor { - public: - // ---------------------------| user interface |---------------------------- - - /** - * Propagate batch in network for signing by other - * participants - * @param batch - batch for propagation - */ - void propagateBatch(const DataType &batch); - - /** - * Check, if passed batch is in pending storage - * @param batch to be checked - * @return true, if batch is already in pending storage, false otherwise - */ - bool batchInStorage(const DataType &batch) const; - - /** - * Prove updating of state for handling status of signing - */ - rxcpp::observable> onStateUpdate() const; - - /** - * Observable emit batches which are prepared for further processing in - * system - */ - rxcpp::observable onPreparedBatches() const; - - /** - * Observable emit expired by time transactions - */ - rxcpp::observable onExpiredBatches() const; - - virtual ~MstProcessor() = default; - - protected: - explicit MstProcessor(logger::LoggerPtr log); - - logger::LoggerPtr log_; - - private: - // ------------------------| inheritance interface |------------------------ - - /** - * @see propagateTransaction method - */ - virtual auto propagateBatchImpl(const DataType &batch) - -> decltype(propagateBatch(batch)) = 0; - - /** - * @see onStateUpdate method - */ - virtual auto onStateUpdateImpl() const -> decltype(onStateUpdate()) = 0; - - /** - * @see onPreparedTransactions method - */ - virtual auto onPreparedBatchesImpl() const - -> decltype(onPreparedBatches()) = 0; - - /** - * @see onExpiredTransactions method - */ - virtual auto onExpiredBatchesImpl() const - -> decltype(onExpiredBatches()) = 0; - - /** - * @see batchInStorage method - */ - virtual bool batchInStorageImpl(const DataType &batch) const = 0; - }; -} // namespace iroha - -#endif // IROHA_MST_PROPAGATOR_HPP diff --git a/irohad/multi_sig_transactions/mst_processor_impl.hpp b/irohad/multi_sig_transactions/mst_processor_impl.hpp deleted file mode 100644 index b5d647c685e..00000000000 --- a/irohad/multi_sig_transactions/mst_processor_impl.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_PROCESSOR_IMPL_HPP -#define IROHA_MST_PROCESSOR_IMPL_HPP - -#include "multi_sig_transactions/mst_processor.hpp" -#include "network/mst_transport.hpp" - -#include - -#include -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/mst_propagation_strategy.hpp" -#include "multi_sig_transactions/mst_time_provider.hpp" -#include "multi_sig_transactions/storage/mst_storage.hpp" -#include "common/common.hpp" - -namespace iroha { - - /** - * Effective implementation of MstProcessor, - * that implements gossip propagation of own state - */ - class FairMstProcessor : public MstProcessor, - public iroha::network::MstTransportNotification { - public: - /** - * @param transport - connection to other peers in network - * @param storage - repository for storing states - * @param strategy - propagation mechanism for sharing state with others - * @param time_provider - repository of current time - */ - FairMstProcessor(std::shared_ptr transport, - std::shared_ptr storage, - std::shared_ptr strategy, - std::shared_ptr time_provider, - logger::LoggerPtr log); - - ~FairMstProcessor(); - - // ------------------------| MstProcessor override |------------------------ - - auto propagateBatchImpl(const DataType &batch) - -> decltype(propagateBatch(batch)) override; - - auto onStateUpdateImpl() const -> decltype(onStateUpdate()) override; - - auto onPreparedBatchesImpl() const - -> decltype(onPreparedBatches()) override; - - auto onExpiredBatchesImpl() const -> decltype(onExpiredBatches()) override; - - bool batchInStorageImpl(const DataType &batch) const override; - - // ------------------| MstTransportNotification override |------------------ - - void onNewState(shared_model::interface::types::PublicKeyHexStringView from, - MstState &&new_state) override; - - // ----------------------------| end override |----------------------------- - - private: - // -----------------------------| private api |----------------------------- - - /** - * Notify subscribers when some of the batches received all necessary - * signatures and ready to move forward - * @param state with those batches - */ - void completedBatchesNotify(MstState const& state) const; - - /** - * Notify subscribers when some of the batches received new signatures, but - * still are not completed - * @param state with those batches - */ - void updatedBatchesNotify(MstState const& state) const; - - /** - * Notify subscribers when some of the batches get expired - * @param state with those batches - */ - void expiredBatchesNotify(MstState const& state) const; - - // -------------------------------| fields |-------------------------------- - logger::LoggerPtr log_; - - std::shared_ptr transport_; - std::shared_ptr storage_; - std::shared_ptr strategy_; - std::shared_ptr time_provider_; - - // rx subjects - - /// use for share new states from other peers - rxcpp::subjects::subject> state_subject_; - - /// use for share completed batches - rxcpp::subjects::subject batches_subject_; - - /// use for share expired batches - rxcpp::subjects::subject expired_subject_; - - /// use for tracking the propagation subscription - - rxcpp::composite_subscription propagation_subscriber_; - - utils::WaitForSingleObject expiration_thread_stopper_waiter_; - std::thread expirator_thread_; - }; -} // namespace iroha - -#endif // IROHA_MST_PROCESSOR_IMPL_HPP diff --git a/irohad/multi_sig_transactions/mst_propagation_strategy.hpp b/irohad/multi_sig_transactions/mst_propagation_strategy.hpp deleted file mode 100644 index a2844e74318..00000000000 --- a/irohad/multi_sig_transactions/mst_propagation_strategy.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_PROPAGATION_STRATEGY_HPP -#define IROHA_MST_PROPAGATION_STRATEGY_HPP - -#include -#include -#include "interfaces/common_objects/peer.hpp" - -namespace iroha { - - /** - * Interface provides strategy for propagation states in network - */ - class PropagationStrategy { - public: - virtual ~PropagationStrategy() = default; - using PropagationData = - std::vector>; - - /** - * Provides observable that will be emit new results - * with respect to own strategy - */ - virtual rxcpp::observable emitter() = 0; - }; -} // namespace iroha - -#endif // IROHA_MST_PROPAGATION_STRATEGY_HPP diff --git a/irohad/multi_sig_transactions/mst_propagation_strategy_stub.hpp b/irohad/multi_sig_transactions/mst_propagation_strategy_stub.hpp deleted file mode 100644 index 2515a6b84e8..00000000000 --- a/irohad/multi_sig_transactions/mst_propagation_strategy_stub.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_PROPAGATION_STRATEGY_STUB_HPP -#define IROHA_PROPAGATION_STRATEGY_STUB_HPP - -#include "multi_sig_transactions/mst_propagation_strategy.hpp" - -namespace iroha { - class PropagationStrategyStub : public PropagationStrategy { - rxcpp::observable emitter() override; - }; -} // namespace iroha - -#endif // IROHA_PROPAGATION_STRATEGY_STUB_HPP diff --git a/irohad/multi_sig_transactions/mst_time_provider.hpp b/irohad/multi_sig_transactions/mst_time_provider.hpp deleted file mode 100644 index 90a3f0c0f46..00000000000 --- a/irohad/multi_sig_transactions/mst_time_provider.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_TIME_PROVIDER_HPP -#define IROHA_MST_TIME_PROVIDER_HPP - -#include "multi_sig_transactions/mst_types.hpp" - -namespace iroha { - - /** - * Interface provides current time for iroha - */ - class MstTimeProvider { - public: - virtual ~MstTimeProvider() = default; - /** - * Fetching current time in system - * @return current time - */ - virtual TimeType getCurrentTime() const = 0; - }; -} // namespace iroha - -#endif // IROHA_MST_TIME_PROVIDER_HPP diff --git a/irohad/multi_sig_transactions/mst_time_provider_impl.hpp b/irohad/multi_sig_transactions/mst_time_provider_impl.hpp deleted file mode 100644 index 0bd69682f58..00000000000 --- a/irohad/multi_sig_transactions/mst_time_provider_impl.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_TIME_PROVIDER_IMPL_HPP -#define IROHA_MST_TIME_PROVIDER_IMPL_HPP - -#include -#include "multi_sig_transactions/mst_time_provider.hpp" - -namespace iroha { - - class MstTimeProviderImpl : public MstTimeProvider { - public: - TimeType getCurrentTime() const override { - return std::chrono::system_clock::now().time_since_epoch() - / std::chrono::milliseconds(1); - } - }; -} // namespace iroha - -#endif // IROHA_MST_TIME_PROVIDER_IMPL_HPP diff --git a/irohad/multi_sig_transactions/mst_types.hpp b/irohad/multi_sig_transactions/mst_types.hpp deleted file mode 100644 index 26cce069033..00000000000 --- a/irohad/multi_sig_transactions/mst_types.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_TYPES_HPP -#define IROHA_MST_TYPES_HPP - -#include - -#include "interfaces/common_objects/types.hpp" - -namespace shared_model { - namespace interface { - class TransactionBatch; - class TransactionResponse; - class Peer; - } // namespace interface -} // namespace shared_model - -namespace iroha { - - using BatchPtr = std::shared_ptr; - using TimeType = shared_model::interface::types::TimestampType; - using TxResponse = - std::shared_ptr; - using DataType = BatchPtr; - - class Completer; - class MstState; - - /** - * Contains result of updating local state: - * - state with completed batches - * - state with updated (still not enough signatures) batches - */ - struct StateUpdateResult { - StateUpdateResult(std::shared_ptr completed_state, - std::shared_ptr updated_state) - : completed_state_{std::move(completed_state)}, - updated_state_{std::move(updated_state)} {} - std::shared_ptr completed_state_; - std::shared_ptr updated_state_; - }; -} // namespace iroha - -#endif // IROHA_MST_TYPES_HPP diff --git a/irohad/multi_sig_transactions/state/CMakeLists.txt b/irohad/multi_sig_transactions/state/CMakeLists.txt deleted file mode 100644 index aac120cce43..00000000000 --- a/irohad/multi_sig_transactions/state/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright Soramitsu Co., Ltd. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -add_library(mst_state - impl/mst_state.cpp - ) - -target_link_libraries(mst_state - mst_hash - Boost::boost - common - logger - ) diff --git a/irohad/multi_sig_transactions/state/impl/mst_state.cpp b/irohad/multi_sig_transactions/state/impl/mst_state.cpp deleted file mode 100644 index 6a0f256261b..00000000000 --- a/irohad/multi_sig_transactions/state/impl/mst_state.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/state/mst_state.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "interfaces/transaction.hpp" -#include "logger/logger.hpp" - -namespace { - shared_model::interface::types::TimestampType oldestTimestamp( - const iroha::BatchPtr &batch) { - const bool batch_is_empty = boost::empty(batch->transactions()); - assert(not batch_is_empty); - if (batch_is_empty) { - return 0; - } - auto timestamps = - batch->transactions() - | boost::adaptors::transformed( - +[](const std::shared_ptr - &tx) { return tx->createdTime(); }); - const auto min_it = - boost::first_min_element(timestamps.begin(), timestamps.end()); - assert(min_it != timestamps.end()); - return min_it == timestamps.end() ? 0 : *min_it; - } -} // namespace - -namespace iroha { - DefaultCompleter::DefaultCompleter(std::chrono::minutes expiration_time) - : expiration_time_(expiration_time) {} - - bool DefaultCompleter::isCompleted(const DataType &batch) const { - return std::all_of(batch->transactions().begin(), - batch->transactions().end(), - [](const auto &tx) { - return boost::size(tx->signatures()) >= tx->quorum(); - }); - } - - bool DefaultCompleter::isExpired(const DataType &batch, - const TimeType ¤t_time) const { - return oldestTimestamp(batch) - + expiration_time_ / std::chrono::milliseconds(1) - < current_time; - } - - // ------------------------------| public api |------------------------------- - - MstState MstState::empty(logger::LoggerPtr log, - const CompleterType &completer) { - return MstState(completer, std::move(log)); - } - - StateUpdateResult MstState::operator+=(const BatchPtr &rhs) { - auto state_update = StateUpdateResult{ - std::make_shared(MstState::empty(log_, completer_)), - std::make_shared(MstState::empty(log_, completer_))}; - insertOne(state_update, rhs); - return state_update; - } - - StateUpdateResult MstState::operator+=(const MstState &rhs) { - auto state_update = StateUpdateResult{ - std::make_shared(MstState::empty(log_, completer_)), - std::make_shared(MstState::empty(log_, completer_))}; - for (auto &&rhs_tx : rhs.batches_.right | boost::adaptors::map_keys) { - insertOne(state_update, rhs_tx); - } - return state_update; - } - - MstState MstState::operator-(const MstState &rhs) const { - const auto &my_batches = batches_.right | boost::adaptors::map_keys; - std::vector difference; - difference.reserve(boost::size(batches_)); - for (const auto &batch : my_batches) { - auto it = rhs.batches_.right.find(batch); - if (it == rhs.batches_.right.end() - or not boost::range::equal( - batch->transactions() | boost::adaptors::indirected, - it->first->transactions() | boost::adaptors::indirected)) { - difference.push_back(batch); - } - } - return MstState(this->completer_, difference, log_); - } - - bool MstState::isEmpty() const { - assert(batches_.empty() == batches_to_hash_.empty()); - return batches_.empty(); - } - - std::unordered_set - MstState::getBatches() const { - const auto batches_range = batches_.right | boost::adaptors::map_keys; - return {batches_range.begin(), batches_range.end()}; - } - - MstState MstState::extractExpired(const TimeType ¤t_time) { - MstState out = MstState::empty(log_, completer_); - extractExpiredImpl(current_time, out); - return out; - } - - void MstState::eraseExpired(const TimeType ¤t_time) { - extractExpiredImpl(current_time, boost::none); - } - - void MstState::eraseByTransactionHash( - const shared_model::interface::types::HashType &hash) { - auto it = batches_to_hash_.left.find(hash); - if (it != batches_to_hash_.left.end()) { - batches_.right.erase(it->second); - batches_to_hash_.left.erase(it); - } - } - - // ------------------------------| private api |------------------------------ - - /** - * Merge signatures in batches - * @param target - batch for inserting - * @param donor - batch with transactions to copy signatures from - * @return return if at least one new signature was inserted - */ - bool mergeSignaturesInBatch(DataType &target, const DataType &donor) { - auto inserted_new_signatures = false; - for (auto zip : - boost::combine(target->transactions(), donor->transactions())) { - const auto &target_tx = zip.get<0>(); - const auto &donor_tx = zip.get<1>(); - inserted_new_signatures = std::accumulate( - std::begin(donor_tx->signatures()), - std::end(donor_tx->signatures()), - inserted_new_signatures, - [&target_tx](bool accumulator, const auto &signature) { - return target_tx->addSignature( - shared_model::interface::types::SignedHexStringView{ - signature.signedData()}, - shared_model::interface::types::PublicKeyHexStringView{ - signature.publicKey()}) - or accumulator; - }); - } - return inserted_new_signatures; - } - - MstState::MstState(CompleterType const &completer, logger::LoggerPtr log) - : MstState(completer, std::vector{}, std::move(log)) {} - - MstState::MstState(CompleterType const &completer, - BatchesForwardCollectionType const &batches, - logger::LoggerPtr log) - : completer_(completer), log_(std::move(log)) { - for (auto const &batch : batches) { - rawInsert(batch); - } - } - - void MstState::insertOne(StateUpdateResult &state_update, - const DataType &rhs_batch) { - log_->info("batch: {}", *rhs_batch); - auto corresponding = batches_.right.find(rhs_batch); - if (corresponding == batches_.right.end()) { - // when this state does not contain transaction - rawInsert(rhs_batch); - state_update.updated_state_->rawInsert(rhs_batch); - return; - } - - BatchPtr found = corresponding->first; - // Append new signatures to the existing state - auto inserted_new_signatures = mergeSignaturesInBatch(found, rhs_batch); - - if (completer_->isCompleted(found)) { - // state already has completed transaction, - // remove from state and return it - batches_to_hash_.right.erase(found); - batches_.right.erase(found); - state_update.completed_state_->rawInsert(found); - return; - } - - // if batch still isn't completed, return it, if new signatures were - // inserted - if (inserted_new_signatures) { - state_update.updated_state_->rawInsert(found); - } - } - - void MstState::rawInsert(const DataType &rhs_batch) { - for (auto &tx : rhs_batch->transactions()) { - batches_to_hash_.insert({tx->hash(), rhs_batch}); - } - batches_.insert({oldestTimestamp(rhs_batch), rhs_batch}); - } - - bool MstState::contains(const DataType &element) const { - auto const result = batches_.right.find(element) != batches_.right.end(); - assert(result - == (batches_to_hash_.right.find(element) - != batches_to_hash_.right.end())); - return result; - } - - void MstState::extractExpiredImpl(const TimeType ¤t_time, - boost::optional extracted) { - for (auto it = batches_.left.begin(); it != batches_.left.end() - and completer_->isExpired(it->second, current_time);) { - if (extracted) { - *extracted += it->second; - } - batches_to_hash_.right.erase(it->second); - it = batches_.left.erase(it); - assert(it == batches_.left.begin()); - } - } - -} // namespace iroha diff --git a/irohad/multi_sig_transactions/state/mst_state.hpp b/irohad/multi_sig_transactions/state/mst_state.hpp deleted file mode 100644 index a97f5a43e84..00000000000 --- a/irohad/multi_sig_transactions/state/mst_state.hpp +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_STATE_HPP -#define IROHA_MST_STATE_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cryptography/hash.hpp" -#include "interfaces/iroha_internal/transaction_batch.hpp" -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/hash.hpp" -#include "multi_sig_transactions/mst_types.hpp" - -namespace iroha { - - /** - * Completer is strategy for verification batches on - * completeness and expiration - */ - class Completer { - public: - /** - * Verify that batch is completed - * @param batch - target object for verification - * @return true, if complete - */ - virtual bool isCompleted(const DataType &batch) const = 0; - - /** - * Check whether the batch has expired - * @param batch - object for validation - * @param current_time - current time - * @return true, if the batch has expired - */ - virtual bool isExpired(const DataType &batch, - const TimeType ¤t_time) const = 0; - - virtual ~Completer() = default; - }; - - /** - * Class provides the default behavior for the batch completer. - * Complete, if all transactions have at least quorum number of signatures. - * Expired if at least one transaction is expired. - */ - class DefaultCompleter : public Completer { - public: - /** - * Creates new Completer with a given expiration time for transactions - * @param expiration_time - expiration time in minutes - */ - explicit DefaultCompleter(std::chrono::minutes expiration_time); - - bool isCompleted(const DataType &batch) const override; - - bool isExpired(const DataType &tx, - const TimeType ¤t_time) const override; - - private: - std::chrono::minutes expiration_time_; - }; - - using CompleterType = std::shared_ptr; - - class MstState { - public: - // -----------------------------| public api |------------------------------ - - /** - * Create empty state - * @param log - the logger to use in the new object - * @param completer - strategy for determine completed and expired batches - * @return empty mst state - */ - static MstState empty(logger::LoggerPtr log, - const CompleterType &completer); - - /** - * Add batch to current state - * @param rhs - batch for insertion - * @return States with completed and updated batches - */ - StateUpdateResult operator+=(const DataType &rhs); - - /** - * Concat internal data of states - * @param rhs - object for merging - * @return States with completed and updated batches - */ - StateUpdateResult operator+=(const MstState &rhs); - - /** - * Operator provide difference between this and rhs operator - * @param rhs, state for removing - * @return State that provide difference between left and right states - * axiom operators: - * A V B == B V A - * A V B == B V (A \ B) - */ - MstState operator-(const MstState &rhs) const; - - /** - * @return true, if there is no batches inside - */ - bool isEmpty() const; - - /** - * @return the batches from the state - */ - std::unordered_set - getBatches() const; - - /** - * Erase and return expired batches - * @param current_time - current time - * @return state with expired batches - */ - MstState extractExpired(const TimeType ¤t_time); - - /** - * Erase expired batches - * @param current_time - current time - */ - void eraseExpired(const TimeType ¤t_time); - - /** - * Erase batch by transaction hash - */ - void eraseByTransactionHash( - const shared_model::interface::types::HashType &hash); - - /** - * Check, if this MST state contains that element - * @param element to be checked - * @return true, if state contains the element, false otherwise - */ - bool contains(const BatchPtr &element) const; - - /// Apply visitor to all batches. - template - inline void iterateBatches(const Visitor &visitor) const { - const auto batches_range = batches_.right | boost::adaptors::map_keys; - std::for_each(batches_range.begin(), batches_range.end(), visitor); - } - - /// Apply visitor to all transactions. - template - inline void iterateTransactions(const Visitor &visitor) const { - for (const auto &batch : batches_.right | boost::adaptors::map_keys) { - std::for_each(batch->transactions().begin(), - batch->transactions().end(), - visitor); - } - } - - size_t count_transactions() const { - size_t cnt = 0; - iterateBatches( - [&cnt](auto const &ba) { cnt += boost::size(ba->transactions()); }); - return cnt; - } - - size_t count_batches() const { - return boost::size(batches_); - } - - private: - // --------------------------| private api |------------------------------ - - using BatchesForwardCollectionType = boost:: - any_range; - - using BatchesToHashBimap = - boost::bimap, - boost::bimaps::unordered_multiset_of< - BatchPtr, - iroha::model::PointerBatchHasher, - shared_model::interface::BatchHashEquality>>; - - using BatchesBimap = - boost::bimap, - boost::bimaps::unordered_set_of< - BatchPtr, - iroha::model::PointerBatchHasher, - shared_model::interface::BatchHashEquality>>; - - MstState(CompleterType const &completer, logger::LoggerPtr log); - - MstState(CompleterType const &completer, - BatchesForwardCollectionType const &batches, - logger::LoggerPtr log); - - /** - * Insert batch in own state and push it in out_completed_state or - * out_updated_state - * @param state_update consists of states with updated and completed batches - * @param rhs_tx - batch for insert - */ - void insertOne(StateUpdateResult &state_update, const DataType &rhs_tx); - - /** - * Insert new value in state with keeping invariant - * @param rhs_tx - data for insertion - */ - void rawInsert(const DataType &rhs_tx); - - /** - * Erase expired batches, optionally returning them. - * @param current_time - current time - * @param extracted - optional storage for extracted batches. - */ - void extractExpiredImpl(const TimeType ¤t_time, - boost::optional extracted); - - // -----------------------------| fields |------------------------------ - - CompleterType completer_; - - BatchesBimap batches_; - BatchesToHashBimap batches_to_hash_; - - logger::LoggerPtr log_; - }; - -} // namespace iroha - -#endif // IROHA_MST_STATE_HPP diff --git a/irohad/multi_sig_transactions/storage/CMakeLists.txt b/irohad/multi_sig_transactions/storage/CMakeLists.txt deleted file mode 100644 index 2def812301d..00000000000 --- a/irohad/multi_sig_transactions/storage/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright Soramitsu Co., Ltd. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -add_library(mst_storage - impl/mst_storage.cpp - impl/mst_storage_impl.cpp - ) - -target_link_libraries(mst_storage - crypto_blob_hasher - mst_state - logger - ) diff --git a/irohad/multi_sig_transactions/storage/impl/mst_storage.cpp b/irohad/multi_sig_transactions/storage/impl/mst_storage.cpp deleted file mode 100644 index 3736d7822e6..00000000000 --- a/irohad/multi_sig_transactions/storage/impl/mst_storage.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include "multi_sig_transactions/storage/mst_storage.hpp" - -namespace iroha { - MstStorage::MstStorage(logger::LoggerPtr log) : log_{std::move(log)} {} - - StateUpdateResult MstStorage::apply( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const MstState &new_state) { - std::lock_guard lock{this->mutex_}; - return applyImpl(target_peer_key, new_state); - } - - StateUpdateResult MstStorage::updateOwnState(const DataType &tx) { - std::lock_guard lock{this->mutex_}; - return updateOwnStateImpl(tx); - } - - MstState MstStorage::extractExpiredTransactions( - const TimeType ¤t_time) { - std::lock_guard lock{this->mutex_}; - return extractExpiredTransactionsImpl(current_time); - } - - MstState MstStorage::getDiffState( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const TimeType ¤t_time) { - std::lock_guard lock{this->mutex_}; - return getDiffStateImpl(target_peer_key, current_time); - } - - MstState MstStorage::whatsNew(MstState const& new_state) const { - std::lock_guard lock{this->mutex_}; - return whatsNewImpl(new_state); - } - - bool MstStorage::batchInStorage(const DataType &batch) const { - return batchInStorageImpl(batch); - } - - void MstStorage::processFinalizedTransaction( - shared_model::interface::types::HashType const &hash) { - std::lock_guard lock{mutex_}; - processFinalizedTransactionImpl(hash); - } -} // namespace iroha diff --git a/irohad/multi_sig_transactions/storage/impl/mst_storage_impl.cpp b/irohad/multi_sig_transactions/storage/impl/mst_storage_impl.cpp deleted file mode 100644 index 8df5baba141..00000000000 --- a/irohad/multi_sig_transactions/storage/impl/mst_storage_impl.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/storage/mst_storage_impl.hpp" - -namespace iroha { - // ------------------------------| private API |------------------------------ - - auto MstStorageStateImpl::getState( - shared_model::interface::types::PublicKeyHexStringView target_peer_key) { - auto target_state_iter = - peer_states_.find(StringViewOrString{target_peer_key}); - if (target_state_iter == peer_states_.end()) { - return peer_states_ - .emplace(StringViewOrString{std::string{target_peer_key}}, - MstState::empty(mst_state_logger_, completer_)) - .first; - } - return target_state_iter; - } - // -----------------------------| interface API |----------------------------- - MstStorageStateImpl::MstStorageStateImpl(CompleterType const &completer, - logger::LoggerPtr mst_state_logger, - logger::LoggerPtr log) - : MstStorage(log), - completer_(completer), - own_state_(MstState::empty(mst_state_logger, completer_)), - mst_state_logger_(std::move(mst_state_logger)) {} - - auto MstStorageStateImpl::applyImpl( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const MstState &new_state) - -> decltype(apply(target_peer_key, new_state)) { - auto target_state_iter = getState(target_peer_key); - target_state_iter->second += new_state; - return own_state_ += new_state; - } - - auto MstStorageStateImpl::updateOwnStateImpl(const BatchPtr &tx) - -> decltype(updateOwnState(tx)) { - return own_state_ += tx; - } - - auto MstStorageStateImpl::extractExpiredTransactionsImpl( - const TimeType ¤t_time) - -> decltype(extractExpiredTransactions(current_time)) { - for (auto &[peer,state] : peer_states_) { - state.extractExpired(current_time); - } - return own_state_.extractExpired(current_time); - } - - auto MstStorageStateImpl::getDiffStateImpl( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const TimeType ¤t_time) - -> decltype(getDiffState(target_peer_key, current_time)) { - auto target_current_state_iter = getState(target_peer_key); - auto new_diff_state = own_state_ - target_current_state_iter->second; - new_diff_state.eraseExpired(current_time); - return new_diff_state; - } - - auto MstStorageStateImpl::whatsNewImpl(MstState const& new_state) const - -> decltype(whatsNew(new_state)) { - return new_state - own_state_; - } - - bool MstStorageStateImpl::batchInStorageImpl(const DataType &batch) const { - return own_state_.contains(batch); - } - - void MstStorageStateImpl::processFinalizedTransactionImpl( - shared_model::interface::types::HashType const &hash) { - for (auto &p : peer_states_) { - p.second.eraseByTransactionHash(hash); - } - own_state_.eraseByTransactionHash(hash); - } - -} // namespace iroha diff --git a/irohad/multi_sig_transactions/storage/mst_storage.hpp b/irohad/multi_sig_transactions/storage/mst_storage.hpp deleted file mode 100644 index c3fe73d8622..00000000000 --- a/irohad/multi_sig_transactions/storage/mst_storage.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_STORAGE_HPP -#define IROHA_MST_STORAGE_HPP - -#include - -#include "interfaces/common_objects/string_view_types.hpp" -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/mst_types.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" - -namespace iroha { - - /** - * MstStorage responsible for manage own and others MstStates. - * All methods of storage covered by mutex, because we assume that mutex - * possible to execute in concurrent environment. - */ - class MstStorage { - public: - // ------------------------------| user API |------------------------------- - - /** - * Apply new state for peer - * @param target_peer_key - key for for updating state - * @param new_state - state with new data - * @return State with completed or updated batches - * General note: implementation of method covered by lock - */ - StateUpdateResult apply( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const MstState &new_state); - - /** - * Provide updating state of current peer with new transaction - * @param tx - new transaction for insertion in state - * @return completed and updated mst states - * General note: implementation of method covered by lock - */ - StateUpdateResult updateOwnState(const DataType &tx); - - /** - * Remove expired transactions and return them - * @return State with expired transactions - * General note: implementation of method covered by lock - */ - MstState extractExpiredTransactions(const TimeType ¤t_time); - - /** - * Make state based on diff of own and target states. - * All expired transactions will be removed from diff. - * @return difference between own and target state - * General note: implementation of method covered by lock - */ - MstState getDiffState( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const TimeType ¤t_time); - - /** - * Return diff between own and new state - * @param new_state - state with new data - * @return state that contains new data with respect to own state - * General note: implementation of method covered by lock - */ - MstState whatsNew(MstState const& new_state) const; - - /** - * Check, if passed batch is in the storage - * @param batch to be checked - * @return true, if batch is already in the storage, false otherwise - */ - bool batchInStorage(const DataType &batch) const; - - void processFinalizedTransaction( - shared_model::interface::types::HashType const &hash); - - virtual ~MstStorage() = default; - - protected: - // ------------------------------| class API |------------------------------ - - /** - * Constructor provide initialization of protected fields, such as logger. - */ - explicit MstStorage(logger::LoggerPtr log); - - private: - virtual auto applyImpl( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const MstState &new_state) - -> decltype(apply(target_peer_key, new_state)) = 0; - - virtual auto updateOwnStateImpl(const DataType &tx) - -> decltype(updateOwnState(tx)) = 0; - - virtual auto extractExpiredTransactionsImpl(const TimeType ¤t_time) - -> decltype(extractExpiredTransactions(current_time)) = 0; - - virtual auto getDiffStateImpl( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const TimeType ¤t_time) - -> decltype(getDiffState(target_peer_key, current_time)) = 0; - - virtual auto whatsNewImpl(MstState const& new_state) const - -> decltype(whatsNew(new_state)) = 0; - - virtual bool batchInStorageImpl(const DataType &batch) const = 0; - - virtual void processFinalizedTransactionImpl( - shared_model::interface::types::HashType const &hash) = 0; - - // -------------------------------| fields |-------------------------------- - - protected: - mutable std::mutex mutex_; - logger::LoggerPtr log_; - }; -} // namespace iroha -#endif // IROHA_MST_STORAGE_HPP diff --git a/irohad/multi_sig_transactions/storage/mst_storage_impl.hpp b/irohad/multi_sig_transactions/storage/mst_storage_impl.hpp deleted file mode 100644 index 98607086d6c..00000000000 --- a/irohad/multi_sig_transactions/storage/mst_storage_impl.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_STORAGE_IMPL_HPP -#define IROHA_MST_STORAGE_IMPL_HPP - -#include -#include - -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/hash.hpp" -#include "multi_sig_transactions/storage/mst_storage.hpp" - -namespace iroha { - class MstStorageStateImpl : public MstStorage { - private: - // -----------------------------| private API |----------------------------- - - /** - * Return state of a peer by its public key. If state doesn't exist, create - * new empty state and return it. - * @param target_peer_key - public key of the peer for searching - * @return valid iterator for state of peer - */ - auto getState( - shared_model::interface::types::PublicKeyHexStringView target_peer_key); - - public: - // ----------------------------| interface API |---------------------------- - MstStorageStateImpl(CompleterType const &completer, - logger::LoggerPtr mst_state_logger, - logger::LoggerPtr log); - - MstStorageStateImpl(MstStorageStateImpl const &) = delete; - MstStorageStateImpl &operator=(MstStorageStateImpl const &) = delete; - - auto applyImpl( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const MstState &new_state) - -> decltype(apply(target_peer_key, new_state)) override; - - auto updateOwnStateImpl(const DataType &tx) - -> decltype(updateOwnState(tx)) override; - - auto extractExpiredTransactionsImpl(const TimeType ¤t_time) - -> decltype(extractExpiredTransactions(current_time)) override; - - auto getDiffStateImpl( - shared_model::interface::types::PublicKeyHexStringView target_peer_key, - const TimeType ¤t_time) - -> decltype(getDiffState(target_peer_key, current_time)) override; - - auto whatsNewImpl(MstState const &new_state) const - -> decltype(whatsNew(new_state)) override; - - bool batchInStorageImpl(const DataType &batch) const override; - - void processFinalizedTransactionImpl( - shared_model::interface::types::HashType const &hash) override; - - std::tuple countBatchesTxs() const { - std::lock_guard lk(mutex_); - return {own_state_.count_batches(), own_state_.count_transactions()}; - } - - private: - // ---------------------------| private fields |---------------------------- - - const CompleterType completer_; - struct StringViewOrString { - std::string s; - std::string_view v; - - explicit StringViewOrString(std::string_view v) : v(v) {} - explicit StringViewOrString(std::string s) : s(s), v(this->s) {} - - StringViewOrString(StringViewOrString const &o) - : s(o.s), v(not this->s.empty() ? this->s : o.v) {} - StringViewOrString(StringViewOrString &&o) noexcept - : s(std::move(o).s), - v(not this->s.empty() ? this->s : std::move(o).v) {} - - bool operator==(StringViewOrString const &x) const { - return v == x.v; - } - - struct Hash { - std::size_t operator()(StringViewOrString const &x) const { - return std::hash()(x.v); - } - }; - }; - - std::unordered_map - peer_states_; - MstState own_state_; - logger::LoggerPtr mst_state_logger_; - }; -} // namespace iroha - -#endif // IROHA_MST_STORAGE_IMPL_HPP diff --git a/irohad/multi_sig_transactions/transport/CMakeLists.txt b/irohad/multi_sig_transactions/transport/CMakeLists.txt deleted file mode 100644 index 93212681eaf..00000000000 --- a/irohad/multi_sig_transactions/transport/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright Soramitsu Co., Ltd. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -add_library(mst_transport - impl/mst_transport_grpc.cpp - impl/mst_transport_stub.cpp - ) - -target_link_libraries(mst_transport - mst_grpc - mst_state - Boost::boost - common - endpoint - grpc_generic_client_factory - shared_model_interfaces_factories - shared_model_stateless_validation - shared_model_cryptography - shared_model_proto_backend - ) diff --git a/irohad/multi_sig_transactions/transport/impl/mst_transport_grpc.cpp b/irohad/multi_sig_transactions/transport/impl/mst_transport_grpc.cpp deleted file mode 100644 index 27093998ffe..00000000000 --- a/irohad/multi_sig_transactions/transport/impl/mst_transport_grpc.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/transport/mst_transport_grpc.hpp" - -#include -#include -#include "ametsuchi/tx_presence_cache.hpp" -#include "ametsuchi/tx_presence_cache_utils.hpp" -#include "backend/protobuf/deserialize_repeated_transactions.hpp" -#include "backend/protobuf/transaction.hpp" -#include "interfaces/common_objects/string_view_types.hpp" -#include "interfaces/iroha_internal/parse_and_create_batches.hpp" -#include "interfaces/iroha_internal/transaction_batch.hpp" -#include "interfaces/transaction.hpp" -#include "logger/logger.hpp" -#include "multi_sig_transactions/mst_types.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" -#include "network/impl/client_factory.hpp" -#include "validators/field_validator.hpp" - -using namespace iroha; -using namespace iroha::network; - -using shared_model::interface::types::PublicKeyHexStringView; - -MstTransportGrpc::MstTransportGrpc( - std::shared_ptr> async_call, - std::shared_ptr transaction_factory, - std::shared_ptr - batch_parser, - std::shared_ptr - transaction_batch_factory, - std::shared_ptr tx_presence_cache, - std::shared_ptr mst_completer, - PublicKeyHexStringView my_key, - logger::LoggerPtr mst_state_logger, - logger::LoggerPtr log, - std::unique_ptr client_factory) - : async_call_(std::move(async_call)), - transaction_factory_(std::move(transaction_factory)), - batch_parser_(std::move(batch_parser)), - batch_factory_(std::move(transaction_batch_factory)), - tx_presence_cache_(std::move(tx_presence_cache)), - mst_completer_(std::move(mst_completer)), - my_key_(my_key), - mst_state_logger_(std::move(mst_state_logger)), - log_(std::move(log)), - client_factory_(std::move(client_factory)) {} - -grpc::Status MstTransportGrpc::SendState( - ::grpc::ServerContext *context, - const ::iroha::network::transport::MstState *request, - ::google::protobuf::Empty *response) { - log_->info("MstState Received"); - - auto transactions = shared_model::proto::deserializeTransactions( - *transaction_factory_, request->transactions()); - if (auto e = expected::resultToOptionalError(transactions)) { - log_->warn( - "Transaction deserialization failed: hash {}, {}", e->hash, e->error); - return ::grpc::Status::OK; - } - - auto batches = shared_model::interface::parseAndCreateBatches( - *batch_parser_, *batch_factory_, std::move(transactions).assumeValue()); - if (auto e = expected::resultToOptionalError(batches)) { - log_->warn("Batch deserialization failed: {}", *e); - return ::grpc::Status::OK; - } - MstState new_state = MstState::empty(mst_state_logger_, mst_completer_); - auto opt_batches = expected::resultToOptionalValue(std::move(batches)); - for (auto &batch : *opt_batches) { - auto cache_presence = tx_presence_cache_->check(*batch); - if (not cache_presence) { - // TODO andrei 30.11.18 IR-51 Handle database error - log_->warn("Check tx presence database error. Batch: {}", *batch); - continue; - } - auto is_replay = std::any_of(cache_presence->begin(), - cache_presence->end(), - &iroha::ametsuchi::isAlreadyProcessed); - - if (not is_replay) { - new_state += std::move(batch); - } - } - - log_->info("batches in MstState: {}", new_state.getBatches().size()); - - const auto &source_key = request->source_peer_key(); - auto key_invalid_reason = - shared_model::validation::validatePubkey(source_key); - if (key_invalid_reason) { - log_->info("Dropping received MST State due to invalid public key: {}", - *key_invalid_reason); - return grpc::Status::OK; - } - - if (new_state.isEmpty()) { - log_->info( - "All transactions from received MST state have been processed already, " - "nothing to propagate to MST processor"); - return grpc::Status::OK; - } - - if (auto subscriber = subscriber_.lock()) { - subscriber->onNewState(PublicKeyHexStringView{source_key}, - std::move(new_state)); - } else { - log_->warn("No subscriber for MST SendState event is set"); - } - - return grpc::Status::OK; -} - -void MstTransportGrpc::subscribe( - std::shared_ptr notification) { - subscriber_ = notification; -} - -rxcpp::observable MstTransportGrpc::sendState( - std::shared_ptr to, - MstState const &providing_state) { - return client_factory_->createClient(*to).match( - [&](auto &&client_val) -> rxcpp::observable { - auto &client{client_val.value}; - return rxcpp::observable<>::create( - [log_ = std::weak_ptr(log_), - client_stub = - std::shared_ptr>{ - std::move(client)}, - to = std::move(to), - providing_state, - my_key = my_key_, - async_call_ = std::weak_ptr< - network::AsyncGrpcClient>( - async_call_)](auto s) { - auto log = log_.lock(); - auto async_call = async_call_.lock(); - - if (log and async_call) { - log->info("Propagate MstState to peer {}", to->address()); - sendStateAsync(providing_state, - PublicKeyHexStringView{my_key}, - *client_stub, - *async_call, - [s](auto &status, auto &) { - s.on_next(status.ok()); - s.on_completed(); - }); - } - }); - }, - [this](const auto &error) -> rxcpp::observable { - log_->error("Could not send state: {}", error.error); - return rxcpp::observable<>::just(false); - }); -} - -void iroha::network::sendStateAsync( - MstState const &state, - PublicKeyHexStringView sender_key, - transport::MstTransportGrpc::StubInterface &client_stub, - AsyncGrpcClient &async_call, - std::function - on_response) { - transport::MstState proto_state; - std::string_view sender_key_sv = sender_key; - proto_state.set_source_peer_key(sender_key_sv.data(), sender_key_sv.size()); - state.iterateTransactions([&proto_state](auto const &tx) { - // TODO (@l4l) 04/03/18 simplify with IR-1040 - *proto_state.add_transactions() = - std::static_pointer_cast(tx) - ->getTransport(); - }); - async_call.Call( - [&](auto context, auto cq) { - return client_stub.AsyncSendState(context, proto_state, cq); - }, - std::move(on_response)); -} diff --git a/irohad/multi_sig_transactions/transport/impl/mst_transport_stub.cpp b/irohad/multi_sig_transactions/transport/impl/mst_transport_stub.cpp deleted file mode 100644 index 80b33987948..00000000000 --- a/irohad/multi_sig_transactions/transport/impl/mst_transport_stub.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/transport/mst_transport_stub.hpp" - -#include - -namespace iroha { - namespace network { - - void MstTransportStub::subscribe( - std::shared_ptr) {} - - rxcpp::observable MstTransportStub::sendState( - std::shared_ptr, - MstState const &) { - return rxcpp::observable<>::just(true); - } - } // namespace network -} // namespace iroha diff --git a/irohad/multi_sig_transactions/transport/mst_transport_grpc.hpp b/irohad/multi_sig_transactions/transport/mst_transport_grpc.hpp deleted file mode 100644 index 143cde132d9..00000000000 --- a/irohad/multi_sig_transactions/transport/mst_transport_grpc.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_TRANSPORT_GRPC_HPP -#define IROHA_MST_TRANSPORT_GRPC_HPP - -#include "mst.grpc.pb.h" -#include "network/mst_transport.hpp" - -#include "interfaces/common_objects/common_objects_factory.hpp" -#include "interfaces/common_objects/string_view_types.hpp" -#include "interfaces/iroha_internal/abstract_transport_factory.hpp" -#include "interfaces/iroha_internal/transaction_batch_factory.hpp" -#include "interfaces/iroha_internal/transaction_batch_parser.hpp" -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/mst_types.hpp" -#include "network/impl/async_grpc_client.hpp" - -namespace iroha { - - namespace ametsuchi { - class TxPresenceCache; - } - - namespace network { - template - class ClientFactory; - - class MstTransportGrpc : public MstTransport, - public transport::MstTransportGrpc::Service { - public: - using TransportFactoryType = - shared_model::interface::AbstractTransportFactory< - shared_model::interface::Transaction, - iroha::protocol::Transaction>; - - using Service = transport::MstTransportGrpc; - using MstClientFactory = ClientFactory; - - MstTransportGrpc( - std::shared_ptr> - async_call, - std::shared_ptr transaction_factory, - std::shared_ptr - batch_parser, - std::shared_ptr - transaction_batch_factory, - std::shared_ptr tx_presence_cache, - std::shared_ptr mst_completer, - shared_model::interface::types::PublicKeyHexStringView my_key, - logger::LoggerPtr mst_state_logger, - logger::LoggerPtr log, - std::unique_ptr client_factory); - - /** - * Server part of grpc SendState method call - * @param context - server context with information about call - * @param request - received new MstState object - * @param response - buffer for response data, not used - * @return grpc::Status (always OK) - */ - grpc::Status SendState( - ::grpc::ServerContext *context, - const ::iroha::network::transport::MstState *request, - ::google::protobuf::Empty *response) override; - - void subscribe( - std::shared_ptr notification) override; - - rxcpp::observable sendState( - std::shared_ptr to, - MstState const &providing_state) override; - - private: - std::weak_ptr subscriber_; - std::shared_ptr> - async_call_; - std::shared_ptr transaction_factory_; - std::shared_ptr - batch_parser_; - std::shared_ptr - batch_factory_; - std::shared_ptr tx_presence_cache_; - /// source peer key for MST propogation messages - std::shared_ptr mst_completer_; - std::string const my_key_; - - logger::LoggerPtr mst_state_logger_; ///< Logger for created MstState - ///< objects. - logger::LoggerPtr log_; ///< Logger for local use. - - std::shared_ptr client_factory_; - }; - - void sendStateAsync( - MstState const &state, - shared_model::interface::types::PublicKeyHexStringView sender_key, - transport::MstTransportGrpc::StubInterface &client_stub, - AsyncGrpcClient &async_call, - std::function - on_response = {}); - - } // namespace network -} // namespace iroha - -#endif // IROHA_MST_TRANSPORT_GRPC_HPP diff --git a/irohad/multi_sig_transactions/transport/mst_transport_stub.hpp b/irohad/multi_sig_transactions/transport/mst_transport_stub.hpp deleted file mode 100644 index b7b5cb78cc7..00000000000 --- a/irohad/multi_sig_transactions/transport/mst_transport_stub.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_TRANSPORT_STUB_HPP -#define IROHA_MST_TRANSPORT_STUB_HPP - -#include "network/mst_transport.hpp" - -namespace iroha { - namespace network { - class MstTransportStub : public MstTransport { - public: - void subscribe(std::shared_ptr) override; - - rxcpp::observable sendState( - std::shared_ptr, - MstState const &) override; - }; - } // namespace network -} // namespace iroha - -#endif // IROHA_MST_TRANSPORT_STUB_HPP diff --git a/irohad/network/mst_transport.hpp b/irohad/network/mst_transport.hpp deleted file mode 100644 index dd4400be431..00000000000 --- a/irohad/network/mst_transport.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_TRANSPORT_HPP -#define IROHA_MST_TRANSPORT_HPP - -#include - -#include -#include "interfaces/common_objects/peer.hpp" -#include "interfaces/common_objects/string_view_types.hpp" - -namespace iroha { - - class MstState; - - namespace network { - - /** - * Interface represents handler for multi-signature notifications - */ - class MstTransportNotification { - public: - /** - * Handler method for updating state, when new data received - * @param from - key of the peer emitted the state - * @param new_state - state propagated from peer - */ - virtual void onNewState( - shared_model::interface::types::PublicKeyHexStringView from, - MstState &&new_state) = 0; - - virtual ~MstTransportNotification() = default; - }; - - /** - * Interface of transport - * for propagating multi-signature transactions in network - */ - class MstTransport { - public: - /** - * Subscribe object for receiving notifications - * @param notification - object that will be notified on updates - */ - virtual void subscribe( - std::shared_ptr notification) = 0; - - /** - * Share state with other peer - * @param to - peer recipient of message - * @param providing_state - state for transmitting - * @return true if transmission was successful, false otherwise - */ - virtual rxcpp::observable sendState( - std::shared_ptr to, - MstState const &providing_state) = 0; - - virtual ~MstTransport() = default; - }; - } // namespace network -} // namespace iroha -#endif // IROHA_MST_TRANSPORT_HPP diff --git a/irohad/ordering/CMakeLists.txt b/irohad/ordering/CMakeLists.txt index 792b61e221b..bbaa58acffe 100644 --- a/irohad/ordering/CMakeLists.txt +++ b/irohad/ordering/CMakeLists.txt @@ -9,15 +9,19 @@ target_link_libraries(on_demand_common consensus_round ) -add_library(on_demand_ordering_service - impl/on_demand_ordering_service_impl.cpp +add_library(batches_cache impl/batches_cache.cpp ) +target_link_libraries(batches_cache + Boost::boost + ) +add_library(on_demand_ordering_service + impl/on_demand_ordering_service_impl.cpp + ) target_link_libraries(on_demand_ordering_service + batches_cache on_demand_common - mst_hash - mst_state shared_model_interfaces consensus_round logger diff --git a/irohad/ordering/impl/batches_cache.cpp b/irohad/ordering/impl/batches_cache.cpp index df51261f511..0162582fda9 100644 --- a/irohad/ordering/impl/batches_cache.cpp +++ b/irohad/ordering/impl/batches_cache.cpp @@ -6,11 +6,57 @@ #include "ordering/impl/batches_cache.hpp" #include -#include #include #include "interfaces/iroha_internal/transaction_batch.hpp" #include "interfaces/transaction.hpp" +#include "main/subscription.hpp" + +namespace { + shared_model::interface::types::TimestampType oldestTimestamp( + std::shared_ptr const &batch) { + if (!batch->transactions().empty()) { + auto it = batch->transactions().begin(); + shared_model::interface::types::TimestampType ts = (*it)->createdTime(); + while (++it != batch->transactions().end()) + ts = std::min(ts, (*it)->createdTime()); + return ts; + } + return 0ull; + } + + bool mergeSignaturesInBatch( + std::shared_ptr &target, + std::shared_ptr const &donor) { + assert(target->transactions().size() == donor->transactions().size()); + auto inserted_new_signatures = false; + + auto it_target = target->transactions().begin(); + auto it_donor = donor->transactions().begin(); + while (it_target != target->transactions().end() + && it_donor != donor->transactions().end()) { + const auto &target_tx = *it_target++; + const auto &donor_tx = *it_donor++; + + for (auto &signature : donor_tx->signatures()) + inserted_new_signatures |= target_tx->addSignature( + shared_model::interface::types::SignedHexStringView{ + signature.signedData()}, + shared_model::interface::types::PublicKeyHexStringView{ + signature.publicKey()}); + } + return inserted_new_signatures; + } + + bool isExpired( + std::shared_ptr const &batch, + std::chrono::minutes const &expiration_range, + const iroha::ordering::BatchesCache::TimeType ¤t_time) { + return oldestTimestamp(batch) + + expiration_range / std::chrono::milliseconds(1) + < current_time; + } +} // namespace namespace iroha::ordering { @@ -70,21 +116,137 @@ namespace iroha::ordering { assert(count(from.batches_) == from.tx_count_); } + BatchesCache::BatchesCache(std::chrono::minutes const &expiration_range) + : mst_state_( + std::make_shared>()) { + getSubscription()->dispatcher()->repeat( + SubscriptionEngineHandlers::kNotifications, + std::chrono::seconds(10ull), /// repeat task execution period + [expiration_range, w_mst_state(utils::make_weak(mst_state_))]() { + if (auto s_mst_state = w_mst_state.lock()) { + auto const now = std::chrono::system_clock::now().time_since_epoch() + / std::chrono::milliseconds(1); + + s_mst_state->exclusiveAccess( + [now, expiration_range](auto &mst_state) { + auto it = mst_state.mst_expirations_.begin(); + while (it != mst_state.mst_expirations_.end() + && isExpired(it->second, expiration_range, now)) { + auto batch = it->second; + it = (mst_state -= it); + notifyEngine(std::make_tuple(std::make_pair( + EventTypes::kOnMstExpiredBatches, batch))); + } + notifyEngine(std::make_tuple( + std::make_pair(EventTypes::kOnMstMetrics, + mst_state.batches_and_txs_counter))); + assert(mst_state.mst_pending_.size() + == mst_state.mst_expirations_.size()); + }); + } + }, + [w_mst_state(utils::make_weak(mst_state_))]() { + return !w_mst_state.expired(); + }); + } + + void BatchesCache::insertMSTCache( + std::shared_ptr const &batch) { + assert(!batch->hasAllSignatures()); + mst_state_->exclusiveAccess([&](auto &mst_state) { + auto ins_res = + mst_state.mst_pending_.emplace(batch->reducedHash(), batch); + auto &it_batch = ins_res.first; + if (ins_res.second) { + auto ts = oldestTimestamp(batch); + while (!mst_state.mst_expirations_.emplace(ts, batch).second) ++ts; + it_batch->second.timestamp = ts; + mst_state += batch; + notifyEngine(std::make_tuple( + std::make_pair(EventTypes::kOnMstStateUpdate, batch), + std::make_pair(EventTypes::kOnMstMetrics, + mst_state.batches_and_txs_counter))); + } else { + if (mergeSignaturesInBatch(it_batch->second.batch, batch)) { + if (it_batch->second.batch->hasAllSignatures()) { + batches_cache_.insert(it_batch->second.batch); + mst_state -= it_batch; + notifyEngine(std::make_tuple( + std::make_pair(EventTypes::kOnMstPreparedBatches, + it_batch->second.batch), + std::make_pair(EventTypes::kOnMstMetrics, + mst_state.batches_and_txs_counter))); + } else { + notifyEngine(std::make_tuple(std::make_pair( + EventTypes::kOnMstStateUpdate, it_batch->second.batch))); + } + } + } + assert(mst_state.mst_pending_.size() + == mst_state.mst_expirations_.size()); + }); + } + + void BatchesCache::removeMSTCache( + std::shared_ptr const &batch) { + mst_state_->exclusiveAccess([&](auto &mst_state) { + if (auto it = mst_state.mst_pending_.find(batch->reducedHash()); + it != mst_state.mst_pending_.end()) { + mst_state -= it; + notifyEngine(std::make_tuple(std::make_pair( + EventTypes::kOnMstMetrics, mst_state.batches_and_txs_counter))); + assert(mst_state.mst_pending_.size() + == mst_state.mst_expirations_.size()); + } + }); + } + + void BatchesCache::removeMSTCache( + OnDemandOrderingService::HashesSetType const &hashes) { + mst_state_->exclusiveAccess([&](auto &mst_state) { + for (auto it = mst_state.mst_pending_.begin(); + it != mst_state.mst_pending_.end();) { + auto const &batch_info = it->second; + auto const need_remove = + std::any_of(batch_info.batch->transactions().begin(), + batch_info.batch->transactions().end(), + [&hashes](auto const &tx) { + return hashes.find(tx->hash()) != hashes.end(); + }); + if (need_remove) { + it = (mst_state -= it); + } else + ++it; + } + notifyEngine(std::make_tuple(std::make_pair( + EventTypes::kOnMstMetrics, mst_state.batches_and_txs_counter))); + assert(mst_state.mst_pending_.size() + == mst_state.mst_expirations_.size()); + }); + } + uint64_t BatchesCache::insert( std::shared_ptr const &batch) { std::unique_lock lock(batches_cache_cs_); - if (used_batches_cache_.getBatchesSet().find(batch) - == used_batches_cache_.getBatchesSet().end()) - batches_cache_.insert(batch); + if (batch->hasAllSignatures()) { + if (used_batches_cache_.getBatchesSet().find(batch) + == used_batches_cache_.getBatchesSet().end()) + batches_cache_.insert(batch); + removeMSTCache(batch); + notifyEngine(std::make_tuple( + std::make_pair(EventTypes::kOnMstPreparedBatches, batch))); + } else + insertMSTCache(batch); return batches_cache_.getTxsCount(); } void BatchesCache::remove( const OnDemandOrderingService::HashesSetType &hashes) { - std::unique_lock lock(batches_cache_cs_); + removeMSTCache(hashes); + std::unique_lock lock(batches_cache_cs_); batches_cache_.merge(used_batches_cache_); assert(used_batches_cache_.getTxsCount() == 0ull); @@ -120,6 +282,7 @@ namespace iroha::ordering { void BatchesCache::processReceivedProposal( OnDemandOrderingService::CollectionType batches) { + /// TODO(iceseer): batches push by reference std::unique_lock lock(batches_cache_cs_); for (auto &batch : batches) { batches_cache_.removeBatch(batch); diff --git a/irohad/ordering/impl/batches_cache.hpp b/irohad/ordering/impl/batches_cache.hpp index e72218d3d22..4af024b3f1b 100644 --- a/irohad/ordering/impl/batches_cache.hpp +++ b/irohad/ordering/impl/batches_cache.hpp @@ -8,12 +8,17 @@ #include "ordering/on_demand_ordering_service.hpp" +#include #include #include +#include #include -#include +#include +#include +#include "common/common.hpp" #include "consensus/round.hpp" +#include "ordering/ordering_types.hpp" namespace shared_model::interface { class TransactionBatch; @@ -26,10 +31,9 @@ namespace iroha::ordering { */ class BatchesContext { public: - using BatchesSetType = std::unordered_set< - std::shared_ptr, - OnDemandOrderingService::BatchPointerHasher, - shared_model::interface::BatchHashEquality>; + using BatchesSetType = + std::set, + shared_model::interface::BatchHashLess>; BatchesContext(BatchesContext const &) = delete; BatchesContext &operator=(BatchesContext const &) = delete; @@ -81,24 +85,99 @@ namespace iroha::ordering { class BatchesCache { public: using BatchesSetType = BatchesContext::BatchesSetType; + using TimeType = shared_model::interface::types::TimestampType; private: + struct BatchInfo { + std::shared_ptr batch; + shared_model::interface::types::TimestampType timestamp; + + BatchInfo( + std::shared_ptr const &b, + shared_model::interface::types::TimestampType const &t = 0ull) + : batch(b), timestamp(t) {} + }; + + using MSTBatchesSetType = + std::unordered_map; + using MSTExpirationSetType = + std::map>; + + struct MSTState { + MSTBatchesSetType mst_pending_; + MSTExpirationSetType mst_expirations_; + std::tuple batches_and_txs_counter; + + void operator-=( + std::shared_ptr const + &batch) { + assert(std::get<0>(batches_and_txs_counter) >= 1ull); + assert(std::get<1>(batches_and_txs_counter) + >= batch->transactions().size()); + + std::get<0>(batches_and_txs_counter) -= 1ull; + std::get<1>(batches_and_txs_counter) -= batch->transactions().size(); + } + + void operator+=( + std::shared_ptr const + &batch) { + std::get<0>(batches_and_txs_counter) += 1ull; + std::get<1>(batches_and_txs_counter) += batch->transactions().size(); + } + + template ::value, + bool> = true> + MSTBatchesSetType::iterator operator-=(Iterator const &it) { + *this -= it->second.batch; + mst_expirations_.erase(it->second.timestamp); + return mst_pending_.erase(it); + } + + template < + typename Iterator, + std::enable_if_t< + std::is_same::value, + bool> = true> + MSTExpirationSetType::iterator operator-=(Iterator const &it) { + *this -= it->second; + mst_pending_.erase(it->second->reducedHash()); + return mst_expirations_.erase(it); + } + }; + mutable std::shared_mutex batches_cache_cs_; BatchesContext batches_cache_, used_batches_cache_; + std::shared_ptr> mst_state_; + + /** + * MST functions + */ + void insertMSTCache( + std::shared_ptr const + &batch); + void removeMSTCache( + std::shared_ptr const + &batch); + void removeMSTCache(OnDemandOrderingService::HashesSetType const &hashes); + public: BatchesCache(BatchesCache const &) = delete; BatchesCache &operator=(BatchesCache const &) = delete; - BatchesCache() = default; + BatchesCache(std::chrono::minutes const &expiration_range = + std::chrono::minutes(24 * 60)); uint64_t insert( std::shared_ptr const &batch); - void remove(const OnDemandOrderingService::HashesSetType &hashes); - bool isEmpty(); - uint64_t txsCount() const; uint64_t availableTxsCount() const; @@ -109,9 +188,11 @@ namespace iroha::ordering { size_t requested_tx_amount, std::vector> &collection, + BloomFilter256 &bf, IsProcessedFunc &&is_processed) { collection.clear(); collection.reserve(requested_tx_amount); + bf.clear(); std::unique_lock lock(batches_cache_cs_); uint32_t depth_counter = 0ul; @@ -126,10 +207,14 @@ namespace iroha::ordering { return false; } + for (auto &tx : batch->transactions()) + tx->storeBatchHash(batch->reducedHash()); + collection.insert(std::end(collection), std::begin(batch->transactions()), std::end(batch->transactions())); + bf.set(batch->reducedHash()); used_batches_cache_.insert(batch); return true; }); diff --git a/irohad/ordering/impl/on_demand_connection_manager.cpp b/irohad/ordering/impl/on_demand_connection_manager.cpp index d588ba473ec..45e202a722f 100644 --- a/irohad/ordering/impl/on_demand_connection_manager.cpp +++ b/irohad/ordering/impl/on_demand_connection_manager.cpp @@ -6,6 +6,7 @@ #include "ordering/impl/on_demand_connection_manager.hpp" #include "common/result.hpp" +#include "interfaces/common_objects/peer.hpp" #include "interfaces/iroha_internal/proposal.hpp" #include "logger/logger.hpp" #include "ordering/impl/on_demand_common.hpp" @@ -21,9 +22,10 @@ OnDemandConnectionManager::OnDemandConnectionManager( OnDemandConnectionManager::OnDemandConnectionManager( std::shared_ptr factory, CurrentPeers initial_peers, + shared_model::interface::types::PeerList const &all_peers, logger::LoggerPtr log) : OnDemandConnectionManager(std::move(factory), std::move(log)) { - initializeConnections(initial_peers); + initializeConnections(initial_peers, all_peers); } OnDemandConnectionManager::~OnDemandConnectionManager() { @@ -31,6 +33,10 @@ OnDemandConnectionManager::~OnDemandConnectionManager() { std::lock_guard lock(mutex_); } +std::chrono::milliseconds OnDemandConnectionManager::getRequestDelay() const { + return factory_->getRequestDelay(); +} + void OnDemandConnectionManager::onBatches(CollectionType batches) { /* * Transactions are sent to the current and next rounds (+1) @@ -57,33 +63,73 @@ void OnDemandConnectionManager::onBatches(CollectionType batches) { propagate(kCommitConsumer); } -void OnDemandConnectionManager::onRequestProposal(consensus::Round round) { +void OnDemandConnectionManager::onBatchesToWholeNetwork( + CollectionType batches) { std::shared_lock lock(mutex_); - if (stop_requested_.load(std::memory_order_relaxed)) { - return; - } + log_->info("Propagate to {} peers.", connections_.all_connections.size()); + if (not stop_requested_.load(std::memory_order_relaxed)) + for (auto &connection : connections_.all_connections) + if (connection.connection) + (*connection.connection)->onBatches(batches); - log_->debug("onRequestProposal, {}", round); + log_->info("Propagation complete."); +} - if (auto &connection = connections_.peers[kIssuer]) { - (*connection)->onRequestProposal(round); - } +void OnDemandConnectionManager::onRequestProposal( + consensus::Round round, + std::optional< + std::pair, + BloomFilter256>> proposal) { + std::shared_lock lock(mutex_); + if (stop_requested_.load(std::memory_order_relaxed)) + return; + + assert(!proposal || proposal.value().first); + log_->debug("onRequestProposal, {} : {}", + round, + proposal ? proposal.value().first->toString() : "NULL_OPT"); + if (auto &connection = connections_.peers[kIssuer]) + (*connection)->onRequestProposal(round, std::move(proposal)); } void OnDemandConnectionManager::initializeConnections( - const CurrentPeers &peers) { + const CurrentPeers &peers, + shared_model::interface::types::PeerList const &all_peers) { std::lock_guard lock(mutex_); if (stop_requested_.load(std::memory_order_relaxed)) { // Object was destroyed and `this' is no longer valid. return; } - auto create_assign = [&](auto target) { - auto maybe_connection = factory_->create(*peers.peers[target]); - if (expected::hasError(maybe_connection)) { - connections_.peers[target] = std::nullopt; - return; + + std::vector tmp; + for (auto &p : all_peers) { + bool found = false; + for (auto &it : connections_.all_connections) { + if (it.connection && it.peer->pubkey() == p->pubkey() + && it.peer->address() == p->address() + && it.peer->isSyncingPeer() == p->isSyncingPeer()) { + tmp.emplace_back(it.connection, it.peer); + found = true; + break; + } } - connections_.peers[target] = std::move(maybe_connection).assumeValue(); + if (found) + continue; + + if (auto maybe_connection = factory_->create(*p); + expected::hasValue(maybe_connection)) + tmp.emplace_back(std::move(maybe_connection).assumeValue(), p); + else + tmp.emplace_back(std::nullopt, p); + } + connections_.all_connections.swap(tmp); + + auto create_assign = [&](auto target) { + for (size_t ix = 0; ix < all_peers.size(); ++ix) + if (all_peers[ix]->address() == peers.peers[target]->address() + && all_peers[ix]->pubkey() == peers.peers[target]->pubkey()) + connections_.peers[target] = + connections_.all_connections[ix].connection; }; create_assign(kIssuer); diff --git a/irohad/ordering/impl/on_demand_connection_manager.hpp b/irohad/ordering/impl/on_demand_connection_manager.hpp index ab5ae54f724..fba42be65b3 100644 --- a/irohad/ordering/impl/on_demand_connection_manager.hpp +++ b/irohad/ordering/impl/on_demand_connection_manager.hpp @@ -50,29 +50,49 @@ namespace iroha { OnDemandConnectionManager( std::shared_ptr factory, CurrentPeers initial_peers, + shared_model::interface::types::PeerList const &all_peers, logger::LoggerPtr log); ~OnDemandConnectionManager() override; void onBatches(CollectionType batches) override; + void onBatchesToWholeNetwork(CollectionType batches) override; + std::chrono::milliseconds getRequestDelay() const override; - void onRequestProposal(consensus::Round round) override; + void onRequestProposal( + consensus::Round round, + std::optional, + BloomFilter256>> proposal) override; /** * Initialize corresponding peers in connections_ using factory_ * @param peers to initialize connections with */ - void initializeConnections(const CurrentPeers &peers); + void initializeConnections( + const CurrentPeers &peers, + shared_model::interface::types::PeerList const &all_peers); private: /** * Corresponding connections created by OdOsNotificationFactory * @see PeerType for individual descriptions */ + struct ConnectionData { + std::optional> connection; + std::shared_ptr peer; + + ConnectionData( + std::optional> const + &c, + std::shared_ptr const &p) + : connection(c), peer(p) {} + }; struct CurrentConnections { PeerCollectionType< - std::optional>> + std::optional>> peers; + std::vector all_connections; }; logger::LoggerPtr log_; diff --git a/irohad/ordering/impl/on_demand_ordering_gate.cpp b/irohad/ordering/impl/on_demand_ordering_gate.cpp index e2b03244d1d..639de7bc03c 100644 --- a/irohad/ordering/impl/on_demand_ordering_gate.cpp +++ b/irohad/ordering/impl/on_demand_ordering_gate.cpp @@ -20,6 +20,7 @@ #include "interfaces/iroha_internal/transaction_batch_impl.hpp" #include "interfaces/iroha_internal/transaction_batch_parser_impl.hpp" #include "logger/logger.hpp" +#include "main/subscription.hpp" #include "ordering/impl/on_demand_common.hpp" #include "validators/field_validator.hpp" @@ -41,7 +42,32 @@ OnDemandOrderingGate::OnDemandOrderingGate( tx_cache_(std::move(tx_cache)), syncing_mode_(syncing_mode) {} +void OnDemandOrderingGate::initialize() { + failed_proposal_response_ = + SubscriberCreator::template create< + EventTypes::kOnProposalResponseFailed>( + SubscriptionEngineHandlers::kYac, + [_w_this{weak_from_this()}](auto, auto ev) { + if (auto _this = _w_this.lock()) { + std::shared_lock stop_lock( + _this->stop_mutex_); + if (_this->stop_requested_) { + _this->log_->warn( + "Not doing anything because stop was requested."); + return; + } + + if (!_this->syncing_mode_) { + assert(_this->network_client_); + _this->network_client_->onRequestProposal(ev.round, + std::nullopt); + } + } + }); +} + OnDemandOrderingGate::~OnDemandOrderingGate() { + failed_proposal_response_->unsubscribe(); stop(); } @@ -53,10 +79,8 @@ void OnDemandOrderingGate::propagateBatch( return; } - // TODO iceseer 14.01.21 IR-959 Refactor to avoid copying. - forLocalOS(&OnDemandOrderingService::onBatches, - transport::OdOsNotification::CollectionType{batch}); - network_client_->onBatches( + log_->info("Propagated for network batch: {}", *batch); + network_client_->onBatchesToWholeNetwork( transport::OdOsNotification::CollectionType{batch}); } @@ -77,9 +101,15 @@ void OnDemandOrderingGate::processRoundSwitch(RoundSwitch const &event) { this->sendCachedTransactions(); - // request proposal for the current round - if (!syncing_mode_) - network_client_->onRequestProposal(event.next_round); + if (!syncing_mode_) { + assert(ordering_service_); + assert(network_client_); + + network_client_->onRequestProposal( + event.next_round, + ordering_service_->waitForLocalProposal( + event.next_round, network_client_->getRequestDelay())); + } } void OnDemandOrderingGate::stop() { diff --git a/irohad/ordering/impl/on_demand_ordering_gate.hpp b/irohad/ordering/impl/on_demand_ordering_gate.hpp index 966f09a25dd..a1a355829f6 100644 --- a/irohad/ordering/impl/on_demand_ordering_gate.hpp +++ b/irohad/ordering/impl/on_demand_ordering_gate.hpp @@ -8,12 +8,14 @@ #include "network/ordering_gate.hpp" +#include #include #include "interfaces/common_objects/types.hpp" #include "interfaces/iroha_internal/proposal.hpp" #include "interfaces/iroha_internal/unsafe_proposal_factory.hpp" #include "logger/logger_fwd.hpp" +#include "main/subscription.hpp" #include "ordering/impl/on_demand_common.hpp" #include "ordering/impl/round_switch.hpp" #include "ordering/on_demand_ordering_service.hpp" @@ -30,7 +32,9 @@ namespace iroha { * Ordering gate which requests proposals from the ordering service * votes for proposals, and passes committed proposals to the pipeline */ - class OnDemandOrderingGate : public network::OrderingGate { + class OnDemandOrderingGate + : public network::OrderingGate, + public std::enable_shared_from_this { public: OnDemandOrderingGate( std::shared_ptr ordering_service, @@ -44,6 +48,8 @@ namespace iroha { ~OnDemandOrderingGate() override; + void initialize(); + void propagateBatch( std::shared_ptr batch) override; @@ -96,6 +102,8 @@ namespace iroha { std::shared_ptr tx_cache_; consensus::Round current_round_; std::shared_ptr current_ledger_state_; + std::shared_ptr> + failed_proposal_response_; std::shared_timed_mutex stop_mutex_; bool stop_requested_{false}; diff --git a/irohad/ordering/impl/on_demand_ordering_service_impl.cpp b/irohad/ordering/impl/on_demand_ordering_service_impl.cpp index 235867f1832..50dc45c2b56 100644 --- a/irohad/ordering/impl/on_demand_ordering_service_impl.cpp +++ b/irohad/ordering/impl/on_demand_ordering_service_impl.cpp @@ -5,6 +5,7 @@ #include "ordering/impl/on_demand_ordering_service_impl.hpp" +#include #include #include @@ -15,12 +16,53 @@ #include "datetime/time.hpp" #include "interfaces/iroha_internal/proposal.hpp" #include "interfaces/iroha_internal/transaction_batch.hpp" +#include "interfaces/iroha_internal/transaction_batch_impl.hpp" +#include "interfaces/iroha_internal/transaction_batch_parser_impl.hpp" #include "interfaces/transaction.hpp" #include "logger/logger.hpp" #include "main/subscription.hpp" +#include "ordering/ordering_types.hpp" +#include "subscription/scheduler_impl.hpp" using iroha::ordering::OnDemandOrderingServiceImpl; +namespace { + auto parseProposal( + shared_model::interface::types::TransactionsCollectionType const &txs) { + shared_model::interface::types::SharedTxsCollectionType transactions; + for (auto const &transaction : txs) + transactions.push_back(clone(transaction)); + + return shared_model::interface::TransactionBatchParserImpl().parseBatches( + transactions); + } + + void uploadBatches( + iroha::ordering::BatchesCache::BatchesSetType &batches, + shared_model::interface::types::TransactionsCollectionType const &txs) { + auto batch_txs = parseProposal(txs); + for (auto &txs : batch_txs) { + batches.insert( + std::make_shared( + std::move(txs))); + } + } + + void uploadBatchesWithFilter( + iroha::ordering::BloomFilter256 const &bf, + iroha::ordering::BatchesCache::BatchesSetType &batches, + shared_model::interface::types::TransactionsCollectionType const &txs) { + auto batch_txs = parseProposal(txs); + for (auto &txs : batch_txs) { + auto batch = + std::make_shared( + std::move(txs)); + if (bf.test(batch->reducedHash())) + batches.insert(batch); + } + } +} // namespace + OnDemandOrderingServiceImpl::OnDemandOrderingServiceImpl( size_t transaction_limit, std::shared_ptr @@ -32,7 +74,66 @@ OnDemandOrderingServiceImpl::OnDemandOrderingServiceImpl( number_of_proposals_(number_of_proposals), proposal_factory_(std::move(proposal_factory)), tx_cache_(std::move(tx_cache)), - log_(std::move(log)) {} + log_(std::move(log)) { + remote_proposal_observer_ = + SubscriberCreator::template create< + iroha::EventTypes::kRemoteProposalDiff>( + iroha::SubscriptionEngineHandlers::kProposalProcessing, + [this]( + auto, + auto ev) { /// TODO(iceseer): remove `this` from lambda context + BatchesCache::BatchesSetType batches; + uploadBatches(batches, ev.remote->transactions()); + + if (ev.bloom_filter.size() == BloomFilter256::kBytesCount) { + BloomFilter256 bf; + bf.store(ev.bloom_filter); + uploadBatchesWithFilter(bf, batches, ev.local->transactions()); + } + + std::vector> + collection; + for (auto const &batch : batches) { + collection.insert(std::end(collection), + std::begin(batch->transactions()), + std::end(batch->transactions())); + } + if (auto result = + tryCreateProposal(ev.round, collection, ev.created_time); + result + && result.value()->hash() + == shared_model::crypto::Hash(ev.remote_proposal_hash)) { + log_->debug("Local correct proposal: {}, while remote {}", + result.value()->hash(), + shared_model::crypto::Hash(ev.remote_proposal_hash)); + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponse, + ProposalEvent{std::move(result).value(), ev.round}); + } else { + if (result) + log_->debug( + "Local incorrect proposal: {}\nwhile remote {}\nremote " + "proposal: {}\nlocal proposal: {}", + result.value()->hash(), + shared_model::crypto::Hash(ev.remote_proposal_hash), + *ev.remote, + **result); + else + log_->debug( + "Local proposal was not created while remote hash " + "{}\nremote proposal: {}", + shared_model::crypto::Hash(ev.remote_proposal_hash), + *ev.remote); + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponseFailed, + ProposalEvent{std::nullopt, ev.round}); + } + }); +} + +OnDemandOrderingServiceImpl::~OnDemandOrderingServiceImpl() { + remote_proposal_observer_->unsubscribe(); +} // -------------------------| OnDemandOrderingService |------------------------- @@ -84,12 +185,49 @@ void OnDemandOrderingServiceImpl::forCachedBatches( batches_cache_.forCachedBatches(f); } -std::optional> +OnDemandOrderingServiceImpl::PackedProposalData +OnDemandOrderingServiceImpl::waitForLocalProposal( + consensus::Round const &round, std::chrono::milliseconds const &delay) { + if (!hasProposal(round) && !hasEnoughBatchesInCache()) { + auto scheduler = std::make_shared(); + auto tid = getSubscription()->dispatcher()->bind(scheduler); + + auto batches_subscription = SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + static_cast(*tid), + [scheduler(utils::make_weak(scheduler))](auto, auto) { + if (auto maybe_scheduler = scheduler.lock()) + maybe_scheduler->dispose(); + }); + auto proposals_subscription = + SubscriberCreator::template create< + EventTypes::kOnPackProposal>( + static_cast(*tid), + [round, scheduler(utils::make_weak(scheduler))](auto, + auto packed_round) { + if (auto maybe_scheduler = scheduler.lock(); + maybe_scheduler and round == packed_round) + maybe_scheduler->dispose(); + }); + scheduler->addDelayed(delay, [scheduler(utils::make_weak(scheduler))] { + if (auto maybe_scheduler = scheduler.lock()) { + maybe_scheduler->dispose(); + } + }); + + scheduler->process(); + getSubscription()->dispatcher()->unbind(*tid); + } + + return onRequestProposal(round); +} + +OnDemandOrderingServiceImpl::PackedProposalData OnDemandOrderingServiceImpl::onRequestProposal(consensus::Round round) { log_->debug("Requesting a proposal for round {}", round); - std::optional< - std::shared_ptr> - result; + OnDemandOrderingServiceImpl::PackedProposalData result; do { std::lock_guard lock(proposals_mutex_); auto it = proposal_map_.find(round); @@ -106,10 +244,12 @@ OnDemandOrderingServiceImpl::onRequestProposal(consensus::Round round) { if (is_current_round_or_next2) { result = packNextProposals(round); + proposal_map_.emplace(round, result); getSubscription()->notify(EventTypes::kOnPackProposal, round); } } while (false); - log_->debug("uploadProposal, {}, {}returning a proposal.", + + log_->debug("uploadProposal, {}, {} returning a proposal.", round, result ? "" : "NOT "); return result; @@ -133,25 +273,27 @@ OnDemandOrderingServiceImpl::tryCreateProposal( proposal = std::nullopt; log_->debug("No transactions to create a proposal for {}", round); } - - assert(proposal_map_.find(round) == proposal_map_.end()); - proposal_map_.emplace(round, proposal); return proposal; } -std::optional> +OnDemandOrderingServiceImpl::PackedProposalData OnDemandOrderingServiceImpl::packNextProposals(const consensus::Round &round) { auto now = iroha::time::now(); std::vector> txs; + BloomFilter256 bf; + if (!isEmptyBatchesCache()) batches_cache_.getTransactions( - transaction_limit_, txs, [&](auto const &batch) { + transaction_limit_, txs, bf, [&](auto const &batch) { assert(batch); return batchAlreadyProcessed(*batch); }); log_->debug("Packed proposal contains: {} transactions.", txs.size()); - return tryCreateProposal(round, txs, now); + if (auto result = tryCreateProposal(round, txs, now)) + return std::make_pair(std::move(result).value(), bf); + + return std::nullopt; } void OnDemandOrderingServiceImpl::tryErase( diff --git a/irohad/ordering/impl/on_demand_ordering_service_impl.hpp b/irohad/ordering/impl/on_demand_ordering_service_impl.hpp index a16bd72106e..46bd7aa6f83 100644 --- a/irohad/ordering/impl/on_demand_ordering_service_impl.hpp +++ b/irohad/ordering/impl/on_demand_ordering_service_impl.hpp @@ -14,10 +14,9 @@ #include "interfaces/iroha_internal/unsafe_proposal_factory.hpp" #include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/hash.hpp" #include "ordering/impl/batches_cache.hpp" // TODO 2019-03-15 andrei: IR-403 Separate BatchHashEquality and MstState -#include "multi_sig_transactions/state/mst_state.hpp" +#include "main/subscription.hpp" #include "ordering/impl/on_demand_common.hpp" namespace iroha { @@ -28,8 +27,7 @@ namespace iroha { namespace detail { using ProposalMapType = std::map>>; + OnDemandOrderingService::PackedProposalData>; } // namespace detail class OnDemandOrderingServiceImpl : public OnDemandOrderingService { @@ -52,12 +50,13 @@ namespace iroha { logger::LoggerPtr log, size_t number_of_proposals = 3); + ~OnDemandOrderingServiceImpl() override; + // --------------------- | OnDemandOrderingService |_--------------------- void onBatches(CollectionType batches) override; - std::optional> onRequestProposal( - consensus::Round round) override; + PackedProposalData onRequestProposal(consensus::Round round) override; void onCollaborationOutcome(consensus::Round round) override; @@ -71,13 +70,16 @@ namespace iroha { void processReceivedProposal(CollectionType batches) override; + PackedProposalData waitForLocalProposal( + consensus::Round const &round, + std::chrono::milliseconds const &delay) override; + private: /** * Packs new proposals and creates new rounds * Note: method is not thread-safe */ - std::optional> - packNextProposals(const consensus::Round &round); + PackedProposalData packNextProposals(const consensus::Round &round); using TransactionsCollectionType = std::vector>; @@ -156,6 +158,10 @@ namespace iroha { * Current round */ consensus::Round current_round_; + + std::shared_ptr< + iroha::BaseSubscriber> + remote_proposal_observer_; }; } // namespace ordering } // namespace iroha diff --git a/irohad/ordering/impl/on_demand_os_client_grpc.cpp b/irohad/ordering/impl/on_demand_os_client_grpc.cpp index d5141647c2e..9e5474ce4a8 100644 --- a/irohad/ordering/impl/on_demand_os_client_grpc.cpp +++ b/irohad/ordering/impl/on_demand_os_client_grpc.cpp @@ -9,6 +9,8 @@ #include "backend/protobuf/transaction.hpp" #include "interfaces/common_objects/peer.hpp" #include "interfaces/iroha_internal/transaction_batch.hpp" +#include "interfaces/iroha_internal/transaction_batch_impl.hpp" +#include "interfaces/iroha_internal/transaction_batch_parser_impl.hpp" #include "logger/logger.hpp" #include "main/subscription.hpp" #include "network/impl/client_factory.hpp" @@ -29,8 +31,11 @@ namespace { std::weak_ptr wlog) { auto maybe_stub = wstub.lock(); auto maybe_log = wlog.lock(); - if (not(maybe_stub and maybe_log)) + if (not(maybe_stub and maybe_log)) { + if (maybe_log) + maybe_log->info("No stub. Send batches skipped."); return true; + } grpc::ClientContext context; context.set_wait_for_ready(false); @@ -59,7 +64,7 @@ namespace { return false; } - maybe_log->info("RPC succeeded: {}", context.peer()); + maybe_log->info("RPC succeeded(SendBatches): {}", context.peer()); return true; } } // namespace @@ -70,7 +75,6 @@ OnDemandOsClientGrpc::OnDemandOsClientGrpc( std::function time_provider, std::chrono::milliseconds proposal_request_timeout, logger::LoggerPtr log, - std::function callback, std::shared_ptr os_execution_keepers, std::string peer_name) : log_(std::move(log)), @@ -78,7 +82,6 @@ OnDemandOsClientGrpc::OnDemandOsClientGrpc( proposal_factory_(std::move(proposal_factory)), time_provider_(std::move(time_provider)), proposal_request_timeout_(proposal_request_timeout), - callback_(std::move(callback)), os_execution_keepers_(std::move(os_execution_keepers)), peer_name_(std::move(peer_name)) { assert(os_execution_keepers_); @@ -89,6 +92,11 @@ OnDemandOsClientGrpc::~OnDemandOsClientGrpc() { sh_ctx->TryCancel(); } +void OnDemandOsClientGrpc::onBatchesToWholeNetwork(CollectionType batches) { + // This code should not be called. + assert(false); +} + void OnDemandOsClientGrpc::onBatches(CollectionType batches) { std::shared_ptr request; for (auto &batch : batches) { @@ -102,6 +110,7 @@ void OnDemandOsClientGrpc::onBatches(CollectionType batches) { } if (request->ByteSizeLong() >= 2ull * 1024 * 1024) { + log_->debug("execute for called"); os_execution_keepers_->executeFor( peer_name_, [peer_name(peer_name_), @@ -122,6 +131,7 @@ void OnDemandOsClientGrpc::onBatches(CollectionType batches) { } if (request) { + log_->debug("execute for called"); os_execution_keepers_->executeFor( peer_name_, [peer_name(peer_name_), @@ -140,7 +150,15 @@ void OnDemandOsClientGrpc::onBatches(CollectionType batches) { } } -void OnDemandOsClientGrpc::onRequestProposal(consensus::Round round) { +std::chrono::milliseconds OnDemandOsClientGrpc::getRequestDelay() const { + return proposal_request_timeout_; +} + +void OnDemandOsClientGrpc::onRequestProposal( + consensus::Round round, + std::optional< + std::pair, + BloomFilter256>> ref_proposal) { // Cancel an unfinished request if (auto maybe_context = context_.lock()) { maybe_context->TryCancel(); @@ -151,23 +169,30 @@ void OnDemandOsClientGrpc::onRequestProposal(consensus::Round round) { proto::ProposalRequest request; request.mutable_round()->set_block_round(round.block_round); request.mutable_round()->set_reject_round(round.reject_round); + if (ref_proposal.has_value()) + request.set_bloom_filter( + std::string(ref_proposal.value().second.load().data(), + ref_proposal.value().second.load().size())); + getSubscription()->dispatcher()->add( getSubscription()->dispatcher()->kExecuteInPool, [round, + ref_proposal{std::move(ref_proposal)}, time_provider(time_provider_), proposal_request_timeout(proposal_request_timeout_), context(std::move(context)), request(std::move(request)), stub(utils::make_weak(stub_)), log(utils::make_weak(log_)), - proposal_factory(utils::make_weak(proposal_factory_)), - callback(callback_)] { + proposal_factory(utils::make_weak(proposal_factory_))] { auto maybe_stub = stub.lock(); auto maybe_log = log.lock(); auto maybe_proposal_factory = proposal_factory.lock(); if (not(maybe_stub and maybe_log and maybe_proposal_factory)) { return; } + + /// make request context->set_deadline(time_provider() + proposal_request_timeout); proto::ProposalResponse response; maybe_log->info("Requesting proposal"); @@ -176,23 +201,62 @@ void OnDemandOsClientGrpc::onRequestProposal(consensus::Round round) { if (not status.ok()) { maybe_log->warn( "RPC failed: {} {}", context->peer(), status.error_message()); - callback({std::nullopt, round}); + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponse, + ProposalEvent{std::nullopt, round}); return; } else { - maybe_log->info("RPC succeeded: {}", context->peer()); + maybe_log->info("RPC succeeded(RequestingProposal): {}", + context->peer()); } - if (not response.has_proposal()) { - callback({std::nullopt, round}); + + if (!response.has_proposal_hash()) { + maybe_log->info("Remote node {} has no proposal.", context->peer()); + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponse, + ProposalEvent{std::nullopt, round}); return; } - auto maybe_proposal = - maybe_proposal_factory->build(response.proposal()); - if (expected::hasError(maybe_proposal)) { - maybe_log->info("{}", maybe_proposal.assumeError().error); - callback({std::nullopt, round}); + + /// parse request + std::shared_ptr + remote_proposal; + if (auto proposal_result = + maybe_proposal_factory->build(response.proposal()); + expected::hasError(proposal_result)) { + maybe_log->warn("{}", proposal_result.assumeError().error); + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponse, + ProposalEvent{std::nullopt, round}); return; + } else + remote_proposal = std::move(proposal_result).assumeValue(); + + /// merge if has local proposal or process directly if not + if (ref_proposal.has_value()) { + std::shared_ptr + local_proposal; + local_proposal = ref_proposal.value().first; + + iroha::getSubscription()->notify( + iroha::EventTypes::kRemoteProposalDiff, + RemoteProposalDownloadedEvent{ + local_proposal, + remote_proposal, + response.bloom_filter(), + response.proposal_hash(), + round, + remote_proposal ? remote_proposal->createdTime() : 0ull}); + } else if (!remote_proposal->transactions().empty()) + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponse, + ProposalEvent{std::move(remote_proposal), round}); + else { + maybe_log->info("Transactions sequence in proposal is empty"); + iroha::getSubscription()->notify( + iroha::EventTypes::kOnProposalResponse, + ProposalEvent{std::nullopt, round}); } - callback({std::move(maybe_proposal).assumeValue(), round}); }); } @@ -202,14 +266,12 @@ OnDemandOsClientGrpcFactory::OnDemandOsClientGrpcFactory( OnDemandOsClientGrpc::TimeoutType proposal_request_timeout, logger::LoggerPtr client_log, std::unique_ptr client_factory, - std::function callback, std::shared_ptr os_execution_keepers) : proposal_factory_(std::move(proposal_factory)), time_provider_(time_provider), proposal_request_timeout_(proposal_request_timeout), client_log_(std::move(client_log)), client_factory_(std::move(client_factory)), - callback_(callback), os_execution_keepers_(std::move(os_execution_keepers)) { assert(os_execution_keepers_); } @@ -225,8 +287,11 @@ OnDemandOsClientGrpcFactory::create(const shared_model::interface::Peer &to) { time_provider_, proposal_request_timeout_, client_log_, - callback_, os_execution_keepers_, to.pubkey()); }; } + +std::chrono::milliseconds OnDemandOsClientGrpcFactory::getRequestDelay() const { + return proposal_request_timeout_; +} diff --git a/irohad/ordering/impl/on_demand_os_client_grpc.hpp b/irohad/ordering/impl/on_demand_os_client_grpc.hpp index 93bac35b813..bd8bbb8fd19 100644 --- a/irohad/ordering/impl/on_demand_os_client_grpc.hpp +++ b/irohad/ordering/impl/on_demand_os_client_grpc.hpp @@ -49,15 +49,21 @@ namespace iroha { std::function time_provider, std::chrono::milliseconds proposal_request_timeout, logger::LoggerPtr log, - std::function callback, std::shared_ptr os_execution_keepers, std::string peer_name); ~OnDemandOsClientGrpc() override; void onBatches(CollectionType batches) override; + void onBatchesToWholeNetwork(CollectionType batches) override; - void onRequestProposal(consensus::Round round) override; + void onRequestProposal( + consensus::Round round, + std::optional, + BloomFilter256>> proposal) override; + + std::chrono::milliseconds getRequestDelay() const override; private: logger::LoggerPtr log_; @@ -65,7 +71,6 @@ namespace iroha { std::shared_ptr proposal_factory_; std::function time_provider_; std::chrono::milliseconds proposal_request_timeout_; - std::function callback_; std::weak_ptr context_; std::shared_ptr os_execution_keepers_; std::string peer_name_; @@ -83,19 +88,19 @@ namespace iroha { OnDemandOsClientGrpc::TimeoutType proposal_request_timeout, logger::LoggerPtr client_log, std::unique_ptr client_factory, - std::function callback, std::shared_ptr os_execution_keepers); iroha::expected::Result, std::string> create(const shared_model::interface::Peer &to) override; + std::chrono::milliseconds getRequestDelay() const override; + private: std::shared_ptr proposal_factory_; std::function time_provider_; std::chrono::milliseconds proposal_request_timeout_; logger::LoggerPtr client_log_; std::unique_ptr client_factory_; - std::function callback_; std::shared_ptr os_execution_keepers_; }; diff --git a/irohad/ordering/impl/on_demand_os_server_grpc.cpp b/irohad/ordering/impl/on_demand_os_server_grpc.cpp index 1dca2fec0b0..5fdb23c059a 100644 --- a/irohad/ordering/impl/on_demand_os_server_grpc.cpp +++ b/irohad/ordering/impl/on_demand_os_server_grpc.cpp @@ -7,6 +7,7 @@ #include "backend/protobuf/deserialize_repeated_transactions.hpp" #include "backend/protobuf/proposal.hpp" +#include "backend/protobuf/transaction.hpp" #include "interfaces/iroha_internal/parse_and_create_batches.hpp" #include "interfaces/iroha_internal/transaction_batch.hpp" #include "logger/logger.hpp" @@ -68,46 +69,45 @@ grpc::Status OnDemandOsServerGrpc::RequestProposal( consensus::Round round{request->round().block_round(), request->round().reject_round()}; log_->info("Received RequestProposal for {} from {}", round, context->peer()); - if (not ordering_service_->hasProposal(round) - and not ordering_service_->hasEnoughBatchesInCache()) { - auto scheduler = std::make_shared(); - auto tid = getSubscription()->dispatcher()->bind(scheduler); + auto maybe_proposal = ordering_service_->waitForLocalProposal(round, delay_); + if (maybe_proposal.has_value()) { + auto const &[sptr_proposal, bf_local] = maybe_proposal.value(); + response->set_bloom_filter(bf_local.load().data(), bf_local.load().size()); + response->set_proposal_hash(sptr_proposal->hash().blob().data(), + sptr_proposal->hash().blob().size()); - auto batches_subscription = SubscriberCreator< - bool, - std::shared_ptr>:: - template create( - static_cast(*tid), - [scheduler(utils::make_weak(scheduler))](auto, auto) { - if (auto maybe_scheduler = scheduler.lock()) - maybe_scheduler->dispose(); - }); - auto proposals_subscription = - SubscriberCreator::template create< - EventTypes::kOnPackProposal>( - static_cast(*tid), - [round, scheduler(utils::make_weak(scheduler))](auto, - auto packed_round) { - if (auto maybe_scheduler = scheduler.lock(); - maybe_scheduler and round == packed_round) - maybe_scheduler->dispose(); - }); - scheduler->addDelayed(delay_, [scheduler(utils::make_weak(scheduler))] { - if (auto maybe_scheduler = scheduler.lock()) { - maybe_scheduler->dispose(); - } - }); + log_->debug( + "OS proposal: {}\nproposal: {}", sptr_proposal->hash(), *sptr_proposal); - scheduler->process(); + auto const &proto_proposal = + static_cast(sptr_proposal.get()) + ->getTransport(); + if (!request->has_bloom_filter() + || request->bloom_filter().size() != BloomFilter256::kBytesCount) { + log_->info("Response with full {} txs proposal.", + sptr_proposal->transactions().size()); + *response->mutable_proposal() = proto_proposal; + } else { + response->mutable_proposal()->set_created_time( + proto_proposal.created_time()); + response->mutable_proposal()->set_height(proto_proposal.height()); - getSubscription()->dispatcher()->unbind(*tid); - } + BloomFilter256 bf_remote; + bf_remote.store(std::string_view(request->bloom_filter())); - if (auto maybe_proposal = ordering_service_->onRequestProposal(round)) { - *response->mutable_proposal() = - static_cast( - maybe_proposal->get()) - ->getTransport(); + assert((size_t)proto_proposal.transactions().size() + == sptr_proposal->transactions().size()); + for (size_t ix = 0; ix < sptr_proposal->transactions().size(); ++ix) { + assert(sptr_proposal->transactions()[ix].getBatchHash()); + if (!bf_remote.test(sptr_proposal->transactions()[(int)ix] + .getBatchHash() + .value())) { + auto *tx_dst = + response->mutable_proposal()->mutable_transactions()->Add(); + *tx_dst = proto_proposal.transactions()[(int)ix]; + } + } + } } return ::grpc::Status::OK; } diff --git a/irohad/ordering/on_demand_ordering_service.hpp b/irohad/ordering/on_demand_ordering_service.hpp index 5bb7875d948..b7923ba94f4 100644 --- a/irohad/ordering/on_demand_ordering_service.hpp +++ b/irohad/ordering/on_demand_ordering_service.hpp @@ -6,11 +6,13 @@ #ifndef IROHA_ON_DEMAND_ORDERING_SERVICE_HPP #define IROHA_ON_DEMAND_ORDERING_SERVICE_HPP +#include #include #include "consensus/round.hpp" #include "cryptography/hash.hpp" #include "interfaces/iroha_internal/transaction_batch.hpp" +#include "ordering/ordering_types.hpp" namespace shared_model { namespace interface { @@ -43,10 +45,12 @@ namespace iroha { } }; - using BatchesSetType = std::unordered_set< - std::shared_ptr, - BatchPointerHasher, - shared_model::interface::BatchHashEquality>; + using BatchesSetType = + std::set, + shared_model::interface::BatchHashLess>; + + using PackedProposalData = std::optional< + std::pair, BloomFilter256>>; /** * Type of stored transaction batches @@ -65,8 +69,7 @@ namespace iroha { */ virtual void onBatches(CollectionType batches) = 0; - virtual std::optional> - onRequestProposal(consensus::Round round) = 0; + virtual PackedProposalData onRequestProposal(consensus::Round round) = 0; using HashesSetType = std::unordered_set #include #include #include #include "common/result_fwd.hpp" #include "consensus/round.hpp" +#include "interfaces/iroha_internal/proposal.hpp" #include "interfaces/iroha_internal/transaction_batch.hpp" +#include "ordering/ordering_types.hpp" namespace shared_model { namespace interface { @@ -48,12 +51,28 @@ namespace iroha { */ virtual void onBatches(CollectionType batches) = 0; + /** + * Callback on receiving transactions, propagated to whole network. + * @param batches - vector of passed transaction batches + */ + virtual void onBatchesToWholeNetwork(CollectionType batches) = 0; + /** * Callback on request about proposal * @param round - number of collaboration round. * Calculated as block_height + 1 + * @param proposal data with Bloom filter + */ + virtual void onRequestProposal( + consensus::Round round, + std::optional, + BloomFilter256>> proposal) = 0; + + /** + * @return delay proposal to wait for. */ - virtual void onRequestProposal(consensus::Round round) = 0; + virtual std::chrono::milliseconds getRequestDelay() const = 0; virtual ~OdOsNotification() = default; }; @@ -73,6 +92,11 @@ namespace iroha { std::string> create(const shared_model::interface::Peer &to) = 0; + /** + * @return delay proposal to wait for. + */ + virtual std::chrono::milliseconds getRequestDelay() const = 0; + virtual ~OdOsNotificationFactory() = default; }; diff --git a/irohad/ordering/ordering_types.hpp b/irohad/ordering/ordering_types.hpp new file mode 100644 index 00000000000..7ef03700f9e --- /dev/null +++ b/irohad/ordering/ordering_types.hpp @@ -0,0 +1,34 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef IROHA_ORDERING_TYPES_HPP +#define IROHA_ORDERING_TYPES_HPP + +#include "consensus/round.hpp" +#include "crypto/bloom.hpp" +#include "interfaces/iroha_internal/proposal.hpp" + +namespace iroha::ordering { + + using BloomFilter256 = shared_model::crypto::BloomFilter< + shared_model::crypto::Hash, + 256, + shared_model::crypto::Iroha2BloomHasher64<0, 32>, + shared_model::crypto::Iroha2BloomHasher64<1, 32>, + shared_model::crypto::Iroha2BloomHasher64<2, 32>, + shared_model::crypto::Iroha2BloomHasher64<3, 32>>; + + struct RemoteProposalDownloadedEvent { + std::shared_ptr local; + std::shared_ptr remote; + std::string bloom_filter; + std::string remote_proposal_hash; + consensus::Round round; + shared_model::interface::types::TimestampType created_time; + }; + +} // namespace iroha::ordering + +#endif // IROHA_ORDERING_TYPES_HPP diff --git a/irohad/pending_txs_storage/CMakeLists.txt b/irohad/pending_txs_storage/CMakeLists.txt index c20309c1955..79922357730 100644 --- a/irohad/pending_txs_storage/CMakeLists.txt +++ b/irohad/pending_txs_storage/CMakeLists.txt @@ -8,7 +8,6 @@ add_library(pending_txs_storage ) target_link_libraries(pending_txs_storage - mst_state shared_model_interfaces rxcpp ) diff --git a/irohad/pending_txs_storage/impl/pending_txs_storage_impl.cpp b/irohad/pending_txs_storage/impl/pending_txs_storage_impl.cpp index 7f7f3936cdd..7e03e35dec2 100644 --- a/irohad/pending_txs_storage/impl/pending_txs_storage_impl.cpp +++ b/irohad/pending_txs_storage/impl/pending_txs_storage_impl.cpp @@ -9,7 +9,6 @@ #include "ametsuchi/tx_presence_cache_utils.hpp" #include "interfaces/transaction.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" using iroha::PendingTransactionStorageImpl; @@ -102,44 +101,42 @@ PendingTransactionStorageImpl::batchCreators(const TransactionBatch &batch) { } void PendingTransactionStorageImpl::updatedBatchesHandler( - const SharedState &updated_batches) { + std::shared_ptr const &batch) { // need to test performance somehow - where to put the lock std::unique_lock lock(mutex_); - updated_batches->iterateBatches([this](const auto &batch) { - if (isReplay(*batch)) { - return; - } + if (isReplay(*batch)) { + return; + } - auto first_tx_hash = batch->transactions().front()->hash(); - auto batch_creators = batchCreators(*batch); - auto batch_size = batch->transactions().size(); - for (const auto &creator : batch_creators) { - auto account_batches_iterator = storage_.find(creator); - if (storage_.end() == account_batches_iterator) { - auto insertion_result = storage_.emplace( - creator, PendingTransactionStorageImpl::AccountBatches{}); - BOOST_ASSERT(insertion_result.second); - account_batches_iterator = insertion_result.first; - } + auto first_tx_hash = batch->transactions().front()->hash(); + auto batch_creators = batchCreators(*batch); + auto batch_size = batch->transactions().size(); + for (const auto &creator : batch_creators) { + auto account_batches_iterator = storage_.find(creator); + if (storage_.end() == account_batches_iterator) { + auto insertion_result = storage_.emplace( + creator, PendingTransactionStorageImpl::AccountBatches{}); + BOOST_ASSERT(insertion_result.second); + account_batches_iterator = insertion_result.first; + } - auto &account_batches = account_batches_iterator->second; - auto index_iterator = account_batches.index.find(first_tx_hash); - if (index_iterator == account_batches.index.end()) { - // inserting the batch - account_batches.all_transactions_quantity += batch_size; - account_batches.batches.push_back(batch); - auto inserted_batch_iterator = std::prev(account_batches.batches.end()); - account_batches.index.emplace(first_tx_hash, inserted_batch_iterator); - for (auto &tx : batch->transactions()) { - account_batches.txs_to_batches.insert({tx->hash(), batch}); - } - } else { - // updating batch - auto &account_batch = index_iterator->second; - *account_batch = batch; + auto &account_batches = account_batches_iterator->second; + auto index_iterator = account_batches.index.find(first_tx_hash); + if (index_iterator == account_batches.index.end()) { + // inserting the batch + account_batches.all_transactions_quantity += batch_size; + account_batches.batches.push_back(batch); + auto inserted_batch_iterator = std::prev(account_batches.batches.end()); + account_batches.index.emplace(first_tx_hash, inserted_batch_iterator); + for (auto &tx : batch->transactions()) { + account_batches.txs_to_batches.insert({tx->hash(), batch}); } + } else { + // updating batch + auto &account_batch = index_iterator->second; + *account_batch = batch; } - }); + } } bool PendingTransactionStorageImpl::isReplay( diff --git a/irohad/pending_txs_storage/impl/pending_txs_storage_impl.hpp b/irohad/pending_txs_storage/impl/pending_txs_storage_impl.hpp index 089b8a7cc4e..adbcb6bff85 100644 --- a/irohad/pending_txs_storage/impl/pending_txs_storage_impl.hpp +++ b/irohad/pending_txs_storage/impl/pending_txs_storage_impl.hpp @@ -19,7 +19,6 @@ #include #include "cryptography/hash.hpp" #include "interfaces/iroha_internal/transaction_batch.hpp" -#include "multi_sig_transactions/hash.hpp" namespace iroha { class PendingTransactionStorageImpl : public PendingTransactionStorage { @@ -41,16 +40,18 @@ namespace iroha { const std::optional &first_tx_hash, const std::optional - &first_tx_time=std::nullopt, + &first_tx_time = std::nullopt, const std::optional - &last_tx_time=std::nullopt) const override; + &last_tx_time = std::nullopt) const override; void insertPresenceCache( std::shared_ptr &cache) override; void removeTransaction(HashType const &hash) override; - void updatedBatchesHandler(const SharedState &updated_batches) override; + void updatedBatchesHandler( + std::shared_ptr const &batch) + override; void removeBatch(const SharedBatch &batch) override; @@ -91,7 +92,7 @@ namespace iroha { shared_model::crypto::Hash::Hasher>, boost::bimaps::unordered_multiset_of< BatchPtr, - iroha::model::PointerBatchHasher, + shared_model::interface::BatchPointerHasher, shared_model::interface::BatchHashEquality>>; std::list batches; diff --git a/irohad/pending_txs_storage/pending_txs_storage.hpp b/irohad/pending_txs_storage/pending_txs_storage.hpp index c9107c2a288..feb120dd1c7 100644 --- a/irohad/pending_txs_storage/pending_txs_storage.hpp +++ b/irohad/pending_txs_storage/pending_txs_storage.hpp @@ -73,7 +73,7 @@ namespace iroha { * @param page_size - requested page size * @param first_tx_hash - an optional hash of the first transaction in the * batch that will be the starting point of returned transactions sequence - * @param first_tx_time - an optional timestamp of first transaction that + * @param first_tx_time - an optional timestamp of first transaction that * will be included * @param last_tx_time - an optional timestamp of last transaction that * will be included @@ -94,7 +94,8 @@ namespace iroha { shared_model::interface::types::HashType const &hash) = 0; virtual void updatedBatchesHandler( - std::shared_ptr const &updated_batches) = 0; + std::shared_ptr const + &batch) = 0; virtual void removeBatch( std::shared_ptr const diff --git a/irohad/torii/processor/CMakeLists.txt b/irohad/torii/processor/CMakeLists.txt index 04bb9c951b0..864bca332e3 100644 --- a/irohad/torii/processor/CMakeLists.txt +++ b/irohad/torii/processor/CMakeLists.txt @@ -9,7 +9,6 @@ add_library(processors target_link_libraries(processors PUBLIC logger endpoint - mst_processor common verified_proposal_creator_common ) diff --git a/irohad/torii/processor/impl/transaction_processor_impl.cpp b/irohad/torii/processor/impl/transaction_processor_impl.cpp index 2389017803f..62fb671cf45 100644 --- a/irohad/torii/processor/impl/transaction_processor_impl.cpp +++ b/irohad/torii/processor/impl/transaction_processor_impl.cpp @@ -10,7 +10,6 @@ #include "interfaces/iroha_internal/transaction_batch.hpp" #include "interfaces/iroha_internal/transaction_sequence.hpp" #include "logger/logger.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" #include "simulator/verified_proposal_creator_common.hpp" #include "validation/stateful_validator_common.hpp" @@ -48,13 +47,11 @@ namespace iroha { TransactionProcessorImpl::TransactionProcessorImpl( std::shared_ptr pcs, - std::shared_ptr mst_processor, std::shared_ptr status_bus, std::shared_ptr status_factory, logger::LoggerPtr log) : pcs_(std::move(pcs)), - mst_processor_(std::move(mst_processor)), status_bus_(std::move(status_bus)), status_factory_(std::move(status_factory)), log_(std::move(log)) {} @@ -63,15 +60,7 @@ namespace iroha { std::shared_ptr transaction_batch) const { log_->info("handle batch"); - if (transaction_batch->hasAllSignatures() - and not mst_processor_->batchInStorage(transaction_batch)) { - log_->info("propagating batch to PCS"); - publishEnoughSignaturesStatus(transaction_batch->transactions()); - pcs_->propagate_batch(transaction_batch); - } else { - log_->info("propagating batch to MST"); - mst_processor_->propagateBatch(transaction_batch); - } + pcs_->propagate_batch(transaction_batch); } void TransactionProcessorImpl::processVerifiedProposalCreatorEvent( @@ -113,19 +102,22 @@ namespace iroha { } void TransactionProcessorImpl::processStateUpdate( - std::shared_ptr const &state) { + std::shared_ptr const + &batch) { log_->info("MST state updated"); - state->iterateTransactions([this](const auto &tx) { - publishStatus(TxStatusType::kMstPending, tx->hash()); - }); + std::for_each(batch->transactions().begin(), + batch->transactions().end(), + [this](const auto &tx) { + publishStatus(TxStatusType::kMstPending, tx->hash()); + }); } void TransactionProcessorImpl::processPreparedBatch( std::shared_ptr const &batch) { log_->info("MST batch prepared"); - publishEnoughSignaturesStatus(batch->transactions()); - pcs_->propagate_batch(batch); + for (const auto &tx : batch->transactions()) + publishStatus(TxStatusType::kEnoughSignaturesCollected, tx->hash()); } void TransactionProcessorImpl::processExpiredBatch( @@ -194,13 +186,5 @@ namespace iroha { }; } } - - void TransactionProcessorImpl::publishEnoughSignaturesStatus( - const shared_model::interface::types::SharedTxsCollectionType &txs) - const { - for (const auto &tx : txs) { - publishStatus(TxStatusType::kEnoughSignaturesCollected, tx->hash()); - } - } } // namespace torii } // namespace iroha diff --git a/irohad/torii/processor/transaction_processor.hpp b/irohad/torii/processor/transaction_processor.hpp index 2bade4c52d2..635406121fd 100644 --- a/irohad/torii/processor/transaction_processor.hpp +++ b/irohad/torii/processor/transaction_processor.hpp @@ -8,6 +8,8 @@ #include +#include "interfaces/common_objects/transaction_sequence_common.hpp" + namespace shared_model { namespace interface { class Block; @@ -43,7 +45,8 @@ namespace iroha { &block) = 0; virtual void processStateUpdate( - std::shared_ptr const &state) = 0; + std::shared_ptr const + &batch) = 0; virtual void processPreparedBatch( std::shared_ptr const diff --git a/irohad/torii/processor/transaction_processor_impl.hpp b/irohad/torii/processor/transaction_processor_impl.hpp index 46b808bd80d..9d7ba09774b 100644 --- a/irohad/torii/processor/transaction_processor_impl.hpp +++ b/irohad/torii/processor/transaction_processor_impl.hpp @@ -12,7 +12,6 @@ #include "interfaces/iroha_internal/tx_status_factory.hpp" #include "interfaces/transaction_responses/tx_response.hpp" #include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/mst_processor.hpp" #include "network/peer_communication_service.hpp" #include "torii/status_bus.hpp" #include "validation/stateful_validator_common.hpp" @@ -30,7 +29,6 @@ namespace iroha { */ TransactionProcessorImpl( std::shared_ptr pcs, - std::shared_ptr mst_processor, std::shared_ptr status_bus, std::shared_ptr status_factory, @@ -47,12 +45,12 @@ namespace iroha { std::shared_ptr const &block) override; - void processStateUpdate(std::shared_ptr const &state) override; - + void processStateUpdate( + std::shared_ptr const + &batch) override; void processPreparedBatch( std::shared_ptr const &batch) override; - void processExpiredBatch( std::shared_ptr const &batch) override; @@ -61,9 +59,6 @@ namespace iroha { // connections std::shared_ptr pcs_; - // processing - std::shared_ptr mst_processor_; - std::shared_ptr status_bus_; // keeps hashes of transaction, which were committed during this round @@ -100,15 +95,6 @@ namespace iroha { const shared_model::crypto::Hash &hash, const validation::CommandError &cmd_error = validation::CommandError{}) const; - - /** - * Publish kEnoughSignaturesCollected status for each transaction in - * collection - * @param txs - collection of those transactions - */ - void publishEnoughSignaturesStatus( - const shared_model::interface::types::SharedTxsCollectionType &txs) - const; }; } // namespace torii } // namespace iroha diff --git a/libs/common/to_lower.hpp b/libs/common/to_lower.hpp index de7f83991c3..bb628dc7d6d 100644 --- a/libs/common/to_lower.hpp +++ b/libs/common/to_lower.hpp @@ -6,6 +6,7 @@ #ifndef IROHA_TO_LOWER_HPP #define IROHA_TO_LOWER_HPP +#include #include namespace iroha { @@ -16,5 +17,18 @@ namespace iroha { return dst; } + template + inline std::string_view toLower(std::string_view src, char (&dst)[N]) { + assert(N >= src.size()); + + char const *from = src.data(); + char const *const end = src.data() + src.size(); + char *ptr = dst; + + while (from != end) *ptr++ = std::tolower(*from++); + + return std::string_view(dst, src.size()); + } + } // namespace iroha #endif // IROHA_TO_LOWER_HPP diff --git a/libs/crypto/bloom.hpp b/libs/crypto/bloom.hpp new file mode 100644 index 00000000000..a8427693ec2 --- /dev/null +++ b/libs/crypto/bloom.hpp @@ -0,0 +1,112 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef IROHA_CRYPTO_BLOOM_HPP +#define IROHA_CRYPTO_BLOOM_HPP + +#include +#include +#include + +#include "common/mem_operations.hpp" +#include "cryptography/hash.hpp" + +namespace shared_model::crypto { + + template + class Iroha2BloomHasher64 { + static_assert(kIndex * sizeof(uint64_t) < kSize, "Unexpected size."); + static_assert(kSize % sizeof(uint64_t) == 0, "Inconsistent size."); + + public: + static auto pack8(shared_model::crypto::Hash const &hash) { + auto const input = *(((uint64_t *)&hash.blob()[0]) + kIndex); + auto const pack1 = (input >> 32) ^ input; + auto const pack2 = (pack1 >> 16) ^ pack1; + auto const pack3 = (((pack2 >> 8) ^ pack2) & 0xff); + + assert((pack3 >> 3) < kSize); + return std::make_pair(pack3 >> 3, pack3 & 0x7); + } + static void set(shared_model::crypto::Hash const &hash, + uint8_t (&bloom)[kSize]) { + auto const &[byte_position, bit_position] = pack8(hash); + auto &target = *(bloom + byte_position); + target |= (1 << bit_position); + } + static bool isSet(shared_model::crypto::Hash const &hash, + uint8_t const (&bloom)[kSize]) { + auto const &[byte_position, bit_position] = pack8(hash); + auto const &target = *(bloom + byte_position); + return ((target & (1 << bit_position)) != 0); + } + }; + + template + class BloomFilter final { + public: + static_assert((kBitsCount & 0x7) == 0, "BitsCount must be multiple of 8"); + static_assert(kBitsCount != 0, "BitsCount can not be 0"); + static constexpr size_t kBytesCount = (kBitsCount >> 3); + + private: + template + struct ArgsListNE { + static constexpr auto value = sizeof...(T) > 0; + }; + + uint8_t filter_[kBytesCount] __attribute__((aligned(16))); + + template + auto checkHash(DataType const &data) const { + return Hasher::isSet(data, filter_); + }; + + template ::value, + bool>::type = true> + auto runHashers(DataType const &data) const { + return checkHash(data) && runHashers(data); + } + template + auto runHashers(DataType const &data) const { + return checkHash(data); + } + + public: + BloomFilter() { + clear(); + } + + bool operator==(BloomFilter const &other) const { + return (0 == std::memcmp(filter_, other.filter_, sizeof(filter_))); + } + + void set(DataType const &data) { + ((void)HashFunctions::set(data, filter_), ...); + } + + bool test(DataType const &data) const { + return runHashers(data); + } + + void clear() { + iroha::memzero(filter_); + } + + void store(std::string_view const &data) { + if (data.size() == kBytesCount) + memcpy(filter_, data.data(), kBytesCount); + } + + std::string_view load() const { + return std::string_view((char *)filter_, kBytesCount); + } + }; + +} // namespace shared_model::crypto + +#endif // IROHA_CRYPTO_BLOOM_HPP diff --git a/schema/CMakeLists.txt b/schema/CMakeLists.txt index 881975ab886..7c117340739 100644 --- a/schema/CMakeLists.txt +++ b/schema/CMakeLists.txt @@ -8,7 +8,6 @@ set(SCHEMA_PATH ${CMAKE_CURRENT_SOURCE_DIR}) compile_proto_to_grpc_cpp(yac.proto) compile_proto_to_grpc_cpp(ordering.proto "-I${SM_SCHEMA_PATH}") compile_proto_to_grpc_cpp(loader.proto "-I${SM_SCHEMA_PATH}") -compile_proto_to_grpc_cpp(mst.proto "-I${SM_SCHEMA_PATH}") compile_proto_to_grpc_cpp(utility_endpoint.proto) add_library(endpoint @@ -57,12 +56,3 @@ target_link_libraries(loader_grpc schema gRPC::grpc++ ) - -add_library(mst_grpc - mst.pb.cc - mst.grpc.pb.cc - ) -target_link_libraries(mst_grpc - schema - gRPC::grpc++ - ) diff --git a/schema/mst.proto b/schema/mst.proto deleted file mode 100644 index 25863b4aab1..00000000000 --- a/schema/mst.proto +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -syntax = "proto3"; -package iroha.network.transport; - -import "transaction.proto"; -import "google/protobuf/empty.proto"; - -message MstState { - repeated iroha.protocol.Transaction transactions = 1; - bytes source_peer_key = 2; -} - -service MstTransportGrpc { - rpc SendState(MstState) returns (google.protobuf.Empty); -} diff --git a/schema/ordering.proto b/schema/ordering.proto index b9d0b2fb136..3d73a0b4513 100644 --- a/schema/ordering.proto +++ b/schema/ordering.proto @@ -25,12 +25,17 @@ message BatchesRequest { message ProposalRequest { ProposalRound round = 1; + oneof optional_bloom_filter { + bytes bloom_filter = 2; + } } message ProposalResponse { - oneof optional_proposal { - protocol.Proposal proposal = 1; - } + bytes bloom_filter = 1; + protocol.Proposal proposal = 2; + oneof optional_proposal_hash { + bytes proposal_hash = 3; + } } service OnDemandOrdering { diff --git a/shared_model/backend/protobuf/impl/proposal.cpp b/shared_model/backend/protobuf/impl/proposal.cpp index dd7a1abc74c..723dcadc93a 100644 --- a/shared_model/backend/protobuf/impl/proposal.cpp +++ b/shared_model/backend/protobuf/impl/proposal.cpp @@ -41,6 +41,10 @@ namespace shared_model { impl_ = std::make_unique(std::move(ref)); } + interface::types::TransactionsCollectionType Proposal::mut_transactions() { + return impl_->transactions_; + } + TransactionsCollectionType Proposal::transactions() const { return impl_->transactions_; } diff --git a/shared_model/backend/protobuf/impl/transaction.cpp b/shared_model/backend/protobuf/impl/transaction.cpp index f43310df2d3..8d9438d27fb 100644 --- a/shared_model/backend/protobuf/impl/transaction.cpp +++ b/shared_model/backend/protobuf/impl/transaction.cpp @@ -176,5 +176,15 @@ namespace shared_model { return new Transaction(TransportType(*impl_->proto_)); } + void Transaction::storeBatchHash( + shared_model::interface::types::HashType const &hash) { + batch_hash_ = hash; + } + + std::optional const & + Transaction::getBatchHash() const { + return batch_hash_; + } + } // namespace proto } // namespace shared_model diff --git a/shared_model/backend/protobuf/proposal.hpp b/shared_model/backend/protobuf/proposal.hpp index e825982abac..00990a4d018 100644 --- a/shared_model/backend/protobuf/proposal.hpp +++ b/shared_model/backend/protobuf/proposal.hpp @@ -35,6 +35,8 @@ namespace shared_model { const interface::types::HashType &hash() const override; + interface::types::TransactionsCollectionType mut_transactions() override; + ~Proposal() override; private: diff --git a/shared_model/backend/protobuf/proto_proposal_factory.hpp b/shared_model/backend/protobuf/proto_proposal_factory.hpp index 947dd7cbce0..1e92a2b9aac 100644 --- a/shared_model/backend/protobuf/proto_proposal_factory.hpp +++ b/shared_model/backend/protobuf/proto_proposal_factory.hpp @@ -42,8 +42,16 @@ namespace shared_model { interface::types::HeightType height, interface::types::TimestampType created_time, UnsafeTransactionsCollectionType transactions) override { - return std::make_unique( + auto proposal = std::make_unique( createProtoProposal(height, created_time, transactions)); + + size_t ix = 0; + for (auto &tx : transactions) + if (tx.getBatchHash()) + proposal->transactions()[ix++].storeBatchHash( + tx.getBatchHash().value()); + + return proposal; } /** diff --git a/shared_model/backend/protobuf/transaction.hpp b/shared_model/backend/protobuf/transaction.hpp index 34d9e49826c..13ad8b72b15 100644 --- a/shared_model/backend/protobuf/transaction.hpp +++ b/shared_model/backend/protobuf/transaction.hpp @@ -58,12 +58,18 @@ namespace shared_model { std::optional> batchMeta() const override; + void storeBatchHash( + shared_model::interface::types::HashType const &hash) override; + std::optional const & + getBatchHash() const override; + protected: Transaction::ModelType *clone() const override; private: struct Impl; std::unique_ptr impl_; + std::optional batch_hash_; }; } // namespace proto } // namespace shared_model diff --git a/shared_model/interfaces/iroha_internal/proposal.hpp b/shared_model/interfaces/iroha_internal/proposal.hpp index 9e9b85dd2bc..89fa5f14c91 100644 --- a/shared_model/interfaces/iroha_internal/proposal.hpp +++ b/shared_model/interfaces/iroha_internal/proposal.hpp @@ -20,6 +20,7 @@ namespace shared_model { * @return transactions */ virtual types::TransactionsCollectionType transactions() const = 0; + virtual types::TransactionsCollectionType mut_transactions() = 0; /** * @return the height diff --git a/shared_model/interfaces/iroha_internal/transaction_batch.cpp b/shared_model/interfaces/iroha_internal/transaction_batch.cpp index f707015dce4..cace9910912 100644 --- a/shared_model/interfaces/iroha_internal/transaction_batch.cpp +++ b/shared_model/interfaces/iroha_internal/transaction_batch.cpp @@ -5,6 +5,8 @@ #include "interfaces/iroha_internal/transaction_batch.hpp" +#include + #include "interfaces/transaction.hpp" #include "utils/string_builder.hpp" @@ -23,5 +25,18 @@ namespace shared_model { const std::shared_ptr &right_tx) const { return left_tx->reducedHash() == right_tx->reducedHash(); } + + size_t BatchPointerHasher::operator()( + const std::shared_ptr &a) + const { + return hasher_(a->reducedHash()); + } + + bool BatchHashLess::operator()( + const std::shared_ptr &left_tx, + const std::shared_ptr &right_tx) const { + return std::less{}( + left_tx->reducedHash().blob(), right_tx->reducedHash().blob()); + } } // namespace interface } // namespace shared_model diff --git a/shared_model/interfaces/iroha_internal/transaction_batch.hpp b/shared_model/interfaces/iroha_internal/transaction_batch.hpp index 20f0e6989e8..1604e8a0eca 100644 --- a/shared_model/interfaces/iroha_internal/transaction_batch.hpp +++ b/shared_model/interfaces/iroha_internal/transaction_batch.hpp @@ -69,6 +69,26 @@ namespace shared_model { bool operator()(const std::shared_ptr &left_tx, const std::shared_ptr &right_tx) const; }; + + struct BatchPointerHasher { + shared_model::crypto::Hash::Hasher hasher_; + size_t operator()( + const std::shared_ptr &a) + const; + }; + + /** + * This is a helper structure which serves as a predicate + * for hash comparison. + */ + struct BatchHashLess { + /** + * The function used to compare batches for equality: + * check only hashes of batches, without signatures + */ + bool operator()(const std::shared_ptr &left_tx, + const std::shared_ptr &right_tx) const; + }; } // namespace interface } // namespace shared_model diff --git a/shared_model/interfaces/iroha_internal/transaction_batch_impl.cpp b/shared_model/interfaces/iroha_internal/transaction_batch_impl.cpp index ae100e257e0..549dd18ea22 100644 --- a/shared_model/interfaces/iroha_internal/transaction_batch_impl.cpp +++ b/shared_model/interfaces/iroha_internal/transaction_batch_impl.cpp @@ -24,6 +24,8 @@ namespace shared_model { transactions_ | boost::adaptors::transformed([](const auto &tx) { return tx->reducedHash(); })); + + for (auto &tx : transactions_) tx->storeBatchHash(reduced_hash_); } const types::SharedTxsCollectionType &TransactionBatchImpl::transactions() diff --git a/shared_model/interfaces/transaction.hpp b/shared_model/interfaces/transaction.hpp index 44ef9c7fa3d..2046fb9138d 100644 --- a/shared_model/interfaces/transaction.hpp +++ b/shared_model/interfaces/transaction.hpp @@ -54,6 +54,9 @@ namespace shared_model { */ virtual const types::HashType &reducedHash() const = 0; + virtual void storeBatchHash(types::HashType const &hash) = 0; + virtual std::optional const &getBatchHash() const = 0; + /** * @return new Transaction obeject with moved data */ diff --git a/shared_model/validators/default_validator.hpp b/shared_model/validators/default_validator.hpp index 70163967994..dc5ab1c462d 100644 --- a/shared_model/validators/default_validator.hpp +++ b/shared_model/validators/default_validator.hpp @@ -109,11 +109,17 @@ namespace shared_model { BatchOrderValidator, false>; + using DefaultSignedTransactionsValidatorWithAllowedEmptyList = + TransactionsCollectionValidator; + /** * Proposal validator which checks stateless validation of proposal */ - using DefaultProposalValidator = - ProposalValidator; + using DefaultProposalValidator = ProposalValidator< + FieldValidator, + DefaultSignedTransactionsValidatorWithAllowedEmptyList>; /** * Block validator which checks blocks WITHOUT signatures. Note that it does diff --git a/test/framework/CMakeLists.txt b/test/framework/CMakeLists.txt index 68e7caf744e..1710e31149b 100644 --- a/test/framework/CMakeLists.txt +++ b/test/framework/CMakeLists.txt @@ -32,7 +32,6 @@ add_library(integration_framework integration_framework/fake_peer/behaviour/empty.cpp integration_framework/fake_peer/behaviour/honest.cpp integration_framework/fake_peer/network/loader_grpc.cpp - integration_framework/fake_peer/network/mst_network_notifier.cpp integration_framework/fake_peer/network/on_demand_os_network_notifier.cpp integration_framework/fake_peer/network/ordering_service_network_notifier.cpp integration_framework/fake_peer/network/ordering_gate_network_notifier.cpp @@ -53,7 +52,6 @@ target_link_libraries(integration_framework ordering_gate_common shared_model_cryptography_model server_runner - mst_transport test_logger pg_connection_init rdb_connection_init diff --git a/test/framework/integration_framework/fake_peer/behaviour/behaviour.cpp b/test/framework/integration_framework/fake_peer/behaviour/behaviour.cpp index 9196b598edc..c3f9306e5bb 100644 --- a/test/framework/integration_framework/fake_peer/behaviour/behaviour.cpp +++ b/test/framework/integration_framework/fake_peer/behaviour/behaviour.cpp @@ -50,11 +50,6 @@ namespace integration_framework { using iroha::operator|; // subscribe for all messages - fake_peer->getMstStatesObservable().subscribe( - subscription, [locker](std::shared_ptr const &message) { - locker.protect() | - [&](auto protector) { protector->processMstMessage(message); }; - }); fake_peer->getYacStatesObservable().subscribe( subscription, [locker](std::shared_ptr const &message) { diff --git a/test/framework/integration_framework/fake_peer/behaviour/behaviour.hpp b/test/framework/integration_framework/fake_peer/behaviour/behaviour.hpp index 806ce5c85d3..79bc0ad1a35 100644 --- a/test/framework/integration_framework/fake_peer/behaviour/behaviour.hpp +++ b/test/framework/integration_framework/fake_peer/behaviour/behaviour.hpp @@ -36,9 +36,6 @@ namespace integration_framework { /// Disable the behaviour void absolve(); - /// This method gets subscribed on Fake Peer's MST messages. - virtual void processMstMessage(std::shared_ptr message) = 0; - /// This method gets subscribed on Fake Peer's YAC messages. virtual void processYacMessage( std::shared_ptr message) = 0; diff --git a/test/framework/integration_framework/fake_peer/behaviour/empty.cpp b/test/framework/integration_framework/fake_peer/behaviour/empty.cpp index 8b89872c8e1..a2100ba03ab 100644 --- a/test/framework/integration_framework/fake_peer/behaviour/empty.cpp +++ b/test/framework/integration_framework/fake_peer/behaviour/empty.cpp @@ -8,8 +8,6 @@ namespace integration_framework { namespace fake_peer { - void EmptyBehaviour::processMstMessage( - std::shared_ptr message) {} void EmptyBehaviour::processYacMessage( std::shared_ptr message) {} void EmptyBehaviour::processOsBatch( diff --git a/test/framework/integration_framework/fake_peer/behaviour/empty.hpp b/test/framework/integration_framework/fake_peer/behaviour/empty.hpp index 5662076912a..5e242d49fb9 100644 --- a/test/framework/integration_framework/fake_peer/behaviour/empty.hpp +++ b/test/framework/integration_framework/fake_peer/behaviour/empty.hpp @@ -20,7 +20,6 @@ namespace integration_framework { public: virtual ~EmptyBehaviour() = default; - void processMstMessage(std::shared_ptr message) override; void processYacMessage( std::shared_ptr message) override; void processOsBatch( diff --git a/test/framework/integration_framework/fake_peer/fake_peer.cpp b/test/framework/integration_framework/fake_peer/fake_peer.cpp index 585e4e45950..f6629954fdb 100644 --- a/test/framework/integration_framework/fake_peer/fake_peer.cpp +++ b/test/framework/integration_framework/fake_peer/fake_peer.cpp @@ -21,7 +21,6 @@ #include "framework/integration_framework/fake_peer/behaviour/behaviour.hpp" #include "framework/integration_framework/fake_peer/block_storage.hpp" #include "framework/integration_framework/fake_peer/network/loader_grpc.hpp" -#include "framework/integration_framework/fake_peer/network/mst_network_notifier.hpp" #include "framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.hpp" #include "framework/integration_framework/fake_peer/network/ordering_gate_network_notifier.hpp" #include "framework/integration_framework/fake_peer/network/ordering_service_network_notifier.hpp" @@ -34,7 +33,6 @@ #include "logger/logger.hpp" #include "logger/logger_manager.hpp" #include "main/server_runner.hpp" -#include "multi_sig_transactions/transport/mst_transport_grpc.hpp" #include "network/impl/async_grpc_client.hpp" #include "network/impl/client_factory.hpp" #include "ordering/impl/on_demand_os_client_grpc.hpp" @@ -105,23 +103,10 @@ FakePeer::FakePeer( log_manager_->getChild("AsyncNetworkClient")->getLogger())), client_factory_( iroha::network::getTestInsecureClientFactory(std::nullopt)), - mst_transport_(std::make_shared( - async_call_, - transaction_factory, - batch_parser, - transaction_batch_factory, - tx_presence_cache, - std::make_shared(std::chrono::minutes(0)), - PublicKeyHexStringView{keypair_->publicKey()}, - mst_log_manager_->getChild("State")->getLogger(), - mst_log_manager_->getChild("Transport")->getLogger(), - iroha::network::makeTransportClientFactory( - client_factory_))), yac_transport_client_(std::make_shared( iroha::network::makeTransportClientFactory( client_factory_), consensus_log_manager_->getChild("Transport")->getLogger())), - mst_network_notifier_(std::make_shared()), yac_network_notifier_(std::make_shared()), os_network_notifier_(std::make_shared()), og_network_notifier_(std::make_shared()), @@ -138,7 +123,6 @@ FakePeer::FakePeer( })), yac_crypto_(std::make_shared( *keypair_, consensus_log_manager_->getChild("Crypto")->getLogger())) { - mst_transport_->subscribe(mst_network_notifier_); } FakePeer::~FakePeer() { @@ -218,7 +202,6 @@ std::unique_ptr FakePeer::run(bool reuse_port) { log_manager_->getChild("InternalServer")->getLogger(), reuse_port); internal_server->append(yac_transport_server_) - .append(mst_transport_) .append(od_os_transport_) .append(synchronizer_transport_) .run() @@ -251,11 +234,6 @@ std::shared_ptr FakePeer::getThisPeer() const { return this_peer_; } -rxcpp::observable> -FakePeer::getMstStatesObservable() { - return mst_network_notifier_->getObservable(); -} - rxcpp::observable< std::shared_ptr> FakePeer::getYacStatesObservable() { @@ -321,10 +299,6 @@ iroha::consensus::yac::VoteMessage FakePeer::makeVote( return yac_crypto_->getVote(my_yac_hash); } -void FakePeer::sendMstState(const iroha::MstState &state) { - mst_transport_->sendState(real_peer_, state); -} - void FakePeer::sendYacState( const std::vector &state) { yac_transport_client_->sendState(*real_peer_, state); diff --git a/test/framework/integration_framework/fake_peer/fake_peer.hpp b/test/framework/integration_framework/fake_peer/fake_peer.hpp index de5af76e2d8..09914959413 100644 --- a/test/framework/integration_framework/fake_peer/fake_peer.hpp +++ b/test/framework/integration_framework/fake_peer/fake_peer.hpp @@ -13,7 +13,6 @@ #include "common/result_fwd.hpp" #include "consensus/yac/transport/impl/consensus_service_impl.hpp" -#include "framework/integration_framework/fake_peer/network/mst_message.hpp" #include "framework/integration_framework/fake_peer/proposal_storage.hpp" #include "framework/integration_framework/fake_peer/types.hpp" #include "interfaces/iroha_internal/abstract_transport_factory.hpp" @@ -46,8 +45,9 @@ namespace integration_framework::fake_peer { public: /// Instead of constructor because shared_from_this template - static std::shared_ptr createShared(Args &&...args) { - return std::make_shared(HideCtor{}, std::forward(args)...); + static std::shared_ptr createShared(Args &&... args) { + return std::make_shared(HideCtor{}, + std::forward(args)...); } /** @@ -125,9 +125,6 @@ namespace integration_framework::fake_peer { /// Get interface::Peer object for this instance. std::shared_ptr getThisPeer() const; - /// Get the observable of MST states received by this peer. - rxcpp::observable> getMstStatesObservable(); - /// Get the observable of YAC states received by this peer. rxcpp::observable> getYacStatesObservable(); @@ -174,9 +171,6 @@ namespace integration_framework::fake_peer { iroha::consensus::yac::VoteMessage makeVote( iroha::consensus::yac::YacHash yac_hash); - /// Send the main peer the given MST state. - void sendMstState(const iroha::MstState &state); - /// Send the main peer the given YAC state. void sendYacState( const std::vector &state); @@ -204,7 +198,6 @@ namespace integration_framework::fake_peer { transactions); private: - using MstTransport = iroha::network::MstTransportGrpc; using YacTransportClient = iroha::consensus::yac::NetworkImpl; using YacTransportServer = iroha::consensus::yac::ServiceImpl; using OsTransport = iroha::ordering::OrderingServiceTransportGrpc; @@ -246,12 +239,10 @@ namespace integration_framework::fake_peer { std::shared_ptr async_call_; std::shared_ptr client_factory_; - std::shared_ptr mst_transport_; std::shared_ptr yac_transport_client_; std::shared_ptr od_os_transport_; std::shared_ptr synchronizer_transport_; - std::shared_ptr mst_network_notifier_; std::shared_ptr yac_network_notifier_; std::shared_ptr os_network_notifier_; std::shared_ptr og_network_notifier_; diff --git a/test/framework/integration_framework/fake_peer/network/mst_message.hpp b/test/framework/integration_framework/fake_peer/network/mst_message.hpp deleted file mode 100644 index 2f348eadbfe..00000000000 --- a/test/framework/integration_framework/fake_peer/network/mst_message.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef INTEGRATION_FRAMEWORK_FAKE_PEER_MST_MESSAGE_HPP_ -#define INTEGRATION_FRAMEWORK_FAKE_PEER_MST_MESSAGE_HPP_ - -#include "multi_sig_transactions/state/mst_state.hpp" - -namespace integration_framework { - namespace fake_peer { - struct MstMessage final { - MstMessage(shared_model::interface::types::PublicKeyHexStringView f, - iroha::MstState s) - : peer_hex_key_from(f), state(std::move(s)) {} - std::string peer_hex_key_from; - iroha::MstState state; - }; - } // namespace fake_peer -} // namespace integration_framework - -#endif /* INTEGRATION_FRAMEWORK_FAKE_PEER_MST_MESSAGE_HPP_ */ diff --git a/test/framework/integration_framework/fake_peer/network/mst_network_notifier.cpp b/test/framework/integration_framework/fake_peer/network/mst_network_notifier.cpp deleted file mode 100644 index 22dfe0af305..00000000000 --- a/test/framework/integration_framework/fake_peer/network/mst_network_notifier.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "framework/integration_framework/fake_peer/network/mst_network_notifier.hpp" - -namespace integration_framework { - namespace fake_peer { - - void MstNetworkNotifier::onNewState( - shared_model::interface::types::PublicKeyHexStringView from, - iroha::MstState &&new_state) { - std::lock_guard guard(mst_subject_mutex_); - mst_subject_.get_subscriber().on_next( - std::make_shared(from, std::move(new_state))); - } - - rxcpp::observable> - MstNetworkNotifier::getObservable() { - return mst_subject_.get_observable(); - } - - } // namespace fake_peer -} // namespace integration_framework diff --git a/test/framework/integration_framework/fake_peer/network/mst_network_notifier.hpp b/test/framework/integration_framework/fake_peer/network/mst_network_notifier.hpp deleted file mode 100644 index 4441c6aef77..00000000000 --- a/test/framework/integration_framework/fake_peer/network/mst_network_notifier.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef FAKE_PEER_MST_NETWORK_NOTIFIER_HPP_ -#define FAKE_PEER_MST_NETWORK_NOTIFIER_HPP_ - -#include "network/mst_transport.hpp" - -#include - -#include -#include "framework/integration_framework/fake_peer/network/mst_message.hpp" -#include "framework/integration_framework/fake_peer/types.hpp" - -namespace integration_framework { - namespace fake_peer { - - class MstNetworkNotifier final - : public iroha::network::MstTransportNotification { - public: - void onNewState( - shared_model::interface::types::PublicKeyHexStringView from, - iroha::MstState &&new_state) override; - - rxcpp::observable> getObservable(); - - private: - rxcpp::subjects::subject> mst_subject_; - std::mutex mst_subject_mutex_; - }; - - } // namespace fake_peer -} // namespace integration_framework - -#endif /* FAKE_PEER_MST_NETWORK_NOTIFIER_HPP_ */ diff --git a/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.cpp b/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.cpp index b6ebeac983d..8927f0623da 100644 --- a/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.cpp +++ b/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.cpp @@ -5,10 +5,13 @@ #include "framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.hpp" +#include + #include "backend/protobuf/proposal.hpp" #include "framework/integration_framework/fake_peer/behaviour/behaviour.hpp" #include "framework/integration_framework/fake_peer/fake_peer.hpp" #include "framework/integration_framework/fake_peer/proposal_storage.hpp" +#include "ordering/ordering_types.hpp" namespace integration_framework::fake_peer { @@ -22,7 +25,14 @@ namespace integration_framework::fake_peer { std::make_shared(std::move(batches))); } - std::optional> + OnDemandOsNetworkNotifier::PackedProposalData + OnDemandOsNetworkNotifier::waitForLocalProposal( + iroha::consensus::Round const &round, + std::chrono::milliseconds const & /*delay*/) { + return onRequestProposal(round); + } + + OnDemandOsNetworkNotifier::PackedProposalData OnDemandOsNetworkNotifier::onRequestProposal(iroha::consensus::Round round) { { std::lock_guard guard(rounds_subject_mutex_); @@ -34,9 +44,11 @@ namespace integration_framework::fake_peer { if (behaviour) { auto opt_proposal = behaviour->processOrderingProposalRequest(round); if (opt_proposal) { - return std::shared_ptr( - std::static_pointer_cast( - *opt_proposal)); + return std::make_pair( + std::shared_ptr( + std::static_pointer_cast( + *opt_proposal)), + iroha::ordering::BloomFilter256{}); } } return {}; diff --git a/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.hpp b/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.hpp index b2d5234cea0..e42dc0b4559 100644 --- a/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.hpp +++ b/test/framework/integration_framework/fake_peer/network/on_demand_os_network_notifier.hpp @@ -23,7 +23,7 @@ namespace integration_framework::fake_peer { void onBatches(CollectionType batches) override; - std::optional> onRequestProposal( + PackedProposalData onRequestProposal( iroha::consensus::Round round) override; void onCollaborationOutcome(iroha::consensus::Round round) override; @@ -37,6 +37,10 @@ namespace integration_framework::fake_peer { iroha::ordering::OnDemandOrderingService::BatchesSetType &)> const &f) override; + PackedProposalData waitForLocalProposal( + iroha::consensus::Round const &round, + std::chrono::milliseconds const &delay) override; + bool isEmptyBatchesCache() override; bool hasEnoughBatchesInCache() const override; diff --git a/test/framework/integration_framework/fake_peer/proposal_storage.hpp b/test/framework/integration_framework/fake_peer/proposal_storage.hpp index c1cb60283cb..7dcd15f7fbb 100644 --- a/test/framework/integration_framework/fake_peer/proposal_storage.hpp +++ b/test/framework/integration_framework/fake_peer/proposal_storage.hpp @@ -15,8 +15,6 @@ #include "consensus/round.hpp" #include "framework/integration_framework/fake_peer/types.hpp" #include "interfaces/iroha_internal/unsafe_proposal_factory.hpp" -#include "multi_sig_transactions/hash.hpp" // for PointerBatchHasher -#include "multi_sig_transactions/state/mst_state.hpp" // for BatchHashEquality namespace integration_framework { namespace fake_peer { diff --git a/test/framework/integration_framework/fake_peer/types.hpp b/test/framework/integration_framework/fake_peer/types.hpp index c633958ddf4..01c3b14ed00 100644 --- a/test/framework/integration_framework/fake_peer/types.hpp +++ b/test/framework/integration_framework/fake_peer/types.hpp @@ -40,10 +40,6 @@ namespace iroha { namespace protocol { class Transaction; } - namespace network { - class MstTransportGrpc; - class MstTransportNotification; - } // namespace network namespace consensus { namespace yac { class NetworkImpl; diff --git a/test/framework/integration_framework/integration_test_framework.cpp b/test/framework/integration_framework/integration_test_framework.cpp index b7d814dae45..6dd1188a88e 100644 --- a/test/framework/integration_framework/integration_test_framework.cpp +++ b/test/framework/integration_framework/integration_test_framework.cpp @@ -47,8 +47,6 @@ #include "module/shared_model/builders/protobuf/block.hpp" #include "module/shared_model/builders/protobuf/proposal.hpp" #include "module/shared_model/validators/always_valid_validators.hpp" -#include "multi_sig_transactions/mst_processor.hpp" -#include "multi_sig_transactions/transport/mst_transport_grpc.hpp" #include "network/consensus_gate.hpp" #include "network/impl/channel_factory.hpp" #include "network/peer_communication_service.hpp" @@ -233,7 +231,8 @@ IntegrationTestFramework::IntegrationTestFramework( logger::LoggerManagerTreePtr log_manager, std::string db_wsv_path, std::string db_store_path) - : log_(log_manager->getLogger()), + : subscription{iroha::getSubscription()}, + log_(log_manager->getLogger()), log_manager_(std::move(log_manager)), proposal_queue_( std::make_uniquesetMstGossipParams(mst_gossip_emitting_period, - mst_gossip_amount_per_once); - return *this; -} - IntegrationTestFramework &IntegrationTestFramework::setInitialState( const Keypair &keypair, const shared_model::interface::Block &block) { initPipeline(keypair); @@ -609,25 +599,6 @@ std::string IntegrationTestFramework::getAddress() const { return format_address(kLocalHost, config_.internal_port); } -rxcpp::observable> -IntegrationTestFramework::getMstStateUpdateObservable() { - return iroha_instance_->getTestIrohad()->getMstProcessor()->onStateUpdate(); -} - -rxcpp::observable -IntegrationTestFramework::getMstPreparedBatchesObservable() { - return iroha_instance_->getTestIrohad() - ->getMstProcessor() - ->onPreparedBatches(); -} - -rxcpp::observable -IntegrationTestFramework::getMstExpiredBatchesObservable() { - return iroha_instance_->getTestIrohad() - ->getMstProcessor() - ->onExpiredBatches(); -} - std::shared_ptr IntegrationTestFramework::getBlockQuery() { return getIrohaInstance().getTestIrohad()->getStorage()->getBlockQuery(); @@ -766,16 +737,6 @@ IntegrationTestFramework &IntegrationTestFramework::sendQuery( return *this; } -IntegrationTestFramework &IntegrationTestFramework::sendMstState( - PublicKeyHexStringView src_key, const iroha::MstState &mst_state) { - auto client = makeTransportClientFactory( - client_factory_) - ->createClient(*this_peer_) - .assumeValue(); - iroha::network::sendStateAsync(mst_state, src_key, *client, *async_call_); - return *this; -} - IntegrationTestFramework &IntegrationTestFramework::sendYacState( const std::vector &yac_state) { yac_transport_->sendState(*this_peer_, yac_state); diff --git a/test/framework/integration_framework/integration_test_framework.hpp b/test/framework/integration_framework/integration_test_framework.hpp index 90ae28c1c38..765fca51f13 100644 --- a/test/framework/integration_framework/integration_test_framework.hpp +++ b/test/framework/integration_framework/integration_test_framework.hpp @@ -69,7 +69,6 @@ namespace iroha { } // namespace consensus namespace network { class GenericClientFactory; - class MstTransportGrpc; struct OrderingEvent; class ServerRunner; template @@ -196,11 +195,6 @@ namespace integration_framework { IntegrationTestFramework &setInitialState( const shared_model::crypto::Keypair &keypair); - /// Set Gossip MST propagation parameters. - IntegrationTestFramework &setMstGossipParams( - std::chrono::milliseconds mst_gossip_emitting_period, - uint32_t mst_gossip_amount_per_once); - /** * Initialize Iroha instance with provided genesis block and signing key * @param keypair - signing key @@ -328,17 +322,6 @@ namespace integration_framework { /// Send a batch of transactions to this peer's ordering service. IntegrationTestFramework &sendBatch(const TransactionBatchSPtr &batch); - /** - * Send MST state message to this peer. - * @param src_key - the key of the peer which the message appears to come - * from - * @param mst_state - the MST state to send - * @return this - */ - IntegrationTestFramework &sendMstState( - shared_model::interface::types::PublicKeyHexStringView src_key, - const iroha::MstState &mst_state); - /** * Send MST state message to this peer. * @param src_key - the key of the peer which the message appears to come @@ -401,17 +384,6 @@ namespace integration_framework { */ IntegrationTestFramework &skipBlock(); - rxcpp::observable> - getMstStateUpdateObservable(); - - rxcpp::observable< - std::shared_ptr> - getMstPreparedBatchesObservable(); - - rxcpp::observable< - std::shared_ptr> - getMstExpiredBatchesObservable(); - /// Get block query for iroha block storage. std::shared_ptr getBlockQuery(); @@ -481,6 +453,8 @@ namespace integration_framework { const WaitTime &wait, const std::string &error_reason); + std::shared_ptr subscription; + logger::LoggerPtr log_; logger::LoggerManagerTreePtr log_manager_; @@ -542,7 +516,6 @@ namespace integration_framework { std::shared_ptr tx_presence_cache_; std::shared_ptr client_factory_; - std::shared_ptr mst_transport_; std::shared_ptr yac_transport_; std::optional my_key_; diff --git a/test/framework/integration_framework/iroha_instance.cpp b/test/framework/integration_framework/iroha_instance.cpp index 45bb85be089..1918b309a1d 100644 --- a/test/framework/integration_framework/iroha_instance.cpp +++ b/test/framework/integration_framework/iroha_instance.cpp @@ -37,13 +37,6 @@ namespace integration_framework { ? config_.database_config->path : (fs::temp_directory_path() / fs::unique_path()).string()), listen_ip_(listen_ip), - opt_mst_gossip_params_(boost::make_optional( - config_.mst_support, - [] { - iroha::GossipPropagationStrategyParams params; - params.emission_period = kMstEmissionPeriod; - return params; - }())), irohad_log_manager_(std::move(irohad_log_manager)), log_(std::move(log)), startup_wsv_data_policy_(startup_wsv_data_policy) {} @@ -76,18 +69,6 @@ namespace integration_framework { } } - void IrohaInstance::setMstGossipParams( - std::chrono::milliseconds mst_gossip_emitting_period, - uint32_t mst_gossip_amount_per_once) { - BOOST_ASSERT_MSG( - not test_irohad_, - "Gossip propagation params must be set before Irohad is started!"); - iroha::GossipPropagationStrategyParams gossip_params; - gossip_params.emission_period = mst_gossip_emitting_period; - gossip_params.amount_per_once = mst_gossip_amount_per_once; - opt_mst_gossip_params_ = gossip_params; - } - void IrohaInstance::printDbStatus() { test_irohad_->printDbStatus(); } @@ -104,15 +85,14 @@ namespace integration_framework { key_pair, irohad_log_manager_, log_, - startup_wsv_data_policy_, - opt_mst_gossip_params_); + startup_wsv_data_policy_); } void IrohaInstance::run() { test_irohad_->run().match( [](const auto &) {}, [this](const auto &error) { - log_->error("{}",error.error); + log_->error("{}", error.error); BOOST_THROW_EXCEPTION(std::runtime_error(error.error)); }); } diff --git a/test/framework/integration_framework/iroha_instance.hpp b/test/framework/integration_framework/iroha_instance.hpp index 108652697e7..0b70bed8f10 100644 --- a/test/framework/integration_framework/iroha_instance.hpp +++ b/test/framework/integration_framework/iroha_instance.hpp @@ -18,7 +18,6 @@ #include "logger/logger_manager_fwd.hpp" #include "main/iroha_conf_loader.hpp" #include "main/startup_params.hpp" -#include "multi_sig_transactions/gossip_propagation_strategy_params.hpp" #include "torii/tls_params.hpp" namespace shared_model { @@ -59,10 +58,6 @@ namespace integration_framework { void rawInsertBlock( std::shared_ptr block); - void setMstGossipParams( - std::chrono::milliseconds mst_gossip_emitting_period, - uint32_t mst_gossip_amount_per_once); - void initPipeline(const shared_model::crypto::Keypair &key_pair, size_t max_proposal_size = 10); @@ -80,8 +75,6 @@ namespace integration_framework { const std::string working_dbname_; const std::string rocksdb_filepath_; const std::string listen_ip_; - boost::optional - opt_mst_gossip_params_; private: std::shared_ptr test_irohad_; diff --git a/test/framework/integration_framework/test_irohad.hpp b/test/framework/integration_framework/test_irohad.hpp index da6c1e35a79..a793e520931 100644 --- a/test/framework/integration_framework/test_irohad.hpp +++ b/test/framework/integration_framework/test_irohad.hpp @@ -25,9 +25,7 @@ namespace integration_framework { const shared_model::crypto::Keypair &keypair, logger::LoggerManagerTreePtr irohad_log_manager, logger::LoggerPtr log, - iroha::StartupWsvDataPolicy startup_wsv_data_policy, - const boost::optional - &opt_mst_gossip_params = boost::none) + iroha::StartupWsvDataPolicy startup_wsv_data_policy) : Irohad(config, std::move(pg_opt), std::move(rdb_opt), @@ -37,7 +35,6 @@ namespace integration_framework { startup_wsv_data_policy, iroha::StartupWsvSynchronizationPolicy::kSyncUpAndGo, std::nullopt, - opt_mst_gossip_params, boost::none), log_(std::move(log)) {} @@ -53,10 +50,6 @@ namespace integration_framework { return query_service; } - auto &getMstProcessor() { - return mst_processor; - } - auto &getConsensusGate() { return consensus_gate; } diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt index 37beb54c660..5e199af3654 100644 --- a/test/fuzzing/CMakeLists.txt +++ b/test/fuzzing/CMakeLists.txt @@ -103,16 +103,6 @@ target_link_libraries(consensus_fuzz ${fuzzing_engine} ) -add_executable(mst_fuzz mst_fuzz.cpp) -target_link_libraries(mst_fuzz - protobuf-mutator - GTest::gtest - GTest::gmock - mst_transport - ametsuchi - ${fuzzing_engine} - ) - add_custom_target(fuzzing DEPENDS torii_fuzz status_fuzz @@ -122,5 +112,4 @@ add_custom_target(fuzzing DEPENDS retrieve_block_fuzz retrieve_blocks_fuzz consensus_fuzz - mst_fuzz ) diff --git a/test/fuzzing/mst_fuzz.cpp b/test/fuzzing/mst_fuzz.cpp deleted file mode 100644 index cd5dca67dad..00000000000 --- a/test/fuzzing/mst_fuzz.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include - -#include "ametsuchi/impl/tx_presence_cache_impl.hpp" -#include "backend/protobuf/proto_transport_factory.hpp" -#include "framework/crypto_literals.hpp" -#include "fuzzing/grpc_servercontext_dtor_segv_workaround.hpp" -#include "interfaces/iroha_internal/transaction_batch_factory_impl.hpp" -#include "interfaces/iroha_internal/transaction_batch_parser_impl.hpp" -#include "logger/dummy_logger.hpp" -#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" -#include "module/irohad/ametsuchi/mock_client_factory.hpp" -#include "module/irohad/common/validators_config.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "multi_sig_transactions/transport/mst_transport_grpc.hpp" -#include "validators/default_validator.hpp" -#include "validators/protobuf/proto_transaction_validator.hpp" - -using namespace testing; -using namespace iroha::network; - -namespace fuzzing { - struct MstFixture { - std::shared_ptr completer_; - std::shared_ptr mst_transport_grpc_; - - MstFixture() { - auto async_call_ = std::make_shared< - iroha::network::AsyncGrpcClient>( - logger::getDummyLoggerPtr()); - // TODO luckychess 25.12.2018 Component initialisation reuse - // IR-1886, IR-142 - std::unique_ptr> - interface_validator = std::make_unique< - shared_model::validation::DefaultUnsignedTransactionValidator>( - iroha::test::kTestsValidatorsConfig); - std::unique_ptr> - tx_validator = std::make_unique< - shared_model::validation::ProtoTransactionValidator>(); - - auto tx_factory = - std::make_shared>(std::move(interface_validator), - std::move(tx_validator)); - auto parser = std::make_shared< - shared_model::interface::TransactionBatchParserImpl>(); - std::shared_ptr> - batch_validator = - std::make_shared( - iroha::test::kTestsValidatorsConfig); - auto batch_factory = std::make_shared< - shared_model::interface::TransactionBatchFactoryImpl>( - batch_validator); - auto storage = - std::make_shared>(); - auto cache = - std::make_shared(storage); - completer_ = std::make_shared(); - mst_transport_grpc_ = std::make_shared( - async_call_, - std::move(tx_factory), - std::move(parser), - std::move(batch_factory), - std::move(cache), - completer_, - "my key"_hex_pubkey, - logger::getDummyLoggerPtr(), - logger::getDummyLoggerPtr(), - std::make_unique< - iroha::network::MockClientFactory>()); - } - }; -} // namespace fuzzing - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size) { - static fuzzing::MstFixture fixture; - - if (size < 1) { - return 0; - } - - transport::MstState request; - if (protobuf_mutator::libfuzzer::LoadProtoInput(true, data, size, &request)) { - grpc::ServerContext context; - google::protobuf::Empty response; - fixture.mst_transport_grpc_->SendState(&context, &request, &response); - } - - return 0; -} diff --git a/test/integration/acceptance/add_peer_test.cpp b/test/integration/acceptance/add_peer_test.cpp index 480174e2907..1feebc903ce 100644 --- a/test/integration/acceptance/add_peer_test.cpp +++ b/test/integration/acceptance/add_peer_test.cpp @@ -126,9 +126,6 @@ TEST_P(AddPeerTest, MstStatePropagtesToNewPeer) { auto new_peer = itf.addFakePeer(boost::none); ASSERT_TRUE(new_peer); - auto mst_states_observable = new_peer->getMstStatesObservable().replay(); - mst_states_observable.connect(); - itf.unbind_guarded_port(new_peer->getPort()); auto new_peer_server = new_peer->run(true); @@ -146,19 +143,6 @@ TEST_P(AddPeerTest, MstStatePropagtesToNewPeer) { checkBlockHasNTxs<1>); // ------------------------ THEN ------------------------- - mst_states_observable - .timeout(kMstStateWaitingTime, rxcpp::observe_on_new_thread()) - .take(1) - .as_blocking() - .subscribe([](const auto &) {}, - [](std::exception_ptr ep) { - try { - std::rethrow_exception(ep); - } catch (const std::exception &e) { - FAIL() << "Error waiting for MST state: " << e.what(); - } - }); - new_peer_server->shutdown(); } diff --git a/test/integration/acceptance/fake_peer_example_test.cpp b/test/integration/acceptance/fake_peer_example_test.cpp index a36655d1503..70f77496551 100644 --- a/test/integration/acceptance/fake_peer_example_test.cpp +++ b/test/integration/acceptance/fake_peer_example_test.cpp @@ -32,41 +32,6 @@ static constexpr std::chrono::seconds kSynchronizerWaitingTime(20); struct FakePeerExampleTest : FakePeerFixture {}; INSTANTIATE_TEST_SUITE_P_DifferentStorageTypes(FakePeerExampleTest); -/** - * Check that after sending a not fully signed transaction, an MST state - * propagates to another peer - * @given a not fully signed transaction - * @when such transaction is sent to one of two iroha peers in the network - * @then that peer propagates MST state to another peer - */ -TEST_P(FakePeerExampleTest, - MstStateOfTransactionWithoutAllSignaturesPropagtesToOtherPeer) { - createFakePeers(1); - auto &itf = prepareState(); - auto mst_states_observable = - fake_peers_.front()->getMstStatesObservable().replay(); - mst_states_observable.connect(); - - itf.sendTxWithoutValidation(complete( - baseTx(kAdminId) - .transferAsset(kAdminId, kUserId, kAssetId, "income", "500.0") - .quorum(2), - kAdminKeypair)); - - mst_states_observable - .timeout(kMstStateWaitingTime, rxcpp::observe_on_new_thread()) - .take(1) - .as_blocking() - .subscribe([](const auto &) {}, - [](std::exception_ptr ep) { - try { - std::rethrow_exception(ep); - } catch (const std::exception &e) { - FAIL() << "Error waiting for MST state: " << e.what(); - } - }); -} - /** * Check that Irohad loads correct block version when having a malicious fork on * the network. @@ -93,14 +58,16 @@ TEST_P(FakePeerExampleTest, SynchronizeTheRightVersionOfForkedLedger) { bad_fake_peers.front(); // the malicious actor // Add two blocks to the ledger. - itf.sendTx(complete(baseTx(kAdminId).transferAsset( - kAdminId, kUserId, kAssetId, "common_tx1", "1.0"), - kAdminKeypair)) - .skipBlock(); - itf.sendTx(complete(baseTx(kAdminId).transferAsset( - kAdminId, kUserId, kAssetId, "common_tx2", "2.0"), - kAdminKeypair)) - .skipBlock(); + itf.sendTxAwait( + complete(baseTx(kAdminId).transferAsset( + kAdminId, kUserId, kAssetId, "common_tx1", "1.0"), + kAdminKeypair), + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); + itf.sendTxAwait( + complete(baseTx(kAdminId).transferAsset( + kAdminId, kUserId, kAssetId, "common_tx2", "2.0"), + kAdminKeypair), + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); // Create the valid branch, supported by the good fake peers: auto valid_block_storage = @@ -248,46 +215,3 @@ TEST_P(FakePeerExampleTest, SynchronizeTheRightVersionOfForkedLedger) { ASSERT_TRUE(completed.wait(kSynchronizerWaitingTime)) << "Error waiting for synchronization"; } - -/** - * Check that after receiving a valid command the ITF peer provides a proposal - * containing it. - * - * \attention this code is nothing more but an example of Fake Peer usage - * - * @given a network of one real and one fake peers - * @when fake peer provides a proposal with valid tx - * @then the real peer must commit the transaction from that proposal - */ -TEST_P(FakePeerExampleTest, OnDemandOrderingProposalAfterValidCommandReceived) { - // Create the tx: - const auto tx = complete( - baseTx(kAdminId).transferAsset(kAdminId, kUserId, kAssetId, "tx1", "1.0"), - kAdminKeypair); - - createFakePeers(1); - - prepareState(); - - // provide the proposal - fake_peers_.front()->getProposalStorage().addTransactions({clone(tx)}); - - // watch the proposal requests to fake peer - constexpr std::chrono::seconds kCommitWaitingTime(20); - iroha::utils::WaitForSingleObject completed; - auto subscriber = iroha::SubscriberCreator< - bool, - std::shared_ptr>:: - template create( - static_cast( - iroha::getSubscription()->dispatcher()->kExecuteInPool), - [&completed, my_hash = tx.reducedHash()](auto, auto block) { - for (const auto &tx : block->transactions()) { - if (my_hash == tx.reducedHash()) { - completed.set(); - } - } - }); - ASSERT_TRUE(completed.wait(kCommitWaitingTime)) - << "Error waiting for the commit"; -} diff --git a/test/integration/acceptance/fake_peer_fixture.hpp b/test/integration/acceptance/fake_peer_fixture.hpp index 7d2d85ebf97..c8b3cbd1e90 100644 --- a/test/integration/acceptance/fake_peer_fixture.hpp +++ b/test/integration/acceptance/fake_peer_fixture.hpp @@ -62,6 +62,7 @@ struct FakePeerFixture : AcceptanceFixture, protected: void SetUp() override { + subscription = iroha::getSubscription(); itf_ = std::make_unique( 1, GetParam(), @@ -74,9 +75,11 @@ struct FakePeerFixture : AcceptanceFixture, void TearDown() override { itf_.reset(); + subscription->dispose(); } std::vector> fake_peers_; + std::shared_ptr subscription; }; #endif // IROHA_FAKE_PEER_FIXTURE_HPP diff --git a/test/integration/acceptance/grant_permission_test.cpp b/test/integration/acceptance/grant_permission_test.cpp index 55e647bdeb1..2844b383fe5 100644 --- a/test/integration/acceptance/grant_permission_test.cpp +++ b/test/integration/acceptance/grant_permission_test.cpp @@ -14,7 +14,7 @@ using namespace shared_model::interface::permissions; using namespace common_constants; struct GrantPermissionFx : GrantablePermissionsFixture, - ::testing::WithParamInterface {}; + ::testing::WithParamInterface {}; INSTANTIATE_TEST_SUITE_P_DifferentStorageTypes(GrantPermissionFx); /** @@ -301,20 +301,16 @@ TEST_P(GrantPermissionFx, GrantMoreThanOnce) { IntegrationTestFramework itf(1, GetParam()); itf.setInitialState(kAdminKeypair); createTwoAccounts(itf, {kCanGrantAll}, {Role::kReceive}) - .sendTx(grantPermission(kAccount1, - kAccount1Keypair, - kAccount2, - permissions::Grantable::kAddMySignatory)) - .skipProposal() - .skipVerifiedProposal() - .skipBlock() - .sendTx(grantPermission(kAccount1, - kAccount1Keypair, - kAccount2, - permissions::Grantable::kAddMySignatory)) - .skipProposal() - .checkVerifiedProposal( - [](auto &proposal) { ASSERT_EQ(proposal->transactions().size(), 0); }) - .checkBlock( + .sendTxAwait( + grantPermission(kAccount1, + kAccount1Keypair, + kAccount2, + permissions::Grantable::kAddMySignatory), + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + .sendTxAwait( + grantPermission(kAccount1, + kAccount1Keypair, + kAccount2, + permissions::Grantable::kAddMySignatory), [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }); } diff --git a/test/integration/acceptance/grantable_permissions_fixture.cpp b/test/integration/acceptance/grantable_permissions_fixture.cpp index c18c1b6a99f..f7a38207339 100644 --- a/test/integration/acceptance/grantable_permissions_fixture.cpp +++ b/test/integration/acceptance/grantable_permissions_fixture.cpp @@ -30,14 +30,12 @@ GrantablePermissionsFixture::createTwoAccounts( integration_framework::IntegrationTestFramework &itf, const shared_model::interface::RolePermissionSet &perm1, const shared_model::interface::RolePermissionSet &perm2) { - itf.sendTx(makeAccountWithPerms(kAccount1, kAccount1Keypair, perm1, kRole1)) - .skipProposal() - .skipVerifiedProposal() - .skipBlock() - .sendTx(makeAccountWithPerms(kAccount2, kAccount2Keypair, perm2, kRole2)) - .skipProposal() - .skipVerifiedProposal() - .skipBlock(); + itf.sendTxAwait( + makeAccountWithPerms(kAccount1, kAccount1Keypair, perm1, kRole1), + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + .sendTxAwait( + makeAccountWithPerms(kAccount2, kAccount2Keypair, perm2, kRole2), + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); return itf; } diff --git a/test/integration/executor/CMakeLists.txt b/test/integration/executor/CMakeLists.txt index e3b362c2203..fee147a4cb0 100644 --- a/test/integration/executor/CMakeLists.txt +++ b/test/integration/executor/CMakeLists.txt @@ -26,6 +26,7 @@ target_link_libraries(executor_fixture_param_postgres add_library(executor_fixture_param_rocksdb executor_fixture_param_rocksdb.cpp) target_link_libraries(executor_fixture_param_rocksdb ametsuchi_rocksdb + rocksdb_burrow_storage executor_fixture_param GTest::gmock rocksdb_indexer diff --git a/test/integration/executor/executor_fixture_param_rocksdb.cpp b/test/integration/executor/executor_fixture_param_rocksdb.cpp index 955a0ded59c..c95b4b8ba26 100644 --- a/test/integration/executor/executor_fixture_param_rocksdb.cpp +++ b/test/integration/executor/executor_fixture_param_rocksdb.cpp @@ -6,8 +6,10 @@ #include "integration/executor/executor_fixture_param_rocksdb.hpp" #include +#include #include "ametsuchi/impl/block_index_impl.hpp" +#include "ametsuchi/impl/rocksdb_burrow_storage.hpp" #include "ametsuchi/impl/rocksdb_command_executor.hpp" #include "ametsuchi/impl/rocksdb_common.hpp" #include "ametsuchi/impl/rocksdb_indexer.hpp" @@ -32,7 +34,8 @@ using namespace iroha::integration_framework; namespace fs = boost::filesystem; namespace { - ExecutorItfTarget createRocksDBExecutorItfTarget( + std::pair> + createRocksDBExecutorItfTarget( std::shared_ptr db_port, VmCaller &); } // namespace @@ -41,7 +44,11 @@ RocksDBExecutorTestParam::RocksDBExecutorTestParam() { db_port_ = std::make_shared(); db_port_->initialize(db_name_); - executor_itf_target_ = createRocksDBExecutorItfTarget(db_port_, *vm_caller_); + auto const &[executor_itf_target, db] = + createRocksDBExecutorItfTarget(db_port_, *vm_caller_); + executor_itf_target_ = executor_itf_target; + db_context_ = db; + common_ = std::make_unique(db_context_); block_indexer_ = std::make_shared( std::make_unique( @@ -62,7 +69,11 @@ void RocksDBExecutorTestParam::clearBackendState() { db_port_ = std::make_shared(); db_port_->initialize(db_name_); - executor_itf_target_ = createRocksDBExecutorItfTarget(db_port_, *vm_caller_); + auto const &[executor_itf_target, db] = + createRocksDBExecutorItfTarget(db_port_, *vm_caller_); + executor_itf_target_ = executor_itf_target; + db_context_ = db; + common_ = std::make_unique(db_context_); block_indexer_ = std::make_shared( std::make_unique( @@ -78,7 +89,7 @@ std::unique_ptr RocksDBExecutorTestParam::makeBurrowStorage( std::string const &tx_hash, shared_model::interface::types::CommandIndexType cmd_index) const { - return std::unique_ptr{}; + return std::make_unique(*common_, tx_hash, cmd_index); } std::shared_ptr @@ -119,7 +130,8 @@ namespace { std::unique_ptr block_storage_; }; - ExecutorItfTarget createRocksDBExecutorItfTarget( + std::pair> + createRocksDBExecutorItfTarget( std::shared_ptr db_port, VmCaller &vm_caller) { ExecutorItfTarget target; @@ -133,9 +145,10 @@ namespace { target.command_executor = std::make_shared( db_context, std::make_shared(), + query_executor, vm_caller); target.query_executor = std::move(query_executor); - return target; + return std::make_pair(target, db_context); } } // namespace diff --git a/test/integration/executor/executor_fixture_param_rocksdb.hpp b/test/integration/executor/executor_fixture_param_rocksdb.hpp index 4e6c3215fc9..0fbe1fd1f1c 100644 --- a/test/integration/executor/executor_fixture_param_rocksdb.hpp +++ b/test/integration/executor/executor_fixture_param_rocksdb.hpp @@ -11,7 +11,9 @@ namespace iroha::ametsuchi { struct RocksDBPort; -} + struct RocksDBContext; + class RocksDbCommon; +} // namespace iroha::ametsuchi namespace executor_testing { @@ -48,6 +50,8 @@ namespace executor_testing { private: std::string db_name_; std::shared_ptr db_port_; + std::shared_ptr db_context_; + std::unique_ptr common_; iroha::integration_framework::ExecutorItfTarget executor_itf_target_; std::shared_ptr block_indexer_; diff --git a/test/integration/pipeline/batch_pipeline_test.cpp b/test/integration/pipeline/batch_pipeline_test.cpp index db1bf77d38f..14f342ec362 100644 --- a/test/integration/pipeline/batch_pipeline_test.cpp +++ b/test/integration/pipeline/batch_pipeline_test.cpp @@ -6,8 +6,9 @@ #include #include +#include +#include -#include "test/integration/acceptance/instantiate_test_suite.hpp" #include "builders/protobuf/transaction.hpp" #include "framework/batch_helper.hpp" #include "framework/integration_framework/integration_test_framework.hpp" @@ -16,8 +17,8 @@ #include "interfaces/iroha_internal/transaction_sequence_factory.hpp" #include "interfaces/permissions.hpp" #include "module/irohad/common/validators_config.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" #include "module/shared_model/cryptography/crypto_defaults.hpp" +#include "test/integration/acceptance/instantiate_test_suite.hpp" using namespace shared_model; using namespace common_constants; @@ -34,6 +35,30 @@ using ::testing::WithParamInterface; using shared_model::interface::types::PublicKeyHexStringView; +template +auto addSignaturesFromKeyPairs(Batch &&batch, + int tx_number, + KeyPairs... keypairs) { + auto create_signature = [&](auto &&key_pair) { + auto &payload = batch->transactions().at(tx_number)->payload(); + auto signed_blob = shared_model::crypto::CryptoSigner::sign( + shared_model::crypto::Blob(payload), key_pair); + using namespace shared_model::interface::types; + batch->addSignature(tx_number, + SignedHexStringView{signed_blob}, + PublicKeyHexStringView{key_pair.publicKey()}); + }; + + // pack expansion trick: + // an ellipsis operator applies insert_signatures to each signature, operator + // comma returns the rightmost argument, which is 0 + int temp[] = {(create_signature(std::forward(keypairs)), 0)...}; + // use unused variable + (void)temp; + + return std::forward(batch); +} + struct BatchPipelineTestBase : AcceptanceFixture { /** * Create transaction to create first user @@ -336,31 +361,18 @@ TEST_P(BatchPipelineTest, InvalidAtomicBatch) { {signedTx(batch_transactions[0], kFirstUserKeypair), signedTx(batch_transactions[1], kSecondUserKeypair)}); - IntegrationTestFramework itf(2, std::get(GetParam())); + IntegrationTestFramework itf(2, + std::get(GetParam()), + boost::none, + iroha::StartupWsvDataPolicy::kDrop, + true, + false, + boost::none, + milliseconds(20000), + milliseconds(20000), + milliseconds(20000)); prepareState(itf, "1.0", "1.0") - .sendTxSequence( - transaction_sequence, - [](const auto &statuses) { - for (const auto &status : statuses) { - EXPECT_NO_THROW( - boost::get(status.get())); - } - }) - .checkStatus(batch_transactions[0]->hash(), CHECK_STATELESS_VALID) - .checkStatus(batch_transactions[0]->hash(), CHECK_ENOUGH_SIGNATURES) - .checkStatus(batch_transactions[1]->hash(), CHECK_STATELESS_VALID) - .checkStatus(batch_transactions[1]->hash(), CHECK_ENOUGH_SIGNATURES) - .checkStatus(batch_transactions[1]->hash(), CHECK_STATEFUL_INVALID) - .checkProposal([&transaction_sequence](const auto proposal) { - ASSERT_THAT( - proposal->transactions(), - Pointwise(RefAndPointerEq(), transaction_sequence.transactions())); - }) - .checkVerifiedProposal([](const auto verified_proposal) { - ASSERT_THAT(verified_proposal->transactions(), IsEmpty()); - }) - .checkBlock([](const auto block) { + .sendTxSequenceAwait(transaction_sequence, [](const auto block) { ASSERT_THAT(block->transactions(), IsEmpty()); }); } diff --git a/test/integration/pipeline/multisig_tx_pipeline_test.cpp b/test/integration/pipeline/multisig_tx_pipeline_test.cpp index 10fc566d88a..d3d82dcb49c 100644 --- a/test/integration/pipeline/multisig_tx_pipeline_test.cpp +++ b/test/integration/pipeline/multisig_tx_pipeline_test.cpp @@ -4,6 +4,10 @@ */ #include +#include +#include +#include +#include #include "backend/protobuf/query_responses/proto_query_response.hpp" #include "builders/protobuf/queries.hpp" @@ -50,28 +54,14 @@ class MstPipelineTest : public AcceptanceFixture { kUserId, PublicKeyHexStringView{signatories[i].publicKey()}); } add_signatories_tx.setAccountQuorum(kUserId, sigs + 1); - itf.sendTx(create_user_tx) - .checkProposal([](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); - }) - .checkVerifiedProposal([](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); - }) - .checkBlock([](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); - }) - .sendTx(add_signatories_tx.build() - .signAndAddSignature(kUserKeypair) - .finish()) - .checkProposal([](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); - }) - .checkVerifiedProposal([](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); - }) - .checkBlock([](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); - }); + itf.sendTxAwait( + create_user_tx, + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + .sendTxAwait( + add_signatories_tx.build() + .signAndAddSignature(kUserKeypair) + .finish(), + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); return itf; } @@ -255,8 +245,10 @@ TEST_F(MstPipelineTest, OldGetPendingTxsAwaitingForThisPeer) { }; // send pending transaction, signing it only with one signatory - mst_itf.sendTx(signed_tx).sendQuery( - makeGetPendingTxsQuery(kUserId, kUserKeypair), pending_tx_check); + mst_itf.sendTx(signed_tx); + std::this_thread::sleep_for(std::chrono::seconds(3)); + mst_itf.sendQuery(makeGetPendingTxsQuery(kUserId, kUserKeypair), + pending_tx_check); }); } @@ -279,10 +271,12 @@ TEST_F(MstPipelineTest, OldGetPendingTxsLatestSignatures) { const auto q2 = makeGetPendingTxsQuery(kUserId, kUserKeypair); executeForItf([&](auto &mst_itf) { - mst_itf.sendTx(complete(pending_tx, signatories[0])) - .sendQuery(q1, oldSignatoryCheck(1)) - .sendTx(complete(pending_tx, signatories[1])) - .sendQuery(q2, oldSignatoryCheck(2)); + mst_itf.sendTx(complete(pending_tx, signatories[0])); + std::this_thread::sleep_for(std::chrono::seconds(3)); + mst_itf.sendQuery(q1, oldSignatoryCheck(1)) + .sendTx(complete(pending_tx, signatories[1])); + std::this_thread::sleep_for(std::chrono::seconds(3)); + mst_itf.sendQuery(q2, oldSignatoryCheck(2)); }); } @@ -372,9 +366,10 @@ TEST_F(MstPipelineTest, GetPendingTxsAwaitingForThisPeer) { }; // send pending transaction, signing it only with one signatory - mst_itf.sendTx(signed_tx).sendQuery( - makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize), - pending_tx_check); + mst_itf.sendTx(signed_tx); + std::this_thread::sleep_for(std::chrono::seconds(3)); + mst_itf.sendQuery(makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize), + pending_tx_check); }); } @@ -396,10 +391,12 @@ TEST_F(MstPipelineTest, GetPendingTxsLatestSignatures) { const auto q2 = makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize); executeForItf([&](auto &mst_itf) { - mst_itf.sendTx(complete(pending_tx, signatories[0])) - .sendQuery(q1, signatoryCheck(1)) - .sendTx(complete(pending_tx, signatories[1])) - .sendQuery(q2, signatoryCheck(2)); + mst_itf.sendTx(complete(pending_tx, signatories[0])); + std::this_thread::sleep_for(std::chrono::seconds(1)); + mst_itf.sendQuery(q1, signatoryCheck(1)) + .sendTx(complete(pending_tx, signatories[1])); + std::this_thread::sleep_for(std::chrono::seconds(1)); + mst_itf.sendQuery(q2, signatoryCheck(2)); }); } @@ -425,9 +422,10 @@ TEST_F(MstPipelineTest, GetPendingTxsNoSignedTxs) { ASSERT_EQ(proposal->transactions()[0].hash(), user_tx.hash()); }) .skipVerifiedProposal() - .skipBlock() - .sendQuery(makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize), - noTxsCheck); + .skipBlock(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + mst_itf.sendQuery(makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize), + noTxsCheck); }); } @@ -457,8 +455,9 @@ TEST_F(MstPipelineTest, ReplayViaFullySignedTransaction) { ASSERT_EQ(proposal->transactions()[0].hash(), fully_signed_tx.hash()); }) .skipVerifiedProposal() - .skipBlock() - .sendQuery(makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize), - noTxsCheck); + .skipBlock(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + mst_itf.sendQuery(makeGetPendingTxsQuery(kUserId, kUserKeypair, kPageSize), + noTxsCheck); }); } diff --git a/test/module/irohad/CMakeLists.txt b/test/module/irohad/CMakeLists.txt index 27491c5268a..64aa920d26a 100644 --- a/test/module/irohad/CMakeLists.txt +++ b/test/module/irohad/CMakeLists.txt @@ -11,7 +11,6 @@ add_subdirectory(consensus) add_subdirectory(logger) add_subdirectory(main) add_subdirectory(model) -add_subdirectory(multi_sig_transactions) add_subdirectory(network) add_subdirectory(ordering) add_subdirectory(simulator) diff --git a/test/module/irohad/ametsuchi/rocksdb_common_test.cpp b/test/module/irohad/ametsuchi/rocksdb_common_test.cpp index afccdfb6ad5..4a28aa30f9b 100644 --- a/test/module/irohad/ametsuchi/rocksdb_common_test.cpp +++ b/test/module/irohad/ametsuchi/rocksdb_common_test.cpp @@ -724,6 +724,90 @@ TEST_F(RocksDBTest, LowerBoundSearch) { } } +TEST_F(RocksDBTest, LogsEnumerator) { + { + RocksDbCommon common(tx_context_); + + common.valueBuffer() = "aaa"; + ASSERT_TRUE(iroha::expected::hasValue( + forCallEngineLogs(common, 50, 0))); + ASSERT_TRUE(iroha::expected::hasValue( + forCallEngineLogs(common, 50, 1))); + ASSERT_TRUE(iroha::expected::hasValue( + forCallEngineLogs(common, 50, 2))); + ASSERT_TRUE(common.commit().ok()); + } + + { + RocksDbCommon common(tx_context_); + bool found[3]; + memset(found, 0, sizeof(found)); + enumerateKeysAndValues(common, + [&](auto key, auto value) { + throw std::runtime_error("Unexpected"); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineLogs, + 10); + enumerateKeysAndValues(common, + [&](auto key, auto value) { + found[atoll(key.data())] = + (value.ToStringView() == "aaa"); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineLogs, + 50); + + ASSERT_TRUE(found[0]); + ASSERT_TRUE(found[1]); + ASSERT_TRUE(found[2]); + } +} + +TEST_F(RocksDBTest, TopicsEnumerator) { + { + RocksDbCommon common(tx_context_); + + common.valueBuffer() = "aaa"; + ASSERT_TRUE(iroha::expected::hasValue( + forCallEngineTopics(common, 50, 0))); + ASSERT_TRUE(iroha::expected::hasValue( + forCallEngineTopics(common, 50, 1))); + ASSERT_TRUE(iroha::expected::hasValue( + forCallEngineTopics(common, 50, 2))); + ASSERT_TRUE(common.commit().ok()); + } + + { + RocksDbCommon common(tx_context_); + bool found[3]; + memset(found, 0, sizeof(found)); + enumerateKeysAndValues(common, + [&](auto key, auto value) { + throw std::runtime_error("Unexpected"); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineTopics, + 10); + enumerateKeysAndValues(common, + [&](auto key, auto value) { + found[atoll(key.data())] = + (value.ToStringView() == "aaa"); + return true; + }, + RocksDBPort::ColumnFamilyType::kWsv, + fmtstrings::kPathEngineTopics, + 50); + + ASSERT_TRUE(found[0]); + ASSERT_TRUE(found[1]); + ASSERT_TRUE(found[2]); + } +} + TEST_F(RocksDBTest, Signatories) { RocksDbCommon common(tx_context_); auto cmd_check = [&](std::string_view pk) { diff --git a/test/module/irohad/ametsuchi/rocksdb_executor_test.cpp b/test/module/irohad/ametsuchi/rocksdb_executor_test.cpp index a6f3344c795..e855503b6d8 100644 --- a/test/module/irohad/ametsuchi/rocksdb_executor_test.cpp +++ b/test/module/irohad/ametsuchi/rocksdb_executor_test.cpp @@ -8,6 +8,7 @@ #include "ametsuchi/impl/executor_common.hpp" #include "ametsuchi/impl/rocksdb_command_executor.hpp" #include "ametsuchi/impl/rocksdb_common.hpp" +#include "ametsuchi/impl/rocksdb_specific_query_executor.hpp" #include "ametsuchi/impl/rocksdb_wsv_query.hpp" #include "backend/protobuf/proto_permission_to_string.hpp" #include "backend/protobuf/proto_query_response_factory.hpp" @@ -65,8 +66,15 @@ namespace iroha::ametsuchi { getTestLogger("WsvQuery")); pending_txs_storage = std::make_shared(); + + auto query_executor = + std::make_shared(tx_context_, + *block_storage_, + pending_txs_storage, + query_response_factory, + perm_converter); executor = std::make_unique( - tx_context_, perm_converter, std::nullopt); + tx_context_, perm_converter, query_executor, std::nullopt); } void SetUp() override { diff --git a/test/module/irohad/multi_sig_transactions/CMakeLists.txt b/test/module/irohad/multi_sig_transactions/CMakeLists.txt deleted file mode 100644 index 6268660ddfa..00000000000 --- a/test/module/irohad/multi_sig_transactions/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright Soramitsu Co., Ltd. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -AddTest(state_test state_test.cpp) -target_link_libraries(state_test - mst_state - test_logger - shared_model_default_builders - shared_model_stateless_validation - shared_model_interfaces_factories - ) - -AddTest(storage_test storage_test.cpp) -target_link_libraries(storage_test - mst_storage - test_logger - shared_model_default_builders - shared_model_stateless_validation - shared_model_interfaces_factories - ) - -AddTest(completer_test completer_test.cpp) -target_link_libraries(completer_test - mst_state - ) - -AddTest(transport_test transport_test.cpp) -target_link_libraries(transport_test - mst_transport - mst_processor - test_logger - shared_model_cryptography - shared_model_stateless_validation - shared_model_proto_backend - ) - -AddTest(mst_processor_test mst_processor_test.cpp) -target_link_libraries(mst_processor_test - mst_processor - test_logger - shared_model_default_builders - shared_model_stateless_validation - sync_subscription - ) - -AddTest(gossip_propagation_strategy_test - gossip_propagation_strategy_test.cpp - ) -target_link_libraries(gossip_propagation_strategy_test - mst_processor - logger - shared_model_cryptography - shared_model_stateless_validation - shared_model_proto_backend - ) - -AddTest(mst_net_input_test mst_net_input_test.cpp) -target_link_libraries(mst_net_input_test - integration_framework - ) diff --git a/test/module/irohad/multi_sig_transactions/completer_test.cpp b/test/module/irohad/multi_sig_transactions/completer_test.cpp deleted file mode 100644 index 1b1e207e226..00000000000 --- a/test/module/irohad/multi_sig_transactions/completer_test.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "datetime/time.hpp" -#include "module/shared_model/interface_mocks.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" - -using namespace iroha; -using namespace testing; - -/** - * @given batch with 3 transactions: first one with quorum 1 and 1 signature, - * second one with quorum 2 and 2 signatures, third one with quorum 3 and 3 - * signatures - * @when completer was called for the batch - * @then batch is complete - */ -TEST(CompleterTest, BatchQuorumTestEnoughSignatures) { - auto completer = std::make_shared(std::chrono::minutes(0)); - - std::vector> sigs1{ - 1, std::make_shared()}; - std::vector> sigs2{ - 2, std::make_shared()}; - std::vector> sigs3{ - 3, std::make_shared()}; - - auto tx1 = std::make_shared(); - EXPECT_CALL(*tx1, quorum()).WillOnce(Return(1)); - EXPECT_CALL(*tx1, signatures()) - .WillOnce(Return( - sigs1 | boost::adaptors::indirected)); - - auto tx2 = std::make_shared(); - EXPECT_CALL(*tx2, quorum()).WillOnce(Return(2)); - EXPECT_CALL(*tx2, signatures()) - .WillOnce(Return( - sigs2 | boost::adaptors::indirected)); - - auto tx3 = std::make_shared(); - EXPECT_CALL(*tx3, quorum()).WillOnce(Return(3)); - EXPECT_CALL(*tx3, signatures()) - .WillOnce(Return( - sigs3 | boost::adaptors::indirected)); - - auto batch = createMockBatchWithTransactions({tx1, tx2, tx3}, ""); - ASSERT_TRUE(completer->isCompleted(batch)); -} - -/** - * @given batch with 3 transactions: first one with quorum 1 and 1 signature, - * second one with quorum 2 and 1 signature, third one with quorum 3 and 3 - * signatures - * @when completer was called for the batch - * @then batch is not complete - */ -TEST(CompleterTest, BatchQuorumTestNotEnoughSignatures) { - auto completer = std::make_shared(std::chrono::minutes(0)); - - std::vector> sigs1{ - 1, std::make_shared()}; - std::vector> sigs2{ - 1, std::make_shared()}; - std::vector> sigs3{ - 3, std::make_shared()}; - - auto tx1 = std::make_shared(); - EXPECT_CALL(*tx1, quorum()).WillOnce(Return(1)); - EXPECT_CALL(*tx1, signatures()) - .WillOnce(Return( - sigs1 | boost::adaptors::indirected)); - - auto tx2 = std::make_shared(); - EXPECT_CALL(*tx2, quorum()).WillOnce(Return(2)); - EXPECT_CALL(*tx2, signatures()) - .WillOnce(Return( - sigs2 | boost::adaptors::indirected)); - - auto tx3 = std::make_shared(); - EXPECT_CALL(*tx3, quorum()).Times(0); - EXPECT_CALL(*tx3, signatures()).Times(0); - - auto batch = createMockBatchWithTransactions({tx1, tx2, tx3}, ""); - ASSERT_FALSE(completer->isCompleted(batch)); -} - -/** - * @given batch with 3 transactions with now() creation time and completer - * with 1 minute expiration time - * @when completer with 2 minute gap was called for the batch - * @then batch is expired - */ -TEST(CompleterTest, BatchExpirationTestExpired) { - auto completer = std::make_shared(std::chrono::minutes(1)); - auto time = iroha::time::now(); - auto tx1 = std::make_shared(); - EXPECT_CALL(*tx1, createdTime()).WillRepeatedly(Return(time)); - auto tx2 = std::make_shared(); - EXPECT_CALL(*tx2, createdTime()).WillRepeatedly(Return(time)); - auto tx3 = std::make_shared(); - EXPECT_CALL(*tx3, createdTime()).WillRepeatedly(Return(time)); - auto batch = createMockBatchWithTransactions({tx1, tx2, tx3}, ""); - ASSERT_TRUE(completer->isExpired( - batch, time + std::chrono::minutes(2) / std::chrono::milliseconds(1))); -} - -/** - * @given batch with 3 transactions: first one in 2 minutes from now, - * second one in 3 minutes from now, third one in 4 minutes from now and - * completer with 5 minute expiration time - * @when completer without time gap was called for the batch - * @then batch is not expired - */ -TEST(CompleterTest, BatchExpirationTestNoExpired) { - auto completer = std::make_shared(std::chrono::minutes(5)); - auto time = iroha::time::now(); - auto tx1 = std::make_shared(); - EXPECT_CALL(*tx1, createdTime()) - .WillRepeatedly(Return( - time + std::chrono::minutes(2) / std::chrono::milliseconds(1))); - auto tx2 = std::make_shared(); - EXPECT_CALL(*tx2, createdTime()) - .WillRepeatedly(Return( - time + std::chrono::minutes(3) / std::chrono::milliseconds(1))); - auto tx3 = std::make_shared(); - EXPECT_CALL(*tx3, createdTime()) - .WillRepeatedly(Return( - time + std::chrono::minutes(4) / std::chrono::milliseconds(1))); - auto batch = createMockBatchWithTransactions({tx1, tx2, tx3}, ""); - ASSERT_FALSE(completer->isExpired(batch, time)); -} diff --git a/test/module/irohad/multi_sig_transactions/gossip_propagation_strategy_test.cpp b/test/module/irohad/multi_sig_transactions/gossip_propagation_strategy_test.cpp deleted file mode 100644 index 2835189063d..00000000000 --- a/test/module/irohad/multi_sig_transactions/gossip_propagation_strategy_test.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/gossip_propagation_strategy.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "ametsuchi/peer_query_factory.hpp" -#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "module/shared_model/interface_mocks.hpp" - -#include - -using namespace iroha; - -using namespace std::chrono_literals; -using namespace iroha::ametsuchi; -using PropagationData = GossipPropagationStrategy::PropagationData; - -/** - * Generates peers with empty pub keys - * @param ids generated addresses of peers - * @param amount for generation - * @return generated peers - */ -PropagationData generate(std::vector &ids, size_t num) { - ids.resize(num); - std::iota(ids.begin(), ids.end(), 'a'); - PropagationData peers; - std::transform( - ids.begin(), ids.end(), std::back_inserter(peers), [](auto &s) { - return makePeer( - s, shared_model::interface::types::PublicKeyHexStringView{}); - }); - return peers; -} - -/** - * Perform subscription and the emitting from specified strategy - * @param strategy is emitter source - * @param take is amount taken from the strategy emitter - * @return emitted data - */ -PropagationData subscribeAndEmit(GossipPropagationStrategy &strategy, - uint32_t take) { - PropagationData emitted; - auto subscriber = rxcpp::make_subscriber([&emitted](auto v) { - std::copy(v.begin(), v.end(), std::back_inserter(emitted)); - }); - strategy.emitter().take(take).as_blocking().subscribe(subscriber); - - return emitted; -} - -/** - * Perform subscription and the emitting from created strategy - * @param data retrieved from the PeerProvider - * @param period of the strategy - * @param amount emit per once - * @param take is amount taken from the strategy emitter - * @return emitted data - */ -PropagationData subscribeAndEmit(boost::optional data, - std::chrono::milliseconds period, - uint32_t amount, - uint32_t take) { - auto query = std::make_shared(); - EXPECT_CALL(*query, getLedgerPeers(false)) - .WillRepeatedly(testing::Return(data)); - auto pbfactory = std::make_shared(); - EXPECT_CALL(*pbfactory, createPeerQuery()) - .WillRepeatedly(testing::Return(boost::make_optional( - std::shared_ptr(query)))); - iroha::GossipPropagationStrategyParams gossip_params; - gossip_params.emission_period = period; - gossip_params.amount_per_once = amount; - GossipPropagationStrategy strategy( - pbfactory, rxcpp::observe_on_event_loop(), gossip_params); - return subscribeAndEmit(strategy, take); -} - -/** - * Checks the emitted data is being subset of peers - * @param emitted is data from observable - * @param peersId is a collection of peers - * @return true if the emitted data is a peer subset - */ -bool validateEmitted(const PropagationData &emitted, - const std::vector &peersId) { - return std::find_if( - emitted.begin(), - emitted.end(), - [&peersId, flag = true](const auto &v) mutable { - if (flag - and std::find(peersId.begin(), peersId.end(), v->address()) - == peersId.end()) - flag = false; - return flag; - }) - != emitted.end(); -} - -/** - * @given list of peers and - * strategy that emits two peers - * @when strategy emits this peers - * @then ensure that all peers are being emitted - */ -TEST(GossipPropagationStrategyTest, EmittingAllPeers) { - auto peers_size = 23, amount = 2, take = peers_size / amount; - std::vector peersId; - PropagationData peers = generate(peersId, peers_size); - - auto emitted = subscribeAndEmit(peers, 1ms, amount, take); - - // emitted.size() can be less than peers.size() - ASSERT_GE(peers.size(), emitted.size()); - // because emitted size should be increased by amount at once - ASSERT_FALSE(emitted.size() % amount); - ASSERT_TRUE(validateEmitted(emitted, peersId)); -} - -/** - * @given list of peers and - * strategy that emits two peers - * @when strategy emits more than peers available - * @then ensure that there's been emitted peers - */ -TEST(GossipPropagationStrategyTest, EmitEvenOnOddPeers) { - auto peers_size = 11, amount = 2, take = 6; - std::vector peersId; - PropagationData peers = generate(peersId, peers_size); - - auto emitted = subscribeAndEmit(peers, 1ms, amount, take); - - ASSERT_EQ(emitted.size(), take * amount); - ASSERT_LE(peers.size(), emitted.size()); - ASSERT_TRUE(validateEmitted(emitted, peersId)); -} - -/** - * @given no peers and strategy - * @when strategy emits this peers - * @then ensure that empty peer list is emitted - */ -TEST(GossipPropagationStrategyTest, EmptyEmitting) { - auto emitted = subscribeAndEmit(PropagationData{}, 1ms, 1, 13); - ASSERT_EQ(emitted.size(), 0); -} - -/** - * @given nullopt emitting instead of peers list and strategy - * @when strategy emits this peers - * @then ensure that empty peer list is emitted - */ -TEST(GossipPropagationStrategyTest, ErrorEmitting) { - auto emitted = subscribeAndEmit(boost::none, 1ms, 1, 13); - ASSERT_EQ(emitted.size(), 0); -} - -/** - * @given list of peers and - * strategy that emits two peers - * @when strategy emits more than peers available - * @then ensure that there's been emitted peers - */ -TEST(GossipPropagationStrategyTest, MultipleSubsEmission) { - auto peers_size = 10, take = 10; - uint32_t amount = 2; - constexpr auto threads = 10; - std::vector peersId; - PropagationData peers = generate(peersId, peers_size); - - // subscribers for the propagation emitter - std::thread ths[threads]; - // Emitted data - PropagationData result[threads]; - auto range = boost::irange(0, threads); - - auto query = std::make_shared(); - auto pbfactory = std::make_shared(); - EXPECT_CALL(*pbfactory, createPeerQuery()) - .WillRepeatedly(testing::Return(boost::make_optional( - std::shared_ptr(query)))); - EXPECT_CALL(*query, getLedgerPeers(false)) - .WillRepeatedly(testing::Return(peers)); - iroha::GossipPropagationStrategyParams gossip_params; - gossip_params.emission_period = 1ms; - gossip_params.amount_per_once = amount; - GossipPropagationStrategy strategy( - pbfactory, rxcpp::observe_on_new_thread(), gossip_params); - - // Create separate subscriber for every thread - // Use result[i] as storage for emitent for i-th one - std::transform(range.begin(), range.end(), std::begin(ths), [&](auto i) { - return std::thread([take, &res = result[i], &strategy] { - res = subscribeAndEmit(strategy, take); - }); - }); - - // Wait until all thread is finished and ensure all threads have emitted peers - std::for_each(range.begin(), range.end(), [&](auto i) { - ths[i].join(); - ASSERT_EQ(result[i].size(), take * amount); - ASSERT_TRUE(validateEmitted(result[i], peersId)); - }); -} diff --git a/test/module/irohad/multi_sig_transactions/mock_mst_transport.hpp b/test/module/irohad/multi_sig_transactions/mock_mst_transport.hpp deleted file mode 100644 index de4f91ad4be..00000000000 --- a/test/module/irohad/multi_sig_transactions/mock_mst_transport.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MOCK_MST_TRANSPORT_HPP -#define IROHA_MOCK_MST_TRANSPORT_HPP - -#include -#include "network/mst_transport.hpp" - -namespace iroha { - class MockMstTransport : public network::MstTransport { - public: - MOCK_METHOD1(subscribe, - void(std::shared_ptr)); - MOCK_METHOD2(sendState, - rxcpp::observable( - std::shared_ptr to, - const MstState &providing_state)); - }; -} // namespace iroha - -#endif // IROHA_MOCK_MST_TRANSPORT_HPP diff --git a/test/module/irohad/multi_sig_transactions/mock_mst_transport_notification.hpp b/test/module/irohad/multi_sig_transactions/mock_mst_transport_notification.hpp deleted file mode 100644 index d32649eaf4d..00000000000 --- a/test/module/irohad/multi_sig_transactions/mock_mst_transport_notification.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MOCK_MST_TRANSPORT_NOTIFICATION_HPP -#define IROHA_MOCK_MST_TRANSPORT_NOTIFICATION_HPP - -#include -#include "network/mst_transport.hpp" - -namespace iroha { - /** - * Transport notification mock - */ - class MockMstTransportNotification - : public network::MstTransportNotification { - public: - MOCK_METHOD2(onNewState, - void(shared_model::interface::types::PublicKeyHexStringView, - MstState &&)); - }; -} // namespace iroha - -#endif // IROHA_MOCK_MST_TRANSPORT_NOTIFICATION_HPP diff --git a/test/module/irohad/multi_sig_transactions/mst_mocks.hpp b/test/module/irohad/multi_sig_transactions/mst_mocks.hpp deleted file mode 100644 index d74de1065ad..00000000000 --- a/test/module/irohad/multi_sig_transactions/mst_mocks.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef IROHA_MST_MOCKS_HPP -#define IROHA_MST_MOCKS_HPP - -#include -#include - -#include "logger/logger_fwd.hpp" -#include "multi_sig_transactions/mst_processor.hpp" -#include "multi_sig_transactions/mst_propagation_strategy.hpp" -#include "multi_sig_transactions/mst_time_provider.hpp" -#include "multi_sig_transactions/mst_types.hpp" - -namespace iroha { - /** - * Propagation strategy mock - */ - class MockPropagationStrategy : public PropagationStrategy { - public: - MOCK_METHOD0(emitter, rxcpp::observable()); - }; - - /** - * Time provider mock - */ - class MockTimeProvider : public MstTimeProvider { - public: - MOCK_CONST_METHOD0(getCurrentTime, TimeType()); - }; - - struct MockMstProcessor : public MstProcessor { - MockMstProcessor(logger::LoggerPtr log) : MstProcessor(std::move(log)) {} - MOCK_METHOD1(propagateBatchImpl, void(const DataType &)); - MOCK_CONST_METHOD0(onStateUpdateImpl, - rxcpp::observable>()); - MOCK_CONST_METHOD0(onPreparedBatchesImpl, rxcpp::observable()); - MOCK_CONST_METHOD0(onExpiredBatchesImpl, rxcpp::observable()); - MOCK_CONST_METHOD1(batchInStorageImpl, bool(const DataType &)); - }; -} // namespace iroha - -#endif // IROHA_MST_MOCKS_HPP diff --git a/test/module/irohad/multi_sig_transactions/mst_net_input_test.cpp b/test/module/irohad/multi_sig_transactions/mst_net_input_test.cpp deleted file mode 100644 index b839b37b443..00000000000 --- a/test/module/irohad/multi_sig_transactions/mst_net_input_test.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "framework/common_constants.hpp" -#include "framework/integration_framework/integration_test_framework.hpp" -#include "mst.grpc.pb.h" - -using namespace common_constants; -using namespace integration_framework; -using namespace iroha::network; - -/** - * @given ITF - * @when it receives MstState that contains a transaction with a - * command, where command type is not set - * @then there should be no SEGFAULT - */ -TEST(MstNetInteraction, TypelessCommand) { - bool enable_mst = true; - for (auto const type : - {iroha::StorageType::kPostgres, iroha::StorageType::kRocksDb}) { - IntegrationTestFramework itf( - 1, type, {}, iroha::StartupWsvDataPolicy::kDrop, true, enable_mst); - itf.setInitialState(kAdminKeypair); - auto internal_port = itf.internalPort(); - - std::string peer_address = "127.0.0.1:" + std::to_string(internal_port); - auto client = transport::MstTransportGrpc::NewStub( - grpc::CreateChannel(peer_address, grpc::InsecureChannelCredentials())); - - grpc::ClientContext context; - google::protobuf::Empty response; - iroha::network::transport::MstState state; - auto transaction = state.add_transactions(); - transaction->mutable_payload()->mutable_reduced_payload()->add_commands(); - - client->SendState(&context, state, &response); - } -} diff --git a/test/module/irohad/multi_sig_transactions/mst_processor_test.cpp b/test/module/irohad/multi_sig_transactions/mst_processor_test.cpp deleted file mode 100644 index 177197ca744..00000000000 --- a/test/module/irohad/multi_sig_transactions/mst_processor_test.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "cryptography/keypair.hpp" -#include "datetime/time.hpp" -#include "framework/test_logger.hpp" -#include "framework/test_subscriber.hpp" -#include "interfaces/common_objects/string_view_types.hpp" -#include "logger/logger.hpp" -#include "module/irohad/multi_sig_transactions/mock_mst_transport.hpp" -#include "module/irohad/multi_sig_transactions/mst_mocks.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "module/shared_model/interface_mocks.hpp" -#include "multi_sig_transactions/mst_processor_impl.hpp" -#include "multi_sig_transactions/storage/mst_storage_impl.hpp" - -auto log_ = getTestLogger("MstProcessorTest"); - -using namespace std::literals; -using namespace iroha; -using namespace framework::test_subscriber; - -using shared_model::interface::types::PeerList; -using shared_model::interface::types::PublicKeyHexStringView; -using testing::_; -using testing::Return; - -static const PublicKeyHexStringView kPublicKey1{"first public key"sv}; -static const PublicKeyHexStringView kPublicKey2{"second public key"sv}; - -class MstProcessorTest : public testing::Test { - public: - // --------------------------------| fields |--------------------------------- - - /// propagation subject, useful for propagation control - rxcpp::subjects::subject - propagation_subject; - /// use effective implementation of storage - std::shared_ptr storage; - std::shared_ptr mst_processor; - - // ---------------------------------| mocks |--------------------------------- - - std::shared_ptr transport; - std::shared_ptr propagation_strategy; - std::shared_ptr time_provider; - - const shared_model::interface::types::CounterType time_now = - iroha::time::now(); - const shared_model::interface::types::CounterType time_before = time_now - 1; - const shared_model::interface::types::CounterType time_after = time_now + 1; - - PublicKeyHexStringView another_peer_key_hex{"another_pubkey"sv}; - PublicKeyHexStringView yet_another_peer_key_hex{"yet_another_pubkey"sv}; - - protected: - void SetUp() override { - transport = std::make_shared(); - storage = - std::make_shared(std::make_shared(), - getTestLogger("MstState"), - getTestLogger("MstStorage")); - - propagation_strategy = std::make_shared(); - EXPECT_CALL(*propagation_strategy, emitter()) - .WillOnce(Return(propagation_subject.get_observable())); - - time_provider = std::make_shared(); - EXPECT_CALL(*time_provider, getCurrentTime()) - .WillRepeatedly(Return(time_now)); - - mst_processor = - std::make_shared(transport, - storage, - propagation_strategy, - time_provider, - getTestLogger("FairMstProcessor")); - } -}; - -/* - * Initialize observables of mst processor - */ -auto initObservers(std::shared_ptr mst_processor, - int a, - int b, - int c) { - auto obs = std::make_tuple( - make_test_subscriber(mst_processor->onStateUpdate(), a), - make_test_subscriber(mst_processor->onPreparedBatches(), b), - make_test_subscriber(mst_processor->onExpiredBatches(), c)); - std::get<0>(obs).subscribe(); - std::get<1>(obs).subscribe(); - std::get<2>(obs).subscribe(); - return obs; -} - -/* - * Make sure that observables in the valid state - */ -template -void check(T &t) { - ASSERT_TRUE(std::get<0>(t).validate()) - << "onStateUpdate" << std::get<0>(t).reason(); - ASSERT_TRUE(std::get<1>(t).validate()) - << "onPreparedBatches" << std::get<1>(t).reason(); - ASSERT_TRUE(std::get<2>(t).validate()) - << "onExpiredBatches" << std::get<2>(t).reason(); -} - -/** - * @given initialised mst processor - * AND wrappers on mst observables - * AND uncompleted batch in mst - * - * @when the same signature for that batch is received - * - * @then check that: - * absent state update transactions - * AND absent prepared transactions - * AND absent expired transactions - */ -TEST_F(MstProcessorTest, receivedSameSignatures) { - // ---------------------------------| given |--------------------------------- - auto same_key = makeKey(); - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 2)), 0, same_key)); - - auto observers = initObservers(mst_processor, 0, 0, 0); - - // ---------------------------------| when |---------------------------------- - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 2)), 0, same_key)); - - // ---------------------------------| then |---------------------------------- - check(observers); -} - -/** - * @given initialised mst processor - * AND wrappers on mst observables - * - * @when an incomplete batch is inserted - * - * @then check that: - * notification about new batch is sent - * AND absent prepared transactions - * AND absent expired transactions - */ -TEST_F(MstProcessorTest, notCompletedTransactionUsecase) { - // ---------------------------------| given |--------------------------------- - auto observers = initObservers(mst_processor, 1, 0, 0); - - // ---------------------------------| when |---------------------------------- - mst_processor->propagateBatch( - addSignaturesFromKeyPairs(makeTestBatch(txBuilder(1)), 0, makeKey())); - - // ---------------------------------| then |---------------------------------- - check(observers); -} - -/** - * @given initialised mst processor - * AND wrappers on mst observables - * AND uncompleted batch in mst - * - * @when new signature for that batch is received, but total number of them is - * still not enough - * - * @then check that: - * state update observer is called - * AND absent prepared transactions - * AND absent expired transactions - */ -TEST_F(MstProcessorTest, newSignatureNotCompleted) { - // ---------------------------------| given |--------------------------------- - auto same_key = makeKey(); - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 3)), 0, makeKey())); - - auto observers = initObservers(mst_processor, 1, 0, 0); - - // ---------------------------------| when |---------------------------------- - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 3)), 0, makeKey())); - - // ---------------------------------| then |---------------------------------- - check(observers); -} - -/** - * @given initialised mst processor - * AND wrappers on mst observables - * - * @when the same transaction arrives with different signatures - * AND the resulting set of signatures satisfies the account quorum number - * - * @then check that: - * state is updated the same number of times as transaction arrival minus one - * AND 1 prepared transaction - * AND absent expired transactions - */ -TEST_F(MstProcessorTest, completedTransactionUsecase) { - // ---------------------------------| given |--------------------------------- - auto observers = initObservers(mst_processor, 2, 1, 0); - - // ---------------------------------| when |---------------------------------- - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 3)), 0, makeKey())); - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 3)), 0, makeKey())); - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 3)), 0, makeKey())); - - // ---------------------------------| then |---------------------------------- - check(observers); -} - -/** - * @given initialised mst processor - * AND wrappers on mst observables - * - * @when insert (by propagate_batch method) batch that already - * expired with quorum one - * - * @then check that: - * state is updated - * AND 0 prepared transaction (although quorum 1) - * AND 1 expired transactions - */ -TEST_F(MstProcessorTest, expiredTransactionUsecase) { - // ---------------------------------| given |--------------------------------- - auto observers = initObservers(mst_processor, 1, 0, 1); - - // ---------------------------------| when |---------------------------------- - auto quorum = 1u; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_before, quorum)), 0, makeKey())); - - // ---------------------------------| then |---------------------------------- - check(observers); -} - -/** - * @given initialised mst processor - * AND our state contains one transactions TX with quorum 2 - * AND wrappers on mst observables - * - * @when received new state from other peer via transport, - * that contains TX with another signature - * - * @then check that: - * state observer is not called - * AND 1 prepared transaction - * AND 0 expired transactions - */ -TEST_F(MstProcessorTest, onUpdateFromTransportUsecase) { - // ---------------------------------| given |--------------------------------- - auto quorum = 2; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, quorum)), 0, makeKey())); - - auto observers = initObservers(mst_processor, 0, 1, 0); - - // ---------------------------------| when |---------------------------------- - auto transported_state = MstState::empty(getTestLogger("MstState"), - std::make_shared()); - transported_state += addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, quorum)), 0, makeKey()); - mst_processor->onNewState(another_peer_key_hex, std::move(transported_state)); - - // ---------------------------------| then |---------------------------------- - check(observers); -} - -/** - * @given initialised mst processor - * AND our state contains one transaction - * - * @when received notification about new propagation - * - * @then check that: - * transport invoked for all peers - */ -TEST_F(MstProcessorTest, onNewPropagationUsecase) { - // ---------------------------------| given |--------------------------------- - auto quorum = 2u; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_after, quorum)), 0, makeKey())); - EXPECT_CALL(*transport, sendState(_, _)) - .Times(2) - .WillRepeatedly(Return(rxcpp::observable<>::just(true))); - - // ---------------------------------| when |---------------------------------- - std::vector> peers{ - makePeer("one", kPublicKey1), makePeer("two", kPublicKey2)}; - propagation_subject.get_subscriber().on_next(peers); -} - -/** - * @given initialised mst processor - * AND our state contains one transaction - * - * @when received notification about new propagation - * AND transport successfully sent the state - * - * @then same diff is applied to storage - */ -TEST_F(MstProcessorTest, SendStateSuccess) { - // ---------------------------------| given |--------------------------------- - auto quorum = 2u; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_after, quorum)), 0, makeKey())); - EXPECT_CALL(*transport, sendState(_, _)) - .WillOnce(Return(rxcpp::observable<>::just(true))); - - // ---------------------------------| when |---------------------------------- - std::vector> peers{ - makePeer("one", another_peer_key_hex)}; - propagation_subject.get_subscriber().on_next(peers); - - // ---------------------------------| then |---------------------------------- - ASSERT_TRUE( - storage->getDiffState(another_peer_key_hex, time_after).isEmpty()); -} - -/** - * @given initialised mst processor - * AND our state contains one transaction - * - * @when received notification about new propagation with two peers - * AND transport successfully sent the state - * - * @then same diff is applied to storage - */ -TEST_F(MstProcessorTest, SendStateSuccessTwiceSamePropagation) { - // ---------------------------------| given |--------------------------------- - auto quorum = 2u; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_after, quorum)), 0, makeKey())); - EXPECT_CALL(*transport, sendState(_, _)) - .WillRepeatedly(Return(rxcpp::observable<>::just(true))); - - // ---------------------------------| when |---------------------------------- - propagation_subject.get_subscriber().on_next( - PeerList{makePeer("one", another_peer_key_hex), - makePeer("two", yet_another_peer_key_hex)}); - - // ---------------------------------| then |---------------------------------- - ASSERT_TRUE( - storage->getDiffState(another_peer_key_hex, time_after).isEmpty()); - ASSERT_TRUE( - storage->getDiffState(yet_another_peer_key_hex, time_after).isEmpty()); -} - -/** - * @given initialised mst processor - * AND our state contains one transaction - * - * @when received two notifications about new propagation with different peers - * AND transport successfully sent the state - * - * @then same diff is applied to storage - */ -TEST_F(MstProcessorTest, SendStateSuccessTwiceDifferentPropagations) { - // ---------------------------------| given |--------------------------------- - auto quorum = 2u; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_after, quorum)), 0, makeKey())); - EXPECT_CALL(*transport, sendState(_, _)) - .WillRepeatedly(Return(rxcpp::observable<>::just(true))); - - // ---------------------------------| when |---------------------------------- - propagation_subject.get_subscriber().on_next( - PeerList{makePeer("one", another_peer_key_hex)}); - propagation_subject.get_subscriber().on_next( - PeerList{makePeer("two", yet_another_peer_key_hex)}); - - // ---------------------------------| then |---------------------------------- - ASSERT_TRUE( - storage->getDiffState(another_peer_key_hex, time_after).isEmpty()); - ASSERT_TRUE( - storage->getDiffState(yet_another_peer_key_hex, time_after).isEmpty()); -} - -/** - * @given initialised mst processor - * AND our state contains one transaction - * - * @when received notification about new propagation - * AND transport failed to send the state - * - * @then diff is not applied to storage - */ -TEST_F(MstProcessorTest, SendStateFailure) { - // ---------------------------------| given |--------------------------------- - auto quorum = 2u; - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_after, quorum)), 0, makeKey())); - EXPECT_CALL(*transport, sendState(_, _)) - .WillOnce(Return(rxcpp::observable<>::just(false))); - - // ---------------------------------| when |---------------------------------- - std::vector> peers{ - makePeer("one", another_peer_key_hex)}; - propagation_subject.get_subscriber().on_next(peers); - - // ---------------------------------| then |---------------------------------- - ASSERT_FALSE( - storage->getDiffState(another_peer_key_hex, time_after).isEmpty()); -} - -/** - * @given initialized mst processor - * AND our state contains one transaction - * AND one peer with the same state as our - * - * @when received notification about new propagation - * - * @then check that transport was not invoked - */ -TEST_F(MstProcessorTest, emptyStatePropagation) { - // ---------------------------------| then |---------------------------------- - EXPECT_CALL(*transport, sendState(_, _)).Times(0); - - // ---------------------------------| given |--------------------------------- - auto another_peer = makePeer("another", kPublicKey1); - - auto another_peer_state = MstState::empty( - getTestLogger("MstState"), - std::make_shared(std::chrono::minutes(0))); - another_peer_state += makeTestBatch(txBuilder(1)); - - storage->apply( - shared_model::interface::types::PublicKeyHexStringView{kPublicKey1}, - another_peer_state); - ASSERT_TRUE(storage - ->getDiffState( - shared_model::interface::types::PublicKeyHexStringView{ - another_peer->pubkey()}, - time_now) - .isEmpty()); - - // ---------------------------------| when |---------------------------------- - std::vector> peers{ - std::move(another_peer)}; - propagation_subject.get_subscriber().on_next(peers); -} - -/** - * @given initialized mst processor with empty state - * - * @when received other peer's state containing an outdated batch - * - * @then check that transport was not invoked - * @and queues are not pushed to - * @and the batch does not get into our state - */ -TEST_F(MstProcessorTest, receivedOutdatedState) { - // ---------------------------------| then |---------------------------------- - EXPECT_CALL(*transport, sendState(_, _)).Times(0); - auto observers = initObservers(mst_processor, 0, 0, 0); - - // ---------------------------------| when |---------------------------------- - const auto expired_batch = makeTestBatch(txBuilder(1, time_before, 3)); - { - auto transported_state = MstState::empty(getTestLogger("MstState"), - std::make_shared()); - transported_state += addSignaturesFromKeyPairs(expired_batch, 0, makeKey()); - mst_processor->onNewState(another_peer_key_hex, - std::move(transported_state)); - } - - // ---------------------------------| then |---------------------------------- - EXPECT_FALSE(storage->batchInStorage(expired_batch)); - check(observers); -} - -/** - * @given initialized mst processor with two incomplete transactions in the - * state - * - * @when one of them is received from another peer - * - * @then no observables are triggered - */ -TEST_F(MstProcessorTest, receivedOneOfExistingTxs) { - const auto batch = addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time_now, 2)), 0, makeKey()); - mst_processor->propagateBatch(batch); - mst_processor->propagateBatch(addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(2, time_now, 2)), 0, makeKey())); - - auto received_state = MstState::empty(getTestLogger("MstState"), - std::make_shared()); - received_state += batch; - auto observers = initObservers(mst_processor, 0, 0, 0); - mst_processor->onNewState(another_peer_key_hex, std::move(received_state)); - - check(observers); -} diff --git a/test/module/irohad/multi_sig_transactions/state_test.cpp b/test/module/irohad/multi_sig_transactions/state_test.cpp deleted file mode 100644 index 96c375dbd34..00000000000 --- a/test/module/irohad/multi_sig_transactions/state_test.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "framework/crypto_literals.hpp" -#include "framework/test_logger.hpp" -#include "logger/logger.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" - -using namespace std; -using namespace iroha; -using namespace iroha::model; - -auto mst_state_log_ = getTestLogger("MstState"); -auto log_ = getTestLogger("MstStateTest"); -auto completer_ = std::make_shared(); - -/** - * @given empty state - * @when insert one batch - * @then checks that state contains the inserted batch - */ -TEST(StateTest, CreateState) { - auto state = MstState::empty(mst_state_log_, completer_); - ASSERT_EQ(0, state.getBatches().size()); - auto tx = addSignatures(makeTestBatch(txBuilder(1)), - 0, - makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - state += tx; - ASSERT_EQ(1, state.getBatches().size()); - ASSERT_EQ(*tx, **state.getBatches().begin()); -} - -/** - * @given empty state - * @when insert batches with different signatures - * @then checks that signatures are merged into the state - */ -TEST(StateTest, UpdateExistingState) { - auto state = MstState::empty(mst_state_log_, completer_); - auto time = iroha::time::now(); - - auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); - auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); - auto base_tx = makeTestBatch(txBuilder(1, time)); - - auto first_tx = addSignatures(base_tx, 0, first_signature); - state += first_tx; - - auto second_tx = addSignatures(base_tx, 0, second_signature); - state += second_tx; - ASSERT_EQ(1, state.getBatches().size()); - - auto merged_tx = addSignatures(base_tx, 0, first_signature, second_signature); - ASSERT_EQ(*merged_tx, **state.getBatches().begin()); -} - -/** - * @given empty state @and a batch - * @when inserting the batch - * @then "contains" method shows presence of the batch - */ -TEST(StateTest, ContainsMethodFindsInsertedBatch) { - auto state = MstState::empty(mst_state_log_, completer_); - - auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); - auto batch = makeTestBatch(txBuilder(1, iroha::time::now())); - auto tx = addSignatures(batch, 0, first_signature); - state += tx; - - EXPECT_TRUE(state.contains(batch)); -} - -/** - * @given state with one batch - * @when batch is erased by hash - * @then "contains" method shows absence of the batch - */ -TEST(StateTest, EraseByTransactionHash) { - auto state = MstState::empty(mst_state_log_, completer_); - - auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); - auto batch = makeTestBatch(txBuilder(1, iroha::time::now())); - auto tx = addSignatures(batch, 0, first_signature); - state += tx; - - EXPECT_TRUE(state.contains(batch)); - - state.eraseByTransactionHash(tx->transactions().front()->hash()); - - EXPECT_FALSE(state.contains(batch)); -} - -/** - * @given empty state @and a distinct batch - * @when checking that batch's presence in the state - * @then "contains" method shows absence of the batch - */ -TEST(StateTest, ContainsMethodDoesNotFindNonInsertedBatch) { - auto state = MstState::empty(mst_state_log_, completer_); - auto batch = makeTestBatch(txBuilder(1, iroha::time::now())); - - EXPECT_FALSE(state.contains(batch)); -} - -/** - * @given empty state - * @when insert batch with same signatures two times - * @then checks that the state contains only one signature - */ -TEST(StateTest, UpdateStateWhenTransactionsSame) { - log_->info("Create empty state => insert two equal transaction"); - - auto state = MstState::empty(mst_state_log_, completer_); - - auto time = iroha::time::now(); - state += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - state += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - - ASSERT_EQ(1, state.getBatches().size()); - ASSERT_EQ(1, - boost::size(state.getBatches() - .begin() - ->get() - ->transactions() - .begin() - ->get() - ->signatures())); -} - -/** - * @given prepared state with 3 batches - * @when insert the batches, which are not present in the state - * @then checks that all batches are here - */ -TEST(StateTest, DifferentSignaturesUnionTest) { - log_->info("Create two states => merge them"); - - auto state1 = MstState::empty(mst_state_log_, completer_); - - state1 += addSignatures(makeTestBatch(txBuilder(1)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - - state1 += addSignatures(makeTestBatch(txBuilder(2)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - state1 += addSignatures(makeTestBatch(txBuilder(3)), - 0, - makeSignature("3"_hex_sig, "3"_hex_pubkey)); - - ASSERT_EQ(3, state1.getBatches().size()); - - auto state2 = MstState::empty(mst_state_log_, completer_); - state2 += addSignatures(makeTestBatch(txBuilder(4)), - 0, - makeSignature("4"_hex_sig, "4"_hex_pubkey)); - state2 += addSignatures(makeTestBatch(txBuilder(5)), - 0, - makeSignature("5"_hex_sig, "5"_hex_pubkey)); - ASSERT_EQ(2, state2.getBatches().size()); - - state1 += state2; - ASSERT_EQ(5, state1.getBatches().size()); -} - -/** - * @given two empty states - * @when insert transaction with quorum 2 to one state - * AND insert same transaction with another signature to second state - * AND merge states - * @then check that merged state contains both signatures - */ -TEST(StateTest, UnionStateWhenSameTransactionHaveDifferentSignatures) { - log_->info( - "Create two transactions with different signatures => move them" - " into owns states => merge states"); - - auto time = iroha::time::now(); - - auto state1 = MstState::empty(mst_state_log_, completer_); - auto state2 = MstState::empty(mst_state_log_, completer_); - - state1 += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - state2 += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - - state1 += state2; - ASSERT_EQ(1, state1.getBatches().size()); - ASSERT_EQ(2, - boost::size(state1.getBatches() - .begin() - ->get() - ->transactions() - .begin() - ->get() - ->signatures())); -} - -/** - * @given given two states with one common transaction but with different - * signatures - * @when states are merged - * @then the common transaction is not appeared in the resulting state - */ -TEST(StateTest, UnionStateWhenTransactionsSame) { - auto time = iroha::time::now(); - - auto state1 = MstState::empty(mst_state_log_, completer_); - state1 += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - state1 += addSignatures(makeTestBatch(txBuilder(2)), - 0, - makeSignature("other"_hex_sig, "other"_hex_pubkey)); - - ASSERT_EQ(2, state1.getBatches().size()); - - auto state2 = MstState::empty(mst_state_log_, completer_); - state2 += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - state2 += addSignatures(makeTestBatch(txBuilder(3)), - 0, - makeSignature("other_"_hex_sig, "other_"_hex_pubkey)); - ASSERT_EQ(2, state2.getBatches().size()); - - state1 += state2; - ASSERT_EQ(3, state1.getBatches().size()); -} - -/** - * @given two states with a common element - * @when difference of the states is taken - * @then the common element is present in the difference set - */ -TEST(StateTest, DifferenceTest) { - auto time = iroha::time::now(); - - auto first_signature = makeSignature("1"_hex_sig, "1"_hex_pubkey); - auto second_signature = makeSignature("2"_hex_sig, "2"_hex_pubkey); - auto third_signature = makeSignature("3"_hex_sig, "3"_hex_pubkey); - - auto another_signature = - makeSignature("another"_hex_sig, "another"_hex_pubkey); - - auto common_batch = makeTestBatch(txBuilder(1, time)); - auto another_batch = makeTestBatch(txBuilder(3)); - - auto state1 = MstState::empty(mst_state_log_, completer_); - state1 += addSignatures(common_batch, 0, first_signature); - state1 += addSignatures(common_batch, 0, second_signature); - - auto state2 = MstState::empty(mst_state_log_, completer_); - state2 += addSignatures(common_batch, 0, second_signature); - state2 += addSignatures(common_batch, 0, third_signature); - state2 += addSignatures(another_batch, 0, another_signature); - - MstState diff = state1 - state2; - ASSERT_EQ(1, diff.getBatches().size()); - auto expected_batch = addSignatures(common_batch, 0, first_signature); - ASSERT_EQ(*expected_batch, **diff.getBatches().begin()); -} - -/** - * @given an empty state - * @when a partially signed transaction with quorum 3 is inserted 3 times - * @then each time new signature inserted state gives this batch back @and - * returned statuses correspond to actual ones @and the resulting state contains - * one signed transaction - */ -TEST(StateTest, UpdateTxUntillQuorum) { - auto quorum = 3u; - auto time = iroha::time::now(); - - auto state = MstState::empty(mst_state_log_, completer_); - - auto state_after_one_tx = state += - addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1"_hex_sig, "1"_hex_pubkey)); - ASSERT_EQ(1, state_after_one_tx.updated_state_->getBatches().size()); - ASSERT_EQ(0, state_after_one_tx.completed_state_->getBatches().size()); - - auto state_after_two_txes = state += - addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - ASSERT_EQ(1, state_after_two_txes.updated_state_->getBatches().size()); - ASSERT_EQ(0, state_after_two_txes.completed_state_->getBatches().size()); - - auto state_after_three_txes = state += - addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("3"_hex_sig, "3"_hex_pubkey)); - ASSERT_EQ(0, state_after_three_txes.updated_state_->getBatches().size()); - ASSERT_EQ(1, state_after_three_txes.completed_state_->getBatches().size()); - ASSERT_TRUE((*state_after_three_txes.completed_state_->getBatches().begin()) - ->hasAllSignatures()); - ASSERT_EQ(0, state.getBatches().size()); -} - -/** - * @given two states with one common partially signed transaction - * @when the states are merged - * @then the resulting state contains one signed transaction - */ -TEST(StateTest, UpdateStateWithNewStateUntilQuorum) { - auto quorum = 3u; - auto keypair = makeKey(); - auto time = iroha::time::now(); - - auto state1 = MstState::empty(mst_state_log_, completer_); - state1 += addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1_1"_hex_sig, "1_1"_hex_pubkey)); - state1 += addSignatures(makeTestBatch(txBuilder(2, time)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - state1 += addSignatures(makeTestBatch(txBuilder(2, time)), - 0, - makeSignature("3"_hex_sig, "3"_hex_pubkey)); - ASSERT_EQ(2, state1.getBatches().size()); - - auto state2 = MstState::empty(mst_state_log_, completer_); - state2 += addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1_2"_hex_sig, "1_2"_hex_pubkey)); - state2 += addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1_3"_hex_sig, "1_3"_hex_pubkey)); - ASSERT_EQ(1, state2.getBatches().size()); - - auto final_state = state1 += state2; - ASSERT_EQ(1, final_state.completed_state_->getBatches().size()); - ASSERT_EQ(1, state1.getBatches().size()); -} - -/** - * @given a timepoint - * AND a state with an expired transaction - * @when erase by time is called - * @then the resulting state contains the expired transaction - */ -TEST(StateTest, TimeIndexInsertionByTx) { - auto quorum = 2u; - auto time = iroha::time::now(); - - auto prepared_batch = - addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1_1"_hex_sig, "1_1"_hex_pubkey)); - - auto state = MstState::empty(mst_state_log_, completer_); - - state += prepared_batch; - - auto expired_state = state.extractExpired(time + 1); - ASSERT_EQ(1, expired_state.getBatches().size()); - ASSERT_EQ(*prepared_batch, **expired_state.getBatches().begin()); - ASSERT_EQ(0, state.getBatches().size()); -} - -/** - * @given two states with expired transactions - * @when merge them - * AND make states expired - * @then checks that all expired transactions are preserved in expired state - */ -TEST(StateTest, TimeIndexInsertionByAddState) { - auto quorum = 3u; - auto time = iroha::time::now(); - - auto state1 = MstState::empty(mst_state_log_, completer_); - state1 += addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1_1"_hex_sig, "1_1"_hex_pubkey)); - state1 += addSignatures(makeTestBatch(txBuilder(1, time, quorum)), - 0, - makeSignature("1_2"_hex_sig, "1_2"_hex_pubkey)); - - auto state2 = MstState::empty(mst_state_log_, completer_); - state2 += addSignatures(makeTestBatch(txBuilder(2, time)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - state2 += addSignatures(makeTestBatch(txBuilder(3, time)), - 0, - makeSignature("3"_hex_sig, "3"_hex_pubkey)); - - auto final_state = state1 += state2; - ASSERT_EQ(0, final_state.completed_state_->getBatches().size()); - ASSERT_EQ(2, final_state.updated_state_->getBatches().size()); -} - -/** - * @given a state with two batches - * AND an empty state - * @when the second state is removed from the first state - * AND erase by time is called - * @then checks that the resulting state does not contain any transactions - */ -TEST(StateTest, RemovingTestWhenByTimeHasExpired) { - auto time = iroha::time::now(); - - auto state1 = MstState::empty(mst_state_log_, completer_); - state1 += addSignatures(makeTestBatch(txBuilder(1, time)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - state1 += addSignatures(makeTestBatch(txBuilder(2, time)), - 0, - makeSignature("2"_hex_sig, "2"_hex_pubkey)); - - auto state2 = MstState::empty(mst_state_log_, completer_); - - auto diff_state = state1 - state2; - - ASSERT_EQ(2, diff_state.getBatches().size()); -} diff --git a/test/module/irohad/multi_sig_transactions/storage_test.cpp b/test/module/irohad/multi_sig_transactions/storage_test.cpp deleted file mode 100644 index 370a711a3b7..00000000000 --- a/test/module/irohad/multi_sig_transactions/storage_test.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "framework/crypto_literals.hpp" -#include "framework/test_logger.hpp" -#include "logger/logger.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "multi_sig_transactions/storage/mst_storage_impl.hpp" - -using namespace iroha; - -auto log_ = getTestLogger("MstStorageTest"); - -class StorageTest : public testing::Test { - public: - void SetUp() override { - completer_ = std::make_shared(); - storage = std::make_shared( - completer_, getTestLogger("MstState"), getTestLogger("MstStorage")); - fillOwnState(); - } - - void fillOwnState() { - storage->updateOwnState(makeTestBatch(txBuilder(1, creation_time))); - storage->updateOwnState(makeTestBatch(txBuilder(2, creation_time))); - storage->updateOwnState(makeTestBatch(txBuilder(3, creation_time))); - } - - std::shared_ptr storage; - const shared_model::interface::types::PublicKeyHexStringView absent_peer_key{ - std::string_view{"0A"}}; - - const unsigned quorum = 3u; - const shared_model::interface::types::TimestampType creation_time = - iroha::time::now(); - std::shared_ptr completer_; -}; - -TEST_F(StorageTest, StorageWhenApplyOtherState) { - using namespace std::literals; - log_->info( - "create state with default peers and other state => " - "apply state"); - - auto new_state = MstState::empty(getTestLogger("MstState"), completer_); - new_state += makeTestBatch(txBuilder(5, creation_time)); - new_state += makeTestBatch(txBuilder(6, creation_time)); - new_state += makeTestBatch(txBuilder(7, creation_time)); - - storage->apply("0B"_hex_pubkey, new_state); - - ASSERT_EQ(6, - storage->getDiffState(absent_peer_key, creation_time) - .getBatches() - .size()); -} - -TEST_F(StorageTest, StorageInsertOtherState) { - log_->info("init fixture state => get expired state"); - - ASSERT_EQ(3, - storage->extractExpiredTransactions(creation_time + 1) - .getBatches() - .size()); - ASSERT_EQ(0, - storage->getDiffState(absent_peer_key, creation_time + 1) - .getBatches() - .size()); -} - -TEST_F(StorageTest, StorageWhenCreateValidDiff) { - log_->info("insert transactions => check their presence"); - - ASSERT_EQ(3, - storage->getDiffState(absent_peer_key, creation_time) - .getBatches() - .size()); -} - -TEST_F(StorageTest, StorageWhenCreate) { - log_->info( - "insert transactions => wait until expiring => " - " check their absence"); - - auto expiration_time = creation_time + 1; - - ASSERT_EQ(0, - storage->getDiffState(absent_peer_key, expiration_time) - .getBatches() - .size()); -} - -/** - * @given storage with three batches - * @when checking, if those batches belong to the storage - * @then storage reports, that those batches are in it - */ -TEST_F(StorageTest, StorageFindsExistingBatch) { - auto batch1 = makeTestBatch(txBuilder(1, creation_time)); - auto batch2 = makeTestBatch(txBuilder(2, creation_time)); - auto batch3 = makeTestBatch(txBuilder(3, creation_time)); - - EXPECT_TRUE(storage->batchInStorage(batch1)); - EXPECT_TRUE(storage->batchInStorage(batch2)); - EXPECT_TRUE(storage->batchInStorage(batch3)); -} - -/** - * @given storage with three batches @and one another batch not in the storage - * @when checking, if the last batch belongs to the storage - * @then storage reports, that this batch is not in it - */ -TEST_F(StorageTest, StorageDoesNotFindNonExistingBatch) { - auto distinct_batch = makeTestBatch(txBuilder(4, creation_time)); - EXPECT_FALSE(storage->batchInStorage(distinct_batch)); -} - -/** - * @given storage with a batch from peer A (quorum = 3, 1 signature) - * @when the batch gets updated with a new signature from Torii - * @then the diff for peer A has the new signature - */ -TEST_F(StorageTest, DiffStateContainsNewSignature) { - using namespace testing; - using namespace shared_model::interface; - - std::vector keypairs; - std::generate_n(std::back_inserter(keypairs), 2, [] { - return shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); - }); - - auto make_batch = [this] { - return framework::batch::makeTestBatch(txBuilder(1, creation_time)); - }; - - auto const reduced_hash = make_batch()->transactions().front()->reducedHash(); - shared_model::interface::types::PublicKeyHexStringView const peer_A_key{"OB"}; - - // storage gets a batch from peer A with 1st signature - { - auto new_state = MstState::empty(getTestLogger("MstState"), completer_); - new_state += addSignaturesFromKeyPairs(make_batch(), 0, keypairs[0]); - - storage->apply(peer_A_key, std::move(new_state)); - } - - // diff with peer A does not have this batch - ASSERT_THAT(storage->getDiffState(peer_A_key, creation_time).getBatches(), - Not(Contains(Pointee( - Property(&TransactionBatch::transactions, - Contains(Pointee(Property(&Transaction::reducedHash, - Eq(reduced_hash))))))))); - - // storage gets another signature for the batch from Torii - storage->updateOwnState( - addSignaturesFromKeyPairs(make_batch(), 0, keypairs[1])); - - // diff with peer A now has the batch with the signature that just came Torii - EXPECT_THAT( - storage->getDiffState(peer_A_key, creation_time).getBatches(), - Contains(Pointee(Property( - &TransactionBatch::transactions, - ElementsAre(Pointee(AllOf( - Property(&Transaction::reducedHash, Eq(reduced_hash)), - Property(&Transaction::signatures, - Contains(Property(&Signature::publicKey, - Eq(keypairs[1].publicKey()))))))))))); -} diff --git a/test/module/irohad/multi_sig_transactions/transport_test.cpp b/test/module/irohad/multi_sig_transactions/transport_test.cpp deleted file mode 100644 index 40a7209db81..00000000000 --- a/test/module/irohad/multi_sig_transactions/transport_test.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "multi_sig_transactions/transport/mst_transport_grpc.hpp" - -#include -#include "backend/protobuf/common_objects/proto_common_objects_factory.hpp" -#include "backend/protobuf/proto_transport_factory.hpp" -#include "framework/crypto_literals.hpp" -#include "framework/mock_stream.h" -#include "framework/test_logger.hpp" -#include "interfaces/iroha_internal/transaction_batch_factory_impl.hpp" -#include "interfaces/iroha_internal/transaction_batch_parser_impl.hpp" -#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" -#include "module/irohad/ametsuchi/mock_client_factory.hpp" -#include "module/irohad/common/validators_config.hpp" -#include "module/irohad/multi_sig_transactions/mock_mst_transport_notification.hpp" -#include "module/irohad/multi_sig_transactions/mst_mocks.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "module/shared_model/interface_mocks.hpp" -#include "module/shared_model/validators/validators.hpp" -#include "mst_mock.grpc.pb.h" -#include "multi_sig_transactions/state/mst_state.hpp" -#include "validators/default_validator.hpp" -#include "validators/field_validator.hpp" -#include "validators/protobuf/proto_transaction_validator.hpp" - -using namespace std::literals; -using namespace iroha::network; -using namespace iroha::model; -using namespace shared_model::interface; - -using ::testing::_; -using ::testing::A; -using ::testing::DoAll; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::SaveArg; - -class TransportTest : public ::testing::Test { - public: - TransportTest() : my_key_(makeKey()) {} - void SetUp() override { - async_call_ = std::make_shared>( - getTestLogger("AsyncClient")); - parser_ = std::make_shared(); - batch_validator_ = - std::make_shared( - iroha::test::kTestsValidatorsConfig); - batch_factory_ = - std::make_shared(batch_validator_); - tx_presence_cache_ = - std::make_shared(); - completer_ = - std::make_shared(std::chrono::minutes(0)); - mst_notification_transport_ = - std::make_shared(); - interface_tx_validator = - std::make_unique>(); - proto_tx_validator = - std::make_unique>(); - tx_factory = std::make_shared>(std::move(interface_tx_validator), - std::move(proto_tx_validator)); - transport = std::make_shared( - async_call_, - tx_factory, - parser_, - batch_factory_, - tx_presence_cache_, - completer_, - types::PublicKeyHexStringView{my_key_.publicKey()}, - getTestLogger("MstState"), - getTestLogger("MstTransportGrpc"), - std::unique_ptr( - mock_client_factory_)); - transport->subscribe(mst_notification_transport_); - - peer = makePeer("localhost:0", "abcdabcdabcdabcdabcdabcd"_hex_pubkey); - } - - template - auto expectConnection(const shared_model::interface::Peer &peer, - ExpectationsSetter &&set_expectations) { - using namespace ::testing; - auto stub = std::make_unique(); - std::forward(set_expectations)(*stub); - EXPECT_CALL(*mock_client_factory_, createClient(Ref(peer))) - .WillOnce(Return(ByMove(std::move(stub)))); - } - - iroha::network::MockClientFactory - *mock_client_factory_{ - new iroha::network::MockClientFactory()}; - std::shared_ptr> async_call_; - std::shared_ptr parser_; - std::shared_ptr> - batch_validator_; - std::shared_ptr batch_factory_; - std::shared_ptr tx_presence_cache_; - shared_model::crypto::Keypair my_key_; - std::shared_ptr completer_; - std::shared_ptr - mst_notification_transport_; - std::unique_ptr> - interface_tx_validator; - std::unique_ptr< - shared_model::validation::MockValidator> - proto_tx_validator; - std::shared_ptr> - tx_factory; - std::shared_ptr transport; - std::shared_ptr peer; -}; - -static bool statesEqual(const iroha::MstState &a, const iroha::MstState &b) { - // treat them like sets of batches: - return (a - b).isEmpty() and (b - a).isEmpty(); -} - -/** - * @brief Sends data over MstTransportGrpc (MstState and Peer objects) and - * receives them. When received deserializes them end ensures that deserialized - * objects equal to objects before sending. - * - * @given Initialized transport - * AND MstState for transfer - * @when Send state via transport - * @then Assume that received state same as sent - */ -TEST_F(TransportTest, SendAndReceive) { - EXPECT_CALL(*tx_presence_cache_, - check(A())) - .WillRepeatedly(Invoke([](const auto &batch) { - iroha::ametsuchi::TxPresenceCache::BatchStatusCollectionType result; - std::transform( - batch.transactions().begin(), - batch.transactions().end(), - std::back_inserter(result), - [](auto &tx) { - return iroha::ametsuchi::tx_cache_status_responses::Missing{ - tx->hash()}; - }); - return result; - })); - auto time = iroha::time::now(); - auto state = iroha::MstState::empty(getTestLogger("MstState"), completer_); - state += addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(1, time)), 0, makeKey()); - state += addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(2, time)), 0, makeKey()); - state += addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(3, time)), 0, makeKey()); - state += addSignaturesFromKeyPairs( - makeTestBatch(txBuilder(3, time)), 0, makeKey()); - ASSERT_EQ(3, state.getBatches().size()); - // we want to ensure that server side will call onNewState() - // with same parameters as on the client side - EXPECT_CALL(*mst_notification_transport_, onNewState(_, _)) - .WillOnce(Invoke( - [this, &state](const auto &from_key, auto const &target_state) { - EXPECT_EQ(this->my_key_.publicKey(), from_key); - EXPECT_TRUE(statesEqual(state, target_state)); - })); - - ::grpc::ServerContext context; - ::iroha::network::transport::MstState request; - auto r = std::make_unique< - grpc::testing::MockClientAsyncResponseReader>(); - expectConnection(*peer, [&request, &r](auto &stub) { - EXPECT_CALL(stub, AsyncSendStateRaw(_, _, _)) - .WillOnce(DoAll(SaveArg<1>(&request), Return(r.get()))); - }); - transport->sendState(peer, state).subscribe(); - auto response = transport->SendState(&context, &request, nullptr); - ASSERT_EQ(response.error_code(), grpc::StatusCode::OK); -} - -/** - * Checks that replayed transactions would not pass MST - * (receiving of already processed transactions would not cause new state - * generation) - * @given an instance of MstTransportGrpc - * @when exactly the same state reaches MST two times (in general, the state can - * be different but should contain exactly the same batch both times) - * @then for the first time the mock of tx_presence_cache says that the - * transactions of the batch are not found in cache, and mst produced and - * propagated new state that contains the batch. At the second time, the mock of - * tx_presence cache says that the transactions from the batch were previously - * rejected, so the state propagated via onNewState call would not contain the - * test batch. - */ -TEST_F(TransportTest, ReplayAttack) { - auto batch = makeTestBatch(txBuilder(1), txBuilder(2)); - auto state = iroha::MstState::empty(getTestLogger("MstState"), completer_); - state += addSignaturesFromKeyPairs( - addSignaturesFromKeyPairs(batch, 0, makeKey()), 1, makeKey()); - - EXPECT_CALL(*mst_notification_transport_, onNewState(_, _)) - .Times(1) // an empty state should not be propagated - .WillOnce( - Invoke([&batch](::testing::Unused, const iroha::MstState &state) { - auto batches = state.getBatches(); - ASSERT_EQ(batches.size(), 1); - ASSERT_EQ(**batches.begin(), *batch); - })); - - auto transactions = batch->transactions(); - auto first_hash = transactions.at(0)->hash(); - auto second_hash = transactions.at(0)->hash(); - iroha::ametsuchi::TxPresenceCache::BatchStatusCollectionType - first_mock_response{ - iroha::ametsuchi::tx_cache_status_responses::Missing{first_hash}, - iroha::ametsuchi::tx_cache_status_responses::Missing{second_hash}}; - iroha::ametsuchi::TxPresenceCache::BatchStatusCollectionType - second_mock_response{ - iroha::ametsuchi::tx_cache_status_responses::Rejected{first_hash}, - iroha::ametsuchi::tx_cache_status_responses::Rejected{second_hash}}; - - transport::MstState proto_state; - proto_state.set_source_peer_key(my_key_.publicKey()); - - state.iterateTransactions([&proto_state](const auto &tx) { - *proto_state.add_transactions() = - std::static_pointer_cast(tx) - ->getTransport(); - }); - - grpc::ServerContext context; - google::protobuf::Empty response; - - EXPECT_CALL( - *tx_presence_cache_, - check( - ::testing::Matcher( - _))) - .WillOnce(::testing::Return(first_mock_response)) - .WillOnce(::testing::Return(second_mock_response)); - - transport->SendState(&context, &proto_state, &response); - transport->SendState(&context, &proto_state, &response); -} diff --git a/test/module/irohad/ordering/CMakeLists.txt b/test/module/irohad/ordering/CMakeLists.txt index cb29715b96d..26142ea86b6 100644 --- a/test/module/irohad/ordering/CMakeLists.txt +++ b/test/module/irohad/ordering/CMakeLists.txt @@ -37,4 +37,25 @@ target_link_libraries(on_demand_ordering_gate_test shared_model_interfaces_factories test_logger shared_model_proto_backend + sync_subscription + ) + +addtest(mst_processing_test mst_processing_test.cpp) +target_link_libraries(mst_processing_test + batches_cache + test_logger + shared_model_default_builders + shared_model_stateless_validation + shared_model_interfaces_factories + sync_subscription + ) + +addtest(mst_notification_test mst_notification_tests.cpp) +target_link_libraries(mst_notification_test + batches_cache + test_logger + shared_model_default_builders + shared_model_stateless_validation + shared_model_interfaces_factories + sync_subscription ) diff --git a/test/module/irohad/ordering/mock_on_demand_os_notification.hpp b/test/module/irohad/ordering/mock_on_demand_os_notification.hpp index ac8a56c2b64..dba669a9e8d 100644 --- a/test/module/irohad/ordering/mock_on_demand_os_notification.hpp +++ b/test/module/irohad/ordering/mock_on_demand_os_notification.hpp @@ -7,6 +7,7 @@ #define IROHA_MOCK_ON_DEMAND_OS_NOTIFICATION_HPP #include "ordering/on_demand_os_transport.hpp" +#include "ordering/ordering_types.hpp" #include @@ -16,8 +17,14 @@ namespace iroha { struct MockOdOsNotification : public OdOsNotification { MOCK_METHOD1(onBatches, void(CollectionType)); - - MOCK_METHOD1(onRequestProposal, void(consensus::Round)); + MOCK_METHOD1(onBatchesToWholeNetwork, void(CollectionType)); + MOCK_METHOD2( + onRequestProposal, + void(consensus::Round, + std::optional, + BloomFilter256>>)); + MOCK_CONST_METHOD0(getRequestDelay, std::chrono::milliseconds()); }; } // namespace transport diff --git a/test/module/irohad/ordering/mst_notification_tests.cpp b/test/module/irohad/ordering/mst_notification_tests.cpp new file mode 100644 index 00000000000..9cc2fc68c1c --- /dev/null +++ b/test/module/irohad/ordering/mst_notification_tests.cpp @@ -0,0 +1,206 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "framework/crypto_literals.hpp" +#include "main/subscription.hpp" +#include "module/irohad/ordering/mst_test_helpers.hpp" +#include "ordering/impl/batches_cache.hpp" + +using ::testing::ByMove; +using ::testing::Ref; +using ::testing::Return; +using ::testing::ReturnRefOfCopy; + +struct MSTNotificationsTest : public ::testing::Test { + using MstStateSubscriber = iroha::BaseSubscriber< + bool, + std::shared_ptr>; + std::shared_ptr mst_state_update_; + std::shared_ptr mst_state_prepared_; + std::shared_ptr mst_state_expired_; + + std::vector> + event_updated_, event_prepared_, event_expired_; + + void SetUp() override { + manager_ = iroha::getSubscription(); + mst_state_update_ = iroha::SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + iroha::SubscriptionEngineHandlers::kNotifications, + [&](auto &, + std::shared_ptr + batch) { + ASSERT_TRUE(batch); + event_updated_.push_back(batch); + }); + mst_state_prepared_ = iroha::SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + iroha::SubscriptionEngineHandlers::kNotifications, + [&](auto &, + std::shared_ptr + batch) { + ASSERT_TRUE(batch); + event_prepared_.push_back(batch); + }); + mst_state_expired_ = iroha::SubscriberCreator< + bool, + std::shared_ptr>:: + template create( + iroha::SubscriptionEngineHandlers::kNotifications, + [&](auto &, + std::shared_ptr + batch) { + ASSERT_TRUE(batch); + event_expired_.push_back(batch); + }); + batches_cache_ = std::make_shared(); + } + + void TearDown() override { + mst_state_update_->unsubscribe(); + mst_state_prepared_->unsubscribe(); + mst_state_expired_->unsubscribe(); + + manager_->dispose(); + manager_.reset(); + + event_updated_.clear(); + event_prepared_.clear(); + event_expired_.clear(); + } + + void checkEvents(size_t prepared, size_t updated, size_t expired) { + ASSERT_EQ(event_expired_.size(), expired); + ASSERT_EQ(event_prepared_.size(), prepared); + ASSERT_EQ(event_updated_.size(), updated); + + event_prepared_.clear(); + event_updated_.clear(); + event_expired_.clear(); + } + + std::shared_ptr manager_; + std::shared_ptr batches_cache_; +}; + +TEST_F(MSTNotificationsTest, SimpleAdd) { + auto batch = addSignaturesFromKeyPairs( + makeTestBatch(txBuilder(1, iroha::time::now(), 1)), 0, makeKey()); + batches_cache_->insert(batch); + checkEvents(1, 0, 0); + ASSERT_EQ(batch, event_prepared_[0]); +} + +TEST_F(MSTNotificationsTest, SimpleUnsubscribedAdd) { + auto batch = addSignaturesFromKeyPairs( + makeTestBatch(txBuilder(1, iroha::time::now(), 2)), 0, makeKey()); + batches_cache_->insert(batch); + checkEvents(0, 1, 0); + ASSERT_EQ(batch, event_updated_[0]); +} + +TEST_F(MSTNotificationsTest, SubscribedAdd) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + auto base_tx = makeTestBatch(txBuilder(1, iroha::time::now(), 2)); + + auto first_tx = addSignatures(base_tx, 0, first_signature); + batches_cache_->insert(first_tx); + checkEvents(0, 1, 0); + + auto second_tx = addSignatures(base_tx, 0, second_signature); + batches_cache_->insert(second_tx); + checkEvents(1, 0, 0); +} + +TEST_F(MSTNotificationsTest, SubscribeDifferentTx) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + + auto base_tx_1 = makeTestBatch(txBuilder(1, iroha::time::now(), 2)); + auto base_tx_2 = makeTestBatch(txBuilder(2, iroha::time::now(), 2)); + + auto first_tx = addSignatures(base_tx_1, 0, first_signature); + batches_cache_->insert(first_tx); + checkEvents(0, 1, 0); + + auto second_tx = addSignatures(base_tx_2, 0, second_signature); + batches_cache_->insert(second_tx); + checkEvents(0, 1, 0); +} + +TEST_F(MSTNotificationsTest, NotFullySubscribed) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + auto base_tx = makeTestBatch(txBuilder(1, iroha::time::now(), 2), + txBuilder(2, iroha::time::now(), 2)); + + auto batch = addSignatures( + addSignatures(base_tx, 0, first_signature, second_signature), + 1, + first_signature); + batches_cache_->insert(batch); + checkEvents(0, 1, 0); +} + +TEST_F(MSTNotificationsTest, StepByStepSubscribed) { + auto get_batch = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 2), txBuilder(2, ts, 2)); + }; + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + checkEvents(0, 1, 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 1, makeKey())); + checkEvents(0, 1, 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + checkEvents(0, 1, 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 1, makeKey())); + checkEvents(1, 0, 0); +} + +TEST_F(MSTNotificationsTest, StepByStepNotSubscribed) { + auto get_batch = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 3), txBuilder(2, ts, 1)); + }; + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 1, makeKey())); + checkEvents(0, 1, 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + checkEvents(0, 1, 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + checkEvents(0, 1, 0); +} + +TEST_F(MSTNotificationsTest, DoubleTxs) { + auto get_batch = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 2)); + }; + auto get_batch_2 = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 1)); + }; + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + checkEvents(0, 1, 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + checkEvents(1, 0, 0); + + batches_cache_->insert( + addSignaturesFromKeyPairs(get_batch_2(), 0, makeKey())); + checkEvents(1, 0, 0); +} diff --git a/test/module/irohad/ordering/mst_processing_test.cpp b/test/module/irohad/ordering/mst_processing_test.cpp new file mode 100644 index 00000000000..7d94f1c8983 --- /dev/null +++ b/test/module/irohad/ordering/mst_processing_test.cpp @@ -0,0 +1,184 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "framework/crypto_literals.hpp" +#include "module/irohad/ordering/mst_test_helpers.hpp" +#include "ordering/impl/batches_cache.hpp" + +using ::testing::ByMove; +using ::testing::Ref; +using ::testing::Return; +using ::testing::ReturnRefOfCopy; + +struct MSTProcessingTest : public ::testing::Test { + void SetUp() override { + batches_cache_ = std::make_shared(); + } + std::shared_ptr batches_cache_; +}; + +TEST_F(MSTProcessingTest, SimpleAdd) { + auto batch = addSignaturesFromKeyPairs( + makeTestBatch(txBuilder(1, iroha::time::now(), 1)), 0, makeKey()); + batches_cache_->insert(batch); + ASSERT_EQ(batches_cache_->availableTxsCount(), 1); +} + +TEST_F(MSTProcessingTest, SimpleUnsubscribedAdd) { + auto batch = addSignaturesFromKeyPairs( + makeTestBatch(txBuilder(1, iroha::time::now(), 2)), 0, makeKey()); + batches_cache_->insert(batch); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); +} + +TEST_F(MSTProcessingTest, SubscribedAdd) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + auto base_tx = makeTestBatch(txBuilder(1, iroha::time::now(), 2)); + + auto first_tx = addSignatures(base_tx, 0, first_signature); + batches_cache_->insert(first_tx); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + auto second_tx = addSignatures(base_tx, 0, second_signature); + batches_cache_->insert(second_tx); + ASSERT_EQ(batches_cache_->availableTxsCount(), 1); +} + +TEST_F(MSTProcessingTest, SubscribeDifferentTx) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + + auto base_tx_1 = makeTestBatch(txBuilder(1, iroha::time::now(), 2)); + auto base_tx_2 = makeTestBatch(txBuilder(2, iroha::time::now(), 2)); + + auto first_tx = addSignatures(base_tx_1, 0, first_signature); + batches_cache_->insert(first_tx); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + auto second_tx = addSignatures(base_tx_2, 0, second_signature); + batches_cache_->insert(second_tx); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); +} + +TEST_F(MSTProcessingTest, NotFullySubscribed) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + auto base_tx = makeTestBatch(txBuilder(1, iroha::time::now(), 2), + txBuilder(2, iroha::time::now(), 2)); + + auto batch = addSignatures( + addSignatures(base_tx, 0, first_signature, second_signature), + 1, + first_signature); + batches_cache_->insert(batch); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); +} + +TEST_F(MSTProcessingTest, FullySubscribed) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + auto base_tx = makeTestBatch(txBuilder(1, iroha::time::now(), 2), + txBuilder(2, iroha::time::now(), 2)); + + auto batch = addSignatures( + addSignatures(base_tx, 0, first_signature, second_signature), + 1, + first_signature); + batches_cache_->insert(batch); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + auto batch2 = addSignatures(base_tx, 1, second_signature); + batches_cache_->insert(batch2); + ASSERT_EQ(batches_cache_->availableTxsCount(), 2); +} + +TEST_F(MSTProcessingTest, StepByStepSubscribed) { + auto first_signature = makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey); + auto second_signature = makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey); + + auto base_tx = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 2), txBuilder(2, ts, 2)); + }; + + batches_cache_->insert(addSignatures(base_tx(), 0, first_signature)); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignatures(base_tx(), 1, second_signature)); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignatures(base_tx(), 0, second_signature)); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignatures(base_tx(), 1, first_signature)); + ASSERT_EQ(batches_cache_->availableTxsCount(), 2); +} + +TEST_F(MSTProcessingTest, StepByStepSubscribed2) { + auto base_tx = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 3)); + }; + + batches_cache_->insert(addSignaturesFromKeyPairs(base_tx(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(base_tx(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(base_tx(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 1); +} + +TEST_F(MSTProcessingTest, StepByStepNotSubscribed) { + auto get_batch = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 3), txBuilder(2, ts, 1)); + }; + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 1, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); +} + +TEST_F(MSTProcessingTest, DoublicateSignature) { + auto get_batch = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 2)); + }; + + auto key = makeKey(); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, key)); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, key)); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); +} + +TEST_F(MSTProcessingTest, DoubleTxs) { + auto get_batch = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 2)); + }; + auto get_batch_2 = [ts{iroha::time::now()}]() { + return makeTestBatch(txBuilder(1, ts, 1)); + }; + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 0); + + batches_cache_->insert(addSignaturesFromKeyPairs(get_batch(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 1); + + batches_cache_->insert( + addSignaturesFromKeyPairs(get_batch_2(), 0, makeKey())); + ASSERT_EQ(batches_cache_->availableTxsCount(), 2); +} diff --git a/test/module/irohad/multi_sig_transactions/mst_test_helpers.hpp b/test/module/irohad/ordering/mst_test_helpers.hpp similarity index 78% rename from test/module/irohad/multi_sig_transactions/mst_test_helpers.hpp rename to test/module/irohad/ordering/mst_test_helpers.hpp index a88ad96eba9..98c320b72f2 100644 --- a/test/module/irohad/multi_sig_transactions/mst_test_helpers.hpp +++ b/test/module/irohad/ordering/mst_test_helpers.hpp @@ -18,8 +18,6 @@ #include "logger/logger.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "module/shared_model/cryptography/crypto_defaults.hpp" -#include "multi_sig_transactions/mst_types.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" inline auto makeKey() { return shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); @@ -27,7 +25,8 @@ inline auto makeKey() { inline auto txBuilder( const shared_model::interface::types::CounterType &counter, - iroha::TimeType created_time = iroha::time::now(), + shared_model::interface::types::TimestampType created_time = + iroha::time::now(), shared_model::interface::types::QuorumType quorum = 3, shared_model::interface::types::AccountIdType account_id = "user@test") { return TestTransactionBuilder() @@ -99,7 +98,8 @@ inline auto makeSignature( } inline auto makeTx(const shared_model::interface::types::CounterType &counter, - iroha::TimeType created_time = iroha::time::now(), + shared_model::interface::types::TimestampType created_time = + iroha::time::now(), shared_model::crypto::Keypair keypair = makeKey(), uint8_t quorum = 3) { return std::make_shared( @@ -113,28 +113,4 @@ inline auto makeTx(const shared_model::interface::types::CounterType &counter, .finish()); } -namespace iroha { - class TestCompleter : public DefaultCompleter { - public: - explicit TestCompleter() : DefaultCompleter(std::chrono::minutes(0)) {} - - bool isCompleted(const DataType &batch) const override { - return std::all_of(batch->transactions().begin(), - batch->transactions().end(), - [](const auto &tx) { - return boost::size(tx->signatures()) >= tx->quorum(); - }); - } - - bool isExpired(const DataType &batch, - const TimeType ¤t_time) const override { - return std::any_of(batch->transactions().begin(), - batch->transactions().end(), - [¤t_time](const auto &tx) { - return tx->createdTime() < current_time; - }); - } - }; -} // namespace iroha - #endif // IROHA_MST_TEST_HELPERS_HPP diff --git a/test/module/irohad/ordering/on_demand_connection_manager_test.cpp b/test/module/irohad/ordering/on_demand_connection_manager_test.cpp index 6080408a757..1f583dd5f6f 100644 --- a/test/module/irohad/ordering/on_demand_connection_manager_test.cpp +++ b/test/module/irohad/ordering/on_demand_connection_manager_test.cpp @@ -14,6 +14,7 @@ #include "module/irohad/ordering/ordering_mocks.hpp" #include "module/shared_model/interface_mocks.hpp" #include "ordering/impl/on_demand_common.hpp" +#include "ordering/ordering_types.hpp" using namespace iroha; using namespace iroha::ordering; @@ -22,6 +23,7 @@ using namespace iroha::ordering::transport; using ::testing::ByMove; using ::testing::Ref; using ::testing::Return; +using ::testing::ReturnRefOfCopy; /** * Create unique_ptr with MockOdOsNotification, save to var, and return it @@ -36,19 +38,29 @@ struct OnDemandConnectionManagerTest : public ::testing::Test { void SetUp() override { factory = std::make_shared(); - auto set = [this](auto &field, auto &ptr) { - field = std::make_shared(); + auto set = [this](size_t ix, auto &field, auto &ptr) { + auto peer = std::make_shared(); + EXPECT_CALL(*peer, pubkey()) + .WillRepeatedly(ReturnRefOfCopy( + iroha::bytestringToHexstring(std::string(32, '0')))); + EXPECT_CALL(*peer, address()) + .WillRepeatedly(testing::ReturnRefOfCopy(std::string{"address"} + + std::to_string(ix))); + field = peer; EXPECT_CALL(*factory, create(Ref(*field))) .WillRepeatedly(CreateAndSave(&ptr)); }; + size_t ix = 0; for (auto &&pair : boost::combine(cpeers.peers, connections)) { - set(boost::get<0>(pair), boost::get<1>(pair)); + set(ix++, boost::get<0>(pair), boost::get<1>(pair)); } + std::vector> all_peers; + for (auto const &p : cpeers.peers) all_peers.push_back(p); manager = std::make_shared( - factory, cpeers, getTestLogger("OsConnectionManager")); + factory, cpeers, all_peers, getTestLogger("OsConnectionManager")); } OnDemandConnectionManager::CurrentPeers cpeers; @@ -96,9 +108,15 @@ TEST_F(OnDemandConnectionManagerTest, onBatches) { */ TEST_F(OnDemandConnectionManagerTest, onRequestProposal) { consensus::Round round{}; + auto proposal = std::make_shared(); + auto p = std::make_optional(std::make_pair( + std::shared_ptr{proposal}, + ordering::BloomFilter256{})); + + EXPECT_CALL(*proposal, toString()).Times(1); EXPECT_CALL(*connections[OnDemandConnectionManager::kIssuer], - onRequestProposal(round)) + onRequestProposal(round, p)) .Times(1); - manager->onRequestProposal(round); + manager->onRequestProposal(round, p); } diff --git a/test/module/irohad/ordering/on_demand_ordering_gate_test.cpp b/test/module/irohad/ordering/on_demand_ordering_gate_test.cpp index 1838a12e566..fe0ac51d21a 100644 --- a/test/module/irohad/ordering/on_demand_ordering_gate_test.cpp +++ b/test/module/irohad/ordering/on_demand_ordering_gate_test.cpp @@ -59,6 +59,7 @@ class OnDemandOrderingGateTest : public ::testing::Test { 1000, getTestLogger("OrderingGate"), false); + ordering_gate->initialize(); auto peer = makePeer("127.0.0.1", "111"_hex_pubkey); ledger_state = std::make_shared( @@ -108,9 +109,7 @@ TEST_F(OnDemandOrderingGateTest, propagateBatch) { auto batch = createMockBatchWithHash(hash1); OdOsNotification::CollectionType collection{batch}; - EXPECT_CALL(*notification, onBatches(collection)).Times(1); - EXPECT_CALL(*ordering_service, onBatches(collection)).Times(1); - + EXPECT_CALL(*notification, onBatchesToWholeNetwork(collection)).Times(1); ordering_gate->propagateBatch(batch); } @@ -135,7 +134,18 @@ TEST_F(OnDemandOrderingGateTest, BlockEvent) { EXPECT_CALL(*ordering_service, forCachedBatches(_)) .WillOnce(InvokeArgument<0>(transactions)); - EXPECT_CALL(*notification, onRequestProposal(round)).Times(1); + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); + + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); + + std::optional< + std::pair, + ordering::BloomFilter256>> + p{}; + EXPECT_CALL(*notification, onRequestProposal(round, p)).Times(1); auto event = RoundSwitch(round, ledger_state); @@ -162,8 +172,19 @@ TEST_F(OnDemandOrderingGateTest, EmptyEvent) { std::vector{generateTx()}) .build()); + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); EXPECT_CALL(*ordering_service, onCollaborationOutcome(round)).Times(1); - EXPECT_CALL(*notification, onRequestProposal(round)).Times(1); + + std::optional< + std::pair, + ordering::BloomFilter256>> + p{}; + EXPECT_CALL(*notification, onRequestProposal(round, p)).Times(1); + + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); auto event = RoundSwitch(round, ledger_state); @@ -185,8 +206,18 @@ TEST_F(OnDemandOrderingGateTest, BlockEventNoProposal) { std::optional> proposal; + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); EXPECT_CALL(*ordering_service, onCollaborationOutcome(round)).Times(1); - EXPECT_CALL(*notification, onRequestProposal(round)).Times(1); + + std::optional< + std::pair, + ordering::BloomFilter256>> + p{}; + EXPECT_CALL(*notification, onRequestProposal(round, p)).Times(1); ordering_gate->processRoundSwitch(RoundSwitch(round, ledger_state)); @@ -206,8 +237,18 @@ TEST_F(OnDemandOrderingGateTest, EmptyEventNoProposal) { std::optional> proposal; + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); EXPECT_CALL(*ordering_service, onCollaborationOutcome(round)).Times(1); - EXPECT_CALL(*notification, onRequestProposal(round)).Times(1); + + std::optional< + std::pair, + ordering::BloomFilter256>> + p{}; + EXPECT_CALL(*notification, onRequestProposal(round, p)).Times(1); ordering_gate->processRoundSwitch(RoundSwitch(round, ledger_state)); @@ -239,8 +280,18 @@ TEST_F(OnDemandOrderingGateTest, ReplayedTransactionInProposal) { std::move(proposal))); // set expectations for ordering service + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); EXPECT_CALL(*ordering_service, onCollaborationOutcome(round)).Times(1); - EXPECT_CALL(*notification, onRequestProposal(round)).Times(1); + + std::optional< + std::pair, + ordering::BloomFilter256>> + p{}; + EXPECT_CALL(*notification, onRequestProposal(round, p)).Times(1); EXPECT_CALL(*tx_cache, check(testing::Matcher(_))) .WillOnce(Return(boost::make_optional( @@ -293,8 +344,18 @@ TEST_F(OnDemandOrderingGateTest, RepeatedTransactionInProposal) { std::move(proposal))); // set expectations for ordering service + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); EXPECT_CALL(*ordering_service, onCollaborationOutcome(round)).Times(1); - EXPECT_CALL(*notification, onRequestProposal(round)).Times(1); + + std::optional< + std::pair, + ordering::BloomFilter256>> + p{}; + EXPECT_CALL(*notification, onRequestProposal(round, p)).Times(1); EXPECT_CALL(*tx_cache, check(testing::Matcher(_))) .WillRepeatedly(Return(boost::make_optional( @@ -338,6 +399,11 @@ TEST_F(OnDemandOrderingGateTest, PopNonEmptyBatchesFromTheCache) { OnDemandOrderingService::BatchesSetType collection{batch1, batch2}; OnDemandOrderingService::BatchesSetType collection2{batch1, batch2}; + EXPECT_CALL(*notification, getRequestDelay()) + .WillOnce(Return(std::chrono::milliseconds(1))); + EXPECT_CALL(*ordering_service, + waitForLocalProposal(round, std::chrono::milliseconds(1))) + .WillOnce(Return(std::nullopt)); EXPECT_CALL(*ordering_service, forCachedBatches(_)) .WillOnce(InvokeArgument<0>(collection2)); diff --git a/test/module/irohad/ordering/on_demand_os_client_grpc_test.cpp b/test/module/irohad/ordering/on_demand_os_client_grpc_test.cpp index 0dde723b906..e9db758c8cb 100644 --- a/test/module/irohad/ordering/on_demand_os_client_grpc_test.cpp +++ b/test/module/irohad/ordering/on_demand_os_client_grpc_test.cpp @@ -42,7 +42,14 @@ class OnDemandOsClientGrpcTest : public ::testing::Test { using MockProtoProposalValidator = shared_model::validation::MockValidator; + void TearDown() override { + proposals_subscription_->unsubscribe(); + proposals_subscription_.reset(); + subscription->dispose(); + } + void SetUp() override { + subscription = iroha::getSubscription(); auto ustub = std::make_unique(); stub = ustub.get(); auto validator = std::make_unique(); @@ -64,15 +71,20 @@ class OnDemandOsClientGrpcTest : public ::testing::Test { std::shared_ptr pk[] = {std::make_shared("123")}; exec_keeper->syncronize(&pk[0], &pk[1]); - client = std::make_shared( - std::move(ustub), - proposal_factory, - [&] { return timepoint; }, - timeout, - getTestLogger("OdOsClientGrpc"), - [this](ProposalEvent event) { received_event = event; }, - exec_keeper, - "123"); + proposals_subscription_ = + SubscriberCreator::template create< + EventTypes::kOnProposalResponse>( + iroha::SubscriptionEngineHandlers::kYac, + [this](auto, auto event) { received_event = event; }); + + client = + std::make_shared(std::move(ustub), + proposal_factory, + [&] { return timepoint; }, + timeout, + getTestLogger("OdOsClientGrpc"), + exec_keeper, + "123"); } proto::MockOnDemandOrderingStub *stub; @@ -81,6 +93,8 @@ class OnDemandOsClientGrpcTest : public ::testing::Test { std::shared_ptr client; consensus::Round round{1, 2}; ProposalEvent received_event; + std::shared_ptr> proposals_subscription_; + std::shared_ptr subscription; MockProposalValidator *proposal_validator; MockProtoProposalValidator *proto_proposal_validator; @@ -165,13 +179,14 @@ TEST_F(OnDemandOsClientGrpcTest, onRequestProposal) { ->mutable_payload() ->mutable_reduced_payload() ->set_creator_account_id(creator); + response.set_proposal_hash("hash_1"); EXPECT_CALL(*stub, RequestProposal(_, _, _)) .WillOnce(DoAll(SaveClientContextDeadline(&deadline), SaveArg<1>(&request), SetArgPointee<2>(response), Return(grpc::Status::OK))); - client->onRequestProposal(round); + client->onRequestProposal(round, std::nullopt); ASSERT_EQ(timepoint + timeout, deadline); ASSERT_EQ(request.round().block_round(), round.block_round); @@ -199,7 +214,7 @@ TEST_F(OnDemandOsClientGrpcTest, onRequestProposalNone) { SetArgPointee<2>(response), Return(grpc::Status::OK))); - client->onRequestProposal(round); + client->onRequestProposal(round, std::nullopt); ASSERT_EQ(timepoint + timeout, deadline); ASSERT_EQ(request.round().block_round(), round.block_round); diff --git a/test/module/irohad/ordering/on_demand_os_server_grpc_test.cpp b/test/module/irohad/ordering/on_demand_os_server_grpc_test.cpp index 2de293dba74..4b728f85e2e 100644 --- a/test/module/irohad/ordering/on_demand_os_server_grpc_test.cpp +++ b/test/module/irohad/ordering/on_demand_os_server_grpc_test.cpp @@ -7,15 +7,22 @@ #include #include +#include + #include "backend/protobuf/proposal.hpp" +#include "backend/protobuf/proto_proposal_factory.hpp" #include "backend/protobuf/proto_transport_factory.hpp" #include "backend/protobuf/transaction.hpp" #include "framework/test_logger.hpp" #include "interfaces/iroha_internal/transaction_batch_impl.hpp" #include "interfaces/iroha_internal/transaction_batch_parser_impl.hpp" +#include "module/irohad/common/validators_config.hpp" +#include "module/irohad/ordering/mst_test_helpers.hpp" #include "module/irohad/ordering/ordering_mocks.hpp" #include "module/shared_model/interface/mock_transaction_batch_factory.hpp" #include "module/shared_model/validators/validators.hpp" +#include "validators/default_validator.hpp" +#include "validators/field_validator.hpp" using namespace iroha; using namespace iroha::ordering; @@ -130,11 +137,13 @@ TEST_F(OnDemandOsServerGrpcTest, RequestProposal) { ->mutable_reduced_payload() ->set_creator_account_id(creator); - std::shared_ptr iproposal( - std::make_shared(proposal)); - EXPECT_CALL(*notification, onRequestProposal(round)) - .WillOnce(Return(ByMove(std::move(iproposal)))); - EXPECT_CALL(*notification, hasEnoughBatchesInCache()).WillOnce(Return(true)); + auto p = std::make_pair( + std::shared_ptr( + std::make_shared(proposal)), + ordering::BloomFilter256{}); + std::chrono::milliseconds delay(0); + EXPECT_CALL(*notification, waitForLocalProposal(round, delay)) + .WillOnce(Return(ByMove(std::move(p)))); grpc::ServerContext context; server->RequestProposal(&context, &request, &response); @@ -160,12 +169,167 @@ TEST_F(OnDemandOsServerGrpcTest, RequestProposalNone) { request.mutable_round()->set_block_round(round.block_round); request.mutable_round()->set_reject_round(round.reject_round); proto::ProposalResponse response; - EXPECT_CALL(*notification, onRequestProposal(round)) + std::chrono::milliseconds delay(0); + EXPECT_CALL(*notification, waitForLocalProposal(round, delay)) .WillOnce(Return(ByMove(std::move(std::nullopt)))); - EXPECT_CALL(*notification, hasEnoughBatchesInCache()).WillOnce(Return(false)); grpc::ServerContext context; server->RequestProposal(&context, &request, &response); ASSERT_FALSE(response.has_proposal()); } + +void add2Proposal( + iroha::protocol::Proposal &to, + ordering::BloomFilter256 &bf, + std::shared_ptr const &batch) { + bf.set(batch->reducedHash()); + for (auto const &transaction : batch->transactions()) + *to.add_transactions() = + static_cast(transaction.get()) + ->getTransport(); +} + +std::tuple makeProposal( + size_t batchCount, + std::vector &hashes, + shared_model::interface::types::TimestampType ts) { + auto result = + std::make_tuple(iroha::protocol::Proposal{}, ordering::BloomFilter256{}); + for (size_t ix = 1; ix <= batchCount; ++ix) { + auto batch = makeTestBatch(txBuilder(ix, ts + ix, 1)); + hashes.emplace_back(batch->reducedHash()); + add2Proposal(std::get<0>(result), std::get<1>(result), batch); + } + return result; +} + +TEST_F(OnDemandOsServerGrpcTest, DiffCalculation_wholeIntersection) { + shared_model::proto::ProtoProposalFactory< + shared_model::validation::DefaultProposalValidator> + factory(iroha::test::kTestsValidatorsConfig); + std::vector hashes; + auto proposal = makeProposal(2, hashes, 10); + + proto::ProposalRequest request; + request.mutable_round()->set_block_round(round.block_round); + request.mutable_round()->set_reject_round(round.reject_round); + request.set_bloom_filter(std::get<1>(proposal).load().data(), + std::get<1>(proposal).load().size()); + + proto::ProposalResponse response; + std::chrono::milliseconds delay(0); + + auto result = std::make_optional( + std::make_pair(std::shared_ptr( + std::make_shared( + std::move(std::get<0>(proposal)))), + std::get<1>(proposal))); + + result->first->mut_transactions()[0].storeBatchHash(hashes[0]); + result->first->mut_transactions()[1].storeBatchHash(hashes[1]); + + EXPECT_CALL(*notification, waitForLocalProposal(round, delay)) + .WillOnce(Return(ByMove(std::move(result)))); + + grpc::ServerContext context; + server->RequestProposal(&context, &request, &response); + + ASSERT_TRUE(response.has_proposal()); + ASSERT_TRUE(response.proposal().transactions().empty()); +} + +TEST_F(OnDemandOsServerGrpcTest, DiffCalculation_noIntersection) { + shared_model::proto::ProtoProposalFactory< + shared_model::validation::DefaultProposalValidator> + factory(iroha::test::kTestsValidatorsConfig); + std::vector hashes_1; + auto proposal_pack_1 = makeProposal(2, hashes_1, 10); + + std::vector hashes_2; + auto proposal_pack_2 = makeProposal(2, hashes_2, 100); + + proto::ProposalRequest request; + request.mutable_round()->set_block_round(round.block_round); + request.mutable_round()->set_reject_round(round.reject_round); + request.set_bloom_filter(std::get<1>(proposal_pack_1).load().data(), + std::get<1>(proposal_pack_1).load().size()); + + proto::ProposalResponse response; + std::chrono::milliseconds delay(0); + + auto result = std::make_optional( + std::make_pair(std::shared_ptr( + std::make_shared( + std::get<0>(proposal_pack_2))), + std::get<1>(proposal_pack_2))); + + result->first->mut_transactions()[0].storeBatchHash(hashes_2[0]); + result->first->mut_transactions()[1].storeBatchHash(hashes_2[1]); + + EXPECT_CALL(*notification, waitForLocalProposal(round, delay)) + .WillOnce(Return(ByMove(result))); + + grpc::ServerContext context; + server->RequestProposal(&context, &request, &response); + + ASSERT_TRUE(response.has_proposal()); + assert(response.proposal().transactions().size() == 2); + ASSERT_TRUE(response.proposal().transactions().size() == 2); + + ASSERT_TRUE( + shared_model::proto::Transaction(response.proposal().transactions()[0]) + == shared_model::proto::Transaction( + std::get<0>(proposal_pack_2).transactions()[0])); + ASSERT_TRUE( + shared_model::proto::Transaction(response.proposal().transactions()[1]) + == shared_model::proto::Transaction( + std::get<0>(proposal_pack_2).transactions()[1])); +} + +TEST_F(OnDemandOsServerGrpcTest, DiffCalculation_partIntersection) { + shared_model::proto::ProtoProposalFactory< + shared_model::validation::DefaultProposalValidator> + factory(iroha::test::kTestsValidatorsConfig); + std::vector hashes; + auto proposal_pack = makeProposal(2, hashes, 10); + + proto::ProposalRequest request; + request.mutable_round()->set_block_round(round.block_round); + request.mutable_round()->set_reject_round(round.reject_round); + request.set_bloom_filter(std::get<1>(proposal_pack).load().data(), + std::get<1>(proposal_pack).load().size()); + + auto addition_batch = makeTestBatch(txBuilder(3, 100, 1)); + add2Proposal( + std::get<0>(proposal_pack), std::get<1>(proposal_pack), addition_batch); + + proto::ProposalResponse response; + std::chrono::milliseconds delay(0); + + auto result = std::make_optional( + std::make_pair(std::shared_ptr( + std::make_shared( + std::get<0>(proposal_pack))), + std::get<1>(proposal_pack))); + + result->first->mut_transactions()[0].storeBatchHash(hashes[0]); + result->first->mut_transactions()[1].storeBatchHash(hashes[1]); + result->first->mut_transactions()[2].storeBatchHash( + addition_batch->reducedHash()); + + EXPECT_CALL(*notification, waitForLocalProposal(round, delay)) + .WillOnce(Return(ByMove(result))); + + grpc::ServerContext context; + server->RequestProposal(&context, &request, &response); + + ASSERT_TRUE(response.has_proposal()); + assert(response.proposal().transactions().size() == 1); + ASSERT_TRUE(response.proposal().transactions().size() == 1); + + ASSERT_TRUE( + shared_model::proto::Transaction(response.proposal().transactions()[0]) + == shared_model::proto::Transaction( + std::get<0>(proposal_pack).transactions()[2])); +} diff --git a/test/module/irohad/ordering/on_demand_os_test.cpp b/test/module/irohad/ordering/on_demand_os_test.cpp index d65523ac3be..999eb775152 100644 --- a/test/module/irohad/ordering/on_demand_os_test.cpp +++ b/test/module/irohad/ordering/on_demand_os_test.cpp @@ -155,7 +155,7 @@ TEST_F(OnDemandOsTest, OverflowRound) { ASSERT_TRUE(os->onRequestProposal(target_round)); ASSERT_EQ(transaction_limit, - (*os->onRequestProposal(target_round))->transactions().size()); + os->onRequestProposal(target_round)->first->transactions().size()); } /** @@ -302,7 +302,7 @@ TEST_F(OnDemandOsTest, SeveralTransactionsOneCommited) { os->onCollaborationOutcome(commit_round); auto proposal = os->onRequestProposal(target_round); - const auto &txs = proposal->get()->transactions(); + const auto &txs = proposal->first->transactions(); auto &batch2_tx = *batch2.transactions().at(0); EXPECT_TRUE(proposal); @@ -326,7 +326,7 @@ TEST_F(OnDemandOsTest, DuplicateTxTest) { os->onCollaborationOutcome(commit_round); auto proposal = os->onRequestProposal(target_round); - ASSERT_EQ(1, boost::size((*proposal)->transactions())); + ASSERT_EQ(1, boost::size(proposal->first->transactions())); } /** @@ -348,10 +348,10 @@ TEST_F(OnDemandOsTest, RejectCommit) { auto proposal = os->onRequestProposal( {initial_round.block_round, initial_round.reject_round + 3}); - ASSERT_EQ(2, boost::size((*proposal)->transactions())); + ASSERT_EQ(2, boost::size(proposal->first->transactions())); proposal = os->onRequestProposal(commit_round); - ASSERT_EQ(2, boost::size((*proposal)->transactions())); + ASSERT_EQ(2, boost::size(proposal->first->transactions())); } /** diff --git a/test/module/irohad/ordering/ordering_mocks.hpp b/test/module/irohad/ordering/ordering_mocks.hpp index 2af8aeb117f..cd5fc9b0b64 100644 --- a/test/module/irohad/ordering/ordering_mocks.hpp +++ b/test/module/irohad/ordering/ordering_mocks.hpp @@ -20,6 +20,7 @@ namespace iroha::ordering::transport { create, (const shared_model::interface::Peer &), (override)); + MOCK_CONST_METHOD0(getRequestDelay, std::chrono::milliseconds()); }; } // namespace iroha::ordering::transport @@ -27,7 +28,7 @@ namespace iroha::ordering { struct MockOnDemandOrderingService : public OnDemandOrderingService { MOCK_METHOD(void, onBatches, (CollectionType), (override)); - MOCK_METHOD((std::optional>), + MOCK_METHOD(PackedProposalData, onRequestProposal, (consensus::Round), (override)); @@ -42,6 +43,10 @@ namespace iroha::ordering { MOCK_METHOD(bool, hasEnoughBatchesInCache, (), (const, override)); MOCK_METHOD(bool, hasProposal, (consensus::Round), (const, override)); MOCK_METHOD(void, processReceivedProposal, (CollectionType), (override)); + + MOCK_METHOD2(waitForLocalProposal, + PackedProposalData(consensus::Round const &, + std::chrono::milliseconds const &)); }; } // namespace iroha::ordering diff --git a/test/module/irohad/pending_txs_storage/old_pending_txs_storage_test.cpp b/test/module/irohad/pending_txs_storage/old_pending_txs_storage_test.cpp index 009d91b5da1..3dc06bbdf98 100644 --- a/test/module/irohad/pending_txs_storage/old_pending_txs_storage_test.cpp +++ b/test/module/irohad/pending_txs_storage/old_pending_txs_storage_test.cpp @@ -7,10 +7,68 @@ #include "datetime/time.hpp" #include "framework/crypto_literals.hpp" #include "framework/test_logger.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" #include "pending_txs_storage/impl/pending_txs_storage_impl.hpp" +#include "builders/protobuf/transaction.hpp" +#include "datetime/time.hpp" +#include "framework/batch_helper.hpp" +#include "framework/test_logger.hpp" +#include "interfaces/common_objects/string_view_types.hpp" +#include "interfaces/common_objects/types.hpp" +#include "logger/logger.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "module/shared_model/cryptography/crypto_defaults.hpp" + +template +auto makeTestBatch(TxBuilders... builders) { + return framework::batch::makeTestBatch(builders...); +} + +inline auto makeSignature( + shared_model::interface::types::SignedHexStringView sign, + shared_model::interface::types::PublicKeyHexStringView public_key) { + return std::make_pair(std::string{std::string_view{sign}}, + std::string{std::string_view{public_key}}); +} + +inline auto txBuilder( + const shared_model::interface::types::CounterType &counter, + shared_model::interface::types::TimestampType created_time = + iroha::time::now(), + shared_model::interface::types::QuorumType quorum = 3, + shared_model::interface::types::AccountIdType account_id = "user@test") { + return TestTransactionBuilder() + .createdTime(created_time) + .creatorAccountId(account_id) + .setAccountQuorum(account_id, counter) + .quorum(quorum); +} + +template +auto addSignatures(Batch &&batch, int tx_number, Signatures... signatures) { + static logger::LoggerPtr log_ = getTestLogger("addSignatures"); + + auto insert_signatures = [&](auto &&sig_pair) { + batch->addSignature( + tx_number, + shared_model::interface::types::SignedHexStringView{sig_pair.first}, + shared_model::interface::types::PublicKeyHexStringView{ + sig_pair.second}); + }; + + // pack expansion trick: + // an ellipsis operator applies insert_signatures to each signature, operator + // comma returns the rightmost argument, which is 0 + int temp[] = { + (insert_signatures(std::forward(signatures)), 0)...}; + // use unused variable + (void)temp; + + log_->info("Number of signatures was inserted {}", + boost::size(batch->transactions().at(tx_number)->signatures())); + return std::forward(batch); +} + class OldPendingTxsStorageFixture : public ::testing::Test { public: using Batch = shared_model::interface::TransactionBatch; @@ -33,36 +91,11 @@ class OldPendingTxsStorageFixture : public ::testing::Test { std::shared_ptr storage_ = std::make_shared(); - std::shared_ptr completer_ = - std::make_shared(std::chrono::minutes(0)); logger::LoggerPtr mst_state_log_{getTestLogger("MstState")}; logger::LoggerPtr log_{getTestLogger("OldPendingTxsStorageFixture")}; }; -/** - * Test that checks that fixture common preparation procedures can be done - * successfully. - * @given empty MST state - * @when two mst transactions generated as batch - * @then the transactions can be added to MST state successfully - */ -TEST_F(OldPendingTxsStorageFixture, FixtureSelfCheck) { - auto state = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); - - auto transactions = - addSignatures(makeTestBatch(txBuilder(1, getUniqueTime()), - txBuilder(1, getUniqueTime())), - 0, - makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - - *state += transactions; - ASSERT_EQ(state->getBatches().size(), 1) << "Failed to prepare MST state"; - ASSERT_EQ((*state->getBatches().begin())->transactions().size(), 2) - << "Test batch contains wrong amount of transactions"; -} - /** * Transactions insertion works in PendingTxsStorage * @given Batch of two transactions and storage @@ -70,16 +103,13 @@ TEST_F(OldPendingTxsStorageFixture, FixtureSelfCheck) { * @then list of pending transactions can be received for all batch creators */ TEST_F(OldPendingTxsStorageFixture, InsertionTest) { - auto state = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); auto transactions = addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), txBuilder(2, getUniqueTime(), 2, "bob@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state += transactions; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto pending = storage_->getPendingTransactions(creator); ASSERT_EQ(pending.size(), 2) @@ -102,21 +132,14 @@ TEST_F(OldPendingTxsStorageFixture, InsertionTest) { * @then pending transactions response is also updated */ TEST_F(OldPendingTxsStorageFixture, SignaturesUpdate) { - auto state1 = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); - auto state2 = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); auto transactions = addSignatures( makeTestBatch(txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state1 += transactions; + storage_->updatedBatchesHandler(transactions); transactions = addSignatures( transactions, 0, makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey)); - *state2 += transactions; - - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); + storage_->updatedBatchesHandler(transactions); auto pending = storage_->getPendingTransactions("alice@iroha"); ASSERT_EQ(pending.size(), 1); ASSERT_EQ(boost::size(pending.front()->signatures()), 2); @@ -129,8 +152,6 @@ TEST_F(OldPendingTxsStorageFixture, SignaturesUpdate) { * @then users receives correct responses */ TEST_F(OldPendingTxsStorageFixture, SeveralBatches) { - auto state = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); auto batch1 = addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), txBuilder(2, getUniqueTime(), 2, "bob@iroha")), @@ -145,11 +166,10 @@ TEST_F(OldPendingTxsStorageFixture, SeveralBatches) { makeTestBatch(txBuilder(2, getUniqueTime(), 2, "bob@iroha")), 0, makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey)); - *state += batch1; - *state += batch2; - *state += batch3; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); + storage_->updatedBatchesHandler(batch3); auto alice_pending = storage_->getPendingTransactions("alice@iroha"); ASSERT_EQ(alice_pending.size(), 4); @@ -164,25 +184,19 @@ TEST_F(OldPendingTxsStorageFixture, SeveralBatches) { * @then updates don't overwrite the whole storage state */ TEST_F(OldPendingTxsStorageFixture, SeparateBatchesDoNotOverwriteStorage) { - auto state1 = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); auto batch1 = addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), txBuilder(2, getUniqueTime(), 2, "bob@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state1 += batch1; - auto state2 = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); auto batch2 = addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state2 += batch2; - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); auto alice_pending = storage_->getPendingTransactions("alice@iroha"); ASSERT_EQ(alice_pending.size(), 4); @@ -198,16 +212,13 @@ TEST_F(OldPendingTxsStorageFixture, SeparateBatchesDoNotOverwriteStorage) { * @then storage removes the batch */ TEST_F(OldPendingTxsStorageFixture, PreparedBatch) { - auto state = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); std::shared_ptr batch = addSignatures( makeTestBatch(txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state += batch; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(batch); batch = addSignatures(batch, 0, makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey), @@ -224,16 +235,13 @@ TEST_F(OldPendingTxsStorageFixture, PreparedBatch) { * @then storage removes the batch */ TEST_F(OldPendingTxsStorageFixture, ExpiredBatch) { - auto state = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); std::shared_ptr batch = addSignatures( makeTestBatch(txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state += batch; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(batch); storage_->removeBatch(batch); auto pending = storage_->getPendingTransactions("alice@iroha"); ASSERT_EQ(pending.size(), 0); diff --git a/test/module/irohad/pending_txs_storage/pending_txs_storage_mock.hpp b/test/module/irohad/pending_txs_storage/pending_txs_storage_mock.hpp index b03e0dca835..01ba9a9a36c 100644 --- a/test/module/irohad/pending_txs_storage/pending_txs_storage_mock.hpp +++ b/test/module/irohad/pending_txs_storage/pending_txs_storage_mock.hpp @@ -27,17 +27,19 @@ namespace iroha { const std::optional &first_tx_time, const std::optional - &last_tx_time), (const)); + &last_tx_time), + (const)); MOCK_METHOD1(insertPresenceCache, void(std::shared_ptr &cache)); MOCK_METHOD(void, removeTransaction, (shared_model::interface::types::HashType const &), (override)); - MOCK_METHOD(void, - updatedBatchesHandler, - (std::shared_ptr const &), - (override)); + MOCK_METHOD( + void, + updatedBatchesHandler, + (std::shared_ptr const &), + (override)); MOCK_METHOD( void, removeBatch, diff --git a/test/module/irohad/pending_txs_storage/pending_txs_storage_test.cpp b/test/module/irohad/pending_txs_storage/pending_txs_storage_test.cpp index 7c37f143f77..84f2bbd01f5 100644 --- a/test/module/irohad/pending_txs_storage/pending_txs_storage_test.cpp +++ b/test/module/irohad/pending_txs_storage/pending_txs_storage_test.cpp @@ -10,10 +10,68 @@ #include "framework/result_gtest_checkers.hpp" #include "framework/test_logger.hpp" #include "module/irohad/ametsuchi/mock_tx_presence_cache.hpp" -#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" -#include "multi_sig_transactions/state/mst_state.hpp" #include "pending_txs_storage/impl/pending_txs_storage_impl.hpp" +#include "builders/protobuf/transaction.hpp" +#include "datetime/time.hpp" +#include "framework/batch_helper.hpp" +#include "framework/test_logger.hpp" +#include "interfaces/common_objects/string_view_types.hpp" +#include "interfaces/common_objects/types.hpp" +#include "logger/logger.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "module/shared_model/cryptography/crypto_defaults.hpp" + +template +auto makeTestBatch(TxBuilders... builders) { + return framework::batch::makeTestBatch(builders...); +} + +inline auto makeSignature( + shared_model::interface::types::SignedHexStringView sign, + shared_model::interface::types::PublicKeyHexStringView public_key) { + return std::make_pair(std::string{std::string_view{sign}}, + std::string{std::string_view{public_key}}); +} + +inline auto txBuilder( + const shared_model::interface::types::CounterType &counter, + shared_model::interface::types::TimestampType created_time = + iroha::time::now(), + shared_model::interface::types::QuorumType quorum = 3, + shared_model::interface::types::AccountIdType account_id = "user@test") { + return TestTransactionBuilder() + .createdTime(created_time) + .creatorAccountId(account_id) + .setAccountQuorum(account_id, counter) + .quorum(quorum); +} + +template +auto addSignatures(Batch &&batch, int tx_number, Signatures... signatures) { + static logger::LoggerPtr log_ = getTestLogger("addSignatures"); + + auto insert_signatures = [&](auto &&sig_pair) { + batch->addSignature( + tx_number, + shared_model::interface::types::SignedHexStringView{sig_pair.first}, + shared_model::interface::types::PublicKeyHexStringView{ + sig_pair.second}); + }; + + // pack expansion trick: + // an ellipsis operator applies insert_signatures to each signature, operator + // comma returns the rightmost argument, which is 0 + int temp[] = { + (insert_signatures(std::forward(signatures)), 0)...}; + // use unused variable + (void)temp; + + log_->info("Number of signatures was inserted {}", + boost::size(batch->transactions().at(tx_number)->signatures())); + return std::forward(batch); +} + class PendingTxsStorageFixture : public ::testing::Test { public: using Batch = shared_model::interface::TransactionBatch; @@ -38,11 +96,6 @@ class PendingTxsStorageFixture : public ::testing::Test { } } - auto emptyState() { - return std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); - } - auto twoTransactionsBatch() { return addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), @@ -87,29 +140,11 @@ class PendingTxsStorageFixture : public ::testing::Test { std::shared_ptr presence_cache_; std::shared_ptr storage_; - std::shared_ptr completer_ = - std::make_shared(std::chrono::minutes(0)); logger::LoggerPtr mst_state_log_{getTestLogger("MstState")}; logger::LoggerPtr log_{getTestLogger("PendingTxsStorageFixture")}; }; -/** - * Test that checks that fixture common preparation procedures can be done - * successfully. - * @given empty MST state - * @when two mst transactions generated as batch - * @then the transactions can be added to MST state successfully - */ -TEST_F(PendingTxsStorageFixture, FixtureSelfCheck) { - auto state = emptyState(); - auto transactions = twoTransactionsBatch(); - *state += transactions; - ASSERT_EQ(state->getBatches().size(), 1) << "Failed to prepare MST state"; - ASSERT_EQ((*state->getBatches().begin())->transactions().size(), 2) - << "Test batch contains wrong amount of transactions"; -} - /** * Transactions insertion works in PendingTxsStorage * @given Batch of two transactions and storage @@ -117,9 +152,7 @@ TEST_F(PendingTxsStorageFixture, FixtureSelfCheck) { * @then list of pending transactions can be received for all batch creators */ TEST_F(PendingTxsStorageFixture, InsertionTest) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(); - *state += transactions; const auto kPageSize = 100u; Response expected; @@ -128,7 +161,7 @@ TEST_F(PendingTxsStorageFixture, InsertionTest) { transactions->transactions().end()); expected.all_transactions_size = transactions->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto pending = storage_->getPendingTransactions(creator, kPageSize, std::nullopt); @@ -144,40 +177,38 @@ TEST_F(PendingTxsStorageFixture, InsertionTest) { * @then list of pending transactions beetwen two timestamps can be obtained */ TEST_F(PendingTxsStorageFixture, TxPaginationTestFirsTimeLastTimeSpecified) { - auto state = emptyState(); auto first_time = 1000001; auto transactions = twoTransactionsBatch(1000010, 1000015); auto last_time = 1000020; - *state += transactions; auto transactions1 = twoTransactionsBatch(1000025, 1000030); - *state += transactions1; const auto kPageSize = 100u; Response expected; expected.transactions.insert(expected.transactions.end(), transactions->transactions().begin(), transactions->transactions().end()); expected.all_transactions_size = transactions->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); + storage_->updatedBatchesHandler(transactions1); const auto &creator = "alice@iroha"; - auto pending = storage_->getPendingTransactions(creator, kPageSize, std::nullopt, first_time, last_time); + auto pending = storage_->getPendingTransactions( + creator, kPageSize, std::nullopt, first_time, last_time); IROHA_ASSERT_RESULT_VALUE(pending); - ASSERT_EQ(expected.all_transactions_size, pending.assumeValue().transactions.size() ); + ASSERT_EQ(expected.all_transactions_size, + pending.assumeValue().transactions.size()); } /** * Timestamp in PaginationMeta works in PendingTxsStorage * @given two batches of two transactions and storage * @when storage receives updated mst state with the batch - * @then list of pending transactions starting from specified timestamp can be obtained + * @then list of pending transactions starting from specified timestamp can be + * obtained */ TEST_F(PendingTxsStorageFixture, TxPaginationTestFirstTimeSpecified) { - auto state = emptyState(); - auto transactions = twoTransactionsBatch(1000020,1000030); - *state += transactions; + auto transactions = twoTransactionsBatch(1000020, 1000030); auto first_time = 1000040; auto transactions1 = twoTransactionsBatch(1000050, 1000060); - *state += transactions1; const auto kPageSize = 100u; Response expected; expected.transactions.insert(expected.transactions.end(), @@ -185,7 +216,8 @@ TEST_F(PendingTxsStorageFixture, TxPaginationTestFirstTimeSpecified) { transactions1->transactions().end()); expected.all_transactions_size = transactions1->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); + storage_->updatedBatchesHandler(transactions1); const auto &creator = "alice@iroha"; auto pending = storage_->getPendingTransactions( creator, kPageSize, std::nullopt, first_time); @@ -203,11 +235,8 @@ TEST_F(PendingTxsStorageFixture, TxPaginationTestFirstTimeSpecified) { * obtained */ TEST_F(PendingTxsStorageFixture, TxPaginationTestLastTimeSpecified) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(1000040, 1000050); - *state += transactions; auto transactions1 = twoTransactionsBatch(1000060, 1000070); - *state += transactions1; auto last_time = 1000080; const auto kPageSize = 100u; Response expected; @@ -217,10 +246,11 @@ TEST_F(PendingTxsStorageFixture, TxPaginationTestLastTimeSpecified) { expected.transactions.insert(expected.transactions.end(), transactions1->transactions().begin(), transactions1->transactions().end()); - expected.all_transactions_size = - transactions->transactions().size() + transactions1->transactions().size(); + expected.all_transactions_size = transactions->transactions().size() + + transactions1->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); + storage_->updatedBatchesHandler(transactions1); const auto &creator = "alice@iroha"; auto pending = storage_->getPendingTransactions( creator, kPageSize, std::nullopt, std::nullopt, last_time); @@ -237,10 +267,9 @@ TEST_F(PendingTxsStorageFixture, TxPaginationTestLastTimeSpecified) { * @then list of pending transactions up to specified timestamp can be * obtained */ -TEST_F(PendingTxsStorageFixture, TxPaginationTestFirstTimeAfterLastTransactionSpecified) { - auto state = emptyState(); +TEST_F(PendingTxsStorageFixture, + TxPaginationTestFirstTimeAfterLastTransactionSpecified) { auto transactions = twoTransactionsBatch(1000030, 1000040); - *state += transactions; auto first_time = 1000050; const auto kPageSize = 100u; Response expected; @@ -249,7 +278,7 @@ TEST_F(PendingTxsStorageFixture, TxPaginationTestFirstTimeAfterLastTransactionSp transactions->transactions().end()); expected.all_transactions_size = transactions->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); const auto &creator = "alice@iroha"; auto pending = storage_->getPendingTransactions( creator, kPageSize, std::nullopt, first_time); @@ -265,9 +294,7 @@ TEST_F(PendingTxsStorageFixture, TxPaginationTestFirstTimeAfterLastTransactionSp * @then all the transactions are correctly returned */ TEST_F(PendingTxsStorageFixture, ExactSize) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(); - *state += transactions; const auto kPageSize = transactions->transactions().size(); Response expected; @@ -276,7 +303,7 @@ TEST_F(PendingTxsStorageFixture, ExactSize) { transactions->transactions().end()); expected.all_transactions_size = transactions->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto pending = storage_->getPendingTransactions(creator, kPageSize, std::nullopt); @@ -292,13 +319,10 @@ TEST_F(PendingTxsStorageFixture, ExactSize) { * @then all the mentioned txs have to be removed from MST's pending txs storage */ TEST_F(PendingTxsStorageFixture, CompletedTransactionsAreRemoved) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(); - *state += transactions; - const auto kPageSize = transactions->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); storage_->removeBatch(transactions); Response empty_response; for (const auto &creator : {"alice@iroha", "bob@iroha"}) { @@ -317,10 +341,7 @@ TEST_F(PendingTxsStorageFixture, CompletedTransactionsAreRemoved) { * @then no transactions are returned, but all the meta is correctly set */ TEST_F(PendingTxsStorageFixture, InsufficientSize) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(); - *state += transactions; - const auto kPageSize = 1; ASSERT_NE(kPageSize, transactions->transactions().size()); Response expected; @@ -330,7 +351,7 @@ TEST_F(PendingTxsStorageFixture, InsufficientSize) { transactions->transactions().front()->hash(); expected.next_batch_info->batch_size = transactions->transactions().size(); - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto pending = storage_->getPendingTransactions(creator, kPageSize, std::nullopt); @@ -345,12 +366,8 @@ TEST_F(PendingTxsStorageFixture, InsufficientSize) { * smaller than the sum of the first and the second batches sizes. */ TEST_F(PendingTxsStorageFixture, BatchAndAHalfPageSize) { - auto state1 = emptyState(); - auto state2 = emptyState(); auto batch1 = twoTransactionsBatch(); auto batch2 = twoTransactionsBatch(); - *state1 += batch1; - *state2 += batch2; const auto kPageSize = batch1->transactions().size() + batch2->transactions().size() - 1; @@ -365,8 +382,8 @@ TEST_F(PendingTxsStorageFixture, BatchAndAHalfPageSize) { batch2->transactions().front()->hash(); expected.next_batch_info->batch_size = batch2->transactions().size(); - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto pending = storage_->getPendingTransactions(creator, kPageSize, std::nullopt); @@ -381,12 +398,8 @@ TEST_F(PendingTxsStorageFixture, BatchAndAHalfPageSize) { * transaction in the second stored batch. */ TEST_F(PendingTxsStorageFixture, StartFromTheSecondBatch) { - auto state1 = emptyState(); - auto state2 = emptyState(); auto batch1 = twoTransactionsBatch(); auto batch2 = twoTransactionsBatch(); - *state1 += batch1; - *state2 += batch2; const auto kPageSize = batch2->transactions().size(); Response expected; @@ -396,8 +409,8 @@ TEST_F(PendingTxsStorageFixture, StartFromTheSecondBatch) { expected.all_transactions_size = batch1->transactions().size() + batch2->transactions().size(); - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto pending = storage_->getPendingTransactions( creator, kPageSize, batch2->transactions().front()->hash()); @@ -413,15 +426,12 @@ TEST_F(PendingTxsStorageFixture, StartFromTheSecondBatch) { * @then an empty response is produced for the user */ TEST_F(PendingTxsStorageFixture, NoPendingBatches) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(); - *state += transactions; - const auto kThirdAccount = "clark@iroha"; const auto kPageSize = 100u; Response empty_response; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); auto pending = storage_->getPendingTransactions(kThirdAccount, kPageSize, std::nullopt); IROHA_ASSERT_RESULT_VALUE(pending); @@ -435,20 +445,16 @@ TEST_F(PendingTxsStorageFixture, NoPendingBatches) { * @then pending transactions response is also updated */ TEST_F(PendingTxsStorageFixture, SignaturesUpdate) { - auto state1 = emptyState(); - auto state2 = emptyState(); auto transactions = addSignatures( makeTestBatch(txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state1 += transactions; + storage_->updatedBatchesHandler(transactions); transactions = addSignatures( transactions, 0, makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey)); - *state2 += transactions; + storage_->updatedBatchesHandler(transactions); const auto kPageSize = 100u; - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); auto pending = storage_->getPendingTransactions("alice@iroha", kPageSize, std::nullopt); pending.match( @@ -470,7 +476,6 @@ TEST_F(PendingTxsStorageFixture, SignaturesUpdate) { * @then users receives correct responses */ TEST_F(PendingTxsStorageFixture, SeveralBatches) { - auto state = emptyState(); auto batch1 = twoTransactionsBatch(); auto batch2 = addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), @@ -481,12 +486,11 @@ TEST_F(PendingTxsStorageFixture, SeveralBatches) { makeTestBatch(txBuilder(2, getUniqueTime(), 2, "bob@iroha")), 0, makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey)); - *state += batch1; - *state += batch2; - *state += batch3; const auto kPageSize = 100u; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); + storage_->updatedBatchesHandler(batch3); auto alice_pending = storage_->getPendingTransactions("alice@iroha", kPageSize, std::nullopt); IROHA_ASSERT_RESULT_VALUE(alice_pending); @@ -505,21 +509,16 @@ TEST_F(PendingTxsStorageFixture, SeveralBatches) { * @then updates don't overwrite the whole storage state */ TEST_F(PendingTxsStorageFixture, SeparateBatchesDoNotOverwriteStorage) { - auto state1 = emptyState(); auto batch1 = twoTransactionsBatch(); - *state1 += batch1; - auto state2 = std::make_shared( - iroha::MstState::empty(mst_state_log_, completer_)); auto batch2 = addSignatures( makeTestBatch(txBuilder(2, getUniqueTime(), 2, "alice@iroha"), txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state2 += batch2; const auto kPageSize = 100u; - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); auto alice_pending = storage_->getPendingTransactions("alice@iroha", kPageSize, std::nullopt); IROHA_ASSERT_RESULT_VALUE(alice_pending); @@ -539,15 +538,13 @@ TEST_F(PendingTxsStorageFixture, SeparateBatchesDoNotOverwriteStorage) { * @then storage removes the batch */ TEST_F(PendingTxsStorageFixture, PreparedBatch) { - auto state = emptyState(); std::shared_ptr batch = addSignatures( makeTestBatch(txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state += batch; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(batch); batch = addSignatures(batch, 0, makeSignature("2"_hex_sig, "pub_key_2"_hex_pubkey), @@ -567,15 +564,13 @@ TEST_F(PendingTxsStorageFixture, PreparedBatch) { * @then storage removes the batch */ TEST_F(PendingTxsStorageFixture, ExpiredBatch) { - auto state = emptyState(); std::shared_ptr batch = addSignatures( makeTestBatch(txBuilder(3, getUniqueTime(), 3, "alice@iroha")), 0, makeSignature("1"_hex_sig, "pub_key_1"_hex_pubkey)); - *state += batch; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(batch); storage_->removeBatch(batch); const auto kPageSize = 100u; auto pending = @@ -590,13 +585,11 @@ TEST_F(PendingTxsStorageFixture, ExpiredBatch) { * @then not found error is returned by the storage */ TEST_F(PendingTxsStorageFixture, QueryingWrongBatch) { - auto state = emptyState(); auto transactions = twoTransactionsBatch(); - *state += transactions; const auto kThirdAccount = "clark@iroha"; const auto kPageSize = 100u; - storage_->updatedBatchesHandler(state); + storage_->updatedBatchesHandler(transactions); auto response = storage_->getPendingTransactions( kThirdAccount, kPageSize, transactions->transactions().front()->hash()); IROHA_ASSERT_RESULT_ERROR(response); @@ -610,12 +603,8 @@ TEST_F(PendingTxsStorageFixture, QueryingWrongBatch) { * @then the second using starting tx hash returned by the first response */ TEST_F(PendingTxsStorageFixture, QueryAllTheBatches) { - auto state1 = emptyState(); - auto state2 = emptyState(); auto batch1 = twoTransactionsBatch(); auto batch2 = twoTransactionsBatch(); - *state1 += batch1; - *state2 += batch2; auto batchSize = [](const auto &batch) { return batch->transactions().size(); @@ -643,8 +632,8 @@ TEST_F(PendingTxsStorageFixture, QueryAllTheBatches) { second_page_expected.all_transactions_size = batchSize(batch1) + batchSize(batch2); - storage_->updatedBatchesHandler(state1); - storage_->updatedBatchesHandler(state2); + storage_->updatedBatchesHandler(batch1); + storage_->updatedBatchesHandler(batch2); for (const auto &creator : {"alice@iroha", "bob@iroha"}) { auto first_page = storage_->getPendingTransactions( creator, batchSize(batch1), std::nullopt); diff --git a/test/module/irohad/torii/processor/CMakeLists.txt b/test/module/irohad/torii/processor/CMakeLists.txt index 122d28e2d10..4dc7807a0e0 100644 --- a/test/module/irohad/torii/processor/CMakeLists.txt +++ b/test/module/irohad/torii/processor/CMakeLists.txt @@ -10,6 +10,8 @@ target_link_libraries(transaction_processor_test processors shared_model_stateless_validation test_logger + shared_model_proto_backend + shared_model_interfaces_factories ) # Testing of query processor diff --git a/test/module/irohad/torii/processor/transaction_processor_test.cpp b/test/module/irohad/torii/processor/transaction_processor_test.cpp index 74c3735d84a..15075f1bd49 100644 --- a/test/module/irohad/torii/processor/transaction_processor_test.cpp +++ b/test/module/irohad/torii/processor/transaction_processor_test.cpp @@ -16,7 +16,6 @@ #include "interfaces/iroha_internal/transaction_batch.hpp" #include "interfaces/iroha_internal/transaction_sequence_factory.hpp" #include "module/irohad/common/validators_config.hpp" -#include "module/irohad/multi_sig_transactions/mst_mocks.hpp" #include "module/irohad/network/network_mocks.hpp" #include "module/irohad/torii/torii_mocks.hpp" #include "module/shared_model/builders/protobuf/proposal.hpp" @@ -40,12 +39,10 @@ class TransactionProcessorTest : public ::testing::Test { public: void SetUp() override { pcs = std::make_shared(); - mst = std::make_shared(getTestLogger("MstProcessor")); status_bus = std::make_shared(); tp = std::make_shared( pcs, - mst, status_bus, std::make_shared(), getTestLogger("TransactionProcessor")); @@ -121,7 +118,6 @@ class TransactionProcessorTest : public ::testing::Test { std::shared_ptr pcs; std::shared_ptr status_bus; std::shared_ptr tp; - std::shared_ptr mst; StatusMapType status_map; std::shared_ptr status_factory = @@ -137,8 +133,7 @@ class TransactionProcessorTest : public ::testing::Test { * @given transaction processor * @when transactions passed to processor compose proposal which is sent to peer * communication service - * @then for every transaction in batches ENOUGH_SIGNATURES_COLLECTED status is - * returned + * @then for every transaction in batches propagate_batch called */ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { std::vector txs; @@ -147,13 +142,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { txs.push_back(tx); } - EXPECT_CALL(*status_bus, publish(_)) - .Times(proposal_size) - .WillRepeatedly(testing::Invoke([this](auto response) { - status_map[response->transactionHash()] = response; - })); - - EXPECT_CALL(*mst, propagateBatchImpl(_)).Times(0); EXPECT_CALL(*pcs, propagate_batch(_)).Times(txs.size()); for (const auto &tx : txs) { @@ -164,10 +152,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { // create proposal and notify about it auto proposal = std::make_shared( TestProposalBuilder().transactions(txs).build()); - - SCOPED_TRACE("Enough signatures collected status verification"); - validateStatuses( - txs); } /** @@ -183,12 +167,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalBatchTest) { auto transactions = framework::batch::createValidBatch(proposal_size)->transactions(); - EXPECT_CALL(*status_bus, publish(_)) - .Times(proposal_size) - .WillRepeatedly(testing::Invoke([this](auto response) { - status_map[response->transactionHash()] = response; - })); - auto transaction_sequence_result = shared_model::interface:: TransactionSequenceFactory::createTransactionSequence( transactions, @@ -197,7 +175,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalBatchTest) { auto transaction_sequence = framework::expected::val(transaction_sequence_result).value().value; - EXPECT_CALL(*mst, propagateBatchImpl(_)).Times(0); EXPECT_CALL(*pcs, propagate_batch(_)) .Times(transaction_sequence.batches().size()); @@ -218,10 +195,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalBatchTest) { auto proposal = std::make_shared( TestProposalBuilder().transactions(proto_transactions).build()); - - SCOPED_TRACE("Enough signatures collected status verification"); - validateStatuses( - proto_transactions); } /** @@ -237,13 +210,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorVerifiedProposalTest) { txs.push_back(tx); } - EXPECT_CALL(*status_bus, publish(_)) - .Times(txs.size() * 2) - .WillRepeatedly(testing::Invoke([this](auto response) { - status_map[response->transactionHash()] = response; - })); - - EXPECT_CALL(*mst, propagateBatchImpl(_)).Times(0); EXPECT_CALL(*pcs, propagate_batch(_)).Times(txs.size()); for (const auto &tx : txs) { @@ -262,9 +228,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorVerifiedProposalTest) { tp->processVerifiedProposalCreatorEvent( simulator::VerifiedProposalCreatorEvent{ validation_result, round, ledger_state}); - - SCOPED_TRACE("Stateful Valid status verification"); - validateStatuses(txs); } /** @@ -281,13 +244,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnCommitTest) { txs.push_back(tx); } - EXPECT_CALL(*status_bus, publish(_)) - .Times(txs.size() * 3) - .WillRepeatedly(testing::Invoke([this](auto response) { - status_map[response->transactionHash()] = response; - })); - - EXPECT_CALL(*mst, propagateBatchImpl(_)).Times(0); EXPECT_CALL(*pcs, propagate_batch(_)).Times(txs.size()); for (const auto &tx : txs) { @@ -312,9 +268,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnCommitTest) { // 2. Create block and notify transaction processor about it tp->processCommit( std::shared_ptr(clone(block))); - - SCOPED_TRACE("Committed status verification"); - validateStatuses(txs); } /** @@ -419,7 +372,7 @@ TEST_F(TransactionProcessorTest, MultisigTransactionToMst) { auto &&after_mst = framework::batch::createBatchFromSingleTransaction( std::shared_ptr(clone(tx))); - EXPECT_CALL(*mst, propagateBatchImpl(_)).Times(1); + EXPECT_CALL(*pcs, propagate_batch(_)).Times(1); tp->batchHandle(std::move(after_mst)); } @@ -436,7 +389,6 @@ TEST_F(TransactionProcessorTest, MultisigTransactionFromMst) { auto &&after_mst = framework::batch::createBatchFromSingleTransaction( std::shared_ptr(clone(tx))); - EXPECT_CALL(*pcs, propagate_batch(_)).Times(1); tp->processPreparedBatch(after_mst); } @@ -446,8 +398,7 @@ TEST_F(TransactionProcessorTest, MultisigTransactionFromMst) { * @then it will has MST_EXPIRED status */ TEST_F(TransactionProcessorTest, MultisigExpired) { - EXPECT_CALL(*mst, propagateBatchImpl(_)).Times(1); - EXPECT_CALL(*pcs, propagate_batch(_)).Times(0); + EXPECT_CALL(*pcs, propagate_batch(_)).Times(1); std::shared_ptr tx = clone(base_tx() diff --git a/test/module/irohad/torii/torii_mocks.hpp b/test/module/irohad/torii/torii_mocks.hpp index 37c00131501..4987c21df7d 100644 --- a/test/module/irohad/torii/torii_mocks.hpp +++ b/test/module/irohad/torii/torii_mocks.hpp @@ -58,10 +58,11 @@ namespace iroha { processCommit, (std::shared_ptr const &), (override)); - MOCK_METHOD(void, - processStateUpdate, - (std::shared_ptr const &), - (override)); + MOCK_METHOD( + void, + processStateUpdate, + (std::shared_ptr const &), + (override)); MOCK_METHOD( void, processPreparedBatch, diff --git a/test/module/libs/crypto/CMakeLists.txt b/test/module/libs/crypto/CMakeLists.txt index 311934f36c6..26645b22959 100644 --- a/test/module/libs/crypto/CMakeLists.txt +++ b/test/module/libs/crypto/CMakeLists.txt @@ -15,3 +15,10 @@ target_link_libraries(keys_manager_test keys_manager test_logger ) + +#Bloom filter Test +AddTest(bloom_filter_test bloom_filter_test.cpp) +target_link_libraries(bloom_filter_test + shared_model_cryptography_model + consensus_round + ) diff --git a/test/module/libs/crypto/bloom_filter_test.cpp b/test/module/libs/crypto/bloom_filter_test.cpp new file mode 100644 index 00000000000..6964789f5ce --- /dev/null +++ b/test/module/libs/crypto/bloom_filter_test.cpp @@ -0,0 +1,201 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "ordering/ordering_types.hpp" + +using ::testing::ByMove; +using ::testing::Ref; +using ::testing::Return; +using ::testing::ReturnRefOfCopy; + +struct BloomFilterTest : public ::testing::Test { + void SetUp() override { + filter_ = std::make_shared(); + } + std::shared_ptr filter_; +}; + +/** + * @given Bloom-filter + * @when set Hash there + * @then test of that Hash will return true + */ +TEST_F(BloomFilterTest, SimplePos) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "0000000000000001000000000000000000000000000000000000000000000000")); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "0000000000000001000000000000000000000000000000000000000000000000"))); +} + +/** + * @given Bloom-filter + * @when set Hash there + * @then test of the other Hash will return false + */ +TEST_F(BloomFilterTest, SimpleNeg) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "0000000000000001000000000000000000000000000000000000000000000000")); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "0000000000000002000000000000000000000000000000000000000000000000"))); +} + +/** + * @given Bloom-filter + * @when set multiple Hashes + * @then test of the Hashes which are not present should return false(remember + * false-positive) + */ +TEST_F(BloomFilterTest, RandomNeg) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "1111111111111111111111111111111111111111111111111111111111111111")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "0000000000000001000000000000000000000000000000000000000000000000")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "3897425687243695369327492877329067903476059372073409674908137884")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "2934756983467951879084309649306870136709760987508225675248658387")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "0912570146507610507436597430971934675798697834672098347567983268")); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "0000000000000002000000000000000000000000000000000000000000000000"))); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "0111111111111111111111111111111111111111111111111111111111111111"))); +} + +/** + * @given Bloom-filter + * @when set multiple Hashes there + * @then test the ones that are present will always return true + */ +TEST_F(BloomFilterTest, RandomPos) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "1111111111111111111111111111111111111111111111111111111111111111")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "0000000000000001000000000000000000000000000000000000000000000000")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "3897425687243695369327492877329067903476059372073409674908137884")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "2934756983467951879084309649306870136709760987508225675248658387")); + filter_->set(shared_model::crypto::Hash::fromHexString( + "0912570146507610507436597430971934675798697834672098347567983268")); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "0000000000000001000000000000000000000000000000000000000000000000"))); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); +} + +/** + * @given Bloom-filter + * @when set Hash there + * @and make clean after that + * @then test of this Hash will return false + */ +TEST_F(BloomFilterTest, ClearTest) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "1111111111111111111111111111111111111111111111111111111111111111")); + filter_->clear(); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1111111111111111111111111111111111111111111111111111111111111111"))); +} + +/** + * @given Bloom-filter + * @when set Hash1 there + * @and make clear after that + * @and add another Hash2 in BF + * @then test of the Hash1 will return false and test Hash 2 will return true + */ +TEST_F(BloomFilterTest, Clear2Test) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597")); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597"))); + filter_->clear(); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597"))); + filter_->set(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598")); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); +} + +/** + * @given Bloom-filter + * @when call load + * @then the result data should be the appropriate size + */ +TEST_F(BloomFilterTest, LoadTest) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597")); + auto value = filter_->load(); + ASSERT_EQ(value.size(), iroha::ordering::BloomFilter256::kBytesCount); +} + +/** + * @given Bloom-filter + * @when set Hash there + * @and after that load data from the filter to string + * @and after thar clear the filter + * @and after that store this data in filter again + * @then test of the Hash should return true + */ +TEST_F(BloomFilterTest, ReloadTest) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598")); + std::string const stored(filter_->load().data(), filter_->load().size()); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); + filter_->clear(); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); + + filter_->store(stored); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); +} + +/** + * @given Bloom-filter + * @when set Hash1 there + * @and after that load data from the filter to string + * @and after thar clear the filter + * @and after that set another Hash2 to the filter + * @and after that store the BF from the string to the BF + * @then BF will be updated: Hash1 test will return true and Hash2 will be + * overriten and return false + */ +TEST_F(BloomFilterTest, ReloadTest2) { + filter_->set(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597")); + std::string const stored(filter_->load().data(), filter_->load().size()); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597"))); + filter_->clear(); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597"))); + + filter_->set(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598")); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); + + filter_->store(stored); + ASSERT_TRUE(filter_->test(shared_model::crypto::Hash::fromHexString( + "9123594865892659791270573928567890379843798672987395677893427597"))); + ASSERT_FALSE(filter_->test(shared_model::crypto::Hash::fromHexString( + "1298367587946526947123063707196892848236917480679537296387464598"))); +} diff --git a/test/module/shared_model/interface_mocks.hpp b/test/module/shared_model/interface_mocks.hpp index a718c9cf0f4..f73a8ee23ff 100644 --- a/test/module/shared_model/interface_mocks.hpp +++ b/test/module/shared_model/interface_mocks.hpp @@ -74,6 +74,12 @@ struct MockTransaction : public shared_model::interface::Transaction { batchMeta, std::optional>()); MOCK_METHOD0(moveTo, std::unique_ptr()); + + MOCK_METHOD1(storeBatchHash, + void(shared_model::interface::types::HashType const &)); + MOCK_CONST_METHOD0( + getBatchHash, + std::optional const &()); }; /** @@ -181,6 +187,9 @@ struct MockProposal : public shared_model::interface::Proposal { MOCK_CONST_METHOD0(blob, const shared_model::interface::types::BlobType &()); MOCK_CONST_METHOD0(hash, const shared_model::interface::types::HashType &()); MOCK_CONST_METHOD0(clone, MockProposal *()); + MOCK_CONST_METHOD0(toString, std::string()); + MOCK_METHOD0(mut_transactions, + shared_model::interface::types::TransactionsCollectionType()); }; struct MockPeer : public shared_model::interface::Peer { diff --git a/test/system/config.sample b/test/system/config.sample index 0a6048e4b9e..ac319e11eef 100644 --- a/test/system/config.sample +++ b/test/system/config.sample @@ -7,7 +7,6 @@ "internal_port" : 10001, "pg_opt" : "host=localhost port=5432 user=postgres password=mysecretpassword", "max_proposal_size" : 10, - "proposal_delay" : 5000, "vote_delay" : 5000, "mst_enable" : false, "mst_expiration_time" : 1440 diff --git a/test/system/irohad_test.cpp b/test/system/irohad_test.cpp index 17ea2703e8c..f284d2597bd 100644 --- a/test/system/irohad_test.cpp +++ b/test/system/irohad_test.cpp @@ -658,8 +658,6 @@ TEST_F(IrohadTest, StartWithoutConfigAndKeyFile) { std::to_string(doc[config_members::InternalPort].GetInt64()); env["IROHA_MAX_PROPOSAL_SIZE"] = std::to_string(doc[config_members::MaxProposalSize].GetInt64()); - env["IROHA_PROPOSAL_DELAY"] = - std::to_string(doc[config_members::ProposalDelay].GetInt64()); env["IROHA_VOTE_DELAY"] = std::to_string(doc[config_members::VoteDelay].GetInt64()); env["IROHA_MST_ENABLE"] = "false"; diff --git a/test/tool/irohad.restore_wsv.config b/test/tool/irohad.restore_wsv.config index 6248152afe4..59c67208f53 100644 --- a/test/tool/irohad.restore_wsv.config +++ b/test/tool/irohad.restore_wsv.config @@ -4,7 +4,6 @@ "torii_port": 50051, "internal_port": 10001, "max_proposal_size": 10, - "proposal_delay": 5000, "vote_delay": 5000, "mst_enable": false, "mst_expiration_time": 1440,