From 76d5ec2a4dbb8db32eabbf6c82262033fc88b7c9 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Sat, 31 Mar 2018 13:05:51 +0300 Subject: [PATCH 001/110] Selected branches coverage (#1122) * run coverage for selected branches only Signed-off-by: Artyom Bakhtin * branches to cover as a separate script Signed-off-by: Artyom Bakhtin --- .jenkinsci/selected-branches-coverage.groovy | 13 ++++++++++++ Jenkinsfile | 21 ++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 .jenkinsci/selected-branches-coverage.groovy diff --git a/.jenkinsci/selected-branches-coverage.groovy b/.jenkinsci/selected-branches-coverage.groovy new file mode 100644 index 0000000000..dce5d5ae70 --- /dev/null +++ b/.jenkinsci/selected-branches-coverage.groovy @@ -0,0 +1,13 @@ +#!/usr/bin/env groovy + +def selectedBranchesCoverage(branches, PRCoverage=true) { + // trigger coverage if branch is either develop or master, or it is a PR + if (PRCoverage) { + return env.BRANCH_NAME in branches || env.CHANGE_ID != null + } + else { + return env.BRANCH_NAME in branches + } +} + +return this \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 6a6d71bf16..8a33536581 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -93,7 +93,13 @@ pipeline { steps { script { debugBuild = load ".jenkinsci/debug-build.groovy" - debugBuild.doDebugBuild(true) + coverage = load ".jenkinsci/selected-branches-coverage.groovy" + if (coverage.selectedBranchesCoverage(['develop', 'master'])) { + debugBuild.doDebugBuild(true) + } + else { + debugBuild.doDebugBuild() + } if (BRANCH_NAME ==~ /(master|develop)/) { releaseBuild = load ".jenkinsci/release-build.groovy" releaseBuild.doReleaseBuild() @@ -117,8 +123,9 @@ pipeline { agent { label 'armv7' } steps { script { - def debugBuild = load ".jenkinsci/debug-build.groovy" - if (!params.Linux && !params.ARMv8 && !params.MacOS) { + debugBuild = load ".jenkinsci/debug-build.groovy" + coverage = load ".jenkinsci/selected-branches-coverage.groovy" + if (!params.Linux && !params.ARMv8 && !params.MacOS && (coverage.selectedBranchesCoverage(['develop', 'master']))) { debugBuild.doDebugBuild(true) } else { @@ -147,8 +154,9 @@ pipeline { agent { label 'armv8' } steps { script { - def debugBuild = load ".jenkinsci/debug-build.groovy" - if (!params.Linux && !params.MacOS) { + debugBuild = load ".jenkinsci/debug-build.groovy" + coverage = load ".jenkinsci/selected-branches-coverage.groovy" + if (!params.Linux && !params.MacOS && (coverage.selectedBranchesCoverage(['develop', 'master']))) { debugBuild.doDebugBuild(true) } else { @@ -179,7 +187,8 @@ pipeline { script { def coverageEnabled = false def cmakeOptions = "" - if (!params.Linux) { + coverage = load ".jenkinsci/selected-branches-coverage.groovy" + if (!params.Linux && (coverage.selectedBranchesCoverage(['develop', 'master']))) { coverageEnabled = true cmakeOptions = " -DCOVERAGE=ON " } From 15de16f2fa68358b257784d9624e5b8feab7557c Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 5 Apr 2018 13:13:36 +0300 Subject: [PATCH 002/110] Fix std::string constructor arguments in tests (#1178) Signed-off-by: Andrei Lebedev --- test/module/irohad/ametsuchi/ametsuchi_test.cpp | 8 ++++---- test/module/irohad/ametsuchi/block_query_test.cpp | 4 ++-- .../module/irohad/ametsuchi/block_query_transfer_test.cpp | 2 +- .../irohad/consensus/yac/yac_crypto_provider_test.cpp | 4 ++-- test/module/irohad/simulator/simulator_test.cpp | 2 +- test/module/irohad/torii/torii_service_test.cpp | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index d859d45e5e..7089d9c0d1 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -402,8 +402,8 @@ TEST_F(AmetsuchiTest, AddSignatoryTest) { ASSERT_TRUE(storage); auto wsv = storage->getWsvQuery(); - shared_model::crypto::PublicKey pubkey1(std::string("1", 32)); - shared_model::crypto::PublicKey pubkey2(std::string("2", 32)); + shared_model::crypto::PublicKey pubkey1(std::string(32, '1')); + shared_model::crypto::PublicKey pubkey2(std::string(32, '2')); auto user1id = "userone@domain"; auto user2id = "usertwo@domain"; @@ -691,8 +691,8 @@ TEST_F(AmetsuchiTest, FindTxByHashTest) { ASSERT_TRUE(storage); auto blocks = storage->getBlockQuery(); - shared_model::crypto::PublicKey pubkey1(std::string("1", 32)); - shared_model::crypto::PublicKey pubkey2(std::string("2", 32)); + shared_model::crypto::PublicKey pubkey1(std::string(32, '1')); + shared_model::crypto::PublicKey pubkey2(std::string(32, '2')); auto txn1 = TestTransactionBuilder() diff --git a/test/module/irohad/ametsuchi/block_query_test.cpp b/test/module/irohad/ametsuchi/block_query_test.cpp index 8e70a0df32..e0490c4043 100644 --- a/test/module/irohad/ametsuchi/block_query_test.cpp +++ b/test/module/irohad/ametsuchi/block_query_test.cpp @@ -104,7 +104,7 @@ class BlockQueryTest : public AmetsuchiTest { std::string creator1 = "user1@test"; std::string creator2 = "user2@test"; std::size_t blocks_total{0}; - std::string zero_string = std::string("0", 32); + std::string zero_string = std::string(32, '0'); }; /** @@ -186,7 +186,7 @@ TEST_F(BlockQueryTest, GetTransactionsExistingTxHashes) { */ TEST_F(BlockQueryTest, GetTransactionsIncludesNonExistingTxHashes) { shared_model::crypto::Hash invalid_tx_hash_1(zero_string), - invalid_tx_hash_2(std::string("9", 32)); + invalid_tx_hash_2(std::string(32, '9')); auto wrapper = make_test_subscriber( blocks->getTransactions({invalid_tx_hash_1, invalid_tx_hash_2}), 2); wrapper.subscribe( diff --git a/test/module/irohad/ametsuchi/block_query_transfer_test.cpp b/test/module/irohad/ametsuchi/block_query_transfer_test.cpp index 4ca512aa04..7075af3004 100644 --- a/test/module/irohad/ametsuchi/block_query_transfer_test.cpp +++ b/test/module/irohad/ametsuchi/block_query_transfer_test.cpp @@ -77,7 +77,7 @@ namespace iroha { std::string asset = "coin#test"; }; - auto zero_string = std::string("0", 32); + auto zero_string = std::string(32, '0'); auto fake_hash = shared_model::crypto::Hash(zero_string); /** diff --git a/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp b/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp index 2d448f39be..8d7683280c 100644 --- a/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp +++ b/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp @@ -22,8 +22,8 @@ #include "consensus/yac/messages.hpp" #include "cryptography/ed25519_sha3_impl/internal/ed25519_impl.hpp" -const auto pubkey = std::string('0', 32); -const auto signed_data = std::string('1', 32); +const auto pubkey = std::string(32, '0'); +const auto signed_data = std::string(32, '1'); namespace iroha { namespace consensus { namespace yac { diff --git a/test/module/irohad/simulator/simulator_test.cpp b/test/module/irohad/simulator/simulator_test.cpp index fcdd8ddd65..d9122e7b2d 100644 --- a/test/module/irohad/simulator/simulator_test.cpp +++ b/test/module/irohad/simulator/simulator_test.cpp @@ -77,7 +77,7 @@ shared_model::proto::Block makeBlock(int height) { return TestBlockBuilder() .transactions(std::vector()) .height(height) - .prevHash(shared_model::crypto::Hash(std::string("0", 32))) + .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) .build(); } diff --git a/test/module/irohad/torii/torii_service_test.cpp b/test/module/irohad/torii/torii_service_test.cpp index 865948544d..5b0f80dc8c 100644 --- a/test/module/irohad/torii/torii_service_test.cpp +++ b/test/module/irohad/torii/torii_service_test.cpp @@ -127,7 +127,7 @@ class ToriiServiceTest : public testing::Test { */ TEST_F(ToriiServiceTest, CommandClient) { iroha::protocol::TxStatusRequest tx_request; - tx_request.set_tx_hash(std::string('1', 32)); + tx_request.set_tx_hash(std::string(32, '1')); iroha::protocol::ToriiResponse toriiResponse; auto client1 = torii::CommandSyncClient(Ip, Port); From f63a9ac8ca44851b3229522b19e761f5c62c6d92 Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 5 Apr 2018 17:39:30 +0300 Subject: [PATCH 003/110] Ordering gate queue proposals order (#1181) * Add order test for OrderingGate, simplify AlwaysValidValidator * Replace regular queue with priority queue in OrderingGateImpl Signed-off-by: Andrei Lebedev --- irohad/ordering/impl/ordering_gate_impl.cpp | 10 +++- irohad/ordering/impl/ordering_gate_impl.hpp | 15 +++++- .../irohad/ordering/ordering_gate_test.cpp | 51 +++++++++++++++++++ .../builders/protobuf/test_block_builder.hpp | 2 +- .../protobuf/test_proposal_builder.hpp | 3 +- .../builders/protobuf/test_query_builder.hpp | 4 +- .../protobuf/test_transaction_builder.hpp | 4 +- .../shared_model/validators/validators.hpp | 10 +--- 8 files changed, 82 insertions(+), 17 deletions(-) diff --git a/irohad/ordering/impl/ordering_gate_impl.cpp b/irohad/ordering/impl/ordering_gate_impl.cpp index 0dfad79966..bf55528127 100644 --- a/irohad/ordering/impl/ordering_gate_impl.cpp +++ b/irohad/ordering/impl/ordering_gate_impl.cpp @@ -17,12 +17,20 @@ #include -#include "interfaces/transaction.hpp" #include "ordering/impl/ordering_gate_impl.hpp" +#include "interfaces/iroha_internal/proposal.hpp" +#include "interfaces/transaction.hpp" + namespace iroha { namespace ordering { + bool ProposalComparator::operator()( + const std::shared_ptr &lhs, + const std::shared_ptr &rhs) const { + return lhs->height() > rhs->height(); + } + OrderingGateImpl::OrderingGateImpl( std::shared_ptr transport) : transport_(std::move(transport)), log_(logger::log("OrderingGate")) {} diff --git a/irohad/ordering/impl/ordering_gate_impl.hpp b/irohad/ordering/impl/ordering_gate_impl.hpp index 3f4e8c52bb..a455160535 100644 --- a/irohad/ordering/impl/ordering_gate_impl.hpp +++ b/irohad/ordering/impl/ordering_gate_impl.hpp @@ -21,7 +21,7 @@ #include "network/ordering_gate.hpp" #include -#include +#include #include "logger/logger.hpp" #include "network/impl/async_grpc_client.hpp" @@ -37,6 +37,15 @@ namespace shared_model { namespace iroha { namespace ordering { + /** + * Compare proposals by height + */ + struct ProposalComparator { + bool operator()( + const std::shared_ptr &lhs, + const std::shared_ptr &rhs) const; + }; + /** * OrderingGate implementation with gRPC asynchronous client * Interacts with given OrderingService @@ -78,7 +87,9 @@ namespace iroha { std::atomic_bool unlock_next_{true}; /// queue with all proposals received from ordering service - tbb::concurrent_queue> + tbb::concurrent_priority_queue< + std::shared_ptr, + ProposalComparator> proposal_queue_; /// subscription of pcs::on_commit diff --git a/test/module/irohad/ordering/ordering_gate_test.cpp b/test/module/irohad/ordering/ordering_gate_test.cpp index 8e488bbd65..f6c2c846bb 100644 --- a/test/module/irohad/ordering/ordering_gate_test.cpp +++ b/test/module/irohad/ordering/ordering_gate_test.cpp @@ -224,3 +224,54 @@ TEST(OrderingGateQueueBehaviour, SendManyProposals) { ASSERT_TRUE(wrapper_after.validate()); } + +/** + * @given Initialized OrderingGate + * AND MockPeerCommunicationService + * @when Receive proposals in random order + * @then on_proposal output is ordered + */ +TEST(OrderingGateQueueBehaviour, ReceiveUnordered) { + std::shared_ptr transport = + std::make_shared(); + + std::shared_ptr pcs = + std::make_shared(); + rxcpp::subjects::subject commit_subject; + EXPECT_CALL(*pcs, on_commit()) + .WillOnce(Return(commit_subject.get_observable())); + + auto pushCommit = [&] { + commit_subject.get_subscriber().on_next(rxcpp::observable<>::just( + std::static_pointer_cast( + std::make_shared( + TestBlockBuilder().build())))); + }; + + OrderingGateImpl ordering_gate(transport); + ordering_gate.setPcs(*pcs); + + auto pushProposal = [&](auto height) { + ordering_gate.onProposal(std::make_shared( + TestProposalBuilder().height(height).build())); + }; + + std::vector messages; + ordering_gate.on_proposal().subscribe([&](auto val) { + messages.push_back(val); + }); + + // this will set unlock_next_ to false, so proposals 4 and 3 are enqueued + pushProposal(2); + + pushProposal(4); + pushProposal(3); + + pushCommit(); + pushCommit(); + + ASSERT_EQ(3, messages.size()); + ASSERT_EQ(2, messages.at(0)->height()); + ASSERT_EQ(3, messages.at(1)->height()); + ASSERT_EQ(4, messages.at(2)->height()); +} diff --git a/test/module/shared_model/builders/protobuf/test_block_builder.hpp b/test/module/shared_model/builders/protobuf/test_block_builder.hpp index 9fe486a673..b53f88bca9 100644 --- a/test/module/shared_model/builders/protobuf/test_block_builder.hpp +++ b/test/module/shared_model/builders/protobuf/test_block_builder.hpp @@ -27,6 +27,6 @@ */ using TestBlockBuilder = shared_model::proto::TemplateBlockBuilder< (1 << shared_model::proto::TemplateBlockBuilder<>::total) - 1, - shared_model::validation::BlockAlwaysValidValidator, + shared_model::validation::AlwaysValidValidator, shared_model::proto::Block>; #endif // IROHA_TEST_BLOCK_BUILDER_HPP diff --git a/test/module/shared_model/builders/protobuf/test_proposal_builder.hpp b/test/module/shared_model/builders/protobuf/test_proposal_builder.hpp index fb8da46423..11bc2f3eba 100644 --- a/test/module/shared_model/builders/protobuf/test_proposal_builder.hpp +++ b/test/module/shared_model/builders/protobuf/test_proposal_builder.hpp @@ -19,6 +19,7 @@ #define IROHA_TEST_PROPOSAL_BUILDER_HPP #include "builders/protobuf/builder_templates/proposal_template.hpp" +#include "module/shared_model/validators/validators.hpp" /** * Builder alias, to build shared model proto proposal object avoiding "required @@ -26,6 +27,6 @@ */ using TestProposalBuilder = shared_model::proto::TemplateProposalBuilder< (1 << shared_model::proto::TemplateProposalBuilder<>::total) - 1, - shared_model::validation::DefaultProposalValidator>; + shared_model::validation::AlwaysValidValidator>; #endif // IROHA_TEST_PROPOSAL_BUILDER_HPP diff --git a/test/module/shared_model/builders/protobuf/test_query_builder.hpp b/test/module/shared_model/builders/protobuf/test_query_builder.hpp index 5324c1d288..3e567eb0a9 100644 --- a/test/module/shared_model/builders/protobuf/test_query_builder.hpp +++ b/test/module/shared_model/builders/protobuf/test_query_builder.hpp @@ -27,12 +27,12 @@ */ using TestQueryBuilder = shared_model::proto::TemplateQueryBuilder< (1 << shared_model::proto::TemplateQueryBuilder<>::total) - 1, - shared_model::validation::QueryAlwaysValidValidator, + shared_model::validation::AlwaysValidValidator, shared_model::proto::Query>; using TestUnsignedQueryBuilder = shared_model::proto::TemplateQueryBuilder< (1 << shared_model::proto::TemplateQueryBuilder<>::total) - 1, - shared_model::validation::QueryAlwaysValidValidator, + shared_model::validation::AlwaysValidValidator, shared_model::proto::UnsignedWrapper>; #endif // IROHA_TEST_QUERY_BUILDER_HPP diff --git a/test/module/shared_model/builders/protobuf/test_transaction_builder.hpp b/test/module/shared_model/builders/protobuf/test_transaction_builder.hpp index 6de9f472f4..9b9f74da50 100644 --- a/test/module/shared_model/builders/protobuf/test_transaction_builder.hpp +++ b/test/module/shared_model/builders/protobuf/test_transaction_builder.hpp @@ -27,13 +27,13 @@ */ using TestTransactionBuilder = shared_model::proto::TemplateTransactionBuilder< (1 << shared_model::proto::TemplateTransactionBuilder<>::total) - 1, - shared_model::validation::TransactionAlwaysValidValidator, + shared_model::validation::AlwaysValidValidator, shared_model::proto::Transaction>; using TestUnsignedTransactionBuilder = shared_model::proto::TemplateTransactionBuilder< (1 << shared_model::proto::TemplateTransactionBuilder<>::total) - 1, - shared_model::validation::TransactionAlwaysValidValidator, + shared_model::validation::AlwaysValidValidator, shared_model::proto::UnsignedWrapper>; #endif // IROHA_TEST_TRANSACTION_BUILDER_HPP diff --git a/test/module/shared_model/validators/validators.hpp b/test/module/shared_model/validators/validators.hpp index 86d7e3c775..29c8d2f991 100644 --- a/test/module/shared_model/validators/validators.hpp +++ b/test/module/shared_model/validators/validators.hpp @@ -27,18 +27,12 @@ namespace shared_model { // TODO: kamilsa 01.02.2018 IR-873 Replace all these validators with mock // classes - template struct AlwaysValidValidator { - Answer validate(const Iface &) const { + template + Answer validate(const T &) const { return {}; } }; - using TransactionAlwaysValidValidator = - AlwaysValidValidator; - using BlockAlwaysValidValidator = AlwaysValidValidator; - using ProposalAlwaysValidValidator = - AlwaysValidValidator; - using QueryAlwaysValidValidator = AlwaysValidValidator; } // namespace validation } // namespace shared_model From 321d6bf1b407efe4b565ae3da336101f9afca8f3 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Mon, 9 Apr 2018 10:17:33 +0300 Subject: [PATCH 004/110] no symlinks + apt-get install (#1169) Signed-off-by: Artyom Bakhtin --- .jenkinsci/release-build.groovy | 2 +- docker/release/aarch64/Dockerfile | 16 +++++++++++++++- docker/release/aarch64/entrypoint.sh | 5 ++++- docker/release/armv7l/Dockerfile | 16 +++++++++++++++- docker/release/armv7l/entrypoint.sh | 5 ++++- docker/release/x86_64/Dockerfile | 11 ++++------- docker/release/x86_64/entrypoint.sh | 1 - 7 files changed, 43 insertions(+), 13 deletions(-) mode change 120000 => 100644 docker/release/aarch64/Dockerfile mode change 120000 => 100755 docker/release/aarch64/entrypoint.sh mode change 120000 => 100644 docker/release/armv7l/Dockerfile mode change 120000 => 100755 docker/release/armv7l/entrypoint.sh diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index 05d6613917..dc4db9ddab 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -57,7 +57,7 @@ def doReleaseBuild() { sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/release/${platform}/entrypoint.sh" sh "cp /tmp/${GIT_COMMIT}-${BUILD_NUMBER}/iroha.deb /tmp/${env.GIT_COMMIT}" sh "chmod +x /tmp/${env.GIT_COMMIT}/entrypoint.sh" - iCRelease = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}-release", "-f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") + iCRelease = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}-release", "--no-cache -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { if (env.BRANCH_NAME == 'develop') { iCRelease.push("${platform}-develop-latest") diff --git a/docker/release/aarch64/Dockerfile b/docker/release/aarch64/Dockerfile deleted file mode 120000 index d810e95633..0000000000 --- a/docker/release/aarch64/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -../x86_64/Dockerfile \ No newline at end of file diff --git a/docker/release/aarch64/Dockerfile b/docker/release/aarch64/Dockerfile new file mode 100644 index 0000000000..c07120cb32 --- /dev/null +++ b/docker/release/aarch64/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:16.04 + +RUN apt-get update; \ + apt-get install -y libc-ares-dev + +#Install iroha +COPY iroha.deb /tmp/iroha.deb +RUN apt-get install -y /tmp/iroha.deb; \ + rm -f /tmp/iroha.deb + +WORKDIR /opt/iroha_data + +COPY entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["/sbin/init"] diff --git a/docker/release/aarch64/entrypoint.sh b/docker/release/aarch64/entrypoint.sh deleted file mode 120000 index d87c399ff9..0000000000 --- a/docker/release/aarch64/entrypoint.sh +++ /dev/null @@ -1 +0,0 @@ -../x86_64/entrypoint.sh \ No newline at end of file diff --git a/docker/release/aarch64/entrypoint.sh b/docker/release/aarch64/entrypoint.sh new file mode 100755 index 0000000000..709e3d9bbc --- /dev/null +++ b/docker/release/aarch64/entrypoint.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo key=$KEY +echo $PWD +irohad --genesis_block genesis.block --config config.sample --keypair_name $KEY diff --git a/docker/release/armv7l/Dockerfile b/docker/release/armv7l/Dockerfile deleted file mode 120000 index d810e95633..0000000000 --- a/docker/release/armv7l/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -../x86_64/Dockerfile \ No newline at end of file diff --git a/docker/release/armv7l/Dockerfile b/docker/release/armv7l/Dockerfile new file mode 100644 index 0000000000..c07120cb32 --- /dev/null +++ b/docker/release/armv7l/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:16.04 + +RUN apt-get update; \ + apt-get install -y libc-ares-dev + +#Install iroha +COPY iroha.deb /tmp/iroha.deb +RUN apt-get install -y /tmp/iroha.deb; \ + rm -f /tmp/iroha.deb + +WORKDIR /opt/iroha_data + +COPY entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["/sbin/init"] diff --git a/docker/release/armv7l/entrypoint.sh b/docker/release/armv7l/entrypoint.sh deleted file mode 120000 index d87c399ff9..0000000000 --- a/docker/release/armv7l/entrypoint.sh +++ /dev/null @@ -1 +0,0 @@ -../x86_64/entrypoint.sh \ No newline at end of file diff --git a/docker/release/armv7l/entrypoint.sh b/docker/release/armv7l/entrypoint.sh new file mode 100755 index 0000000000..709e3d9bbc --- /dev/null +++ b/docker/release/armv7l/entrypoint.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo key=$KEY +echo $PWD +irohad --genesis_block genesis.block --config config.sample --keypair_name $KEY diff --git a/docker/release/x86_64/Dockerfile b/docker/release/x86_64/Dockerfile index 53f05883fd..c07120cb32 100644 --- a/docker/release/x86_64/Dockerfile +++ b/docker/release/x86_64/Dockerfile @@ -1,15 +1,12 @@ FROM ubuntu:16.04 -RUN apt-get update;\ - apt-get upgrade -y; \ - apt-get install -y \ - libc-ares-dev +RUN apt-get update; \ + apt-get install -y libc-ares-dev #Install iroha COPY iroha.deb /tmp/iroha.deb -RUN dpkg -i /tmp/iroha.deb - -RUN apt-get -fy install;rm -f /tmp/iroha.deb +RUN apt-get install -y /tmp/iroha.deb; \ + rm -f /tmp/iroha.deb WORKDIR /opt/iroha_data diff --git a/docker/release/x86_64/entrypoint.sh b/docker/release/x86_64/entrypoint.sh index 85595eb18a..709e3d9bbc 100755 --- a/docker/release/x86_64/entrypoint.sh +++ b/docker/release/x86_64/entrypoint.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash echo key=$KEY echo $PWD -iroha-cli --genesis_block --peers_address peers.list irohad --genesis_block genesis.block --config config.sample --keypair_name $KEY From 2e0306321f44d0226498368402d0b083688bea7b Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Mon, 9 Apr 2018 13:23:22 +0300 Subject: [PATCH 005/110] Fix consensus getting locked due to synchronous subscribers (#1180) * Fix consensus getting locked due to synchronous subscribers * Add tests for operation order on vote and on reject Signed-off-by: Andrei Lebedev --- irohad/consensus/yac/impl/yac.cpp | 4 +- .../yac/yac_simple_cold_case_test.cpp | 66 +++++++++++++++++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/irohad/consensus/yac/impl/yac.cpp b/irohad/consensus/yac/impl/yac.cpp index a663f4e13a..014895eeee 100644 --- a/irohad/consensus/yac/impl/yac.cpp +++ b/irohad/consensus/yac/impl/yac.cpp @@ -210,8 +210,8 @@ namespace iroha { // IR-497 }, [&](const CommitMessage &commit) { - notifier_.get_subscriber().on_next(commit); this->propagateCommit(commit); + notifier_.get_subscriber().on_next(commit); }); } this->closeRound(); @@ -246,8 +246,8 @@ namespace iroha { // propagate for all log_->info("Propagate commit {} to whole network", vote.hash.block_hash); - notifier_.get_subscriber().on_next(commit); this->propagateCommit(commit); + notifier_.get_subscriber().on_next(commit); }, [&](const RejectMessage &reject) { // propagate reject for all diff --git a/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp b/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp index 4978884e57..2476988ade 100644 --- a/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp +++ b/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp @@ -15,9 +15,6 @@ * limitations under the License. */ -#ifndef IROHA_YAC_SIMPLE_CASE_TEST_HPP -#define IROHA_YAC_SIMPLE_CASE_TEST_HPP - #include #include #include @@ -34,6 +31,7 @@ using ::testing::_; using ::testing::An; using ::testing::AtLeast; using ::testing::Return; +using ::testing::Invoke; using namespace iroha::consensus::yac; using namespace framework::test_subscriber; @@ -176,4 +174,64 @@ TEST_F(YacTest, YacWhenColdStartAndAchieveCommitMessage) { ASSERT_TRUE(wrapper.validate()); } -#endif // IROHA_YAC_SIMPLE_CASE_TEST_HPP + +/** + * @given initialized YAC + * @when receive supermajority of votes for a hash + * @then commit is sent to the network before notifying subscribers + */ +TEST_F(YacTest, PropagateCommitBeforeNotifyingSubscribersApplyVote) { + EXPECT_CALL(*crypto, verify(An())).Times(default_peers.size()) + .WillRepeatedly(Return(true)); + std::vector messages; + EXPECT_CALL(*network, send_commit(_, _)) + .Times(default_peers.size()) + .WillRepeatedly(Invoke([&](const auto &, const auto &msg) { + messages.push_back(msg); + })); + + yac->on_commit().subscribe([&](auto msg) { + // verify that commits are already sent to the network + ASSERT_EQ(default_peers.size(), messages.size()); + messages.push_back(msg); + }); + + for (size_t i = 0; i < default_peers.size(); ++i) { + yac->on_vote(create_vote(YacHash{}, std::to_string(i))); + } + + // verify that on_commit subscribers are notified + ASSERT_EQ(default_peers.size() + 1, messages.size()); +} + +/** + * @given initialized YAC + * @when receive reject message which triggers commit + * @then commit is sent to the network before notifying subscribers + */ +TEST_F(YacTest, PropagateCommitBeforeNotifyingSubscribersApplyReject) { + EXPECT_CALL(*crypto, verify(An())).WillOnce(Return(true)); + EXPECT_CALL(*timer, deny()).Times(AtLeast(1)); + std::vector messages; + EXPECT_CALL(*network, send_commit(_, _)) + .Times(default_peers.size()) + .WillRepeatedly(Invoke([&](const auto &, const auto &msg) { + messages.push_back(msg); + })); + + yac->on_commit().subscribe([&](auto msg) { + // verify that commits are already sent to the network + ASSERT_EQ(default_peers.size(), messages.size()); + messages.push_back(msg); + }); + + RejectMessage reject({}); + for (size_t i = 0; i < default_peers.size(); ++i) { + reject.votes.push_back(create_vote(YacHash{}, std::to_string(i))); + } + + yac->on_reject(reject); + + // verify that on_commit subscribers are notified + ASSERT_EQ(default_peers.size() + 1, messages.size()); +} From 9a87c2bbef7f31c3e512642dc2280ebb188e03b8 Mon Sep 17 00:00:00 2001 From: Konstantin Munichev Date: Tue, 10 Apr 2018 11:58:16 +0300 Subject: [PATCH 006/110] Change namespace for permissions (#1194) - Use shared_model::permissions namespace for permissions.hpp - Corresponding changes in dependent files Signed-off-by: luckychess --- .../impl/interactive_transaction_cli.cpp | 1 + irohad/execution/impl/command_executor.cpp | 102 +++++++++++------- .../converters/impl/pb_command_factory.cpp | 19 ++-- .../generators/impl/command_generator.cpp | 1 + irohad/model/impl/query_execution.cpp | 1 + shared_model/validators/field_validator.cpp | 10 +- shared_model/validators/permissions.hpp | 14 +-- .../integration_test_framework.cpp | 12 +-- test/framework/test_block_generator.cpp | 3 +- .../acceptance/add_asset_qty_test.cpp | 12 +-- .../acceptance/create_account_test.cpp | 6 +- .../acceptance/create_domain_test.cpp | 6 +- .../acceptance/create_role_test.cpp | 21 ++-- .../acceptance/get_transactions_test.cpp | 16 +-- .../acceptance/subtract_asset_qty_test.cpp | 8 +- .../acceptance/transfer_asset_test.cpp | 24 +++-- test/integration/client_test.cpp | 1 + .../irohad/ametsuchi/ametsuchi_test.cpp | 53 ++++----- .../irohad/ametsuchi/kv_storage_test.cpp | 8 +- .../model/command_validate_execute_test.cpp | 1 + .../model/converters/json_commands_test.cpp | 1 + .../model/converters/pb_commands_test.cpp | 1 + .../torii/processor/query_processor_test.cpp | 8 +- .../irohad/torii/torii_queries_test.cpp | 43 +++++--- .../irohad/validation/query_execution.cpp | 1 + .../validators/field_validator_test.cpp | 17 +-- 26 files changed, 230 insertions(+), 160 deletions(-) diff --git a/iroha-cli/interactive/impl/interactive_transaction_cli.cpp b/iroha-cli/interactive/impl/interactive_transaction_cli.cpp index 386629218c..c2af842707 100644 --- a/iroha-cli/interactive/impl/interactive_transaction_cli.cpp +++ b/iroha-cli/interactive/impl/interactive_transaction_cli.cpp @@ -36,6 +36,7 @@ #include "parser/parser.hpp" // for parser::ParseValue using namespace iroha::model; +using namespace shared_model::permissions; namespace iroha_cli { namespace interactive { diff --git a/irohad/execution/impl/command_executor.cpp b/irohad/execution/impl/command_executor.cpp index a6bd3eda6e..6170e524a2 100644 --- a/irohad/execution/impl/command_executor.cpp +++ b/irohad/execution/impl/command_executor.cpp @@ -21,8 +21,8 @@ #include "execution/common_executor.hpp" #include "interfaces/commands/command.hpp" -#include "validators/permissions.hpp" #include "utils/amount_utils.hpp" +#include "validators/permissions.hpp" namespace iroha { @@ -362,8 +362,8 @@ namespace iroha { .str(), command_name); } - auto account_asset = queries->getAccountAsset( - command->accountId(), command->assetId()); + auto account_asset = + queries->getAccountAsset(command->accountId(), command->assetId()); if (not account_asset) { return makeExecutionError((boost::format("%s do not have %s") % command->accountId() % command->assetId()) @@ -506,7 +506,9 @@ namespace iroha { // any asset return creator_account_id == command.accountId() and checkAccountRolePermission( - creator_account_id, queries, model::can_add_asset_qty); + creator_account_id, + queries, + shared_model::permissions::can_add_asset_qty); } bool CommandValidator::hasPermissions( @@ -514,7 +516,7 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_add_peer); + creator_account_id, queries, shared_model::permissions::can_add_peer); } bool CommandValidator::hasPermissions( @@ -526,11 +528,15 @@ namespace iroha { // account and he has permission CanAddSignatory (command.accountId() == creator_account_id and checkAccountRolePermission( - creator_account_id, queries, model::can_add_signatory)) + creator_account_id, + queries, + shared_model::permissions::can_add_signatory)) or // Case 2. Creator has granted permission for it (queries.hasAccountGrantablePermission( - creator_account_id, command.accountId(), model::can_add_signatory)); + creator_account_id, + command.accountId(), + shared_model::permissions::can_add_signatory)); } bool CommandValidator::hasPermissions( @@ -538,7 +544,9 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_append_role); + creator_account_id, + queries, + shared_model::permissions::can_append_role); } bool CommandValidator::hasPermissions( @@ -546,7 +554,9 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_create_account); + creator_account_id, + queries, + shared_model::permissions::can_create_account); } bool CommandValidator::hasPermissions( @@ -554,7 +564,9 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_create_asset); + creator_account_id, + queries, + shared_model::permissions::can_create_asset); } bool CommandValidator::hasPermissions( @@ -562,7 +574,9 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_create_domain); + creator_account_id, + queries, + shared_model::permissions::can_create_domain); } bool CommandValidator::hasPermissions( @@ -570,7 +584,9 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_create_role); + creator_account_id, + queries, + shared_model::permissions::can_create_role); } bool CommandValidator::hasPermissions( @@ -578,7 +594,9 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { return checkAccountRolePermission( - creator_account_id, queries, model::can_detach_role); + creator_account_id, + queries, + shared_model::permissions::can_detach_role); } bool CommandValidator::hasPermissions( @@ -588,7 +606,7 @@ namespace iroha { return checkAccountRolePermission( creator_account_id, queries, - model::can_grant + command.permissionName()); + shared_model::permissions::can_grant + command.permissionName()); } bool CommandValidator::hasPermissions( @@ -600,11 +618,14 @@ namespace iroha { // permission on it (creator_account_id == command.accountId() and checkAccountRolePermission( - creator_account_id, queries, model::can_remove_signatory)) + creator_account_id, + queries, + shared_model::permissions::can_remove_signatory)) // 2. Creator has granted permission on removal - or (queries.hasAccountGrantablePermission(creator_account_id, - command.accountId(), - model::can_remove_signatory)); + or (queries.hasAccountGrantablePermission( + creator_account_id, + command.accountId(), + shared_model::permissions::can_remove_signatory)); } bool CommandValidator::hasPermissions( @@ -624,7 +645,9 @@ namespace iroha { creator_account_id == command.accountId() or // Case 2. Creator has grantable permission to set account key/value queries.hasAccountGrantablePermission( - creator_account_id, command.accountId(), model::can_set_detail); + creator_account_id, + command.accountId(), + shared_model::permissions::can_set_detail); } bool CommandValidator::hasPermissions( @@ -635,10 +658,14 @@ namespace iroha { // 1. Creator set quorum for his account -> must have permission (creator_account_id == command.accountId() and checkAccountRolePermission( - creator_account_id, queries, model::can_set_quorum)) + creator_account_id, + queries, + shared_model::permissions::can_set_quorum)) // 2. Creator has granted permission on it or (queries.hasAccountGrantablePermission( - creator_account_id, command.accountId(), model::can_set_quorum)); + creator_account_id, + command.accountId(), + shared_model::permissions::can_set_quorum)); } bool CommandValidator::hasPermissions( @@ -647,7 +674,9 @@ namespace iroha { const shared_model::interface::types::AccountIdType &creator_account_id) { return creator_account_id == command.accountId() and checkAccountRolePermission( - creator_account_id, queries, model::can_subtract_asset_qty); + creator_account_id, + queries, + shared_model::permissions::can_subtract_asset_qty); } bool CommandValidator::hasPermissions( @@ -660,15 +689,18 @@ namespace iroha { and queries.hasAccountGrantablePermission( creator_account_id, command.srcAccountId(), - model::can_transfer)) + shared_model::permissions::can_transfer)) or // 2. Creator transfer from their account (creator_account_id == command.srcAccountId() and checkAccountRolePermission( - creator_account_id, queries, model::can_transfer))) + creator_account_id, + queries, + shared_model::permissions::can_transfer))) // For both cases, dest_account must have can_receive - and checkAccountRolePermission( - command.destAccountId(), queries, model::can_receive); + and checkAccountRolePermission(command.destAccountId(), + queries, + shared_model::permissions::can_receive); } bool CommandValidator::isValid( @@ -745,12 +777,12 @@ namespace iroha { const shared_model::interface::CreateRole &command, ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { - return std::all_of( - command.rolePermissions().begin(), - command.rolePermissions().end(), - [&queries, &creator_account_id](auto perm) { - return checkAccountRolePermission(creator_account_id, queries, perm); - }); + return std::all_of(command.rolePermissions().begin(), + command.rolePermissions().end(), + [&queries, &creator_account_id](auto perm) { + return checkAccountRolePermission( + creator_account_id, queries, perm); + }); } bool CommandValidator::isValid( @@ -772,8 +804,7 @@ namespace iroha { ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { auto account = queries.getAccount(command.accountId()); - auto signatories = - queries.getSignatories(command.accountId()); + auto signatories = queries.getSignatories(command.accountId()); if (not(account and signatories)) { // No account or signatories found @@ -803,8 +834,7 @@ namespace iroha { const shared_model::interface::SetQuorum &command, ametsuchi::WsvQuery &queries, const shared_model::interface::types::AccountIdType &creator_account_id) { - auto signatories = - queries.getSignatories(command.accountId()); + auto signatories = queries.getSignatories(command.accountId()); if (not(signatories)) { // No signatories of an account found diff --git a/irohad/model/converters/impl/pb_command_factory.cpp b/irohad/model/converters/impl/pb_command_factory.cpp index 3a68bb484c..9d1fbd1818 100644 --- a/irohad/model/converters/impl/pb_command_factory.cpp +++ b/irohad/model/converters/impl/pb_command_factory.cpp @@ -21,6 +21,8 @@ #include "model/converters/pb_common.hpp" +using namespace shared_model::permissions; + namespace iroha { namespace model { namespace converters { @@ -85,19 +87,24 @@ namespace iroha { // Can get all account assets (protocol::RolePermission::can_get_all_acc_ast, can_get_all_acc_ast) // Can get domain account assets - (protocol::RolePermission::can_get_domain_acc_ast, can_get_domain_acc_ast) + (protocol::RolePermission::can_get_domain_acc_ast, + can_get_domain_acc_ast) // Can get my account detail - (protocol::RolePermission::can_get_my_acc_detail, can_get_my_acc_detail) + (protocol::RolePermission::can_get_my_acc_detail, + can_get_my_acc_detail) // Can get all account detail - (protocol::RolePermission::can_get_all_acc_detail, can_get_all_acc_detail) + (protocol::RolePermission::can_get_all_acc_detail, + can_get_all_acc_detail) // Can get domain account detail - (protocol::RolePermission::can_get_domain_acc_detail, can_get_domain_acc_detail) + (protocol::RolePermission::can_get_domain_acc_detail, + can_get_domain_acc_detail) // Can get my account transactions (protocol::RolePermission::can_get_my_acc_txs, can_get_my_acc_txs) // Can get all account transactions (protocol::RolePermission::can_get_all_acc_txs, can_get_all_acc_txs) // Can get domain account transactions - (protocol::RolePermission::can_get_domain_acc_txs, can_get_domain_acc_txs) + (protocol::RolePermission::can_get_domain_acc_txs, + can_get_domain_acc_txs) // Can get my account assets transactions (protocol::RolePermission::can_get_my_acc_ast_txs, can_get_my_acc_ast_txs) @@ -142,7 +149,7 @@ namespace iroha { can_set_detail) // Can transfer my assets (protocol::GrantablePermission::can_transfer_my_assets, - can_transfer); + can_transfer); } // asset quantity diff --git a/irohad/model/generators/impl/command_generator.cpp b/irohad/model/generators/impl/command_generator.cpp index 5b79890bef..6c1fcd4220 100644 --- a/irohad/model/generators/impl/command_generator.cpp +++ b/irohad/model/generators/impl/command_generator.cpp @@ -32,6 +32,7 @@ #include "validators/permissions.hpp" using namespace generator; +using namespace shared_model::permissions; namespace iroha { namespace model { diff --git a/irohad/model/impl/query_execution.cpp b/irohad/model/impl/query_execution.cpp index 6feec625d0..cd68b41f35 100644 --- a/irohad/model/impl/query_execution.cpp +++ b/irohad/model/impl/query_execution.cpp @@ -23,6 +23,7 @@ #include "validators/permissions.hpp" using namespace iroha::model; +using namespace shared_model::permissions; using namespace iroha::ametsuchi; // TODO: 28/03/2018 x3medima17 remove poly wrapper, IR-1011 diff --git a/shared_model/validators/field_validator.cpp b/shared_model/validators/field_validator.cpp index 64cf17a4c3..5bd825fec0 100644 --- a/shared_model/validators/field_validator.cpp +++ b/shared_model/validators/field_validator.cpp @@ -18,8 +18,8 @@ #include "validators/field_validator.hpp" #include #include -#include "permissions.hpp" #include "cryptography/crypto_provider/crypto_verifier.hpp" +#include "permissions.hpp" // TODO: 15.02.18 nickaleks Change structure to compositional IR-978 @@ -213,8 +213,8 @@ namespace shared_model { void FieldValidator::validatePermission( ReasonsGroupType &reason, const interface::types::PermissionNameType &permission_name) const { - if (iroha::model::all_perm_group.find(permission_name) - == iroha::model::all_perm_group.end()) { + if (shared_model::permissions::all_perm_group.find(permission_name) + == shared_model::permissions::all_perm_group.end()) { reason.second.push_back("Provided permission does not exist"); } } @@ -226,8 +226,8 @@ namespace shared_model { reason.second.push_back( "Permission set should contain at least one permission"); } - if (not std::includes(iroha::model::role_perm_group.begin(), - iroha::model::role_perm_group.end(), + if (not std::includes(shared_model::permissions::role_perm_group.begin(), + shared_model::permissions::role_perm_group.end(), permissions.begin(), permissions.end())) { reason.second.push_back( diff --git a/shared_model/validators/permissions.hpp b/shared_model/validators/permissions.hpp index 0f692b0dfa..8c3e1281ae 100644 --- a/shared_model/validators/permissions.hpp +++ b/shared_model/validators/permissions.hpp @@ -15,14 +15,14 @@ * limitations under the License. */ -#ifndef IROHA_PERMISSIONS_HPP -#define IROHA_PERMISSIONS_HPP +#ifndef SHARED_MODEL_PERMISSIONS_HPP +#define SHARED_MODEL_PERMISSIONS_HPP #include #include -namespace iroha { - namespace model { +namespace shared_model { + namespace permissions { /* ~~~~~~~~ Command-related permissions ~~~~~~~~ */ @@ -252,7 +252,7 @@ namespace iroha { can_set_my_account_detail, can_transfer_my_assets}; - } // namespace model -} // namespace iroha + } // namespace shared_model +} // namespace permissions -#endif // IROHA_PERMISSIONS_HPP +#endif // SHARED_MODEL_PERMISSIONS_HPP diff --git a/test/framework/integration_framework/integration_test_framework.cpp b/test/framework/integration_framework/integration_test_framework.cpp index de9bccc4f9..d20bc3f546 100644 --- a/test/framework/integration_framework/integration_test_framework.cpp +++ b/test/framework/integration_framework/integration_test_framework.cpp @@ -75,12 +75,12 @@ DROP TABLE IF EXISTS index_by_id_height_asset; .txCounter(1) .createdTime(iroha::time::now()) .addPeer("0.0.0.0:50541", key.publicKey()) - .createRole( - kDefaultRole, - // TODO (@l4l) IR-874 create more confort way for - // permssion-dependent proto building - std::vector{iroha::model::role_perm_group.begin(), - iroha::model::role_perm_group.end()}) + .createRole(kDefaultRole, + // TODO (@l4l) IR-874 create more confort way for + // permssion-dependent proto building + std::vector{ + shared_model::permissions::role_perm_group.begin(), + shared_model::permissions::role_perm_group.end()}) .createDomain(kDefaultDomain, kDefaultRole) .createAccount(kAdminName, kDefaultDomain, key.publicKey()) .createAsset(kAssetName, kDefaultDomain, 1) diff --git a/test/framework/test_block_generator.cpp b/test/framework/test_block_generator.cpp index 3dd0a229cd..12081bc710 100644 --- a/test/framework/test_block_generator.cpp +++ b/test/framework/test_block_generator.cpp @@ -22,11 +22,12 @@ #include "model/commands/create_account.hpp" #include "model/commands/create_asset.hpp" #include "model/commands/create_domain.hpp" -#include "validators/permissions.hpp" #include "model/sha3_hash.hpp" +#include "validators/permissions.hpp" using namespace iroha; using namespace iroha::model; +using namespace shared_model::permissions; namespace framework { namespace generator { diff --git a/test/integration/acceptance/add_asset_qty_test.cpp b/test/integration/acceptance/add_asset_qty_test.cpp index ed49ed805e..5a66b3ec11 100644 --- a/test/integration/acceptance/add_asset_qty_test.cpp +++ b/test/integration/acceptance/add_asset_qty_test.cpp @@ -21,8 +21,8 @@ #include "datetime/time.hpp" #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -36,7 +36,7 @@ class AddAssetQuantity : public ::testing::Test { * @return built tx and a hash of its payload */ auto makeUserWithPerms(const std::vector &perms = { - iroha::model::can_add_asset_qty}) { + shared_model::permissions::can_add_asset_qty}) { return framework::createUserWithPerms( kUser, kUserKeypair.publicKey(), "role"s, perms) .build() @@ -100,7 +100,7 @@ TEST_F(AddAssetQuantity, Basic) { TEST_F(AddAssetQuantity, NoPermissions) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() .sendTx(completeTx(baseTx().addAssetQuantity(kUserId, kAsset, kAmount))) @@ -252,9 +252,9 @@ TEST_F(AddAssetQuantity, OtherDomain) { .creatorAccountId( integration_framework::IntegrationTestFramework::kAdminId) .createdTime(iroha::time::now()) - .createRole( - kNewRole, - std::vector{iroha::model::can_get_my_txs}) + .createRole(kNewRole, + std::vector{ + shared_model::permissions::can_get_my_txs}) .createDomain(kNewDomain, kNewRole) .createAccount( kNewUser, diff --git a/test/integration/acceptance/create_account_test.cpp b/test/integration/acceptance/create_account_test.cpp index e0f3512725..7eb2c60370 100644 --- a/test/integration/acceptance/create_account_test.cpp +++ b/test/integration/acceptance/create_account_test.cpp @@ -21,8 +21,8 @@ #include "datetime/time.hpp" #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -36,7 +36,7 @@ class CreateAccount : public ::testing::Test { * @return built tx and a hash of its payload */ auto makeUserWithPerms(const std::vector &perms = { - iroha::model::can_create_account}) { + shared_model::permissions::can_create_account}) { return framework::createUserWithPerms( kUser, kUserKeypair.publicKey(), "role"s, perms) .build() @@ -103,7 +103,7 @@ TEST_F(CreateAccount, Basic) { TEST_F(CreateAccount, NoPermissions) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() .sendTx(completeTx(baseTx().createAccount( diff --git a/test/integration/acceptance/create_domain_test.cpp b/test/integration/acceptance/create_domain_test.cpp index d8e3e73131..90a636a542 100644 --- a/test/integration/acceptance/create_domain_test.cpp +++ b/test/integration/acceptance/create_domain_test.cpp @@ -21,8 +21,8 @@ #include "datetime/time.hpp" #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -36,7 +36,7 @@ class CreateDomain : public ::testing::Test { * @return built tx */ auto makeUserWithPerms(const std::vector &perms = { - iroha::model::can_create_domain}) { + shared_model::permissions::can_create_domain}) { return framework::createUserWithPerms( kUser, kUserKeypair.publicKey(), kRole, perms) .build() @@ -100,7 +100,7 @@ TEST_F(CreateDomain, Basic) { TEST_F(CreateDomain, NoPermissions) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() .sendTx(completeTx(baseTx().createDomain(kNewDomain, kRole))) diff --git a/test/integration/acceptance/create_role_test.cpp b/test/integration/acceptance/create_role_test.cpp index 8f75a234f2..65b88943af 100644 --- a/test/integration/acceptance/create_role_test.cpp +++ b/test/integration/acceptance/create_role_test.cpp @@ -21,8 +21,8 @@ #include "datetime/time.hpp" #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -36,8 +36,8 @@ class CreateRole : public ::testing::Test { * @return built tx and a hash of its payload */ auto makeUserWithPerms(const std::vector &perms = { - iroha::model::can_get_my_txs, - iroha::model::can_create_role}) { + shared_model::permissions::can_get_my_txs, + shared_model::permissions::can_create_role}) { return framework::createUserWithPerms( kUser, kUserKeypair.publicKey(), kNewRole, perms) .build() @@ -60,7 +60,7 @@ class CreateRole : public ::testing::Test { } auto baseTx(const std::vector &perms = { - iroha::model::can_get_my_txs}) { + shared_model::permissions::can_get_my_txs}) { return baseTx(perms, kRole); } @@ -110,7 +110,7 @@ TEST_F(CreateRole, Basic) { TEST_F(CreateRole, HaveNoPerms) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() .sendTx(completeTx(baseTx())) @@ -131,7 +131,8 @@ TEST_F(CreateRole, EmptyRole) { .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx({iroha::model::can_get_my_txs}, ""))); + .sendTx( + completeTx(baseTx({shared_model::permissions::can_get_my_txs}, ""))); ASSERT_ANY_THROW(itf.skipProposal()); } @@ -163,8 +164,8 @@ TEST_F(CreateRole, LongRoleName) { .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx( - baseTx({iroha::model::can_get_my_txs}, std::string(33, 'a')))); + .sendTx(completeTx(baseTx({shared_model::permissions::can_get_my_txs}, + std::string(33, 'a')))); ASSERT_ANY_THROW(itf.skipProposal()); } @@ -179,8 +180,8 @@ TEST_F(CreateRole, MaxLenRoleName) { .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx( - baseTx({iroha::model::can_get_my_txs}, std::string(32, 'a')))) + .sendTx(completeTx(baseTx({shared_model::permissions::can_get_my_txs}, + std::string(32, 'a')))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) diff --git a/test/integration/acceptance/get_transactions_test.cpp b/test/integration/acceptance/get_transactions_test.cpp index a290197902..b21a37543c 100644 --- a/test/integration/acceptance/get_transactions_test.cpp +++ b/test/integration/acceptance/get_transactions_test.cpp @@ -23,8 +23,8 @@ #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" #include "interfaces/utils/specified_visitor.hpp" -#include "validators/permissions.hpp" #include "utils/query_error_response_visitor.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -39,7 +39,7 @@ class GetTransactions : public ::testing::Test { */ auto makeUserWithPerms(const std::vector &perms) { auto new_perms = perms; - new_perms.push_back(iroha::model::can_set_quorum); + new_perms.push_back(shared_model::permissions::can_set_quorum); return framework::createUserWithPerms( kUser, kUserKeypair.publicKey(), kNewRole, new_perms) .build() @@ -101,7 +101,7 @@ TEST_F(GetTransactions, HaveNoGetPerms) { auto dummy_tx = dummyTx(); IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_read_assets})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_read_assets})) .sendTx(dummy_tx) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) @@ -127,7 +127,7 @@ TEST_F(GetTransactions, HaveGetAllTx) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_all_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_all_txs})) .sendTx(dummy_tx) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) @@ -153,7 +153,7 @@ TEST_F(GetTransactions, HaveGetMyTx) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .sendTx(dummy_tx) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) @@ -187,7 +187,7 @@ TEST_F(GetTransactions, InvalidSignatures) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .sendQuery(query, check) .done(); } @@ -208,7 +208,7 @@ TEST_F(GetTransactions, InexistentHash) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_get_my_txs})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) .sendQuery(makeQuery(crypto::Hash(std::string(32, '0'))), check) @@ -230,7 +230,7 @@ TEST_F(GetTransactions, DISABLED_OtherUserTx) { ASSERT_EQ(resp.value()->transactions().size(), 0); }; - auto tx = makeUserWithPerms({iroha::model::can_get_my_txs}); + auto tx = makeUserWithPerms({shared_model::permissions::can_get_my_txs}); IntegrationTestFramework() .setInitialState(kAdminKeypair) .sendTx(tx) diff --git a/test/integration/acceptance/subtract_asset_qty_test.cpp b/test/integration/acceptance/subtract_asset_qty_test.cpp index 5cb78ecf57..c161ed4630 100644 --- a/test/integration/acceptance/subtract_asset_qty_test.cpp +++ b/test/integration/acceptance/subtract_asset_qty_test.cpp @@ -21,8 +21,8 @@ #include "datetime/time.hpp" #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -36,8 +36,8 @@ class SubtractAssetQuantity : public ::testing::Test { * @return built tx and a hash of its payload */ auto makeUserWithPerms(const std::vector &perms = { - iroha::model::can_subtract_asset_qty, - iroha::model::can_add_asset_qty}) { + shared_model::permissions::can_subtract_asset_qty, + shared_model::permissions::can_add_asset_qty}) { return framework::createUserWithPerms( kUser, kUserKeypair.publicKey(), "role"s, perms) .build() @@ -131,7 +131,7 @@ TEST_F(SubtractAssetQuantity, Overdraft) { TEST_F(SubtractAssetQuantity, NoPermissions) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({iroha::model::can_add_asset_qty})) + .sendTx(makeUserWithPerms({shared_model::permissions::can_add_asset_qty})) .sendTx(replenish()) .skipProposal() .skipBlock() diff --git a/test/integration/acceptance/transfer_asset_test.cpp b/test/integration/acceptance/transfer_asset_test.cpp index cb06c4657e..4d434166d6 100644 --- a/test/integration/acceptance/transfer_asset_test.cpp +++ b/test/integration/acceptance/transfer_asset_test.cpp @@ -25,9 +25,9 @@ #include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" #include "interfaces/utils/specified_visitor.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "utils/query_error_response_visitor.hpp" +#include "validators/permissions.hpp" using namespace std::string_literals; using namespace integration_framework; @@ -103,9 +103,10 @@ class TransferAsset : public ::testing::Test { crypto::DefaultCryptoAlgorithmType::generateKeypair(); const crypto::Keypair kUser2Keypair = crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const std::vector kPerms{iroha::model::can_add_asset_qty, - iroha::model::can_transfer, - iroha::model::can_receive}; + const std::vector kPerms{ + shared_model::permissions::can_add_asset_qty, + shared_model::permissions::can_transfer, + shared_model::permissions::can_receive}; }; /** @@ -137,8 +138,10 @@ TEST_F(TransferAsset, Basic) { TEST_F(TransferAsset, WithOnlyCanTransferPerm) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms( - kUser1, kUser1Keypair, {iroha::model::can_transfer}, kRole1)) + .sendTx(makeUserWithPerms(kUser1, + kUser1Keypair, + {shared_model::permissions::can_transfer}, + kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() @@ -160,8 +163,10 @@ TEST_F(TransferAsset, WithOnlyCanTransferPerm) { TEST_F(TransferAsset, WithOnlyCanReceivePerm) { IntegrationTestFramework() .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms( - kUser1, kUser1Keypair, {iroha::model::can_receive}, kRole1)) + .sendTx(makeUserWithPerms(kUser1, + kUser1Keypair, + {shared_model::permissions::can_receive}, + kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() @@ -406,7 +411,8 @@ TEST_F(TransferAsset, InterDomain) { integration_framework::IntegrationTestFramework::kAdminId) .createdTime(iroha::time::now()) .createRole(kNewRole, - std::vector{iroha::model::can_receive}) + std::vector{ + shared_model::permissions::can_receive}) .createDomain(kNewDomain, kNewRole) .createAccount( kUser2, diff --git a/test/integration/client_test.cpp b/test/integration/client_test.cpp index 5871442384..f914aadb57 100644 --- a/test/integration/client_test.cpp +++ b/test/integration/client_test.cpp @@ -58,6 +58,7 @@ using namespace iroha::validation; using namespace iroha::model::converters; using namespace iroha::model; using namespace shared_model::proto; +using namespace shared_model::permissions; using namespace std::chrono_literals; constexpr std::chrono::milliseconds proposal_delay = 10s; diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index 7089d9c0d1..3412c85601 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -24,10 +24,10 @@ #include "ametsuchi/mutable_storage.hpp" #include "builders/protobuf/transaction.hpp" #include "framework/test_subscriber.hpp" -#include "validators/permissions.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" #include "module/shared_model/builders/protobuf/test_block_builder.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" using namespace iroha::ametsuchi; using namespace framework::test_subscriber; @@ -195,9 +195,9 @@ TEST_F(AmetsuchiTest, SampleTest) { .createRole( "user", shared_model::interface::types::PermissionSetType{ - iroha::model::can_add_peer, - iroha::model::can_create_asset, - iroha::model::can_get_my_account}) + shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}) .createDomain(domain, "user") .createAccount(user1name, domain, fake_pubkey) .build()})) @@ -234,7 +234,7 @@ TEST_F(AmetsuchiTest, SampleTest) { // Block store tests auto hashes = {block1.hash(), block2.hash()}; validateCalls(blocks->getBlocks(1, 2), - [i = 0, &hashes](auto eachBlock) mutable { + [ i = 0, &hashes ](auto eachBlock) mutable { EXPECT_EQ(*(hashes.begin() + i), eachBlock->hash()); ++i; }, @@ -293,9 +293,10 @@ TEST_F(AmetsuchiTest, queryGetAccountAssetTransactionsTest) { TestTransactionBuilder() .creatorAccountId(admin) .createRole("user", - std::set{iroha::model::can_add_peer, - iroha::model::can_create_asset, - iroha::model::can_get_my_account}) + std::set{ + shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}) .createDomain(domain, "user") .createAccount(user1name, domain, fake_pubkey) .createAccount(user2name, domain, fake_pubkey) @@ -376,7 +377,7 @@ TEST_F(AmetsuchiTest, queryGetAccountAssetTransactionsTest) { // Block store test auto hashes = {block1.hash(), block2.hash(), block3.hash()}; validateCalls(blocks->getBlocks(1, 3), - [i = 0, &hashes](auto eachBlock) mutable { + [ i = 0, &hashes ](auto eachBlock) mutable { EXPECT_EQ(*(hashes.begin() + i), eachBlock->hash()); ++i; }, @@ -413,9 +414,10 @@ TEST_F(AmetsuchiTest, AddSignatoryTest) { TestTransactionBuilder() .creatorAccountId("adminone") .createRole("user", - std::set{iroha::model::can_add_peer, - iroha::model::can_create_asset, - iroha::model::can_get_my_account}) + std::set{ + shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}) .createDomain("domain", "user") .createAccount("userone", "domain", pubkey1) .build(); @@ -698,9 +700,10 @@ TEST_F(AmetsuchiTest, FindTxByHashTest) { TestTransactionBuilder() .creatorAccountId("admin1") .createRole("user", - std::set{iroha::model::can_add_peer, - iroha::model::can_create_asset, - iroha::model::can_get_my_account}) + std::set{ + shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}) .createDomain("domain", "user") .createAccount("userone", "domain", pubkey1) .build(); @@ -709,9 +712,10 @@ TEST_F(AmetsuchiTest, FindTxByHashTest) { TestTransactionBuilder() .creatorAccountId("admin1") .createRole("usertwo", - std::set{iroha::model::can_add_peer, - iroha::model::can_create_asset, - iroha::model::can_get_my_account}) + std::set{ + shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}) .createDomain("domaintwo", "user") .build(); @@ -866,12 +870,13 @@ TEST_F(AmetsuchiTest, TestRestoreWSV) { .txCounter(1) .createdTime(iroha::time::now()) .createRole(default_role, - std::vector{iroha::model::can_create_domain, - iroha::model::can_create_account, - iroha::model::can_add_asset_qty, - iroha::model::can_add_peer, - iroha::model::can_receive, - iroha::model::can_transfer}) + std::vector{ + shared_model::permissions::can_create_domain, + shared_model::permissions::can_create_account, + shared_model::permissions::can_add_asset_qty, + shared_model::permissions::can_add_peer, + shared_model::permissions::can_receive, + shared_model::permissions::can_transfer}) .createDomain(default_domain, default_role) .build() .signAndAddSignature( diff --git a/test/module/irohad/ametsuchi/kv_storage_test.cpp b/test/module/irohad/ametsuchi/kv_storage_test.cpp index 4d09b1179a..a91b2741d0 100644 --- a/test/module/irohad/ametsuchi/kv_storage_test.cpp +++ b/test/module/irohad/ametsuchi/kv_storage_test.cpp @@ -24,9 +24,9 @@ #include "ametsuchi/impl/storage_impl.hpp" #include "ametsuchi/mutable_storage.hpp" #include "model/block.hpp" -#include "validators/permissions.hpp" #include "model/sha3_hash.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" +#include "validators/permissions.hpp" // TODO: 14-02-2018 Alexey Chernyshov remove this after relocation to // shared_model https://soramitsu.atlassian.net/browse/IR-887 @@ -61,9 +61,9 @@ class KVTest : public AmetsuchiTest { iroha::model::CreateRole createRole; createRole.role_name = "user"; - createRole.permissions = {iroha::model::can_add_peer, - iroha::model::can_create_asset, - iroha::model::can_get_my_account}; + createRole.permissions = {shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}; // Create domain ru txn1_1.commands.push_back( diff --git a/test/module/irohad/model/command_validate_execute_test.cpp b/test/module/irohad/model/command_validate_execute_test.cpp index b82d35f85d..f0de843127 100644 --- a/test/module/irohad/model/command_validate_execute_test.cpp +++ b/test/module/irohad/model/command_validate_execute_test.cpp @@ -49,6 +49,7 @@ using namespace iroha; using namespace iroha::ametsuchi; using namespace iroha::model; using namespace framework::expected; +using namespace shared_model::permissions; class CommandValidateExecuteTest : public ::testing::Test { public: diff --git a/test/module/irohad/model/converters/json_commands_test.cpp b/test/module/irohad/model/converters/json_commands_test.cpp index dd816056f9..df227e5eca 100644 --- a/test/module/irohad/model/converters/json_commands_test.cpp +++ b/test/module/irohad/model/converters/json_commands_test.cpp @@ -43,6 +43,7 @@ using namespace rapidjson; using namespace iroha; using namespace iroha::model; using namespace iroha::model::converters; +using namespace shared_model::permissions; class JsonCommandTest : public ::testing::Test { public: diff --git a/test/module/irohad/model/converters/pb_commands_test.cpp b/test/module/irohad/model/converters/pb_commands_test.cpp index 6fe0fb1543..3b8bf4c783 100644 --- a/test/module/irohad/model/converters/pb_commands_test.cpp +++ b/test/module/irohad/model/converters/pb_commands_test.cpp @@ -37,6 +37,7 @@ #include "validators/permissions.hpp" using namespace iroha::model; +using namespace shared_model::permissions; void command_converter_test(iroha::model::Command &abstract_command) { auto factory = iroha::model::converters::PbCommandFactory(); diff --git a/test/module/irohad/torii/processor/query_processor_test.cpp b/test/module/irohad/torii/processor/query_processor_test.cpp index b842f0a3a5..b18cbbd1e1 100644 --- a/test/module/irohad/torii/processor/query_processor_test.cpp +++ b/test/module/irohad/torii/processor/query_processor_test.cpp @@ -15,9 +15,9 @@ * limitations under the License. */ -#include "validators/permissions.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/validation/validation_mocks.hpp" +#include "validators/permissions.hpp" #include "framework/test_subscriber.hpp" #include "model/queries/responses/error_response.hpp" @@ -91,7 +91,8 @@ TEST_F(QueryProcessorTest, QueryProcessorWhereInvokeInvalidQuery) { shared_model::proto::AccountBuilder().accountId(account_id).build()); auto role = "admin"; std::vector roles = {role}; - std::vector perms = {iroha::model::can_get_my_account}; + std::vector perms = { + shared_model::permissions::can_get_my_account}; EXPECT_CALL(*storage, getWsvQuery()).WillRepeatedly(Return(wsv_queries)); EXPECT_CALL(*storage, getBlockQuery()).WillRepeatedly(Return(block_queries)); @@ -147,7 +148,8 @@ TEST_F(QueryProcessorTest, QueryProcessorWithWrongKey) { shared_model::proto::AccountBuilder().accountId(account_id).build()); auto role = "admin"; std::vector roles = {role}; - std::vector perms = {iroha::model::can_get_my_account}; + std::vector perms = { + shared_model::permissions::can_get_my_account}; EXPECT_CALL(*storage, getWsvQuery()).WillRepeatedly(Return(wsv_queries)); EXPECT_CALL(*storage, getBlockQuery()).WillRepeatedly(Return(block_queries)); diff --git a/test/module/irohad/torii/torii_queries_test.cpp b/test/module/irohad/torii/torii_queries_test.cpp index 3a23bca782..2aab5b337d 100644 --- a/test/module/irohad/torii/torii_queries_test.cpp +++ b/test/module/irohad/torii/torii_queries_test.cpp @@ -27,10 +27,10 @@ limitations under the License. #include "model/converters/pb_common.hpp" #include "main/server_runner.hpp" -#include "validators/permissions.hpp" #include "torii/processor/query_processor_impl.hpp" #include "torii/query_client.hpp" #include "torii/query_service.hpp" +#include "validators/permissions.hpp" #include "builders/protobuf/queries.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" @@ -151,10 +151,11 @@ TEST_F(ToriiQueriesTest, FindAccountWhenNoGrantPermissions) { account.account_id = "b@domain"; auto creator = "a@domain"; - EXPECT_CALL( - *wsv_query, - hasAccountGrantablePermission( - creator, account.account_id, iroha::model::can_get_my_account)) + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + creator, + account.account_id, + shared_model::permissions::can_get_my_account)) .WillOnce(Return(false)); EXPECT_CALL(*wsv_query, getSignatories(creator)) @@ -193,10 +194,11 @@ TEST_F(ToriiQueriesTest, FindAccountWhenHasReadPermissions) { EXPECT_CALL(*wsv_query, getSignatories(creator)) .WillRepeatedly(Return(signatories)); - EXPECT_CALL( - *wsv_query, - hasAccountGrantablePermission( - creator, accountB->accountId(), iroha::model::can_get_my_account)) + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + creator, + accountB->accountId(), + shared_model::permissions::can_get_my_account)) .WillOnce(Return(true)); // Should be called once, after successful stateful validation @@ -239,7 +241,8 @@ TEST_F(ToriiQueriesTest, FindAccountWhenHasRolePermission) { std::vector roles = {"test"}; EXPECT_CALL(*wsv_query, getAccountRoles(creator)) .WillRepeatedly(Return(roles)); - std::vector perm = {iroha::model::can_get_my_account}; + std::vector perm = { + shared_model::permissions::can_get_my_account}; EXPECT_CALL(*wsv_query, getRolePermissions("test")).WillOnce(Return(perm)); iroha::protocol::QueryResponse response; @@ -276,9 +279,10 @@ TEST_F(ToriiQueriesTest, FindAccountAssetWhenNoGrantPermissions) { EXPECT_CALL(*wsv_query, getSignatories(creator)) .WillRepeatedly(Return(signatories)); - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - creator, accountb_id, iroha::model::can_get_my_acc_ast)) + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + creator, accountb_id, shared_model::permissions::can_get_my_acc_ast)) .WillOnce(Return(false)); EXPECT_CALL(*wsv_query, getAccountRoles(creator)) .WillOnce(Return(boost::none)); @@ -332,7 +336,8 @@ TEST_F(ToriiQueriesTest, FindAccountAssetWhenHasRolePermissions) { .WillRepeatedly(Return(signatories)); std::vector roles = {"test"}; EXPECT_CALL(*wsv_query, getAccountRoles(creator)).WillOnce(Return(roles)); - std::vector perm = {iroha::model::can_get_my_acc_ast}; + std::vector perm = { + shared_model::permissions::can_get_my_acc_ast}; EXPECT_CALL(*wsv_query, getRolePermissions("test")).WillOnce(Return(perm)); EXPECT_CALL(*wsv_query, getAccountAsset(_, _)) .WillOnce(Return(account_asset)); @@ -386,7 +391,9 @@ TEST_F(ToriiQueriesTest, FindSignatoriesWhenNoGrantPermissions) { .WillRepeatedly(Return(signatories)); EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - creator, "b@domain", iroha::model::can_get_my_signatories)) + creator, + "b@domain", + shared_model::permissions::can_get_my_signatories)) .WillOnce(Return(false)); EXPECT_CALL(*wsv_query, getAccountRoles(creator)) .WillOnce(Return(boost::none)); @@ -425,7 +432,8 @@ TEST_F(ToriiQueriesTest, FindSignatoriesHasRolePermissions) { std::vector roles = {"test"}; EXPECT_CALL(*wsv_query, getAccountRoles(creator)).WillOnce(Return(roles)); - std::vector perm = {iroha::model::can_get_my_signatories}; + std::vector perm = { + shared_model::permissions::can_get_my_signatories}; EXPECT_CALL(*wsv_query, getRolePermissions("test")).WillOnce(Return(perm)); iroha::protocol::QueryResponse response; @@ -482,7 +490,8 @@ TEST_F(ToriiQueriesTest, FindTransactionsWhenValid) { .WillRepeatedly(Return(signatories)); std::vector roles = {"test"}; EXPECT_CALL(*wsv_query, getAccountRoles(creator)).WillOnce(Return(roles)); - std::vector perm = {iroha::model::can_get_my_acc_txs}; + std::vector perm = { + shared_model::permissions::can_get_my_acc_txs}; EXPECT_CALL(*wsv_query, getRolePermissions("test")).WillOnce(Return(perm)); EXPECT_CALL(*block_query, getAccountTransactions(creator)) .WillOnce(Return(txs_observable)); diff --git a/test/module/irohad/validation/query_execution.cpp b/test/module/irohad/validation/query_execution.cpp index 996882270b..5fc8c9be67 100644 --- a/test/module/irohad/validation/query_execution.cpp +++ b/test/module/irohad/validation/query_execution.cpp @@ -39,6 +39,7 @@ using ::testing::_; using namespace iroha::ametsuchi; using namespace iroha::model; using namespace framework::test_subscriber; +using namespace shared_model::permissions; using wTransaction = std::shared_ptr; diff --git a/test/module/shared_model/validators/field_validator_test.cpp b/test/module/shared_model/validators/field_validator_test.cpp index 5c801c92f5..31c43f5dcd 100644 --- a/test/module/shared_model/validators/field_validator_test.cpp +++ b/test/module/shared_model/validators/field_validator_test.cpp @@ -29,10 +29,10 @@ #include "backend/protobuf/common_objects/peer.hpp" #include "builders/protobuf/queries.hpp" #include "builders/protobuf/transaction.hpp" -#include "validators/permissions.hpp" #include "module/shared_model/validators/validators_fixture.hpp" #include "utils/lazy_initializer.hpp" #include "validators/field_validator.hpp" +#include "validators/permissions.hpp" using namespace shared_model; @@ -516,14 +516,15 @@ class FieldValidatorTest : public ValidatorsTest { "too big quorum size", &FieldValidatorTest::quorum, 129, false, "")}; std::vector permissionTestCases() { - auto valid_cases = iroha::model::role_perm_group + auto valid_cases = + shared_model::permissions::role_perm_group | boost::adaptors::transformed([&](const auto &permission) { - return this->makeTestCase(permission, - &FieldValidatorTest::permission, - permission, - true, - ""); - }); + return this->makeTestCase(permission, + &FieldValidatorTest::permission, + permission, + true, + ""); + }); std::vector invalid_cases = { makeInvalidCase("non existing permission", "permission", From 1d1a02ad1bb838ee02ad717fa4b8d098f373be11 Mon Sep 17 00:00:00 2001 From: Kitsu Date: Tue, 10 Apr 2018 15:24:07 +0300 Subject: [PATCH 007/110] Remove empty files (#1197) Signed-off-by: Eugene Minibaev --- deploy/ansible/playbooks/iroha-docker-cluster/main.yml | 0 test/integration/pipeline/tx_pipeline_integration_test.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 deploy/ansible/playbooks/iroha-docker-cluster/main.yml delete mode 100644 test/integration/pipeline/tx_pipeline_integration_test.cpp diff --git a/deploy/ansible/playbooks/iroha-docker-cluster/main.yml b/deploy/ansible/playbooks/iroha-docker-cluster/main.yml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/integration/pipeline/tx_pipeline_integration_test.cpp b/test/integration/pipeline/tx_pipeline_integration_test.cpp deleted file mode 100644 index e69de29bb2..0000000000 From 80bae880c5bfc07bb2d219823c5d770be7113685 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Tue, 10 Apr 2018 15:57:28 +0300 Subject: [PATCH 008/110] Uploading of the build artifacts (#1170) * upload artifacts on successful build Signed-off-by: Artyom Bakhtin * temporarily disable mac coverage Signed-off-by: Artyom Bakhtin * remove WIP Signed-off-by: Artyom Bakhtin * replace artifacts.groovy paths concat with a more elegant version Signed-off-by: Artyom Bakhtin --- .jenkinsci/artifacts.groovy | 44 ++++++++++ .jenkinsci/debug-build.groovy | 11 +-- .jenkinsci/linux-post-step.groovy | 22 +++++ .jenkinsci/mac-release-build.groovy | 28 +++++++ Jenkinsfile | 126 +++++++++++++--------------- 5 files changed, 154 insertions(+), 77 deletions(-) create mode 100644 .jenkinsci/artifacts.groovy create mode 100644 .jenkinsci/linux-post-step.groovy create mode 100644 .jenkinsci/mac-release-build.groovy diff --git a/.jenkinsci/artifacts.groovy b/.jenkinsci/artifacts.groovy new file mode 100644 index 0000000000..3a5aa0a68b --- /dev/null +++ b/.jenkinsci/artifacts.groovy @@ -0,0 +1,44 @@ +#!/usr/bin/env groovy + +def uploadArtifacts(filePaths, uploadPath, artifactServers=['artifact.soramitsu.co.jp']) { + def baseUploadPath = 'files' + def filePathsConverted = [] + agentType = sh(script: 'uname', returnStdout: true).trim() + uploadPath = baseUploadPath + uploadPath + filePaths.each { + fp = sh(script: "ls -d ${it} | tr '\n' ','", returnStdout: true).trim() + filePathsConverted.addAll(fp.split(',')) + } + def shaSumBinary = 'sha256sum' + def md5SumBinary = 'md5sum' + if (agentType == 'Darwin') { + shaSumBinary = 'shasum -a 256' + md5SumBinary = 'md5 -r' + } + sh "> \$(pwd)/batch.txt" + filePathsConverted.each { + sh "echo put ${it} $uploadPath >> \$(pwd)/batch.txt;" + sh "$shaSumBinary ${it} | cut -d' ' -f1 > \$(pwd)/\$(basename ${it}).sha256" + sh "$md5SumBinary ${it} | cut -d' ' -f1 > \$(pwd)/\$(basename ${it}).md5" + sh "echo put \$(pwd)/\$(basename ${it}).sha256 $uploadPath >> \$(pwd)/batch.txt;" + sh "echo put \$(pwd)/\$(basename ${it}).md5 $uploadPath >> \$(pwd)/batch.txt;" + } + // mkdirs recursively + uploadPath = uploadPath.split('/') + def p = '' + sh "> \$(pwd)/mkdirs.txt" + uploadPath.each { + p += "/${it}" + sh("echo -mkdir $p >> \$(pwd)/mkdirs.txt") + } + + sshagent(['jenkins-artifact']) { + sh "ssh-agent" + artifactServers.each { + sh "sftp -b \$(pwd)/mkdirs.txt jenkins@${it} || true" + sh "sftp -b \$(pwd)/batch.txt jenkins@${it}" + } + } +} + +return this diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index dd430e67d6..5d934dd8fa 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -40,7 +40,8 @@ def doDebugBuild(coverageEnabled=false) { + " -e IROHA_POSTGRES_USER=${env.IROHA_POSTGRES_USER}" + " -e IROHA_POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" + " --network=${env.IROHA_NETWORK}" - + " -v /var/jenkins/ccache:${CCACHE_DIR}") { + + " -v /var/jenkins/ccache:${CCACHE_DIR}" + + " -v /tmp/${GIT_COMMIT}-${BUILD_NUMBER}:/tmp/${GIT_COMMIT}") { def scmVars = checkout scm def cmakeOptions = "" @@ -95,12 +96,8 @@ def doDebugBuild(coverageEnabled=false) { sh "python /tmp/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false } - - // TODO: replace with upload to artifactory server - // develop branch only - if ( env.BRANCH_NAME == "develop" ) { - //archive(includes: 'build/bin/,compile_commands.json') - } + // copy built binaries to the volume + sh "cp ./build/bin/* /tmp/${GIT_COMMIT}/" } } return this diff --git a/.jenkinsci/linux-post-step.groovy b/.jenkinsci/linux-post-step.groovy new file mode 100644 index 0000000000..0dc8611445 --- /dev/null +++ b/.jenkinsci/linux-post-step.groovy @@ -0,0 +1,22 @@ +def linuxPostStep() { + timeout(time: 600, unit: "SECONDS") { + try { + if (currentBuild.result != "UNSTABLE" && BRANCH_NAME ==~ /(master|develop)/) { + def artifacts = load ".jenkinsci/artifacts.groovy" + def commit = env.GIT_COMMIT + def platform = sh(script: 'uname -m', returnStdout: true).trim() + filePaths = [ '/tmp/${GIT_COMMIT}-${BUILD_NUMBER}/*' ] + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/linux/%4%s/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6), platform])) + } + } + finally { + if (env.BUILD_TYPE == 'Debug') { + def cleanup = load ".jenkinsci/docker-cleanup.groovy" + cleanup.doDockerCleanup() + } + cleanWs() + } + } +} + +return this diff --git a/.jenkinsci/mac-release-build.groovy b/.jenkinsci/mac-release-build.groovy new file mode 100644 index 0000000000..b799e19200 --- /dev/null +++ b/.jenkinsci/mac-release-build.groovy @@ -0,0 +1,28 @@ +#!/usr/bin/env groovy + +def doReleaseBuild(coverageEnabled=false) { + def scmVars = checkout scm + env.IROHA_VERSION = "0x${scmVars.GIT_COMMIT}" + env.IROHA_HOME = "/opt/iroha" + env.IROHA_BUILD = "${env.IROHA_HOME}/build" + + sh """ + export CCACHE_DIR=${CCACHE_RELEASE_DIR} + ccache --version + ccache --show-stats + ccache --zero-stats + ccache --max-size=1G + + cmake -H. \ + -Bbuild \ + -DCOVERAGE=OFF \ + -DPACKAGE_TGZ=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DIROHA_VERSION=${env.IROHA_VERSION} + + cmake --build build --target package -- -j${params.PARALLELISM} + ccache --show-stats + """ +} + +return this diff --git a/Jenkinsfile b/Jenkinsfile index 8a33536581..7975707397 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -109,11 +109,8 @@ pipeline { post { always { script { - timeout(time: 60, unit: "SECONDS") { - def cleanup = load ".jenkinsci/docker-cleanup.groovy" - cleanup.doDockerCleanup() - cleanWs() - } + post = load ".jenkinsci/linux-post-step.groovy" + post.linuxPostStep() } } } @@ -140,11 +137,8 @@ pipeline { post { always { script { - timeout(time: 60, unit: "SECONDS") { - def cleanup = load ".jenkinsci/docker-cleanup.groovy" - cleanup.doDockerCleanup() - cleanWs() - } + post = load ".jenkinsci/linux-post-step.groovy" + post.linuxPostStep() } } } @@ -171,11 +165,8 @@ pipeline { post { always { script { - timeout(time: 60, unit: "SECONDS") { - def cleanup = load ".jenkinsci/docker-cleanup.groovy" - cleanup.doDockerCleanup() - cleanWs() - } + post = load ".jenkinsci/linux-post-step.groovy" + post.linuxPostStep() } } } @@ -246,25 +237,34 @@ pipeline { sh "cmake --build build --target coverage.info" sh "python /usr/local/bin/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false - } - - // TODO: replace with upload to artifactory server - // only develop branch - if ( env.BRANCH_NAME == "develop" ) { - //archive(includes: 'build/bin/,compile_commands.json') + if (BRANCH_NAME ==~ /(master|develop)/) { + releaseBuild = load ".jenkinsci/mac-release-build.groovy" + releaseBuild.doReleaseBuild() } } } post { always { script { - timeout(time: 60, unit: "SECONDS") { - cleanWs() - sh """ - pg_ctl -D /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ stop && \ - rm -rf /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ - """ + timeout(time: 600, unit: "SECONDS") { + if (currentBuild.result != "UNSTABLE") { + if (BRANCH_NAME ==~ /(master|develop)/) { + try { + def artifacts = load ".jenkinsci/artifacts.groovy" + def commit = env.GIT_COMMIT + filePaths = [ '\$(pwd)/build/*.tar.gz' ] + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) + } + finally { + cleanWs() + sh """ + pg_ctl -D /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ stop && \ + rm -rf /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ + """ + } + } + } } } } @@ -282,7 +282,7 @@ pipeline { parallel { stage('Linux') { when { expression { return params.Linux } } - agent { label 'linux && x86_64' } + agent { label 'x86_64' } steps { script { def releaseBuild = load ".jenkinsci/release-build.groovy" @@ -292,11 +292,8 @@ pipeline { post { always { script { - timeout(time: 60, unit: "SECONDS") { - def cleanup = load ".jenkinsci/docker-cleanup.groovy" - cleanup.doDockerCleanup() - cleanWs() - } + post = load ".jenkinsci/linux-post-step.groovy" + post.linuxPostStep() } } } @@ -313,14 +310,11 @@ pipeline { post { always { script { - timeout(time: 60, unit: "SECONDS") { - def cleanup = load ".jenkinsci/docker-cleanup.groovy" - cleanup.doDockerCleanup() - cleanWs() - } + post = load ".jenkinsci/linux-post-step.groovy" + post.linuxPostStep() } } - } + } } stage('ARMv8') { when { expression { return params.ARMv8 } } @@ -334,44 +328,36 @@ pipeline { post { always { script { - timeout(time: 60, unit: "SECONDS") { - def cleanup = load ".jenkinsci/docker-cleanup.groovy" - cleanup.doDockerCleanup() - cleanWs() - } + post = load ".jenkinsci/linux-post-step.groovy" + post.linuxPostStep() } } - } + } } stage('MacOS') { when { expression { return params.MacOS } } steps { script { - def scmVars = checkout scm - env.IROHA_VERSION = "0x${scmVars.GIT_COMMIT}" - env.IROHA_HOME = "/opt/iroha" - env.IROHA_BUILD = "${env.IROHA_HOME}/build" - - sh """ - ccache --version - ccache --show-stats - ccache --zero-stats - ccache --max-size=5G - """ - sh """ - cmake \ - -H. \ - -Bbuild \ - -DCMAKE_BUILD_TYPE=${params.BUILD_TYPE} \ - -DIROHA_VERSION=${env.IROHA_VERSION} - """ - sh "cmake --build build -- -j${params.PARALLELISM}" - sh "ccache --show-stats" - - // TODO: replace with upload to artifactory server - // only develop branch - if ( env.BRANCH_NAME == "develop" ) { - //archive(includes: 'build/bin/,compile_commands.json') + def releaseBuild = load ".jenkinsci/mac-release-build.groovy" + releaseBuild.doReleaseBuild() + } + } + post { + always { + script { + timeout(time: 600, unit: "SECONDS") { + if (BRANCH_NAME ==~ /(master|develop)/) { + try { + def artifacts = load ".jenkinsci/artifacts.groovy" + def commit = env.GIT_COMMIT + filePaths = [ '\$(pwd)/build/*.tar.gz' ] + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) + } + finally { + cleanWs() + } + } + } } } } From 8e3944f5a5f4da94cdd25feb6cfc41c9b215c438 Mon Sep 17 00:00:00 2001 From: Bulat Nasrulin Date: Wed, 11 Apr 2018 14:21:35 +0800 Subject: [PATCH 009/110] Add comments, apply clang-format in keys_manager (#1195) Signed-off-by: grimadas --- libs/crypto/keys_manager_impl.cpp | 4 +++- test/module/libs/crypto/keys_manager_test.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libs/crypto/keys_manager_impl.cpp b/libs/crypto/keys_manager_impl.cpp index f9a9973605..8b9b2d1eb7 100644 --- a/libs/crypto/keys_manager_impl.cpp +++ b/libs/crypto/keys_manager_impl.cpp @@ -58,8 +58,10 @@ namespace iroha { template static std::string encrypt(const T &key, const std::string &pass_phrase) { std::string ciphertext(key.size(), '\0'); + // pass_size will always be > 0 const auto pass_size = std::max(1ul, pass_phrase.size()); - + // When pass_phrase is empty it, pass_phrase[0] is "\0", so no out_of_range + // exception is possible for (auto i = 0u; i < key.size(); i++) { ciphertext[i] = key[i] ^ pass_phrase[i % pass_size]; } diff --git a/test/module/libs/crypto/keys_manager_test.cpp b/test/module/libs/crypto/keys_manager_test.cpp index 1244b5783e..d461c49631 100644 --- a/test/module/libs/crypto/keys_manager_test.cpp +++ b/test/module/libs/crypto/keys_manager_test.cpp @@ -60,9 +60,10 @@ class KeyManager : public ::testing::Test { "36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80"s; KeysManagerImpl manager = KeysManagerImpl(filepath); const std::string passphrase = "test"; - const std::string nonexistent = (boost::filesystem::temp_directory_path() - / "path" / "that" / "doesnt" / "exist") - .string(); + const std::string nonexistent = + (boost::filesystem::temp_directory_path() / "path" / "that" / "doesnt" + / "exist") + .string(); }; TEST_F(KeyManager, LoadNonExistentKeyFile) { From ebcf06d38068784951d3622ebf326bdb71fcb4c0 Mon Sep 17 00:00:00 2001 From: Dumitru Date: Wed, 11 Apr 2018 22:14:56 +0300 Subject: [PATCH 010/110] Replace signature with signatures (#1203) Signed-off-by: Dumitru --- irohad/model/converters/impl/pb_transaction_factory.cpp | 4 ++-- schema/block.proto | 2 +- shared_model/backend/protobuf/transaction.hpp | 4 ++-- test/integration/acceptance/invalid_fields_test.cpp | 4 ++-- .../backend_proto/shared_proto_transaction_test.cpp | 2 +- test/module/shared_model/validators/field_validator_test.cpp | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/irohad/model/converters/impl/pb_transaction_factory.cpp b/irohad/model/converters/impl/pb_transaction_factory.cpp index c4fc9ec257..91c5d10145 100644 --- a/irohad/model/converters/impl/pb_transaction_factory.cpp +++ b/irohad/model/converters/impl/pb_transaction_factory.cpp @@ -43,7 +43,7 @@ namespace iroha { } for (const auto &sig_obj : tx.signatures) { - auto proto_signature = pbtx.add_signature(); + auto proto_signature = pbtx.add_signatures(); proto_signature->set_pubkey(sig_obj.pubkey.to_string()); proto_signature->set_signature(sig_obj.signature.to_string()); } @@ -60,7 +60,7 @@ namespace iroha { tx.creator_account_id = pl.creator_account_id(); tx.created_ts = pl.created_time(); - for (const auto &pb_sig : pb_tx.signature()) { + for (const auto &pb_sig : pb_tx.signatures()) { model::Signature sig{}; sig.pubkey = pubkey_t::from_string(pb_sig.pubkey()); sig.signature = sig_t::from_string(pb_sig.signature()); diff --git a/schema/block.proto b/schema/block.proto index 3b37491963..4563e995e0 100644 --- a/schema/block.proto +++ b/schema/block.proto @@ -17,7 +17,7 @@ message Header { } Payload payload = 1; - repeated Signature signature = 2; + repeated Signature signatures = 2; } message Block { diff --git a/shared_model/backend/protobuf/transaction.hpp b/shared_model/backend/protobuf/transaction.hpp index 76a5caca49..f78c22ad77 100644 --- a/shared_model/backend/protobuf/transaction.hpp +++ b/shared_model/backend/protobuf/transaction.hpp @@ -79,7 +79,7 @@ namespace shared_model { return false; } - auto sig = proto_->add_signature(); + auto sig = proto_->add_signatures(); sig->set_signature(crypto::toBinaryString(signed_blob)); sig->set_pubkey(crypto::toBinaryString(public_key)); @@ -119,7 +119,7 @@ namespace shared_model { [this] { return makeBlob(payload_); }}; const Lazy signatures_{[this] { - return boost::accumulate(proto_->signature(), + return boost::accumulate(proto_->signatures(), interface::SignatureSetType{}, [](auto &&acc, const auto &sig) { acc.emplace(new Signature(sig)); diff --git a/test/integration/acceptance/invalid_fields_test.cpp b/test/integration/acceptance/invalid_fields_test.cpp index e5bdbbfdec..8134b11bb5 100644 --- a/test/integration/acceptance/invalid_fields_test.cpp +++ b/test/integration/acceptance/invalid_fields_test.cpp @@ -53,7 +53,7 @@ TEST_F(InvalidField, Signature) { .signAndAddSignature(kAdminKeypair) .getTransport(); // extend signature to invalid size - auto sig = tx.mutable_signature(0)->mutable_signature(); + auto sig = tx.mutable_signatures(0)->mutable_signature(); sig->resize(sig->size() + 1, 'a'); auto check = [](auto &resp) { ASSERT_TRUE(boost::apply_visitor( @@ -82,7 +82,7 @@ TEST_F(InvalidField, Pubkey) { .signAndAddSignature(kAdminKeypair) .getTransport(); // extend public key to invalid size - auto pkey = tx.mutable_signature(0)->mutable_pubkey(); + auto pkey = tx.mutable_signatures(0)->mutable_pubkey(); pkey->resize(pkey->size() + 1, 'a'); auto check = [](auto &resp) { ASSERT_TRUE(boost::apply_visitor( diff --git a/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp b/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp index 297b0a2067..aeb294cbbb 100644 --- a/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp +++ b/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp @@ -93,7 +93,7 @@ TEST(ProtoTransaction, Builder) { shared_model::crypto::Blob(proto_tx.payload().SerializeAsString()), keypair); - auto sig = proto_tx.add_signature(); + auto sig = proto_tx.add_signatures(); sig->set_pubkey(shared_model::crypto::toBinaryString(keypair.publicKey())); sig->set_signature(shared_model::crypto::toBinaryString(signedProto)); diff --git a/test/module/shared_model/validators/field_validator_test.cpp b/test/module/shared_model/validators/field_validator_test.cpp index 31c43f5dcd..f7a7630896 100644 --- a/test/module/shared_model/validators/field_validator_test.cpp +++ b/test/module/shared_model/validators/field_validator_test.cpp @@ -655,7 +655,7 @@ TEST_F(FieldValidatorTest, CommandFieldsValidation) { */ TEST_F(FieldValidatorTest, TransactionFieldsValidation) { iroha::protocol::Transaction proto_tx; - proto_tx.add_signature(); // at least one signature in message + proto_tx.add_signatures(); // at least one signature in message // iterate over all fields in transaction iterateContainer( From 520674774b190cf2486c6ef526b151b29e56cf93 Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Wed, 11 Apr 2018 19:02:57 +0300 Subject: [PATCH 011/110] Fix toString in account Signed-off-by: Fedor Muratov --- shared_model/interfaces/common_objects/account.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared_model/interfaces/common_objects/account.hpp b/shared_model/interfaces/common_objects/account.hpp index 545d5aa335..3e22a276b7 100644 --- a/shared_model/interfaces/common_objects/account.hpp +++ b/shared_model/interfaces/common_objects/account.hpp @@ -65,6 +65,7 @@ namespace shared_model { .append("accountId", accountId()) .append("domainId", domainId()) .append("quorum", std::to_string(quorum())) + .append("json", jsonData()) .finalize(); } From a9f49237c37806cf9d695c3496416ae799d21d12 Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Thu, 12 Apr 2018 15:28:50 +0300 Subject: [PATCH 012/110] Tests for heavy transactions (#1198) Tests for heavy transactions and queries Signed-off-by: Fedor Muratov --- shared_model/validators/field_validator.cpp | 3 +- test/integration/acceptance/CMakeLists.txt | 9 + test/integration/acceptance/tx_heavy_data.cpp | 234 ++++++++++++++++++ 3 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 test/integration/acceptance/tx_heavy_data.cpp diff --git a/shared_model/validators/field_validator.cpp b/shared_model/validators/field_validator.cpp index 5bd825fec0..725def24e3 100644 --- a/shared_model/validators/field_validator.cpp +++ b/shared_model/validators/field_validator.cpp @@ -47,7 +47,8 @@ namespace shared_model { const std::string FieldValidator::role_id_pattern_ = R"#([a-z_0-9]{1,32})#"; const size_t FieldValidator::public_key_size = 32; - const size_t FieldValidator::value_size = 4096; + /// limit for the set account detail size in bytes + const size_t FieldValidator::value_size = 4 * 1024 * 1024; const size_t FieldValidator::description_size = 64; FieldValidator::FieldValidator(time_t future_gap) diff --git a/test/integration/acceptance/CMakeLists.txt b/test/integration/acceptance/CMakeLists.txt index 990bed52eb..e73ab3769e 100644 --- a/test/integration/acceptance/CMakeLists.txt +++ b/test/integration/acceptance/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(tx_acceptance_test integration_framework shared_model_stateless_validation ) + addtest(get_transactions_test get_transactions_test.cpp) target_link_libraries(get_transactions_test application @@ -86,3 +87,11 @@ target_link_libraries(create_account_test shared_model_proto_builders shared_model_stateless_validation ) + +addtest(tx_heavy_data tx_heavy_data.cpp) +target_link_libraries(tx_heavy_data + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) diff --git a/test/integration/acceptance/tx_heavy_data.cpp b/test/integration/acceptance/tx_heavy_data.cpp new file mode 100644 index 0000000000..1bc11d0720 --- /dev/null +++ b/test/integration/acceptance/tx_heavy_data.cpp @@ -0,0 +1,234 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "builders/protobuf/queries.hpp" +#include "builders/protobuf/transaction.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" +#include "datetime/time.hpp" +#include "framework/base_tx.hpp" +#include "framework/integration_framework/integration_test_framework.hpp" +#include "interfaces/utils/specified_visitor.hpp" +#include "module/shared_model/builders/protobuf/test_query_builder.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" + +using namespace std::string_literals; +using namespace integration_framework; +using namespace shared_model; + +class HeavyTransactionTest : public ::testing::Test { + public: + /** + * Creates the transaction with the user creation commands + * @param perms are the permissions of the user + * @return built tx and a hash of its payload + */ + auto makeUserWithPerms( + const std::vector &perms = { + shared_model::permissions::role_perm_group.begin(), + shared_model::permissions::role_perm_group.end()}) { + return framework::createUserWithPerms( + kUser, kUserKeypair.publicKey(), "role"s, perms) + .build() + .signAndAddSignature(kAdminKeypair); + } + + /** + * Create valid base pre-built transaction + * @return pre-built tx + */ + auto baseTx() { + return TestUnsignedTransactionBuilder() + .txCounter(1) + .creatorAccountId(kUserId) + .createdTime(iroha::time::now()); + } + + /** + * Generate stub of transaction for setting data to default user account + * @param key - key for the insertion + * @param value - data that will be attached + * @return generated builder, without signature + */ + auto setAcountDetailTx(const std::string &key, const std::string &value) { + return baseTx().setAccountDetail(kUserId, key, value); + } + + /** + * Util method for stub data generation + * @param quantity - number of bytes + * @return new string with passed quantity length + */ + static auto generateData(size_t quantity) { + return std::string(quantity, 'F'); + } + + /** + * Sign pre-built object + * @param builder is a pre-built signable object + * @return completed object + */ + template + auto complete(Builder builder) { + return builder.build().signAndAddSignature(kUserKeypair); + } + + /** + * Create valid basis of pre-built query + * @return query stub with counter, creator and time + */ + auto baseQuery() { + return TestUnsignedQueryBuilder() + .queryCounter(1) + .creatorAccountId(kUserId) + .createdTime(iroha::time::now()); + } + + const std::string kUser = "user"s; + const std::string kUserId = + kUser + "@"s + IntegrationTestFramework::kDefaultDomain; + const crypto::Keypair kUserKeypair = + crypto::DefaultCryptoAlgorithmType::generateKeypair(); + const crypto::Keypair kAdminKeypair = + crypto::DefaultCryptoAlgorithmType::generateKeypair(); +}; + +/** + * @given some user with all required permissions + * @when send tx with addAccountDetail with big, but stateless invalid data + * inside + * @then transaction is passed + */ +TEST_F(HeavyTransactionTest, OneLargeTx) { + IntegrationTestFramework() + .setInitialState(kAdminKeypair) + .sendTx(makeUserWithPerms()) + .skipProposal() + .checkBlock( + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + // "foo" transactions will not be passed because it has large size into + // one field - 5Mb per one set + .sendTx(complete(setAcountDetailTx("foo", generateData(5 * 1024 * 1024)))) + .skipProposal() + .checkBlock( + [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) + .done(); +} + +/** + * NOTE: test is disabled until fix of + * https://soramitsu.atlassian.net/browse/IR-1205 will not be completed. + * @given some user with all required permissions + * @when send many txes with addAccountDetail with large data inside + * @then transaction have been passed + */ +TEST_F(HeavyTransactionTest, DISABLED_ManyLargeTxes) { + IntegrationTestFramework itf; + + itf.setInitialState(kAdminKeypair) + .sendTx(makeUserWithPerms()) + .skipProposal() + .checkBlock([](auto &b) { ASSERT_EQ(b->transactions().size(), 1); }); + + auto number_of_txes = 4u; + for (auto i = 0u; i < number_of_txes; ++i) { + itf.sendTx(complete(setAcountDetailTx("foo_" + std::to_string(i), + generateData(2 * 1024 * 1024)))); + } + itf.skipProposal() + .checkBlock( + [&](auto &b) { ASSERT_EQ(b->transactions().size(), number_of_txes); }) + .done(); +} + +/** + * NOTE: test is disabled until fix of + * https://soramitsu.atlassian.net/browse/IR-1205 will not be completed. + * @given some user with all required permissions + * @when send tx with many addAccountDetails with large data inside + * @then transaction is passed + */ +TEST_F(HeavyTransactionTest, DISABLED_VeryLargeTxWithManyCommands) { + auto big_data = generateData(3 * 1024 * 1024); + auto large_tx_builder = setAcountDetailTx("foo_1", big_data) + .setAccountDetail(kUserId, "foo_2", big_data) + .setAccountDetail(kUserId, "foo_3", big_data); + + IntegrationTestFramework() + .setInitialState(kAdminKeypair) + .sendTx(makeUserWithPerms()) + // in itf tx build from large_tx_build will pass in Torii but in + // production the transaction will be failed before stateless validation + // because of size. + .sendTx(complete(large_tx_builder)) + .skipProposal() + .checkBlock( + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + .done(); +} + +/** + * NOTE: test is disabled until fix of + * https://soramitsu.atlassian.net/browse/IR-1205 will not be completed. + * @given some user with all required permissions + * AND max proposal size is 1. + * @when send txes with addAccountDetail with large data inside. + * AND transactions are passed stateful validation + * @then query executed sucessfully + */ +TEST_F(HeavyTransactionTest, DISABLED_QueryLargeData) { + auto number_of_times = 15u; + auto size_of_data = 3 * 1024 * 1024u; + auto data = generateData(size_of_data); + + auto name_generator = [](auto val) { return "foo_" + std::to_string(val); }; + + auto query_checker = [&](auto &status) { + auto response = *boost::apply_visitor( + interface::SpecifiedVisitor(), + status.get()); + + boost::property_tree::ptree root; + boost::property_tree::read_json(response->account().jsonData(), root); + auto user = root.get_child(kUserId); + + ASSERT_EQ(number_of_times, user.size()); + + for (auto i = 0u; i < number_of_times; ++i) { + ASSERT_EQ(data, user.get(name_generator(i))); + } + }; + + IntegrationTestFramework itf(1); + itf.setInitialState(kAdminKeypair).sendTx(makeUserWithPerms()); + + for (auto i = 0u; i < number_of_times; ++i) { + itf.sendTx(complete(setAcountDetailTx(name_generator(i), data))) + .skipProposal() + .checkBlock( + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); + } + + // The query works fine only with ITF. It doesn't work in production version + // of Iroha + itf.sendQuery(complete(baseQuery().getAccount(kUserId)), query_checker) + .done(); +} From f1db8a1eba917dca7741fa760bf317854f11daaf Mon Sep 17 00:00:00 2001 From: Dumitru Date: Thu, 12 Apr 2018 16:18:56 +0300 Subject: [PATCH 013/110] Shared model/torii test (#1202) * Remove old model from Torii test Signed-off-by: Dumitru * Docs Signed-off-by: Dumitru * Fix typo Signed-off-by: Dumitru * Remove getError, refactor Signed-off-by: Dumitru --- .../query_responses/error_query_response.hpp | 2 + .../torii/processor/query_processor_test.cpp | 30 +-- .../processor/transaction_processor_test.cpp | 1 + .../irohad/torii/query_service_test.cpp | 44 ++-- test/module/irohad/torii/torii_mocks.hpp | 1 + .../irohad/torii/torii_queries_test.cpp | 203 +++++++++--------- .../irohad/torii/torii_service_test.cpp | 119 +++++----- .../protobuf/test_query_response_builder.hpp | 3 +- 8 files changed, 198 insertions(+), 205 deletions(-) diff --git a/shared_model/interfaces/query_responses/error_query_response.hpp b/shared_model/interfaces/query_responses/error_query_response.hpp index c8aa5a4a8c..480c3f9a45 100644 --- a/shared_model/interfaces/query_responses/error_query_response.hpp +++ b/shared_model/interfaces/query_responses/error_query_response.hpp @@ -19,6 +19,7 @@ #define IROHA_SHARED_MODEL_QUERY_ERROR_RESPONSE_HPP #include + #include "interfaces/base/primitive.hpp" #include "interfaces/query_responses/error_responses/no_account_assets_error_response.hpp" #include "interfaces/query_responses/error_responses/no_account_detail_error_response.hpp" @@ -29,6 +30,7 @@ #include "interfaces/query_responses/error_responses/not_supported_error_response.hpp" #include "interfaces/query_responses/error_responses/stateful_failed_error_response.hpp" #include "interfaces/query_responses/error_responses/stateless_failed_error_response.hpp" +#include "utils/visitor_apply_for_all.hpp" namespace shared_model { namespace interface { diff --git a/test/module/irohad/torii/processor/query_processor_test.cpp b/test/module/irohad/torii/processor/query_processor_test.cpp index b18cbbd1e1..98fc386ba5 100644 --- a/test/module/irohad/torii/processor/query_processor_test.cpp +++ b/test/module/irohad/torii/processor/query_processor_test.cpp @@ -15,21 +15,19 @@ * limitations under the License. */ -#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" -#include "module/irohad/validation/validation_mocks.hpp" -#include "validators/permissions.hpp" - -#include "framework/test_subscriber.hpp" -#include "model/queries/responses/error_response.hpp" -#include "model/query_execution.hpp" -#include "network/ordering_gate.hpp" -#include "torii/processor/query_processor_impl.hpp" - #include "backend/protobuf/query_responses/proto_error_query_response.hpp" #include "builders/protobuf/common_objects/proto_account_builder.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" #include "cryptography/keypair.hpp" +#include "framework/test_subscriber.hpp" +#include "model/query_execution.hpp" +#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" +#include "module/irohad/validation/validation_mocks.hpp" #include "module/shared_model/builders/protobuf/test_query_builder.hpp" +#include "module/shared_model/builders/protobuf/test_query_response_builder.hpp" +#include "network/ordering_gate.hpp" +#include "torii/processor/query_processor_impl.hpp" +#include "validators/permissions.hpp" using namespace iroha; using namespace iroha::ametsuchi; @@ -54,9 +52,6 @@ class QueryProcessorTest : public ::testing::Test { shared_model::crypto::Keypair keypair = shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); - decltype(shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()) - pair = - shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); std::vector signatories = { keypair.publicKey()}; }; @@ -83,12 +78,9 @@ TEST_F(QueryProcessorTest, QueryProcessorWhereInvokeInvalidQuery) { .build() .signAndAddSignature(keypair); - auto qry_resp = std::make_shared(); - auto account = model::Account(); - account.account_id = account_id; - qry_resp->account = account; std::shared_ptr shared_account = clone( shared_model::proto::AccountBuilder().accountId(account_id).build()); + auto role = "admin"; std::vector roles = {role}; std::vector perms = { @@ -140,10 +132,6 @@ TEST_F(QueryProcessorTest, QueryProcessorWithWrongKey) { shared_model::crypto::DefaultCryptoAlgorithmType:: generateKeypair()); - auto qry_resp = std::make_shared(); - auto account = model::Account(); - account.account_id = account_id; - qry_resp->account = account; std::shared_ptr shared_account = clone( shared_model::proto::AccountBuilder().accountId(account_id).build()); auto role = "admin"; diff --git a/test/module/irohad/torii/processor/transaction_processor_test.cpp b/test/module/irohad/torii/processor/transaction_processor_test.cpp index f0905112bf..867656d309 100644 --- a/test/module/irohad/torii/processor/transaction_processor_test.cpp +++ b/test/module/irohad/torii/processor/transaction_processor_test.cpp @@ -16,6 +16,7 @@ */ #include + #include "builders/protobuf/proposal.hpp" #include "builders/protobuf/transaction.hpp" #include "framework/test_subscriber.hpp" diff --git a/test/module/irohad/torii/query_service_test.cpp b/test/module/irohad/torii/query_service_test.cpp index 8bddc449f8..b30ea1fc33 100644 --- a/test/module/irohad/torii/query_service_test.cpp +++ b/test/module/irohad/torii/query_service_test.cpp @@ -17,8 +17,11 @@ #include "torii/query_service.hpp" #include "backend/protobuf/query_responses/proto_query_response.hpp" +#include "builders/protobuf/common_objects/proto_account_builder.hpp" #include "builders/protobuf/queries.hpp" #include "module/irohad/torii/torii_mocks.hpp" +#include "module/shared_model/builders/protobuf/test_query_response_builder.hpp" +#include "utils/query_error_response_visitor.hpp" using namespace torii; @@ -48,19 +51,16 @@ class QueryServiceTest : public ::testing::Test { shared_model::crypto::DefaultCryptoAlgorithmType:: generateKeypair())); - // TODO: IR-1041 Update to query response builders (kamilsa, 04.03.2018) - protocol::QueryResponse response; - response.set_query_hash( - shared_model::crypto::toBinaryString(query->hash())); - auto account_response = response.mutable_account_response(); - account_response->add_account_roles("user"); - auto account = account_response->mutable_account(); - account->set_domain_id("ru"); - account->set_account_id("a"); - account->set_quorum(2); - - model_response = std::make_shared( - std::move(response)); + auto account = shared_model::proto::AccountBuilder() + .accountId("a") + .domainId("ru") + .quorum(2) + .build(); + + model_response = clone(TestQueryResponseBuilder() + .accountResponse(account, {"user"}) + .queryHash(query->hash()) + .build()); } void init() { @@ -99,8 +99,8 @@ TEST_F(QueryServiceTest, ValidWhenUniqueHash) { protocol::QueryResponse response; query_service->Find(query->getTransport(), response); - ASSERT_EQ(response.SerializeAsString(), - model_response->getTransport().SerializeAsString()); + auto resp = shared_model::proto::QueryResponse(response); + ASSERT_EQ(resp, *model_response); } /** @@ -129,8 +129,11 @@ TEST_F(QueryServiceTest, InvalidWhenUniqueHash) { protocol::QueryResponse response; query_service->Find(query->getTransport(), response); ASSERT_TRUE(response.has_error_response()); - ASSERT_EQ(response.error_response().reason(), - protocol::ErrorResponse::NOT_SUPPORTED); + auto resp = shared_model::proto::QueryResponse(response); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::NotSupportedErrorResponse>(), + resp.get())); } /** @@ -154,6 +157,9 @@ TEST_F(QueryServiceTest, InvalidWhenDuplicateHash) { // second call of the same query query_service->Find(query->getTransport(), response); ASSERT_TRUE(response.has_error_response()); - ASSERT_EQ(response.error_response().reason(), - protocol::ErrorResponse::STATELESS_INVALID); + auto resp = shared_model::proto::QueryResponse(response); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::StatelessFailedErrorResponse>(), + resp.get())); } diff --git a/test/module/irohad/torii/torii_mocks.hpp b/test/module/irohad/torii/torii_mocks.hpp index 0889042328..10fb2ded6e 100644 --- a/test/module/irohad/torii/torii_mocks.hpp +++ b/test/module/irohad/torii/torii_mocks.hpp @@ -24,6 +24,7 @@ namespace iroha { namespace torii { + class MockQueryProcessor : public QueryProcessor { public: MOCK_METHOD1(queryHandle, diff --git a/test/module/irohad/torii/torii_queries_test.cpp b/test/module/irohad/torii/torii_queries_test.cpp index 2aab5b337d..08e8c9a088 100644 --- a/test/module/irohad/torii/torii_queries_test.cpp +++ b/test/module/irohad/torii/torii_queries_test.cpp @@ -14,28 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" +#include "module/irohad/network/network_mocks.hpp" +#include "module/irohad/torii/torii_mocks.hpp" +#include "module/irohad/validation/validation_mocks.hpp" + #include "builders/protobuf/common_objects/proto_account_asset_builder.hpp" #include "builders/protobuf/common_objects/proto_account_builder.hpp" #include "builders/protobuf/common_objects/proto_amount_builder.hpp" #include "builders/protobuf/common_objects/proto_asset_builder.hpp" -#include "generator/generator.hpp" -#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" -#include "module/irohad/network/network_mocks.hpp" -#include "module/irohad/validation/validation_mocks.hpp" +#include "builders/protobuf/queries.hpp" +#include "module/shared_model/builders/protobuf/test_query_builder.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" -// to compare pb amount and iroha amount -#include "model/converters/pb_common.hpp" #include "main/server_runner.hpp" #include "torii/processor/query_processor_impl.hpp" #include "torii/query_client.hpp" #include "torii/query_service.hpp" +#include "utils/query_error_response_visitor.hpp" #include "validators/permissions.hpp" -#include "builders/protobuf/queries.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "module/shared_model/builders/protobuf/test_query_builder.hpp" - constexpr const char *Ip = "0.0.0.0"; constexpr int Port = 50051; @@ -47,6 +45,7 @@ using ::testing::AtLeast; using ::testing::Return; using namespace iroha::ametsuchi; +using namespace iroha::torii; using wTransaction = std::shared_ptr; @@ -77,20 +76,14 @@ class ToriiQueriesTest : public testing::Test { } ServerRunner *runner; - decltype(shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()) - pair = - shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); + shared_model::crypto::Keypair pair = + shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); std::vector signatories = { pair.publicKey()}; std::shared_ptr wsv_query; std::shared_ptr block_query; std::shared_ptr storage; - - // just random hex strings - const std::string pubkey_test = generator::random_blob<16>(0).to_hexstring(); - const std::string signature_test = - generator::random_blob<32>(0).to_hexstring(); }; /** @@ -100,12 +93,11 @@ class ToriiQueriesTest : public testing::Test { */ TEST_F(ToriiQueriesTest, QueryClient) { iroha::protocol::QueryResponse response; - auto query = iroha::protocol::Query(); - - query.mutable_payload()->set_creator_account_id("accountA"); - query.mutable_payload()->mutable_get_account()->set_account_id("accountB"); - query.mutable_signature()->set_pubkey(pubkey_test); - query.mutable_signature()->set_signature(signature_test); + auto query = TestUnsignedQueryBuilder() + .creatorAccountId("accountA") + .getAccount("accountB") + .build() + .signAndAddSignature(pair); auto client1 = torii_utils::QuerySyncClient(Ip, Port); // Copy ctor @@ -116,7 +108,7 @@ TEST_F(ToriiQueriesTest, QueryClient) { torii_utils::QuerySyncClient client4(std::move(client3)); // move assignment auto client5 = std::move(client4); - auto stat = client5.Find(query, response); + auto stat = client5.Find(query.getTransport(), response); ASSERT_TRUE(stat.ok()); } @@ -126,19 +118,23 @@ TEST_F(ToriiQueriesTest, QueryClient) { TEST_F(ToriiQueriesTest, FindWhenResponseInvalid) { iroha::protocol::QueryResponse response; - auto query = iroha::protocol::Query(); - - query.mutable_payload()->set_creator_account_id("accountA"); - query.mutable_payload()->mutable_get_account()->set_account_id("accountB"); - query.mutable_signature()->set_pubkey(pubkey_test); - query.mutable_signature()->set_signature(signature_test); - - auto stat = torii_utils::QuerySyncClient(Ip, Port).Find(query, response); + auto query = TestUnsignedQueryBuilder() + .creatorAccountId("accountA") + .getAccount("accountB") + .build() + .signAndAddSignature(pair); + + auto stat = torii_utils::QuerySyncClient(Ip, Port).Find(query.getTransport(), + response); + auto resp = shared_model::proto::QueryResponse(response); ASSERT_TRUE(stat.ok()); // Must return Error Response - ASSERT_EQ(response.error_response().reason(), - iroha::model::ErrorResponse::STATELESS_INVALID); - ASSERT_EQ(iroha::hash(query).to_string(), response.query_hash()); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::StatelessFailedErrorResponse>(), + resp.get())); + + ASSERT_EQ(query.hash(), resp.queryHash()); } /** @@ -146,15 +142,14 @@ TEST_F(ToriiQueriesTest, FindWhenResponseInvalid) { */ TEST_F(ToriiQueriesTest, FindAccountWhenNoGrantPermissions) { - // TODO: kamilsa 19.02.2017 remove old model - iroha::model::Account account; - account.account_id = "b@domain"; + auto account = + shared_model::proto::AccountBuilder().accountId("b@domain").build(); auto creator = "a@domain"; EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( creator, - account.account_id, + account.accountId(), shared_model::permissions::can_get_my_account)) .WillOnce(Return(false)); @@ -169,7 +164,7 @@ TEST_F(ToriiQueriesTest, FindAccountWhenNoGrantPermissions) { .creatorAccountId(creator) .queryCounter(1) .createdTime(iroha::time::now()) - .getAccount(account.account_id) + .getAccount(account.accountId()) .build() .signAndAddSignature(pair); @@ -177,13 +172,15 @@ TEST_F(ToriiQueriesTest, FindAccountWhenNoGrantPermissions) { model_query.getTransport(), response); ASSERT_TRUE(stat.ok()); - + auto resp = shared_model::proto::QueryResponse(response); // Must be invalid due to failed stateful validation caused by no permission // to read account - ASSERT_EQ(response.error_response().reason(), - iroha::model::ErrorResponse::STATEFUL_INVALID); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::StatefulFailedErrorResponse>(), + resp.get())); + + ASSERT_EQ(model_query.hash(), resp.queryHash()); } TEST_F(ToriiQueriesTest, FindAccountWhenHasReadPermissions) { @@ -220,14 +217,18 @@ TEST_F(ToriiQueriesTest, FindAccountWhenHasReadPermissions) { auto stat = torii_utils::QuerySyncClient(Ip, Port).Find( model_query.getTransport(), response); + auto resp = shared_model::proto::QueryResponse(response); + ASSERT_TRUE(stat.ok()); // Should not return Error Response because tx is stateless and stateful valid ASSERT_FALSE(response.has_error_response()); - ASSERT_EQ(response.account_response().account().account_id(), - accountB->accountId()); - ASSERT_EQ(response.account_response().account_roles().size(), 1); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + + auto account_resp = boost::get>(resp.get()); + + ASSERT_EQ(account_resp->account().accountId(), accountB->accountId()); + ASSERT_EQ(account_resp->roles().size(), 1); + ASSERT_EQ(model_query.hash(), resp.queryHash()); } TEST_F(ToriiQueriesTest, FindAccountWhenHasRolePermission) { @@ -257,16 +258,17 @@ TEST_F(ToriiQueriesTest, FindAccountWhenHasRolePermission) { auto stat = torii_utils::QuerySyncClient(Ip, Port).Find( model_query.getTransport(), response); + auto resp = shared_model::proto::QueryResponse(response); ASSERT_TRUE(stat.ok()); // Should not return Error Response because tx is stateless and stateful valid ASSERT_FALSE(response.has_error_response()); - // ASSERT_EQ(response.account_detail_response().detail(), "value"); - ASSERT_EQ(response.account_response().account().account_id(), - account->accountId()); - ASSERT_EQ(response.account_response().account().domain_id(), - account->domainId()); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + + auto detail_resp = boost::get>(resp.get()); + + ASSERT_EQ(detail_resp->account().accountId(), account->accountId()); + ASSERT_EQ(detail_resp->account().domainId(), account->domainId()); + ASSERT_EQ(model_query.hash(), resp.queryHash()); } /** @@ -302,13 +304,16 @@ TEST_F(ToriiQueriesTest, FindAccountAssetWhenNoGrantPermissions) { auto stat = torii_utils::QuerySyncClient(Ip, Port).Find( model_query.getTransport(), response); + auto resp = shared_model::proto::QueryResponse(response); ASSERT_TRUE(stat.ok()); // Must be invalid due to failed stateful validation caused by no permission // to read account asset - ASSERT_EQ(response.error_response().reason(), - iroha::model::ErrorResponse::STATEFUL_INVALID); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::StatefulFailedErrorResponse>(), + resp.get())); + + ASSERT_EQ(model_query.hash(), resp.queryHash()); } TEST_F(ToriiQueriesTest, FindAccountAssetWhenHasRolePermissions) { @@ -361,18 +366,15 @@ TEST_F(ToriiQueriesTest, FindAccountAssetWhenHasRolePermissions) { // Should not return Error Response because tx is stateless and stateful valid ASSERT_FALSE(response.has_error_response()); + auto resp = shared_model::proto::QueryResponse(response); + auto asset_resp = boost::get>(resp.get()); + // Check if the fields in account asset response are correct - ASSERT_EQ(response.account_assets_response().account_asset().asset_id(), - account_asset->assetId()); - ASSERT_EQ(response.account_assets_response().account_asset().account_id(), - account_asset->accountId()); - auto iroha_amount_asset = iroha::model::converters::deserializeAmount( - response.account_assets_response().account_asset().balance()); - ASSERT_EQ( - iroha_amount_asset, - *std::unique_ptr(account_asset->balance().makeOldModel())); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + ASSERT_EQ(asset_resp->accountAsset().assetId(), account_asset->assetId()); + ASSERT_EQ(asset_resp->accountAsset().accountId(), account_asset->accountId()); + ASSERT_EQ(asset_resp->accountAsset().balance(), account_asset->balance()); + ASSERT_EQ(model_query.hash(), resp.queryHash()); } /** @@ -413,10 +415,13 @@ TEST_F(ToriiQueriesTest, FindSignatoriesWhenNoGrantPermissions) { ASSERT_TRUE(stat.ok()); // Must be invalid due to failed stateful validation caused by no permission // to read account - ASSERT_EQ(response.error_response().reason(), - iroha::model::ErrorResponse::STATEFUL_INVALID); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + auto resp = shared_model::proto::QueryResponse(response); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::StatefulFailedErrorResponse>(), + resp.get())); + + ASSERT_EQ(model_query.hash(), resp.queryHash()); } TEST_F(ToriiQueriesTest, FindSignatoriesHasRolePermissions) { @@ -460,8 +465,7 @@ TEST_F(ToriiQueriesTest, FindSignatoriesHasRolePermissions) { ASSERT_FALSE(response.has_error_response()); // check if fields in response are valid ASSERT_EQ(*resp_pubkey, signatories.back()); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + ASSERT_EQ(model_query.hash(), shared_response.queryHash()); } /** @@ -469,16 +473,15 @@ TEST_F(ToriiQueriesTest, FindSignatoriesHasRolePermissions) { */ TEST_F(ToriiQueriesTest, FindTransactionsWhenValid) { - // TODO 19.02.2018 kamilsa remove old model - iroha::model::Account account; - account.account_id = "accountA"; + auto account = + shared_model::proto::AccountBuilder().accountId("accountA").build(); auto creator = "a@domain"; - auto txs_observable = rxcpp::observable<>::iterate([account] { + auto txs_observable = rxcpp::observable<>::iterate([&account] { std::vector result; for (size_t i = 0; i < 3; ++i) { std::shared_ptr current = clone(TestTransactionBuilder() - .creatorAccountId(account.account_id) + .creatorAccountId(account.accountId()) .txCounter(i) .build()); result.push_back(current); @@ -511,19 +514,16 @@ TEST_F(ToriiQueriesTest, FindTransactionsWhenValid) { ASSERT_TRUE(stat.ok()); // Should not return Error Response because tx is stateless and stateful valid ASSERT_FALSE(response.has_error_response()); - for (auto i = 0; i < response.transactions_response().transactions_size(); - i++) { - ASSERT_EQ(response.transactions_response() - .transactions(i) - .payload() - .creator_account_id(), - account.account_id); - ASSERT_EQ( - response.transactions_response().transactions(i).payload().tx_counter(), - i); + auto resp = shared_model::proto::QueryResponse(response); + auto tx_resp = boost::get>(resp.get()); + + const auto &txs = tx_resp->transactions(); + for (auto i = 0ul; i < txs.size(); i++) { + ASSERT_EQ(txs.at(i)->creatorAccountId(), account.accountId()); + ASSERT_EQ(txs.at(i)->transactionCounter(), i); } - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + ASSERT_EQ(model_query.hash(), resp.queryHash()); } TEST_F(ToriiQueriesTest, FindManyTimesWhereQueryServiceSync) { @@ -542,10 +542,13 @@ TEST_F(ToriiQueriesTest, FindManyTimesWhereQueryServiceSync) { auto stat = client.Find(model_query.getTransport(), response); ASSERT_TRUE(stat.ok()); + auto resp = shared_model::proto::QueryResponse(response); // Must return Error Response - ASSERT_EQ(response.error_response().reason(), - iroha::model::ErrorResponse::STATELESS_INVALID); - ASSERT_EQ(iroha::hash(model_query.getTransport()).to_string(), - response.query_hash()); + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::QueryErrorResponseChecker< + shared_model::interface::StatelessFailedErrorResponse>(), + resp.get())); + + ASSERT_EQ(model_query.hash(), resp.queryHash()); } } diff --git a/test/module/irohad/torii/torii_service_test.cpp b/test/module/irohad/torii/torii_service_test.cpp index 5b0f80dc8c..f1fbceabc0 100644 --- a/test/module/irohad/torii/torii_service_test.cpp +++ b/test/module/irohad/torii/torii_service_test.cpp @@ -15,16 +15,16 @@ limitations under the License. */ #include "builders/protobuf/block.hpp" -#include "builders/protobuf/transaction.hpp" #include "builders/protobuf/proposal.hpp" +#include "builders/protobuf/transaction.hpp" #include "endpoint.pb.h" #include "main/server_runner.hpp" -#include "model/converters/pb_transaction_factory.hpp" -#include "model/sha3_hash.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/network/network_mocks.hpp" #include "module/shared_model/builders/protobuf/test_block_builder.hpp" #include "module/shared_model/builders/protobuf/test_proposal_builder.hpp" +#include "module/shared_model/builders/protobuf/test_query_response_builder.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "torii/command_client.hpp" #include "torii/command_service.hpp" #include "torii/processor/transaction_processor_impl.hpp" @@ -86,8 +86,6 @@ class ToriiServiceTest : public testing::Test { auto tx_processor = std::make_shared(pcsMock); - auto pb_tx_factory = - std::make_shared(); EXPECT_CALL(*block_query, getTxByHashSync(_)) .WillRepeatedly(Return(boost::none)); @@ -149,22 +147,17 @@ TEST_F(ToriiServiceTest, CommandClient) { * @then ensure those are not received */ TEST_F(ToriiServiceTest, StatusWhenTxWasNotReceivedBlocking) { - std::vector txs; - std::vector tx_hashes; - - iroha::model::converters::PbTransactionFactory tx_factory; + std::vector txs; + std::vector tx_hashes; // create transactions, but do not send them for (size_t i = 0; i < TimesToriiBlocking; ++i) { - auto new_tx = iroha::protocol::Transaction(); - auto payload = new_tx.mutable_payload(); - payload->set_tx_counter(i); - payload->set_creator_account_id("accountA"); - - auto iroha_tx = tx_factory.deserialize(new_tx); - txs.push_back(*iroha_tx); - auto tx_hash = iroha::hash(*iroha_tx); - tx_hashes.push_back(tx_hash.to_string()); + auto tx = TestTransactionBuilder() + .creatorAccountId("accountA") + .txCounter(i) + .build(); + txs.push_back(tx); + tx_hashes.push_back(tx.hash()); } // get statuses of unsent transactions @@ -172,10 +165,10 @@ TEST_F(ToriiServiceTest, StatusWhenTxWasNotReceivedBlocking) { for (size_t i = 0; i < TimesToriiBlocking; ++i) { iroha::protocol::TxStatusRequest tx_request; - tx_request.set_tx_hash(tx_hashes.at(i)); + tx_request.set_tx_hash( + shared_model::crypto::toBinaryString(tx_hashes.at(i))); iroha::protocol::ToriiResponse toriiResponse; client.Status(tx_request, toriiResponse); - ASSERT_EQ(toriiResponse.tx_status(), iroha::protocol::TxStatus::NOT_RECEIVED); } @@ -196,7 +189,7 @@ TEST_F(ToriiServiceTest, StatusWhenTxWasNotReceivedBlocking) { */ TEST_F(ToriiServiceTest, StatusWhenBlocking) { std::vector txs; - std::vector tx_hashes; + std::vector tx_hashes; auto client1 = torii::CommandSyncClient(Ip, Port); @@ -212,19 +205,22 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { .signAndAddSignature( shared_model::crypto::DefaultCryptoAlgorithmType:: generateKeypair()); - auto new_tx = shm_tx.getTransport(); + const auto &new_tx = shm_tx.getTransport(); auto stat = client1.Torii(new_tx); txs.push_back(shm_tx); - auto tx_hash = shared_model::crypto::toBinaryString(shm_tx.hash()); - tx_hashes.push_back(tx_hash); + tx_hashes.push_back(shm_tx.hash()); ASSERT_TRUE(stat.ok()); } // create proposal from these transactions auto proposal = std::make_shared( - TestProposalBuilder().height(1).createdTime(iroha::time::now()).transactions(txs).build()); + TestProposalBuilder() + .height(1) + .createdTime(iroha::time::now()) + .transactions(txs) + .build()); prop_notifier_.get_subscriber().on_next(proposal); torii::CommandSyncClient client2(client1); @@ -232,7 +228,8 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { // check if stateless validation passed for (size_t i = 0; i < TimesToriiBlocking; ++i) { iroha::protocol::TxStatusRequest tx_request; - tx_request.set_tx_hash(tx_hashes.at(i)); + tx_request.set_tx_hash( + shared_model::crypto::toBinaryString(tx_hashes.at(i))); iroha::protocol::ToriiResponse toriiResponse; client2.Status(tx_request, toriiResponse); @@ -242,13 +239,13 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { // create block from the all transactions but the last one txs.pop_back(); - auto block = std::make_shared( - TestBlockBuilder() - .transactions(txs) - .height(1) - .createdTime(0) - .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) - .build()); + auto block = + clone(TestBlockBuilder() + .transactions(txs) + .height(1) + .createdTime(0) + .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) + .build()); // create commit from block notifier's observable rxcpp::subjects::subject> @@ -257,13 +254,14 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { // invoke on next of commit_notifier by sending new block to commit commit_notifier_.get_subscriber().on_next(commit); - block_notifier_.get_subscriber().on_next(block); + block_notifier_.get_subscriber().on_next(std::move(block)); auto client3 = client2; // check if all transactions but the last one passed stateful validation for (size_t i = 0; i < TimesToriiBlocking - 1; ++i) { iroha::protocol::TxStatusRequest tx_request; - tx_request.set_tx_hash(tx_hashes.at(i)); + tx_request.set_tx_hash( + shared_model::crypto::toBinaryString(tx_hashes.at(i))); iroha::protocol::ToriiResponse toriiResponse; client3.Status(tx_request, toriiResponse); @@ -278,7 +276,8 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { // check if all transactions but the last have committed state for (size_t i = 0; i < TimesToriiBlocking - 1; ++i) { iroha::protocol::TxStatusRequest tx_request; - tx_request.set_tx_hash(tx_hashes.at(i)); + tx_request.set_tx_hash( + shared_model::crypto::toBinaryString(tx_hashes.at(i))); iroha::protocol::ToriiResponse toriiResponse; client4.Status(tx_request, toriiResponse); @@ -288,7 +287,8 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { torii::CommandSyncClient client5(client4); // check if the last transaction from txs has failed stateful validation iroha::protocol::TxStatusRequest last_tx_request; - last_tx_request.set_tx_hash(tx_hashes.at(TimesToriiBlocking - 1)); + last_tx_request.set_tx_hash(shared_model::crypto::toBinaryString( + tx_hashes.at(TimesToriiBlocking - 1))); iroha::protocol::ToriiResponse stful_invalid_response; client5.Status(last_tx_request, stful_invalid_response); ASSERT_EQ(stful_invalid_response.tx_status(), @@ -302,19 +302,13 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { */ TEST_F(ToriiServiceTest, CheckHash) { // given - std::vector tx_hashes; + std::vector tx_hashes; const int tx_num = 10; - iroha::model::converters::PbTransactionFactory tx_factory; - // create transactions, but do not send them for (size_t i = 0; i < tx_num; ++i) { - auto new_tx = iroha::protocol::Transaction(); - auto payload = new_tx.mutable_payload(); - payload->set_tx_counter(i); - auto tx = tx_factory.deserialize(new_tx); - - tx_hashes.push_back(iroha::hash(*tx).to_string()); + auto tx = TestTransactionBuilder().txCounter(i).build(); + tx_hashes.push_back(tx.hash()); } auto client = torii::CommandSyncClient(Ip, Port); @@ -322,12 +316,13 @@ TEST_F(ToriiServiceTest, CheckHash) { // get statuses of transactions for (auto &hash : tx_hashes) { iroha::protocol::TxStatusRequest tx_request; - tx_request.set_tx_hash(hash); + tx_request.set_tx_hash(shared_model::crypto::toBinaryString(hash)); iroha::protocol::ToriiResponse toriiResponse; // when client.Status(tx_request, toriiResponse); // then - ASSERT_EQ(toriiResponse.tx_hash(), hash); + ASSERT_EQ(toriiResponse.tx_hash(), + shared_model::crypto::toBinaryString(hash)); } } @@ -341,13 +336,12 @@ TEST_F(ToriiServiceTest, CheckHash) { TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { using namespace shared_model; - iroha::model::converters::PbTransactionFactory tx_factory; auto client = torii::CommandSyncClient(Ip, Port); - auto new_tx = iroha::protocol::Transaction(); - auto payload = new_tx.mutable_payload(); - payload->set_tx_counter(1); - payload->set_creator_account_id("accountA"); + auto new_tx = TestTransactionBuilder() + .creatorAccountId("accountA") + .txCounter(1) + .build(); auto iroha_tx = proto::TransactionBuilder() .txCounter(1) @@ -369,7 +363,7 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { client.StatusStream(tx_request, torii_response); }); - client.Torii(new_tx); + client.Torii(new_tx.getTransport()); std::vector txs; txs.push_back(iroha_tx); @@ -381,14 +375,13 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { .build()); prop_notifier_.get_subscriber().on_next(proposal); - auto block = std::make_shared( - proto::BlockBuilder() - .height(1) - .createdTime(iroha::time::now()) - .transactions(txs) - .prevHash(crypto::Hash(std::string(32, '0'))) - .build() - .signAndAddSignature(keypair)); + auto block = clone(proto::BlockBuilder() + .height(1) + .createdTime(iroha::time::now()) + .transactions(txs) + .prevHash(crypto::Hash(std::string(32, '0'))) + .build() + .signAndAddSignature(keypair)); // create commit from block notifier's observable rxcpp::subjects::subject> @@ -397,7 +390,7 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { // invoke on next of commit_notifier by sending new block to commit commit_notifier_.get_subscriber().on_next(commit); - block_notifier_.get_subscriber().on_next(block); + block_notifier_.get_subscriber().on_next(std::move(block)); block_notifier_.get_subscriber().on_completed(); t.join(); diff --git a/test/module/shared_model/builders/protobuf/test_query_response_builder.hpp b/test/module/shared_model/builders/protobuf/test_query_response_builder.hpp index f904a80f93..8d1b03d8fe 100644 --- a/test/module/shared_model/builders/protobuf/test_query_response_builder.hpp +++ b/test/module/shared_model/builders/protobuf/test_query_response_builder.hpp @@ -26,7 +26,6 @@ */ using TestQueryResponseBuilder = shared_model::proto::TemplateQueryResponseBuilder< - (1 << shared_model::proto::TemplateQueryResponseBuilder<>::total) - 1, - shared_model::proto::QueryResponse>; + (1 << shared_model::proto::TemplateQueryResponseBuilder<>::total) - 1>; #endif // IROHA_TEST_QUERY_RESPONSE_BUILDER_HPP From 50255f14101ab07e1517b869e0a75a67994d3e67 Mon Sep 17 00:00:00 2001 From: kamilsa Date: Fri, 13 Apr 2018 11:18:09 +0300 Subject: [PATCH 014/110] Rework test/framework (#1215) * Remove test block generator Signed-off-by: kamilsa --- test/framework/CMakeLists.txt | 12 --- test/framework/test_block_generator.cpp | 101 ------------------ test/framework/test_block_generator.hpp | 34 ------ test/module/irohad/common/CMakeLists.txt | 2 +- .../irohad/common/raw_block_loader_test.cpp | 17 ++- 5 files changed, 14 insertions(+), 152 deletions(-) delete mode 100644 test/framework/test_block_generator.cpp delete mode 100644 test/framework/test_block_generator.hpp diff --git a/test/framework/CMakeLists.txt b/test/framework/CMakeLists.txt index 9363c06aaa..aa55bdd915 100644 --- a/test/framework/CMakeLists.txt +++ b/test/framework/CMakeLists.txt @@ -20,13 +20,6 @@ target_link_libraries(test_subscriber_testing rxcpp ) -add_library(test_block_generator test_block_generator.cpp) -target_link_libraries(test_block_generator - model - ) - -target_include_directories(test_block_generator PUBLIC ${PROJECT_SOURCE_DIR}/test) - add_library(integration_framework integration_framework/integration_test_framework.cpp @@ -34,11 +27,6 @@ add_library(integration_framework ) target_link_libraries(integration_framework application - raw_block_insertion - keys_manager - model_generators - pb_model_converters - tbb ) target_include_directories(integration_framework PUBLIC ${PROJECT_SOURCE_DIR}/test) diff --git a/test/framework/test_block_generator.cpp b/test/framework/test_block_generator.cpp deleted file mode 100644 index 12081bc710..0000000000 --- a/test/framework/test_block_generator.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "framework/test_block_generator.hpp" -#include -#include -#include "model/commands/add_peer.hpp" -#include "model/commands/create_account.hpp" -#include "model/commands/create_asset.hpp" -#include "model/commands/create_domain.hpp" -#include "model/sha3_hash.hpp" -#include "validators/permissions.hpp" - -using namespace iroha; -using namespace iroha::model; -using namespace shared_model::permissions; - -namespace framework { - namespace generator { - Transaction getAddPeerTransaction(uint64_t create_time, - std::string address) { - Transaction transaction; - transaction.created_ts = create_time; - Signature sign{}; - transaction.signatures = {sign}; - - auto add_peer = std::make_shared(); - add_peer->peer.address = address; - add_peer->peer.pubkey = {}; - - transaction.commands = {add_peer}; - return transaction; - } - - Transaction getTestCreateTransaction(uint64_t create_time) { - Transaction transaction; - transaction.created_ts = create_time; - Signature sign{}; - transaction.signatures = {sign}; - - auto create_role = std::make_shared("user", role_perm_group); - - auto create_domain = std::make_shared(); - create_domain->domain_id = "test"; - create_domain->user_default_role = "user"; - - auto create_asset = std::make_shared(); - create_asset->domain_id = "test"; - create_asset->asset_name = "coin"; - create_asset->precision = 2; - - auto create_admin = std::make_shared(); - create_admin->domain_id = "test"; - create_admin->account_name = "admin"; - - auto create_acc = std::make_shared(); - create_acc->domain_id = "test"; - create_acc->account_name = "test"; - - transaction.commands = { - create_domain, create_asset, create_admin, create_acc}; - return transaction; - } - - Block generateBlock() { - Block block; - block.created_ts = 100500; - block.height = 1; - std::fill(block.prev_hash.begin(), block.prev_hash.end(), 0); - block.txs_number = 4; - - auto start_port = 10001u; - for (size_t i = start_port; i < start_port + block.txs_number; ++i) { - block.transactions.push_back(getAddPeerTransaction( - block.created_ts, "0.0.0.0:" + std::to_string(i))); - } - - block.transactions.push_back(getTestCreateTransaction(block.created_ts)); - block.txs_number++; - - Signature sign{}; - block.sigs = {sign}; - block.hash = hash(block); - return block; - } - } // namespace generator -} // namespace framework diff --git a/test/framework/test_block_generator.hpp b/test/framework/test_block_generator.hpp deleted file mode 100644 index c3ecc46266..0000000000 --- a/test/framework/test_block_generator.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef IROHA_TEST_BLOCK_GENERATOR_HPP -#define IROHA_TEST_BLOCK_GENERATOR_HPP - -#include "model/block.hpp" -#include "model/transaction.hpp" - -namespace framework { - namespace generator { - iroha::model::Transaction getAddPeerTransaction(uint64_t create_time, - std::string address); - - iroha::model::Transaction getTestCreateTransaction(uint64_t create_time); - - iroha::model::Block generateBlock(); - } // namespace generator -} // namespace framework -#endif // IROHA_TEST_BLOCK_GENERATOR_HPP diff --git a/test/module/irohad/common/CMakeLists.txt b/test/module/irohad/common/CMakeLists.txt index 685320ae24..56dea9f068 100644 --- a/test/module/irohad/common/CMakeLists.txt +++ b/test/module/irohad/common/CMakeLists.txt @@ -6,7 +6,7 @@ target_link_libraries(blob_converter_test AddTest(block_insertion_test raw_block_loader_test.cpp) target_link_libraries(block_insertion_test json_model_converters - test_block_generator raw_block_insertion + shared_model_cryptography_model logger ) diff --git a/test/module/irohad/common/raw_block_loader_test.cpp b/test/module/irohad/common/raw_block_loader_test.cpp index 20906b3eef..da4e9bba7b 100644 --- a/test/module/irohad/common/raw_block_loader_test.cpp +++ b/test/module/irohad/common/raw_block_loader_test.cpp @@ -18,15 +18,23 @@ #include "main/raw_block_loader.hpp" #include -#include "framework/test_block_generator.hpp" #include "model/converters/json_block_factory.hpp" #include "model/converters/json_common.hpp" #include "model/converters/pb_command_factory.hpp" +#include "module/shared_model/builders/protobuf/test_block_builder.hpp" using namespace iroha::main; using namespace iroha::model::converters; using namespace iroha; +auto generateBlock() { + return TestBlockBuilder() + .createdTime(100500) + .height(1) + .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) + .build(); +} + /** * @given generated block * @@ -37,10 +45,11 @@ using namespace iroha; */ TEST(BlockLoaderTest, BlockLoaderWhenParseBlock) { BlockLoader loader; - auto block = framework::generator::generateBlock(); - auto doc = JsonBlockFactory().serialize(block); + auto block = generateBlock(); + auto old_block = *std::unique_ptr(block.makeOldModel()); + auto doc = JsonBlockFactory().serialize(old_block); auto str = jsonToString(doc); auto new_block = loader.parseBlock(str); ASSERT_TRUE(new_block); - ASSERT_EQ(block, *new_block); + ASSERT_EQ(old_block, *new_block); } From 4ae6a7885e864acc66e53f4490c2333f98904cd0 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 24 Mar 2018 08:08:57 +0300 Subject: [PATCH 015/110] Feature/rework postgres block query with shared model (#1110) rework postgres_block_query with shared_model Storage now uses the new JSON format provided by ptotobuf Signed-off-by: Alexey Chernyshov --- .../ametsuchi/impl/mutable_storage_impl.cpp | 4 +- .../ametsuchi/impl/postgres_block_query.cpp | 104 +++++++++--------- .../ametsuchi/impl/postgres_block_query.hpp | 2 - irohad/ametsuchi/impl/storage_impl.cpp | 15 ++- irohad/ametsuchi/impl/storage_impl.hpp | 3 - irohad/main/iroha_conf_loader.hpp | 1 + .../irohad/ametsuchi/ametsuchi_test.cpp | 11 +- .../irohad/ametsuchi/block_query_test.cpp | 14 +-- .../ametsuchi/block_query_transfer_test.cpp | 16 +-- 9 files changed, 77 insertions(+), 93 deletions(-) diff --git a/irohad/ametsuchi/impl/mutable_storage_impl.cpp b/irohad/ametsuchi/impl/mutable_storage_impl.cpp index 45a34b4c20..f60b911be6 100644 --- a/irohad/ametsuchi/impl/mutable_storage_impl.cpp +++ b/irohad/ametsuchi/impl/mutable_storage_impl.cpp @@ -76,9 +76,7 @@ namespace iroha { execute_transaction); if (result) { - block_store_.insert(std::make_pair( - block.height(), - clone(block))); + block_store_.insert(std::make_pair(block.height(), clone(block))); block_index_->index(block); top_hash_ = block.hash(); diff --git a/irohad/ametsuchi/impl/postgres_block_query.cpp b/irohad/ametsuchi/impl/postgres_block_query.cpp index d17aa25c41..dd33cd42e9 100644 --- a/irohad/ametsuchi/impl/postgres_block_query.cpp +++ b/irohad/ametsuchi/impl/postgres_block_query.cpp @@ -16,9 +16,11 @@ */ #include "ametsuchi/impl/postgres_block_query.hpp" + #include #include -#include "backend/protobuf/from_old_model.hpp" + +#include "converters/protobuf/json_proto_converter.hpp" namespace iroha { namespace ametsuchi { @@ -38,26 +40,26 @@ namespace iroha { if (height > to or count == 0) { return rxcpp::observable<>::empty(); } - return rxcpp::observable<>::range(height, to).flat_map([this](auto i) { - // TODO IR-975 victordrobny 12.02.2018 convert directly to - // shared_model::proto::Block after FlatFile will be reworked to new - // model - auto block = block_store_.get(i) | [](const auto &bytes) { - return model::converters::stringToJson(bytesToString(bytes)); - } | [this](const auto &d) { - return serializer_.deserialize(d); - } | [](const auto &block_old) { - return std::make_shared( - shared_model::proto::from_old(block_old)); - }; - return rxcpp::observable<>::create( - [block{std::move(block)}](auto s) { + return rxcpp::observable<>::range(height, to) + .flat_map([this](const auto &i) { + auto block = block_store_.get(i) | [](const auto &bytes) { + return shared_model::converters::protobuf::jsonToModel< + shared_model::proto::Block>(bytesToString(bytes)); + }; + if (not block) { + log_->error("error while converting from JSON"); + } + + return rxcpp::observable<>::create< + PostgresBlockQuery::wBlock>([block{std::move(block)}]( + const auto &s) { if (block) { - s.on_next(block); + s.on_next(std::make_shared( + block.value())); } s.on_completed(); }); - }); + }); } rxcpp::observable PostgresBlockQuery::getBlocksFrom( @@ -111,19 +113,20 @@ namespace iroha { std::function PostgresBlockQuery::callback( const rxcpp::subscriber &subscriber, uint64_t block_id) { return [this, &subscriber, block_id](pqxx::result &result) { - auto block = block_store_.get(block_id) | [this](auto bytes) { - // TODO IR-975 victordrobny 12.02.2018 convert directly to - // shared_model::proto::Block after FlatFile will be reworked to new - // model - return boost::optional( - shared_model::proto::from_old(*serializer_.deserialize( - *model::converters::stringToJson(bytesToString(bytes))))); + auto block = block_store_.get(block_id) | [this](const auto &bytes) { + return shared_model::converters::protobuf::jsonToModel< + shared_model::proto::Block>(bytesToString(bytes)); }; + if (not block) { + log_->error("error while converting from JSON"); + return; + } + boost::for_each( result | boost::adaptors::transformed([](const auto &x) { return x.at("index").template as(); }), - [&](auto x) { + [&](const auto &x) { subscriber.on_next(PostgresBlockQuery::wTransaction( clone(*block->transactions().at(x)))); }); @@ -134,7 +137,7 @@ namespace iroha { PostgresBlockQuery::getAccountTransactions( const shared_model::interface::types::AccountIdType &account_id) { return rxcpp::observable<>::create( - [this, account_id](auto subscriber) { + [this, account_id](const auto &subscriber) { auto block_ids = this->getBlockIds(account_id); if (block_ids.empty()) { subscriber.on_completed(); @@ -183,10 +186,10 @@ namespace iroha { PostgresBlockQuery::getTransactions( const std::vector &tx_hashes) { return rxcpp::observable<>::create>( - [this, tx_hashes](auto subscriber) { + [this, tx_hashes](const auto &subscriber) { std::for_each(tx_hashes.begin(), tx_hashes.end(), - [that = this, &subscriber](auto tx_hash) { + [ that = this, &subscriber ](const auto &tx_hash) { subscriber.on_next(that->getTxByHashSync(tx_hash)); }); subscriber.on_completed(); @@ -196,30 +199,27 @@ namespace iroha { boost::optional PostgresBlockQuery::getTxByHashSync( const shared_model::crypto::Hash &hash) { - return getBlockId(hash) | - [this](auto blockId) { return block_store_.get(blockId); } | - [](auto bytes) { - // TODO IR-975 victordrobny 12.02.2018 convert directly to - // shared_model::proto::Block after FlatFile will be reworked to new - // model - return model::converters::stringToJson(bytesToString(bytes)); - } - | [&](const auto &json) { return serializer_.deserialize(json); } | - [](const auto &block) { - return boost::optional( - shared_model::proto::from_old(block)); - } - | [&](const auto &block) { - boost::optional result; - auto it = - std::find_if(block.transactions().begin(), - block.transactions().end(), - [&hash](auto tx) { return tx->hash() == hash; }); - if (it != block.transactions().end()) { - result = boost::optional(clone(**it)); - } - return result; - }; + auto block = getBlockId(hash) | [this](const auto &block_id) { + return block_store_.get(block_id); + } | [](const auto &bytes) { + return shared_model::converters::protobuf::jsonToModel< + shared_model::proto::Block>(bytesToString(bytes)); + }; + if (not block) { + log_->error("error while converting from JSON"); + return boost::none; + } + + boost::optional result; + auto it = + std::find_if(block->transactions().begin(), + block->transactions().end(), + [&hash](const auto &tx) { return tx->hash() == hash; }); + if (it != block->transactions().end()) { + result = boost::optional( + PostgresBlockQuery::wTransaction(clone(**it))); + } + return result; } } // namespace ametsuchi diff --git a/irohad/ametsuchi/impl/postgres_block_query.hpp b/irohad/ametsuchi/impl/postgres_block_query.hpp index 7343331e4a..dce3fe07ee 100644 --- a/irohad/ametsuchi/impl/postgres_block_query.hpp +++ b/irohad/ametsuchi/impl/postgres_block_query.hpp @@ -24,7 +24,6 @@ #include "ametsuchi/block_query.hpp" #include "ametsuchi/impl/flat_file/flat_file.hpp" #include "logger/logger.hpp" -#include "model/converters/json_block_factory.hpp" #include "postgres_wsv_common.hpp" namespace iroha { @@ -95,7 +94,6 @@ namespace iroha { logger::Logger log_; using ExecuteType = decltype(makeExecuteOptional(transaction_, log_)); ExecuteType execute_; - model::converters::JsonBlockFactory serializer_; }; } // namespace ametsuchi } // namespace iroha diff --git a/irohad/ametsuchi/impl/storage_impl.cpp b/irohad/ametsuchi/impl/storage_impl.cpp index d020533ab3..4d1f8e4725 100644 --- a/irohad/ametsuchi/impl/storage_impl.cpp +++ b/irohad/ametsuchi/impl/storage_impl.cpp @@ -22,7 +22,8 @@ #include "ametsuchi/impl/postgres_block_query.hpp" #include "ametsuchi/impl/postgres_wsv_query.hpp" #include "ametsuchi/impl/temporary_wsv_impl.hpp" -#include "model/converters/json_common.hpp" +#include "converters/protobuf/json_proto_converter.hpp" +#include "model/execution/command_executor_factory.hpp" // for CommandExecutorFactory #include "postgres_ordering_service_persistent_state.hpp" // TODO: 14-02-2018 Alexey Chernyshov remove this after relocation to @@ -257,13 +258,11 @@ DROP TABLE IF EXISTS index_by_id_height_asset; auto storage_ptr = std::move(mutableStorage); // get ownership of storage auto storage = static_cast(storage_ptr.get()); for (const auto &block : storage->block_store_) { - // TODO: rework to shared model converters once they are available - // IR-1084 Nikita Alekseev - auto old_block = - *std::unique_ptr(block.second->makeOldModel()); - block_store_->add(block.first, - stringToBytes(model::converters::jsonToString( - serializer_.serialize(old_block)))); + block_store_->add( + block.first, + stringToBytes(shared_model::converters::protobuf::modelToJson( + *std::static_pointer_cast( + block.second)))); } storage->transaction_->exec("COMMIT;"); diff --git a/irohad/ametsuchi/impl/storage_impl.hpp b/irohad/ametsuchi/impl/storage_impl.hpp index c9838da7fc..b44b6eb3c1 100644 --- a/irohad/ametsuchi/impl/storage_impl.hpp +++ b/irohad/ametsuchi/impl/storage_impl.hpp @@ -25,7 +25,6 @@ #include #include #include "logger/logger.hpp" -#include "model/converters/json_block_factory.hpp" namespace iroha { namespace ametsuchi { @@ -111,8 +110,6 @@ namespace iroha { std::shared_ptr blocks_; - model::converters::JsonBlockFactory serializer_; - // Allows multiple readers and a single writer std::shared_timed_mutex rw_lock_; diff --git a/irohad/main/iroha_conf_loader.hpp b/irohad/main/iroha_conf_loader.hpp index 63982aa871..099137df3f 100644 --- a/irohad/main/iroha_conf_loader.hpp +++ b/irohad/main/iroha_conf_loader.hpp @@ -18,6 +18,7 @@ #ifndef IROHA_CONF_LOADER_HPP #define IROHA_CONF_LOADER_HPP +#include #include #include #include diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index 3412c85601..6addddf223 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -734,13 +734,14 @@ TEST_F(AmetsuchiTest, FindTxByHashTest) { auto tx2hash = txn2.hash(); auto tx3hash = shared_model::crypto::Hash("some garbage"); - auto tx1check = *blocks->getTxByHashSync(tx1hash); + auto tx1 = blocks->getTxByHashSync(tx1hash); + ASSERT_TRUE(tx1); - auto tx1 = *blocks->getTxByHashSync(tx1hash); - auto tx2 = *blocks->getTxByHashSync(tx2hash); + auto tx2 = blocks->getTxByHashSync(tx2hash); + ASSERT_TRUE(tx2); - ASSERT_EQ(*tx1.operator->(), txn1); - ASSERT_EQ(*tx2.operator->(), txn2); + ASSERT_EQ(**tx1, txn1); + ASSERT_EQ(**tx2, txn2); ASSERT_EQ(blocks->getTxByHashSync(tx3hash), boost::none); } diff --git a/test/module/irohad/ametsuchi/block_query_test.cpp b/test/module/irohad/ametsuchi/block_query_test.cpp index e0490c4043..ceb9c79877 100644 --- a/test/module/irohad/ametsuchi/block_query_test.cpp +++ b/test/module/irohad/ametsuchi/block_query_test.cpp @@ -19,7 +19,7 @@ #include #include "ametsuchi/impl/postgres_block_index.hpp" #include "ametsuchi/impl/postgres_block_query.hpp" -#include "backend/protobuf/from_old_model.hpp" +#include "converters/protobuf/json_proto_converter.hpp" #include "framework/test_subscriber.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" #include "module/shared_model/builders/protobuf/test_block_builder.hpp" @@ -83,13 +83,9 @@ class BlockQueryTest : public AmetsuchiTest { .build(); for (const auto &b : {block1, block2}) { - // TODO IR-975 victordrobny 12.02.2018 convert from - // shared_model::proto::Block after FlatFile will be reworked to new - // model - auto old_block = *std::unique_ptr(b.makeOldModel()); file->add(b.height(), - iroha::stringToBytes(iroha::model::converters::jsonToString( - iroha::model::converters::JsonBlockFactory().serialize(old_block)))); + iroha::stringToBytes( + shared_model::converters::protobuf::modelToJson(b))); index->index(b); blocks_total++; } @@ -167,10 +163,10 @@ TEST_F(BlockQueryTest, GetTransactionsExistingTxHashes) { static auto subs_cnt = 0; subs_cnt++; if (subs_cnt == 1) { - EXPECT_TRUE(tx); + ASSERT_TRUE(tx); EXPECT_EQ(tx_hashes[1], (*tx)->hash()); } else { - EXPECT_TRUE(tx); + ASSERT_TRUE(tx); EXPECT_EQ(tx_hashes[3], (*tx)->hash()); } }); diff --git a/test/module/irohad/ametsuchi/block_query_transfer_test.cpp b/test/module/irohad/ametsuchi/block_query_transfer_test.cpp index 7075af3004..2820721a70 100644 --- a/test/module/irohad/ametsuchi/block_query_transfer_test.cpp +++ b/test/module/irohad/ametsuchi/block_query_transfer_test.cpp @@ -18,7 +18,7 @@ #include #include "ametsuchi/impl/postgres_block_index.hpp" #include "ametsuchi/impl/postgres_block_query.hpp" -#include "backend/protobuf/from_old_model.hpp" +#include "converters/protobuf/json_proto_converter.hpp" #include "framework/test_subscriber.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" #include "module/shared_model/builders/protobuf/test_block_builder.hpp" @@ -52,16 +52,10 @@ namespace iroha { transaction->exec(init_); } - void insert(const shared_model::interface::Block &block) { - // TODO IR-975 victordrobny 12.02.2018 convert from - // shared_model::proto::Block after FlatFile will be reworked to new - // model - auto old_block = - *std::unique_ptr(block.makeOldModel()); - file->add( - block.height(), - iroha::stringToBytes(model::converters::jsonToString( - model::converters::JsonBlockFactory().serialize(old_block)))); + void insert(const shared_model::proto::Block &block) { + file->add(block.height(), + iroha::stringToBytes( + shared_model::converters::protobuf::modelToJson(block))); index->index(block); } From 056bf717dd31a52017c8a2434a2ad6328fcd1c43 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Tue, 27 Mar 2018 16:20:15 +0300 Subject: [PATCH 016/110] shared model raw block loader (#1135) Rework raw_block_loader to shared model Signed-off-by: Nikita Alekseev --- irohad/main/impl/raw_block_loader.cpp | 26 ++++---- irohad/main/irohad.cpp | 4 +- irohad/main/raw_block_loader.hpp | 24 +++---- .../irohad/common/raw_block_loader_test.cpp | 62 +++++++++---------- 4 files changed, 61 insertions(+), 55 deletions(-) diff --git a/irohad/main/impl/raw_block_loader.cpp b/irohad/main/impl/raw_block_loader.cpp index 38f1600e98..a4c601c243 100644 --- a/irohad/main/impl/raw_block_loader.cpp +++ b/irohad/main/impl/raw_block_loader.cpp @@ -16,26 +16,30 @@ */ #include "main/raw_block_loader.hpp" + #include -#include -#include "common/types.hpp" -#include "model/converters/json_common.hpp" + +#include "converters/protobuf/json_proto_converter.hpp" +#include "backend/protobuf/block.hpp" namespace iroha { namespace main { + using shared_model::converters::protobuf::jsonToProto; + using shared_model::interface::Block; + BlockLoader::BlockLoader() : log_(logger::log("BlockLoader")) {} - boost::optional BlockLoader::parseBlock(std::string data) { - auto document = model::converters::stringToJson(data); - if (not document) { - log_->error("Blob parsing failed"); - return boost::none; - } - return block_factory_.deserialize(document.value()); + boost::optional> BlockLoader::parseBlock( + const std::string &data) { + return jsonToProto(data) | [](auto &&block) { + return boost::optional>( + std::make_shared(std::move(block))); + }; } - boost::optional BlockLoader::loadFile(std::string path) { + boost::optional BlockLoader::loadFile( + const std::string &path) { std::ifstream file(path); if (not file) { log_->error("Cannot read '" + path + "'"); diff --git a/irohad/main/irohad.cpp b/irohad/main/irohad.cpp index 06f6936630..9fac29ac32 100644 --- a/irohad/main/irohad.cpp +++ b/irohad/main/irohad.cpp @@ -151,9 +151,9 @@ int main(int argc, char *argv[]) { log->info("Block is parsed"); // Applying transactions from genesis block to iroha storage - irohad.storage->insertBlock(shared_model::proto::from_old(block.value())); + irohad.storage->insertBlock(*block.value()); log->info("Genesis block inserted, number of transactions: {}", - block.value().transactions.size()); + block.value()->transactions().size()); } // init pipeline components diff --git a/irohad/main/raw_block_loader.hpp b/irohad/main/raw_block_loader.hpp index e6500c4b04..c6fc3b0c66 100644 --- a/irohad/main/raw_block_loader.hpp +++ b/irohad/main/raw_block_loader.hpp @@ -19,13 +19,17 @@ #define IROHA_RAW_BLOCK_INSERTION_HPP #include -#include #include -#include -#include "ametsuchi/storage.hpp" + +#include + #include "logger/logger.hpp" -#include "model/block.hpp" -#include "model/converters/json_block_factory.hpp" + +namespace shared_model { + namespace interface { + class Block; + } +} namespace iroha { namespace main { @@ -44,19 +48,17 @@ namespace iroha { * @param data - raw presenetation of block * @return object if operation done successfully, nullopt otherwise */ - boost::optional parseBlock(std::string data); + boost::optional> + parseBlock(const std::string &data); /** - * Additional method * Loading file from target path * @param path - target file - * @return string with content or nullopt + * @return string with file content or nullopt */ - boost::optional loadFile(std::string path); + boost::optional loadFile(const std::string &path); private: - model::converters::JsonBlockFactory block_factory_; - logger::Logger log_; }; diff --git a/test/module/irohad/common/raw_block_loader_test.cpp b/test/module/irohad/common/raw_block_loader_test.cpp index da4e9bba7b..353c4e73d4 100644 --- a/test/module/irohad/common/raw_block_loader_test.cpp +++ b/test/module/irohad/common/raw_block_loader_test.cpp @@ -15,41 +15,41 @@ * limitations under the License. */ -#include "main/raw_block_loader.hpp" #include -#include "model/converters/json_block_factory.hpp" -#include "model/converters/json_common.hpp" -#include "model/converters/pb_command_factory.hpp" -#include "module/shared_model/builders/protobuf/test_block_builder.hpp" - -using namespace iroha::main; -using namespace iroha::model::converters; -using namespace iroha; - -auto generateBlock() { - return TestBlockBuilder() - .createdTime(100500) - .height(1) - .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) - .build(); -} +#include "interfaces/iroha_internal/block.hpp" +#include "main/raw_block_loader.hpp" + +using iroha::main::BlockLoader; /** - * @given generated block - * - * @when convert block to JSON - * AND parseBlock() with BlockLoader API - * - * @then check that blocks are equal + * @given block in json format + * @when converting json to block using raw block loader + * @then check that the block is correct */ -TEST(BlockLoaderTest, BlockLoaderWhenParseBlock) { +TEST(BlockLoaderTest, BlockLoaderJsonParsing) { BlockLoader loader; - auto block = generateBlock(); - auto old_block = *std::unique_ptr(block.makeOldModel()); - auto doc = JsonBlockFactory().serialize(old_block); - auto str = jsonToString(doc); - auto new_block = loader.parseBlock(str); - ASSERT_TRUE(new_block); - ASSERT_EQ(old_block, *new_block); + auto str = + R"({ +"payload": { + "transactions": [], + "height": 1, + "prev_block_hash": "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=", + "created_time": 0 + }, +"signatures": [] +})"; + + auto block = loader.parseBlock(str); + + + + ASSERT_TRUE(block); + auto b = block.value(); + + ASSERT_EQ(b->transactions().size(), 0); + ASSERT_EQ(b->height(), 1); + ASSERT_EQ(b->createdTime(), 0); + ASSERT_TRUE(b->signatures().empty()); + ASSERT_EQ(b->prevHash().hex(), "0101010101010101010101010101010101010101010101010101010101010101"); } From 1c8d1d9dd98740c7658c062f175903c783786155 Mon Sep 17 00:00:00 2001 From: victordrobny Date: Tue, 27 Mar 2018 18:56:33 +0300 Subject: [PATCH 017/110] Genesis block is now generated in new format (#1111) * Genesis block now generates in new format Signed-off-by: Victor Drobny --- example/admin@test.priv | 2 +- example/admin@test.pub | 2 +- example/genesis.block | 231 ++++++++++++++++++++-------------------- example/node0.priv | 2 +- example/node0.pub | 2 +- example/test@test.priv | 2 +- example/test@test.pub | 2 +- iroha-cli/main.cpp | 6 +- 8 files changed, 128 insertions(+), 121 deletions(-) diff --git a/example/admin@test.priv b/example/admin@test.priv index ef24e1430d..87ff52af36 100644 --- a/example/admin@test.priv +++ b/example/admin@test.priv @@ -1 +1 @@ -1d7e0a32ee0affeb4d22acd73c2c6fb6bd58e266c8c2ce4fa0ffe3dd6a253ffb \ No newline at end of file +0f0ce16d2afbb8eca23c7d8c2724f0c257a800ee2bbd54688cec6b898e3f7e33 \ No newline at end of file diff --git a/example/admin@test.pub b/example/admin@test.pub index d80b9b299f..1dfda5428f 100644 --- a/example/admin@test.pub +++ b/example/admin@test.pub @@ -1 +1 @@ -407e57f50ca48969b08ba948171bb2435e035d82cec417e18e4a38f5fb113f83 \ No newline at end of file +889f6b881e331be21487db77dcf32c5f8d3d5e8066e78d2feac4239fe91d416f \ No newline at end of file diff --git a/example/genesis.block b/example/genesis.block index a8f665dd13..004f42d54a 100644 --- a/example/genesis.block +++ b/example/genesis.block @@ -1,116 +1,119 @@ { - "signatures": [], - "created_ts": 0, - "hash": "ef9781aadf6d4d5ac8d01e14f7bbc805278ed9bb7200dafe8335bfc3a254e82b", - "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "height": 1, - "txs_number": 1, - "transactions": [ - { - "signatures": [], - "created_ts": 0, - "creator_account_id": "", - "tx_counter": 0, - "commands": [ - { - "command_type": "AddPeer", - "peer": { - "address": "localhost:10001", - "peer_key": "292a8714694095edce6be799398ed5d6244cd7be37eb813106b217d850d261f2" - } - }, - { - "command_type": "CreateRole", - "role_name": "admin", - "permissions": [ - "can_add_peer", - "can_add_signatory", - "can_create_account", - "can_create_domain", - "can_get_my_acc_detail", - "can_get_all_acc_detail", - "can_get_all_acc_ast", - "can_get_all_acc_ast_txs", - "can_get_all_acc_txs", - "can_get_all_accounts", - "can_get_all_signatories", - "can_get_all_txs", - "can_get_roles", - "can_read_assets", - "can_remove_signatory", - "can_set_detail", - "can_set_quorum" - ] - }, - { - "command_type": "CreateRole", - "role_name": "user", - "permissions": [ - "can_add_signatory", - "can_get_my_account", - "can_get_my_acc_detail", - "can_get_domain_acc_detail", - "can_get_my_acc_ast", - "can_get_my_acc_ast_txs", - "can_get_my_acc_txs", - "can_get_my_signatories", - "can_get_my_txs", - "can_grant_can_add_signatory", - "can_grant_can_remove_signatory", - "can_grant_can_set_detail", - "can_grant_can_set_quorum", - "can_grant_can_transfer", - "can_receive", - "can_remove_signatory", - "can_set_quorum", - "can_set_detail", - "can_transfer" - ] - }, - { - "command_type": "CreateRole", - "role_name": "money_creator", - "permissions": [ - "can_add_asset_qty", - "can_create_asset", - "can_receive", - "can_transfer" - ] - }, - { - "command_type": "CreateDomain", - "domain_id": "test", - "user_default_role": "user" - }, - { - "command_type": "CreateAsset", - "asset_name": "coin", - "domain_id": "test", - "precision": 2 - }, - { - "command_type": "CreateAccount", - "account_name": "admin", - "domain_id": "test", - "pubkey": "407e57f50ca48969b08ba948171bb2435e035d82cec417e18e4a38f5fb113f83" - }, - { - "command_type": "CreateAccount", - "account_name": "test", - "domain_id": "test", - "pubkey": "359f925e4eeecfdd6aa1abc0b79a6a121a5dd63bb612b603247ea4f8ad160156" - }, - { - "command_type": "AppendRole", - "account_id": "admin@test", - "role_name": "admin" - }, - { - "command_type": "AppendRole", - "account_id": "admin@test", - "role_name": "money_creator" - } - ] - } - ] + "payload":{ + "transactions":[ + { + "payload":{ + "commands":[ + { + "addPeer":{ + "peer":{ + "address":"localhost:10001", + "peerKey":"0E2icbV/5jQmrh3Jf2lSEEA3QR/PTztzncIX9F5fyZs=" + } + } + }, + { + "createRole":{ + "roleName":"admin", + "permissions":[ + "can_add_peer", + "can_add_signatory", + "can_create_account", + "can_create_domain", + "can_get_all_acc_ast", + "can_get_all_acc_ast_txs", + "can_get_all_acc_detail", + "can_get_all_acc_txs", + "can_get_all_accounts", + "can_get_all_signatories", + "can_get_all_txs", + "can_get_roles", + "can_read_assets", + "can_remove_signatory", + "can_set_quorum" + ] + } + }, + { + "createRole":{ + "roleName":"user", + "permissions":[ + "can_add_signatory", + "can_get_my_acc_ast", + "can_get_my_acc_ast_txs", + "can_get_my_acc_detail", + "can_get_my_acc_txs", + "can_get_my_account", + "can_get_my_signatories", + "can_get_my_txs", + "can_grant_can_add_signatory", + "can_grant_can_remove_signatory", + "can_grant_can_set_detail", + "can_grant_can_set_quorum", + "can_grant_can_transfer", + "can_receive", + "can_remove_signatory", + "can_set_quorum", + "can_transfer" + ] + } + }, + { + "createRole":{ + "roleName":"money_creator", + "permissions":[ + "can_add_asset_qty", + "can_create_asset", + "can_receive", + "can_transfer" + ] + } + }, + { + "createDomain":{ + "domainId":"test", + "defaultRole":"user" + } + }, + { + "createAsset":{ + "assetName":"coin", + "domainId":"test", + "precision":2 + } + }, + { + "createAccount":{ + "accountName":"admin", + "domainId":"test", + "mainPubkey":"iJ9riB4zG+IUh9t33PMsX409XoBm540v6sQjn+kdQW8=" + } + }, + { + "createAccount":{ + "accountName":"test", + "domainId":"test", + "mainPubkey":"3MfszkSPLhkKSBrsfKIe5S7aVG5mC0gg9JdtATIVcJc=" + } + }, + { + "appendRole":{ + "accountId":"admin@test", + "roleName":"admin" + } + }, + { + "appendRole":{ + "accountId":"admin@test", + "roleName":"money_creator" + } + } + ] + } + } + ], + "txNumber":1, + "height":"1", + "prevBlockHash":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } } diff --git a/example/node0.priv b/example/node0.priv index 4ee1612c19..1362af9c39 100644 --- a/example/node0.priv +++ b/example/node0.priv @@ -1 +1 @@ -8316fe25fda2bb3964ae756251b5f1fe010fafe56443978d524dc6485548be76 \ No newline at end of file +41209bd907789fd5a796ac6bdff908bac2f7abcf7a1d0b99a18290f285f6e965 \ No newline at end of file diff --git a/example/node0.pub b/example/node0.pub index e3e0793df3..bb7c1c9dcd 100644 --- a/example/node0.pub +++ b/example/node0.pub @@ -1 +1 @@ -292a8714694095edce6be799398ed5d6244cd7be37eb813106b217d850d261f2 \ No newline at end of file +d04da271b57fe63426ae1dc97f6952104037411fcf4f3b739dc217f45e5fc99b \ No newline at end of file diff --git a/example/test@test.priv b/example/test@test.priv index 7e6f039b91..f41898d68e 100644 --- a/example/test@test.priv +++ b/example/test@test.priv @@ -1 +1 @@ -4209ba343a92f4d086921a3f3c1eb26f50f2fece610ec3524058de79281564c2 \ No newline at end of file +2e5b37fd881f260323dca4f0776e6e1e969bef7dab14673858f82663e7cd8556 \ No newline at end of file diff --git a/example/test@test.pub b/example/test@test.pub index 556317b45f..95419850c9 100644 --- a/example/test@test.pub +++ b/example/test@test.pub @@ -1 +1 @@ -359f925e4eeecfdd6aa1abc0b79a6a121a5dd63bb612b603247ea4f8ad160156 \ No newline at end of file +dcc7ecce448f2e190a481aec7ca21ee52eda546e660b4820f4976d0132157097 \ No newline at end of file diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index cc9d533804..542e4b2302 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -20,8 +20,10 @@ #include #include +#include "backend/protobuf/from_old_model.hpp" #include "client.hpp" #include "common/assert_config.hpp" +#include "converters/protobuf/json_proto_converter.hpp" #include "crypto/keys_manager_impl.hpp" #include "grpc_response_handler.hpp" #include "interactive/interactive_cli.hpp" @@ -94,7 +96,9 @@ int main(int argc, char *argv[]) { JsonBlockFactory json_factory; auto doc = json_factory.serialize(block); std::ofstream output_file("genesis.block"); - output_file << jsonToString(doc); + output_file << shared_model::converters::protobuf::modelToJson( + shared_model::proto::from_old(block) + ); logger->info("File saved to genesis.block"); } // Create new pub/priv key, register in Iroha Network From f41eee8a859b9e10d0b20bb321e12afd9e684072 Mon Sep 17 00:00:00 2001 From: Alexey Chernyshov Date: Thu, 29 Mar 2018 09:28:15 +0300 Subject: [PATCH 018/110] fix cmake fix build and remove unused captures fix unused includes Signed-off-by: Alexey Chernyshov --- iroha-cli/main.cpp | 2 -- irohad/ametsuchi/impl/postgres_block_query.cpp | 2 +- irohad/ametsuchi/impl/storage_impl.cpp | 5 ----- irohad/main/CMakeLists.txt | 8 ++++---- test/integration/acceptance/CMakeLists.txt | 2 +- test/module/irohad/common/CMakeLists.txt | 9 +++------ test/module/irohad/common/raw_block_loader_test.cpp | 2 -- 7 files changed, 9 insertions(+), 21 deletions(-) diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index 542e4b2302..c3e0bbfdcb 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -93,8 +93,6 @@ int main(int argc, char *argv[]) { 0, std::move(peers_address)); auto block = generator.generateGenesisBlock(0, {transaction}); // Convert to json - JsonBlockFactory json_factory; - auto doc = json_factory.serialize(block); std::ofstream output_file("genesis.block"); output_file << shared_model::converters::protobuf::modelToJson( shared_model::proto::from_old(block) diff --git a/irohad/ametsuchi/impl/postgres_block_query.cpp b/irohad/ametsuchi/impl/postgres_block_query.cpp index dd33cd42e9..7477048ce1 100644 --- a/irohad/ametsuchi/impl/postgres_block_query.cpp +++ b/irohad/ametsuchi/impl/postgres_block_query.cpp @@ -113,7 +113,7 @@ namespace iroha { std::function PostgresBlockQuery::callback( const rxcpp::subscriber &subscriber, uint64_t block_id) { return [this, &subscriber, block_id](pqxx::result &result) { - auto block = block_store_.get(block_id) | [this](const auto &bytes) { + auto block = block_store_.get(block_id) | [](const auto &bytes) { return shared_model::converters::protobuf::jsonToModel< shared_model::proto::Block>(bytesToString(bytes)); }; diff --git a/irohad/ametsuchi/impl/storage_impl.cpp b/irohad/ametsuchi/impl/storage_impl.cpp index 4d1f8e4725..150c30f948 100644 --- a/irohad/ametsuchi/impl/storage_impl.cpp +++ b/irohad/ametsuchi/impl/storage_impl.cpp @@ -23,13 +23,8 @@ #include "ametsuchi/impl/postgres_wsv_query.hpp" #include "ametsuchi/impl/temporary_wsv_impl.hpp" #include "converters/protobuf/json_proto_converter.hpp" -#include "model/execution/command_executor_factory.hpp" // for CommandExecutorFactory #include "postgres_ordering_service_persistent_state.hpp" -// TODO: 14-02-2018 Alexey Chernyshov remove this after relocation to -// shared_model https://soramitsu.atlassian.net/browse/IR-887 -#include "backend/protobuf/from_old_model.hpp" - namespace iroha { namespace ametsuchi { diff --git a/irohad/main/CMakeLists.txt b/irohad/main/CMakeLists.txt index 39d1427740..8f071832e5 100644 --- a/irohad/main/CMakeLists.txt +++ b/irohad/main/CMakeLists.txt @@ -24,9 +24,9 @@ target_link_libraries(server_runner boost # iroha::expected::Result ) -add_library(raw_block_insertion impl/raw_block_loader.cpp) -target_link_libraries(raw_block_insertion - json_model_converters +add_library(raw_block_loader impl/raw_block_loader.cpp) +target_link_libraries(raw_block_loader + model_interfaces ) add_library(application @@ -57,7 +57,7 @@ target_link_libraries(application add_executable(irohad irohad.cpp) target_link_libraries(irohad application - raw_block_insertion + raw_block_loader gflags rapidjson keys_manager diff --git a/test/integration/acceptance/CMakeLists.txt b/test/integration/acceptance/CMakeLists.txt index e73ab3769e..588066356f 100644 --- a/test/integration/acceptance/CMakeLists.txt +++ b/test/integration/acceptance/CMakeLists.txt @@ -18,7 +18,7 @@ addtest(tx_acceptance_test tx_acceptance_test.cpp) target_link_libraries(tx_acceptance_test application - raw_block_insertion + raw_block_loader model_generators integration_framework shared_model_stateless_validation diff --git a/test/module/irohad/common/CMakeLists.txt b/test/module/irohad/common/CMakeLists.txt index 56dea9f068..879ed80660 100644 --- a/test/module/irohad/common/CMakeLists.txt +++ b/test/module/irohad/common/CMakeLists.txt @@ -3,10 +3,7 @@ target_link_libraries(blob_converter_test common ) -AddTest(block_insertion_test raw_block_loader_test.cpp) -target_link_libraries(block_insertion_test - json_model_converters - raw_block_insertion - shared_model_cryptography_model - logger +AddTest(raw_block_loader_test raw_block_loader_test.cpp) +target_link_libraries(raw_block_loader_test + raw_block_loader ) diff --git a/test/module/irohad/common/raw_block_loader_test.cpp b/test/module/irohad/common/raw_block_loader_test.cpp index 353c4e73d4..62b23a7a5e 100644 --- a/test/module/irohad/common/raw_block_loader_test.cpp +++ b/test/module/irohad/common/raw_block_loader_test.cpp @@ -42,8 +42,6 @@ TEST(BlockLoaderTest, BlockLoaderJsonParsing) { auto block = loader.parseBlock(str); - - ASSERT_TRUE(block); auto b = block.value(); From d4917932014a8a9708fe453ea4aa9054676a0b1c Mon Sep 17 00:00:00 2001 From: Dumitru Date: Mon, 9 Apr 2018 15:03:55 +0300 Subject: [PATCH 019/110] Shared model/new block loader (#1164) * Block loader impl Signed-off-by: Dumitru Block loader service Signed-off-by: Dumitru New block loader Signed-off-by: Dumitru * Fix block loader test Signed-off-by: Dumitru * Remove unused imports, clang-format, remove unused variables in lambda closure Signed-off-by: Dumitru * Remove unused imports Signed-off-by: Dumitru * Static to dynamic pointer cast Signed-off-by: Dumitru --- irohad/network/impl/block_loader_impl.cpp | 32 +++++++------------ irohad/network/impl/block_loader_impl.hpp | 11 ++++--- irohad/network/impl/block_loader_service.cpp | 29 +++++++---------- .../irohad/network/block_loader_test.cpp | 2 +- 4 files changed, 31 insertions(+), 43 deletions(-) diff --git a/irohad/network/impl/block_loader_impl.cpp b/irohad/network/impl/block_loader_impl.cpp index 01670afb0c..6557b7986a 100644 --- a/irohad/network/impl/block_loader_impl.cpp +++ b/irohad/network/impl/block_loader_impl.cpp @@ -17,8 +17,6 @@ #include "network/impl/block_loader_impl.hpp" -#include - #include #include "backend/protobuf/block.hpp" @@ -43,7 +41,6 @@ BlockLoaderImpl::BlockLoaderImpl( const char *kPeerNotFound = "Cannot find peer"; const char *kTopBlockRetrieveFail = "Failed to retrieve top block"; -const char *kInvalidBlockSignatures = "Block signatures are invalid"; const char *kPeerRetrieveFail = "Failed to retrieve peers"; const char *kPeerFindFail = "Failed to find requested peer"; @@ -51,14 +48,11 @@ rxcpp::observable> BlockLoaderImpl::retrieveBlocks( const PublicKey &peer_pubkey) { return rxcpp::observable<>::create>( [this, peer_pubkey](auto subscriber) { - boost::optional top_block; + boost::optional> top_block; block_query_->getTopBlocks(1) .subscribe_on(rxcpp::observe_on_new_thread()) .as_blocking() - .subscribe([&top_block](auto block) { - top_block = - *std::unique_ptr(block->makeOldModel()); - }); + .subscribe([&top_block](auto block) { top_block = block; }); if (not top_block) { log_->error(kTopBlockRetrieveFail); subscriber.on_completed(); @@ -77,10 +71,10 @@ rxcpp::observable> BlockLoaderImpl::retrieveBlocks( protocol::Block block; // request next block to our top - request.set_height(top_block->height + 1); + request.set_height((*top_block)->height() + 1); auto reader = - this->getPeerStub(peer.value()).retrieveBlocks(&context, request); + this->getPeerStub(**peer).retrieveBlocks(&context, request); while (reader->Read(&block)) { shared_model::proto::TransportBuilder< shared_model::proto::Block, @@ -122,8 +116,7 @@ boost::optional> BlockLoaderImpl::retrieveBlock( // request block with specified hash request.set_hash(toBinaryString(block_hash)); - auto status = - getPeerStub(peer.value()).retrieveBlock(&context, request, &block); + auto status = getPeerStub(**peer).retrieveBlock(&context, request, &block); if (not status.ok()) { log_->warn(status.error_message()); return boost::none; @@ -140,8 +133,8 @@ boost::optional> BlockLoaderImpl::retrieveBlock( return boost::optional>(std::move(result)); } -boost::optional BlockLoaderImpl::findPeer( - const shared_model::crypto::PublicKey &pubkey) { +boost::optional> +BlockLoaderImpl::findPeer(const shared_model::crypto::PublicKey &pubkey) { auto peers = peer_query_->getLedgerPeers(); if (not peers) { log_->error(kPeerRetrieveFail); @@ -157,19 +150,18 @@ boost::optional BlockLoaderImpl::findPeer( log_->error(kPeerFindFail); return boost::none; } - - return *std::unique_ptr((*it)->makeOldModel()); + return *it; } proto::Loader::Stub &BlockLoaderImpl::getPeerStub( - const iroha::model::Peer &peer) { - auto it = peer_connections_.find(peer); + const shared_model::interface::Peer &peer) { + auto it = peer_connections_.find(peer.address()); if (it == peer_connections_.end()) { it = peer_connections_ .insert(std::make_pair( - peer, + peer.address(), proto::Loader::NewStub(grpc::CreateChannel( - peer.address, grpc::InsecureChannelCredentials())))) + peer.address(), grpc::InsecureChannelCredentials())))) .first; } return *it->second; diff --git a/irohad/network/impl/block_loader_impl.hpp b/irohad/network/impl/block_loader_impl.hpp index 2af25b7d3e..b78c75995f 100644 --- a/irohad/network/impl/block_loader_impl.hpp +++ b/irohad/network/impl/block_loader_impl.hpp @@ -36,7 +36,8 @@ namespace iroha { std::shared_ptr peer_query, std::shared_ptr block_query, std::shared_ptr = - std::make_shared()); + std::make_shared< + shared_model::validation::DefaultBlockValidator>()); rxcpp::observable> retrieveBlocks( @@ -54,16 +55,18 @@ namespace iroha { * @return peer, if it was found, otherwise nullopt * TODO 14/02/17 (@l4l) IR-960 rework method with returning result */ - boost::optional findPeer( + boost::optional> findPeer( const shared_model::crypto::PublicKey &pubkey); /** * Get or create a RPC stub for connecting to peer * @param peer for connecting * @return RPC stub */ - proto::Loader::Stub &getPeerStub(const model::Peer &peer); + proto::Loader::Stub &getPeerStub( + const shared_model::interface::Peer &peer); - std::unordered_map> + std::unordered_map> peer_connections_; std::shared_ptr peer_query_; std::shared_ptr block_query_; diff --git a/irohad/network/impl/block_loader_service.cpp b/irohad/network/impl/block_loader_service.cpp index bdd6d393bf..a0afac026d 100644 --- a/irohad/network/impl/block_loader_service.cpp +++ b/irohad/network/impl/block_loader_service.cpp @@ -16,13 +16,10 @@ */ #include "network/impl/block_loader_service.hpp" - -#include "common/byteutils.hpp" +#include "backend/protobuf/block.hpp" using namespace iroha; using namespace iroha::ametsuchi; -using namespace iroha::model; -using namespace iroha::model::converters; using namespace iroha::network; BlockLoaderService::BlockLoaderService(std::shared_ptr storage) @@ -35,9 +32,9 @@ grpc::Status BlockLoaderService::retrieveBlocks( const proto::BlocksRequest *request, ::grpc::ServerWriter<::iroha::protocol::Block> *writer) { storage_->getBlocksFrom(request->height()) - .map([this](auto block) { - return factory_.serialize( - *std::unique_ptr(block->makeOldModel())); + .map([](auto block) { + return std::dynamic_pointer_cast(block) + ->getTransport(); }) .as_blocking() .subscribe([writer](auto block) { writer->Write(block); }); @@ -48,23 +45,19 @@ grpc::Status BlockLoaderService::retrieveBlock( ::grpc::ServerContext *context, const proto::BlockRequest *request, protocol::Block *response) { - const auto hash = stringToBlob(request->hash()); - if (not hash) { - log_->error("Bad hash in request, {}", - bytestringToHexstring(request->hash())); + const auto hash = shared_model::crypto::Hash(request->hash()); + if (hash.size() == 0) { + log_->error("Bad hash in request"); return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Bad hash provided"); } boost::optional result; storage_->getBlocksFrom(1) - .filter([hash](auto block) { - return shared_model::crypto::toBinaryString(block->hash()) - == hash->to_string(); - }) - .map([this](auto block) { - return factory_.serialize( - *std::unique_ptr(block->makeOldModel())); + .filter([&hash](auto block) { return block->hash() == hash; }) + .map([](auto block) { + return std::dynamic_pointer_cast(block) + ->getTransport(); }) .as_blocking() .subscribe([&result](auto block) { result = block; }); diff --git a/test/module/irohad/network/block_loader_test.cpp b/test/module/irohad/network/block_loader_test.cpp index 6dd050cd65..633253ecf3 100644 --- a/test/module/irohad/network/block_loader_test.cpp +++ b/test/module/irohad/network/block_loader_test.cpp @@ -203,7 +203,7 @@ TEST_F(BlockLoaderTest, ValidWhenBlockPresent) { auto block = loader->retrieveBlock(peer_key, requested.hash()); ASSERT_TRUE(block); - ASSERT_EQ(*(*block), requested); + ASSERT_EQ(**block, requested); } /** From 9ebde5af3a438a527184ad66db4b818972b0f211 Mon Sep 17 00:00:00 2001 From: Alexey Date: Fri, 13 Apr 2018 15:34:31 +0300 Subject: [PATCH 020/110] Feature/rework key manager shm (#1185) * move keys_manager to shared_model Signed-off-by: Alexey Chernyshov --- iroha-cli/main.cpp | 25 ++-- .../yac/impl/yac_crypto_provider_impl.cpp | 9 +- .../yac/impl/yac_crypto_provider_impl.hpp | 6 +- irohad/main/application.cpp | 17 +-- irohad/main/application.hpp | 5 +- irohad/main/impl/consensus_init.cpp | 6 +- irohad/main/impl/consensus_init.hpp | 7 +- irohad/main/irohad.cpp | 8 +- .../generators/impl/transaction_generator.cpp | 6 +- libs/crypto/CMakeLists.txt | 2 +- libs/crypto/keys_manager.hpp | 36 +++-- libs/crypto/keys_manager_impl.cpp | 124 ++++++------------ libs/crypto/keys_manager_impl.hpp | 23 ++-- .../integration_framework/test_irohad.hpp | 2 +- .../yac/yac_crypto_provider_test.cpp | 8 +- test/module/libs/crypto/keys_manager_test.cpp | 4 +- 16 files changed, 129 insertions(+), 159 deletions(-) diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index c3e0bbfdcb..42333694a0 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -34,10 +34,9 @@ #include "validators.hpp" // Account information -DEFINE_bool( - new_account, - false, - "Generate and save locally new public/private keys"); +DEFINE_bool(new_account, + false, + "Generate and save locally new public/private keys"); DEFINE_string(account_name, "", "Name of the account. Must be unique in iroha network"); @@ -64,7 +63,6 @@ DEFINE_string(peers_address, // Run iroha-cli in interactive mode DEFINE_bool(interactive, true, "Run iroha-cli in interactive mode"); - using namespace iroha::protocol; using namespace iroha::model::generators; using namespace iroha::model::converters; @@ -160,20 +158,17 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } iroha::KeysManagerImpl manager((path / FLAGS_account_name).string()); - boost::optional keypair; - if (FLAGS_pass_phrase.size() != 0) { - keypair = manager.loadKeys(FLAGS_pass_phrase); - } else { - keypair = manager.loadKeys(); - } + auto keypair = FLAGS_pass_phrase.size() != 0 + ? manager.loadKeys(FLAGS_pass_phrase) + : manager.loadKeys(); if (not keypair) { logger->error( "Cannot load specified keypair, or keypair is invalid. Path: {}, " - "keypair name: {}. Use --key_path to path to your keypair. \nMaybe wrong pass phrase (\"{}\")?", + "keypair name: {}. Use --key_path with path of your keypair. \n" + "Maybe wrong pass phrase (\"{}\")?", path.string(), FLAGS_account_name, - FLAGS_pass_phrase - ); + FLAGS_pass_phrase); return EXIT_FAILURE; } // TODO 13/09/17 grimadas: Init counters from Iroha, or read from disk? @@ -185,7 +180,7 @@ int main(int argc, char *argv[]) { 0, 0, std::make_shared( - *keypair)); + *std::unique_ptr(keypair->makeOldModel()))); interactiveCli.run(); } else { logger->error("Invalid flags"); diff --git a/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp b/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp index 77401f3399..585c3bba7b 100644 --- a/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp +++ b/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp @@ -23,7 +23,7 @@ namespace iroha { namespace consensus { namespace yac { - CryptoProviderImpl::CryptoProviderImpl(const keypair_t &keypair) + CryptoProviderImpl::CryptoProviderImpl(const shared_model::crypto::Keypair &keypair) : keypair_(keypair) {} bool CryptoProviderImpl::verify(CommitMessage msg) { @@ -52,14 +52,15 @@ namespace iroha { VoteMessage CryptoProviderImpl::getVote(YacHash hash) { VoteMessage vote; vote.hash = hash; + keypair_t keypair = *std::unique_ptr(keypair_.makeOldModel()); auto signature = iroha::sign( iroha::sha3_256( PbConverters::serializeVote(vote).hash().SerializeAsString()) .to_string(), - keypair_.pubkey, - keypair_.privkey); + keypair.pubkey, + keypair.privkey); vote.signature.signature = signature; - vote.signature.pubkey = keypair_.pubkey; + vote.signature.pubkey = keypair.pubkey; return vote; } diff --git a/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp b/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp index d55288b087..5c07ebb3cb 100644 --- a/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp +++ b/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp @@ -19,13 +19,15 @@ #define IROHA_YAC_CRYPTO_PROVIDER_IMPL_HPP #include "consensus/yac/yac_crypto_provider.hpp" +#include "cryptography/keypair.hpp" namespace iroha { namespace consensus { namespace yac { class CryptoProviderImpl : public YacCryptoProvider { public: - explicit CryptoProviderImpl(const keypair_t &keypair); + explicit CryptoProviderImpl( + const shared_model::crypto::Keypair &keypair); bool verify(CommitMessage msg) override; @@ -36,7 +38,7 @@ namespace iroha { VoteMessage getVote(YacHash hash) override; private: - keypair_t keypair_; + shared_model::crypto::Keypair keypair_; }; } // namespace yac } // namespace consensus diff --git a/irohad/main/application.cpp b/irohad/main/application.cpp index 3af241645c..b919553864 100644 --- a/irohad/main/application.cpp +++ b/irohad/main/application.cpp @@ -42,7 +42,7 @@ Irohad::Irohad(const std::string &block_store_dir, std::chrono::milliseconds proposal_delay, std::chrono::milliseconds vote_delay, std::chrono::milliseconds load_delay, - const keypair_t &keypair) + const shared_model::crypto::Keypair &keypair) : block_store_dir_(block_store_dir), pg_conn_(pg_conn), torii_port_(torii_port), @@ -136,11 +136,8 @@ void Irohad::initPeerQuery() { * Initializing crypto provider */ void Irohad::initCryptoProvider() { - shared_model::crypto::Keypair keypair_( - shared_model::crypto::PublicKey(keypair.pubkey.to_string()), - shared_model::crypto::PrivateKey(keypair.privkey.to_string())); crypto_signer_ = - std::make_shared>(keypair_); + std::make_shared>(keypair); log_->info("[Init] => crypto provider"); } @@ -183,8 +180,7 @@ void Irohad::initSimulator() { * Initializing block loader */ void Irohad::initBlockLoader() { - block_loader = loader_init.initBlockLoader( - wsv, storage->getBlockQuery()); + block_loader = loader_init.initBlockLoader(wsv, storage->getBlockQuery()); log_->info("[Init] => block loader"); } @@ -194,7 +190,12 @@ void Irohad::initBlockLoader() { */ void Irohad::initConsensusGate() { consensus_gate = yac_init.initConsensusGate( - wsv, simulator, block_loader, keypair, vote_delay_, load_delay_); + wsv, + simulator, + block_loader, + keypair, + vote_delay_, + load_delay_); log_->info("[Init] => consensus gate"); } diff --git a/irohad/main/application.hpp b/irohad/main/application.hpp index 0fa00f558f..59daf94786 100644 --- a/irohad/main/application.hpp +++ b/irohad/main/application.hpp @@ -22,6 +22,7 @@ #include "ametsuchi/impl/storage_impl.hpp" #include "ametsuchi/ordering_service_persistent_state.hpp" #include "cryptography/crypto_provider/crypto_model_signer.hpp" +#include "cryptography/keypair.hpp" #include "logger/logger.hpp" #include "main/impl/block_loader_init.hpp" #include "main/impl/consensus_init.hpp" @@ -76,7 +77,7 @@ class Irohad { std::chrono::milliseconds proposal_delay, std::chrono::milliseconds vote_delay, std::chrono::milliseconds load_delay, - const iroha::keypair_t &keypair); + const shared_model::crypto::Keypair &keypair); /** * Initialization of whole objects in system @@ -204,7 +205,7 @@ class Irohad { public: std::shared_ptr storage; - iroha::keypair_t keypair; + shared_model::crypto::Keypair keypair; grpc::ServerBuilder builder; }; diff --git a/irohad/main/impl/consensus_init.cpp b/irohad/main/impl/consensus_init.cpp index d219c66a09..f90195a83a 100644 --- a/irohad/main/impl/consensus_init.cpp +++ b/irohad/main/impl/consensus_init.cpp @@ -38,7 +38,7 @@ namespace iroha { return consensus_network; } - auto YacInit::createCryptoProvider(const keypair_t &keypair) { + auto YacInit::createCryptoProvider(const shared_model::crypto::Keypair &keypair) { auto crypto = std::make_shared(keypair); return crypto; @@ -54,7 +54,7 @@ namespace iroha { std::shared_ptr YacInit::createYac( ClusterOrdering initial_order, - const keypair_t &keypair, + const shared_model::crypto::Keypair &keypair, std::chrono::milliseconds delay_milliseconds) { return Yac::create(YacVoteStorage(), createNetwork(), @@ -68,7 +68,7 @@ namespace iroha { std::shared_ptr wsv, std::shared_ptr block_creator, std::shared_ptr block_loader, - const keypair_t &keypair, + const shared_model::crypto::Keypair &keypair, std::chrono::milliseconds vote_delay_milliseconds, std::chrono::milliseconds load_delay_milliseconds) { auto peer_orderer = createPeerOrderer(wsv); diff --git a/irohad/main/impl/consensus_init.hpp b/irohad/main/impl/consensus_init.hpp index 97406e8009..2f9b999ded 100644 --- a/irohad/main/impl/consensus_init.hpp +++ b/irohad/main/impl/consensus_init.hpp @@ -30,6 +30,7 @@ #include "consensus/yac/yac_gate.hpp" #include "consensus/yac/yac_hash_provider.hpp" #include "consensus/yac/yac_peer_orderer.hpp" +#include "cryptography/keypair.hpp" #include "network/block_loader.hpp" #include "simulator/block_creator.hpp" @@ -45,7 +46,7 @@ namespace iroha { auto createNetwork(); - auto createCryptoProvider(const keypair_t &keypair); + auto createCryptoProvider(const shared_model::crypto::Keypair &keypair); auto createTimer(); @@ -53,7 +54,7 @@ namespace iroha { std::shared_ptr createYac( ClusterOrdering initial_order, - const keypair_t &keypair, + const shared_model::crypto::Keypair &keypair, std::chrono::milliseconds delay_milliseconds); public: @@ -61,7 +62,7 @@ namespace iroha { std::shared_ptr wsv, std::shared_ptr block_creator, std::shared_ptr block_loader, - const keypair_t &keypair, + const shared_model::crypto::Keypair &keypair, std::chrono::milliseconds vote_delay_milliseconds, std::chrono::milliseconds load_delay_milliseconds); diff --git a/irohad/main/irohad.cpp b/irohad/main/irohad.cpp index 9fac29ac32..a93b7f9c7b 100644 --- a/irohad/main/irohad.cpp +++ b/irohad/main/irohad.cpp @@ -100,11 +100,9 @@ int main(int argc, char *argv[]) { // Reading public and private key files iroha::KeysManagerImpl keysManager(FLAGS_keypair_name); - iroha::keypair_t keypair{}; + auto keypair = keysManager.loadKeys(); // Check if both keys are read properly - if (auto loadedKeypair = keysManager.loadKeys()) { - keypair = *loadedKeypair; - } else { + if (not keypair) { // Abort execution if not log->error("Failed to load keypair"); return EXIT_FAILURE; @@ -119,7 +117,7 @@ int main(int argc, char *argv[]) { std::chrono::milliseconds(config[mbr::ProposalDelay].GetUint()), std::chrono::milliseconds(config[mbr::VoteDelay].GetUint()), std::chrono::milliseconds(config[mbr::LoadDelay].GetUint()), - keypair); + *keypair); // Check if iroha daemon storage was successfully initialized if (not irohad.storage) { diff --git a/irohad/model/generators/impl/transaction_generator.cpp b/irohad/model/generators/impl/transaction_generator.cpp index 0632dc2f98..ae5d6d6682 100644 --- a/irohad/model/generators/impl/transaction_generator.cpp +++ b/irohad/model/generators/impl/transaction_generator.cpp @@ -36,7 +36,7 @@ namespace iroha { for (size_t i = 0; i < peers_address.size(); ++i) { KeysManagerImpl manager("node" + std::to_string(i)); manager.createKeys(); - auto keypair = *manager.loadKeys(); + auto keypair = *std::unique_ptr(manager.loadKeys()->makeOldModel()); tx.commands.push_back(command_generator.generateAddPeer( Peer(peers_address[i], keypair.pubkey))); } @@ -57,12 +57,12 @@ namespace iroha { // Create accounts KeysManagerImpl manager("admin@test"); manager.createKeys(); - auto keypair = *manager.loadKeys(); + auto keypair = *std::unique_ptr(manager.loadKeys()->makeOldModel()); tx.commands.push_back(command_generator.generateCreateAccount( "admin", "test", keypair.pubkey)); manager = KeysManagerImpl("test@test"); manager.createKeys(); - keypair = *manager.loadKeys(); + keypair = *std::unique_ptr(manager.loadKeys()->makeOldModel()); tx.commands.push_back(command_generator.generateCreateAccount( "test", "test", keypair.pubkey)); diff --git a/libs/crypto/CMakeLists.txt b/libs/crypto/CMakeLists.txt index d853a9dce1..3c0346253f 100644 --- a/libs/crypto/CMakeLists.txt +++ b/libs/crypto/CMakeLists.txt @@ -21,6 +21,6 @@ add_library(keys_manager ) target_link_libraries(keys_manager - ed25519_crypto + shared_model_cryptography logger ) diff --git a/libs/crypto/keys_manager.hpp b/libs/crypto/keys_manager.hpp index ad2337f5bd..523c891fd0 100644 --- a/libs/crypto/keys_manager.hpp +++ b/libs/crypto/keys_manager.hpp @@ -15,15 +15,23 @@ * limitations under the License. */ -#ifndef IROHA_CLI_KEYS_MANAGER_HPP -#define IROHA_CLI_KEYS_MANAGER_HPP +#ifndef IROHA_KEYS_MANAGER_HPP +#define IROHA_KEYS_MANAGER_HPP #include + #include -namespace iroha { - struct keypair_t; +namespace shared_model { + namespace crypto { + class Keypair; + } +} +namespace iroha { + /** + * Interface provides facilities to create and store keypair on disk. + */ class KeysManager { public: virtual ~KeysManager() = default; @@ -34,14 +42,6 @@ namespace iroha { */ virtual bool createKeys() = 0; - /** - * Load plain-text keys associated with the manager, then validate loaded - * keypair by signing and verifying signature of test message - * @return nullopt if no keypair found locally, or verification failure; - * related keypair otherwise - */ - virtual boost::optional loadKeys() = 0; - /** * Create keys a new keypair and store it encrypted on disk * @param pass_phrase is a password for the keys @@ -49,6 +49,14 @@ namespace iroha { */ virtual bool createKeys(const std::string &pass_phrase) = 0; + /** + * Load plain-text keys associated with the manager, then validate loaded + * keypair by signing and verifying signature of test message + * @return nullopt if no keypair found locally, or verification failure; + * related keypair otherwise + */ + virtual boost::optional loadKeys() = 0; + /** * Load encrypted keys associated with the manager, then validate loaded * keypair by signing and verifying signature of test message @@ -56,9 +64,9 @@ namespace iroha { * @return nullopt if no keypair found locally, or verification failure; * related keypair otherwise */ - virtual boost::optional loadKeys( + virtual boost::optional loadKeys( const std::string &pass_phrase) = 0; }; } // namespace iroha -#endif // IROHA_CLI_KEYS_MANAGER_HPP +#endif // IROHA_KEYS_MANAGER_HPP diff --git a/libs/crypto/keys_manager_impl.cpp b/libs/crypto/keys_manager_impl.cpp index 8b9b2d1eb7..f9d7d968f8 100644 --- a/libs/crypto/keys_manager_impl.cpp +++ b/libs/crypto/keys_manager_impl.cpp @@ -17,37 +17,16 @@ #include "crypto/keys_manager_impl.hpp" -#include -#include #include -#include -#include #include "common/byteutils.hpp" -#include "common/types.hpp" // for keypair_t, pubkey_t, privkey_t -#include "cryptography/ed25519_sha3_impl/internal/ed25519_impl.hpp" -#include "cryptography/ed25519_sha3_impl/internal/sha3_hash.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" + +using namespace shared_model::crypto; using iroha::operator|; namespace iroha { - /** - * Return a function which will try deserialize the value to - * specified field in given keypair - * @tparam T - keypair field type - * @tparam V - value type to deserialize - * @param field - keypair field to be deserialized - * @param value - value to be deserialized - * @return function that will return keypair on success, otherwise nullopt - */ - template - static auto deserializeKeypairField(T keypair_t::*field, const V &value) { - return [=](auto keypair) mutable { - return hexstringToArray(value) - | assignObjectField(keypair, field); - }; - } - /** * Function for the key encryption via XOR * @tparam is a key type @@ -71,39 +50,23 @@ namespace iroha { /** * Function for XOR decryption */ - static constexpr auto decrypt = encrypt; - - /** - * Return a function which will try to deserialize and then decrypt private - * key via XORing with pass phrase - * @param s is an encrypted data from file - * @param pass_phrase for decryption - * @return function that will set keypair::privkey on successful - * deserialization and decryption - */ - static auto deserializedEncrypted(const std::string &s, - const std::string &pass_phrase) { - constexpr auto size = privkey_t::size(); - - return [=](auto keypair) mutable { - return hexstringToBytestring(s) | - [&](auto binstr) { - return boost::make_optional(decrypt(binstr, pass_phrase)); - } - | stringToBlob | assignObjectField(keypair, &keypair_t::privkey); - }; - } + static constexpr auto decrypt = encrypt; KeysManagerImpl::KeysManagerImpl(const std::string &account_name) : account_name_(std::move(account_name)), log_(logger::log("KeysManagerImpl")) {} - bool KeysManagerImpl::validate(const keypair_t &keypair) const { - std::string test = "12345"; - auto sig = - sign(sha3_256(test).to_string(), keypair.pubkey, keypair.privkey); - if (not verify(sha3_256(test).to_string(), keypair.pubkey, sig)) { - log_->error("key validation failed"); + bool KeysManagerImpl::validate(const Keypair &keypair) const { + try { + auto test = Blob("12345"); + auto sig = DefaultCryptoAlgorithmType::sign(test, keypair); + if (not DefaultCryptoAlgorithmType::verify( + sig, test, keypair.publicKey())) { + log_->error("key validation failed"); + return false; + } + } catch (const BadFormatException &exception) { + log_->error("Cannot validate keyapir: {}", exception.what()); return false; } return true; @@ -120,59 +83,58 @@ namespace iroha { return true; } - boost::optional KeysManagerImpl::loadKeys() { + boost::optional KeysManagerImpl::loadKeys() { std::string pub_key; std::string priv_key; - if (not loadFile(account_name_ + kPubExt, pub_key) - or not loadFile(account_name_ + kPrivExt, priv_key)) + if (not loadFile(account_name_ + kPublicKeyExtension, pub_key) + or not loadFile(account_name_ + kPrivateKeyExtension, priv_key)) return boost::none; - return boost::make_optional(keypair_t()) - | deserializeKeypairField(&keypair_t::pubkey, pub_key) - | deserializeKeypairField(&keypair_t::privkey, priv_key) | - [this](auto keypair) { - return this->validate(keypair) ? boost::make_optional(keypair) - : boost::none; - }; + Keypair keypair = Keypair(PublicKey(Blob::fromHexString(pub_key)), + PrivateKey(Blob::fromHexString(priv_key))); + + return this->validate(keypair) ? boost::make_optional(keypair) + : boost::none; } - boost::optional KeysManagerImpl::loadKeys( + boost::optional KeysManagerImpl::loadKeys( const std::string &pass_phrase) { std::string pub_key; std::string priv_key; - if (not loadFile(account_name_ + kPubExt, pub_key) - or not loadFile(account_name_ + kPrivExt, priv_key)) + if (not loadFile(account_name_ + kPublicKeyExtension, pub_key) + or not loadFile(account_name_ + kPrivateKeyExtension, priv_key)) return boost::none; - return boost::make_optional(keypair_t()) - | deserializeKeypairField(&keypair_t::pubkey, pub_key) - | deserializedEncrypted(priv_key, pass_phrase) | [this](auto keypair) { - return this->validate(keypair) ? boost::make_optional(keypair) - : boost::none; - }; + Keypair keypair = Keypair( + PublicKey(Blob::fromHexString(pub_key)), + PrivateKey(decrypt(Blob::fromHexString(priv_key).blob(), pass_phrase))); + + return this->validate(keypair) ? boost::make_optional(keypair) + : boost::none; } bool KeysManagerImpl::createKeys() { - auto key_pairs = create_keypair(); + Keypair keypair = DefaultCryptoAlgorithmType::generateKeypair(); - auto pub = key_pairs.pubkey.to_hexstring(); - auto priv = key_pairs.privkey.to_hexstring(); + auto pub = keypair.publicKey().hex(); + auto priv = keypair.privateKey().hex(); return store(pub, priv); } bool KeysManagerImpl::createKeys(const std::string &pass_phrase) { - auto key_pairs = create_keypair(); + Keypair keypair = DefaultCryptoAlgorithmType::generateKeypair(); - auto pub = key_pairs.pubkey.to_hexstring(); - auto priv = bytestringToHexstring(encrypt(key_pairs.privkey, pass_phrase)); + auto pub = keypair.publicKey().hex(); + auto priv = bytestringToHexstring( + encrypt(keypair.privateKey().blob(), pass_phrase)); return store(pub, priv); } bool KeysManagerImpl::store(const std::string &pub, const std::string &priv) { - std::ofstream pub_file(account_name_ + kPubExt); - std::ofstream priv_file(account_name_ + kPrivExt); + std::ofstream pub_file(account_name_ + kPublicKeyExtension); + std::ofstream priv_file(account_name_ + kPrivateKeyExtension); if (not pub_file or not priv_file) { return false; } @@ -182,6 +144,6 @@ namespace iroha { return pub_file.good() && priv_file.good(); } - const std::string KeysManagerImpl::kPubExt = ".pub"; - const std::string KeysManagerImpl::kPrivExt = ".priv"; + const std::string KeysManagerImpl::kPublicKeyExtension = ".pub"; + const std::string KeysManagerImpl::kPrivateKeyExtension = ".priv"; } // namespace iroha diff --git a/libs/crypto/keys_manager_impl.hpp b/libs/crypto/keys_manager_impl.hpp index 0dfe8b6c64..05ac450bb1 100644 --- a/libs/crypto/keys_manager_impl.hpp +++ b/libs/crypto/keys_manager_impl.hpp @@ -15,14 +15,13 @@ * limitations under the License. */ -#ifndef IROHA_CLI_KEYS_MANAGER_IMPL_HPP -#define IROHA_CLI_KEYS_MANAGER_IMPL_HPP +#ifndef IROHA_KEYS_MANAGER_IMPL_HPP +#define IROHA_KEYS_MANAGER_IMPL_HPP #include "crypto/keys_manager.hpp" #include - -#include "common/types.hpp" // for keypair_t, pubkey_t, privkey_t +#include "cryptography/keypair.hpp" #include "logger/logger.hpp" namespace iroha { @@ -31,15 +30,15 @@ namespace iroha { public: explicit KeysManagerImpl(const std::string &account_name); - boost::optional loadKeys() override; - boost::optional loadKeys( - const std::string &pass_phrase) override; - bool createKeys() override; bool createKeys(const std::string &pass_phrase) override; - static const std::string kPubExt; - static const std::string kPrivExt; + boost::optional loadKeys() override; + boost::optional loadKeys( + const std::string &pass_phrase) override; + + static const std::string kPublicKeyExtension; + static const std::string kPrivateKeyExtension; private: /** @@ -47,7 +46,7 @@ namespace iroha { * @param keypair - keypair for validation * @return true, if verification of signature is successful */ - bool validate(const iroha::keypair_t &keypair) const; + bool validate(const shared_model::crypto::Keypair &keypair) const; /** * Tries to load file to the resulting string @@ -69,4 +68,4 @@ namespace iroha { logger::Logger log_; }; } // namespace iroha -#endif // IROHA_CLI_KEYS_MANAGER_IMPL_HPP +#endif // IROHA_KEYS_MANAGER_IMPL_HPP diff --git a/test/framework/integration_framework/test_irohad.hpp b/test/framework/integration_framework/test_irohad.hpp index 6fe5eb500e..cf356dcbe9 100644 --- a/test/framework/integration_framework/test_irohad.hpp +++ b/test/framework/integration_framework/test_irohad.hpp @@ -44,7 +44,7 @@ namespace integration_framework { proposal_delay, vote_delay, load_delay, - *std::unique_ptr(keypair.makeOldModel())) {} + keypair) {} auto &getCommandService() { return command_service; diff --git a/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp b/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp index 8d7683280c..a694591c23 100644 --- a/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp +++ b/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp @@ -20,7 +20,7 @@ #include "consensus/yac/impl/yac_crypto_provider_impl.hpp" #include "consensus/yac/impl/yac_hash_provider_impl.hpp" #include "consensus/yac/messages.hpp" -#include "cryptography/ed25519_sha3_impl/internal/ed25519_impl.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" const auto pubkey = std::string(32, '0'); const auto signed_data = std::string(32, '1'); @@ -29,13 +29,15 @@ namespace iroha { namespace yac { class YacCryptoProviderTest : public ::testing::Test { public: - YacCryptoProviderTest() : keypair(create_keypair()) {} + YacCryptoProviderTest() + : keypair(shared_model::crypto::DefaultCryptoAlgorithmType:: + generateKeypair()) {} void SetUp() override { crypto_provider = std::make_shared(keypair); } - const keypair_t keypair; + const shared_model::crypto::Keypair keypair; std::shared_ptr crypto_provider; }; diff --git a/test/module/libs/crypto/keys_manager_test.cpp b/test/module/libs/crypto/keys_manager_test.cpp index d461c49631..ffeba986df 100644 --- a/test/module/libs/crypto/keys_manager_test.cpp +++ b/test/module/libs/crypto/keys_manager_test.cpp @@ -52,8 +52,8 @@ class KeyManager : public ::testing::Test { const path test_dir = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); const std::string filepath = (test_dir / "keymanager_test_file").string(); - const path pub_key_path = filepath + KeysManagerImpl::kPubExt; - const path pri_key_path = filepath + KeysManagerImpl::kPrivExt; + const path pub_key_path = filepath + KeysManagerImpl::kPublicKeyExtension; + const path pri_key_path = filepath + KeysManagerImpl::kPrivateKeyExtension; const std::string pubkey = "00576e02f23c8c694c322796cb3ef494829fdf484f4b42312fb7d776fbd5123b"s; const std::string prikey = From 21ea3fee3b1efd6312ea23ff210e8f452eff7bed Mon Sep 17 00:00:00 2001 From: Alexey Date: Fri, 13 Apr 2018 15:35:06 +0300 Subject: [PATCH 021/110] Move client-test to iroha-cli/ (#1190) refactor client_test Signed-off-by: Alexey Chernyshov --- test/CMakeLists.txt | 19 +++- test/integration/CMakeLists.txt | 29 +++--- test/integration/acceptance/CMakeLists.txt | 91 +++++++++---------- test/integration/consensus/CMakeLists.txt | 18 +++- test/integration/pipeline/CMakeLists.txt | 2 +- test/module/CMakeLists.txt | 18 +++- test/module/iroha-cli/CMakeLists.txt | 26 ++++++ .../iroha-cli}/client_test.cpp | 17 +--- test/module/irohad/CMakeLists.txt | 4 - 9 files changed, 143 insertions(+), 81 deletions(-) create mode 100644 test/module/iroha-cli/CMakeLists.txt rename test/{integration => module/iroha-cli}/client_test.cpp (95%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 745955ffba..5e3038d2ff 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,21 @@ -SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test_bin) +# +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. +# http://soramitsu.co.jp +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test_bin) add_subdirectory(module) add_subdirectory(framework) diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index bb9997b377..ded6a88c2a 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -1,17 +1,20 @@ -set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test_bin) +# +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. +# http://soramitsu.co.jp +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# add_subdirectory(acceptance) add_subdirectory(consensus) add_subdirectory(pipeline) - -addtest(client_test client_test.cpp) -target_link_libraries(client_test - pb_model_converters - json_model_converters - client - processors - server_runner - ) -target_include_directories(client_test PUBLIC - ${PROJECT_SOURCE_DIR}/iroha-cli - ) diff --git a/test/integration/acceptance/CMakeLists.txt b/test/integration/acceptance/CMakeLists.txt index 588066356f..d58931da92 100644 --- a/test/integration/acceptance/CMakeLists.txt +++ b/test/integration/acceptance/CMakeLists.txt @@ -17,76 +17,75 @@ addtest(tx_acceptance_test tx_acceptance_test.cpp) target_link_libraries(tx_acceptance_test - application - raw_block_loader - model_generators - integration_framework - shared_model_stateless_validation - ) + application + raw_block_loader + integration_framework + shared_model_stateless_validation + ) addtest(get_transactions_test get_transactions_test.cpp) target_link_libraries(get_transactions_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(add_asset_qty_test add_asset_qty_test.cpp) target_link_libraries(add_asset_qty_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(create_role_test create_role_test.cpp) target_link_libraries(create_role_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(invalid_fields_test invalid_fields_test.cpp) target_link_libraries(invalid_fields_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(transfer_asset_test transfer_asset_test.cpp) target_link_libraries(transfer_asset_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(create_domain_test create_domain_test.cpp) target_link_libraries(create_domain_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(subtract_asset_qty_test subtract_asset_qty_test.cpp) target_link_libraries(subtract_asset_qty_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(create_account_test create_account_test.cpp) target_link_libraries(create_account_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) addtest(tx_heavy_data tx_heavy_data.cpp) target_link_libraries(tx_heavy_data diff --git a/test/integration/consensus/CMakeLists.txt b/test/integration/consensus/CMakeLists.txt index ad8508c60d..cf5cc95b80 100644 --- a/test/integration/consensus/CMakeLists.txt +++ b/test/integration/consensus/CMakeLists.txt @@ -1,6 +1,22 @@ +# +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. +# http://soramitsu.co.jp +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + addtest(consensus_sunny_day consensus_sunny_day.cpp) target_link_libraries(consensus_sunny_day yac - model shared_model_stateless_validation ) diff --git a/test/integration/pipeline/CMakeLists.txt b/test/integration/pipeline/CMakeLists.txt index 19d646aa8a..6cad70072b 100644 --- a/test/integration/pipeline/CMakeLists.txt +++ b/test/integration/pipeline/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. # http://soramitsu.co.jp # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test/module/CMakeLists.txt b/test/module/CMakeLists.txt index 02b87b1f6a..34b0656c93 100644 --- a/test/module/CMakeLists.txt +++ b/test/module/CMakeLists.txt @@ -1,6 +1,22 @@ -set(CMAKE_BUILD_TYPE Debug) +# +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. +# http://soramitsu.co.jp +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# # Reusable tests +add_subdirectory(iroha-cli) add_subdirectory(irohad) add_subdirectory(libs) add_subdirectory(vendor) diff --git a/test/module/iroha-cli/CMakeLists.txt b/test/module/iroha-cli/CMakeLists.txt new file mode 100644 index 0000000000..8ff164a3a5 --- /dev/null +++ b/test/module/iroha-cli/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. +# http://soramitsu.co.jp +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +addtest(client_test client_test.cpp) +target_link_libraries(client_test + client + processors + server_runner + ) +target_include_directories(client_test PUBLIC + ${PROJECT_SOURCE_DIR}/iroha-cli + ) diff --git a/test/integration/client_test.cpp b/test/module/iroha-cli/client_test.cpp similarity index 95% rename from test/integration/client_test.cpp rename to test/module/iroha-cli/client_test.cpp index f914aadb57..d965d9bc7a 100644 --- a/test/integration/client_test.cpp +++ b/test/module/iroha-cli/client_test.cpp @@ -15,11 +15,6 @@ * limitations under the License. */ -#include - -#include - -#include "builders/protobuf/common_objects/proto_account_builder.hpp" #include "model/sha3_hash.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/network/network_mocks.hpp" @@ -55,8 +50,6 @@ using ::testing::_; using namespace iroha::ametsuchi; using namespace iroha::network; using namespace iroha::validation; -using namespace iroha::model::converters; -using namespace iroha::model; using namespace shared_model::proto; using namespace shared_model::permissions; @@ -156,8 +149,8 @@ TEST_F(ClientServerTest, SendTxWhenInvalidJson) { } }] })"; - JsonTransactionFactory tx_factory; - auto json_doc = stringToJson(json_string); + iroha::model::converters::JsonTransactionFactory tx_factory; + auto json_doc = iroha::model::converters::stringToJson(json_string); ASSERT_TRUE(json_doc); auto model_tx = tx_factory.deserialize(json_doc.value()); ASSERT_FALSE(model_tx); @@ -198,7 +191,7 @@ TEST_F(ClientServerTest, SendQueryWhenInvalidJson) { }] })"; - JsonQueryFactory queryFactory; + iroha::model::converters::JsonQueryFactory queryFactory; auto model_query = queryFactory.deserialize(json_query); ASSERT_FALSE(model_query); } @@ -224,8 +217,6 @@ TEST_F(ClientServerTest, SendQueryWhenStatelessInvalid) { TEST_F(ClientServerTest, SendQueryWhenValid) { // TODO: 30/04/2018 x3medima17, fix Uninteresting mock function call, IR-1187 iroha_cli::CliClient client(Ip, Port); - auto account_admin = iroha::model::Account(); - account_admin.account_id = "admin@test"; std::shared_ptr account_test = clone( shared_model::proto::AccountBuilder().accountId("test@test").build()); @@ -256,8 +247,6 @@ TEST_F(ClientServerTest, SendQueryWhenValid) { TEST_F(ClientServerTest, SendQueryWhenStatefulInvalid) { iroha_cli::CliClient client(Ip, Port); - auto account_admin = iroha::model::Account(); - account_admin.account_id = "admin@test"; auto account_test = iroha::model::Account(); account_test.account_id = "test@test"; diff --git a/test/module/irohad/CMakeLists.txt b/test/module/irohad/CMakeLists.txt index cda20ef600..3ac06f353e 100644 --- a/test/module/irohad/CMakeLists.txt +++ b/test/module/irohad/CMakeLists.txt @@ -12,10 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(CMAKE_BUILD_TYPE Debug) - -SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test_bin) - # Reusable tests add_subdirectory(common) add_subdirectory(ametsuchi) From f76c01b01fcf65b50a5df2df1f7255f0f64ebc59 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Fri, 13 Apr 2018 18:11:52 +0300 Subject: [PATCH 022/110] Remove old model from ametsuchi test (#1188) Signed-off-by: Nikita Alekseev --- .../irohad/ametsuchi/ametsuchi_test.cpp | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index 6addddf223..df8a92b5be 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,9 @@ #include "ametsuchi/impl/postgres_wsv_query.hpp" #include "ametsuchi/impl/wsv_restorer_impl.hpp" #include "ametsuchi/mutable_storage.hpp" +#include "builders/default_builders.hpp" #include "builders/protobuf/transaction.hpp" +#include "framework/result_fixture.hpp" #include "framework/test_subscriber.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" #include "module/shared_model/builders/protobuf/test_block_builder.hpp" @@ -35,6 +37,17 @@ using namespace framework::test_subscriber; auto zero_string = std::string(32, '0'); auto fake_hash = shared_model::crypto::Hash(zero_string); auto fake_pubkey = shared_model::crypto::PublicKey(zero_string); +using AmountBuilder = shared_model::builder::AmountBuilderWithoutValidator; + +/** + * Return shared pointer to amount from result, or throw exception + * @return amount from result + */ +std::shared_ptr getAmount( + const shared_model::builder::BuilderResult + &result) { + return framework::expected::checkValueCase(result).value; +} /** * Shortcut to create CallExact observable wrapper, subscribe with given lambda, @@ -110,14 +123,12 @@ template void validateAccountAsset(W &&wsv, const std::string &account, const std::string &asset, - const iroha::Amount &amount) { + const shared_model::interface::Amount &amount) { auto account_asset = wsv->getAccountAsset(account, asset); ASSERT_TRUE(account_asset); ASSERT_EQ((*account_asset)->accountId(), account); ASSERT_EQ((*account_asset)->assetId(), asset); - ASSERT_EQ(*std::unique_ptr( - (*account_asset)->balance().makeOldModel()), - amount); + ASSERT_EQ((*account_asset)->balance(), amount); } /** @@ -183,7 +194,6 @@ TEST_F(AmetsuchiTest, SampleTest) { assetid = "rub#ru"; std::string account, src_account, dest_account, asset; - iroha::Amount amount; // Block 1 // TODO: 26/04/2018 x3medima17 replace string permissions IR-999 @@ -227,9 +237,9 @@ TEST_F(AmetsuchiTest, SampleTest) { apply(storage, block2); validateAccountAsset( - wsv, user1id, assetid, *iroha::Amount::createFromString("50.0")); + wsv, user1id, assetid, *getAmount(AmountBuilder::fromString("50.0"))); validateAccountAsset( - wsv, user2id, assetid, *iroha::Amount::createFromString("100.0")); + wsv, user2id, assetid, *getAmount(AmountBuilder::fromString("100.0"))); // Block store tests auto hashes = {block1.hash(), block2.hash()}; @@ -286,7 +296,6 @@ TEST_F(AmetsuchiTest, queryGetAccountAssetTransactionsTest) { asset2id = "assettwo#domain"; std::string account, src_account, dest_account, asset; - iroha::Amount amount; // 1st tx auto txn1 = @@ -323,9 +332,9 @@ TEST_F(AmetsuchiTest, queryGetAccountAssetTransactionsTest) { // Check querying assets for users validateAccountAsset( - wsv, user1id, asset1id, *iroha::Amount::createFromString("300.0")); + wsv, user1id, asset1id, *getAmount(AmountBuilder::fromString("300.0"))); validateAccountAsset( - wsv, user2id, asset2id, *iroha::Amount::createFromString("250.0")); + wsv, user2id, asset2id, *getAmount(AmountBuilder::fromString("250.0"))); // 2th tx (user1 -> user2 # asset1) auto txn2 = @@ -344,9 +353,9 @@ TEST_F(AmetsuchiTest, queryGetAccountAssetTransactionsTest) { // Check account asset after transfer assets validateAccountAsset( - wsv, user1id, asset1id, *iroha::Amount::createFromString("180.0")); + wsv, user1id, asset1id, *getAmount(AmountBuilder::fromString("180.0"))); validateAccountAsset( - wsv, user2id, asset1id, *iroha::Amount::createFromString("120.0")); + wsv, user2id, asset1id, *getAmount(AmountBuilder::fromString("120.0"))); // 3rd tx // (user2 -> user3 # asset2) @@ -368,11 +377,11 @@ TEST_F(AmetsuchiTest, queryGetAccountAssetTransactionsTest) { apply(storage, block3); validateAccountAsset( - wsv, user2id, asset2id, *iroha::Amount::createFromString("90.0")); + wsv, user2id, asset2id, *getAmount(AmountBuilder::fromString("90.0"))); validateAccountAsset( - wsv, user3id, asset2id, *iroha::Amount::createFromString("150.0")); + wsv, user3id, asset2id, *getAmount(AmountBuilder::fromString("150.0"))); validateAccountAsset( - wsv, user1id, asset2id, *iroha::Amount::createFromString("10.0")); + wsv, user1id, asset2id, *getAmount(AmountBuilder::fromString("10.0"))); // Block store test auto hashes = {block1.hash(), block2.hash(), block3.hash()}; From 79a1cef243931889d688d2aafca49a8eb3d9b7ac Mon Sep 17 00:00:00 2001 From: DenDoronin Date: Sat, 14 Apr 2018 09:43:16 +0300 Subject: [PATCH 023/110] Change package build scripts to use https for git clone (#1211) * Changed ios build script to use https for all git clone operations (fixed issue with connection timeout) * Changed android build script to use https for all git clone operations Signed-off-by: DenDoronin --- shared_model/packages/android/android-build.sh | 2 +- shared_model/packages/ios/ios-build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared_model/packages/android/android-build.sh b/shared_model/packages/android/android-build.sh index 7d03d4cb57..a7f1caca92 100755 --- a/shared_model/packages/android/android-build.sh +++ b/shared_model/packages/android/android-build.sh @@ -92,7 +92,7 @@ LDFLAGS="-llog -landroid" cmake "${ANDROID_TOOLCHAIN_ARGS[@]}" "${INSTALL_ARGS[@ VERBOSE=1 cmake --build ./protobuf/.build --target install -- -j"$CORES" # ed25519 -git clone git://github.com/hyperledger/iroha-ed25519 +git clone https://github.com/hyperledger/iroha-ed25519.git (cd ./iroha-ed25519 ; git checkout e7188b8393dbe5ac54378610d53630bd4a180038) cmake "${ANDROID_TOOLCHAIN_ARGS[@]}" "${INSTALL_ARGS[@]}" -DTESTING=OFF -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DBUILD=STATIC -H./iroha-ed25519 -B./iroha-ed25519/build VERBOSE=1 cmake --build ./iroha-ed25519/build --target install -- -j"$CORES" diff --git a/shared_model/packages/ios/ios-build.sh b/shared_model/packages/ios/ios-build.sh index 5678f7afa0..e4a336d583 100755 --- a/shared_model/packages/ios/ios-build.sh +++ b/shared_model/packages/ios/ios-build.sh @@ -90,7 +90,7 @@ cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" "${IOS_TOOLCHAIN_ARGS[@]}" "${INSTALL_ARG VERBOSE=1 cmake --build ./protobuf/.build --target install -- -j"$CORES" # ed25519 -git clone git://github.com/hyperledger/iroha-ed25519 +git clone https://github.com/hyperledger/iroha-ed25519.git (cd ./iroha-ed25519; git checkout e7188b8393dbe5ac54378610d53630bd4a180038) cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" "${IOS_TOOLCHAIN_ARGS[@]}" "${INSTALL_ARGS[@]}" -DTESTING=OFF -DBUILD=STATIC -H./iroha-ed25519 -B./iroha-ed25519/build From b7a70f016b6068a0ba65634c77847c76881855cc Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Mon, 16 Apr 2018 10:37:36 +0300 Subject: [PATCH 024/110] Fix artifacts upload path (#1226) Signed-off-by: Artyom Bakhtin --- .jenkinsci/linux-post-step.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jenkinsci/linux-post-step.groovy b/.jenkinsci/linux-post-step.groovy index 0dc8611445..c4c9f13886 100644 --- a/.jenkinsci/linux-post-step.groovy +++ b/.jenkinsci/linux-post-step.groovy @@ -6,7 +6,7 @@ def linuxPostStep() { def commit = env.GIT_COMMIT def platform = sh(script: 'uname -m', returnStdout: true).trim() filePaths = [ '/tmp/${GIT_COMMIT}-${BUILD_NUMBER}/*' ] - artifacts.uploadArtifacts(filePaths, sprintf('/iroha/linux/%4%s/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6), platform])) + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/linux/%4$s/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6), platform])) } } finally { From c298800d37326f6408f31369f4537fa01fec12d4 Mon Sep 17 00:00:00 2001 From: Nikolay Yushkevich Date: Mon, 16 Apr 2018 11:49:23 +0300 Subject: [PATCH 025/110] Update Maintainers.md (#1205) * Update Maintainers.md Signed-off-by: Nikolay Yushkevich * Change name Signed-off-by: Nikolay Yushkevich * Prepend @ sign Signed-off-by: Nikolay Yushkevich * Add Yanno Ban Signed-off-by: Nikolay Yushkevich --- MAINTAINERS.md | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 0bee5ed289..a531fc7495 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,21 +1,30 @@ ## Maintainers -| Name | GitHub Id | email | -|---|---|---| -| Makoto Takemiya | takemiyamakoto | takemiya@soramitsu.co.jp | -| Ryu Okada | ryuo88 | okada@soramitsu.co.jp | -| Taisei Igarashi | MizukiSonoko | igarashi@soramitsu.co.jp | -| Motohiko Abe | motxx | abe@soramitsu.co.jp | -| Daisuke Shimada | cimadai | dice.k1984@gmail.com | -| Sushant D. Mayekar | Sushantdm | Sushantdm@gmail.com | -| Yanno Ban | yannoban | ban.yanno@nbc.org.kh -| Hiroshi Sasagawa | SasagawaHiroshi | sasagawa_hiroshi@intec.co.jp | -| Takumi Yamashita | satelliteyes | yamashita@soramitsu.co.jp | -| Bogdan Vaneev | Warchant | bogdan@soramitsu.co.jp | -| Fyodor Muratov | muratovv | fyodor@soramitsu.co.jp | -| Andrei Lebedev | lebdron | andrei@soramitsu.co.jp | -| Bulat Nasrulin | grimadas | bulat@soramitsu.co.jp | -| Kamil Salakhiev | kamilsa | kamil@soramitsu.co.jp | -| Konstantin Munichev | luckychess | konstantin@soramitsu.co.jp | -| Evgenii Mininbaev | l4l | evgenii@soramitsu.co.jp | -| Nikolay Yushkevich | neewy | nikolai@soramitsu.co.jp | +Maintainers of Hyperledger Iroha project +are supposed to help contributors by explain them project details, +such as architecture, process, existing issues. + +This is the list of maintainers, including their email address for direct communications: + +| Name | GitHub Id | email | Area of expertise | +|------------------------|--------------------------|--------------------------------|---------------------------------| +| Makoto Takemiya | @takemiyamakoto | takemiya@soramitsu.co.jp | Product vision | +| Ryu Okada | @ryuo88 | okada@soramitsu.co.jp | Product vision | +| Nikolay Yushkevich | @neewy | nikolai@soramitsu.co.jp | Project state | +| Fyodor Muratov | @muratovv | fyodor@soramitsu.co.jp | Architecture, Java library, QA | +| Andrei Lebedev | @lebdron | andrei@soramitsu.co.jp | Research | +| Sergei Solonets | @Solonets | ssolonets@gmail.com | Development | +| Yanno Ban | @yannoban | ban.yanno@nbc.org.kh | Development | +| Dumitru Savva | @x3medima17 | savva@soramitsu.co.jp | Development | +| Nikita Alekseev | @nickaleks | alekseev@soramitsu.co.jp | Development | +| Victor Drobny | @victordrobny | drobny@soramitsu.co.jp | Development | +| Bulat Nasrulin | @grimadas | bulat@soramitsu.co.jp | Development | +| Kamil Salakhiev | @kamilsa | kamil@soramitsu.co.jp | Development | +| Igor Egorov | @igor-egorov | igor@soramitsu.co.jp | Development, Android library | +| Konstantin Munichev | @luckychess | konstantin@soramitsu.co.jp | Security | +| Evgenii Mininbaev | @l4l | evgenii@soramitsu.co.jp | Security, Python library | +| Vyacheslav Bikbaev | @laSinteZ | bikbaev@soramitsu.co.jp | Documentation, NodeJS library | +| Arseniy Fokin | @stinger112 | stinger112@gmail.com | NodeJS library | +| Alexey Chernyshov | @Alexey-N-Chernyshov | chernyshov@soramitsu.co.jp | Development | +| Artyom Bakhtin | @bakhtin | a@bakhtin.net | Ansible, Jenkins, artifacts | +| Anatoly Tyukushin | @tyvision | tyukushin@soramitsu.co.jp | Ansible, Jenkins | From 22c8a8aaf5a352ba3e5edfeb0b0e6229b62ccf89 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Mon, 16 Apr 2018 12:26:38 +0300 Subject: [PATCH 026/110] Rework Docker images pull mechanism (#1192) * rework Docker images pull mechanism Signed-off-by: Artyom Bakhtin * move functions to a separate file Signed-off-by: Artyom Bakhtin * fixes Signed-off-by: Artyom Bakhtin --- .jenkinsci/debug-build.groovy | 17 ++-------- .jenkinsci/docker-pull-or-build.groovy | 47 ++++++++++++++++++++++++++ .jenkinsci/release-build.groovy | 8 ++--- docker/develop/aarch64/Dockerfile | 5 ++- docker/develop/armv7l/Dockerfile | 5 ++- docker/develop/x86_64/Dockerfile | 5 ++- 6 files changed, 58 insertions(+), 29 deletions(-) create mode 100644 .jenkinsci/docker-pull-or-build.groovy diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index 5d934dd8fa..fc55ee7bb7 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -1,6 +1,7 @@ #!/usr/bin/env groovy def doDebugBuild(coverageEnabled=false) { + def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" def parallelism = params.PARALLELISM // params are always null unless job is started // this is the case for the FIRST build only. @@ -20,20 +21,7 @@ def doDebugBuild(coverageEnabled=false) { + " --name ${env.IROHA_POSTGRES_HOST}" + " --network=${env.IROHA_NETWORK}") - def platform = sh(script: 'uname -m', returnStdout: true).trim() - sh "curl -L -o /tmp/${env.GIT_COMMIT}/Dockerfile --create-dirs https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile" - // pull docker image in case we don't have one - // speeds up consequent image builds as we simply tag them - sh "docker pull ${DOCKER_BASE_IMAGE_DEVELOP}" - if (env.BRANCH_NAME == 'develop') { - iC = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}", "--build-arg PARALLELISM=${parallelism} -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") - docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { - iC.push("${platform}-develop") - } - } - else { - iC = docker.build("hyperledger/iroha-workflow:${GIT_COMMIT}-${BUILD_NUMBER}", "-f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT} --build-arg PARALLELISM=${parallelism}") - } + def iC = dPullOrBuild.dockerPullOrUpdate() iC.inside("" + " -e IROHA_POSTGRES_HOST=${env.IROHA_POSTGRES_HOST}" + " -e IROHA_POSTGRES_PORT=${env.IROHA_POSTGRES_PORT}" @@ -100,4 +88,5 @@ def doDebugBuild(coverageEnabled=false) { sh "cp ./build/bin/* /tmp/${GIT_COMMIT}/" } } + return this diff --git a/.jenkinsci/docker-pull-or-build.groovy b/.jenkinsci/docker-pull-or-build.groovy new file mode 100644 index 0000000000..403e3e3303 --- /dev/null +++ b/.jenkinsci/docker-pull-or-build.groovy @@ -0,0 +1,47 @@ +#!/usr/bin/env groovy + +def remoteFilesDiffer(f1, f2) { + sh "curl -L -o /tmp/${env.GIT_COMMIT}/f1 --create-dirs ${f1}" + sh "curl -L -o /tmp/${env.GIT_COMMIT}/f2 ${f2}" + diffExitCode = sh(script: "diff -q /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}/f2", returnStatus: true) + if (diffExitCode == 0) { + return false + } + return true +} + +def dockerPullOrUpdate() { + def platform = sh(script: 'uname -m', returnStdout: true).trim() + def commit = sh(script: "echo ${BRANCH_NAME} | md5sum | cut -c 1-8", returnStdout: true).trim() + if (remoteFilesDiffer("https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", + "https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile")) { + iC = docker.build("hyperledger/iroha:${commit}", "--build-arg PARALLELISM=${parallelism} -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + // develop branch Docker image has been modified + if (BRANCH_NAME == 'develop') { + docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { + iC.push("${platform}-develop") + } + } + } + else { + // reuse develop branch Docker image + if (BRANCH_NAME == 'develop') { + iC = docker.image("hyperledger/iroha:${platform}-develop") + iC.pull() + } + else { + // first commit in this branch or Dockerfile modified + if (remoteFilesDiffer("https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", + "https://raw.githubusercontent.com/hyperledger/iroha/develop/docker/develop/${platform}/Dockerfile")) { + iC = docker.build("hyperledger/iroha:${commit}", "--build-arg PARALLELISM=${parallelism} -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + } + // reuse develop branch Docker image + else { + iC = docker.image("hyperledger/iroha:${platform}-develop") + } + } + } + return iC +} + +return this diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index dc4db9ddab..9a2a3d6e50 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -13,13 +13,9 @@ def doReleaseBuild() { parallelism = 1 } def platform = sh(script: 'uname -m', returnStdout: true).trim() - sh "curl -L -o /tmp/${env.GIT_COMMIT}/Dockerfile --create-dirs https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile" - // pull docker image for building release package of Iroha - // speeds up consequent image builds as we simply tag them - sh "docker pull ${DOCKER_BASE_IMAGE_DEVELOP}" - iC = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}", "--build-arg PARALLELISM=${parallelism} -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") - sh "mkdir /tmp/${env.GIT_COMMIT}-${BUILD_NUMBER} || true" + iC = docker.image("hyperledger/iroha:${platform}-develop") + iC.pull() iC.inside("" + " -v /tmp/${GIT_COMMIT}-${BUILD_NUMBER}:/tmp/${GIT_COMMIT}" + " -v /var/jenkins/ccache:${CCACHE_RELEASE_DIR}") { diff --git a/docker/develop/aarch64/Dockerfile b/docker/develop/aarch64/Dockerfile index 15d79ff37c..a9c84165e4 100644 --- a/docker/develop/aarch64/Dockerfile +++ b/docker/develop/aarch64/Dockerfile @@ -8,14 +8,13 @@ ARG CMAKE_BUILD_TYPE=Release ENV IROHA_HOME /opt/iroha ENV IROHA_BUILD /opt/iroha/build -RUN apt-get update; \ - apt-get -y upgrade; \ +RUN apt-get update && \ apt-get -y --no-install-recommends install apt-utils software-properties-common; \ apt-get -y clean # add git repository -RUN add-apt-repository -y ppa:git-core/ppa; \ +RUN add-apt-repository -y ppa:git-core/ppa && \ apt-get update diff --git a/docker/develop/armv7l/Dockerfile b/docker/develop/armv7l/Dockerfile index 11e52a94c1..1f668a872e 100644 --- a/docker/develop/armv7l/Dockerfile +++ b/docker/develop/armv7l/Dockerfile @@ -8,14 +8,13 @@ ARG CMAKE_BUILD_TYPE=Release ENV IROHA_HOME /opt/iroha ENV IROHA_BUILD /opt/iroha/build -RUN apt-get update; \ - apt-get -y upgrade; \ +RUN apt-get update && \ apt-get -y --no-install-recommends install apt-utils software-properties-common; \ apt-get -y clean # add git repository -RUN add-apt-repository -y ppa:git-core/ppa; \ +RUN add-apt-repository -y ppa:git-core/ppa && \ apt-get update diff --git a/docker/develop/x86_64/Dockerfile b/docker/develop/x86_64/Dockerfile index 15d79ff37c..a9c84165e4 100644 --- a/docker/develop/x86_64/Dockerfile +++ b/docker/develop/x86_64/Dockerfile @@ -8,14 +8,13 @@ ARG CMAKE_BUILD_TYPE=Release ENV IROHA_HOME /opt/iroha ENV IROHA_BUILD /opt/iroha/build -RUN apt-get update; \ - apt-get -y upgrade; \ +RUN apt-get update && \ apt-get -y --no-install-recommends install apt-utils software-properties-common; \ apt-get -y clean # add git repository -RUN add-apt-repository -y ppa:git-core/ppa; \ +RUN add-apt-repository -y ppa:git-core/ppa && \ apt-get update From de9fa46ea6d95c02389f7a4d42f59a1bad4925bd Mon Sep 17 00:00:00 2001 From: Nikolay Yushkevich Date: Mon, 16 Apr 2018 12:46:23 +0300 Subject: [PATCH 027/110] Fix overview link (#1230) Signed-off-by: Nikolay Yushkevich --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e9b321ed34..dfc86e12b5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Blockchain platform Hyperledger Iroha is designed for simple creation and management of assets. This is a distributed ledger of transactions. -Check [overview](http://iroha.readthedocs.io/en/latest/overview/) page of our documentation. +Check [overview](http://iroha.readthedocs.io/en/latest/overview.html) page of our documentation. Iroha logo From a023fced9d3a6f6b69b91dfd0624081b29cdb96e Mon Sep 17 00:00:00 2001 From: Nikolay Yushkevich Date: Mon, 16 Apr 2018 13:44:37 +0300 Subject: [PATCH 028/110] Delete obsolete data (#1232) Signed-off-by: Nikolay Yushkevich --- docs/source/overview.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 51783ee7cf..a2a8462a9c 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -49,11 +49,6 @@ Finally, Iroha is the only ledger that has a robust permission system, allowing .. [#f1] Yet Another Consensus -Is it fast? ------------ - -As per the latest review date of these docs, according to `Huawei Caliper `_ testing tool, Iroha is capable of processing 45 transactions per second. Theoretically, this is not even close to the limit of the system, and we will continue constant optimizations in order to improve stability and performance. - How to create applications around Iroha? ---------------------------------------- From b5b2831e66f4b1118886832da63a8892c6165d3e Mon Sep 17 00:00:00 2001 From: Kitsu Date: Mon, 16 Apr 2018 13:49:53 +0300 Subject: [PATCH 029/110] Add transport logging (#1224) Signed-off-by: Kitsu --- irohad/consensus/yac/transport/impl/network_impl.cpp | 6 +++--- irohad/consensus/yac/transport/impl/network_impl.hpp | 5 ----- irohad/main/impl/ordering_init.cpp | 1 + irohad/network/impl/async_grpc_client.hpp | 9 +++++++-- irohad/ordering/impl/ordering_gate_transport_grpc.cpp | 8 +++++--- irohad/ordering/impl/ordering_gate_transport_grpc.hpp | 1 - irohad/ordering/impl/ordering_service_transport_grpc.cpp | 7 ++++++- irohad/ordering/impl/ordering_service_transport_grpc.hpp | 1 - 8 files changed, 22 insertions(+), 16 deletions(-) diff --git a/irohad/consensus/yac/transport/impl/network_impl.cpp b/irohad/consensus/yac/transport/impl/network_impl.cpp index 13709f8385..2235d07e7e 100644 --- a/irohad/consensus/yac/transport/impl/network_impl.cpp +++ b/irohad/consensus/yac/transport/impl/network_impl.cpp @@ -30,9 +30,9 @@ namespace iroha { namespace yac { // ----------| Public API |---------- - NetworkImpl::NetworkImpl() { - log_ = logger::log("YacNetwork"); - } + NetworkImpl::NetworkImpl() + : network::AsyncGrpcClient( + logger::log("YacNetwork")) {} void NetworkImpl::subscribe( std::shared_ptr handler) { diff --git a/irohad/consensus/yac/transport/impl/network_impl.hpp b/irohad/consensus/yac/transport/impl/network_impl.hpp index d75c833a60..b2d3ab46c5 100644 --- a/irohad/consensus/yac/transport/impl/network_impl.hpp +++ b/irohad/consensus/yac/transport/impl/network_impl.hpp @@ -101,11 +101,6 @@ namespace iroha { * Subscriber of network messages */ std::weak_ptr handler_; - - /** - * Internal logger - */ - logger::Logger log_; }; } // namespace yac diff --git a/irohad/main/impl/ordering_init.cpp b/irohad/main/impl/ordering_init.cpp index a6b8137ffc..64bc56400c 100644 --- a/irohad/main/impl/ordering_init.cpp +++ b/irohad/main/impl/ordering_init.cpp @@ -55,6 +55,7 @@ namespace iroha { "Ledger don't have peers. Do you set correct genesis block?"); } auto network_address = ledger_peers->front()->address(); + log_->info("Ordering gate is at {}", network_address); ordering_gate_transport = std::make_shared( network_address); diff --git a/irohad/network/impl/async_grpc_client.hpp b/irohad/network/impl/async_grpc_client.hpp index 9db412b9aa..b82a732a04 100644 --- a/irohad/network/impl/async_grpc_client.hpp +++ b/irohad/network/impl/async_grpc_client.hpp @@ -32,7 +32,9 @@ namespace iroha { template class AsyncGrpcClient { public: - AsyncGrpcClient() : thread_(&AsyncGrpcClient::asyncCompleteRpc, this) {} + explicit AsyncGrpcClient(logger::Logger &&log) + : thread_(&AsyncGrpcClient::asyncCompleteRpc, this), + log_(std::move(log)) {} /** * Listen to gRPC server responses @@ -42,7 +44,9 @@ namespace iroha { auto ok = false; while (cq_.Next(&got_tag, &ok)) { auto call = static_cast(got_tag); - + if (not call->status.ok()) { + log_->warn("RPC failed: {}", call->status.error_message()); + } delete call; } } @@ -56,6 +60,7 @@ namespace iroha { grpc::CompletionQueue cq_; std::thread thread_; + logger::Logger log_; /** * State and data information of gRPC call diff --git a/irohad/ordering/impl/ordering_gate_transport_grpc.cpp b/irohad/ordering/impl/ordering_gate_transport_grpc.cpp index 316300e784..f07eddd43d 100644 --- a/irohad/ordering/impl/ordering_gate_transport_grpc.cpp +++ b/irohad/ordering/impl/ordering_gate_transport_grpc.cpp @@ -52,9 +52,10 @@ grpc::Status OrderingGateTransportGrpc::onProposal( OrderingGateTransportGrpc::OrderingGateTransportGrpc( const std::string &server_address) - : client_(proto::OrderingServiceTransportGrpc::NewStub(grpc::CreateChannel( - server_address, grpc::InsecureChannelCredentials()))), - log_(logger::log("OrderingGate")) {} + : network::AsyncGrpcClient( + logger::log("OrderingGate")), + client_(proto::OrderingServiceTransportGrpc::NewStub(grpc::CreateChannel( + server_address, grpc::InsecureChannelCredentials()))) {} void OrderingGateTransportGrpc::propagateTransaction( std::shared_ptr transaction) { @@ -64,6 +65,7 @@ void OrderingGateTransportGrpc::propagateTransaction( auto transaction_transport = static_cast(*transaction) .getTransport(); + log_->debug("Propagating: '{}'", transaction_transport.DebugString()); call->response_reader = client_->AsynconTransaction(&call->context, transaction_transport, &cq_); diff --git a/irohad/ordering/impl/ordering_gate_transport_grpc.hpp b/irohad/ordering/impl/ordering_gate_transport_grpc.hpp index 005bd16de4..39292b42f8 100644 --- a/irohad/ordering/impl/ordering_gate_transport_grpc.hpp +++ b/irohad/ordering/impl/ordering_gate_transport_grpc.hpp @@ -53,7 +53,6 @@ namespace iroha { private: std::weak_ptr subscriber_; std::unique_ptr client_; - logger::Logger log_; }; } // namespace ordering diff --git a/irohad/ordering/impl/ordering_service_transport_grpc.cpp b/irohad/ordering/impl/ordering_service_transport_grpc.cpp index 98554df766..ea1c72eb2c 100644 --- a/irohad/ordering/impl/ordering_service_transport_grpc.cpp +++ b/irohad/ordering/impl/ordering_service_transport_grpc.cpp @@ -30,6 +30,7 @@ grpc::Status OrderingServiceTransportGrpc::onTransaction( ::grpc::ServerContext *context, const iroha::protocol::Transaction *request, ::google::protobuf::Empty *response) { + log_->info("OrderingServiceTransportGrpc::onTransaction"); if (subscriber_.expired()) { log_->error("No subscriber"); } else { @@ -44,6 +45,7 @@ grpc::Status OrderingServiceTransportGrpc::onTransaction( void OrderingServiceTransportGrpc::publishProposal( std::unique_ptr proposal, const std::vector &peers) { + log_->info("OrderingServiceTransportGrpc::publishProposal"); std::unordered_map> peers_map; @@ -57,6 +59,8 @@ void OrderingServiceTransportGrpc::publishProposal( auto call = new AsyncClientCall; auto proto = static_cast(proposal.get()); + log_->debug("Publishing proposal: '{}'", + proto->getTransport().DebugString()); call->response_reader = peer.second->AsynconProposal( &call->context, proto->getTransport(), &cq_); @@ -65,4 +69,5 @@ void OrderingServiceTransportGrpc::publishProposal( } OrderingServiceTransportGrpc::OrderingServiceTransportGrpc() - : log_(logger::testLog("OrderingServiceTransportGrpc")) {} + : network::AsyncGrpcClient( + logger::log("OrderingServiceTransportGrpc")) {} diff --git a/irohad/ordering/impl/ordering_service_transport_grpc.hpp b/irohad/ordering/impl/ordering_service_transport_grpc.hpp index 4e65196303..5946fb9a1a 100644 --- a/irohad/ordering/impl/ordering_service_transport_grpc.hpp +++ b/irohad/ordering/impl/ordering_service_transport_grpc.hpp @@ -50,7 +50,6 @@ namespace iroha { private: std::weak_ptr subscriber_; - logger::Logger log_; }; } // namespace ordering From 9bd7535333fc8524bcc412593f8c35fee6242686 Mon Sep 17 00:00:00 2001 From: victordrobny Date: Mon, 16 Apr 2018 13:56:58 +0300 Subject: [PATCH 030/110] Remove txCounter from Iroha (#1200) * Remove txCounter from Iroha Signed-off-by: Victor Drobny --- docs/source/guides/libraries/python.rst | 4 -- example/java/TransactionExample.java | 3 +- example/node/index.js | 2 - example/python/tx-example.py | 4 -- .../interactive/impl/interactive_cli.cpp | 3 +- .../impl/interactive_transaction_cli.cpp | 9 +-- iroha-cli/interactive/interactive_cli.hpp | 2 - .../interactive_transaction_cli.hpp | 5 -- iroha-cli/main.cpp | 1 - .../ametsuchi/impl/postgres_wsv_command.cpp | 9 +-- .../ametsuchi/impl/postgres_wsv_command.hpp | 2 - irohad/ametsuchi/impl/storage_impl.hpp | 1 - .../impl/json_transaction_factory.cpp | 2 - .../impl/pb_transaction_factory.cpp | 2 - .../generators/impl/transaction_generator.cpp | 6 +- .../generators/transaction_generator.hpp | 4 -- irohad/model/impl/model_operators.cpp | 2 +- irohad/model/transaction.hpp | 11 --- irohad/ordering/impl/ordering_gate_impl.cpp | 3 +- schema/block.proto | 3 +- shared_model/backend/protobuf/transaction.hpp | 4 -- .../bindings/model_transaction_builder.cpp | 7 +- .../bindings/model_transaction_builder.hpp | 8 --- .../transaction_template.hpp | 7 -- shared_model/interfaces/transaction.hpp | 7 -- .../packages/javascript/example/index.js | 2 - .../packages/javascript/tests/txbuilder.js | 20 +++--- .../validators/container_validator.hpp | 10 +-- .../validators/transaction_validator.hpp | 1 - test/framework/base_tx.hpp | 1 - .../integration_test_framework.cpp | 1 - .../acceptance/add_asset_qty_test.cpp | 2 - .../acceptance/create_account_test.cpp | 1 - .../acceptance/create_domain_test.cpp | 1 - .../acceptance/create_role_test.cpp | 1 - .../acceptance/get_transactions_test.cpp | 1 - .../acceptance/invalid_fields_test.cpp | 2 - .../acceptance/subtract_asset_qty_test.cpp | 1 - .../acceptance/transfer_asset_test.cpp | 3 - .../acceptance/tx_acceptance_test.cpp | 72 ------------------- test/integration/acceptance/tx_heavy_data.cpp | 1 - test/integration/pipeline/pipeline_test.cpp | 1 - test/module/iroha-cli/client_test.cpp | 2 - .../irohad/ametsuchi/ametsuchi_fixture.hpp | 1 - .../irohad/ametsuchi/ametsuchi_test.cpp | 1 - .../converters/json_transaction_test.cpp | 1 - .../irohad/model/converters/pb_block_test.cpp | 1 - .../converters/pb_query_responses_test.cpp | 9 --- .../model/converters/pb_transaction_test.cpp | 1 - .../model/model_crypto_provider_test.cpp | 2 +- .../model/operators/model_operators_test.cpp | 1 - .../ordering/ordering_gate_service_test.cpp | 12 ---- .../irohad/ordering/ordering_gate_test.cpp | 2 - .../irohad/ordering/ordering_service_test.cpp | 1 - .../irohad/simulator/simulator_test.cpp | 2 - .../processor/transaction_processor_test.cpp | 5 -- .../irohad/torii/torii_queries_test.cpp | 2 - .../irohad/torii/torii_service_test.cpp | 6 +- .../irohad/validation/query_execution.cpp | 6 +- .../shared_proto_transaction_test.cpp | 16 ----- .../shared_model/bindings/BuilderTest.java | 2 +- .../shared_model/bindings/builder-test.py | 2 +- .../query_response_builder_test.cpp | 2 - .../protobuf/transport_builder_test.cpp | 2 - .../converters/json_proto_converter_test.cpp | 4 +- .../cryptography/crypto_usage_test.cpp | 1 - .../validators/field_validator_test.cpp | 6 +- .../validators/transaction_validator_test.cpp | 4 +- 68 files changed, 39 insertions(+), 287 deletions(-) diff --git a/docs/source/guides/libraries/python.rst b/docs/source/guides/libraries/python.rst index db61ddc66c..15f89c2e35 100644 --- a/docs/source/guides/libraries/python.rst +++ b/docs/source/guides/libraries/python.rst @@ -230,7 +230,6 @@ Create domain and asset: .. code:: python tx = tx_builder.creatorAccountId(creator) \ - .txCounter(tx_counter) \ .createdTime(current_time) \ .createDomain("domain", "user") \ .createAsset("coin", "domain", 2).build() @@ -243,7 +242,6 @@ Create asset quantity: .. code:: python tx = tx_builder.creatorAccountId(creator) \ - .txCounter(tx_counter) \ .createdTime(current_time) \ .addAssetQuantity("admin@test", "coin#domain", "1000.2").build() @@ -257,7 +255,6 @@ Create account: user1_kp = crypto.generateKeypair() tx = tx_builder.creatorAccountId(creator) \ - .txCounter(tx_counter) \ .createdTime(current_time) \ .createAccount("userone", "domain", user1_kp.publicKey()).build() @@ -269,7 +266,6 @@ Send asset: .. code:: python tx = tx_builder.creatorAccountId(creator) \ - .txCounter(tx_counter) \ .createdTime(current_time) \ .transferAsset("admin@test", "userone@domain", "coin#domain", "Some message", "2.0").build() diff --git a/example/java/TransactionExample.java b/example/java/TransactionExample.java index 19481053d6..08ab4b30a0 100644 --- a/example/java/TransactionExample.java +++ b/example/java/TransactionExample.java @@ -69,12 +69,11 @@ public static void main(String[] args) { long currentTime = System.currentTimeMillis(); String creator = "admin@test"; - long startTxCounter = 1, startQueryCounter = 1; + long startQueryCounter = 1; // build transaction (still unsigned) UnsignedTx utx = txBuilder.creatorAccountId(creator) .createdTime(BigInteger.valueOf(currentTime)) - .txCounter(BigInteger.valueOf(startTxCounter)) .createDomain("ru", "user") .createAsset("dollar", "ru", (short)2).build(); diff --git a/example/node/index.js b/example/node/index.js index 41d4ce3b86..833ecae984 100644 --- a/example/node/index.js +++ b/example/node/index.js @@ -28,14 +28,12 @@ var adminPub = fs.readFileSync('../admin@test.pub').toString() var keys = crypto.convertFromExisting(adminPub, adminPriv) var currentTime = Date.now() -var startTxCounter = 1 var startQueryCounter = 1 var creator = 'admin@test' // build transaction var tx = txBuilder .creatorAccountId(creator) - .txCounter(startTxCounter) .createdTime(currentTime) .createDomain('ru', 'user') .createAsset('dollar', 'ru', 2) diff --git a/example/python/tx-example.py b/example/python/tx-example.py index e1acc0691f..0b80857287 100644 --- a/example/python/tx-example.py +++ b/example/python/tx-example.py @@ -116,7 +116,6 @@ def send_query(query, key_pair): def tx1(): tx = tx_builder.creatorAccountId(creator) \ - .txCounter(1) \ .createdTime(current_time) \ .createDomain("domain", "user") \ .createAsset("coin", "domain", 2).build() @@ -127,7 +126,6 @@ def tx1(): def tx2(): tx = tx_builder.creatorAccountId(creator) \ - .txCounter(2) \ .createdTime(current_time) \ .addAssetQuantity("admin@test", "coin#domain", "1000.00").build() @@ -139,7 +137,6 @@ def tx3(): user1_kp = crypto.generateKeypair() tx = tx_builder.creatorAccountId(creator) \ - .txCounter(3) \ .createdTime(current_time) \ .createAccount("userone", "domain", user1_kp.publicKey()).build() @@ -149,7 +146,6 @@ def tx3(): def tx4(): tx = tx_builder.creatorAccountId(creator) \ - .txCounter(4) \ .createdTime(current_time) \ .transferAsset("admin@test", "userone@domain", "coin#domain", "Some message", "2.00").build() diff --git a/iroha-cli/interactive/impl/interactive_cli.cpp b/iroha-cli/interactive/impl/interactive_cli.cpp index e5fb118eb3..222fa7b8e2 100644 --- a/iroha-cli/interactive/impl/interactive_cli.cpp +++ b/iroha-cli/interactive/impl/interactive_cli.cpp @@ -44,12 +44,11 @@ namespace iroha_cli { const std::string &account_name, const std::string &default_peer_ip, int default_port, - uint64_t tx_counter, uint64_t qry_counter, const std::shared_ptr &provider) : creator_(account_name), tx_cli_( - creator_, default_peer_ip, default_port, tx_counter, provider), + creator_, default_peer_ip, default_port, provider), query_cli_( creator_, default_peer_ip, default_port, qry_counter, provider), statusCli_(default_peer_ip, default_port) { diff --git a/iroha-cli/interactive/impl/interactive_transaction_cli.cpp b/iroha-cli/interactive/impl/interactive_transaction_cli.cpp index c2af842707..d7849a029f 100644 --- a/iroha-cli/interactive/impl/interactive_transaction_cli.cpp +++ b/iroha-cli/interactive/impl/interactive_transaction_cli.cpp @@ -178,13 +178,11 @@ namespace iroha_cli { const std::string &creator_account, const std::string &default_peer_ip, int default_port, - uint64_t tx_counter, const std::shared_ptr &provider) : current_context_(MAIN), creator_(creator_account), default_peer_ip_(default_peer_ip), default_port_(default_port), - tx_counter_(tx_counter), provider_(provider) { log_ = logger::log("InteractiveTransactionCli"); createCommandMenu(); @@ -196,8 +194,7 @@ namespace iroha_cli { current_context_ = MAIN; printMenu("Forming a new transactions, choose command to add: ", commands_menu_); - // Creating a new transaction, increment local tx_counter - ++tx_counter_; + // Creating a new transaction while (is_parsing) { auto line = promptString("> "); if (not line) { @@ -475,7 +472,7 @@ namespace iroha_cli { // Forming a transaction auto tx = - tx_generator_.generateTransaction(creator_, tx_counter_, commands_); + tx_generator_.generateTransaction(creator_, commands_); // clear commands so that we can start creating new tx commands_.clear(); @@ -504,7 +501,7 @@ namespace iroha_cli { // Forming a transaction auto tx = - tx_generator_.generateTransaction(creator_, tx_counter_, commands_); + tx_generator_.generateTransaction(creator_, commands_); // clear commands so that we can start creating new tx commands_.clear(); diff --git a/iroha-cli/interactive/interactive_cli.hpp b/iroha-cli/interactive/interactive_cli.hpp index 8f0b00a915..0756746042 100644 --- a/iroha-cli/interactive/interactive_cli.hpp +++ b/iroha-cli/interactive/interactive_cli.hpp @@ -32,7 +32,6 @@ namespace iroha_cli { * @param account_name registered in Iroha network * @param default_peer_ip default peer ip to send transactions/query * @param default_port default port of peer's Iroha Torii - * @param tx_counter synchronized nonce for sending transaction * @param qry_counter synchronized nonce for sending queries * @param provider crypto provider to make signatures */ @@ -40,7 +39,6 @@ namespace iroha_cli { const std::string &account_name, const std::string &default_peer_ip, int default_port, - uint64_t tx_counter, uint64_t qry_counter, const std::shared_ptr &provider); /** diff --git a/iroha-cli/interactive/interactive_transaction_cli.hpp b/iroha-cli/interactive/interactive_transaction_cli.hpp index a9a5abb572..5e8f2a9597 100644 --- a/iroha-cli/interactive/interactive_transaction_cli.hpp +++ b/iroha-cli/interactive/interactive_transaction_cli.hpp @@ -40,14 +40,12 @@ namespace iroha_cli { * @param creator_account user Iroha account * @param default_peer_ip of Iroha peer * @param default_port of Iroha peer - * @param tx_counter synchronized with Iroha network * @param provider for signing transactions */ InteractiveTransactionCli( const std::string &creator_account, const std::string &default_peer_ip, int default_port, - uint64_t tx_counter, const std::shared_ptr &provider); /** * Run interactive query command line @@ -180,9 +178,6 @@ namespace iroha_cli { std::string default_peer_ip_; int default_port_; - // Transaction counter specific for account creator - uint64_t tx_counter_; - // Builder for new commands iroha::model::generators::CommandGenerator generator_; diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index 42333694a0..1e6d7960f2 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -178,7 +178,6 @@ int main(int argc, char *argv[]) { FLAGS_peer_ip, FLAGS_torii_port, 0, - 0, std::make_shared( *std::unique_ptr(keypair->makeOldModel()))); interactiveCli.run(); diff --git a/irohad/ametsuchi/impl/postgres_wsv_command.cpp b/irohad/ametsuchi/impl/postgres_wsv_command.cpp index d0b30339a5..32a53a54ee 100644 --- a/irohad/ametsuchi/impl/postgres_wsv_command.cpp +++ b/irohad/ametsuchi/impl/postgres_wsv_command.cpp @@ -162,13 +162,11 @@ namespace iroha { const shared_model::interface::Account &account) { auto result = execute_( "INSERT INTO account(account_id, domain_id, quorum, " - "transaction_count, data) VALUES (" + "data) VALUES (" + transaction_.quote(account.accountId()) + ", " + transaction_.quote(account.domainId()) + ", " + transaction_.quote(account.quorum()) + ", " - // Transaction counter - + transaction_.quote(default_tx_counter) + ", " + transaction_.quote(account.jsonData()) + ");"); auto message_gen = [&] { @@ -176,10 +174,9 @@ namespace iroha { "account id: '%s', " "domain id: '%s', " "quorum: '%d', " - "transaction counter: '%d', " "json_data: %s") % account.accountId() % account.domainId() % account.quorum() - % default_tx_counter % account.jsonData()) + % account.jsonData()) .str(); }; @@ -359,8 +356,6 @@ namespace iroha { "UPDATE account\n" " SET quorum=" + transaction_.quote(account.quorum()) + - ", transaction_count=" + - /*account.transaction_count*/ transaction_.quote(default_tx_counter) + "\n" " WHERE account_id=" + transaction_.quote(account.accountId()) + ";"); diff --git a/irohad/ametsuchi/impl/postgres_wsv_command.hpp b/irohad/ametsuchi/impl/postgres_wsv_command.hpp index 4290db4365..2f251a3599 100644 --- a/irohad/ametsuchi/impl/postgres_wsv_command.hpp +++ b/irohad/ametsuchi/impl/postgres_wsv_command.hpp @@ -91,8 +91,6 @@ namespace iroha { &permission_id) override; private: - const size_t default_tx_counter = 0; - pqxx::nontransaction &transaction_; using ExecuteType = decltype(makeExecuteResult(transaction_)); diff --git a/irohad/ametsuchi/impl/storage_impl.hpp b/irohad/ametsuchi/impl/storage_impl.hpp index b44b6eb3c1..db05de7358 100644 --- a/irohad/ametsuchi/impl/storage_impl.hpp +++ b/irohad/ametsuchi/impl/storage_impl.hpp @@ -134,7 +134,6 @@ CREATE TABLE IF NOT EXISTS account ( account_id character varying(288), domain_id character varying(255) NOT NULL REFERENCES domain, quorum int NOT NULL, - transaction_count int NOT NULL DEFAULT 0, data JSONB, PRIMARY KEY (account_id) ); diff --git a/irohad/model/converters/impl/json_transaction_factory.cpp b/irohad/model/converters/impl/json_transaction_factory.cpp index 75e1a285c1..7ab22929b9 100644 --- a/irohad/model/converters/impl/json_transaction_factory.cpp +++ b/irohad/model/converters/impl/json_transaction_factory.cpp @@ -43,7 +43,6 @@ namespace iroha { document.AddMember("created_ts", transaction.created_ts, allocator); document.AddMember( "creator_account_id", transaction.creator_account_id, allocator); - document.AddMember("tx_counter", transaction.tx_counter, allocator); Value commands; commands.SetArray(); @@ -82,7 +81,6 @@ namespace iroha { return boost::make_optional(Transaction()) | des.Uint64(&Transaction::created_ts, "created_ts") | des.String(&Transaction::creator_account_id, "creator_account_id") - | des.Uint64(&Transaction::tx_counter, "tx_counter") | des.Array(&Transaction::signatures, "signatures") | des.Array(&Transaction::commands, "commands", des_commands); } diff --git a/irohad/model/converters/impl/pb_transaction_factory.cpp b/irohad/model/converters/impl/pb_transaction_factory.cpp index 91c5d10145..c7c34a3d15 100644 --- a/irohad/model/converters/impl/pb_transaction_factory.cpp +++ b/irohad/model/converters/impl/pb_transaction_factory.cpp @@ -34,7 +34,6 @@ namespace iroha { auto pl = pbtx.mutable_payload(); pl->set_created_time(tx.created_ts); pl->set_creator_account_id(tx.creator_account_id); - pl->set_tx_counter(tx.tx_counter); for (const auto &command : tx.commands) { auto cmd = pl->add_commands(); @@ -56,7 +55,6 @@ namespace iroha { model::Transaction tx; const auto &pl = pb_tx.payload(); - tx.tx_counter = pl.tx_counter(); tx.creator_account_id = pl.creator_account_id(); tx.created_ts = pl.created_time(); diff --git a/irohad/model/generators/impl/transaction_generator.cpp b/irohad/model/generators/impl/transaction_generator.cpp index ae5d6d6682..1e570e3809 100644 --- a/irohad/model/generators/impl/transaction_generator.cpp +++ b/irohad/model/generators/impl/transaction_generator.cpp @@ -30,7 +30,6 @@ namespace iroha { Transaction tx; tx.created_ts = timestamp; tx.creator_account_id = ""; - tx.tx_counter = 0; CommandGenerator command_generator; // Add peers for (size_t i = 0; i < peers_address.size(); ++i) { @@ -76,22 +75,19 @@ namespace iroha { Transaction TransactionGenerator::generateTransaction( ts64_t timestamp, std::string creator_account_id, - uint64_t tx_counter, std::vector> commands) { Transaction tx; tx.created_ts = timestamp; tx.creator_account_id = creator_account_id; - tx.tx_counter = tx_counter; tx.commands = commands; return tx; } Transaction TransactionGenerator::generateTransaction( std::string creator_account_id, - uint64_t tx_counter, std::vector> commands) { return generateTransaction( - iroha::time::now(), creator_account_id, tx_counter, commands); + iroha::time::now(), creator_account_id, commands); } } // namespace generators diff --git a/irohad/model/generators/transaction_generator.hpp b/irohad/model/generators/transaction_generator.hpp index f72d335e76..fe72ed4361 100644 --- a/irohad/model/generators/transaction_generator.hpp +++ b/irohad/model/generators/transaction_generator.hpp @@ -41,27 +41,23 @@ namespace iroha { * Generate transaction from give meta data and commands list * @param timestamp * @param creator_account_id - * @param tx_counter * @param commands * @return */ Transaction generateTransaction( ts64_t timestamp, std::string creator_account_id, - uint64_t tx_counter, std::vector> commands); /** * Generate transaction from give meta data and commands list * @param timestamp * @param creator_account_id - * @param tx_counter * @param commands * @return */ Transaction generateTransaction( std::string creator_account_id, - uint64_t tx_counter, std::vector> commands); }; } // namespace generators diff --git a/irohad/model/impl/model_operators.cpp b/irohad/model/impl/model_operators.cpp index 1aaf25a310..5e2e5256d9 100644 --- a/irohad/model/impl/model_operators.cpp +++ b/irohad/model/impl/model_operators.cpp @@ -211,7 +211,7 @@ namespace iroha { rhs.commands.begin(), rhs.commands.end(), [](const auto &i, const auto &j) { return *i == *j; }) - && rhs.tx_counter == tx_counter && rhs.signatures == signatures + && rhs.signatures == signatures && rhs.created_ts == created_ts; } diff --git a/irohad/model/transaction.hpp b/irohad/model/transaction.hpp index 7b0df51ec3..16272c4765 100644 --- a/irohad/model/transaction.hpp +++ b/irohad/model/transaction.hpp @@ -54,17 +54,6 @@ namespace iroha { */ std::string creator_account_id{}; - /** - * Number for protecting against replay attack. - * Number that is stored inside of each account. - * Used to prevent replay attacks. - * During a stateful validation look at account and compare numbers - * if number inside a transaction is less than in account, - * this transaction is replayed. - * META field - */ - uint64_t tx_counter{}; - /** * Bunch of commands attached to transaction * shared_ptr is used since Proposal has to be copied diff --git a/irohad/ordering/impl/ordering_gate_impl.cpp b/irohad/ordering/impl/ordering_gate_impl.cpp index bf55528127..3770102227 100644 --- a/irohad/ordering/impl/ordering_gate_impl.cpp +++ b/irohad/ordering/impl/ordering_gate_impl.cpp @@ -38,8 +38,7 @@ namespace iroha { void OrderingGateImpl::propagateTransaction( std::shared_ptr transaction) { - log_->info("propagate tx, tx_counter: {} account_id: {}", - std::to_string(transaction->transactionCounter()), + log_->info("propagate tx, account_id: {}", " account_id: " + transaction->creatorAccountId()); transport_->propagateTransaction(transaction); diff --git a/schema/block.proto b/schema/block.proto index 4563e995e0..7917d2706a 100644 --- a/schema/block.proto +++ b/schema/block.proto @@ -12,8 +12,7 @@ message Header { message Payload { repeated Command commands = 1; string creator_account_id = 2; - uint64 tx_counter = 3; - uint64 created_time = 4; + uint64 created_time = 3; } Payload payload = 1; diff --git a/shared_model/backend/protobuf/transaction.hpp b/shared_model/backend/protobuf/transaction.hpp index f78c22ad77..3a6b374d90 100644 --- a/shared_model/backend/protobuf/transaction.hpp +++ b/shared_model/backend/protobuf/transaction.hpp @@ -46,10 +46,6 @@ namespace shared_model { return payload_.creator_account_id(); } - interface::types::CounterType transactionCounter() const override { - return payload_.tx_counter(); - } - const Transaction::CommandsType &commands() const override { return *commands_; } diff --git a/shared_model/bindings/model_transaction_builder.cpp b/shared_model/bindings/model_transaction_builder.cpp index 45dad87608..2fbd77c656 100644 --- a/shared_model/bindings/model_transaction_builder.cpp +++ b/shared_model/bindings/model_transaction_builder.cpp @@ -20,7 +20,7 @@ namespace shared_model { namespace bindings { ModelTransactionBuilder::ModelTransactionBuilder() { - *this = creatorAccountId("").createdTime(0).txCounter(0); + *this = creatorAccountId("").createdTime(0); } ModelTransactionBuilder ModelTransactionBuilder::creatorAccountId( @@ -28,11 +28,6 @@ namespace shared_model { return ModelTransactionBuilder(builder_.creatorAccountId(account_id)); } - ModelTransactionBuilder ModelTransactionBuilder::txCounter( - interface::types::CounterType tx_counter) { - return ModelTransactionBuilder(builder_.txCounter(tx_counter)); - } - ModelTransactionBuilder ModelTransactionBuilder::createdTime( interface::types::TimestampType created_time) { return ModelTransactionBuilder(builder_.createdTime(created_time)); diff --git a/shared_model/bindings/model_transaction_builder.hpp b/shared_model/bindings/model_transaction_builder.hpp index 55dda0687c..ce9d96cf30 100644 --- a/shared_model/bindings/model_transaction_builder.hpp +++ b/shared_model/bindings/model_transaction_builder.hpp @@ -46,14 +46,6 @@ namespace shared_model { ModelTransactionBuilder creatorAccountId( const interface::types::AccountIdType &account_id); - /** - * Sets transaction counter field - * @param tx_counter - transaction counter - * @return builder with tx_counter field appended - */ - ModelTransactionBuilder txCounter( - interface::types::CounterType tx_counter); - /** * Sets time of creation * @param created_time - time of creation diff --git a/shared_model/builders/protobuf/builder_templates/transaction_template.hpp b/shared_model/builders/protobuf/builder_templates/transaction_template.hpp index 1440e29366..2387a1a120 100644 --- a/shared_model/builders/protobuf/builder_templates/transaction_template.hpp +++ b/shared_model/builders/protobuf/builder_templates/transaction_template.hpp @@ -53,7 +53,6 @@ namespace shared_model { enum RequiredFields { Command, CreatorAccountId, - TxCounter, CreatedTime, TOTAL }; @@ -107,12 +106,6 @@ namespace shared_model { }); } - auto txCounter(interface::types::CounterType tx_counter) const { - return transform([&](auto &tx) { - tx.mutable_payload()->set_tx_counter(tx_counter); - }); - } - auto createdTime(interface::types::TimestampType created_time) const { return transform([&](auto &tx) { tx.mutable_payload()->set_created_time(created_time); diff --git a/shared_model/interfaces/transaction.hpp b/shared_model/interfaces/transaction.hpp index 970a17b885..994ed49d97 100644 --- a/shared_model/interfaces/transaction.hpp +++ b/shared_model/interfaces/transaction.hpp @@ -44,11 +44,6 @@ namespace shared_model { */ virtual const types::AccountIdType &creatorAccountId() const = 0; - /** - * @return actual number of transaction of this user - */ - virtual types::CounterType transactionCounter() const = 0; - /// Type of command using CommandType = detail::PolymorphicWrapper; @@ -66,7 +61,6 @@ namespace shared_model { new iroha::model::Transaction(); oldStyleTransaction->created_ts = createdTime(); oldStyleTransaction->creator_account_id = creatorAccountId(); - oldStyleTransaction->tx_counter = transactionCounter(); std::for_each(commands().begin(), commands().end(), @@ -91,7 +85,6 @@ namespace shared_model { return detail::PrettyStringBuilder() .init("Transaction") .append("hash", hash().hex()) - .append("txCounter", std::to_string(transactionCounter())) .append("creatorAccountId", creatorAccountId()) .append("createdTime", std::to_string(createdTime())) .append("commands") diff --git a/shared_model/packages/javascript/example/index.js b/shared_model/packages/javascript/example/index.js index a5e6345997..563b19eb03 100644 --- a/shared_model/packages/javascript/example/index.js +++ b/shared_model/packages/javascript/example/index.js @@ -28,14 +28,12 @@ var adminPub = fs.readFileSync('admin@test.pub').toString() var keys = crypto.convertFromExisting(adminPub, adminPriv) var currentTime = Date.now() -var startTxCounter = 1 var startQueryCounter = 1 var creator = 'admin@test' // build transaction var tx = txBuilder .creatorAccountId(creator) - .txCounter(startTxCounter) .createdTime(currentTime) .createDomain('ru', 'user') .createAsset('dollar', 'ru', 2) diff --git a/shared_model/packages/javascript/tests/txbuilder.js b/shared_model/packages/javascript/tests/txbuilder.js index 79b59516ea..4e3c7490ed 100644 --- a/shared_model/packages/javascript/tests/txbuilder.js +++ b/shared_model/packages/javascript/tests/txbuilder.js @@ -20,16 +20,16 @@ test('ModelTransactionBuilder tests', function (t) { t.comment('Basic TransactionBuilder tests') - t.throws(() => txBuilder.build(), /Transaction should contain at least one command/, 'Should throw exception 0 commands in transaction, wrong creator_account_id, timestamp and counter') - t.throws(() => txBuilder.creatorAccountId(adminAccountId).build(), /Transaction should contain at least one command/, 'Should throw exception about zero commands in transaction, wrong timestamp and counter') - t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(0).txCounter(1).build(), /Transaction should contain at least one command bad timestamp: too old/, 'Should throw 0 commands + bad timestamp: too old') - t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(time).txCounter(0).build(), /Transaction should contain at least one command Counter should be > 0/, 'Should throw 0 commands + Counter should be > 0') - t.throws(() => txBuilder.creatorAccountId('').createdTime(time).txCounter(1).build(), /Transaction should contain at least one command Wrongly formed creator_account_id, passed value: ''/, 'Should throw 0 commands + Wrongly formed creator_account_id') - t.throws(() => txBuilder.creatorAccountId('@@@').createdTime(time).txCounter(1).build(), /Transaction should contain at least one command Wrongly formed creator_account_id, passed value: '@@@'/, 'Should throw 0 commands + Wrongly formed creator_account_id') - t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(time).txCounter(1).build(), /Transaction should contain at least one command/, 'Should throw exception about zero commands in transaction') - - // Transaction with valid txCounter, creatorAccountId and createdTime - let correctTx = txBuilder.creatorAccountId(adminAccountId).createdTime(time).txCounter(1) + t.throws(() => txBuilder.build(), /Transaction should contain at least one command/, 'Should throw exception 0 commands in transaction, wrong creator_account_id, timestamp') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).build(), /Transaction should contain at least one command/, 'Should throw exception about zero commands in transaction, wrong timestamp') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(0).build(), /Transaction should contain at least one command bad timestamp: too old/, 'Should throw 0 commands + bad timestamp: too old') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(time).build(), /Transaction should contain at least one command/, 'Should throw 0 commands') + t.throws(() => txBuilder.creatorAccountId('').createdTime(time).build(), /Transaction should contain at least one command Wrongly formed creator_account_id, passed value: ''/, 'Should throw 0 commands + Wrongly formed creator_account_id') + t.throws(() => txBuilder.creatorAccountId('@@@').createdTime(time).build(), /Transaction should contain at least one command Wrongly formed creator_account_id, passed value: '@@@'/, 'Should throw 0 commands + Wrongly formed creator_account_id') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(time).build(), /Transaction should contain at least one command/, 'Should throw exception about zero commands in transaction') + + // Transaction with valid creatorAccountId and createdTime + let correctTx = txBuilder.creatorAccountId(adminAccountId).createdTime(time) // addAssetQuantity() tests t.comment('Testing addAssetQuantity()') diff --git a/shared_model/validators/container_validator.hpp b/shared_model/validators/container_validator.hpp index 52634050c2..450f0f265e 100644 --- a/shared_model/validators/container_validator.hpp +++ b/shared_model/validators/container_validator.hpp @@ -32,7 +32,9 @@ namespace shared_model { /** * Class that validates blocks and proposal common fieds */ - template + template class ContainerValidator { protected: void validateHeight(ReasonsGroupType &reason, @@ -49,9 +51,7 @@ namespace shared_model { const interface::Transaction &transaction) const { auto answer = transaction_validator_.validate(transaction); if (answer.hasErrors()) { - auto message = (boost::format("Tx #%d: %s") - % transaction.transactionCounter() % answer.reason()) - .str(); + auto message = (boost::format("Tx: %s") % answer.reason()).str(); reason.second.push_back(message); } } @@ -83,8 +83,10 @@ namespace shared_model { } return answer; } + private: TransactionValidator transaction_validator_; + protected: FieldValidator field_validator_; }; diff --git a/shared_model/validators/transaction_validator.hpp b/shared_model/validators/transaction_validator.hpp index 43f6a42f8b..655b1842e6 100644 --- a/shared_model/validators/transaction_validator.hpp +++ b/shared_model/validators/transaction_validator.hpp @@ -279,7 +279,6 @@ namespace shared_model { field_validator_.validateCreatorAccountId(tx_reason, tx.creatorAccountId()); field_validator_.validateCreatedTime(tx_reason, tx.createdTime()); - field_validator_.validateCounter(tx_reason, tx.transactionCounter()); if (not tx_reason.second.empty()) { answer.addReason(std::move(tx_reason)); diff --git a/test/framework/base_tx.hpp b/test/framework/base_tx.hpp index 67314f7be0..3ee5f59979 100644 --- a/test/framework/base_tx.hpp +++ b/test/framework/base_tx.hpp @@ -35,7 +35,6 @@ namespace framework { user, integration_framework::IntegrationTestFramework::kDefaultDomain, key) - .txCounter(1) .creatorAccountId( integration_framework::IntegrationTestFramework::kAdminId) .createdTime(iroha::time::now()); diff --git a/test/framework/integration_framework/integration_test_framework.cpp b/test/framework/integration_framework/integration_test_framework.cpp index d20bc3f546..9af9197f8f 100644 --- a/test/framework/integration_framework/integration_test_framework.cpp +++ b/test/framework/integration_framework/integration_test_framework.cpp @@ -72,7 +72,6 @@ DROP TABLE IF EXISTS index_by_id_height_asset; auto genesis_tx = shared_model::proto::TransactionBuilder() .creatorAccountId(kAdminId) - .txCounter(1) .createdTime(iroha::time::now()) .addPeer("0.0.0.0:50541", key.publicKey()) .createRole(kDefaultRole, diff --git a/test/integration/acceptance/add_asset_qty_test.cpp b/test/integration/acceptance/add_asset_qty_test.cpp index 5a66b3ec11..c6c14ecf8f 100644 --- a/test/integration/acceptance/add_asset_qty_test.cpp +++ b/test/integration/acceptance/add_asset_qty_test.cpp @@ -49,7 +49,6 @@ class AddAssetQuantity : public ::testing::Test { */ auto baseTx() { return TestUnsignedTransactionBuilder() - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()); } @@ -248,7 +247,6 @@ TEST_F(AddAssetQuantity, OtherDomain) { // Generate new domain, new user and an asset .sendTx( shared_model::proto::TransactionBuilder() - .txCounter(1) .creatorAccountId( integration_framework::IntegrationTestFramework::kAdminId) .createdTime(iroha::time::now()) diff --git a/test/integration/acceptance/create_account_test.cpp b/test/integration/acceptance/create_account_test.cpp index 7eb2c60370..9945ad7c6c 100644 --- a/test/integration/acceptance/create_account_test.cpp +++ b/test/integration/acceptance/create_account_test.cpp @@ -49,7 +49,6 @@ class CreateAccount : public ::testing::Test { */ auto baseTx() { return TestUnsignedTransactionBuilder() - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()); } diff --git a/test/integration/acceptance/create_domain_test.cpp b/test/integration/acceptance/create_domain_test.cpp index 90a636a542..e70b036629 100644 --- a/test/integration/acceptance/create_domain_test.cpp +++ b/test/integration/acceptance/create_domain_test.cpp @@ -49,7 +49,6 @@ class CreateDomain : public ::testing::Test { */ auto baseTx() { return TestUnsignedTransactionBuilder() - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()); } diff --git a/test/integration/acceptance/create_role_test.cpp b/test/integration/acceptance/create_role_test.cpp index 65b88943af..f116046400 100644 --- a/test/integration/acceptance/create_role_test.cpp +++ b/test/integration/acceptance/create_role_test.cpp @@ -54,7 +54,6 @@ class CreateRole : public ::testing::Test { const std::string &role_name) { return TestUnsignedTransactionBuilder() .createRole(role_name, perms) - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()); } diff --git a/test/integration/acceptance/get_transactions_test.cpp b/test/integration/acceptance/get_transactions_test.cpp index b21a37543c..4efade0235 100644 --- a/test/integration/acceptance/get_transactions_test.cpp +++ b/test/integration/acceptance/get_transactions_test.cpp @@ -54,7 +54,6 @@ class GetTransactions : public ::testing::Test { auto dummyTx() { return shared_model::proto::TransactionBuilder() .setAccountQuorum(kUserId, 1) - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()) .build() diff --git a/test/integration/acceptance/invalid_fields_test.cpp b/test/integration/acceptance/invalid_fields_test.cpp index 8134b11bb5..3d4eb57753 100644 --- a/test/integration/acceptance/invalid_fields_test.cpp +++ b/test/integration/acceptance/invalid_fields_test.cpp @@ -46,7 +46,6 @@ class InvalidField : public ::testing::Test { TEST_F(InvalidField, Signature) { auto tx = proto::TransactionBuilder() .createAccount(kUser, "test", kUserKeypair.publicKey()) - .txCounter(1) .creatorAccountId("admin@test") .createdTime(iroha::time::now()) .build() @@ -75,7 +74,6 @@ TEST_F(InvalidField, Signature) { TEST_F(InvalidField, Pubkey) { auto tx = proto::TransactionBuilder() .createAccount(kUser, "test", kUserKeypair.publicKey()) - .txCounter(1) .creatorAccountId("admin@test") .createdTime(iroha::time::now()) .build() diff --git a/test/integration/acceptance/subtract_asset_qty_test.cpp b/test/integration/acceptance/subtract_asset_qty_test.cpp index c161ed4630..7df25dee1f 100644 --- a/test/integration/acceptance/subtract_asset_qty_test.cpp +++ b/test/integration/acceptance/subtract_asset_qty_test.cpp @@ -50,7 +50,6 @@ class SubtractAssetQuantity : public ::testing::Test { */ auto baseTx() { return TestUnsignedTransactionBuilder() - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()); } diff --git a/test/integration/acceptance/transfer_asset_test.cpp b/test/integration/acceptance/transfer_asset_test.cpp index 4d434166d6..b7ecaa9e26 100644 --- a/test/integration/acceptance/transfer_asset_test.cpp +++ b/test/integration/acceptance/transfer_asset_test.cpp @@ -59,7 +59,6 @@ class TransferAsset : public ::testing::Test { const std::string &amount) { const std::string kUserId = user + "@test"; return proto::TransactionBuilder() - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()) .addAssetQuantity(kUserId, kAsset, amount) @@ -73,7 +72,6 @@ class TransferAsset : public ::testing::Test { */ auto baseTx() { return TestUnsignedTransactionBuilder() - .txCounter(1) .creatorAccountId(kUser1 + "@test") .createdTime(iroha::time::now()); } @@ -406,7 +404,6 @@ TEST_F(TransferAsset, InterDomain) { .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx( shared_model::proto::TransactionBuilder() - .txCounter(1) .creatorAccountId( integration_framework::IntegrationTestFramework::kAdminId) .createdTime(iroha::time::now()) diff --git a/test/integration/acceptance/tx_acceptance_test.cpp b/test/integration/acceptance/tx_acceptance_test.cpp index fb497f6248..03c5f8c085 100644 --- a/test/integration/acceptance/tx_acceptance_test.cpp +++ b/test/integration/acceptance/tx_acceptance_test.cpp @@ -58,7 +58,6 @@ auto checkStatefulValid = [](auto &block) { */ TEST(AcceptanceTest, NonExistentCreatorAccountId) { auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId(kNonUser) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -73,65 +72,6 @@ TEST(AcceptanceTest, NonExistentCreatorAccountId) { .done(); } -/** - * @given some user - * @when sending 2 transactions with the same txCounter to the ledger - * @then receive STATELESS_VALIDATION_SUCCESS status on both txs - * AND STATELESS_VALIDATION_SUCCESS on first - * AND STATEFUL_VALIDATION_FAILED on second - */ - -// TODO: Solonets / IR-1166 - Double tx counter / Satisfy disabled test -TEST(AcceptanceTest, DISABLED_DublicatedTxCounter) { - auto tx1 = shared_model::proto::TransactionBuilder() - .txCounter(2) - .createdTime(iroha::time::now()) - .creatorAccountId(kAdmin) - .addAssetQuantity(kAdmin, kAsset, "1.0") - .build() - .signAndAddSignature(kAdminKeypair); - auto tx2 = shared_model::proto::TransactionBuilder() - .txCounter(2) - .createdTime(iroha::time::now()) - .creatorAccountId(kAdmin) - .addAssetQuantity(kAdmin, kAsset, "1.0") - .build() - .signAndAddSignature(kAdminKeypair); - - integration_framework::IntegrationTestFramework(1) - .setInitialState(kAdminKeypair) - .sendTx(tx1, checkStatelessValid) - .skipProposal() - .checkBlock(checkStatefulValid) - .sendTx(tx2, checkStatelessValid) - .skipProposal() - .checkBlock(checkStatefulInvalid) - .done(); -} - -/** - * @given some user - * @when sending transactions with the Maximum txCounter possible to the ledger - * @then receive STATELESS_VALIDATION_SUCCESS status - * AND STATEFUL_VALIDATION_SUCCESS on that tx - */ -TEST(AcceptanceTest, MaxTxCounter) { - auto tx1 = shared_model::proto::TransactionBuilder() - .txCounter(2) - .createdTime(iroha::time::now()) - .creatorAccountId(kAdmin) - .addAssetQuantity(kAdmin, kAsset, "1.0") - .build() - .signAndAddSignature(kAdminKeypair); - - integration_framework::IntegrationTestFramework(1) - .setInitialState(kAdminKeypair) - .sendTx(tx1, checkStatelessValid) - .skipProposal() - .checkBlock(checkStatefulValid) - .done(); -} - /** * @given some user * @when sending transactions with an 1 hour old UNIX time @@ -140,7 +80,6 @@ TEST(AcceptanceTest, MaxTxCounter) { */ TEST(AcceptanceTest, Transaction1HourOld) { auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::hours(-1))) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -162,7 +101,6 @@ TEST(AcceptanceTest, Transaction1HourOld) { */ TEST(AcceptanceTest, DISABLED_TransactionLess24HourOld) { auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::hours(24) - std::chrono::minutes(1))) .creatorAccountId(kAdmin) @@ -185,7 +123,6 @@ TEST(AcceptanceTest, DISABLED_TransactionLess24HourOld) { TEST(AcceptanceTest, TransactionMore24HourOld) { ASSERT_ANY_THROW( auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::hours(24) + std::chrono::minutes(1))) .creatorAccountId(kAdmin) @@ -193,7 +130,6 @@ TEST(AcceptanceTest, TransactionMore24HourOld) { .build() .signAndAddSignature(kAdminKeypair);); auto tx = TestUnsignedTransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::hours(24) + std::chrono::minutes(1))) .creatorAccountId(kAdmin) @@ -214,7 +150,6 @@ TEST(AcceptanceTest, TransactionMore24HourOld) { */ TEST(AcceptanceTest, Transaction5MinutesFromFuture) { auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::minutes(5) - std::chrono::seconds(10))) .creatorAccountId(kAdmin) @@ -238,14 +173,12 @@ TEST(AcceptanceTest, Transaction5MinutesFromFuture) { TEST(AcceptanceTest, Transaction10MinutesFromFuture) { ASSERT_ANY_THROW( auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::minutes(10))) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") .build() .signAndAddSignature(kAdminKeypair);); auto tx = TestUnsignedTransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now(std::chrono::minutes(10))) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -265,7 +198,6 @@ TEST(AcceptanceTest, Transaction10MinutesFromFuture) { TEST(AcceptanceTest, TransactionEmptyPubKey) { shared_model::proto::Transaction tx = TestTransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -288,7 +220,6 @@ TEST(AcceptanceTest, TransactionEmptyPubKey) { TEST(AcceptanceTest, TransactionEmptySignedblob) { shared_model::proto::Transaction tx = TestTransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -308,7 +239,6 @@ TEST(AcceptanceTest, TransactionEmptySignedblob) { TEST(AcceptanceTest, TransactionInvalidPublicKey) { shared_model::proto::Transaction tx = TestTransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -331,7 +261,6 @@ TEST(AcceptanceTest, TransactionInvalidPublicKey) { TEST(AcceptanceTest, TransactionInvalidSignedBlob) { shared_model::proto::Transaction tx = TestTransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -360,7 +289,6 @@ TEST(AcceptanceTest, TransactionInvalidSignedBlob) { TEST(AcceptanceTest, TransactionValidSignedBlob) { shared_model::proto::Transaction tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") diff --git a/test/integration/acceptance/tx_heavy_data.cpp b/test/integration/acceptance/tx_heavy_data.cpp index 1bc11d0720..93e6d09ce4 100644 --- a/test/integration/acceptance/tx_heavy_data.cpp +++ b/test/integration/acceptance/tx_heavy_data.cpp @@ -57,7 +57,6 @@ class HeavyTransactionTest : public ::testing::Test { */ auto baseTx() { return TestUnsignedTransactionBuilder() - .txCounter(1) .creatorAccountId(kUserId) .createdTime(iroha::time::now()); } diff --git a/test/integration/pipeline/pipeline_test.cpp b/test/integration/pipeline/pipeline_test.cpp index 5834c008ac..c94adbef95 100644 --- a/test/integration/pipeline/pipeline_test.cpp +++ b/test/integration/pipeline/pipeline_test.cpp @@ -70,7 +70,6 @@ TEST(PipelineIntegrationTest, SendTx) { auto tx = shared_model::proto::TransactionBuilder() .createdTime(iroha::time::now()) .creatorAccountId(kUser) - .txCounter(1) .addAssetQuantity(kUser, kAsset, "1.0") .build() .signAndAddSignature( diff --git a/test/module/iroha-cli/client_test.cpp b/test/module/iroha-cli/client_test.cpp index d965d9bc7a..d60fa6d1ff 100644 --- a/test/module/iroha-cli/client_test.cpp +++ b/test/module/iroha-cli/client_test.cpp @@ -122,7 +122,6 @@ TEST_F(ClientServerTest, SendTxWhenValid) { auto shm_tx = shared_model::proto::TransactionBuilder() .creatorAccountId("some@account") - .txCounter(1) .createdTime(iroha::time::now()) .setAccountQuorum("some@account", 2) .build() @@ -160,7 +159,6 @@ TEST_F(ClientServerTest, SendTxWhenStatelessInvalid) { // creating stateless invalid tx auto shm_tx = TestTransactionBuilder() .creatorAccountId("some@account") - .txCounter(1) .createdTime(iroha::time::now()) .setAccountQuorum("some@@account", 2) .build(); diff --git a/test/module/irohad/ametsuchi/ametsuchi_fixture.hpp b/test/module/irohad/ametsuchi/ametsuchi_fixture.hpp index 89fc25c817..0874ce5bbd 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_fixture.hpp +++ b/test/module/irohad/ametsuchi/ametsuchi_fixture.hpp @@ -140,7 +140,6 @@ CREATE TABLE IF NOT EXISTS account ( account_id character varying(288), domain_id character varying(255) NOT NULL REFERENCES domain, quorum int NOT NULL, - transaction_count int NOT NULL DEFAULT 0, data JSONB, PRIMARY KEY (account_id) ); diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index df8a92b5be..314aeec479 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -877,7 +877,6 @@ TEST_F(AmetsuchiTest, TestRestoreWSV) { auto genesis_tx = shared_model::proto::TransactionBuilder() .creatorAccountId("admin@test") - .txCounter(1) .createdTime(iroha::time::now()) .createRole(default_role, std::vector{ diff --git a/test/module/irohad/model/converters/json_transaction_test.cpp b/test/module/irohad/model/converters/json_transaction_test.cpp index 095c01ed4a..dcb4486fc7 100644 --- a/test/module/irohad/model/converters/json_transaction_test.cpp +++ b/test/module/irohad/model/converters/json_transaction_test.cpp @@ -63,7 +63,6 @@ TEST_F(JsonTransactionTest, InvalidWhenNegativeAddAssetQuantity) { ], "created_ts": 1503845603221, "creator_account_id": "admin@test", - "tx_counter": 1, "commands": [ { "command_type": "CreateAsset", diff --git a/test/module/irohad/model/converters/pb_block_test.cpp b/test/module/irohad/model/converters/pb_block_test.cpp index 719653c664..4f6251983a 100644 --- a/test/module/irohad/model/converters/pb_block_test.cpp +++ b/test/module/irohad/model/converters/pb_block_test.cpp @@ -41,7 +41,6 @@ TEST(BlockTest, bl_test) { orig_tx.signatures = {siga}; orig_tx.created_ts = 2; - orig_tx.tx_counter = 1; auto c1 = iroha::model::CreateDomain(); c1.domain_id = "keker"; diff --git a/test/module/irohad/model/converters/pb_query_responses_test.cpp b/test/module/irohad/model/converters/pb_query_responses_test.cpp index 1681808066..686022f830 100644 --- a/test/module/irohad/model/converters/pb_query_responses_test.cpp +++ b/test/module/irohad/model/converters/pb_query_responses_test.cpp @@ -143,7 +143,6 @@ TEST(QueryResponseTest, TransactionsResponseTest) { std::vector result; for (size_t i = 0; i < 3; ++i) { model::Transaction current; - current.tx_counter = i; result.push_back(current); } return result; @@ -153,14 +152,6 @@ TEST(QueryResponseTest, TransactionsResponseTest) { auto query_response = *pb_factory.serialize(shrd_tr); ASSERT_EQ(query_response.transactions_response().transactions().size(), 3); - for (size_t i = 0; i < 3; i++) { - ASSERT_EQ(query_response.transactions_response() - .transactions() - .Get(i) - .payload() - .tx_counter(), - i); - } } TEST(QueryResponseTest, roles_response) { diff --git a/test/module/irohad/model/converters/pb_transaction_test.cpp b/test/module/irohad/model/converters/pb_transaction_test.cpp index a286e434e4..a564f3b3dc 100644 --- a/test/module/irohad/model/converters/pb_transaction_test.cpp +++ b/test/module/irohad/model/converters/pb_transaction_test.cpp @@ -39,7 +39,6 @@ TEST(TransactionTest, tx_test) { orig_tx.signatures = {siga}; orig_tx.created_ts = 2; - orig_tx.tx_counter = 1; auto c1 = iroha::model::CreateDomain(); c1.domain_id = "keker"; diff --git a/test/module/irohad/model/model_crypto_provider_test.cpp b/test/module/irohad/model/model_crypto_provider_test.cpp index e8cc99a211..d86cc88972 100644 --- a/test/module/irohad/model/model_crypto_provider_test.cpp +++ b/test/module/irohad/model/model_crypto_provider_test.cpp @@ -33,7 +33,7 @@ namespace iroha { TEST_F(CryptoProviderTest, SignAndVerifyTransaction) { auto model_tx = - generators::TransactionGenerator().generateTransaction("test", 0, {}); + generators::TransactionGenerator().generateTransaction("test", {}); provider.sign(model_tx); ASSERT_TRUE(provider.verify(model_tx)); diff --git a/test/module/irohad/model/operators/model_operators_test.cpp b/test/module/irohad/model/operators/model_operators_test.cpp index f5acc205d3..8f27c9a17b 100644 --- a/test/module/irohad/model/operators/model_operators_test.cpp +++ b/test/module/irohad/model/operators/model_operators_test.cpp @@ -322,7 +322,6 @@ Transaction createTransaction() { Transaction transaction; transaction.created_ts = 1; transaction.creator_account_id = "132"; - transaction.tx_counter = 5; transaction.signatures.push_back(createSignature()); // commands diff --git a/test/module/irohad/ordering/ordering_gate_service_test.cpp b/test/module/irohad/ordering/ordering_gate_service_test.cpp index 5f4c1c887a..f4212109ec 100644 --- a/test/module/irohad/ordering/ordering_gate_service_test.cpp +++ b/test/module/irohad/ordering/ordering_gate_service_test.cpp @@ -130,7 +130,6 @@ class OrderingGateServiceTest : public ::testing::Test { void send_transaction(size_t i) { auto tx = std::make_shared( shared_model::proto::TransactionBuilder() - .txCounter(i) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -219,13 +218,6 @@ TEST_F(OrderingGateServiceTest, SplittingBunchTransactions) { ASSERT_EQ(proposals.at(1)->transactions().size(), 2); ASSERT_EQ(counter, 0); ASSERT_TRUE(wrapper.validate()); - - size_t i = 1; - for (auto &&proposal : proposals) { - for (auto &&tx : proposal->transactions()) { - ASSERT_EQ(tx->transactionCounter(), i++); - } - } } /** @@ -275,11 +267,7 @@ TEST_F(OrderingGateServiceTest, ProposalsReceivedWhenProposalSize) { ASSERT_EQ(proposals.size(), 2); ASSERT_EQ(counter, 0); - size_t i = 1; for (auto &&proposal : proposals) { ASSERT_EQ(proposal->transactions().size(), 5); - for (auto &&tx : proposal->transactions()) { - ASSERT_EQ(tx->transactionCounter(), i++); - } } } diff --git a/test/module/irohad/ordering/ordering_gate_test.cpp b/test/module/irohad/ordering/ordering_gate_test.cpp index f6c2c846bb..d34f2d3c18 100644 --- a/test/module/irohad/ordering/ordering_gate_test.cpp +++ b/test/module/irohad/ordering/ordering_gate_test.cpp @@ -139,7 +139,6 @@ TEST_F(OrderingGateTest, ProposalReceivedByGateWhenSent) { grpc::ServerContext context; auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -190,7 +189,6 @@ TEST(OrderingGateQueueBehaviour, SendManyProposals) { wrapper_after.subscribe(); auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") diff --git a/test/module/irohad/ordering/ordering_service_test.cpp b/test/module/irohad/ordering/ordering_service_test.cpp index aa17145d15..d6a1a4b4fc 100644 --- a/test/module/irohad/ordering/ordering_service_test.cpp +++ b/test/module/irohad/ordering/ordering_service_test.cpp @@ -84,7 +84,6 @@ class OrderingServiceTest : public ::testing::Test { auto getTx() { return std::make_shared( shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") diff --git a/test/module/irohad/simulator/simulator_test.cpp b/test/module/irohad/simulator/simulator_test.cpp index d9122e7b2d..71324bbeaf 100644 --- a/test/module/irohad/simulator/simulator_test.cpp +++ b/test/module/irohad/simulator/simulator_test.cpp @@ -83,7 +83,6 @@ shared_model::proto::Block makeBlock(int height) { shared_model::proto::Proposal makeProposal(int height) { auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -112,7 +111,6 @@ TEST_F(SimulatorTest, ValidWhenInitialized) { TEST_F(SimulatorTest, ValidWhenPreviousBlock) { // proposal with height 2 => height 1 block present => new block generated auto tx = shared_model::proto::TransactionBuilder() - .txCounter(2) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") diff --git a/test/module/irohad/torii/processor/transaction_processor_test.cpp b/test/module/irohad/torii/processor/transaction_processor_test.cpp index 867656d309..d465d9423d 100644 --- a/test/module/irohad/torii/processor/transaction_processor_test.cpp +++ b/test/module/irohad/torii/processor/transaction_processor_test.cpp @@ -104,7 +104,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { std::vector txs; for (size_t i = 0; i < proposal_size; i++) { auto &&tx = shared_model::proto::TransactionBuilder() - .txCounter(i + 1) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -158,7 +157,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorBlockCreatedTest) { std::vector txs; for (size_t i = 0; i < proposal_size; i++) { auto &&tx = shared_model::proto::TransactionBuilder() - .txCounter(i + 1) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -233,7 +231,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnCommitTest) { std::vector txs; for (size_t i = 0; i < proposal_size; i++) { auto &&tx = shared_model::proto::TransactionBuilder() - .txCounter(i + 1) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -304,7 +301,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorInvalidTxsTest) { std::vector block_txs; for (size_t i = 0; i < block_size; i++) { auto &&tx = shared_model::proto::TransactionBuilder() - .txCounter(i + 1) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") @@ -322,7 +318,6 @@ TEST_F(TransactionProcessorTest, TransactionProcessorInvalidTxsTest) { // in proposal but didn't appear in block for (size_t i = block_size; i < proposal_size; i++) { auto &&tx = shared_model::proto::TransactionBuilder() - .txCounter(i + 1) .createdTime(iroha::time::now()) .creatorAccountId("admin@ru") .addAssetQuantity("admin@tu", "coin#coin", "1.0") diff --git a/test/module/irohad/torii/torii_queries_test.cpp b/test/module/irohad/torii/torii_queries_test.cpp index 08e8c9a088..5ac4106ac1 100644 --- a/test/module/irohad/torii/torii_queries_test.cpp +++ b/test/module/irohad/torii/torii_queries_test.cpp @@ -482,7 +482,6 @@ TEST_F(ToriiQueriesTest, FindTransactionsWhenValid) { std::shared_ptr current = clone(TestTransactionBuilder() .creatorAccountId(account.accountId()) - .txCounter(i) .build()); result.push_back(current); } @@ -521,7 +520,6 @@ TEST_F(ToriiQueriesTest, FindTransactionsWhenValid) { const auto &txs = tx_resp->transactions(); for (auto i = 0ul; i < txs.size(); i++) { ASSERT_EQ(txs.at(i)->creatorAccountId(), account.accountId()); - ASSERT_EQ(txs.at(i)->transactionCounter(), i); } ASSERT_EQ(model_query.hash(), resp.queryHash()); } diff --git a/test/module/irohad/torii/torii_service_test.cpp b/test/module/irohad/torii/torii_service_test.cpp index f1fbceabc0..212f7079ab 100644 --- a/test/module/irohad/torii/torii_service_test.cpp +++ b/test/module/irohad/torii/torii_service_test.cpp @@ -154,7 +154,6 @@ TEST_F(ToriiServiceTest, StatusWhenTxWasNotReceivedBlocking) { for (size_t i = 0; i < TimesToriiBlocking; ++i) { auto tx = TestTransactionBuilder() .creatorAccountId("accountA") - .txCounter(i) .build(); txs.push_back(tx); tx_hashes.push_back(tx.hash()); @@ -198,7 +197,6 @@ TEST_F(ToriiServiceTest, StatusWhenBlocking) { for (size_t i = 0; i < TimesToriiBlocking; ++i) { auto shm_tx = shared_model::proto::TransactionBuilder() .creatorAccountId(account_id) - .txCounter(i + 1) .createdTime(iroha::time::now()) .setAccountQuorum(account_id, 2) .build() @@ -307,7 +305,7 @@ TEST_F(ToriiServiceTest, CheckHash) { // create transactions, but do not send them for (size_t i = 0; i < tx_num; ++i) { - auto tx = TestTransactionBuilder().txCounter(i).build(); + auto tx = TestTransactionBuilder().build(); tx_hashes.push_back(tx.hash()); } @@ -340,11 +338,9 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { auto new_tx = TestTransactionBuilder() .creatorAccountId("accountA") - .txCounter(1) .build(); auto iroha_tx = proto::TransactionBuilder() - .txCounter(1) .creatorAccountId("a@domain") .setAccountQuorum("a@domain", 2) .createdTime(iroha::time::now()) diff --git a/test/module/irohad/validation/query_execution.cpp b/test/module/irohad/validation/query_execution.cpp index 5fc8c9be67..a5dc422626 100644 --- a/test/module/irohad/validation/query_execution.cpp +++ b/test/module/irohad/validation/query_execution.cpp @@ -81,14 +81,12 @@ class QueryValidateExecuteTest : public ::testing::Test { /** * Make transaction with specified parameters - * @param counter * @param creator * @return wrapper with created transaction */ - wTransaction makeTransaction(int counter, std::string creator) { + wTransaction makeTransaction(std::string creator) { return clone(TestTransactionBuilder() .creatorAccountId(creator) - .txCounter(counter) .build()); } @@ -102,7 +100,7 @@ class QueryValidateExecuteTest : public ::testing::Test { return rxcpp::observable<>::iterate([&creator, &N, this] { std::vector result; for (size_t i = 0; i < N; ++i) { - auto current = makeTransaction(i, creator); + auto current = makeTransaction(creator); result.push_back(current); } return result; diff --git a/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp b/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp index aeb294cbbb..cc4e8421cf 100644 --- a/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp +++ b/test/module/shared_model/backend_proto/shared_proto_transaction_test.cpp @@ -23,21 +23,8 @@ #include -/** - * @given protobuf transaction with transaction counter set - * @when converted to shared model - * @then shared model is created correctly - */ -TEST(ProtoTransaction, Create) { - iroha::protocol::Transaction transaction; - transaction.mutable_payload()->set_tx_counter(1); - shared_model::proto::Transaction proto(transaction); - ASSERT_EQ(proto.transactionCounter(), transaction.payload().tx_counter()); -} - // common data for tests auto created_time = iroha::time::now(); -shared_model::interface::types::CounterType tx_counter = 1; std::string creator_account_id = "admin@test"; /** @@ -47,7 +34,6 @@ std::string creator_account_id = "admin@test"; iroha::protocol::Transaction generateEmptyTransaction() { iroha::protocol::Transaction proto_tx; auto &payload = *proto_tx.mutable_payload(); - payload.set_tx_counter(tx_counter); payload.set_creator_account_id(creator_account_id); payload.set_created_time(created_time); @@ -98,7 +84,6 @@ TEST(ProtoTransaction, Builder) { sig->set_signature(shared_model::crypto::toBinaryString(signedProto)); auto tx = shared_model::proto::TransactionBuilder() - .txCounter(tx_counter) .creatorAccountId(creator_account_id) .addAssetQuantity(account_id, asset_id, amount) .createdTime(created_time) @@ -123,7 +108,6 @@ TEST(ProtoTransaction, BuilderWithInvalidTx) { ASSERT_THROW( shared_model::proto::TransactionBuilder() - .txCounter(tx_counter) .creatorAccountId(invalid_account_id) .addAssetQuantity(invalid_account_id, invalid_asset_id, amount) .createdTime(created_time) diff --git a/test/module/shared_model/bindings/BuilderTest.java b/test/module/shared_model/bindings/BuilderTest.java index 965006d194..f91d1f509b 100644 --- a/test/module/shared_model/bindings/BuilderTest.java +++ b/test/module/shared_model/bindings/BuilderTest.java @@ -28,7 +28,7 @@ public class BuilderTest { private ModelTransactionBuilder builder; ModelTransactionBuilder base() { - return new ModelTransactionBuilder().txCounter(BigInteger.valueOf(123)) + return new ModelTransactionBuilder() .createdTime(BigInteger.valueOf(System.currentTimeMillis())) .creatorAccountId("admin@test"); } diff --git a/test/module/shared_model/bindings/builder-test.py b/test/module/shared_model/bindings/builder-test.py index ee261f045c..057d59732e 100644 --- a/test/module/shared_model/bindings/builder-test.py +++ b/test/module/shared_model/bindings/builder-test.py @@ -14,7 +14,7 @@ def test_empty_tx(self): with self.assertRaises(ValueError): iroha.ModelTransactionBuilder().build() def generate_base(self): - return iroha.ModelTransactionBuilder().txCounter(123)\ + return iroha.ModelTransactionBuilder()\ .createdTime(int(time.time() * 1000))\ .creatorAccountId("admin@test")\ diff --git a/test/module/shared_model/builders/common_objects/query_response_builder_test.cpp b/test/module/shared_model/builders/common_objects/query_response_builder_test.cpp index ef67637091..770210f90e 100644 --- a/test/module/shared_model/builders/common_objects/query_response_builder_test.cpp +++ b/test/module/shared_model/builders/common_objects/query_response_builder_test.cpp @@ -33,7 +33,6 @@ const auto hash = std::string(32, '0'); uint64_t height = 1; uint8_t quorum = 2; -uint64_t counter = 1048576; boost::multiprecision::uint256_t valid_value = 1000; auto valid_precision = 1; @@ -337,7 +336,6 @@ TEST(QueryResponseBuilderTest, SignatoriesResponse) { TEST(QueryResponseBuilderTest, TransactionsResponse) { auto transaction = TestTransactionBuilder() .createdTime(created_time) - .txCounter(counter) .creatorAccountId(account_id) .setAccountQuorum(account_id, quorum) .build(); diff --git a/test/module/shared_model/builders/protobuf/transport_builder_test.cpp b/test/module/shared_model/builders/protobuf/transport_builder_test.cpp index e8ba2bd544..c48569ea66 100644 --- a/test/module/shared_model/builders/protobuf/transport_builder_test.cpp +++ b/test/module/shared_model/builders/protobuf/transport_builder_test.cpp @@ -44,7 +44,6 @@ class TransportBuilderTest : public ::testing::Test { auto createTransaction() { return TestUnsignedTransactionBuilder() .createdTime(created_time) - .txCounter(counter) .creatorAccountId(account_id) .setAccountQuorum(account_id, quorum) .build() @@ -54,7 +53,6 @@ class TransportBuilderTest : public ::testing::Test { auto createInvalidTransaction() { return TestUnsignedTransactionBuilder() .createdTime(created_time) - .txCounter(counter) .creatorAccountId(invalid_account_id) .setAccountQuorum(account_id, quorum) .build() diff --git a/test/module/shared_model/converters/json_proto_converter_test.cpp b/test/module/shared_model/converters/json_proto_converter_test.cpp index 2dec88ed48..93e7f88415 100644 --- a/test/module/shared_model/converters/json_proto_converter_test.cpp +++ b/test/module/shared_model/converters/json_proto_converter_test.cpp @@ -35,11 +35,9 @@ using namespace shared_model; TEST(JsonProtoConverterTest, JsonToProtoTxTest) { TestTransactionBuilder builder; - shared_model::interface::types::CounterType tx_counter = 1; std::string creator_account_id = "admin@test"; - auto orig_tx = builder.txCounter(tx_counter) - .creatorAccountId(creator_account_id) + auto orig_tx = builder.creatorAccountId(creator_account_id) .createdTime(123) .build(); diff --git a/test/module/shared_model/cryptography/crypto_usage_test.cpp b/test/module/shared_model/cryptography/crypto_usage_test.cpp index 211258f743..a32b312d39 100644 --- a/test/module/shared_model/cryptography/crypto_usage_test.cpp +++ b/test/module/shared_model/cryptography/crypto_usage_test.cpp @@ -49,7 +49,6 @@ class CryptoUsageTest : public ::testing::Test { transaction = std::make_unique( TestTransactionBuilder() .creatorAccountId(account_id) - .txCounter(1) .setAccountQuorum(account_id, 2) .build()); diff --git a/test/module/shared_model/validators/field_validator_test.cpp b/test/module/shared_model/validators/field_validator_test.cpp index f7a7630896..57e9df9ed3 100644 --- a/test/module/shared_model/validators/field_validator_test.cpp +++ b/test/module/shared_model/validators/field_validator_test.cpp @@ -113,11 +113,11 @@ class FieldValidatorTest : public ValidatorsTest { &FieldValidator::validateDomainId, &FieldValidatorTest::domain_id, domain_id_test_cases)); - for (const auto &field : {"tx_counter", "query_counter"}) { + for (const auto &field : {"query_counter"}) { field_validators.insert(makeValidator(field, &FieldValidator::validateCounter, &FieldValidatorTest::counter, - tx_counter_test_cases)); + counter_test_cases)); } field_validators.insert(makeValidator("quorum", @@ -466,7 +466,7 @@ class FieldValidatorTest : public ValidatorsTest { makeValidCase(&FieldValidatorTest::role_permission, iroha::protocol::RolePermission::can_append_role)}; - std::vector tx_counter_test_cases{ + std::vector counter_test_cases{ makeValidCase(&FieldValidatorTest::counter, 5), makeTestCase("zero_counter", &FieldValidatorTest::counter, diff --git a/test/module/shared_model/validators/transaction_validator_test.cpp b/test/module/shared_model/validators/transaction_validator_test.cpp index 2704c1e108..c6fda28442 100644 --- a/test/module/shared_model/validators/transaction_validator_test.cpp +++ b/test/module/shared_model/validators/transaction_validator_test.cpp @@ -30,12 +30,10 @@ using namespace shared_model; class TransactionValidatorTest : public ValidatorsTest { protected: iroha::protocol::Transaction generateEmptyTransaction() { - shared_model::interface::types::CounterType tx_counter = 1; std::string creator_account_id = "admin@test"; TestTransactionBuilder builder; - auto tx = builder.txCounter(tx_counter) - .creatorAccountId(creator_account_id) + auto tx = builder.creatorAccountId(creator_account_id) .createdTime(created_time) .build() .getTransport(); From 728f0c1f2f04671f10bf4980c12b2cb46c5d5f20 Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Mon, 16 Apr 2018 14:23:19 +0300 Subject: [PATCH 031/110] Restrict swig targets includes (#1221) Signed-off-by: Andrei Lebedev --- shared_model/bindings/CMakeLists.txt | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/shared_model/bindings/CMakeLists.txt b/shared_model/bindings/CMakeLists.txt index 4e21695fe4..93cdc42011 100644 --- a/shared_model/bindings/CMakeLists.txt +++ b/shared_model/bindings/CMakeLists.txt @@ -37,7 +37,6 @@ if (SWIG_PYTHON OR SWIG_JAVA OR SWIG_CSHARP OR SWIG_NODE) if (SHARED_MODEL_DISABLE_COMPATIBILITY) set(CMAKE_SWIG_FLAGS "-DDISABLE_BACKWARD") endif() - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set_source_files_properties(bindings.i PROPERTIES CPLUSPLUS ON) set_property(GLOBAL PROPERTY SWIG_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) @@ -51,9 +50,6 @@ if (SWIG_PYTHON) find_package(PythonLibs 3.6 REQUIRED) endif() - # path to where Python.h is found - include_directories(${PYTHON_INCLUDE_DIRS}) - if (${CMAKE_SYSTEM_NAME} STREQUAL Darwin) set(MAC_OPTS "-flat_namespace -undefined suppress") endif() @@ -61,18 +57,22 @@ if (SWIG_PYTHON) swig_add_library(iroha LANGUAGE python SOURCES bindings.i) swig_link_libraries(iroha ${Python_LIBRARIES} bindings ${MAC_OPTS}) add_custom_target(irohapy DEPENDS ${SWIG_MODULE_iroha_REAL_NAME}) - + # path to where Python.h is found + target_include_directories(${SWIG_MODULE_iroha_REAL_NAME} PUBLIC + ${PYTHON_INCLUDE_DIRS} + ) endif() if (SWIG_JAVA) find_package(JNI REQUIRED) - # the include path to jni.h - include_directories(${JAVA_INCLUDE_PATH}) - # the include path to jni_md.h - include_directories(${JAVA_INCLUDE_PATH2}) swig_add_library(irohajava LANGUAGE java SOURCES bindings.i) swig_link_libraries(irohajava ${Java_LIBRARIES} bindings) + # the include path to jni.h and jni_md.h + target_include_directories(${SWIG_MODULE_irohajava_REAL_NAME} PUBLIC + ${JAVA_INCLUDE_PATH} + ${JAVA_INCLUDE_PATH2} + ) endif() if (SWIG_CSHARP) @@ -83,10 +83,6 @@ endif() if (SWIG_NODE) find_package (nodejs REQUIRED) - include_directories ( - ${NODEJS_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR}/.. - ) set (V8_VERSION_HEX 0x0${V8_VERSION_MAJOR}${V8_VERSION_MINOR}${V8_VERSION_PATCH}) string (LENGTH "${V8_VERSION_HEX}" V8_VERSION_HEX_length) @@ -110,4 +106,7 @@ if (SWIG_NODE) ) set_target_properties(irohanode PROPERTIES PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX}) target_link_libraries(irohanode bindings ${MAC_OPTS}) + target_include_directories(${SWIG_MODULE_irohanode_REAL_NAME} PUBLIC + ${NODEJS_INCLUDE_DIRS} + ) endif() From 5c4169fde38417649d5ddc76b7df2666695354c8 Mon Sep 17 00:00:00 2001 From: Kitsu Date: Mon, 16 Apr 2018 15:10:49 +0300 Subject: [PATCH 032/110] Add custom genesis block generation (#1168) Signed-off-by: Kitsu --- iroha-cli/main.cpp | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index 1e6d7960f2..bc203e02df 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -16,6 +16,8 @@ */ #include +#include +#include #include #include #include @@ -56,6 +58,9 @@ DEFINE_string(json_query, "", "Query in json format"); DEFINE_bool(genesis_block, false, "Generate genesis block for new Iroha network"); +DEFINE_string(genesis_transaction, + "", + "File with transaction in json format for the genesis block"); DEFINE_string(peers_address, "", "File with peers address for new Iroha network"); @@ -76,19 +81,36 @@ int main(int argc, char *argv[]) { // Generate new genesis block now Iroha network if (FLAGS_genesis_block) { BlockGenerator generator; - - if (FLAGS_peers_address.empty()) { - logger->error("--peers_address is empty"); - return EXIT_FAILURE; + iroha::model::Transaction transaction; + if (FLAGS_genesis_transaction.empty()) { + if (FLAGS_peers_address.empty()) { + logger->error("--peers_address is empty"); + return EXIT_FAILURE; + } + std::ifstream file(FLAGS_peers_address); + std::vector peers_address; + std::copy(std::istream_iterator(file), + std::istream_iterator(), + std::back_inserter(peers_address)); + // Generate genesis block + transaction = TransactionGenerator().generateGenesisTransaction( + 0, std::move(peers_address)); + } else { + rapidjson::Document doc; + std::ifstream file(FLAGS_genesis_transaction); + rapidjson::IStreamWrapper isw(file); + doc.ParseStream(isw); + auto some_tx = JsonTransactionFactory{}.deserialize(doc); + if (some_tx) { + transaction = *some_tx; + } else { + logger->error( + "Cannot deserialize genesis transaction (problem with file reading " + "or illformed json?)"); + return EXIT_FAILURE; + } } - std::ifstream file(FLAGS_peers_address); - std::vector peers_address; - std::copy(std::istream_iterator(file), - std::istream_iterator(), - std::back_inserter(peers_address)); - // Generate genesis block - auto transaction = TransactionGenerator().generateGenesisTransaction( - 0, std::move(peers_address)); + auto block = generator.generateGenesisBlock(0, {transaction}); // Convert to json std::ofstream output_file("genesis.block"); From ab4bcbbdd40eca534d20f07c0cb4d38a38f035d3 Mon Sep 17 00:00:00 2001 From: Nikolay Yushkevich Date: Mon, 16 Apr 2018 15:30:15 +0300 Subject: [PATCH 033/110] Add details to description of Set Account Detail (#1234) Signed-off-by: Nikolay Yushkevich --- docs/source/api/commands.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/api/commands.rst b/docs/source/api/commands.rst index 7736cef7b4..094d73994e 100644 --- a/docs/source/api/commands.rst +++ b/docs/source/api/commands.rst @@ -462,6 +462,8 @@ Purpose Purpose of set account detail command is to set key-value information for a given account +.. warning:: If there was a value for a given key already in the storage then it will be replaced with the new value + Schema ^^^^^^ From ae2fd8c01a8b6431a4c0762cb20fecd5f9791a7f Mon Sep 17 00:00:00 2001 From: Nikolay Yushkevich Date: Mon, 16 Apr 2018 15:49:25 +0300 Subject: [PATCH 034/110] Change level of heading (#1235) Signed-off-by: Nikolay Yushkevich --- docs/source/api/queries.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/api/queries.rst b/docs/source/api/queries.rst index da3cb1e1c5..fd1a17f06b 100644 --- a/docs/source/api/queries.rst +++ b/docs/source/api/queries.rst @@ -300,7 +300,7 @@ Response Structure "Balance", "balance of the asset", "Not less than 0", "200.20" Get Asset Info --------------- +^^^^^^^^^^^^^^ Purpose ------- From f439255bda82a9992fa29aa67137c6f9aa26561e Mon Sep 17 00:00:00 2001 From: Bulat Nasrulin Date: Mon, 16 Apr 2018 21:46:59 +0800 Subject: [PATCH 035/110] Fix/ir 1122 (#1225) * Add test for invalid chain ending Signed-off-by: grimadas * Add chain ending check Signed-off-by: grimadas * Add comments, fix issues, apply clang Signed-off-by: grimadas * Add gwt comments Signed-off-by: grimadas --- .../synchronizer/impl/synchronizer_impl.cpp | 7 +- .../irohad/synchronizer/synchronizer_test.cpp | 85 ++++++++++++++++++- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/irohad/synchronizer/impl/synchronizer_impl.cpp b/irohad/synchronizer/impl/synchronizer_impl.cpp index 8a07f314b4..6134311656 100644 --- a/irohad/synchronizer/impl/synchronizer_impl.cpp +++ b/irohad/synchronizer/impl/synchronizer_impl.cpp @@ -85,7 +85,12 @@ namespace iroha { } auto chain = blockLoader_->retrieveBlocks( shared_model::crypto::PublicKey(signature->publicKey())); - if (validator_->validateChain(chain, *storage)) { + // Check chain last commit + auto is_chain_end_expected = + chain.as_blocking().last()->hash() == commit_message->hash(); + + if (validator_->validateChain(chain, *storage) + and is_chain_end_expected) { // Peer send valid chain mutableFactory_->commit(std::move(storage)); notifier_.get_subscriber().on_next(chain); diff --git a/test/module/irohad/synchronizer/synchronizer_test.cpp b/test/module/irohad/synchronizer/synchronizer_test.cpp index 2b05ccffaf..dd40b31410 100644 --- a/test/module/irohad/synchronizer/synchronizer_test.cpp +++ b/test/module/irohad/synchronizer/synchronizer_test.cpp @@ -88,8 +88,13 @@ TEST_F(SynchronizerTest, ValidWhenInitialized) { init(); } + +/** + * @given A commit from consensus and initialized components + * @when a valid block that can be applied + * @then Successful commit + */ TEST_F(SynchronizerTest, ValidWhenSingleCommitSynchronized) { - // commit from consensus => chain validation passed => commit successful auto block = TestBlockBuilder().height(5).build(); std::shared_ptr test_block = std::make_shared(std::move(block)); @@ -127,8 +132,12 @@ TEST_F(SynchronizerTest, ValidWhenSingleCommitSynchronized) { ASSERT_TRUE(wrapper.validate()); } +/** + * @given A commit from consensus and initialized components + * @when Storage cannot be initialized + * @then No commit should be passed + */ TEST_F(SynchronizerTest, ValidWhenBadStorage) { - // commit from consensus => storage not created => no commit std::shared_ptr test_block = std::make_shared(TestBlockBuilder().build()); @@ -157,8 +166,12 @@ TEST_F(SynchronizerTest, ValidWhenBadStorage) { ASSERT_TRUE(wrapper.validate()); } -TEST_F(SynchronizerTest, ValidWhenBlockValidationFailure) { - // commit from consensus => chain validation failed => commit successful +/** + * @given A commit from consensus and initialized components + * @when A valid chain with expected ending + * @then Successful commit + */ +TEST_F(SynchronizerTest, ValidWhenValidChain) { TemplateMockBlockValidator mockBlockValidator; EXPECT_CALL(*mockBlockValidator.validator, validate(_)) .WillOnce(Return(shared_model::validation::Answer())); @@ -211,3 +224,67 @@ TEST_F(SynchronizerTest, ValidWhenBlockValidationFailure) { ASSERT_TRUE(wrapper.validate()); } + +/** + * @given A commit from consensus and initialized components + * @when A valid chain with unexpected ending + * @then No commit should be passed + */ +TEST_F(SynchronizerTest, InvalidWhenUnexpectedEnd) { + TemplateMockBlockValidator mockBlockValidator; + EXPECT_CALL(*mockBlockValidator.validator, validate(_)) + .WillRepeatedly(Return(shared_model::validation::Answer())); + using TestUnsignedBlockBuilder = shared_model::proto::TemplateBlockBuilder< + (1 << shared_model::proto::TemplateBlockBuilder<>::total) - 1, + TemplateMockBlockValidator, + shared_model::proto::UnsignedWrapper>; + + auto block = TestUnsignedBlockBuilder(mockBlockValidator) + .height(5) + .build() + .signAndAddSignature( + shared_model::crypto::DefaultCryptoAlgorithmType:: + generateKeypair()); + std::shared_ptr test_block = + std::make_shared(std::move(block)); + + DefaultValue, std::string>>:: + SetFactory(&createMockMutableStorage); + EXPECT_CALL(*mutable_factory, createMutableStorage()).Times(2); + + EXPECT_CALL(*mutable_factory, commit_(_)).Times(0); + + EXPECT_CALL(*chain_validator, validateBlock(testing::Ref(*test_block), _)) + .WillOnce(Return(false)); + + EXPECT_CALL(*chain_validator, validateChain(_, _)).WillOnce(Return(true)); + + // wrong block has different hash + auto wrong_block_end = + TestUnsignedBlockBuilder(mockBlockValidator) + .height(5) + .createdTime(iroha::time::now()) + .build() + .signAndAddSignature( + shared_model::crypto::DefaultCryptoAlgorithmType:: + generateKeypair()); + std::shared_ptr wrong_test_block = + std::make_shared(std::move(wrong_block_end)); + + EXPECT_CALL(*block_loader, retrieveBlocks(_)) + .WillOnce(Return(rxcpp::observable<>::just(wrong_test_block))); + + EXPECT_CALL(*consensus_gate, on_commit()) + .WillOnce(Return(rxcpp::observable<>::empty< + std::shared_ptr>())); + + init(); + + auto wrapper = + make_test_subscriber(synchronizer->on_commit_chain(), 0); + wrapper.subscribe(); + + synchronizer->process_commit(test_block); + + ASSERT_TRUE(wrapper.validate()); +} From 88e7bd378802520fd5cd0281d86c08ee58860eb2 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bikbaev Date: Mon, 16 Apr 2018 17:41:46 +0300 Subject: [PATCH 036/110] Fix of licenses (#1184) * feat: mentioning CC-BY-4.0 license of docs Signed-off-by: Vyacheslav Bikbaev * fix: license in readme Signed-off-by: Vyacheslav Bikbaev * fix: correct copyright value Signed-off-by: Vyacheslav Bikbaev * fix: typo Signed-off-by: Vyacheslav Bikbaev --- README.md | 13 ++++++++----- docs/source/conf.py | 6 +++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dfc86e12b5..e7ba224bc9 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,17 @@ For more information, such as how to use client libraries in your target program Copyright 2016 – 2018 Soramitsu Co., Ltd. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +Iroha codebase is licensed under the Apache License, +Version 2.0 (the "License"); you may not use this file except +in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +Iroha documentation files are made available under the Creative Commons +Attribution 4.0 International License (CC-BY-4.0), available at +http://creativecommons.org/licenses/by/4.0/ \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index d2b982d7e6..741f702a2d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -52,9 +52,9 @@ # General information about the project. project = u'Iroha' documentation = u'Iroha Documentation' -description = u'Distributed ledger technology platworm, written in C++' -copyright = u'Creative Commons Attribution-NonCommercial 3.0 Unported' -author = u'Nikolay Yushkevich at Soramitsu Co Ltd' +description = u'Distributed ledger technology platform, written in C++' +copyright = u'2018 Soramitsu Co., Ltd.' +author = u'Nikolay Yushkevich at Soramitsu Co., Ltd.' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From bc4a0b515ba8059315a0d4f3cafc8ec5444e93a5 Mon Sep 17 00:00:00 2001 From: Moonraker Date: Tue, 17 Apr 2018 14:47:16 +0700 Subject: [PATCH 037/110] add transaction creator check #1209 Signed-off-by: Moonraker --- irohad/model/impl/query_execution.cpp | 16 ++++++++++------ irohad/model/query_execution.hpp | 3 ++- .../acceptance/get_transactions_test.cpp | 3 +-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/irohad/model/impl/query_execution.cpp b/irohad/model/impl/query_execution.cpp index cd68b41f35..e623cfa666 100644 --- a/irohad/model/impl/query_execution.cpp +++ b/irohad/model/impl/query_execution.cpp @@ -314,17 +314,21 @@ QueryProcessingFactory::executeGetAccountTransactions( QueryProcessingFactory::QueryResponseBuilderDone iroha::model::QueryProcessingFactory::executeGetTransactions( - const shared_model::interface::GetTransactions &query) { - const std::vector &hashes = - query.transactionHashes(); + const shared_model::interface::GetTransactions &q, + const shared_model::interface::types::AccountIdType &accountId) { + const std::vector &hashes = q.transactionHashes(); auto transactions = _blockQuery->getTransactions(hashes); std::vector txs; + bool can_get_all = + checkAccountRolePermission(accountId, *_wsvQuery, can_get_all_txs); transactions.subscribe([&](const auto &tx) { if (tx) { - txs.push_back( - *std::static_pointer_cast(*tx)); + auto proto_tx = + *std::static_pointer_cast(*tx); + if (can_get_all or proto_tx.creatorAccountId() == accountId) + txs.push_back(proto_tx); } }); @@ -378,7 +382,7 @@ QueryProcessingFactory::execute(const shared_model::interface::Query &query) { if (not validate(query, *q)) { builder = statefulFailed(); } else { - builder = executeGetTransactions(*q); + builder = executeGetTransactions(*q, query.creatorAccountId()); } return clone(builder.queryHash(query_hash).build()); }, diff --git a/irohad/model/query_execution.hpp b/irohad/model/query_execution.hpp index 7953d4be59..1801aec757 100644 --- a/irohad/model/query_execution.hpp +++ b/irohad/model/query_execution.hpp @@ -125,7 +125,8 @@ namespace iroha { const shared_model::interface::GetAccountTransactions &query); QueryResponseBuilderDone executeGetTransactions( - const shared_model::interface::GetTransactions &query); + const shared_model::interface::GetTransactions &q, + const shared_model::interface::types::AccountIdType &accountId); std::shared_ptr _wsvQuery; std::shared_ptr _blockQuery; diff --git a/test/integration/acceptance/get_transactions_test.cpp b/test/integration/acceptance/get_transactions_test.cpp index 4efade0235..86545af38d 100644 --- a/test/integration/acceptance/get_transactions_test.cpp +++ b/test/integration/acceptance/get_transactions_test.cpp @@ -218,9 +218,8 @@ TEST_F(GetTransactions, InexistentHash) { * @given some user with can_get_my_txs * @when query GetTransactions of existing transaction of the other user * @then TransactionsResponse with no transactions - * TODO(@l4l) 02/01/18 Should be enabled after resolving IR-1039 */ -TEST_F(GetTransactions, DISABLED_OtherUserTx) { +TEST_F(GetTransactions, OtherUserTx) { auto check = [](auto &status) { auto resp = boost::apply_visitor( interface::SpecifiedVisitor(), From 694b54846eb643769ff679490c00cce527544c56 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bikbaev Date: Tue, 17 Apr 2018 17:30:16 +0300 Subject: [PATCH 038/110] fix: docker image in getting started guide (#1244) Signed-off-by: Vyacheslav Bikbaev --- docs/source/getting_started/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index 627eb9ef18..86d5751497 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -103,7 +103,7 @@ command -v blockstore:/tmp/block_store \ --network=iroha-network \ --entrypoint=/bin/bash \ - hyperledger/iroha-docker:develop + hyperledger/iroha:x86_64-develop-latest Let's look in detail what this command does: @@ -116,10 +116,10 @@ Let's look in detail what this command does: the container - ``--network=iroha-network \`` adds our container to previously created ``iroha-network``, so Iroha and Postgres could see each other. -- ``--entrypoint=/bin/bash \`` Because ``hyperledger/iroha-docker`` has +- ``--entrypoint=/bin/bash \`` Because ``hyperledger/iroha`` has the custom script which runs after starting the container, we want to override it so we can start Iroha Daemon manually. -- ``hyperledger/iroha-docker:develop`` is the image which has the ``develop`` +- ``hyperledger/iroha:x86_64-develop-latest`` is the image which has the ``develop`` branch. Launching Iroha Daemon From 803fe831f359184e6c1598b00f6bf6efa3f2cbaf Mon Sep 17 00:00:00 2001 From: Dumitru Date: Tue, 17 Apr 2018 18:12:15 +0300 Subject: [PATCH 039/110] Add default hash provider (#1213) * Add default hash provider Signed-off-by: Dumitru * Remove unused import Signed-off-by: Dumitru * Remove using from Signable Signed-off-by: Dumitru * Improve codestyle Signed-off-by: Dumitru --- irohad/torii/impl/command_service.cpp | 7 +++-- irohad/torii/impl/query_service.cpp | 7 +++-- .../cryptography/default_hash_provider.hpp | 30 +++++++++++++++++++ shared_model/interfaces/base/signable.hpp | 9 +++--- 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 shared_model/cryptography/default_hash_provider.hpp diff --git a/irohad/torii/impl/command_service.cpp b/irohad/torii/impl/command_service.cpp index d2369c7d40..c12418d189 100644 --- a/irohad/torii/impl/command_service.cpp +++ b/irohad/torii/impl/command_service.cpp @@ -16,6 +16,7 @@ */ #include + #include "backend/protobuf/transaction_responses/proto_tx_response.hpp" #include "ametsuchi/block_query.hpp" @@ -24,6 +25,7 @@ #include "builders/protobuf/transport_builder.hpp" #include "common/byteutils.hpp" #include "common/types.hpp" +#include "cryptography/default_hash_provider.hpp" #include "endpoint.pb.h" #include "torii/command_service.hpp" #include "validators/default_validator.hpp" @@ -100,9 +102,8 @@ namespace torii { // getting hash from invalid transaction auto blobPayload = shared_model::proto::makeBlob(request.payload()); - tx_hash = - shared_model::proto::Transaction::HashProviderType::makeHash( - blobPayload); + tx_hash = shared_model::crypto::DefaultHashProvider::makeHash( + blobPayload); log_->warn("Stateless invalid tx: {}, hash: {}", error.error, tx_hash.hex()); diff --git a/irohad/torii/impl/query_service.cpp b/irohad/torii/impl/query_service.cpp index e67a7e6a58..6d3c0f9245 100644 --- a/irohad/torii/impl/query_service.cpp +++ b/irohad/torii/impl/query_service.cpp @@ -17,6 +17,7 @@ #include "torii/query_service.hpp" #include "backend/protobuf/query_responses/proto_query_response.hpp" +#include "cryptography/default_hash_provider.hpp" #include "validators/default_validator.hpp" namespace torii { @@ -41,7 +42,7 @@ namespace torii { iroha::protocol::QueryResponse &response) { shared_model::crypto::Hash hash; auto blobPayload = shared_model::proto::makeBlob(request.payload()); - hash = shared_model::proto::Query::HashProviderType::makeHash(blobPayload); + hash = shared_model::crypto::DefaultHashProvider::makeHash(blobPayload); if (cache_.findItem(hash)) { // Query was already processed @@ -70,8 +71,8 @@ namespace torii { cache_.addItem(hash, response); } }, - [&hash, &response]( - const iroha::expected::Error &error) { + [&hash, + &response](const iroha::expected::Error &error) { response.set_query_hash( shared_model::crypto::toBinaryString(hash)); response.mutable_error_response()->set_reason( diff --git a/shared_model/cryptography/default_hash_provider.hpp b/shared_model/cryptography/default_hash_provider.hpp new file mode 100644 index 0000000000..ce07b4b574 --- /dev/null +++ b/shared_model/cryptography/default_hash_provider.hpp @@ -0,0 +1,30 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IROHA_DEFAULT_HASH_PROVIDER_HPP +#define IROHA_DEFAULT_HASH_PROVIDER_HPP + +#include "cryptography/hash_providers/sha3_256.hpp" + +namespace shared_model { + namespace crypto { + // Default class that provides hashing functionality + using DefaultHashProvider = shared_model::crypto::Sha3_256; + } // namespace crypto +} // namespace shared_model + +#endif // IROHA_DEFAULT_HASH_PROVIDER_HPP diff --git a/shared_model/interfaces/base/signable.hpp b/shared_model/interfaces/base/signable.hpp index f65164f11a..4eda8dd900 100644 --- a/shared_model/interfaces/base/signable.hpp +++ b/shared_model/interfaces/base/signable.hpp @@ -20,7 +20,7 @@ #include -#include "cryptography/hash_providers/sha3_256.hpp" +#include "cryptography/default_hash_provider.hpp" #include "interfaces/common_objects/signable_hash.hpp" #include "interfaces/common_objects/signature.hpp" #include "interfaces/common_objects/types.hpp" @@ -48,16 +48,15 @@ namespace shared_model { #ifndef DISABLE_BACKWARD template + typename HashProvider = crypto::DefaultHashProvider> class Signable : public Primitive { #else template class Signable : public ModelPrimitive { #endif - public: - using HashProviderType = HashProvider; + public: /** * @return attached signatures */ @@ -105,7 +104,7 @@ namespace shared_model { const types::HashType &hash() const { if (hash_ == boost::none) { - hash_.emplace(HashProviderType::makeHash(payload())); + hash_.emplace(HashProvider::makeHash(payload())); } return *hash_; } From eb68ba768eb7e74fc7c9e052938a8a784fe16034 Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Tue, 17 Apr 2018 18:40:09 +0300 Subject: [PATCH 040/110] Fix tests after heavy tx PR (#1219) * Fix tests after heavy tx PR Also * rework assert in acceptance test * add docs for field_validator_test --- test/integration/acceptance/tx_heavy_data.cpp | 11 +++++++---- .../shared_model/validators/field_validator_test.cpp | 10 ++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/test/integration/acceptance/tx_heavy_data.cpp b/test/integration/acceptance/tx_heavy_data.cpp index 93e6d09ce4..9a3afdee8b 100644 --- a/test/integration/acceptance/tx_heavy_data.cpp +++ b/test/integration/acceptance/tx_heavy_data.cpp @@ -125,10 +125,13 @@ TEST_F(HeavyTransactionTest, OneLargeTx) { [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) // "foo" transactions will not be passed because it has large size into // one field - 5Mb per one set - .sendTx(complete(setAcountDetailTx("foo", generateData(5 * 1024 * 1024)))) - .skipProposal() - .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) + .sendTx(complete(setAcountDetailTx("foo", generateData(5 * 1024 * 1024))), + [](const auto &status) { + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::SpecifiedVisitor< + shared_model::interface::StatelessFailedTxResponse>(), + status.get())); + }) .done(); } diff --git a/test/module/shared_model/validators/field_validator_test.cpp b/test/module/shared_model/validators/field_validator_test.cpp index 57e9df9ed3..201c5de0db 100644 --- a/test/module/shared_model/validators/field_validator_test.cpp +++ b/test/module/shared_model/validators/field_validator_test.cpp @@ -495,10 +495,12 @@ class FieldValidatorTest : public ValidatorsTest { makeValidCase(&FieldValidatorTest::detail_value, "valid value"), makeValidCase(&FieldValidatorTest::detail_value, std::string(4096, '0')), makeValidCase(&FieldValidatorTest::detail_value, ""), - makeInvalidCase("long_value", - "value", - &FieldValidatorTest::detail_value, - std::string(4097, '0'))}; + makeInvalidCase( + "long_value", + "value", + &FieldValidatorTest::detail_value, + // 5 Mb, value greater than can put into one setAccountDetail + std::string(5 * 1024 * 1024, '0'))}; std::vector description_test_cases{ makeValidCase(&FieldValidatorTest::description, "valid description"), From d0f1894bbf0b5145be4c3ba1deb3c0961eb4662d Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Tue, 17 Apr 2018 19:39:45 +0300 Subject: [PATCH 041/110] Fix/on absent genesis block (#1240) * Add failure for irohad when blocks in ledger don't exist * Add logger in itf::config_helper and remove redundant include. Signed-off-by: Fedor Muratov --- irohad/main/irohad.cpp | 11 +++++++++++ test/framework/CMakeLists.txt | 3 +++ test/framework/config_helper.cpp | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/irohad/main/irohad.cpp b/irohad/main/irohad.cpp index a93b7f9c7b..8471becae7 100644 --- a/irohad/main/irohad.cpp +++ b/irohad/main/irohad.cpp @@ -154,6 +154,17 @@ int main(int argc, char *argv[]) { block.value()->transactions().size()); } + // check if at least one block is available in the ledger + auto blocks_exist = false; + irohad.storage->getBlockQuery()->getTopBlocks(1).subscribe( + [&blocks_exist](auto block) { blocks_exist = true; }); + + if (not blocks_exist) { + log->error( + "There are no blocks in the ledger. Use --genesis_block parameter."); + return EXIT_FAILURE; + } + // init pipeline components irohad.init(); diff --git a/test/framework/CMakeLists.txt b/test/framework/CMakeLists.txt index aa55bdd915..4212071a0c 100644 --- a/test/framework/CMakeLists.txt +++ b/test/framework/CMakeLists.txt @@ -32,4 +32,7 @@ target_link_libraries(integration_framework target_include_directories(integration_framework PUBLIC ${PROJECT_SOURCE_DIR}/test) add_library(integration_framework_config_helper config_helper.cpp) +target_link_libraries(integration_framework_config_helper + logger + ) target_include_directories(integration_framework_config_helper PUBLIC ${PROJECT_SOURCE_DIR}/test) diff --git a/test/framework/config_helper.cpp b/test/framework/config_helper.cpp index 6d4be64578..0f8596f696 100644 --- a/test/framework/config_helper.cpp +++ b/test/framework/config_helper.cpp @@ -17,8 +17,8 @@ #include "framework/config_helper.hpp" -#include #include +#include "logger/logger.hpp" namespace integration_framework { std::string getPostgresCredsOrDefault(const std::string &default_conn) { @@ -32,6 +32,7 @@ namespace integration_framework { std::stringstream ss; ss << "host=" << pg_host << " port=" << pg_port << " user=" << pg_user << " password=" << pg_pass; + logger::log("ITF")->info("Postgres credentials: {}", ss.str()); return ss.str(); } } From 491338aa3d8ec64cfd269de7557f9df1653d32a5 Mon Sep 17 00:00:00 2001 From: DenDoronin Date: Wed, 18 Apr 2018 01:00:49 +0300 Subject: [PATCH 042/110] iOS Swift installation guide (#1236) Signed-off-by: DenDoronin --- .../iroha_swift_guide_001.png | Bin 0 -> 149588 bytes .../iroha_swift_guide_002.png | Bin 0 -> 553900 bytes .../iroha_swift_guide_003.png | Bin 0 -> 269070 bytes .../iroha_swift_guide_004.png | Bin 0 -> 200130 bytes .../iroha_swift_guide_005.png | Bin 0 -> 35190 bytes .../iroha_swift_guide_007.png | Bin 0 -> 140251 bytes .../iroha_swift_guide_008.png | Bin 0 -> 475144 bytes docs/source/guides/libraries.rst | 3 +- docs/source/guides/libraries/swift_ios.rst | 230 ++++++++++++++++++ .../packages/ios/iroha-preparation.sh | 41 ++++ 10 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_001.png create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_002.png create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_003.png create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_004.png create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_005.png create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_007.png create mode 100644 docs/image_assets/iroha_swift_guide/iroha_swift_guide_008.png create mode 100644 docs/source/guides/libraries/swift_ios.rst create mode 100755 shared_model/packages/ios/iroha-preparation.sh diff --git a/docs/image_assets/iroha_swift_guide/iroha_swift_guide_001.png b/docs/image_assets/iroha_swift_guide/iroha_swift_guide_001.png new file mode 100644 index 0000000000000000000000000000000000000000..54ba9316ebc1bd03df8c4b77289916f81afe65d2 GIT binary patch literal 149588 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 dF;;#v1oDk~ip+|6ohdln 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�_`Q(aa}*GR0SAhX}undYMeC_^vY(7B) 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 z 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 #h1#5)j`>Y8g>$R#6DR$ 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Ϧi!<`Hr4#mejgf1l~1AX}h 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 literal 0 HcmV?d00001 diff --git a/docs/image_assets/iroha_swift_guide/iroha_swift_guide_002.png b/docs/image_assets/iroha_swift_guide/iroha_swift_guide_002.png new file mode 100644 index 0000000000000000000000000000000000000000..0110bda65e65758cbe6daf64af970df08bce4371 GIT binary patch literal 553900 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%0A{#h19$&CMV?fPIq-e$Djk5Z3iQxd%7#-b?y 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

hs5 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

NU< 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

{R5TA`FTiF=hMA8LER4w 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

|c`@SXuL;=@mu+ zfnp1=HQGZ776QvEDk9Cz%{zpYB#ey>+;EjPHa39r8L}n=TL%a93uu9lZF+Myf^*!` z#%+H_Tejn`!{;AF-{r%}-8|OSQ}=2(5cH5X?pWzV z`hL`c18ISD^<3znrii%XlfS#f_JN{ZJ{4mMux zGB>xficSQjoT_QX?*!R@brno3^$^slF>rE6^5tHVA;X?67Kry05OrrGif3re`XCo`u7?`a;&$$esQRheklUQdoM4oM_7^XRl_C0Q|{FfW=E+>-+u>245&i literal 0 HcmV?d00001 diff --git a/docs/image_assets/iroha_swift_guide/iroha_swift_guide_003.png b/docs/image_assets/iroha_swift_guide/iroha_swift_guide_003.png new file mode 100644 index 0000000000000000000000000000000000000000..a1fe925e9bba19c36f28f02e97b8b6e308fbcc52 GIT binary patch literal 269070 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%0Dr1c;6-8EGUfH(QTPTrYY^yAF2gcs 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

C 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

8%n@o5#*WSUnO#RC|sC4MI`YA2HUHH4T zF+PiIHd)rBLT1G!M#}Z46YV9=dX3MSrDp?fvsHIuqb+XHe=QrYge%(kq#(%(Ryhse zzyA6Qb?VfK*@B^vv4w2+?%l}C%fq^L>x5OUu&_{5%7_Eg@j+x>cgeVqF&pzyXy)VH znh!?Roy70>GShk8932Y-TQ6KSR%V9D_+D1`8&S>Vx8A<^!p9ji@fp}Dj8PWN_Zn|e z3K^3KNCZ-ifI<^o*HA{T-F3$ZN;}#MW!^Kkh`cUtBNyfk8ab~C5K#3{hd5>er@YZ7CpIK6tWNmFef7;KEyv7tttB$$f7c`7BwoL@Z%kwrm-V?~F)3)3D;kma)2Z>!M!0df2&hr=VrUE)v*U#)_FORP5f_ zn3pSX&l9BVrhj;Z$T=t?Uy-4TfUG|*n$K~*H%m&?8Fn7Q0yph-i; zn{<5nV+xo+AuCQ{8sMyW8KG;}u0~W`c^RUiVDXhdtd#N6#SR@hVCmAOLMdz7w5f#; z(}}u*OESQ)h-FFeeF-`uEDUN}f^UcQ-Qj^RQ2HJQl`LlJ z>(A1@o`q2wjx``Jc}JaO&8w;u^)+)6%xT9RV~YuZxQpLjCw{ zfDYES1Ufi7bnX?FEOSCRVFY=uoDt2UL!!+=IsPB!q$OTu7#qhMn50p^_yFOK`$J(1 zXooIP+VWD*Dhl2E0`GiiX7D`-w|Xawf%XX03B)ScUDLf%l5 zkDY(q`6R-p(fLlsk~}VYJs$s%)A1|JXfqe(hh zS}fuF1yJb|D=3#-1LW(NxDYCb9tG5=J$E~351u{n5d`hK*mI-lD#BPSS>@m7O^cpb z5mj%#N!SdPD=vpJrs@>3(8*__{LL4vhkkD*FN(L{LGs-Z#m^aG;{j0anFJKnanQPEG^~TrqfbIP@i;gYlp4bxWtmBXucS2;;X`f3zaz1oT}()Nu)Z ziPl(rNm5)9%ZzwWz~SuMpFWY@phf)oz+VP5@dv_q$AybQg)9CFvgyv(_(P(?1F2ik zw90DK0cLPq(agwq>j3K^ZGjcKF-6gf#bXJR06*7sH^SE{WUxxux@nDLT?FZO;xdh% z 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˭A&GuRmY=R9%!w7cwXo$0W1w z_9SYH-L>y*+))-vZYC81{pwtLReQ!)g(l56#a+_}>#&#QfOU@B`TmD?TX>-qqa8?& zX_82f)sPyLg}yex_$yJN_2ts}ey)M+`l_4VBkfWyk7L!cQ2|4D%6__L-P=4RST+Ku(r zT$LRBQ*22WM+%ZyB-~#orHKV$@6&AOiKLmG&G~IpFba>SS!nk2+IdWEHkO*%S`)FV z!(B7qF4c+xDT{V#?c=1F`FGu8E%ZC)>zDUHT|{85b}Z ztBi}q3@7(QsqSmvA`w(cu6}oVX7^rS^eGrelOyD12QoeQ4>CSv=rtTAM9zo$t#E|x ztZrvi-d@1nnST)wj^`JDu8uMzNB^;zXx*&;llCTBFPc?aGN^nIhkD$SbpLOD25v_L zd3(N=aVVJ~+svL$H!1MO3r^QR-2xx*x*m^daM$l`oOsf{evlFII);3cWr0*u0nsJwm)HH85o)t&X)h-FU>XR8_sY(Ep&AdKL#s6Z$Zu%8 zC?#W#kRt|2?~i#UA%Z|H$xahVotA_nvYPL}yV$f_Q6`Ko{rO;gJldnB^3wJ|1wAox z_sDyLYR_?Yz+QzlE3TFAXjEkmNI`K?h4lV~uxT|(MpaU!nO!g?eGIvzW1=L6{y`_d z(P@lnk1A3#@XS4zq!VwcE0I$t0FLbIr755y@iIW_G`h)j96J~^fT_1itq>>mS7alv z_m}lantK{*>LP3M^8)ie76qCb?xm=6q5Nb}DBTtZS)!x8rAo6Iwv^0bc&V2z3cQ}6 zL*E;J9jG2f9I;g6C|H{SHg(n*=aFG+Tp9||{9_yw#{@nizu`F_lxOO5gW z`k)(SfMwPd266Yfq&3BGm5oi-TFRI<9JcvD8g;2Tq4JlXD4kvmPQ}?fO18hGUpM;u zoRGZgHnJH}!jf8+a;tI_Yl-&ji%Jp1)yFr0159>cQ{>_Lq*p-9Cl2G5^+i5%+Fx%C506SsJA%eUjz%Ge^Z(7 z!wo#kCkXr0!=4;8WvWu8e8Pfi!ME9KYyC>?@OBv4-{<741BanICwTcN23!Oo?J~axgCtkl%pTm#Qf(ciGGQ3f(7md&C4%9QA%4nw#9t=Sd~opSkI8(fUbr3Wqj zRcZi)vDsi3<5B^(D-$1_IkDotZBRcPgw1Dv@r$6Pu2GLgJD+JKeNEeZ_Bp!N;nm}L zw7Kc3Emc*=rCn3$=hk@#=>D3#!oS7_E^QYcdKP8|W&_e?Q*&}^*cVD!^l)({ezut3 zjxb^E6xj9P7KmL->f!kRk=}vCyK%5)McfWj*wUQ2bCPEl%8sWW=mv|^n@eSy(biDq zl*&SqZ}O5fiIoi-{+UW@2|y9+(4eN|?@V zp0?rWkeWyk9+F8kOtTw(kFvNw}#9WUWgXAasXPbvTfCPDRkL!WL2D zE7-xf+3NibnHYjOgbE$?!YiGePF{{N?aj=~D9Tg+m0XK&dTSHvS}cN%%o{Db%-@A6 z^RHBe_b1hnM@-0)EcyeP?1Aq# z-j3Km$?nrw#Dgv%B6ha6TCGu8l&DDYR=DSV%uYNl!qn+dN&duif?DF>0AI`YMbuf& zxiH>*SMWz$N%_P$t8ZhgMKb4~SJ6Ud_BjeV2l1)Pxqec5fB{>T@sZbBssC z@`+Xdmp#V+!4bK{ZRC1u*4HVB=WnqEEouJ{BR^w#k6JS!v5hnfwZ32DUhOFCD~~Vu z9NsMVYA4Ty6w|I$L=#i|2dy#w*}ICkk>lpF)|kUdK)q;B&A%`+fbS; zOVfaXHlj^wZL5kHhTJgJzgsFD<~^qHyeOG8(|_63|M}Bs4<2~a1&&}j!~X=^f6eO; yzcn7}hg`qkrz`cBzxqpn|Kn{S{n>%tZyywo>vQu7^WENo|0Km^MXQDN1O7iQ&~-Kd literal 0 HcmV?d00001 diff --git a/docs/image_assets/iroha_swift_guide/iroha_swift_guide_004.png b/docs/image_assets/iroha_swift_guide/iroha_swift_guide_004.png new file mode 100644 index 0000000000000000000000000000000000000000..1bc7aba4a427299d7d72770b36ff236f642b7a13 GIT binary patch literal 200130 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%0D`rO%iaY4 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
  • Yy*$VJe+N=GyzZ1gb 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
    ZEX-cm>yxNnVI}WP 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

    drL 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

    E0EwzA0&UK=&Gfx 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 + +Prerequisites +^^^^^^^^^^^^^ + +Before starting you need to install the following software on your mac: + +- XCode +- Carthage +- Git +- Cmake +- Postgresql + +This tutorial was tested with the following environment: + +- MacOS Sierra 10.12.6 +- Xcode 9.2 +- carthage 0.29.0 +- cmake 3.11.0 +- iPhone 7 iOS 11.2 Simulator +  +Hyperledger Iroha iOS library +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Iroha has the following features: + +1. Creation and management of custom complex assets, such as currencies or indivisible rights, serial numbers, patents, etc. +2. Management of user accounts +3. Taxonomy of accounts based on domains — or sub-ledgers in the system +4. The system of rights and verification of user permissions for the execution of transactions and queries in the system +5. Validation of business rules for transactions and queries in the system + +Among the non-functional requirements can be noted a high degree of network fault tolerance (Byzantine Fault Tolerant). +Iroha iOS library gives the ability to provide key generation and signing logic for queries and transactions passed to Iroha blockchain. +Let's start with the detailed instructions how to install Iroha on the local machine. + + +  +Instruction +^^^^^^^^^^^ + +1. Open the terminal and go to the folder where you want to install all artifacts: + + .. code-block:: bash + + cd path/to/your/folder/for/example/iroha-ios/project/ + +2. Clone the repository for the iOS client: + + .. code-block:: bash + + git clone https://github.com/hyperledger/iroha-ios.git + +3. Go to the Iroha-ios folder: + + .. code-block:: bash + + cd iroha-ios/ + +4. Update dependencies: + + .. code-block:: bash + + carthage update --platform iOS + +5. Go to sample project directory: + + .. code-block:: bash + + cd SwiftyIrohaExample + +6. Update dependencies for the sample: + + .. code-block:: bash + + carthage update --platform iOS + +7. Go to GRPC library source's location: + + .. code-block:: bash + + cd grpc-swift/ + +8. Remove old library sources: + +.. note:: Make sure you are located in ``grpc-swift/`` subfolder + + .. code-block:: bash + + # removes all files from the current directory + rm -rf ./* + # removes all hidden files too (so clean build can be done) + rm -rf ./.* +  +9. Download release version of GRCP from git to the current directory: + + .. code-block:: bash + + git clone --branch 0.3.3 https://github.com/grpc/grpc-swift.git . + +10. Build library: + + .. code-block:: bash + + make + +11. Go to the root of your playground folder (from the first step - path/to/your/folder/for/example/iroha-ios/project/): + + .. code-block:: bash + + cd ../../.. + +.. note:: Make sure now you are located in ``path/to/your/folder/for/example/iroha-ios/project/`` folder + +12. This step downloads script for client library which is needed to build client library. Clone it from the repository: + + .. code-block:: bash + + curl https://raw.githubusercontent.com/hyperledger/iroha/master/shared_model/packages/ios/ios-build.sh > ios-build.sh + +13. Optional step. If you have issues with cloning during ios-build.sh execution do the following command before the script invocation: + + .. code-block:: bash + + sed -i '' 's|git://github.com/hyperledger/iroha-ed25519|https://github.com/hyperledger/iroha-ed25519.git|g' ios-build.sh + +14. Make downloaded script executable: + + .. code-block:: bash + + chmod +x ios-build.sh + +15. Finally, build the client iOS library with proper options - platform: OS | SIMULATOR | SIMULATOR64; build: Debug | Release : + + .. code-block:: bash + + ./ios-build.sh SIMULATOR64 Debug + +16. The generated artifacts should be copied to the proper location (let's create it first): + + .. code-block:: bash + + # this command shows location for simulator artifacts + # use this command for device instead: + # mkdir -p iroha-ios/libs/iOS/ + mkdir -p iroha-ios/libs/Simulator/ +  +17. Copy generated binaries: + + .. code-block:: bash + + # this command shows location for simulator artifacts + # use this command for device instead: + # cp lib/* iroha-ios/libs/iOS/ + cp lib/* iroha-ios/libs/Simulator/ + +18. Do not forget to copy generated headers: + + .. code-block:: bash + + cp -a include/. iroha-ios/headers/ + +19. Now it's time to manually config Xcode project for the sample application. Open SwiftyIroha.xcodeproj: + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_001.png +  +20. Select SwiftyIrohaExample.xcodeproj general tab and link SwiftProtobuf framework from iroha-ios/SwiftProtobuf.framework location + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_002.png + +21. Select SwiftGRPC.xcodeproj project and remove zlib-example target from it: + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_003.png +  +22. Go to Proto group and remove it (In future this step will be removed, but for now it's needed for sample app to be built): + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_004.png + +23. Congratulations! We are done. Select SwiftyIrohaExample target, choose iPhone simulator device and build the application to make sure we have done everything correctly: + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_005.png + +Before we launch the application and test it we should deploy Iroha peer on our local machine and launch it. + +There is good news - steps 1-18 should not be done manually every time - here is the script which does it automatically. + +The script for iOS client installation and setup +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All you need now is to download `build script `__ +``iroha-preparation.sh`` and launch it from ``path/to/your/folder/for/example/iroha-ios/project/``. + +Starting Iroha Node +^^^^^^^^^^^^^^^^^^^ + +To run this example, you need an Iroha node up and running. Please check out +:ref:`getting-started` if you want to learn how to start it. + +Launching Iroha iOS sample +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now it's time to switch back to SwiftyIrohaSample application and launch it on the simulator. Open Xcode project, select proper sample target and run. +The sample will send test transaction to our node and query the result from blockchain. Successful operations will look similar to this Xcode console output: + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_007.png + +The output from Iroha terminal window (where the node is running): + +.. image:: https://github.com/hyperledger/iroha/raw/develop/docs/image_assets/iroha_swift_guide/iroha_swift_guide_008.png + +Great! We have sent our transaction and verified its presence in blockchain. diff --git a/shared_model/packages/ios/iroha-preparation.sh b/shared_model/packages/ios/iroha-preparation.sh new file mode 100755 index 0000000000..03a74e3e27 --- /dev/null +++ b/shared_model/packages/ios/iroha-preparation.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# download ios client and update dependencies +git clone https://github.com/hyperledger/iroha-ios.git +cd iroha-ios/ +carthage update --platform iOS +cd SwiftyIrohaExample +carthage update --platform iOS + +# build grpc client for sample application +cd grpc-swift/ +rm -rf ./* +rm -rf ./.* +git clone --branch 0.3.3 https://github.com/grpc/grpc-swift.git . +make + +# back to the root where script was executed +cd ../../.. + +# download and build Iroha library for iOS +curl https://raw.githubusercontent.com/hyperledger/iroha/master/shared_model/packages/ios/ios-build.sh > ios-build.sh + +# optional step - sometimes connection timeout appears when using git: scheme instead of https url +sed -i '' 's|git://github.com/hyperledger/iroha-ed25519|https://github.com/hyperledger/iroha-ed25519.git|g' ios-build.sh + +# build library +chmod +x ios-build.sh +./ios-build.sh SIMULATOR64 Debug + +# place artifacts to proper sample's locations + +# this command shows location for simulator artifacts +# use this command for device instead: +# mkdir -p iroha-ios/libs/iOS/ +mkdir -p iroha-ios/libs/Simulator/ + +# this command shows location for simulator artifacts +# use this command for device instead: +# cp lib/* iroha-ios/libs/iOS/ +cp lib/* iroha-ios/libs/Simulator/ +cp -a include/. iroha-ios/headers/ From ec16af858448084e8e332ae2765d7b5328c0bb6d Mon Sep 17 00:00:00 2001 From: luckychess Date: Fri, 13 Apr 2018 17:22:14 +0300 Subject: [PATCH 043/110] Add mocks for getAccountRoles() in client test (#1218) Signed-off-by: luckychess --- test/module/iroha-cli/client_test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/module/iroha-cli/client_test.cpp b/test/module/iroha-cli/client_test.cpp index d60fa6d1ff..b7585b9d87 100644 --- a/test/module/iroha-cli/client_test.cpp +++ b/test/module/iroha-cli/client_test.cpp @@ -230,6 +230,9 @@ TEST_F(ClientServerTest, SendQueryWhenValid) { EXPECT_CALL(*wsv_query, getAccountDetail("test@test")) .WillOnce(Return(boost::make_optional(std::string("value")))); + EXPECT_CALL(*wsv_query, getAccountRoles("admin@test")) + .WillOnce(Return(boost::none)); + auto query = QueryBuilder() .createdTime(iroha::time::now()) .creatorAccountId("admin@test") @@ -257,6 +260,9 @@ TEST_F(ClientServerTest, SendQueryWhenStatefulInvalid) { "admin@test", "test@test", can_get_my_acc_detail)) .WillOnce(Return(false)); + EXPECT_CALL(*wsv_query, getAccountRoles("admin@test")) + .WillOnce(Return(boost::none)); + auto query = QueryBuilder() .createdTime(iroha::time::now()) .creatorAccountId("admin@test") From f8c76431e00211d80464d4aa2aa18244c19ec20e Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 19 Apr 2018 10:58:58 +0300 Subject: [PATCH 044/110] remove old model from cmake (#1222) * remove old model from cmake Signed-off-by: Alexey Chernyshov --- irohad/ametsuchi/CMakeLists.txt | 3 +-- irohad/consensus/yac/CMakeLists.txt | 2 +- irohad/main/CMakeLists.txt | 3 +-- irohad/main/irohad.cpp | 1 - irohad/network/CMakeLists.txt | 5 ++-- irohad/network/impl/block_loader_service.hpp | 2 -- .../impl/peer_communication_service_impl.cpp | 1 - irohad/ordering/CMakeLists.txt | 3 +-- irohad/simulator/CMakeLists.txt | 2 +- irohad/synchronizer/CMakeLists.txt | 2 +- irohad/torii/CMakeLists.txt | 12 ++++----- irohad/validation/CMakeLists.txt | 5 ++-- shared_model/backend/protobuf/CMakeLists.txt | 2 +- shared_model/builders/CMakeLists.txt | 1 + shared_model/builders/protobuf/CMakeLists.txt | 2 +- shared_model/interfaces/CMakeLists.txt | 4 +-- shared_model/validators/CMakeLists.txt | 2 +- test/integration/acceptance/CMakeLists.txt | 10 ++++---- .../irohad/consensus/yac/CMakeLists.txt | 25 +++++-------------- .../consensus/yac/peer_orderer_test.cpp | 1 - test/module/irohad/validation/CMakeLists.txt | 2 +- test/system/CMakeLists.txt | 2 +- test/system/irohad_test.cpp | 9 ++++--- 23 files changed, 40 insertions(+), 61 deletions(-) diff --git a/irohad/ametsuchi/CMakeLists.txt b/irohad/ametsuchi/CMakeLists.txt index 8806c4ce01..80d078380e 100644 --- a/irohad/ametsuchi/CMakeLists.txt +++ b/irohad/ametsuchi/CMakeLists.txt @@ -13,14 +13,13 @@ add_library(ametsuchi ) target_link_libraries(ametsuchi - json_model_converters logger rxcpp pqxx libs_common command_execution boost - model_interfaces + shared_model_interfaces shared_model_proto_backend shared_model_proto_builders shared_model_stateless_validation diff --git a/irohad/consensus/yac/CMakeLists.txt b/irohad/consensus/yac/CMakeLists.txt index 4eac54002d..14c42364e0 100644 --- a/irohad/consensus/yac/CMakeLists.txt +++ b/irohad/consensus/yac/CMakeLists.txt @@ -19,7 +19,7 @@ add_library(supermajority_check impl/supermajority_checker_impl.cpp ) target_link_libraries(supermajority_check - model + shared_model_interfaces ) add_library(yac diff --git a/irohad/main/CMakeLists.txt b/irohad/main/CMakeLists.txt index 8f071832e5..cd351ee33e 100644 --- a/irohad/main/CMakeLists.txt +++ b/irohad/main/CMakeLists.txt @@ -26,7 +26,7 @@ target_link_libraries(server_runner add_library(raw_block_loader impl/raw_block_loader.cpp) target_link_libraries(raw_block_loader - model_interfaces + shared_model_interfaces ) add_library(application @@ -39,7 +39,6 @@ target_link_libraries(application logger yac server_runner - model ametsuchi networking ordering_service diff --git a/irohad/main/irohad.cpp b/irohad/main/irohad.cpp index 8471becae7..71fd35cb1f 100644 --- a/irohad/main/irohad.cpp +++ b/irohad/main/irohad.cpp @@ -20,7 +20,6 @@ #include #include #include -#include "backend/protobuf/from_old_model.hpp" #include "common/result.hpp" #include "crypto/keys_manager_impl.hpp" #include "main/application.hpp" diff --git a/irohad/network/CMakeLists.txt b/irohad/network/CMakeLists.txt index 9c57e2e9d5..21b66bd9f5 100644 --- a/irohad/network/CMakeLists.txt +++ b/irohad/network/CMakeLists.txt @@ -4,7 +4,7 @@ add_library(networking target_link_libraries(networking rxcpp - model + shared_model_interfaces ordering_service synchronizer logger @@ -15,10 +15,9 @@ add_library(block_loader ) target_link_libraries(block_loader - pb_model_converters loader_grpc rxcpp - model + shared_model_interfaces ) add_library(block_loader_service diff --git a/irohad/network/impl/block_loader_service.hpp b/irohad/network/impl/block_loader_service.hpp index 723ecacc97..8347dcfa0d 100644 --- a/irohad/network/impl/block_loader_service.hpp +++ b/irohad/network/impl/block_loader_service.hpp @@ -21,7 +21,6 @@ #include "ametsuchi/block_query.hpp" #include "loader.grpc.pb.h" #include "logger/logger.hpp" -#include "model/converters/pb_block_factory.hpp" namespace iroha { namespace network { @@ -40,7 +39,6 @@ namespace iroha { protocol::Block *response) override; private: - model::converters::PbBlockFactory factory_; std::shared_ptr storage_; logger::Logger log_; }; diff --git a/irohad/network/impl/peer_communication_service_impl.cpp b/irohad/network/impl/peer_communication_service_impl.cpp index 85bd639057..27776e156a 100644 --- a/irohad/network/impl/peer_communication_service_impl.cpp +++ b/irohad/network/impl/peer_communication_service_impl.cpp @@ -15,7 +15,6 @@ limitations under the License. */ #include "network/impl/peer_communication_service_impl.hpp" -#include "backend/protobuf/from_old_model.hpp" namespace iroha { namespace network { diff --git a/irohad/ordering/CMakeLists.txt b/irohad/ordering/CMakeLists.txt index 139e797f26..4f4e38c797 100644 --- a/irohad/ordering/CMakeLists.txt +++ b/irohad/ordering/CMakeLists.txt @@ -21,10 +21,9 @@ add_library(ordering_service target_link_libraries(ordering_service - pb_model_converters rxcpp tbb - model + shared_model_interfaces ordering_grpc logger ) diff --git a/irohad/simulator/CMakeLists.txt b/irohad/simulator/CMakeLists.txt index 825855f90f..55aed3c0fb 100644 --- a/irohad/simulator/CMakeLists.txt +++ b/irohad/simulator/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(simulator ) target_link_libraries(simulator - model + shared_model_proto_backend rxcpp logger ) diff --git a/irohad/synchronizer/CMakeLists.txt b/irohad/synchronizer/CMakeLists.txt index e61d120f52..1f316488b1 100644 --- a/irohad/synchronizer/CMakeLists.txt +++ b/irohad/synchronizer/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(synchronizer ) target_link_libraries(synchronizer - model + shared_model_interfaces rxcpp logger ) diff --git a/irohad/torii/CMakeLists.txt b/irohad/torii/CMakeLists.txt index 066e553ef1..c2cb96c6aa 100644 --- a/irohad/torii/CMakeLists.txt +++ b/irohad/torii/CMakeLists.txt @@ -20,22 +20,20 @@ add_library(command_client command_client.cpp) target_link_libraries(command_client torii_service endpoint - model + schema ) - target_link_libraries(query_client - torii_service - endpoint - ) + torii_service + endpoint + ) add_library(torii_service impl/query_service.cpp impl/command_service.cpp ) target_link_libraries(torii_service - pb_model_converters endpoint - model + shared_model_proto_backend logger shared_model_stateless_validation ) diff --git a/irohad/validation/CMakeLists.txt b/irohad/validation/CMakeLists.txt index 3c5b1ade2a..2d05d57730 100644 --- a/irohad/validation/CMakeLists.txt +++ b/irohad/validation/CMakeLists.txt @@ -20,8 +20,7 @@ add_library(stateful_validator ) target_link_libraries(stateful_validator rxcpp - model - model_interfaces + shared_model_interfaces logger ) @@ -29,7 +28,7 @@ add_library(chain_validator impl/chain_validator_impl.cpp) target_link_libraries(chain_validator rxcpp - model + shared_model_interfaces logger supermajority_check ) diff --git a/shared_model/backend/protobuf/CMakeLists.txt b/shared_model/backend/protobuf/CMakeLists.txt index 0fdc3ad7dc..2967ea3688 100644 --- a/shared_model/backend/protobuf/CMakeLists.txt +++ b/shared_model/backend/protobuf/CMakeLists.txt @@ -4,6 +4,6 @@ add_library(shared_model_proto_backend target_link_libraries(shared_model_proto_backend schema - model_interfaces + shared_model_interfaces iroha_amount ) diff --git a/shared_model/builders/CMakeLists.txt b/shared_model/builders/CMakeLists.txt index 4d83299aed..f9e2bc0efc 100644 --- a/shared_model/builders/CMakeLists.txt +++ b/shared_model/builders/CMakeLists.txt @@ -18,4 +18,5 @@ add_library(shared_model_default_builders INTERFACE) target_link_libraries(shared_model_default_builders INTERFACE shared_model_proto_builders + shared_model_stateless_validation ) diff --git a/shared_model/builders/protobuf/CMakeLists.txt b/shared_model/builders/protobuf/CMakeLists.txt index 92d1e494e7..a7f4cdc027 100644 --- a/shared_model/builders/protobuf/CMakeLists.txt +++ b/shared_model/builders/protobuf/CMakeLists.txt @@ -19,6 +19,6 @@ add_library(shared_model_proto_builders target_link_libraries( shared_model_proto_builders - model_interfaces + shared_model_interfaces shared_model_proto_backend ) diff --git a/shared_model/interfaces/CMakeLists.txt b/shared_model/interfaces/CMakeLists.txt index 1a05fc4b8e..8a610cbb34 100644 --- a/shared_model/interfaces/CMakeLists.txt +++ b/shared_model/interfaces/CMakeLists.txt @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_library(model_interfaces +add_library(shared_model_interfaces impl.cpp ) -target_link_libraries(model_interfaces +target_link_libraries(shared_model_interfaces old_model shared_model_cryptography ${Boost_LIBRARIES} diff --git a/shared_model/validators/CMakeLists.txt b/shared_model/validators/CMakeLists.txt index a540fbe418..44cc2c7ab4 100644 --- a/shared_model/validators/CMakeLists.txt +++ b/shared_model/validators/CMakeLists.txt @@ -19,5 +19,5 @@ add_library(shared_model_stateless_validation target_link_libraries(shared_model_stateless_validation schema - model_interfaces + shared_model_interfaces ) diff --git a/test/integration/acceptance/CMakeLists.txt b/test/integration/acceptance/CMakeLists.txt index d58931da92..03e1cef83c 100644 --- a/test/integration/acceptance/CMakeLists.txt +++ b/test/integration/acceptance/CMakeLists.txt @@ -89,8 +89,8 @@ target_link_libraries(create_account_test addtest(tx_heavy_data tx_heavy_data.cpp) target_link_libraries(tx_heavy_data - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation - ) + application + integration_framework + shared_model_proto_builders + shared_model_stateless_validation + ) diff --git a/test/module/irohad/consensus/yac/CMakeLists.txt b/test/module/irohad/consensus/yac/CMakeLists.txt index 026f86f422..73d1f1ce5e 100644 --- a/test/module/irohad/consensus/yac/CMakeLists.txt +++ b/test/module/irohad/consensus/yac/CMakeLists.txt @@ -25,43 +25,33 @@ target_link_libraries(cluster_order_test addtest(yac_cold_case_test yac_simple_cold_case_test.cpp) target_link_libraries(yac_cold_case_test yac - model - shared_model_cryptography_model ) addtest(yac_sunny_day_test yac_sunny_day_test.cpp) target_link_libraries(yac_sunny_day_test yac - model shared_model_cryptography_model ) addtest(yac_rainy_day_test yac_rainy_day_test.cpp) target_link_libraries(yac_rainy_day_test yac - model shared_model_cryptography_model ) addtest(yac_unknown_peer_test yac_unknown_peer_test.cpp) target_link_libraries(yac_unknown_peer_test yac - model - shared_model_stateless_validation ) addtest(yac_block_storage_test yac_block_storage_test.cpp) target_link_libraries(yac_block_storage_test yac - model - shared_model_cryptography_model ) addtest(yac_proposal_storage_test yac_proposal_storage_test.cpp) target_link_libraries(yac_proposal_storage_test yac - model - shared_model_stateless_validation ) addtest(yac_timer_test timer_test.cpp) @@ -72,23 +62,22 @@ target_link_libraries(yac_timer_test addtest(yac_network_test network_test.cpp) target_link_libraries(yac_network_test yac - model - shared_model_stateless_validation + shared_model_interfaces + shared_model_default_builders ) addtest(yac_peer_orderer_test peer_orderer_test.cpp) target_link_libraries(yac_peer_orderer_test yac - shared_model_stateless_validation - model + shared_model_interfaces + shared_model_default_builders ) addtest(yac_gate_test yac_gate_test.cpp) target_link_libraries(yac_gate_test yac - model shared_model_cryptography_model - shared_model_stateless_validation + shared_model_default_builders ) addtest(yac_hash_provider_test yac_hash_provider_test.cpp) @@ -106,13 +95,11 @@ target_link_libraries(yac_common_test addtest(yac_crypto_provider_test yac_crypto_provider_test.cpp) target_link_libraries(yac_crypto_provider_test yac - model shared_model_cryptography_model - shared_model_stateless_validation + shared_model_default_builders ) addtest(supermajority_checker_test supermajority_checker_test.cpp) target_link_libraries(supermajority_checker_test yac - model ) diff --git a/test/module/irohad/consensus/yac/peer_orderer_test.cpp b/test/module/irohad/consensus/yac/peer_orderer_test.cpp index 9cbd59ed41..2314a2bd46 100644 --- a/test/module/irohad/consensus/yac/peer_orderer_test.cpp +++ b/test/module/irohad/consensus/yac/peer_orderer_test.cpp @@ -29,7 +29,6 @@ #include "consensus/yac/storage/yac_proposal_storage.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/consensus/yac/yac_mocks.hpp" -#include "validators/field_validator.hpp" using namespace boost::adaptors; using namespace iroha::ametsuchi; diff --git a/test/module/irohad/validation/CMakeLists.txt b/test/module/irohad/validation/CMakeLists.txt index 49c6c12e7c..209e0d65c7 100644 --- a/test/module/irohad/validation/CMakeLists.txt +++ b/test/module/irohad/validation/CMakeLists.txt @@ -17,7 +17,7 @@ addtest(query_execution query_execution.cpp) target_link_libraries(query_execution - model + shared_model_interfaces shared_model_stateless_validation ) diff --git a/test/system/CMakeLists.txt b/test/system/CMakeLists.txt index 9df9aa2e6c..6462cd0118 100644 --- a/test/system/CMakeLists.txt +++ b/test/system/CMakeLists.txt @@ -2,7 +2,7 @@ addtest(irohad_test irohad_test.cpp) target_link_libraries(irohad_test boost pqxx - json_model_converters + rapidjson integration_framework_config_helper libs_common ) diff --git a/test/system/irohad_test.cpp b/test/system/irohad_test.cpp index 0771b1bd9d..26e5473aa9 100644 --- a/test/system/irohad_test.cpp +++ b/test/system/irohad_test.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -30,7 +32,6 @@ #undef RAPIDJSON_HAS_STDSTRING #include "framework/config_helper.hpp" -#include "model/converters/json_common.hpp" using namespace boost::process; using namespace boost::filesystem; @@ -52,8 +53,10 @@ class IrohadTest : public testing::Test { auto config_copy_json = parse_iroha_config(path_config_.string()); config_copy_json[config_members::PgOpt].SetString(pgopts_.data(), pgopts_.size()); - auto config_copy_string = - iroha::model::converters::jsonToString(config_copy_json); + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter writer(sb); + config_copy_json.Accept(writer); + std::string config_copy_string = sb.GetString(); std::ofstream copy_file(config_copy_); copy_file.write(config_copy_string.data(), config_copy_string.size()); } From c52f6655e81b65afefe440f704ee64fb3b50e029 Mon Sep 17 00:00:00 2001 From: Dumitru Date: Thu, 19 Apr 2018 16:11:10 +0300 Subject: [PATCH 045/110] New message (#1174) Signed-off-by: Dumitru New signer Signed-off-by: Dumitru Fix all tests Signed-off-by: Dumitru Fix linking Signed-off-by: Dumitru Fix sunny day test Signed-off-by: Dumitru Add log, add test signature builder, removed unused imports Signed-off-by: Dumitru Remove empty signatures Signed-off-by: Dumitru Imporve codestyle, add todo's, remove unused imports Signed-off-by: Dumitru Refactor includes, change year in copyright Signed-off-by: Dumitru Improved codestyle, removed unused imports Signed-off-by: Dumitru --- irohad/consensus/yac/impl/yac.cpp | 14 ++- .../yac/impl/yac_crypto_provider_impl.cpp | 51 ++++++----- .../yac/impl/yac_crypto_provider_impl.hpp | 2 +- irohad/consensus/yac/impl/yac_gate_impl.cpp | 6 +- irohad/consensus/yac/messages.hpp | 8 +- .../yac/transport/yac_pb_converters.hpp | 85 ++++++++++++------- irohad/main/impl/consensus_init.cpp | 5 +- irohad/main/impl/consensus_init.hpp | 2 +- .../builders/common_objects/common.hpp | 2 + .../consensus/consensus_sunny_day.cpp | 21 +++-- .../irohad/consensus/yac/CMakeLists.txt | 8 +- .../irohad/consensus/yac/network_test.cpp | 5 +- .../irohad/consensus/yac/yac_common_test.cpp | 3 +- .../yac/yac_crypto_provider_test.cpp | 1 - .../irohad/consensus/yac/yac_gate_test.cpp | 16 +--- .../module/irohad/consensus/yac/yac_mocks.hpp | 25 +++++- .../consensus/yac/yac_unknown_peer_test.cpp | 8 +- .../validation/chain_validation_test.cpp | 2 +- .../protobuf/test_signature_builder.hpp | 29 +++++++ 19 files changed, 187 insertions(+), 106 deletions(-) create mode 100644 test/module/shared_model/builders/protobuf/test_signature_builder.hpp diff --git a/irohad/consensus/yac/impl/yac.cpp b/irohad/consensus/yac/impl/yac.cpp index 014895eeee..aaec12c54f 100644 --- a/irohad/consensus/yac/impl/yac.cpp +++ b/irohad/consensus/yac/impl/yac.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,9 +35,9 @@ namespace iroha { "Crypto verification failed for message.\n Votes: "; result += logger::to_string(votes, [](const auto &vote) { std::string result = "(Public key: "; - result += vote.signature.pubkey.to_hexstring(); + result += vote.signature->publicKey().hex(); result += ", Signature: "; - result += vote.signature.signature.to_hexstring(); + result += vote.signature->signedData().hex(); result += ")\n"; return result; }); @@ -151,11 +151,7 @@ namespace iroha { auto peers = cluster_order_.getPeers(); auto it = std::find_if(peers.begin(), peers.end(), [&](const auto &peer) { - // TODO: 24/03/2018 x3medima17, remove makeOldModel after - // migrating VoteMessage to the new model - auto old_peer = - *std::unique_ptr(peer->makeOldModel()); - return old_peer.pubkey == vote.signature.pubkey; + return peer->pubkey() == vote.signature->publicKey(); }); return it != peers.end() ? boost::make_optional(std::move(*it)) : boost::none; @@ -228,7 +224,7 @@ namespace iroha { } else { log_->info("Apply vote: {} from unknown peer {}", vote.hash.block_hash, - vote.signature.pubkey.to_hexstring()); + vote.signature->publicKey().hex()); } auto answer = diff --git a/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp b/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp index 585c3bba7b..a5850925e4 100644 --- a/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp +++ b/irohad/consensus/yac/impl/yac_crypto_provider_impl.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,13 +17,14 @@ #include "consensus/yac/impl/yac_crypto_provider_impl.hpp" #include "consensus/yac/transport/yac_pb_converters.hpp" -#include "cryptography/ed25519_sha3_impl/internal/ed25519_impl.hpp" -#include "cryptography/ed25519_sha3_impl/internal/sha3_hash.hpp" +#include "cryptography/crypto_provider/crypto_signer.hpp" +#include "cryptography/crypto_provider/crypto_verifier.hpp" namespace iroha { namespace consensus { namespace yac { - CryptoProviderImpl::CryptoProviderImpl(const shared_model::crypto::Keypair &keypair) + CryptoProviderImpl::CryptoProviderImpl( + const shared_model::crypto::Keypair &keypair) : keypair_(keypair) {} bool CryptoProviderImpl::verify(CommitMessage msg) { @@ -41,26 +42,38 @@ namespace iroha { } bool CryptoProviderImpl::verify(VoteMessage msg) { - return iroha::verify( - iroha::sha3_256( - PbConverters::serializeVote(msg).hash().SerializeAsString()) - .to_string(), - msg.signature.pubkey, - msg.signature.signature); + auto serialized = + PbConverters::serializeVote(msg).hash().SerializeAsString(); + auto blob = shared_model::crypto::Blob(serialized); + + return shared_model::crypto::CryptoVerifier<>::verify( + msg.signature->signedData(), blob, msg.signature->publicKey()); } VoteMessage CryptoProviderImpl::getVote(YacHash hash) { VoteMessage vote; vote.hash = hash; - keypair_t keypair = *std::unique_ptr(keypair_.makeOldModel()); - auto signature = iroha::sign( - iroha::sha3_256( - PbConverters::serializeVote(vote).hash().SerializeAsString()) - .to_string(), - keypair.pubkey, - keypair.privkey); - vote.signature.signature = signature; - vote.signature.pubkey = keypair.pubkey; + auto serialized = + PbConverters::serializeVotePayload(vote).hash().SerializeAsString(); + auto blob = shared_model::crypto::Blob(serialized); + const auto &pubkey = keypair_.publicKey(); + const auto &privkey = keypair_.privateKey(); + auto signature = shared_model::crypto::CryptoSigner<>::sign( + blob, shared_model::crypto::Keypair(pubkey, privkey)); + + shared_model::builder::DefaultSignatureBuilder() + .publicKey(pubkey) + .signedData(signature) + .build() + .match([&vote](iroha::expected::Value< + std::shared_ptr> + &sig) { vote.signature = sig.value; }, + [](iroha::expected::Error> + &reason) { + logger::log("YacCryptoProvider::getVote") + ->error("Cannot build vote signature: {}", + *reason.error); + }); return vote; } diff --git a/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp b/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp index 5c07ebb3cb..9e04a46e0e 100644 --- a/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp +++ b/irohad/consensus/yac/impl/yac_crypto_provider_impl.hpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/irohad/consensus/yac/impl/yac_gate_impl.cpp b/irohad/consensus/yac/impl/yac_gate_impl.cpp index b472fea6b0..0329402a35 100644 --- a/irohad/consensus/yac/impl/yac_gate_impl.cpp +++ b/irohad/consensus/yac/impl/yac_gate_impl.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -103,9 +103,7 @@ namespace iroha { std::shared_ptr>( [this, model_hash, vote](auto subscriber) { auto block = block_loader_->retrieveBlock( - shared_model::crypto::PublicKey( - {vote.signature.pubkey.begin(), - vote.signature.pubkey.end()}), + vote.signature->publicKey(), shared_model::crypto::Hash(model_hash)); // if load is successful if (block) { diff --git a/irohad/consensus/yac/messages.hpp b/irohad/consensus/yac/messages.hpp index 53ec70bbef..6a9174a8c8 100644 --- a/irohad/consensus/yac/messages.hpp +++ b/irohad/consensus/yac/messages.hpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ #include #include "consensus/yac/yac_hash_provider.hpp" // for YacHash -#include "model/signature.hpp" // for model::Signature +#include "interfaces/common_objects/signature.hpp" namespace iroha { namespace consensus { @@ -32,10 +32,10 @@ namespace iroha { */ struct VoteMessage { YacHash hash; - model::Signature signature; + std::shared_ptr signature; bool operator==(const VoteMessage &rhs) const { - return hash == rhs.hash and signature == rhs.signature; + return hash == rhs.hash and *signature == *rhs.signature; } bool operator!=(const VoteMessage &rhs) const { diff --git a/irohad/consensus/yac/transport/yac_pb_converters.hpp b/irohad/consensus/yac/transport/yac_pb_converters.hpp index ac963f0b04..1ed047b955 100644 --- a/irohad/consensus/yac/transport/yac_pb_converters.hpp +++ b/irohad/consensus/yac/transport/yac_pb_converters.hpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,7 @@ #include "consensus/yac/messages.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" #include "interfaces/common_objects/signature.hpp" +#include "logger/logger.hpp" #include "yac.pb.h" namespace iroha { @@ -30,7 +31,7 @@ namespace iroha { namespace yac { class PbConverters { public: - static proto::Vote serializeVote(const VoteMessage &vote) { + static proto::Vote serializeVotePayload(const VoteMessage &vote) { proto::Vote pb_vote; auto hash = pb_vote.mutable_hash(); @@ -39,24 +40,23 @@ namespace iroha { auto block_signature = hash->mutable_block_signature(); - // Will fix it in the next PR, very soon, don't worry - if (vote.hash.block_signature == nullptr) { - auto peer_key = shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair() - .publicKey(); - shared_model::builder::DefaultSignatureBuilder() - .publicKey(peer_key) - .signedData(shared_model::crypto::Signed("")) - .build() - .match( - [&](iroha::expected::Value> &sig) { - const_cast(vote).hash.block_signature = - sig.value; - }, - [](iroha::expected::Error>) { - }); - } + block_signature->set_signature(shared_model::crypto::toBinaryString( + vote.hash.block_signature->signedData())); + + block_signature->set_pubkey(shared_model::crypto::toBinaryString( + vote.hash.block_signature->publicKey())); + + return pb_vote; + } + + static proto::Vote serializeVote(const VoteMessage &vote) { + proto::Vote pb_vote; + + auto hash = pb_vote.mutable_hash(); + hash->set_block(vote.hash.block_hash); + hash->set_proposal(vote.hash.proposal_hash); + + auto block_signature = hash->mutable_block_signature(); block_signature->set_signature(shared_model::crypto::toBinaryString( vote.hash.block_signature->signedData())); @@ -65,8 +65,11 @@ namespace iroha { vote.hash.block_signature->publicKey())); auto signature = pb_vote.mutable_signature(); - signature->set_signature(vote.signature.signature.to_string()); - signature->set_pubkey(vote.signature.pubkey.to_string()); + const auto &sig = *vote.signature; + signature->set_signature( + shared_model::crypto::toBinaryString(sig.signedData())); + signature->set_pubkey( + shared_model::crypto::toBinaryString(sig.publicKey())); return pb_vote; } @@ -84,15 +87,35 @@ namespace iroha { pb_vote.hash().block_signature().signature())) .build() .match( - [&](iroha::expected::Value< - std::shared_ptr> - &sig) { vote.hash.block_signature = sig.value; }, - [](iroha::expected::Error>) {}); - - vote.signature.signature = *stringToBlob( - pb_vote.signature().signature()); - vote.signature.pubkey = *stringToBlob( - pb_vote.signature().pubkey()); + [&vote](iroha::expected::Value< + std::shared_ptr> + &sig) { vote.hash.block_signature = sig.value; }, + [](iroha::expected::Error> + &reason) { + logger::log("YacPbConverter::deserializeVote") + ->error("Cannot build vote hash block signature: {}", + *reason.error); + }); + + const auto &pubkey = + shared_model::crypto::PublicKey(pb_vote.signature().pubkey()); + const auto &signed_data = + shared_model::crypto::Signed(pb_vote.signature().signature()); + + shared_model::builder::DefaultSignatureBuilder() + .publicKey(pubkey) + .signedData(signed_data) + .build() + .match( + [&vote](iroha::expected::Value< + std::shared_ptr> + &sig) { vote.signature = sig.value; }, + [](iroha::expected::Error> + &reason) { + logger::log("YacPbConverter::deserializeVote") + ->error("Cannot build vote signature: {}", + *reason.error); + }); return vote; } diff --git a/irohad/main/impl/consensus_init.cpp b/irohad/main/impl/consensus_init.cpp index f90195a83a..29da71f8b3 100644 --- a/irohad/main/impl/consensus_init.cpp +++ b/irohad/main/impl/consensus_init.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,7 +38,8 @@ namespace iroha { return consensus_network; } - auto YacInit::createCryptoProvider(const shared_model::crypto::Keypair &keypair) { + auto YacInit::createCryptoProvider( + const shared_model::crypto::Keypair &keypair) { auto crypto = std::make_shared(keypair); return crypto; diff --git a/irohad/main/impl/consensus_init.hpp b/irohad/main/impl/consensus_init.hpp index 2f9b999ded..ef50028753 100644 --- a/irohad/main/impl/consensus_init.hpp +++ b/irohad/main/impl/consensus_init.hpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/shared_model/builders/common_objects/common.hpp b/shared_model/builders/common_objects/common.hpp index 275c1bc407..ffd44669f6 100644 --- a/shared_model/builders/common_objects/common.hpp +++ b/shared_model/builders/common_objects/common.hpp @@ -65,6 +65,8 @@ namespace shared_model { } if (answer) { + // TODO 15.04.2018 x3medima17 IR-1240: rework with std::string instead + // of pointer to string return iroha::expected::makeError( std::make_shared(answer.reason())); } diff --git a/test/integration/consensus/consensus_sunny_day.cpp b/test/integration/consensus/consensus_sunny_day.cpp index e3a7a85ec0..abeeb80601 100644 --- a/test/integration/consensus/consensus_sunny_day.cpp +++ b/test/integration/consensus/consensus_sunny_day.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,11 +16,14 @@ */ #include + #include "consensus/yac/impl/timer_impl.hpp" #include "consensus/yac/storage/yac_proposal_storage.hpp" #include "consensus/yac/transport/impl/network_impl.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" #include "framework/test_subscriber.hpp" #include "module/irohad/consensus/yac/yac_mocks.hpp" +#include "module/shared_model/builders/protobuf/test_signature_builder.hpp" using ::testing::An; using ::testing::Return; @@ -36,17 +39,23 @@ auto mk_local_peer(uint64_t num) { class FixedCryptoProvider : public MockYacCryptoProvider { public: explicit FixedCryptoProvider(const std::string &public_key) { - pubkey.fill(0); - std::copy(public_key.begin(), public_key.end(), pubkey.begin()); + // TODO 15.04.2018 x3medima17 IR-1189: move to separate class + auto size = + shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair() + .publicKey().size(); + // TODO 16.04.2018 x3medima17 IR-977: add sizes + std::string key(size, 0); + std::copy(public_key.begin(), public_key.end(), key.begin()); + pubkey = clone(shared_model::crypto::PublicKey(key)); } VoteMessage getVote(YacHash hash) override { auto vote = MockYacCryptoProvider::getVote(hash); - vote.signature.pubkey = pubkey; + vote.signature = clone(TestSignatureBuilder().publicKey(*pubkey).build()); return vote; } - decltype(VoteMessage().signature.pubkey) pubkey; + std::unique_ptr pubkey; }; class ConsensusSunnyDayTest : public ::testing::Test { @@ -142,7 +151,7 @@ TEST_F(ConsensusSunnyDayTest, SunnyDayTest) { std::this_thread::sleep_for(std::chrono::milliseconds(delay_before)); YacHash my_hash("proposal_hash", "block_hash"); - + my_hash.block_signature = createSig(""); auto order = ClusterOrdering::create(default_peers); ASSERT_TRUE(order); diff --git a/test/module/irohad/consensus/yac/CMakeLists.txt b/test/module/irohad/consensus/yac/CMakeLists.txt index 73d1f1ce5e..d216caa87a 100644 --- a/test/module/irohad/consensus/yac/CMakeLists.txt +++ b/test/module/irohad/consensus/yac/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. +# Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. # http://soramitsu.co.jp # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ addtest(cluster_order_test cluster_order_test.cpp) target_link_libraries(cluster_order_test yac - shared_model_cryptography_model + shared_model_cryptography ) addtest(yac_cold_case_test yac_simple_cold_case_test.cpp) @@ -83,13 +83,13 @@ target_link_libraries(yac_gate_test addtest(yac_hash_provider_test yac_hash_provider_test.cpp) target_link_libraries(yac_hash_provider_test yac - shared_model_cryptography_model + shared_model_cryptography ) addtest(yac_common_test yac_common_test.cpp) target_link_libraries(yac_common_test yac - shared_model_cryptography_model + shared_model_cryptography ) addtest(yac_crypto_provider_test yac_crypto_provider_test.cpp) diff --git a/test/module/irohad/consensus/yac/network_test.cpp b/test/module/irohad/consensus/yac/network_test.cpp index d338d06038..4e6a182213 100644 --- a/test/module/irohad/consensus/yac/network_test.cpp +++ b/test/module/irohad/consensus/yac/network_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,9 +19,7 @@ #include -#include "consensus/yac/storage/yac_proposal_storage.hpp" #include "consensus/yac/transport/impl/network_impl.hpp" -#include "consensus/yac/transport/yac_pb_converters.hpp" using ::testing::_; using ::testing::InvokeWithoutArgs; @@ -47,6 +45,7 @@ namespace iroha { .build(); message.hash.block_signature = clone(sig); + message.signature = createSig(""); network->subscribe(notifications); grpc::ServerBuilder builder; diff --git a/test/module/irohad/consensus/yac/yac_common_test.cpp b/test/module/irohad/consensus/yac/yac_common_test.cpp index 037ff904cc..51e8b0490a 100644 --- a/test/module/irohad/consensus/yac/yac_common_test.cpp +++ b/test/module/irohad/consensus/yac/yac_common_test.cpp @@ -15,8 +15,9 @@ * limitations under the License. */ -#include "consensus/yac/storage/yac_common.hpp" #include + +#include "consensus/yac/storage/yac_common.hpp" #include "consensus/yac/storage/yac_proposal_storage.hpp" #include "logger/logger.hpp" #include "module/irohad/consensus/yac/yac_mocks.hpp" diff --git a/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp b/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp index a694591c23..179bc7fc12 100644 --- a/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp +++ b/test/module/irohad/consensus/yac/yac_crypto_provider_test.cpp @@ -18,7 +18,6 @@ #include #include "builders/protobuf/common_objects/proto_signature_builder.hpp" #include "consensus/yac/impl/yac_crypto_provider_impl.hpp" -#include "consensus/yac/impl/yac_hash_provider_impl.hpp" #include "consensus/yac/messages.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" diff --git a/test/module/irohad/consensus/yac/yac_gate_test.cpp b/test/module/irohad/consensus/yac/yac_gate_test.cpp index 84de78655f..613f25243c 100644 --- a/test/module/irohad/consensus/yac/yac_gate_test.cpp +++ b/test/module/irohad/consensus/yac/yac_gate_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,19 +18,15 @@ #include #include -#include "backend/protobuf/from_old_model.hpp" #include "builders/protobuf/block.hpp" #include "builders/protobuf/common_objects/proto_signature_builder.hpp" #include "consensus/yac/impl/yac_gate_impl.hpp" #include "consensus/yac/storage/yac_proposal_storage.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "cryptography/hash.hpp" -#include "cryptography/hash_providers/sha3_256.hpp" #include "framework/test_subscriber.hpp" #include "module/irohad/consensus/yac/yac_mocks.hpp" #include "module/irohad/network/network_mocks.hpp" #include "module/irohad/simulator/simulator_mocks.hpp" -#include "cryptography/hash.hpp" using namespace iroha::consensus::yac; using namespace iroha::network; @@ -63,13 +59,10 @@ class YacGateTest : public ::testing::Test { expected_block = clone(tmp); const auto &wrapped_sig = *(expected_block->signatures().begin()); const auto &signature = *wrapped_sig; - // TODO: 24/04/2018 x3medima17 remove makeOldModel in next PR - const auto old_signature = - *std::unique_ptr(signature.makeOldModel()); expected_hash.block_signature = clone(signature); message.hash = expected_hash; - message.signature = old_signature; + message.signature = clone(signature); commit_message = CommitMessage({message}); expected_commit = rxcpp::observable<>::just(commit_message); @@ -133,9 +126,8 @@ TEST_F(YacGateTest, YacGateSubscriptionTest) { // verify that yac gate emit expected block auto gate_wrapper = make_test_subscriber(gate->on_commit(), 1); - gate_wrapper.subscribe([this](auto block) { - ASSERT_EQ(*block, *expected_block); - }); + gate_wrapper.subscribe( + [this](auto block) { ASSERT_EQ(*block, *expected_block); }); ASSERT_TRUE(gate_wrapper.validate()); } diff --git a/test/module/irohad/consensus/yac/yac_mocks.hpp b/test/module/irohad/consensus/yac/yac_mocks.hpp index 34262eab54..e517ecfb9c 100644 --- a/test/module/irohad/consensus/yac/yac_mocks.hpp +++ b/test/module/irohad/consensus/yac/yac_mocks.hpp @@ -32,7 +32,9 @@ #include "consensus/yac/yac_gate.hpp" #include "consensus/yac/yac_hash_provider.hpp" #include "consensus/yac/yac_peer_orderer.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" #include "interfaces/iroha_internal/block.hpp" +#include "module/shared_model/builders/protobuf/test_signature_builder.hpp" namespace iroha { namespace consensus { @@ -49,12 +51,28 @@ namespace iroha { return clone(ptr); } + /** + * Creates test signature with empty signed data, and provided pubkey + * @param pub_key - public key to put in the signature + * @return new signature + */ + std::shared_ptr createSig( + const std::string &pub_key) { + auto tmp = + shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair() + .publicKey(); + std::string key(tmp.blob().size(), 0); + std::copy(pub_key.begin(), pub_key.end(), key.begin()); + + return clone(TestSignatureBuilder() + .publicKey(shared_model::crypto::PublicKey(key)) + .build()); + } + VoteMessage create_vote(YacHash hash, std::string pub_key) { VoteMessage vote; vote.hash = hash; - // TODO: 19.01.2019 kamil substitute with function, IR-813 - std::copy( - pub_key.begin(), pub_key.end(), vote.signature.pubkey.begin()); + vote.signature = createSig(pub_key); return vote; } @@ -67,6 +85,7 @@ namespace iroha { VoteMessage getVote(YacHash hash) override { VoteMessage vote; vote.hash = hash; + vote.signature = createSig(""); return vote; } diff --git a/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp b/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp index 8febd0de8c..8c9cc0fa01 100644 --- a/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp +++ b/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,7 +51,8 @@ TEST_F(YacTest, UnknownVoteBeforeCommit) { VoteMessage vote; vote.hash = YacHash("my_proposal", "my_block"); std::string unknown = "unknown"; - std::copy(unknown.begin(), unknown.end(), vote.signature.pubkey.begin()); + vote.signature = createSig(unknown); + // assume that our peer receive message network->notification->on_vote(vote); @@ -101,7 +102,6 @@ TEST_F(YacTest, UnknownVoteAfterCommit) { VoteMessage vote; vote.hash = my_hash; std::string unknown = "unknown"; - std::copy(unknown.begin(), unknown.end(), vote.signature.pubkey.begin()); - + vote.signature = createSig(unknown); yac->on_vote(vote); } diff --git a/test/module/irohad/validation/chain_validation_test.cpp b/test/module/irohad/validation/chain_validation_test.cpp index 8908b168c5..6352bee226 100644 --- a/test/module/irohad/validation/chain_validation_test.cpp +++ b/test/module/irohad/validation/chain_validation_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test/module/shared_model/builders/protobuf/test_signature_builder.hpp b/test/module/shared_model/builders/protobuf/test_signature_builder.hpp new file mode 100644 index 0000000000..55b28182cd --- /dev/null +++ b/test/module/shared_model/builders/protobuf/test_signature_builder.hpp @@ -0,0 +1,29 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IROHA_TEST_SIGNATURE_BUILDER_HPP +#define IROHA_TEST_SIGNATURE_BUILDER_HPP + +#include "builders/protobuf/common_objects/proto_signature_builder.hpp" + +/** + * Builder alias, for building shared model proto block object avoiding validation + * and "required fields" check + */ +using TestSignatureBuilder = shared_model::proto::SignatureBuilder; + +#endif // IROHA_TEST_SIGNATURE_BUILDER_HPP From b49fce24ec98047f7abcb6b51e49e7dca9608508 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Thu, 19 Apr 2018 23:34:49 +0300 Subject: [PATCH 046/110] Remove old model from kv_storage_test (#1189) Signed-off-by: Nikita Alekseev --- test/module/irohad/ametsuchi/CMakeLists.txt | 1 - .../irohad/ametsuchi/kv_storage_test.cpp | 91 +++++++------------ 2 files changed, 32 insertions(+), 60 deletions(-) diff --git a/test/module/irohad/ametsuchi/CMakeLists.txt b/test/module/irohad/ametsuchi/CMakeLists.txt index 8d72781c58..485bb11d09 100644 --- a/test/module/irohad/ametsuchi/CMakeLists.txt +++ b/test/module/irohad/ametsuchi/CMakeLists.txt @@ -42,5 +42,4 @@ target_link_libraries(kv_storage_test add_library(ametsuchi_fixture INTERFACE) target_link_libraries(ametsuchi_fixture INTERFACE pqxx - model_generators ) diff --git a/test/module/irohad/ametsuchi/kv_storage_test.cpp b/test/module/irohad/ametsuchi/kv_storage_test.cpp index a91b2741d0..46fa55b442 100644 --- a/test/module/irohad/ametsuchi/kv_storage_test.cpp +++ b/test/module/irohad/ametsuchi/kv_storage_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,21 +17,16 @@ #include #include -#include #include "ametsuchi/block_query.hpp" #include "ametsuchi/impl/postgres_wsv_query.hpp" #include "ametsuchi/impl/storage_impl.hpp" #include "ametsuchi/mutable_storage.hpp" -#include "model/block.hpp" -#include "model/sha3_hash.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" +#include "module/shared_model/builders/protobuf/test_block_builder.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "validators/permissions.hpp" -// TODO: 14-02-2018 Alexey Chernyshov remove this after relocation to -// shared_model https://soramitsu.atlassian.net/browse/IR-887 -#include "backend/protobuf/from_old_model.hpp" - using namespace iroha::ametsuchi; /** @@ -55,54 +50,34 @@ class KVTest : public AmetsuchiTest { blocks = storage->getBlockQuery(); wsv_query = storage->getWsvQuery(); - // First transaction in block1 - iroha::model::Transaction txn1_1; - txn1_1.creator_account_id = "userone@ru"; - - iroha::model::CreateRole createRole; - createRole.role_name = "user"; - createRole.permissions = {shared_model::permissions::can_add_peer, - shared_model::permissions::can_create_asset, - shared_model::permissions::can_get_my_account}; - - // Create domain ru - txn1_1.commands.push_back( - std::make_shared(createRole)); - iroha::model::CreateDomain createDomain; - createDomain.domain_id = "ru"; - createDomain.user_default_role = "user"; - txn1_1.commands.push_back( - std::make_shared(createDomain)); - - // Create account user1 - iroha::model::CreateAccount createAccount1; - createAccount1.account_name = account_name1; - createAccount1.domain_id = domain_id; - txn1_1.commands.push_back( - std::make_shared(createAccount1)); - - // Create account user2 - iroha::model::CreateAccount createAccount2; - createAccount2.account_name = account_name2; - createAccount2.domain_id = domain_id; - txn1_1.commands.push_back( - std::make_shared(createAccount2)); - - // Set age for user2 - iroha::model::SetAccountDetail setAccount2Age; - setAccount2Age.account_id = account_name2 + "@" + domain_id; - setAccount2Age.key = "age"; - setAccount2Age.value = "24"; - txn1_1.commands.push_back( - std::make_shared(setAccount2Age)); - - iroha::model::Block old_block1; - old_block1.height = 1; - old_block1.transactions.push_back(txn1_1); - old_block1.prev_hash.fill(0); - auto block1hash = iroha::hash(old_block1); - old_block1.hash = block1hash; - old_block1.txs_number = old_block1.transactions.size(); + std::string empty_key(32, '0'); + // transaction for block 1 + auto txn = + TestTransactionBuilder() + .creatorAccountId("userone@ru") + .createRole( + "user", + std::vector{ + shared_model::permissions::can_add_peer, + shared_model::permissions::can_create_asset, + shared_model::permissions::can_get_my_account}) + .createDomain("ru", "user") + .createAccount( + account_name1, + domain_id, + shared_model::crypto::PublicKey(empty_key)) + .createAccount( + account_name2, + domain_id, + shared_model::crypto::PublicKey(empty_key)) + .setAccountDetail(account_name2 + "@" + domain_id, "age", "24") + .build(); + auto block1 = + TestBlockBuilder() + .height(1) + .prevHash(shared_model::crypto::Hash(empty_key)) + .transactions(std::vector{txn}) + .build(); { std::unique_ptr ms; @@ -113,9 +88,7 @@ class KVTest : public AmetsuchiTest { [](iroha::expected::Error &error) { FAIL() << "MutableStorage: " << error.error; }); - // TODO: 14-02-2018 Alexey Chernyshov remove this after relocation to - // shared_model https://soramitsu.atlassian.net/browse/IR-887 - auto block1 = shared_model::proto::from_old(old_block1); + ms->apply(block1, [](const auto &blk, auto &query, const auto &top_hash) { return true; }); From f78314f5086507168f986fb6866d6570641bc644 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Thu, 19 Apr 2018 23:39:12 +0300 Subject: [PATCH 047/110] Add error message to error response (#1220) Signed-off-by: Nikita Alekseev --- irohad/torii/impl/command_service.cpp | 1 + irohad/torii/impl/query_service.cpp | 1 + schema/endpoint.proto | 1 + schema/responses.proto | 1 + test/module/iroha-cli/client_test.cpp | 10 ++++++---- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/irohad/torii/impl/command_service.cpp b/irohad/torii/impl/command_service.cpp index c12418d189..fc3a88acbe 100644 --- a/irohad/torii/impl/command_service.cpp +++ b/irohad/torii/impl/command_service.cpp @@ -113,6 +113,7 @@ namespace torii { shared_model::crypto::toBinaryString(tx_hash)); response.set_tx_status( iroha::protocol::TxStatus::STATELESS_VALIDATION_FAILED); + response.set_error_message(std::move(error.error)); }); cache_->addItem(tx_hash, response); diff --git a/irohad/torii/impl/query_service.cpp b/irohad/torii/impl/query_service.cpp index 6d3c0f9245..cc712b56e5 100644 --- a/irohad/torii/impl/query_service.cpp +++ b/irohad/torii/impl/query_service.cpp @@ -77,6 +77,7 @@ namespace torii { shared_model::crypto::toBinaryString(hash)); response.mutable_error_response()->set_reason( iroha::protocol::ErrorResponse::STATELESS_INVALID); + response.mutable_error_response()->set_message(std::move(error.error)); }); } diff --git a/schema/endpoint.proto b/schema/endpoint.proto index 42beb2e484..c4320302af 100644 --- a/schema/endpoint.proto +++ b/schema/endpoint.proto @@ -20,6 +20,7 @@ enum TxStatus { message ToriiResponse { TxStatus tx_status = 1; bytes tx_hash = 2; + string error_message = 3; } message TxStatusRequest{ diff --git a/schema/responses.proto b/schema/responses.proto index 88c64101ad..aeea59037d 100644 --- a/schema/responses.proto +++ b/schema/responses.proto @@ -67,6 +67,7 @@ message ErrorResponse { NO_ROLES = 8; // when there are no roles defined in the system } Reason reason = 1; + string message = 2; } message SignatoriesResponse { diff --git a/test/module/iroha-cli/client_test.cpp b/test/module/iroha-cli/client_test.cpp index b7585b9d87..8170c1c5ea 100644 --- a/test/module/iroha-cli/client_test.cpp +++ b/test/module/iroha-cli/client_test.cpp @@ -42,10 +42,10 @@ constexpr const char *Ip = "0.0.0.0"; constexpr int Port = 50051; +using ::testing::_; using ::testing::A; using ::testing::AtLeast; using ::testing::Return; -using ::testing::_; using namespace iroha::ametsuchi; using namespace iroha::network; @@ -167,10 +167,11 @@ TEST_F(ClientServerTest, SendTxWhenStatelessInvalid) { ASSERT_EQ(iroha_cli::CliClient(Ip, Port).sendTx(*old_tx).answer, iroha_cli::CliClient::OK); auto tx_hash = shm_tx.hash(); - ASSERT_EQ(iroha_cli::CliClient(Ip, Port) - .getTxStatus(shared_model::crypto::toBinaryString(tx_hash)) - .answer.tx_status(), + auto res = iroha_cli::CliClient(Ip, Port).getTxStatus( + shared_model::crypto::toBinaryString(tx_hash)); + ASSERT_EQ(res.answer.tx_status(), iroha::protocol::TxStatus::STATELESS_VALIDATION_FAILED); + ASSERT_NE(res.answer.error_message().size(), 0); } TEST_F(ClientServerTest, SendQueryWhenInvalidJson) { @@ -210,6 +211,7 @@ TEST_F(ClientServerTest, SendQueryWhenStatelessInvalid) { ASSERT_TRUE(res.answer.has_error_response()); ASSERT_EQ(res.answer.error_response().reason(), iroha::model::ErrorResponse::STATELESS_INVALID); + ASSERT_NE(res.answer.error_response().message().size(), 0); } TEST_F(ClientServerTest, SendQueryWhenValid) { From 58c9eecddb97366f34c49500c848ef9dc0b3655c Mon Sep 17 00:00:00 2001 From: Moonraker Date: Fri, 20 Apr 2018 13:35:43 +0700 Subject: [PATCH 048/110] fix synchronization issues #1247 Signed-off-by: Moonraker --- irohad/consensus/yac/impl/yac_gate_impl.cpp | 1 + irohad/consensus/yac/impl/yac_gate_impl.hpp | 5 ++ .../irohad/consensus/yac/yac_gate_test.cpp | 54 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/irohad/consensus/yac/impl/yac_gate_impl.cpp b/irohad/consensus/yac/impl/yac_gate_impl.cpp index 0329402a35..9006c10d95 100644 --- a/irohad/consensus/yac/impl/yac_gate_impl.cpp +++ b/irohad/consensus/yac/impl/yac_gate_impl.cpp @@ -114,6 +114,7 @@ namespace iroha { }) // need only the first .first() + .retry() .subscribe( // if load is successful from at least one node [subscriber](auto block) { diff --git a/irohad/consensus/yac/impl/yac_gate_impl.hpp b/irohad/consensus/yac/impl/yac_gate_impl.hpp index 2070befbe0..3b70fd834d 100644 --- a/irohad/consensus/yac/impl/yac_gate_impl.hpp +++ b/irohad/consensus/yac/impl/yac_gate_impl.hpp @@ -49,6 +49,11 @@ namespace iroha { std::shared_ptr block_loader, uint64_t delay); void vote(const shared_model::interface::Block &) override; + /** + * method called when commit recived + * assumes to retrieve a block eventually + * @return observable with the Block commited + */ rxcpp::observable> on_commit() override; diff --git a/test/module/irohad/consensus/yac/yac_gate_test.cpp b/test/module/irohad/consensus/yac/yac_gate_test.cpp index 613f25243c..d49c966bf5 100644 --- a/test/module/irohad/consensus/yac/yac_gate_test.cpp +++ b/test/module/irohad/consensus/yac/yac_gate_test.cpp @@ -200,3 +200,57 @@ TEST_F(YacGateTest, LoadBlockWhenDifferentCommit) { ASSERT_TRUE(gate_wrapper.validate()); } + +/** + * @given yac gate + * @when recives new commit different to the one it voted for + * @then polls nodes for the block with corresponding hash until it succeed, + * (reciving none on the first poll) + */ +TEST_F(YacGateTest, LoadBlockWhenDifferentCommitFailFirst) { + // Vote for block => receive different block => load committed block + + // make blocks + EXPECT_CALL(*block_creator, on_block()) + .WillOnce(Return(rxcpp::observable<>::just(expected_block))); + + // make hash from block + EXPECT_CALL(*hash_provider, makeHash(_)).WillOnce(Return(expected_hash)); + + // generate order of peers + EXPECT_CALL(*peer_orderer, getOrdering(_)) + .WillOnce(Return(ClusterOrdering::create({mk_peer("fake_node")}))); + + EXPECT_CALL(*hash_gate, vote(expected_hash, _)).Times(1); + + // expected values + expected_hash = YacHash("actual_proposal", "actual_block"); + + message.hash = expected_hash; + + commit_message = CommitMessage({message}); + expected_commit = rxcpp::observable<>::just(commit_message); + + // yac consensus + EXPECT_CALL(*hash_gate, on_commit()).WillOnce(Return(expected_commit)); + + // convert yac hash to model hash + EXPECT_CALL(*hash_provider, toModelHash(expected_hash)) + .WillOnce(Return(expected_block->hash())); + + // load block + auto sig = expected_block->signatures().begin(); + auto &pubkey = (*sig)->publicKey(); + EXPECT_CALL(*block_loader, retrieveBlock(pubkey, expected_block->hash())) + .WillOnce(Return(boost::none)) + .WillOnce(Return(expected_block)); + + init(); + + // verify that yac gate emit expected block + auto gate_wrapper = make_test_subscriber(gate->on_commit(), 1); + gate_wrapper.subscribe( + [this](auto block) { ASSERT_EQ(*block, *expected_block); }); + + ASSERT_TRUE(gate_wrapper.validate()); +} From 2181d9e351bccf26e627f717d8f03d6c86210e29 Mon Sep 17 00:00:00 2001 From: Nikolay Yushkevich Date: Fri, 20 Apr 2018 15:45:05 +0300 Subject: [PATCH 049/110] =?UTF-8?q?One=20small=20step=20for=20Iroha=20?= =?UTF-8?q?=E2=80=94=20one=20giant=20transaction=20for=20a=20client=20(#12?= =?UTF-8?q?52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add gRPC params for message limit (MAX_INT) Signed-off-by: Nikolay Yushkevich * Add template function Signed-off-by: Nikolay Yushkevich * Add newline Signed-off-by: Nikolay Yushkevich * Change query client Signed-off-by: Nikolay Yushkevich * Update test and field validator Signed-off-by: Nikolay Yushkevich * Correct code after review - remove unnecessary test - correct typo - change JIRA link Signed-off-by: Nikolay Yushkevich * Correct code after review - reorder imports - correct typo Signed-off-by: Nikolay Yushkevich --- .../yac/transport/impl/network_impl.cpp | 5 +- irohad/main/server_runner.cpp | 4 ++ irohad/network/impl/block_loader_impl.cpp | 4 +- irohad/network/impl/grpc_channel_builder.hpp | 47 +++++++++++++++ .../impl/ordering_gate_transport_grpc.cpp | 5 +- .../impl/ordering_service_transport_grpc.cpp | 7 +-- irohad/torii/command_client.cpp | 6 +- irohad/torii/query_client.cpp | 7 ++- test/integration/acceptance/tx_heavy_data.cpp | 58 ++++++------------- 9 files changed, 87 insertions(+), 56 deletions(-) create mode 100644 irohad/network/impl/grpc_channel_builder.hpp diff --git a/irohad/consensus/yac/transport/impl/network_impl.cpp b/irohad/consensus/yac/transport/impl/network_impl.cpp index 2235d07e7e..fef94eb2b4 100644 --- a/irohad/consensus/yac/transport/impl/network_impl.cpp +++ b/irohad/consensus/yac/transport/impl/network_impl.cpp @@ -24,6 +24,7 @@ #include "consensus/yac/transport/yac_pb_converters.hpp" #include "interfaces/common_objects/peer.hpp" #include "logger/logger.hpp" +#include "network/impl/grpc_channel_builder.hpp" namespace iroha { namespace consensus { @@ -154,8 +155,8 @@ namespace iroha { void NetworkImpl::createPeerConnection( const shared_model::interface::Peer &peer) { if (peers_.count(peer.address()) == 0) { - peers_[peer.address()] = proto::Yac::NewStub(grpc::CreateChannel( - peer.address(), grpc::InsecureChannelCredentials())); + peers_[peer.address()] = + network::createClient(peer.address()); } } diff --git a/irohad/main/server_runner.cpp b/irohad/main/server_runner.cpp index 0b40f3a8a7..110f8ea11e 100644 --- a/irohad/main/server_runner.cpp +++ b/irohad/main/server_runner.cpp @@ -44,6 +44,10 @@ iroha::expected::Result ServerRunner::run() { builder.RegisterService(service.get()); } + // in order to bypass built-it limitation of gRPC message size + builder.SetMaxReceiveMessageSize(INT_MAX); + builder.SetMaxSendMessageSize(INT_MAX); + serverInstance_ = builder.BuildAndStart(); serverInstanceCV_.notify_one(); diff --git a/irohad/network/impl/block_loader_impl.cpp b/irohad/network/impl/block_loader_impl.cpp index 6557b7986a..90203580f4 100644 --- a/irohad/network/impl/block_loader_impl.cpp +++ b/irohad/network/impl/block_loader_impl.cpp @@ -22,6 +22,7 @@ #include "backend/protobuf/block.hpp" #include "builders/protobuf/transport_builder.hpp" #include "interfaces/common_objects/peer.hpp" +#include "network/impl/grpc_channel_builder.hpp" using namespace iroha::ametsuchi; using namespace iroha::network; @@ -160,8 +161,7 @@ proto::Loader::Stub &BlockLoaderImpl::getPeerStub( it = peer_connections_ .insert(std::make_pair( peer.address(), - proto::Loader::NewStub(grpc::CreateChannel( - peer.address(), grpc::InsecureChannelCredentials())))) + network::createClient(peer.address()))) .first; } return *it->second; diff --git a/irohad/network/impl/grpc_channel_builder.hpp b/irohad/network/impl/grpc_channel_builder.hpp new file mode 100644 index 0000000000..7b5f524776 --- /dev/null +++ b/irohad/network/impl/grpc_channel_builder.hpp @@ -0,0 +1,47 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IROHA_GRPC_CHANNEL_BUILDER_HPP +#define IROHA_GRPC_CHANNEL_BUILDER_HPP + +#include + +namespace iroha { + namespace network { + + /** + * Creates client which is capable of sending and receiving + * messages of INT_MAX bytes size + * @tparam T type for gRPC stub, e.g. proto::Yac + * @param address ip address for connection, ipv4:port + * @return gRPC stub of parametrized type + */ + template + auto createClient(const grpc::string& address) { + // in order to bypass built-in limitation of gRPC message size + grpc::ChannelArguments args; + args.SetMaxSendMessageSize(INT_MAX); + args.SetMaxReceiveMessageSize(INT_MAX); + + return + T::NewStub(grpc::CreateCustomChannel( + address, grpc::InsecureChannelCredentials(), args)); + } + } // namespace network +} // namespace iroha + +#endif // IROHA_GRPC_CHANNEL_BUILDER_HPP diff --git a/irohad/ordering/impl/ordering_gate_transport_grpc.cpp b/irohad/ordering/impl/ordering_gate_transport_grpc.cpp index f07eddd43d..15364dc778 100644 --- a/irohad/ordering/impl/ordering_gate_transport_grpc.cpp +++ b/irohad/ordering/impl/ordering_gate_transport_grpc.cpp @@ -19,6 +19,7 @@ #include "backend/protobuf/transaction.hpp" #include "builders/protobuf/proposal.hpp" #include "interfaces/common_objects/types.hpp" +#include "network/impl/grpc_channel_builder.hpp" using namespace iroha::ordering; @@ -54,8 +55,8 @@ OrderingGateTransportGrpc::OrderingGateTransportGrpc( const std::string &server_address) : network::AsyncGrpcClient( logger::log("OrderingGate")), - client_(proto::OrderingServiceTransportGrpc::NewStub(grpc::CreateChannel( - server_address, grpc::InsecureChannelCredentials()))) {} + client_(network::createClient( + server_address)) {} void OrderingGateTransportGrpc::propagateTransaction( std::shared_ptr transaction) { diff --git a/irohad/ordering/impl/ordering_service_transport_grpc.cpp b/irohad/ordering/impl/ordering_service_transport_grpc.cpp index ea1c72eb2c..7092ff53dc 100644 --- a/irohad/ordering/impl/ordering_service_transport_grpc.cpp +++ b/irohad/ordering/impl/ordering_service_transport_grpc.cpp @@ -18,6 +18,7 @@ #include "backend/protobuf/transaction.hpp" #include "builders/protobuf/proposal.hpp" +#include "network/impl/grpc_channel_builder.hpp" using namespace iroha::ordering; @@ -49,15 +50,13 @@ void OrderingServiceTransportGrpc::publishProposal( std::unordered_map> peers_map; - for (const auto &peer : peers) { - peers_map[peer] = proto::OrderingGateTransportGrpc::NewStub( - grpc::CreateChannel(peer, grpc::InsecureChannelCredentials())); + peers_map[peer] = + network::createClient(peer); } for (const auto &peer : peers_map) { auto call = new AsyncClientCall; - auto proto = static_cast(proposal.get()); log_->debug("Publishing proposal: '{}'", proto->getTransport().DebugString()); diff --git a/irohad/torii/command_client.cpp b/irohad/torii/command_client.cpp index be4f1b7294..ce9aa2b418 100644 --- a/irohad/torii/command_client.cpp +++ b/irohad/torii/command_client.cpp @@ -16,6 +16,7 @@ limitations under the License. #include #include "block.pb.h" +#include "network/impl/grpc_channel_builder.hpp" #include "torii/command_client.hpp" namespace torii { @@ -26,9 +27,8 @@ namespace torii { CommandSyncClient::CommandSyncClient(const std::string &ip, size_t port) : ip_(ip), port_(port), - stub_(iroha::protocol::CommandService::NewStub( - grpc::CreateChannel(ip + ":" + std::to_string(port), - grpc::InsecureChannelCredentials()))) {} + stub_(iroha::network::createClient( + ip + ":" + std::to_string(port))) {} CommandSyncClient::CommandSyncClient(const CommandSyncClient &rhs) : CommandSyncClient(rhs.ip_, rhs.port_) {} diff --git a/irohad/torii/query_client.cpp b/irohad/torii/query_client.cpp index 8e8da6a1e4..1f480c089a 100644 --- a/irohad/torii/query_client.cpp +++ b/irohad/torii/query_client.cpp @@ -13,6 +13,8 @@ limitations under the License. #include "torii/query_client.hpp" +#include "network/impl/grpc_channel_builder.hpp" + namespace torii_utils { using iroha::protocol::Query; @@ -21,9 +23,8 @@ namespace torii_utils { QuerySyncClient::QuerySyncClient(const std::string &ip, size_t port) : ip_(ip), port_(port), - stub_(iroha::protocol::QueryService::NewStub( - grpc::CreateChannel(ip + ":" + std::to_string(port), - grpc::InsecureChannelCredentials()))) {} + stub_(iroha::network::createClient( + ip + ":" + std::to_string(port))) {} QuerySyncClient::QuerySyncClient(const QuerySyncClient &rhs) : QuerySyncClient(rhs.ip_, rhs.port_) {} diff --git a/test/integration/acceptance/tx_heavy_data.cpp b/test/integration/acceptance/tx_heavy_data.cpp index 9a3afdee8b..20cd6da77f 100644 --- a/test/integration/acceptance/tx_heavy_data.cpp +++ b/test/integration/acceptance/tx_heavy_data.cpp @@ -111,33 +111,8 @@ class HeavyTransactionTest : public ::testing::Test { }; /** - * @given some user with all required permissions - * @when send tx with addAccountDetail with big, but stateless invalid data - * inside - * @then transaction is passed - */ -TEST_F(HeavyTransactionTest, OneLargeTx) { - IntegrationTestFramework() - .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms()) - .skipProposal() - .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) - // "foo" transactions will not be passed because it has large size into - // one field - 5Mb per one set - .sendTx(complete(setAcountDetailTx("foo", generateData(5 * 1024 * 1024))), - [](const auto &status) { - ASSERT_TRUE(boost::apply_visitor( - shared_model::interface::SpecifiedVisitor< - shared_model::interface::StatelessFailedTxResponse>(), - status.get())); - }) - .done(); -} - -/** - * NOTE: test is disabled until fix of - * https://soramitsu.atlassian.net/browse/IR-1205 will not be completed. + * TODO: refactor the test when all stability issues are fixed + * IR-1264 20/04/2018 neewy * @given some user with all required permissions * @when send many txes with addAccountDetail with large data inside * @then transaction have been passed @@ -162,39 +137,42 @@ TEST_F(HeavyTransactionTest, DISABLED_ManyLargeTxes) { } /** - * NOTE: test is disabled until fix of - * https://soramitsu.atlassian.net/browse/IR-1205 will not be completed. * @given some user with all required permissions * @when send tx with many addAccountDetails with large data inside * @then transaction is passed */ -TEST_F(HeavyTransactionTest, DISABLED_VeryLargeTxWithManyCommands) { +TEST_F(HeavyTransactionTest, VeryLargeTxWithManyCommands) { auto big_data = generateData(3 * 1024 * 1024); auto large_tx_builder = setAcountDetailTx("foo_1", big_data) .setAccountDetail(kUserId, "foo_2", big_data) .setAccountDetail(kUserId, "foo_3", big_data); - IntegrationTestFramework() - .setInitialState(kAdminKeypair) + IntegrationTestFramework itf; + itf.setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) - // in itf tx build from large_tx_build will pass in Torii but in - // production the transaction will be failed before stateless validation - // because of size. + // in itf tx build from large_tx_build will pass in Torii but + // in production the transaction will be failed before + // stateless validation because of size. .sendTx(complete(large_tx_builder)) .skipProposal() .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) - .done(); + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); + // this sleep method is a temporary work-around + // because BlockLoaderImpl Failed to retrieve top block + // TODO: IR-1264 neewy 19/04/2018 + std::this_thread::sleep_for(std::chrono::seconds(10)); + itf.done(); } /** - * NOTE: test is disabled until fix of - * https://soramitsu.atlassian.net/browse/IR-1205 will not be completed. + * TODO: disabled until proposal process time in simulator is not optimized + * and the test freezes (on a proposal verification stage) + * IR-1264 20/04/2018 neewy * @given some user with all required permissions * AND max proposal size is 1. * @when send txes with addAccountDetail with large data inside. * AND transactions are passed stateful validation - * @then query executed sucessfully + * @then query executed successfully */ TEST_F(HeavyTransactionTest, DISABLED_QueryLargeData) { auto number_of_times = 15u; From a5c3c6efb56393f30699554f187430af0cf44dac Mon Sep 17 00:00:00 2001 From: kamilsa Date: Sat, 21 Apr 2018 19:34:39 +0300 Subject: [PATCH 050/110] Fix permission bug (#1229) * Fix permission bug Signed-off-by: kamilsa * Fix counters Signed-off-by: kamilsa --- example/genesis.block | 10 +- example/python/tx-example.py | 95 ++++++++++++++++--- irohad/execution/impl/command_executor.cpp | 10 +- .../converters/impl/pb_command_factory.cpp | 20 ++-- schema/primitive.proto | 10 +- shared_model/validators/permissions.hpp | 30 +++--- .../model/command_validate_execute_test.cpp | 36 +++---- 7 files changed, 138 insertions(+), 73 deletions(-) diff --git a/example/genesis.block b/example/genesis.block index 004f42d54a..464d26bd50 100644 --- a/example/genesis.block +++ b/example/genesis.block @@ -46,11 +46,11 @@ "can_get_my_account", "can_get_my_signatories", "can_get_my_txs", - "can_grant_can_add_signatory", - "can_grant_can_remove_signatory", - "can_grant_can_set_detail", - "can_grant_can_set_quorum", - "can_grant_can_transfer", + "can_grant_can_add_my_signatory", + "can_grant_can_remove_my_signatory", + "can_grant_can_set_my_account_detail", + "can_grant_can_set_my_quorum", + "can_grant_can_transfer_my_assets", "can_receive", "can_remove_signatory", "can_set_quorum", diff --git a/example/python/tx-example.py b/example/python/tx-example.py index 0b80857287..10c310d03a 100644 --- a/example/python/tx-example.py +++ b/example/python/tx-example.py @@ -20,9 +20,13 @@ admin_pub = open("../admin@test.pub", "r").read() key_pair = crypto.convertFromExisting(admin_pub, admin_priv) +user1_kp = crypto.generateKeypair() + current_time = int(round(time.time() * 1000)) - 10**5 creator = "admin@test" +query_counter = 1 + def get_status(tx): # Create status request @@ -114,7 +118,10 @@ def send_query(query, key_pair): return query_response -def tx1(): +def create_asset_coin(): + """ + Create domain "domain" and asset "coin#domain" with precision 2 + """ tx = tx_builder.creatorAccountId(creator) \ .createdTime(current_time) \ .createDomain("domain", "user") \ @@ -124,7 +131,10 @@ def tx1(): print_status_streaming(tx) -def tx2(): +def add_coin_to_admin(): + """ + Add 1000.00 asset quantity of asset coin to admin + """ tx = tx_builder.creatorAccountId(creator) \ .createdTime(current_time) \ .addAssetQuantity("admin@test", "coin#domain", "1000.00").build() @@ -133,9 +143,10 @@ def tx2(): print_status_streaming(tx) -def tx3(): - user1_kp = crypto.generateKeypair() - +def create_account_userone(): + """ + Create account "userone@domain" + """ tx = tx_builder.creatorAccountId(creator) \ .createdTime(current_time) \ .createAccount("userone", "domain", user1_kp.publicKey()).build() @@ -143,8 +154,10 @@ def tx3(): send_tx(tx, key_pair) print_status_streaming(tx) - -def tx4(): +def transfer_coin_from_admin_to_userone(): + """ + Transfer 2.00 of coin from admin@test to userone@domain + """ tx = tx_builder.creatorAccountId(creator) \ .createdTime(current_time) \ .transferAsset("admin@test", "userone@domain", "coin#domain", "Some message", "2.00").build() @@ -152,11 +165,39 @@ def tx4(): send_tx(tx, key_pair) print_status_streaming(tx) +def grant_admin_to_add_detail_to_userone(): + """ + Grant admin@test to be able to set details information to userone@domain + """ + tx = tx_builder.creatorAccountId("userone@domain") \ + .createdTime(current_time) \ + .grantPermission(creator, "can_set_my_account_detail") \ + .build() + + send_tx(tx, user1_kp) + print_status_streaming(tx) + +def set_age_to_userone_by_admin(): + """ + Set age to userone@domain by admin@test + """ + tx = tx_builder.creatorAccountId(creator) \ + .createdTime(current_time) \ + .setAccountDetail("userone@domain", "age", "18") \ + .build() + + send_tx(tx, key_pair) + print_status_streaming(tx) -def get_asset(): +def get_coin_info(): + """ + Get information about asset coin#domain + """ + global query_counter + query_counter += 1 query = query_builder.creatorAccountId(creator) \ .createdTime(current_time) \ - .queryCounter(1) \ + .queryCounter(query_counter) \ .getAssetInfo("coin#domain") \ .build() @@ -174,9 +215,14 @@ def get_asset(): def get_account_asset(): + """ + Get list of transactions done by userone@domain with asset coin#domain + """ + global query_counter + query_counter += 1 query = query_builder.creatorAccountId(creator) \ .createdTime(current_time) \ - .queryCounter(11) \ + .queryCounter(query_counter) \ .getAccountAssets("userone@domain", "coin#domain") \ .build() @@ -184,11 +230,30 @@ def get_account_asset(): print(query_response) +def get_userone_info(): + """ + Get userone's key value information + """ + global query_counter + query_counter += 1 + query = query_builder.creatorAccountId(creator) \ + .createdTime(current_time) \ + .queryCounter(query_counter) \ + .getAccountDetail("userone@domain") \ + .build() + + query_response = send_query(query, key_pair) + print(query_response.account_detail_response.detail) + + -tx1() -tx2() -tx3() -tx4() -get_asset() +create_asset_coin() +add_coin_to_admin() +create_account_userone() +transfer_coin_from_admin_to_userone() +grant_admin_to_add_detail_to_userone() +set_age_to_userone_by_admin() +get_coin_info() get_account_asset() +get_userone_info() print("done!") diff --git a/irohad/execution/impl/command_executor.cpp b/irohad/execution/impl/command_executor.cpp index 6170e524a2..bb790c483a 100644 --- a/irohad/execution/impl/command_executor.cpp +++ b/irohad/execution/impl/command_executor.cpp @@ -536,7 +536,7 @@ namespace iroha { (queries.hasAccountGrantablePermission( creator_account_id, command.accountId(), - shared_model::permissions::can_add_signatory)); + shared_model::permissions::can_add_my_signatory)); } bool CommandValidator::hasPermissions( @@ -625,7 +625,7 @@ namespace iroha { or (queries.hasAccountGrantablePermission( creator_account_id, command.accountId(), - shared_model::permissions::can_remove_signatory)); + shared_model::permissions::can_remove_my_signatory)); } bool CommandValidator::hasPermissions( @@ -647,7 +647,7 @@ namespace iroha { queries.hasAccountGrantablePermission( creator_account_id, command.accountId(), - shared_model::permissions::can_set_detail); + shared_model::permissions::can_set_my_account_detail); } bool CommandValidator::hasPermissions( @@ -665,7 +665,7 @@ namespace iroha { or (queries.hasAccountGrantablePermission( creator_account_id, command.accountId(), - shared_model::permissions::can_set_quorum)); + shared_model::permissions::can_set_my_quorum)); } bool CommandValidator::hasPermissions( @@ -689,7 +689,7 @@ namespace iroha { and queries.hasAccountGrantablePermission( creator_account_id, command.srcAccountId(), - shared_model::permissions::can_transfer)) + shared_model::permissions::can_transfer_my_assets)) or // 2. Creator transfer from their account (creator_account_id == command.srcAccountId() diff --git a/irohad/model/converters/impl/pb_command_factory.cpp b/irohad/model/converters/impl/pb_command_factory.cpp index 9d1fbd1818..e8f7bcf363 100644 --- a/irohad/model/converters/impl/pb_command_factory.cpp +++ b/irohad/model/converters/impl/pb_command_factory.cpp @@ -120,20 +120,20 @@ namespace iroha { (protocol::RolePermission::can_get_all_txs, can_get_all_txs) // Can grant set quorum - (protocol::RolePermission::can_grant_can_set_quorum, - can_grant + can_set_quorum) + (protocol::RolePermission::can_grant_can_set_my_quorum, + can_grant + can_set_my_quorum) // Can grant add signatory - (protocol::RolePermission::can_grant_can_add_signatory, - can_grant + can_add_signatory) + (protocol::RolePermission::can_grant_can_add_my_signatory, + can_grant + can_add_my_signatory) // Can grant remove signatory - (protocol::RolePermission::can_grant_can_remove_signatory, - can_grant + can_remove_signatory) + (protocol::RolePermission::can_grant_can_remove_my_signatory, + can_grant + can_remove_my_signatory) // Can grant can_transfer - (protocol::RolePermission::can_grant_can_transfer, - can_grant + can_transfer) + (protocol::RolePermission::can_grant_can_transfer_my_assets, + can_grant + can_transfer_my_assets) // Can write details to other accounts - (protocol::RolePermission::can_grant_can_set_detail, - can_grant + can_set_detail); + (protocol::RolePermission::can_grant_can_set_my_account_detail, + can_grant + can_set_my_account_detail); boost::assign::insert(pb_grant_map_) // Can add my signatory diff --git a/schema/primitive.proto b/schema/primitive.proto index 4f226b9f5d..cc2355221f 100644 --- a/schema/primitive.proto +++ b/schema/primitive.proto @@ -65,11 +65,11 @@ enum RolePermission { can_get_all_txs = 36; // Grant permissions - can_grant_can_set_quorum = 37; - can_grant_can_add_signatory = 38; - can_grant_can_remove_signatory = 39; - can_grant_can_transfer = 40; - can_grant_can_set_detail = 41; + can_grant_can_set_my_quorum = 37; + can_grant_can_add_my_signatory = 38; + can_grant_can_remove_my_signatory = 39; + can_grant_can_transfer_my_assets = 40; + can_grant_can_set_my_account_detail = 41; } enum GrantablePermission { diff --git a/shared_model/validators/permissions.hpp b/shared_model/validators/permissions.hpp index 8c3e1281ae..876f89a610 100644 --- a/shared_model/validators/permissions.hpp +++ b/shared_model/validators/permissions.hpp @@ -145,11 +145,11 @@ namespace shared_model { /* Grantable permissions */ const std::string can_grant = "can_grant_"; - const std::set grant_group = {can_grant + can_set_quorum, - can_grant + can_add_signatory, - can_grant + can_remove_signatory, - can_grant + can_transfer, - can_grant + can_set_detail}; + const std::set grant_group = {can_grant + can_set_my_quorum, + can_grant + can_add_my_signatory, + can_grant + can_remove_my_signatory, + can_grant + can_transfer_my_assets, + can_grant + can_set_my_account_detail}; const std::set edit_self_group = { can_set_quorum, can_add_signatory, can_remove_signatory}; @@ -195,11 +195,11 @@ namespace shared_model { can_get_domain_acc_ast_txs, can_get_my_txs, can_get_all_txs, - can_grant + can_set_quorum, - can_grant + can_add_signatory, - can_grant + can_remove_signatory, - can_grant + can_transfer, - can_grant + can_set_detail}; + can_grant + can_set_my_quorum, + can_grant + can_add_my_signatory, + can_grant + can_remove_my_signatory, + can_grant + can_transfer_my_assets, + can_grant + can_set_my_account_detail}; /* All permissions */ const std::set all_perm_group = { @@ -240,11 +240,11 @@ namespace shared_model { can_get_domain_acc_ast_txs, can_get_my_txs, can_get_all_txs, - can_grant + can_set_quorum, - can_grant + can_add_signatory, - can_grant + can_remove_signatory, - can_grant + can_transfer, - can_grant + can_set_detail, + can_grant + can_set_my_quorum, + can_grant + can_add_my_signatory, + can_grant + can_remove_my_signatory, + can_grant + can_transfer_my_assets, + can_grant + can_set_my_account_detail, // TODO: IR 1190 kamilsa 30.03.2018 move permissions below to separated group can_add_my_signatory, can_remove_my_signatory, diff --git a/test/module/irohad/model/command_validate_execute_test.cpp b/test/module/irohad/model/command_validate_execute_test.cpp index f0de843127..f4b35a5b64 100644 --- a/test/module/irohad/model/command_validate_execute_test.cpp +++ b/test/module/irohad/model/command_validate_execute_test.cpp @@ -578,7 +578,7 @@ TEST_F(AddSignatoryTest, ValidWhenCreatorHasPermissions) { // Creator has role permissions to add signatory EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_signatory)) + admin_id, add_signatory->account_id, can_add_my_signatory)) .WillOnce(Return(true)); EXPECT_CALL( *wsv_command, @@ -620,7 +620,7 @@ TEST_F(AddSignatoryTest, InvalidWhenNoPermissions) { // Creator has no permission EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_signatory)) + admin_id, add_signatory->account_id, can_add_my_signatory)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); } @@ -631,7 +631,7 @@ TEST_F(AddSignatoryTest, InvalidWhenNoAccount) { EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_signatory)) + admin_id, add_signatory->account_id, can_add_my_signatory)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); } @@ -640,7 +640,7 @@ TEST_F(AddSignatoryTest, InvalidWhenSameKey) { // Add same signatory EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_signatory)) + admin_id, add_signatory->account_id, can_add_my_signatory)) .WillOnce(Return(true)); add_signatory->pubkey.fill(2); EXPECT_CALL( @@ -876,7 +876,7 @@ TEST_F(RemoveSignatoryTest, ValidWhenMultipleKeys) { EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) @@ -904,7 +904,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenSingleKey) { EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) @@ -934,7 +934,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissions) { // Add same signatory EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); @@ -944,7 +944,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoKey) { // Remove signatory not present in account EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(true)); remove_signatory->pubkey.fill(0xF); @@ -966,7 +966,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoKey) { TEST_F(RemoveSignatoryTest, InvalidWhenNoAccount) { EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) @@ -987,7 +987,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoAccount) { TEST_F(RemoveSignatoryTest, InvalidWhenNoSignatories) { EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) @@ -1008,7 +1008,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoSignatories) { TEST_F(RemoveSignatoryTest, InvalidWhenNoAccountAndSignatories) { EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_signatory)) + admin_id, remove_signatory->account_id, can_remove_my_signatory)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) @@ -1035,7 +1035,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissionToRemoveFromSelf) { .WillOnce(Return(std::vector{admin_role})); EXPECT_CALL( *wsv_query, - hasAccountGrantablePermission(admin_id, admin_id, can_remove_signatory)) + hasAccountGrantablePermission(admin_id, admin_id, can_remove_my_signatory)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); @@ -1084,7 +1084,7 @@ TEST_F(SetQuorumTest, ValidWhenCreatorHasPermissions) { // Creator is admin EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, set_quorum->account_id, can_set_quorum)) + admin_id, set_quorum->account_id, can_set_my_quorum)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccount(set_quorum->account_id)) @@ -1120,7 +1120,7 @@ TEST_F(SetQuorumTest, InvalidWhenNoPermissions) { // Creator has no permissions EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, set_quorum->account_id, can_set_quorum)) + admin_id, set_quorum->account_id, can_set_my_quorum)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); @@ -1131,7 +1131,7 @@ TEST_F(SetQuorumTest, InvalidWhenNoAccount) { set_quorum->account_id = "noacc"; EXPECT_CALL(*wsv_query, hasAccountGrantablePermission( - admin_id, set_quorum->account_id, can_set_quorum)) + admin_id, set_quorum->account_id, can_set_my_quorum)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); @@ -1556,7 +1556,7 @@ TEST_F(TransferAssetTest, InvalidWhenCreatorHasNoPermission) { transfer_asset->src_account_id = account_id; transfer_asset->dest_account_id = admin_id; EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission(admin_id, account_id, can_transfer)) + hasAccountGrantablePermission(admin_id, account_id, can_transfer_my_assets)) .WillOnce(Return(false)); ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); } @@ -1566,7 +1566,7 @@ TEST_F(TransferAssetTest, ValidWhenCreatorHasPermission) { transfer_asset->src_account_id = account_id; transfer_asset->dest_account_id = admin_id; EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission(admin_id, account_id, can_transfer)) + hasAccountGrantablePermission(admin_id, account_id, can_transfer_my_assets)) .WillOnce(Return(true)); EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) @@ -1958,7 +1958,7 @@ class SetAccountDetailTest : public CommandValidateExecuteTest { role_permissions = {can_set_quorum}; } std::shared_ptr cmd; - std::string needed_permission = can_set_detail; + std::string needed_permission = can_set_my_account_detail; }; /** From 61969d20d1e8d71c60f4417fe271c30cf2d6dce4 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Sun, 22 Apr 2018 10:55:16 +0300 Subject: [PATCH 051/110] [WIP] Fix artifacts uploading on unsuccessful build (#1233) Fix artifacts uploading on unsuccessful build --- .jenkinsci/linux-post-step.groovy | 2 +- Jenkinsfile | 42 +++++++++++++++---------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/.jenkinsci/linux-post-step.groovy b/.jenkinsci/linux-post-step.groovy index c4c9f13886..3d27278b8d 100644 --- a/.jenkinsci/linux-post-step.groovy +++ b/.jenkinsci/linux-post-step.groovy @@ -1,7 +1,7 @@ def linuxPostStep() { timeout(time: 600, unit: "SECONDS") { try { - if (currentBuild.result != "UNSTABLE" && BRANCH_NAME ==~ /(master|develop)/) { + if (currentBuild.currentResult == "SUCCESS" && BRANCH_NAME ==~ /(master|develop)/) { def artifacts = load ".jenkinsci/artifacts.groovy" def commit = env.GIT_COMMIT def platform = sh(script: 'uname -m', returnStdout: true).trim() diff --git a/Jenkinsfile b/Jenkinsfile index 7975707397..13097fbc79 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -218,7 +218,7 @@ pipeline { """ def testExitCode = sh(script: 'IROHA_POSTGRES_HOST=localhost IROHA_POSTGRES_PORT=5433 cmake --build build --target test', returnStatus: true) if (testExitCode != 0) { - currentBuild.result = "UNSTABLE" + currentBuild.currentResult = "UNSTABLE" } if ( coverageEnabled ) { sh "cmake --build build --target cppcheck" @@ -248,23 +248,21 @@ pipeline { always { script { timeout(time: 600, unit: "SECONDS") { - if (currentBuild.result != "UNSTABLE") { - if (BRANCH_NAME ==~ /(master|develop)/) { - try { - def artifacts = load ".jenkinsci/artifacts.groovy" - def commit = env.GIT_COMMIT - filePaths = [ '\$(pwd)/build/*.tar.gz' ] - artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) - } - finally { - cleanWs() - sh """ - pg_ctl -D /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ stop && \ - rm -rf /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ - """ - } + try { + if (currentBuild.currentResult == "SUCCESS" && BRANCH_NAME ==~ /(master|develop)/) { + def artifacts = load ".jenkinsci/artifacts.groovy" + def commit = env.GIT_COMMIT + filePaths = [ '\$(pwd)/build/*.tar.gz' ] + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) } } + finally { + cleanWs() + sh """ + pg_ctl -D /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ stop && \ + rm -rf /var/jenkins/${GIT_COMMIT}-${BUILD_NUMBER}/ + """ + } } } } @@ -346,17 +344,17 @@ pipeline { always { script { timeout(time: 600, unit: "SECONDS") { - if (BRANCH_NAME ==~ /(master|develop)/) { - try { + try { + if (currentBuild.currentResult == "SUCCESS" && BRANCH_NAME ==~ /(master|develop)/) { def artifacts = load ".jenkinsci/artifacts.groovy" def commit = env.GIT_COMMIT filePaths = [ '\$(pwd)/build/*.tar.gz' ] - artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) - } - finally { - cleanWs() + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) } } + finally { + cleanWs() + } } } } From c7489139ca52101024377c61ac230b9b9ba3e72e Mon Sep 17 00:00:00 2001 From: Moonraker Date: Thu, 19 Apr 2018 14:28:23 +0700 Subject: [PATCH 052/110] Use hex-encoded query hashes instead of binary hashes Signed-off-by: Moonraker --- .../converters/impl/pb_query_response_factory.cpp | 2 +- irohad/torii/impl/query_service.cpp | 2 +- schema/responses.proto | 2 +- .../query_responses/proto_query_response.hpp | 13 +++++++------ .../builder_templates/query_response_template.hpp | 2 +- .../shared_proto_query_responses_test.cpp | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/irohad/model/converters/impl/pb_query_response_factory.cpp b/irohad/model/converters/impl/pb_query_response_factory.cpp index 02ae58224c..80f288e432 100644 --- a/irohad/model/converters/impl/pb_query_response_factory.cpp +++ b/irohad/model/converters/impl/pb_query_response_factory.cpp @@ -84,7 +84,7 @@ namespace iroha { } if (response) { - response->set_query_hash(query_response->query_hash.to_string()); + response->set_query_hash(query_response->query_hash.to_hexstring()); } return response; } diff --git a/irohad/torii/impl/query_service.cpp b/irohad/torii/impl/query_service.cpp index cc712b56e5..ec6db792fe 100644 --- a/irohad/torii/impl/query_service.cpp +++ b/irohad/torii/impl/query_service.cpp @@ -74,7 +74,7 @@ namespace torii { [&hash, &response](const iroha::expected::Error &error) { response.set_query_hash( - shared_model::crypto::toBinaryString(hash)); + hash.hex()); response.mutable_error_response()->set_reason( iroha::protocol::ErrorResponse::STATELESS_INVALID); response.mutable_error_response()->set_message(std::move(error.error)); diff --git a/schema/responses.proto b/schema/responses.proto index aeea59037d..2818f8c19b 100644 --- a/schema/responses.proto +++ b/schema/responses.proto @@ -90,5 +90,5 @@ message QueryResponse { RolesResponse roles_response = 8; RolePermissionsResponse role_permissions_response = 9; } - bytes query_hash = 10; + string query_hash = 10; } diff --git a/shared_model/backend/protobuf/query_responses/proto_query_response.hpp b/shared_model/backend/protobuf/query_responses/proto_query_response.hpp index f41a55f3c1..a7b626e5f2 100644 --- a/shared_model/backend/protobuf/query_responses/proto_query_response.hpp +++ b/shared_model/backend/protobuf/query_responses/proto_query_response.hpp @@ -39,10 +39,9 @@ template auto loadQueryResponse(Archive &&ar) { int which = ar.GetDescriptor()->FindFieldByNumber(ar.response_case())->index(); - return shared_model::detail::variant_impl:: - template load(std::forward(ar), - which); + return shared_model::detail::variant_impl::template load< + shared_model::interface::QueryResponse::QueryResponseVariantType>( + std::forward(ar), which); } namespace shared_model { @@ -97,8 +96,10 @@ namespace shared_model { return loadQueryResponse(*proto_); }}; - const Lazy hash_{ - [this] { return interface::types::HashType(proto_->query_hash()); }}; + const Lazy hash_{[this] { + return interface::types::HashType( + iroha::hexstringToBytestring(proto_->query_hash()).get()); + }}; }; } // namespace proto } // namespace shared_model diff --git a/shared_model/builders/protobuf/builder_templates/query_response_template.hpp b/shared_model/builders/protobuf/builder_templates/query_response_template.hpp index 048268d768..6aa808fda4 100644 --- a/shared_model/builders/protobuf/builder_templates/query_response_template.hpp +++ b/shared_model/builders/protobuf/builder_templates/query_response_template.hpp @@ -205,7 +205,7 @@ namespace shared_model { auto queryHash(const interface::types::HashType &query_hash) const { return transform([&](auto &proto_query_response) { proto_query_response.set_query_hash( - crypto::toBinaryString(query_hash)); + query_hash.hex()); }); } diff --git a/test/module/shared_model/backend_proto/shared_proto_query_responses_test.cpp b/test/module/shared_model/backend_proto/shared_proto_query_responses_test.cpp index 4e5d7bf091..359fc0be63 100644 --- a/test/module/shared_model/backend_proto/shared_proto_query_responses_test.cpp +++ b/test/module/shared_model/backend_proto/shared_proto_query_responses_test.cpp @@ -30,7 +30,7 @@ TEST(QueryResponse, QueryResponseLoad) { iroha::protocol::QueryResponse response; const std::string hash = "123"; - response.set_query_hash(hash); + response.set_query_hash(iroha::bytestringToHexstring(hash)); auto refl = response.GetReflection(); auto desc = response.GetDescriptor(); auto resp_status = desc->FindOneofByName("response"); @@ -54,7 +54,7 @@ TEST(QueryResponse, QueryResponseLoad) { TEST(QueryResponse, ErrorResponseLoad) { iroha::protocol::QueryResponse response; const std::string hash = "123"; - response.set_query_hash(hash); + response.set_query_hash(iroha::bytestringToHexstring(hash)); auto error_resp = response.mutable_error_response(); auto refl = error_resp->GetReflection(); auto desc = error_resp->GetDescriptor(); From 4a133776703260ae6fcb9d16b20c0a0ce8b4c915 Mon Sep 17 00:00:00 2001 From: srcmake <34385198+srcmake@users.noreply.github.com> Date: Mon, 23 Apr 2018 15:11:44 -0400 Subject: [PATCH 053/110] Fix the reStructureTest URL in docs/README.md. (#1265) Add http:// to the url in the first paragraph. Remove excess to to correct grammar. [ci skip] Signed-off-by: srcmake --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 7883d2e54a..a57bff90f7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # Iroha reStructuredTest documentation -The purpose of this documentation is to convey design and architecture aspects of Iroha ledger in a structured approach, as well as operational side: how-tos, guides, and examples. Docs are accessible via ReadTheDocs website, and can be generated to a lot of formats, available in Sphinx. In order to contribute, one should to be familiar with [reStructuredTest](docutils.sourceforge.net/rst.html) syntax, and follow principles described in this file. +The purpose of this documentation is to convey design and architecture aspects of Iroha ledger in a structured approach, as well as operational side: how-tos, guides, and examples. Docs are accessible via ReadTheDocs website, and can be generated to a lot of formats, available in Sphinx. In order to contribute, one should be familiar with [reStructuredTest](http://docutils.sourceforge.net/rst.html) syntax, and follow principles described in this file. ## Principles From 14a852d98a19d1864bbd2e0eb1fd5e1144cee75b Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Tue, 24 Apr 2018 13:47:20 +0300 Subject: [PATCH 054/110] Fix bindings and Android package build (#1249) - UPDATE_COMMAND was supposedly doing an unnecessary reconfiguration and rebuild - SWIG_DIR was pointing to root instead of directory with swig.swg - Add swig dependency for target introduced in CMake 3.11 - Fix android-build.sh with new lines in sed - Fix empty dependency list handling; fix swig flags @luckychess - Set version as separate var in Findswig.cmake; use $HOME in example Signed-off-by: Andrei Lebedev --- cmake/Modules/Findswig.cmake | 8 ++++--- shared_model/bindings/CMakeLists.txt | 22 +++++++++++++++---- .../packages/android/android-build.sh | 10 ++++----- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/cmake/Modules/Findswig.cmake b/cmake/Modules/Findswig.cmake index 449a957902..e012686edf 100644 --- a/cmake/Modules/Findswig.cmake +++ b/cmake/Modules/Findswig.cmake @@ -8,8 +8,9 @@ find_package_handle_standard_args(SWIG DEFAULT_MSG if(NOT SWIG_EXECUTABLE) find_package(Git REQUIRED) - set(URL ftp://www.mirrorservice.org/sites/ftp.sourceforge.net/pub/sourceforge/s/sw/swig/swig/swig-3.0.12/swig-3.0.12.tar.gz) - set_target_description(swig "Simplified Wrapper and Interface Generator (SWIG)" ${URL} 3.0.12) + set(SWIG_VERSION 3.0.12) + set(URL ftp://www.mirrorservice.org/sites/ftp.sourceforge.net/pub/sourceforge/s/sw/swig/swig/swig-${SWIG_VERSION}/swig-${SWIG_VERSION}.tar.gz) + set_target_description(swig "Simplified Wrapper and Interface Generator (SWIG)" ${URL} ${SWIG_VERSION}) ExternalProject_Add(swig_swig URL ${URL} @@ -20,12 +21,13 @@ if(NOT SWIG_EXECUTABLE) BUILD_IN_SOURCE ON BUILD_COMMAND ${MAKE} swig TEST_COMMAND "" # remove test step + UPDATE_COMMAND "" # remove update step ) ExternalProject_Get_Property(swig_swig source_dir) # Predefined vars for local installed SWIG set(SWIG_EXECUTABLE ${source_dir}/swig) - set(SWIG_DIR ${source_dir}) + set(SWIG_DIR ${source_dir}/share/swig/${SWIG_VERSION}) add_dependencies(swig swig_swig) diff --git a/shared_model/bindings/CMakeLists.txt b/shared_model/bindings/CMakeLists.txt index 93cdc42011..213bed5777 100644 --- a/shared_model/bindings/CMakeLists.txt +++ b/shared_model/bindings/CMakeLists.txt @@ -41,6 +41,20 @@ if (SWIG_PYTHON OR SWIG_JAVA OR SWIG_CSHARP OR SWIG_NODE) set_property(GLOBAL PROPERTY SWIG_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) add_dependencies(bindings swig) + + macro (myswig_add_library target) + swig_add_library(${ARGV}) + # get internal dependencies + get_target_property(dependencies + ${SWIG_MODULE_${target}_REAL_NAME} + MANUALLY_ADDED_DEPENDENCIES) + if (dependencies) + # add external project dependency on internal targets + foreach (dependency IN LISTS dependencies) + add_dependencies(${dependency} swig) + endforeach() + endif() + endmacro() endif() if (SWIG_PYTHON) @@ -54,7 +68,7 @@ if (SWIG_PYTHON) set(MAC_OPTS "-flat_namespace -undefined suppress") endif() - swig_add_library(iroha LANGUAGE python SOURCES bindings.i) + myswig_add_library(iroha LANGUAGE python SOURCES bindings.i) swig_link_libraries(iroha ${Python_LIBRARIES} bindings ${MAC_OPTS}) add_custom_target(irohapy DEPENDS ${SWIG_MODULE_iroha_REAL_NAME}) # path to where Python.h is found @@ -66,7 +80,7 @@ endif() if (SWIG_JAVA) find_package(JNI REQUIRED) - swig_add_library(irohajava LANGUAGE java SOURCES bindings.i) + myswig_add_library(irohajava LANGUAGE java SOURCES bindings.i) swig_link_libraries(irohajava ${Java_LIBRARIES} bindings) # the include path to jni.h and jni_md.h target_include_directories(${SWIG_MODULE_irohajava_REAL_NAME} PUBLIC @@ -76,7 +90,7 @@ if (SWIG_JAVA) endif() if (SWIG_CSHARP) - swig_add_library(libirohacs LANGUAGE csharp SOURCES bindings.i) + myswig_add_library(libirohacs LANGUAGE csharp SOURCES bindings.i) swig_link_libraries(libirohacs bindings) add_custom_target(irohacs DEPENDS ${SWIG_MODULE_libirohacs_REAL_NAME}) endif() @@ -99,7 +113,7 @@ if (SWIG_NODE) set_property(SOURCE bindings.i PROPERTY SWIG_FLAGS "-node" "-DV8_VERSION=${V8_VERSION_HEX}") # Build SWIG library always statically for the subsequent assembly by GYP - swig_add_library(irohanode + myswig_add_library(irohanode TYPE STATIC LANGUAGE javascript SOURCES bindings.i diff --git a/shared_model/packages/android/android-build.sh b/shared_model/packages/android/android-build.sh index a7f1caca92..e6359c87cc 100755 --- a/shared_model/packages/android/android-build.sh +++ b/shared_model/packages/android/android-build.sh @@ -7,7 +7,7 @@ fi if [[ ( "$#" -ne 4 ) && ( "$#" -ne 5 ) ]]; then echo "Illegal number of parameters" echo "Usage: $0 [BUILD_TYPE=Release]" - echo "Example: $0 arm64-v8a 26 /Users/me/Downloads/android-ndk-r16b jp.co.soramitsu.iroha.android Debug" + echo "Example: $0 arm64-v8a 26 $HOME/Downloads/android-ndk-r16b jp.co.soramitsu.iroha.android Debug" exit 1 fi @@ -99,10 +99,10 @@ VERBOSE=1 cmake --build ./iroha-ed25519/build --target install -- -j"$CORES" mv "$DEPS_DIR"/lib/static/libed25519.a "$DEPS_DIR"/lib; rmdir "$DEPS_DIR"/lib/static/ # SWIG fixes -sed -i.bak "s~find_package(JNI REQUIRED)~#find_package(JNI REQUIRED)~" ./iroha/shared_model/bindings/CMakeLists.txt -sed -i.bak "s~include_directories(${JAVA_INCLUDE_PATH})~#include_directories(${JAVA_INCLUDE_PATH})~" ./iroha/shared_model/bindings/CMakeLists.txt -sed -i.bak "s~include_directories(${JAVA_INCLUDE_PATH2})~#include_directories(${JAVA_INCLUDE_PATH2})~" ./iroha/shared_model/bindings/CMakeLists.txt -sed -i.bak "s~# the include path to jni.h~SET(CMAKE_SWIG_FLAGS \${CMAKE_SWIG_FLAGS} -package ${PACKAGE})~" ./iroha/shared_model/bindings/CMakeLists.txt +sed -i.bak "s~find_package(JNI REQUIRED)~SET(CMAKE_SWIG_FLAGS \${CMAKE_SWIG_FLAGS} -package ${PACKAGE})~" ./iroha/shared_model/bindings/CMakeLists.txt +sed -i.bak "s~\${JAVA_INCLUDE_PATH}~#\${JAVA_INCLUDE_PATH}~" ./iroha/shared_model/bindings/CMakeLists.txt +sed -i.bak "s~\${JAVA_INCLUDE_PATH2}~#\${JAVA_INCLUDE_PATH2}~" ./iroha/shared_model/bindings/CMakeLists.txt +sed -i.bak "s~target_include_directories(\${SWIG_MODULE_irohajava_REAL_NAME} PUBLIC~SET(CMAKE_SWIG_FLAGS \${CMAKE_SWIG_FLAGS}~" ./iroha/shared_model/bindings/CMakeLists.txt sed -i.bak "s~swig_link_libraries(irohajava~swig_link_libraries(irohajava \"${PWD}/protobuf/.build/lib${PROTOBUF_LIB_NAME}.a\" \"${NDK_PATH}/platforms/android-${VERSION}/${ARCH}/usr/${LIBP}/liblog.so\"~" ./iroha/shared_model/bindings/CMakeLists.txt # build iroha From 4c4029f7272345055749366805625e2311b8896e Mon Sep 17 00:00:00 2001 From: Dumitru Date: Tue, 24 Apr 2018 13:51:43 +0300 Subject: [PATCH 055/110] Decrease required python version (#1267) Signed-off-by: Dumitru --- shared_model/bindings/CMakeLists.txt | 2 +- test/module/shared_model/bindings/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared_model/bindings/CMakeLists.txt b/shared_model/bindings/CMakeLists.txt index 213bed5777..fae93bdca0 100644 --- a/shared_model/bindings/CMakeLists.txt +++ b/shared_model/bindings/CMakeLists.txt @@ -61,7 +61,7 @@ if (SWIG_PYTHON) if(SUPPORT_PYTHON2) find_package(PythonLibs 2.7 REQUIRED) else() - find_package(PythonLibs 3.6 REQUIRED) + find_package(PythonLibs 3.5 REQUIRED) endif() if (${CMAKE_SYSTEM_NAME} STREQUAL Darwin) diff --git a/test/module/shared_model/bindings/CMakeLists.txt b/test/module/shared_model/bindings/CMakeLists.txt index d3933f70e8..63719a02d9 100644 --- a/test/module/shared_model/bindings/CMakeLists.txt +++ b/test/module/shared_model/bindings/CMakeLists.txt @@ -36,7 +36,7 @@ if (SWIG_PYTHON) if(SUPPORT_PYTHON2) find_package(PythonInterp 2.7 REQUIRED) else() - find_package(PythonInterp 3.6 REQUIRED) + find_package(PythonInterp 3.5 REQUIRED) endif() add_test(NAME python_transaction_test COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/builder-test.py From e73e5a0ba87fc93689cf80f0dc72bab6b6f42917 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Tue, 24 Apr 2018 18:45:39 +0300 Subject: [PATCH 056/110] HasTxWithHash for Block Query (#1255) * Add function to check the presence of transaction in a ledger and Command Service checks if a transaction was added by hasTxWithHash Signed-off-by: Nikita Alekseev --- irohad/ametsuchi/block_query.hpp | 8 +++++++ .../ametsuchi/impl/postgres_block_query.cpp | 24 +++++++++++-------- .../ametsuchi/impl/postgres_block_query.hpp | 2 ++ irohad/torii/impl/command_service.cpp | 2 +- .../irohad/ametsuchi/ametsuchi_mocks.hpp | 1 + .../irohad/ametsuchi/block_query_test.cpp | 22 +++++++++++++++++ 6 files changed, 48 insertions(+), 11 deletions(-) diff --git a/irohad/ametsuchi/block_query.hpp b/irohad/ametsuchi/block_query.hpp index cac9647d5c..47780171fd 100644 --- a/irohad/ametsuchi/block_query.hpp +++ b/irohad/ametsuchi/block_query.hpp @@ -96,6 +96,14 @@ namespace iroha { */ virtual boost::optional getTxByHashSync( const shared_model::crypto::Hash &hash) = 0; + + /** + * Synchronously checks whether transaction + * with given hash is present in any block + * @param hash - transaction hash + * @return true if transaction exists, false otherwise + */ + virtual bool hasTxWithHash(const shared_model::crypto::Hash &hash) = 0; }; } // namespace ametsuchi } // namespace iroha diff --git a/irohad/ametsuchi/impl/postgres_block_query.cpp b/irohad/ametsuchi/impl/postgres_block_query.cpp index 7477048ce1..b6434788c5 100644 --- a/irohad/ametsuchi/impl/postgres_block_query.cpp +++ b/irohad/ametsuchi/impl/postgres_block_query.cpp @@ -50,15 +50,14 @@ namespace iroha { log_->error("error while converting from JSON"); } - return rxcpp::observable<>::create< - PostgresBlockQuery::wBlock>([block{std::move(block)}]( - const auto &s) { - if (block) { - s.on_next(std::make_shared( - block.value())); - } - s.on_completed(); - }); + return rxcpp::observable<>::create( + [block{std::move(block)}](const auto &s) { + if (block) { + s.on_next(std::make_shared( + block.value())); + } + s.on_completed(); + }); }); } @@ -189,7 +188,7 @@ namespace iroha { [this, tx_hashes](const auto &subscriber) { std::for_each(tx_hashes.begin(), tx_hashes.end(), - [ that = this, &subscriber ](const auto &tx_hash) { + [that = this, &subscriber](const auto &tx_hash) { subscriber.on_next(that->getTxByHashSync(tx_hash)); }); subscriber.on_completed(); @@ -222,5 +221,10 @@ namespace iroha { return result; } + bool PostgresBlockQuery::hasTxWithHash( + const shared_model::crypto::Hash &hash) { + return getBlockId(hash) != boost::none; + } + } // namespace ametsuchi } // namespace iroha diff --git a/irohad/ametsuchi/impl/postgres_block_query.hpp b/irohad/ametsuchi/impl/postgres_block_query.hpp index dce3fe07ee..c2eab7f51e 100644 --- a/irohad/ametsuchi/impl/postgres_block_query.hpp +++ b/irohad/ametsuchi/impl/postgres_block_query.hpp @@ -62,6 +62,8 @@ namespace iroha { rxcpp::observable getTopBlocks(uint32_t count) override; + bool hasTxWithHash(const shared_model::crypto::Hash &hash) override; + private: /** * Returns all blocks' ids containing given account id diff --git a/irohad/torii/impl/command_service.cpp b/irohad/torii/impl/command_service.cpp index fc3a88acbe..135fec821d 100644 --- a/irohad/torii/impl/command_service.cpp +++ b/irohad/torii/impl/command_service.cpp @@ -135,7 +135,7 @@ namespace torii { response.CopyFrom(*resp); } else { response.set_tx_hash(request.tx_hash()); - if (block_query_->getTxByHashSync( + if (block_query_->hasTxWithHash( shared_model::crypto::Hash(request.tx_hash()))) { response.set_tx_status(iroha::protocol::TxStatus::COMMITTED); } else { diff --git a/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp b/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp index 039b408061..827c004b83 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp +++ b/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp @@ -163,6 +163,7 @@ namespace iroha { rxcpp::observable( shared_model::interface::types::HeightType)); MOCK_METHOD1(getTopBlocks, rxcpp::observable(uint32_t)); + MOCK_METHOD1(hasTxWithHash, bool(const shared_model::crypto::Hash &hash)); }; class MockTemporaryFactory : public TemporaryFactory { diff --git a/test/module/irohad/ametsuchi/block_query_test.cpp b/test/module/irohad/ametsuchi/block_query_test.cpp index ceb9c79877..7c82baa7a6 100644 --- a/test/module/irohad/ametsuchi/block_query_test.cpp +++ b/test/module/irohad/ametsuchi/block_query_test.cpp @@ -366,3 +366,25 @@ TEST_F(BlockQueryTest, GetTop2Blocks) { ASSERT_TRUE(wrapper.validate()); } + +/** + * @given block store with preinserted blocks + * @when hasTxWithHash is invoked on existing transaction hash + * @then True is returned + */ +TEST_F(BlockQueryTest, HasTxWithExistingHash) { + for (const auto &hash : tx_hashes) { + EXPECT_TRUE(blocks->hasTxWithHash(hash)); + } +} + +/** + * @given block store with preinserted blocks + * user1@test AND 1 tx created by user2@test + * @when hasTxWithHash is invoked on non-existing hash + * @then False is returned + */ +TEST_F(BlockQueryTest, HasTxWithInvalidHash) { + shared_model::crypto::Hash invalid_tx_hash(zero_string); + EXPECT_FALSE(blocks->hasTxWithHash(invalid_tx_hash)); +} From aaf487ccb49e3bb87ebf6bd9c4b409f7b89950d0 Mon Sep 17 00:00:00 2001 From: luckychess Date: Tue, 24 Apr 2018 20:56:42 +0300 Subject: [PATCH 057/110] Fix hint about git clone depth (#1269) Signed-off-by: luckychess --- docs/source/getting_started/index.rst | 2 +- docs/source/guides/build.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index 86d5751497..dc966ebded 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -86,7 +86,7 @@ In order to get those files, you need to clone the git clone -b develop https://github.com/hyperledger/iroha --depth=1 -.. hint:: ``--depth-1`` option allows us to download only latest commit and +.. hint:: ``--depth=1`` option allows us to download only latest commit and save some time and bandwidth. If you want to get a full commit history, you can omit this option. diff --git a/docs/source/guides/build.rst b/docs/source/guides/build.rst index 4b3657f023..beaee71092 100644 --- a/docs/source/guides/build.rst +++ b/docs/source/guides/build.rst @@ -38,7 +38,7 @@ to the directory of your choice. git clone -b develop https://github.com/hyperledger/iroha --depth=1 -.. hint:: ``--depth-1`` option allows us to download only latest commit and +.. hint:: ``--depth=1`` option allows us to download only latest commit and save some time and bandwidth. If you want to get a full commit history, you can omit this option. From 24e3ed086f9e64978a54118ec5b1a4313c03459d Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Wed, 25 Apr 2018 12:43:00 +0300 Subject: [PATCH 058/110] Rework ordering service event handling (#1268) Signed-off-by: Andrei Lebedev --- .../ordering/impl/ordering_service_impl.cpp | 80 +++++++++++-------- .../ordering/impl/ordering_service_impl.hpp | 51 ++++++------ .../irohad/ordering/ordering_service_test.cpp | 46 ++++++----- 3 files changed, 101 insertions(+), 76 deletions(-) diff --git a/irohad/ordering/impl/ordering_service_impl.cpp b/irohad/ordering/impl/ordering_service_impl.cpp index 886bd8f96c..ed65a6dbce 100644 --- a/irohad/ordering/impl/ordering_service_impl.cpp +++ b/irohad/ordering/impl/ordering_service_impl.cpp @@ -33,18 +33,51 @@ namespace iroha { size_t delay_milliseconds, std::shared_ptr transport, std::shared_ptr - persistent_state) + persistent_state, + bool is_async) : wsv_(wsv), max_size_(max_size), delay_milliseconds_(delay_milliseconds), transport_(transport), - persistent_state_(persistent_state), - is_finished(false) { - updateTimer(); + persistent_state_(persistent_state) { log_ = logger::log("OrderingServiceImpl"); // restore state of ordering service from persistent storage - proposal_height = persistent_state_->loadProposalHeight().value(); + proposal_height_ = persistent_state_->loadProposalHeight().value(); + + rxcpp::observable timer = + rxcpp::observable<>::interval( + std::chrono::milliseconds(delay_milliseconds_), + rxcpp::observe_on_new_thread()) + .map([](auto) { return ProposalEvent::kTimerEvent; }); + + auto subscribe = [&](auto merge_strategy) { + handle_ = merge_strategy(rxcpp::observable<>::from( + timer, transactions_.get_observable())) + .subscribe([this](auto &&v) { + auto check_queue = [&] { + switch (v) { + case ProposalEvent::kTimerEvent: + return not queue_.empty(); + case ProposalEvent::kTransactionEvent: + return queue_.unsafe_size() >= max_size_; + default: + BOOST_ASSERT_MSG(false, "Unknown value"); + } + }; + if (check_queue()) { + this->generateProposal(); + } + }); + }; + + if (is_async) { + subscribe([](auto observable) { + return observable.merge(rxcpp::synchronize_new_thread()); + }); + } else { + subscribe([](auto observable) { return observable.merge(); }); + } } void OrderingServiceImpl::onTransaction( @@ -52,25 +85,24 @@ namespace iroha { queue_.push(transaction); log_->info("Queue size is {}", queue_.unsafe_size()); - if (queue_.unsafe_size() >= max_size_) { - handle.unsubscribe(); - updateTimer(); - } + // on_next calls should not be concurrent + std::lock_guard lk(mutex_); + transactions_.get_subscriber().on_next(ProposalEvent::kTransactionEvent); } void OrderingServiceImpl::generateProposal() { // TODO 05/03/2018 andrei IR-1046 Server-side shared model object // factories with move semantics iroha::protocol::Proposal proto_proposal; - proto_proposal.set_height(proposal_height++); + proto_proposal.set_height(proposal_height_++); proto_proposal.set_created_time(iroha::time::now()); log_->info("Start proposal generation"); for (std::shared_ptr tx; static_cast(proto_proposal.transactions_size()) < max_size_ and queue_.try_pop(tx);) { - *proto_proposal.add_transactions() = std::move( - std::static_pointer_cast(tx) - ->getTransport()); + *proto_proposal.add_transactions() = + std::move(static_cast(tx.get()) + ->getTransport()); } auto proposal = std::make_unique( @@ -78,10 +110,10 @@ namespace iroha { // Save proposal height to the persistent storage. // In case of restart it reloads state. - if (persistent_state_->saveProposalHeight(proposal_height)) { + if (persistent_state_->saveProposalHeight(proposal_height_)) { publishProposal(std::move(proposal)); } else { - // TODO(@l4l) 23/03/18: publish proposal independant of psql status + // TODO(@l4l) 23/03/18: publish proposal independent of psql status // IR-1162 log_->warn( "Proposal height cannot be saved. Skipping proposal publish"); @@ -103,24 +135,8 @@ namespace iroha { } } - void OrderingServiceImpl::updateTimer() { - std::lock_guard lock(m); - if (is_finished) { - return; - } - if (not queue_.empty()) { - this->generateProposal(); - } - timer = rxcpp::observable<>::timer( - std::chrono::milliseconds(delay_milliseconds_)); - handle = timer.subscribe_on(rxcpp::observe_on_new_thread()) - .subscribe([this](auto) { this->updateTimer(); }); - } - OrderingServiceImpl::~OrderingServiceImpl() { - std::lock_guard lock(m); - is_finished = true; - handle.unsubscribe(); + handle_.unsubscribe(); } } // namespace ordering } // namespace iroha diff --git a/irohad/ordering/impl/ordering_service_impl.hpp b/irohad/ordering/impl/ordering_service_impl.hpp index e0c044a8cb..0549274c87 100644 --- a/irohad/ordering/impl/ordering_service_impl.hpp +++ b/irohad/ordering/impl/ordering_service_impl.hpp @@ -31,7 +31,6 @@ namespace iroha { namespace ametsuchi { class OrderingServicePersistentState; - class OrderingServiceTransport; class PeerQuery; } // namespace ametsuchi @@ -42,20 +41,26 @@ namespace iroha { * Allows receiving transactions concurrently from multiple peers by using * concurrent queue * Sends proposal by given timer interval and proposal size - * @param delay_milliseconds timer delay - * @param max_size proposal size - * @param persistent_state - storage for persistent state of ordering - * service */ class OrderingServiceImpl : public network::OrderingService { public: + /** + * Constructor + * @param wsv interface for fetching peers from world state view + * @param max_size maximum size of proposal + * @param delay_milliseconds timeout for proposal generation + * @param transport receive transactions and publish proposals + * @param persistent_state storage for auxiliary information + * @param is_async whether proposals are generated in a separate thread + */ OrderingServiceImpl( std::shared_ptr wsv, size_t max_size, size_t delay_milliseconds, std::shared_ptr transport, std::shared_ptr - persistent_state); + persistent_state, + bool is_async = true); /** * Process transaction received from network @@ -77,22 +82,16 @@ namespace iroha { private: /** - * Collect transactions from queue - * Passes the generated proposal to publishProposal - */ - void generateProposal() override; - - /** - * Method update peers for sending proposal + * Events for queue check strategy */ + enum class ProposalEvent { kTransactionEvent, kTimerEvent }; /** - * Update the timer to be called after delay_milliseconds_ + * Collect transactions from queue + * Passes the generated proposal to publishProposal */ - void updateTimer(); + void generateProposal() override; - rxcpp::observable timer; - rxcpp::composite_subscription handle; std::shared_ptr wsv_; tbb::concurrent_queue< @@ -108,10 +107,11 @@ namespace iroha { * wait for specified time if queue is empty */ const size_t delay_milliseconds_; + std::shared_ptr transport_; /** - * Persistense storage for proposal counter. + * Persistent storage for proposal counter. * In case of relaunch, ordering server will enumerate proposals * consecutively. */ @@ -122,17 +122,18 @@ namespace iroha { * Proposal counter of expected proposal. Should be number of blocks in * the ledger + 1. */ - size_t proposal_height; + size_t proposal_height_; - /** - * Mutex for proper quit handling - */ - std::mutex m; + /// Observable for transaction events from the network + rxcpp::subjects::subject transactions_; + + /// Internal event observable handle + rxcpp::composite_subscription handle_; /** - * Set after destruction + * Mutex for incoming transactions */ - bool is_finished; + std::mutex mutex_; logger::Logger log_; }; diff --git a/test/module/irohad/ordering/ordering_service_test.cpp b/test/module/irohad/ordering/ordering_service_test.cpp index d6a1a4b4fc..bd0f6400f7 100644 --- a/test/module/irohad/ordering/ordering_service_test.cpp +++ b/test/module/irohad/ordering/ordering_service_test.cpp @@ -19,6 +19,7 @@ #include "backend/protobuf/common_objects/peer.hpp" #include "builders/protobuf/common_objects/proto_peer_builder.hpp" +#include "builders/protobuf/transaction.hpp" #include "logger/logger.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/network/network_mocks.hpp" @@ -27,7 +28,6 @@ #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "ordering/impl/ordering_service_impl.hpp" #include "ordering/impl/ordering_service_transport_grpc.hpp" -#include "builders/protobuf/transaction.hpp" using namespace iroha; using namespace iroha::ordering; @@ -35,12 +35,12 @@ using namespace iroha::network; using namespace iroha::ametsuchi; using namespace std::chrono_literals; +using ::testing::_; using ::testing::AtLeast; using ::testing::DoAll; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; using ::testing::Return; -using ::testing::_; static logger::Logger log_ = logger::testLog("OrderingService"); @@ -82,15 +82,24 @@ class OrderingServiceTest : public ::testing::Test { } auto getTx() { - return std::make_shared( + return std::make_unique( shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId("admin@ru") - .addAssetQuantity("admin@tu", "coin#coin", "1.0") - .build() - .signAndAddSignature( - shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair())); + .createdTime(iroha::time::now()) + .creatorAccountId("admin@ru") + .addAssetQuantity("admin@tu", "coin#coin", "1.0") + .build() + .signAndAddSignature( + shared_model::crypto::DefaultCryptoAlgorithmType:: + generateKeypair())); + } + + auto initOs(size_t max_proposal, size_t commit_delay) { + return std::make_shared(wsv, + max_proposal, + commit_delay, + fake_transport, + fake_persistent_state, + false); } std::shared_ptr fake_transport; @@ -113,15 +122,17 @@ TEST_F(OrderingServiceTest, SimpleTest) { .Times(1) .WillOnce(Return(boost::optional(2))); - auto ordering_service = std::make_shared( - wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + auto ordering_service = initOs(max_proposal, commit_delay); fake_transport->subscribe(ordering_service); EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(1); fake_transport->publishProposal( std::make_unique( - TestProposalBuilder().height(1).createdTime(iroha::time::now()).build()), + TestProposalBuilder() + .height(1) + .createdTime(iroha::time::now()) + .build()), {}); } @@ -136,8 +147,7 @@ TEST_F(OrderingServiceTest, ValidWhenProposalSizeStrategy) { .Times(1) .WillOnce(Return(boost::optional(2))); - auto ordering_service = std::make_shared( - wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + auto ordering_service = initOs(max_proposal, commit_delay); fake_transport->subscribe(ordering_service); // Init => proposal size 5 => 2 proposals after 10 transactions @@ -186,8 +196,7 @@ TEST_F(OrderingServiceTest, ValidWhenTimerStrategy) { .Times(1) .WillOnce(Return(boost::optional(2))); - auto ordering_service = std::make_shared( - wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + auto ordering_service = initOs(max_proposal, commit_delay); fake_transport->subscribe(ordering_service); EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)) @@ -224,8 +233,7 @@ TEST_F(OrderingServiceTest, BrokenPersistentState) { .Times(1) .WillRepeatedly(Return(false)); - auto ordering_service = std::make_shared( - wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + auto ordering_service = initOs(max_proposal, commit_delay); ordering_service->onTransaction(getTx()); std::unique_lock lk(m); From f050aa7d38e2b52971cd01d2f8dd4eaf9dee2571 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bikbaev Date: Wed, 25 Apr 2018 14:23:54 +0300 Subject: [PATCH 059/110] Feat/run node tests (#1256) * fix: fixed js tests with correct exception values, added todo * feat: ctest for nodejs tests * chore: replaced tap-spec with tap-dot for cleaner test output * feat: nodejs documentation clarification * feat: more tests to the god of tests * feat: now library rebuilds before running tests, like java. need to change this later on Signed-off-by: Vyacheslav Bikbaev --- docs/source/guides/libraries/nodejs.rst | 2 +- shared_model/packages/javascript/package.json | 12 ++-- .../packages/javascript/tests/queryBuilder.js | 6 +- .../packages/javascript/tests/txbuilder.js | 63 +++++++++++-------- .../shared_model/bindings/CMakeLists.txt | 7 +++ 5 files changed, 57 insertions(+), 33 deletions(-) diff --git a/docs/source/guides/libraries/nodejs.rst b/docs/source/guides/libraries/nodejs.rst index 997135ea18..90451d83e7 100644 --- a/docs/source/guides/libraries/nodejs.rst +++ b/docs/source/guides/libraries/nodejs.rst @@ -67,7 +67,7 @@ Go to the NPM package directory and start the build process .. code-block:: shell cd iroha/shared_model/packages/javascript - npm install + npm install --build-from-source=iroha-lib That's all. You can use the library now. diff --git a/shared_model/packages/javascript/package.json b/shared_model/packages/javascript/package.json index a057a74fcf..8776868774 100644 --- a/shared_model/packages/javascript/package.json +++ b/shared_model/packages/javascript/package.json @@ -7,9 +7,10 @@ "prepare": "sh scripts/generate-protobuf.sh", "prepublishOnly": "npm ls", "install": "node-pre-gyp install --fallback-to-build", - "test": "tape tests/**/*.js | tap-spec", + "test": "tape tests/**/*.js | tap-dot", "build": "node-pre-gyp build", - "rebuild": "node-pre-gyp rebuild" + "rebuild": "node-pre-gyp rebuild", + "build-and-test": "npm install --build-from-source=iroha-lib && npm run test" }, "repository": { "type": "git", @@ -44,13 +45,16 @@ "dependencies": { "google-protobuf": "^3.5.0", "grpc": "^1.9.1", - "node-pre-gyp": "^0.6.39" + "node-pre-gyp": "^0.6.39", + "npm": "^5.8.0", + "run": "^1.4.0", + "test": "^0.6.0" }, "devDependencies": { "grpc-tools": "^1.6.6", "node-gyp": "^3.6.2", "node-pre-gyp-github": "^1.3.1", - "tap-spec": "^4.1.1", + "tap-dot": "^1.0.5", "tape": "^4.9.0" }, "bundledDependencies": [ diff --git a/shared_model/packages/javascript/tests/queryBuilder.js b/shared_model/packages/javascript/tests/queryBuilder.js index 6a5ea1a2dd..17da9bdcc5 100644 --- a/shared_model/packages/javascript/tests/queryBuilder.js +++ b/shared_model/packages/javascript/tests/queryBuilder.js @@ -5,7 +5,7 @@ const accountId = 'admin@test' const assetId = 'coin#test' test('ModelQueryBuilder tests', function (t) { - t.plan(49) + t.plan(50) let queryBuilder = new iroha.ModelQueryBuilder() const time = (new Date()).getTime() @@ -86,9 +86,13 @@ test('ModelQueryBuilder tests', function (t) { t.comment('Testing getTransactions()') t.throws(() => correctQuery.getTransactions(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctQuery.getTransactions(''), /argument 2 of type 'std::vector< shared_model::crypto::Hash >/, 'Should throw ...argument 2 of type...') + let hv = new iroha.HashVector() hv.add(new iroha.Hash('11111111111111111111111111111111')) hv.add(new iroha.Hash('22222222222222222222222222222222')) + let emptyHv = new iroha.HashVector() + + t.throws(() => correctQuery.getTransactions(emptyHv), /Hash set should contain at least one hash/, 'Should throw Hash set should contain at least one hash') t.doesNotThrow(() => correctQuery.getTransactions(hv), null, 'Should not throw any exceptions') // getAccountDetail() tests diff --git a/shared_model/packages/javascript/tests/txbuilder.js b/shared_model/packages/javascript/tests/txbuilder.js index 4e3c7490ed..cc29430020 100644 --- a/shared_model/packages/javascript/tests/txbuilder.js +++ b/shared_model/packages/javascript/tests/txbuilder.js @@ -9,23 +9,25 @@ const assetId = 'coin#test' const testAccountId = 'test@test' test('ModelTransactionBuilder tests', function (t) { - t.plan(130) + t.plan(135) let crypto = new iroha.ModelCrypto() let keypair = crypto.convertFromExisting(publicKey, privateKey) let txBuilder = new iroha.ModelTransactionBuilder() const time = (new Date()).getTime() + const futureTime = 2400000000000 const address = '0.0.0.0:50051' t.comment('Basic TransactionBuilder tests') - t.throws(() => txBuilder.build(), /Transaction should contain at least one command/, 'Should throw exception 0 commands in transaction, wrong creator_account_id, timestamp') - t.throws(() => txBuilder.creatorAccountId(adminAccountId).build(), /Transaction should contain at least one command/, 'Should throw exception about zero commands in transaction, wrong timestamp') - t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(0).build(), /Transaction should contain at least one command bad timestamp: too old/, 'Should throw 0 commands + bad timestamp: too old') + t.throws(() => txBuilder.build(), /Transaction should contain at least one command(.*)Wrongly formed creator_account_id, passed value: ''(.*)bad timestamp: too old/, 'Should throw exception 0 commands in transaction, wrong creator_account_id, timestamp') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).build(), /Transaction should contain at least one command(.*)bad timestamp: too old/, 'Should throw exception about zero commands in transaction, wrong timestamp') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(0).build(), /Transaction should contain at least one command(.*)bad timestamp: too old/, 'Should throw 0 commands + bad timestamp: too old') t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(time).build(), /Transaction should contain at least one command/, 'Should throw 0 commands') - t.throws(() => txBuilder.creatorAccountId('').createdTime(time).build(), /Transaction should contain at least one command Wrongly formed creator_account_id, passed value: ''/, 'Should throw 0 commands + Wrongly formed creator_account_id') - t.throws(() => txBuilder.creatorAccountId('@@@').createdTime(time).build(), /Transaction should contain at least one command Wrongly formed creator_account_id, passed value: '@@@'/, 'Should throw 0 commands + Wrongly formed creator_account_id') + t.throws(() => txBuilder.creatorAccountId('').createdTime(time).build(), /Transaction should contain at least one command(.*)Wrongly formed creator_account_id, passed value: ''/, 'Should throw 0 commands + Wrongly formed creator_account_id') + t.throws(() => txBuilder.creatorAccountId('@@@').createdTime(time).build(), /Transaction should contain at least one command(.*)Wrongly formed creator_account_id, passed value: '@@@'/, 'Should throw 0 commands + Wrongly formed creator_account_id') + t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(futureTime).build(), /Transaction should contain at least one command(.*)bad timestamp: sent from future/, 'Should throw exception about zero commands in transaction, Sent from future') t.throws(() => txBuilder.creatorAccountId(adminAccountId).createdTime(time).build(), /Transaction should contain at least one command/, 'Should throw exception about zero commands in transaction') // Transaction with valid creatorAccountId and createdTime @@ -36,7 +38,7 @@ test('ModelTransactionBuilder tests', function (t) { t.throws(() => correctTx.addAssetQuantity(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.addAssetQuantity(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.addAssetQuantity('', ''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') - t.throws(() => correctTx.addAssetQuantity('', '', '').build(), /AddAssetQuantity: \[\[Wrongly formed account_id, passed value: '' Wrongly formed asset_id, passed value: '' Amount must be greater than 0, passed value: 0 \]\]/, 'Should throw wrongly formed account_id, asset_id, Amount must be greater than 0') + t.throws(() => correctTx.addAssetQuantity('', '', '').build(), /AddAssetQuantity: \[\[Wrongly formed account_id, passed value: ''(.*)Wrongly formed asset_id, passed value: ''(.*)Amount must be greater than 0, passed value: 0 \]\]/, 'Should throw wrongly formed account_id, asset_id, Amount must be greater than 0') t.throws(() => correctTx.addAssetQuantity(adminAccountId, assetId, '0').build(), /AddAssetQuantity: \[\[Amount must be greater than 0, passed value: 0 \]\]/, 'Should throw Amount must be greater than 0') t.throws(() => correctTx.addAssetQuantity('', assetId, '1000').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.addAssetQuantity('@@@', assetId, '1000').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') @@ -74,12 +76,11 @@ test('ModelTransactionBuilder tests', function (t) { t.comment('Testing appendRole()') t.throws(() => correctTx.appendRole(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.appendRole(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') - t.throws(() => correctTx.appendRole('', 'ruser').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') - t.throws(() => correctTx.appendRole('@@@', 'ruser').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') + t.throws(() => correctTx.appendRole('', 'new_user_role').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') + t.throws(() => correctTx.appendRole('@@@', 'new_user_role').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.appendRole(adminAccountId, '').build(), /Wrongly formed role_id, passed value: ''/, 'Should throw Wrongly formed role_id') t.throws(() => correctTx.appendRole(adminAccountId, '@@@').build(), /Wrongly formed role_id, passed value: '@@@'/, 'Should throw Wrongly formed role_id') - // TODO: 8 symbols - t.doesNotThrow(() => correctTx.appendRole(adminAccountId, 'ruser').build(), null, 'Should not throw any exceptions') + t.doesNotThrow(() => correctTx.appendRole(adminAccountId, 'new_user_role').build(), null, 'Should not throw any exceptions') // createAsset() tests t.comment('Testing createAsset()') @@ -110,34 +111,40 @@ test('ModelTransactionBuilder tests', function (t) { t.comment('Testing createDomain()') t.throws(() => correctTx.createDomain(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.createDomain(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') - t.throws(() => correctTx.createDomain('', 'ruser').build(), /Wrongly formed domain_id, passed value: ''/, 'Should throw Wrongly formed domain_id') - t.throws(() => correctTx.createDomain('$$$', 'ruser').build(), /Wrongly formed domain_id, passed value: '\$\$\$'/, 'Should throw Wrongly formed domain_id') + t.throws(() => correctTx.createDomain('', 'new_user_role').build(), /Wrongly formed domain_id, passed value: ''/, 'Should throw Wrongly formed domain_id') + t.throws(() => correctTx.createDomain('$$$', 'new_user_role').build(), /Wrongly formed domain_id, passed value: '\$\$\$'/, 'Should throw Wrongly formed domain_id') t.throws(() => correctTx.createDomain('domain', '').build(), /Wrongly formed role_id, passed value: ''/, 'Should throw Wrongly formed role_id') t.throws(() => correctTx.createDomain('domain', '@@@').build(), /Wrongly formed role_id, passed value: '@@@'/, 'Should throw Wrongly formed role_id') - t.doesNotThrow(() => correctTx.createDomain('domain', 'ruser').build(), null, 'Should not throw any exceptions') + t.doesNotThrow(() => correctTx.createDomain('domain', 'new_user_role').build(), null, 'Should not throw any exceptions') // createRole() tests t.comment('Testing createRole()') t.throws(() => correctTx.createRole(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.createRole(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') + let sv = new iroha.StringVector() - sv.add('permission1') - sv.add('permission2') + sv.add('can_add_peer') + sv.add('can_read_assets') + let emptySv = new iroha.StringVector() + let invalidPermissionSv = new iroha.StringVector() + invalidPermissionSv.add('wrong_permission') + + t.throws(() => correctTx.createRole('new_user_role', emptySv).build(), /Permission set should contain at least one permission/, 'Should throw Permission set should contain at least one permission') + t.throws(() => correctTx.createRole('new_user_role', invalidPermissionSv).build(), /Provided permission does not exist/, 'Should throw Provided permission does not exist') t.throws(() => correctTx.createRole('', sv).build(), /Wrongly formed role_id, passed value: ''/, 'Should throw Wrongly formed role_id') t.throws(() => correctTx.createRole('@@@', sv).build(), /Wrongly formed role_id, passed value: '@@@'/, 'Should throw Wrongly formed role_id') - t.throws(() => correctTx.createRole('ruser', '').build(), /argument 3 of type 'std::vector< shared_model::interface::types::PermissionNameType >/, 'Should throw ...argument 3 of type...') - t.doesNotThrow(() => correctTx.createRole('ruser', sv).build(), null, 'Should not throw any exceptions') + t.throws(() => correctTx.createRole('new_user_role', '').build(), /argument 3 of type 'std::vector< shared_model::interface::types::PermissionNameType >/, 'Should throw ...argument 3 of type...') + t.doesNotThrow(() => correctTx.createRole('new_user_role', sv).build(), null, 'Should not throw any exceptions') // detachRole() tests t.comment('Testing detachRole()') t.throws(() => correctTx.detachRole(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.detachRole(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') - t.throws(() => correctTx.detachRole('', 'ruser').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') - t.throws(() => correctTx.detachRole('@@@', 'ruser').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') + t.throws(() => correctTx.detachRole('', 'new_user_role').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') + t.throws(() => correctTx.detachRole('@@@', 'new_user_role').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.detachRole(adminAccountId, '').build(), /Wrongly formed role_id, passed value: ''/, 'Should throw Wrongly formed role_id') t.throws(() => correctTx.detachRole(adminAccountId, '@@@').build(), /Wrongly formed role_id, passed value: '@@@'/, 'Should throw Wrongly formed role_id') - // TODO: 8 symbols - t.doesNotThrow(() => correctTx.detachRole(adminAccountId, 'ruser').build(), null, 'Should not throw any exceptions') + t.doesNotThrow(() => correctTx.detachRole(adminAccountId, 'new_user_role').build(), null, 'Should not throw any exceptions') // grantPermission() tests t.comment('Testing grantPermission()') @@ -145,8 +152,8 @@ test('ModelTransactionBuilder tests', function (t) { t.throws(() => correctTx.grantPermission(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.grantPermission('', 'can_read_assets').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.grantPermission('@@@', 'can_read_assets').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') - t.throws(() => correctTx.grantPermission(adminAccountId, '').build(), /Wrongly formed permission, passed value: ''/, 'Should throw Wrongly formed permission') - t.throws(() => correctTx.grantPermission(adminAccountId, '@@@').build(), /Wrongly formed permission, passed value: '@@@'/, 'Should throw Wrongly formed permission') + t.throws(() => correctTx.grantPermission(adminAccountId, '').build(), /Provided permission does not exist/, 'Should throw Provided permission does not exist') + t.throws(() => correctTx.grantPermission(adminAccountId, '@@@').build(), /Provided permission does not exist/, 'Should throw Provided permission does not exist') t.doesNotThrow(() => correctTx.grantPermission(adminAccountId, 'can_read_assets').build(), null, 'Should not throw any exceptions') // revokePermission() tests @@ -155,8 +162,8 @@ test('ModelTransactionBuilder tests', function (t) { t.throws(() => correctTx.revokePermission(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.revokePermission('', 'can_read_assets').build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.revokePermission('@@@', 'can_read_assets').build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') - t.throws(() => correctTx.revokePermission(adminAccountId, '').build(), /Wrongly formed permission, passed value: ''/, 'Should throw Wrongly formed permission') - t.throws(() => correctTx.revokePermission(adminAccountId, '@@@').build(), /Wrongly formed permission, passed value: '@@@'/, 'Should throw Wrongly formed permission') + t.throws(() => correctTx.revokePermission(adminAccountId, '').build(), /Provided permission does not exist/, 'Should throw Provided permission does not exist') + t.throws(() => correctTx.revokePermission(adminAccountId, '@@@').build(), /Provided permission does not exist/, 'Should throw Provided permission does not exist') t.doesNotThrow(() => correctTx.revokePermission(adminAccountId, 'can_read_assets').build(), null, 'Should not throw any exceptions') // setAccountDetail() tests @@ -177,6 +184,8 @@ test('ModelTransactionBuilder tests', function (t) { t.throws(() => correctTx.setAccountQuorum('', 10).build(), /Wrongly formed account_id, passed value: ''/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.setAccountQuorum('@@@', 10).build(), /Wrongly formed account_id, passed value: '@@@'/, 'Should throw Wrongly formed account_id') t.throws(() => correctTx.setAccountQuorum(adminAccountId, 'kek').build(), /argument 3 of type 'shared_model::interface::types::QuorumType'/, 'Should throw ...argument 3 of type...') + t.throws(() => correctTx.setAccountQuorum(adminAccountId, 0).build(), /Quorum should be within range \(0, 128\]/, 'Should throw Quorum should be within range (0, 128]') + t.throws(() => correctTx.setAccountQuorum(adminAccountId, 200).build(), /Quorum should be within range \(0, 128\]/, 'Should throw Quorum should be within range (0, 128]') t.doesNotThrow(() => correctTx.setAccountQuorum(adminAccountId, 10).build(), null, 'Should not throw any exceptions') // subtractAssetQuantity() tests @@ -184,7 +193,7 @@ test('ModelTransactionBuilder tests', function (t) { t.throws(() => correctTx.subtractAssetQuantity(), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.subtractAssetQuantity(''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') t.throws(() => correctTx.subtractAssetQuantity('', ''), /Error: Illegal number of arguments/, 'Should throw Illegal number of arguments') - t.throws(() => correctTx.subtractAssetQuantity('', '', '').build(), /SubtractAssetQuantity: \[\[Wrongly formed account_id, passed value: '' Wrongly formed asset_id, passed value: '' Amount must be greater than 0, passed value: 0 \]\]/, 'Should throw wrongly formed account_id, asset_id, Amount must be greater than 0') + t.throws(() => correctTx.subtractAssetQuantity('', '', '').build(), /SubtractAssetQuantity: \[\[Wrongly formed account_id, passed value: ''(.*)Wrongly formed asset_id, passed value: ''(.*)Amount must be greater than 0, passed value: 0 \]\]/, 'Should throw wrongly formed account_id, asset_id, Amount must be greater than 0') t.throws(() => correctTx.subtractAssetQuantity(adminAccountId, assetId, '0').build(), /SubtractAssetQuantity: \[\[Amount must be greater than 0, passed value: 0 \]\]/, 'Should throw Amount must be greater than 0') // TODO: MAYBE Throw an exception on real amount // t.throws(() => correctTx.subtractAssetQuantity(adminAccountId, assetId, '0.123').build(), /SubtractAssetQuantity: \[\[Amount must be integer, passed value: 0.123 \]\]/, 'Should throw Amount must be integer') diff --git a/test/module/shared_model/bindings/CMakeLists.txt b/test/module/shared_model/bindings/CMakeLists.txt index 63719a02d9..cb2a0da431 100644 --- a/test/module/shared_model/bindings/CMakeLists.txt +++ b/test/module/shared_model/bindings/CMakeLists.txt @@ -68,3 +68,10 @@ if (SWIG_JAVA) set_tests_properties(java_builders_test PROPERTIES DEPENDS builders) endif() + +if (SWIG_NODE) + find_package (nodejs REQUIRED) + add_test(NAME javascript_tests + COMMAND npm run build-and-test + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/shared_model/packages/javascript) +endif() From 3dab93def64839be529f7d8a7e07bcc7fae9ba96 Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 26 Apr 2018 08:23:36 +0300 Subject: [PATCH 060/110] Feature/rework command validate execute test with shm (#1264) rework command_validate_execute_test with shared_model Signed-off-by: Alexey Chernyshov --- test/module/irohad/CMakeLists.txt | 15 +- test/module/irohad/execution/CMakeLists.txt | 19 + .../command_validate_execute_test.cpp | 2218 +++++++++++++++++ test/module/irohad/model/CMakeLists.txt | 7 - .../model/command_validate_execute_test.cpp | 2017 --------------- 5 files changed, 2245 insertions(+), 2031 deletions(-) create mode 100644 test/module/irohad/execution/CMakeLists.txt create mode 100644 test/module/irohad/execution/command_validate_execute_test.cpp delete mode 100644 test/module/irohad/model/command_validate_execute_test.cpp diff --git a/test/module/irohad/CMakeLists.txt b/test/module/irohad/CMakeLists.txt index 3ac06f353e..c3654e516b 100644 --- a/test/module/irohad/CMakeLists.txt +++ b/test/module/irohad/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2017 Soramitsu Co., Ltd. +# Copyright 2018 Soramitsu Co., Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,15 +13,16 @@ # limitations under the License. # Reusable tests -add_subdirectory(common) add_subdirectory(ametsuchi) +add_subdirectory(common) add_subdirectory(consensus) +add_subdirectory(execution) add_subdirectory(logger) -add_subdirectory(validation) -add_subdirectory(torii) add_subdirectory(main) add_subdirectory(model) -add_subdirectory(synchronizer) -add_subdirectory(simulator) -add_subdirectory(ordering) add_subdirectory(network) +add_subdirectory(ordering) +add_subdirectory(simulator) +add_subdirectory(synchronizer) +add_subdirectory(torii) +add_subdirectory(validation) diff --git a/test/module/irohad/execution/CMakeLists.txt b/test/module/irohad/execution/CMakeLists.txt new file mode 100644 index 0000000000..3068bc81a7 --- /dev/null +++ b/test/module/irohad/execution/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2018 Soramitsu Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +addtest(command_validate_execute_test command_validate_execute_test.cpp) +target_link_libraries(command_validate_execute_test + command_execution + shared_model_stateless_validation + ) diff --git a/test/module/irohad/execution/command_validate_execute_test.cpp b/test/module/irohad/execution/command_validate_execute_test.cpp new file mode 100644 index 0000000000..f460a5c2ec --- /dev/null +++ b/test/module/irohad/execution/command_validate_execute_test.cpp @@ -0,0 +1,2218 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "builders/default_builders.hpp" +#include "execution/command_executor.hpp" +#include "framework/result_fixture.hpp" +#include "interfaces/commands/command.hpp" +#include "interfaces/utils/specified_visitor.hpp" +#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "validators/permissions.hpp" + +using ::testing::Return; +using ::testing::StrictMock; +using ::testing::_; + +using namespace iroha; +using namespace iroha::ametsuchi; +using namespace framework::expected; +using namespace shared_model::permissions; + +// TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework function with +// CommandBuilder +/** + * Hepler function to build command and wrap it into + * std::unique_ptr<> + * @param builder command builder + * @return command + */ +std::unique_ptr buildCommand( + const TestTransactionBuilder &builder) { + return clone(*(builder.build().commands().front())); +} + +/** + * Helper function to get concrete command from Command container. + * @tparam T - type of concrete command + * @param command - Command container + * @return concrete command extracted from container + */ +template +std::shared_ptr getConcreteCommand( + const std::unique_ptr &command) { + return clone( + *(boost::apply_visitor(shared_model::interface::SpecifiedVisitor(), + command->get()) + .value())); +} + +class CommandValidateExecuteTest : public ::testing::Test { + public: + void SetUp() override { + wsv_query = std::make_shared>(); + wsv_command = std::make_shared>(); + + executor = std::make_unique(wsv_query, wsv_command); + validator = std::make_unique(wsv_query); + + shared_model::builder::AccountBuilder< + shared_model::proto::AccountBuilder, + shared_model::validation::FieldValidator>() + .accountId(kAdminId) + .domainId(kDomainId) + .quorum(1) + .build() + .match( + [&](expected::Value< + std::shared_ptr> &v) { + creator = v.value; + }, + [](expected::Error> &e) { + FAIL() << *e.error; + }); + + shared_model::builder::AccountBuilder< + shared_model::proto::AccountBuilder, + shared_model::validation::FieldValidator>() + .accountId(kAccountId) + .domainId(kDomainId) + .quorum(1) + .build() + .match( + [&](expected::Value< + std::shared_ptr> &v) { + account = v.value; + }, + [](expected::Error> &e) { + FAIL() << *e.error; + }); + + shared_model::builder::AssetBuilder< + shared_model::proto::AssetBuilder, + shared_model::validation::FieldValidator>() + .assetId(kAssetId) + .domainId(kDomainId) + .precision(2) + .build() + .match( + [&](expected::Value> + &v) { asset = v.value; }, + [](expected::Error> &e) { + FAIL() << *e.error; + }); + + shared_model::builder::AmountBuilder< + shared_model::proto::AmountBuilder, + shared_model::validation::FieldValidator>() + .intValue(150) + .precision(2) + .build() + .match( + [&](expected::Value< + std::shared_ptr> &v) { + balance = v.value; + }, + [](expected::Error> &e) { + FAIL() << *e.error; + }); + + shared_model::builder::AccountAssetBuilder< + shared_model::proto::AccountAssetBuilder, + shared_model::validation::FieldValidator>() + .assetId(kAssetId) + .accountId(kAccountId) + .balance(*balance) + .build() + .match( + [&](expected::Value< + std::shared_ptr> &v) { + wallet = v.value; + }, + [](expected::Error> &e) { + FAIL() << *e.error; + }); + } + + iroha::ExecutionResult validateAndExecute( + const std::unique_ptr &command) { + validator->setCreatorAccountId(creator->accountId()); + + if (boost::apply_visitor(*validator, command->get())) { + return execute(command); + } + return expected::makeError( + iroha::ExecutionError{"Validate", "validation of a command failed"}); + } + + iroha::ExecutionResult execute( + const std::unique_ptr &command) { + executor->setCreatorAccountId(creator->accountId()); + return boost::apply_visitor(*executor, command->get()); + } + + /// return result with empty error message + WsvCommandResult makeEmptyError() { + return WsvCommandResult(iroha::expected::makeError("")); + } + + /// Returns error from result or throws error in case result contains value + iroha::ExecutionResult::ErrorType checkErrorCase( + const iroha::ExecutionResult &result) { + return boost::get(result); + } + + const std::string kMaxAmountStr = + std::numeric_limits::max().str() + + ".00"; + const std::string kAmountWrongPrecision = "1.0000"; + const std::string kAmount = "1.00"; + const std::string kAmountOverflow = "12.04"; + const std::string kAdminId = "admin@test"; + const std::string kAccountId = "test@test"; + const std::string kNoAcountId = "noacc"; + const std::string kAssetId = "coin#test"; + const std::string kNoAssetId = "no_asset#test"; + const std::string kDomainId = "test"; + const std::string kDescription = "test transfer"; + const std::string kAdminRole = "admin"; + const std::string kMasterRole = "master"; + const std::vector admin_roles = {kAdminRole}; + const shared_model::interface::types::PubkeyType kPubKey1 = + shared_model::interface::types::PubkeyType(std::string(32, '1')); + const shared_model::interface::types::PubkeyType kPubKey2 = + shared_model::interface::types::PubkeyType(std::string(32, '2')); + + std::vector role_permissions; + std::shared_ptr creator, account; + std::shared_ptr balance; + std::shared_ptr asset; + std::shared_ptr wallet; + + std::unique_ptr command; + + std::shared_ptr wsv_query; + std::shared_ptr wsv_command; + + std::unique_ptr executor; + std::unique_ptr validator; +}; + +class AddAssetQuantityTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_add_asset_qty}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().addAssetQuantity( + creator->accountId(), kAssetId, kAmount)); + add_asset_quantity = + getConcreteCommand(command); + } + + std::shared_ptr add_asset_quantity; +}; + +/** + * @given AddAssetQuantity where accountAsset doesn't exist at first call + * @when command is executed, new accountAsset will be created + * @then executor will be passed + */ +TEST_F(AddAssetQuantityTest, ValidWhenNewWallet) { + EXPECT_CALL(*wsv_query, getAccountAsset(add_asset_quantity->accountId(), _)) + .WillOnce(Return(boost::none)); + EXPECT_CALL(*wsv_query, getAsset(add_asset_quantity->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->accountId())) + .WillOnce(Return(account)); + EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_query, getAccountRoles(creator->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given AddAssetQuantity where accountAsset exists + * @when command is executed + * @then executor will be passed + */ +TEST_F(AddAssetQuantityTest, ValidWhenExistingWallet) { + EXPECT_CALL(*wsv_query, + getAccountAsset(add_asset_quantity->accountId(), + add_asset_quantity->assetId())) + .WillOnce(Return(wallet)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->accountId())) + .WillOnce(Return(account)); + EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given AddAssetQuantity where command creator role is wrong + * @when command is executed + * @then executor will be failed + */ +TEST_F(AddAssetQuantityTest, InvalidWhenNoRoles) { + EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->accountId())) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddAssetQuantity with amount with wrong precision (must be 2) + * @when command is executed + * @then executor will be failed + */ +TEST_F(AddAssetQuantityTest, InvalidWhenWrongPrecision) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - IR-1276 - rework with + // CommandBuilder + command = buildCommand(TestTransactionBuilder().addAssetQuantity( + creator->accountId(), kAssetId, kAmountWrongPrecision)); + add_asset_quantity = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddAssetQuantity + * @when command references non-existing account + * @then execute fails + */ +TEST_F(AddAssetQuantityTest, InvalidWhenNoAccount) { + // Account to add does not exist + EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->accountId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddAssetQuantity with wrong asset + * @when command is executed + * @then execute fails + */ +TEST_F(AddAssetQuantityTest, InvalidWhenNoAsset) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - IR-1276 - rework with + // CommandBuilder + command = buildCommand(TestTransactionBuilder().addAssetQuantity( + creator->accountId(), kNoAssetId, kAmount)); + add_asset_quantity = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAsset(add_asset_quantity->assetId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddAssetQuantity + * @when command adds value which overflows account balance + * @then execute fails + */ +TEST_F(AddAssetQuantityTest, InvalidWhenAssetAdditionFails) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().addAssetQuantity( + creator->accountId(), kAssetId, kMaxAmountStr)); + add_asset_quantity = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + getAccountAsset(add_asset_quantity->accountId(), + add_asset_quantity->assetId())) + .WillOnce(Return(wallet)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->accountId())) + .WillOnce(Return(account)); + EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +class SubtractAssetQuantityTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_subtract_asset_qty}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().subtractAssetQuantity( + creator->accountId(), kAssetId, kAmount)); + subtract_asset_quantity = + getConcreteCommand( + command); + } + + std::shared_ptr + subtract_asset_quantity; +}; + +/** + * @given SubtractAssetQuantity + * @when account doesn't have wallet of target asset + * @then executor will be failed + */ +TEST_F(SubtractAssetQuantityTest, InvalidWhenNoWallet) { + EXPECT_CALL(*wsv_query, + getAccountAsset(subtract_asset_quantity->accountId(), + subtract_asset_quantity->assetId())) + .WillOnce(Return(boost::none)); + EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SubtractAssetQuantity + * @when arguments are valid + * @then executor will be passed + */ +TEST_F(SubtractAssetQuantityTest, ValidWhenExistingWallet) { + EXPECT_CALL(*wsv_query, + getAccountAsset(subtract_asset_quantity->accountId(), + subtract_asset_quantity->assetId())) + .WillOnce(Return(wallet)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given SubtractAssetQuantity + * @when arguments amount is greater than wallet's amount + * @then executor will be failed + */ +TEST_F(SubtractAssetQuantityTest, InvalidWhenOverAmount) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().subtractAssetQuantity( + creator->accountId(), kAssetId, kAmountOverflow)); + subtract_asset_quantity = + getConcreteCommand( + command); + + EXPECT_CALL(*wsv_query, + getAccountAsset(subtract_asset_quantity->accountId(), + subtract_asset_quantity->assetId())) + .WillOnce(Return(wallet)); + + EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->accountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SubtractAssetQuantity + * @when account doesn't have role + * @then executor will be failed + */ +TEST_F(SubtractAssetQuantityTest, InvalidWhenNoRoles) { + EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->accountId())) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SubtractAssetQuantity + * @when arguments amount precision is invalid (greater than 2) + * @then executor will be failed + */ +TEST_F(SubtractAssetQuantityTest, InvalidWhenWrongPrecision) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().subtractAssetQuantity( + creator->accountId(), kAssetId, kAmountWrongPrecision)); + subtract_asset_quantity = + getConcreteCommand( + command); + + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SubtractAssetQuantity + * @when account doesn't exist + * @then executor will be failed + */ +TEST_F(SubtractAssetQuantityTest, InvalidWhenNoAccount) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().subtractAssetQuantity( + kNoAcountId, kAssetId, kAmount)); + subtract_asset_quantity = + getConcreteCommand( + command); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SubtractAssetQuantity + * @when asset doesn't exist + * @then executor will be failed + */ +TEST_F(SubtractAssetQuantityTest, InvalidWhenNoAsset) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().subtractAssetQuantity( + creator->accountId(), kNoAssetId, kAmount)); + subtract_asset_quantity = + getConcreteCommand( + command); + + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAsset(subtract_asset_quantity->assetId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +class AddSignatoryTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_add_signatory}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().addSignatory(kAccountId, kPubKey1)); + add_signatory = + getConcreteCommand(command); + } + + std::shared_ptr add_signatory; +}; + +/** + * @given AddSignatory creator has role permission to add signatory + * @when command is executed + * @then executor finishes successfully + */ +TEST_F(AddSignatoryTest, ValidWhenCreatorHasPermissions) { + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, add_signatory->accountId(), can_add_my_signatory)) + .WillOnce(Return(true)); + EXPECT_CALL(*wsv_command, insertSignatory(add_signatory->pubkey())) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, + insertAccountSignatory(add_signatory->accountId(), + add_signatory->pubkey())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given AddSignatory with valid parameters + * @when creator is adding public key to his account + * @then executor finishes successfully + */ +TEST_F(AddSignatoryTest, ValidWhenSameAccount) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().addSignatory(creator->accountId(), kPubKey1)); + add_signatory = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_command, insertSignatory(add_signatory->pubkey())) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, + insertAccountSignatory(add_signatory->accountId(), + add_signatory->pubkey())) + .WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given AddSignatory creator has not grantable permissions + * @when command is executed + * @then executor will be failed + */ +TEST_F(AddSignatoryTest, InvalidWhenNoPermissions) { + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, add_signatory->accountId(), can_add_my_signatory)) + .WillOnce(Return(false)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddSignatory command with wrong account + * @when command is executed + * @then executor will be failed + */ +TEST_F(AddSignatoryTest, InvalidWhenNoAccount) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = + buildCommand(TestTransactionBuilder().addSignatory(kNoAcountId, kPubKey1)); + add_signatory = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, add_signatory->accountId(), can_add_my_signatory)) + .WillOnce(Return(false)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddSignatory command with an existed public key + * @when command is executed + * @then executor will be failed + */ +TEST_F(AddSignatoryTest, InvalidWhenSameKey) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = + buildCommand(TestTransactionBuilder().addSignatory(kAccountId, kPubKey2)); + add_signatory = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, add_signatory->accountId(), can_add_my_signatory)) + .WillOnce(Return(true)); + EXPECT_CALL(*wsv_command, insertSignatory(add_signatory->pubkey())) + .WillOnce(Return(makeEmptyError())); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +class CreateAccountTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_create_account}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().createAccount("test", kDomainId, kPubKey2)); + create_account = + getConcreteCommand(command); + + default_domain = clone(shared_model::proto::DomainBuilder() + .domainId(kDomainId) + .defaultRole(kAdminRole) + .build()); + } + std::shared_ptr default_domain; + + std::shared_ptr create_account; +}; + +/** + * @given CreateAccount with vaild parameters + * @when command is executed + * @then executor will be passed + */ +TEST_F(CreateAccountTest, ValidWhenNewAccount) { + // Valid case + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getDomain(kDomainId)) + .WillOnce(Return(default_domain)); + EXPECT_CALL(*wsv_command, insertSignatory(create_account->pubkey())) + .Times(1) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, insertAccount(_)) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, + insertAccountSignatory(kAccountId, create_account->pubkey())) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, insertAccountRole(kAccountId, kAdminRole)) + .WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given CreateAccount command and creator has not roles + * @when command is executed + * @then executor will be failed + */ +TEST_F(CreateAccountTest, InvalidWhenNoPermissions) { + // Creator has no permission + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given CreateAccount command + * @when command tries to create account in a non-existing domain + * @then execute fails + */ +TEST_F(CreateAccountTest, InvalidWhenNoDomain) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getDomain(kDomainId)).WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +class CreateAssetTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_create_asset}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().createAsset("fcoin", kDomainId, 2)); + create_asset = + getConcreteCommand(command); + } + + std::shared_ptr create_asset; +}; + +/** + * @given CreateAsset with valid parameters + * @when command is executed + * @then executor will be passed + */ +TEST_F(CreateAssetTest, ValidWhenCreatorHasPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_command, insertAsset(_)) + .WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given CreateAsset and creator has not role permissions + * @when command is executed + * @then executor will be failed + */ +TEST_F(CreateAssetTest, InvalidWhenNoPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given CreateAsset + * @when command tries to create asset, but insertion fails + * @then execute() fails + */ +TEST_F(CreateAssetTest, InvalidWhenAssetInsertionFails) { + EXPECT_CALL(*wsv_command, insertAsset(_)).WillOnce(Return(makeEmptyError())); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class CreateDomainTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_create_domain}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = + buildCommand(TestTransactionBuilder().createDomain("cn", kDomainId)); + create_domain = + getConcreteCommand(command); + } + + std::shared_ptr create_domain; +}; + +/** + * @given CreateDomain with valid parameters + * @when command is executed + * @then executor will be passed + */ +TEST_F(CreateDomainTest, ValidWhenCreatorHasPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + + EXPECT_CALL(*wsv_command, insertDomain(_)) + .WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given CreateDomain and creator has not account roles + * @when command is executed + * @then executor will be failed + */ +TEST_F(CreateDomainTest, InvalidWhenNoPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given CreateDomain + * @when command tries to create domain, but insertion fails + * @then execute() fails + */ +TEST_F(CreateDomainTest, InvalidWhenDomainInsertionFails) { + EXPECT_CALL(*wsv_command, insertDomain(_)).WillOnce(Return(makeEmptyError())); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class RemoveSignatoryTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + auto creator_key = kPubKey1; + auto account_key = kPubKey2; + + account_pubkeys = {account_key}; + + many_pubkeys = {creator_key, account_key}; + + role_permissions = {can_remove_signatory}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().removeSignatory(kAccountId, kPubKey1)); + remove_signatory = + getConcreteCommand(command); + } + + std::vector account_pubkeys; + std::vector many_pubkeys; + + std::shared_ptr remove_signatory; +}; + +/** + * @given RemoveSignatory with valid parameters + * @when command is executed + * @then executor will be passed + */ +TEST_F(RemoveSignatoryTest, ValidWhenMultipleKeys) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccount(remove_signatory->accountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) + .WillOnce(Return(many_pubkeys)); + + EXPECT_CALL(*wsv_command, + deleteAccountSignatory(remove_signatory->accountId(), + remove_signatory->pubkey())) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, deleteSignatory(remove_signatory->pubkey())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory with valid parameters + * @when command is executed and return single signatory pubkey + * @then executor will be failed + */ +TEST_F(RemoveSignatoryTest, InvalidWhenSingleKey) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccount(remove_signatory->accountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) + .WillOnce(Return(account_pubkeys)); + + // delete methods must not be called because the account quorum is 1. + EXPECT_CALL(*wsv_command, + deleteAccountSignatory(remove_signatory->accountId(), + remove_signatory->pubkey())) + .Times(0); + EXPECT_CALL(*wsv_command, deleteSignatory(remove_signatory->pubkey())) + .Times(0); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory and creator has not grantable permissions + * @when command is executed + * @then executor will be passed + */ +TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissions) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) + .WillOnce(Return(false)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory with signatory is not present in account + * @when command is executed + * @then executor will be passed + */ +TEST_F(RemoveSignatoryTest, InvalidWhenNoKey) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + std::unique_ptr wrong_key_command = + buildCommand( + TestTransactionBuilder().removeSignatory(kAccountId, kPubKey1)); + auto wrong_key_remove_signatory = + getConcreteCommand( + wrong_key_command); + + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission(kAdminId, + wrong_key_remove_signatory->accountId(), + can_remove_my_signatory)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccount(wrong_key_remove_signatory->accountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_query, + getSignatories(wrong_key_remove_signatory->accountId())) + .WillOnce(Return(account_pubkeys)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(wrong_key_command))); +} + +/** + * @given RemoveSignatory + * @when command tries to remove signatory from non-existing account + * @then execute fails + */ +TEST_F(RemoveSignatoryTest, InvalidWhenNoAccount) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccount(remove_signatory->accountId())) + .WillOnce(Return(boost::none)); + + EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) + .WillOnce(Return(many_pubkeys)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory + * @when command tries to remove signatory from account which does not have + * any signatories + * @then execute fails + */ +TEST_F(RemoveSignatoryTest, InvalidWhenNoSignatories) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccount(remove_signatory->accountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory + * @when command tries to remove signatory from non-existing account and it + * has no signatories + * @then execute fails + */ +TEST_F(RemoveSignatoryTest, InvalidWhenNoAccountAndSignatories) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccount(remove_signatory->accountId())) + .WillOnce(Return(boost::none)); + + EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory + * @when command tries to remove signatory from creator's account but has no + * permissions and no grantable permissions to do that + * @then execute fails + */ +TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissionToRemoveFromSelf) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().removeSignatory(creator->accountId(), kPubKey1)); + auto remove_signatory = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(std::vector{})); + EXPECT_CALL(*wsv_query, getAccountRoles(creator->accountId())) + .WillOnce(Return(std::vector{kAdminRole})); + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, kAdminId, can_remove_my_signatory)) + .WillOnce(Return(false)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RemoveSignatory + * @when command tries to remove signatory but deletion fails + * @then execute() fails + */ +TEST_F(RemoveSignatoryTest, InvalidWhenAccountSignatoryDeletionFails) { + EXPECT_CALL(*wsv_command, + deleteAccountSignatory(remove_signatory->accountId(), + remove_signatory->pubkey())) + .WillOnce(Return(makeEmptyError())); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class SetQuorumTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + account_pubkeys = {kPubKey1, kPubKey2}; + role_permissions = {can_set_quorum}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = + buildCommand(TestTransactionBuilder().setAccountQuorum(kAccountId, 2)); + set_quorum = + getConcreteCommand(command); + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + creator_command = buildCommand( + TestTransactionBuilder().setAccountQuorum(creator->accountId(), 2)); + creator_set_quorum = + getConcreteCommand(creator_command); + } + + std::vector account_pubkeys; + + std::shared_ptr set_quorum; + std::unique_ptr creator_command; + std::shared_ptr creator_set_quorum; +}; + +/** + * @given SetQuorum and command creator is admin + * @when command executes + * @then execute successes + */ +TEST_F(SetQuorumTest, ValidWhenCreatorHasPermissions) { + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, set_quorum->accountId(), can_set_my_quorum)) + .WillOnce(Return(true)); + EXPECT_CALL(*wsv_query, getAccount(set_quorum->accountId())) + .WillOnce(Return(account)); + EXPECT_CALL(*wsv_query, getSignatories(set_quorum->accountId())) + .WillOnce(Return(account_pubkeys)); + EXPECT_CALL(*wsv_command, updateAccount(_)) + .WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given SetQuorum and creator is the account parameter + * @when command executes + * @then execute successes + */ +TEST_F(SetQuorumTest, ValidWhenSameAccount) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAccount(creator_set_quorum->accountId())) + .WillOnce(Return(account)); + EXPECT_CALL(*wsv_query, getSignatories(creator_set_quorum->accountId())) + .WillOnce(Return(account_pubkeys)); + EXPECT_CALL(*wsv_command, updateAccount(_)) + .WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(creator_command))); +} +/** + * @given SetQuorum and creator has not grantable permissions + * @when command executes + * @then execute fails + */ +TEST_F(SetQuorumTest, InvalidWhenNoPermissions) { + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, set_quorum->accountId(), can_set_my_quorum)) + .WillOnce(Return(false)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} +/** + * @given SetQuorum and account parameter is invalid + * @when command executes + * @then execute fails + */ +TEST_F(SetQuorumTest, InvalidWhenNoAccount) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().setAccountQuorum(kNoAcountId, 2)); + set_quorum = getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, set_quorum->accountId(), can_set_my_quorum)) + .WillOnce(Return(false)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SetQuorum + * @when command tries to set quorum for non-existing account + * @then execute fails + */ +TEST_F(SetQuorumTest, InvalidWhenNoAccountButPassedPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getSignatories(creator_set_quorum->accountId())) + .WillOnce(Return(account_pubkeys)); + + EXPECT_CALL(*wsv_query, getAccount(creator_set_quorum->accountId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(creator_command))); +} + +/** + * @given SetQuorum + * @when command tries to set quorum for account which does not have any + * signatories + * @then execute fails + */ +TEST_F(SetQuorumTest, InvalidWhenNoSignatories) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getSignatories(creator_set_quorum->accountId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(creator_command))); +} + +/** + * @given SetQuorum + * @when command tries to set quorum for account which does not have enough + * signatories + * @then execute fails + */ +TEST_F(SetQuorumTest, InvalidWhenNotEnoughSignatories) { + // Creator is the account + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getAccount(creator_set_quorum->accountId())).Times(0); + std::vector acc_pubkeys = { + kPubKey1}; + EXPECT_CALL(*wsv_query, getSignatories(creator_set_quorum->accountId())) + .WillOnce(Return(acc_pubkeys)); + EXPECT_CALL(*wsv_command, updateAccount(_)).Times(0); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(creator_command))); +} + +class TransferAssetTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + src_wallet = clone(shared_model::proto::AccountAssetBuilder() + .assetId(kAssetId) + .accountId(kAdminId) + .balance(*balance) + .build()); + + dst_wallet = clone(shared_model::proto::AccountAssetBuilder() + .assetId(kAssetId) + .accountId(kAccountId) + .balance(*balance) + .build()); + + role_permissions = {can_transfer, can_receive}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAdminId, kAccountId, kAssetId, kDescription, kAmount)); + transfer_asset = + getConcreteCommand(command); + } + + std::shared_ptr src_wallet, dst_wallet; + + std::shared_ptr transfer_asset; +}; + +/** + * @given TransferAsset and destination account has not AccountAsset + * @when command is executed and new AccountAsset will be created + * @then execute successes + */ +TEST_F(TransferAssetTest, ValidWhenNewWallet) { + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAccountAsset(transfer_asset->destAccountId(), _)) + .WillOnce(Return(boost::none)); + + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(src_wallet)); + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) + .Times(2) + .WillRepeatedly(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command is executed + * @then execute successes + */ +TEST_F(TransferAssetTest, ValidWhenExistingWallet) { + // When there is a wallet - no new accountAsset created + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->destAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(dst_wallet)); + + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(src_wallet)); + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) + .Times(2) + .WillRepeatedly(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset and creator has permissions + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(TransferAssetTest, ValidWhenCreatorHasPermission) { + // Transfer creator is not connected to account + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAccountId, kAdminId, kAssetId, kDescription, kAmount)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, kAccountId, can_transfer_my_assets)) + .WillOnce(Return(true)); + + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAccountAsset(transfer_asset->destAccountId(), _)) + .WillOnce(Return(boost::none)); + + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(src_wallet)); + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) + .WillOnce(Return(account)); + + EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) + .Times(2) + .WillRepeatedly(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset and creator has not account roles + * @when command is executed + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenNoPermissions) { + // Creator has no permissions + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset and destination account doesn't have any role + * @when command is executed + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenNoDestAccount) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAdminId, kNoAcountId, kAssetId, kDescription, kAmount)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(boost::none)); + + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset and source account doesn't have asset + * @when command is executed + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenNoSrcAccountAsset) { + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer asset from non-existing account + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenNoSrcAccountAssetDuringExecute) { + // No source account asset exists + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .Times(2) + .WillOnce(Return(src_wallet)) + .WillOnce(Return(boost::none)); + EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) + .WillOnce(Return(account)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer non-existent asset + * @then isValid fails + */ +TEST_F(TransferAssetTest, InvalidWhenNoAssetDuringValidation) { + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(boost::none)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer non-existent asset + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenNoAssetId) { + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)) + .WillOnce(Return(boost::none)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .Times(2) + .WillRepeatedly(Return(src_wallet)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->destAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(dst_wallet)); + EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) + .WillOnce(Return(account)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer amount which is less than source balance + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenInsufficientFunds) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAdminId, kAccountId, kAssetId, kDescription, kAmountOverflow)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(src_wallet)); + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) + .WillOnce(Return(account)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer amount which is less than source balance + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenInsufficientFundsDuringExecute) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAdminId, kAccountId, kAssetId, kDescription, kAmountOverflow)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(src_wallet)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->destAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(dst_wallet)); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer amount which has wrong precesion (must be 2) + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenWrongPrecision) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAdminId, kAccountId, kAssetId, kDescription, kAmountWrongPrecision)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->destAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer amount with wrong precision + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenWrongPrecisionDuringExecute) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAdminId, kAccountId, kAssetId, kDescription, kAmountWrongPrecision)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(src_wallet)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->destAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(dst_wallet)); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +/** + * @given TransferAsset + * @when command tries to transfer asset which overflows destination balance + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenAmountOverflow) { + std::shared_ptr max_balance = clone( + shared_model::proto::AmountBuilder() + .intValue( + std::numeric_limits::max()) + .precision(2) + .build()); + + std::shared_ptr max_wallet = + clone(shared_model::proto::AccountAssetBuilder() + .assetId(src_wallet->assetId()) + .accountId(src_wallet->accountId()) + .balance(*max_balance) + .build()); + + EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) + .WillOnce(Return(asset)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->srcAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(src_wallet)); + EXPECT_CALL(*wsv_query, + getAccountAsset(transfer_asset->destAccountId(), + transfer_asset->assetId())) + .WillOnce(Return(max_wallet)); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +/** + * @given TransferAsset and creator has not grantable permissions + * @when command tries to transfer + * @then execute fails + */ +TEST_F(TransferAssetTest, InvalidWhenCreatorHasNoPermission) { + // Transfer creator is not connected to account + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().transferAsset( + kAccountId, kAdminId, kAssetId, kDescription, kAmount)); + auto transfer_asset = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, kAccountId, can_transfer_my_assets)) + .WillOnce(Return(false)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +class AddPeerTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_add_peer}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().addPeer("iroha_node:10001", kPubKey1)); + } +}; + +/** + * @given AddPeer and all parameters are valid + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(AddPeerTest, ValidCase) { + // Valid case + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_command, insertPeer(_)).WillOnce(Return(WsvCommandResult())); + + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given AddPeer and creator has not role permissions + * @when command tries to transfer + * @then execute failed + */ +TEST_F(AddPeerTest, InvalidCaseWhenNoPermissions) { + // Valid case + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AddPeer + * @when command tries to insert peer but insertion fails + * @then execute failed + */ +TEST_F(AddPeerTest, InvalidCaseWhenInsertPeerFails) { + EXPECT_CALL(*wsv_command, insertPeer(_)).WillOnce(Return(makeEmptyError())); + + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class CreateRoleTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + std::set perm = {can_create_role}; + role_permissions = {can_create_role}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand(TestTransactionBuilder().createRole(kAccountId, perm)); + create_role = + getConcreteCommand(command); + } + std::shared_ptr create_role; +}; + +/** + * @given CreateRole and all parameters are valid + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(CreateRoleTest, ValidCase) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillRepeatedly(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillRepeatedly(Return(role_permissions)); + EXPECT_CALL(*wsv_command, insertRole(create_role->roleName())) + .WillOnce(Return(WsvCommandResult())); + EXPECT_CALL(*wsv_command, + insertRolePermissions(create_role->roleName(), + create_role->rolePermissions())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given CreateRole and creator has not role permissions + * @when command tries to transfer + * @then execute is failed + */ +TEST_F(CreateRoleTest, InvalidCaseWhenNoPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillRepeatedly(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillRepeatedly(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given CreateRole with wrong permissions + * @when command tries to transfer + * @then execute is failed + */ +TEST_F(CreateRoleTest, InvalidCaseWhenRoleSuperset) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + std::set master_perms = {can_add_peer, can_append_role}; + command = + buildCommand(TestTransactionBuilder().createRole(kMasterRole, master_perms)); + + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillRepeatedly(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillRepeatedly(Return(role_permissions)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given CreateRole + * @when command tries to create new role, but insertion fails + * @then execute failed + */ +TEST_F(CreateRoleTest, InvalidCaseWhenRoleInsertionFails) { + EXPECT_CALL(*wsv_command, insertRole(create_role->roleName())) + .WillOnce(Return(makeEmptyError())); + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class AppendRoleTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_append_role}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = + buildCommand(TestTransactionBuilder().appendRole(kAccountId, kMasterRole)); + append_role = + getConcreteCommand(command); + } + std::shared_ptr append_role; +}; + +/** + * @given CreateRole and all parameters are valid + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(AppendRoleTest, ValidCase) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .Times(2) + .WillRepeatedly(Return(admin_roles)); + + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillRepeatedly(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) + .WillOnce(Return(role_permissions)); + + EXPECT_CALL( + *wsv_command, + insertAccountRole(append_role->accountId(), append_role->roleName())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given CreateRole and creator has not role permissions + * @when command tries to transfer + * @then execute failed + */ +TEST_F(AppendRoleTest, InvalidCaseNoPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AppendRole + * @when command tries to append non-existing role + * @then execute() fails + */ +TEST_F(AppendRoleTest, InvalidCaseNoAccountRole) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .Times(2) + .WillOnce(Return(admin_roles)) + .WillOnce((Return(boost::none))); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) + .WillOnce(Return(role_permissions)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AppendRole + * @when command tries to append non-existing role and creator does not have + any + * roles + * @then execute() fails + */ +TEST_F(AppendRoleTest, InvalidCaseNoAccountRoleAndNoPermission) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .Times(2) + .WillOnce(Return(admin_roles)) + .WillOnce((Return(boost::none))); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AppendRole + * @when command tries to append role, but creator account does not have + * necessary permission + * @then execute() fails + */ +TEST_F(AppendRoleTest, InvalidCaseRoleHasNoPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .Times(2) + .WillOnce(Return(admin_roles)) + .WillOnce((Return(admin_roles))); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .Times(2) + .WillOnce(Return(role_permissions)) + .WillOnce(Return(boost::none)); + EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) + .WillOnce(Return(role_permissions)); + + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given AppendRole + * @when command tries to append role, but insertion of account fails + * @then execute() fails + */ +TEST_F(AppendRoleTest, InvalidCaseInsertAccountRoleFails) { + EXPECT_CALL( + *wsv_command, + insertAccountRole(append_role->accountId(), append_role->roleName())) + .WillOnce(Return(makeEmptyError())); + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class DetachRoleTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + role_permissions = {can_detach_role}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = + buildCommand(TestTransactionBuilder().detachRole(kAccountId, kMasterRole)); + detach_role = + getConcreteCommand(command); + } + std::shared_ptr detach_role; +}; + +/** + * @given DetachRole and all parameters are valid + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(DetachRoleTest, ValidCase) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL( + *wsv_command, + deleteAccountRole(detach_role->accountId(), detach_role->roleName())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given DetachRole and creator has not role permissions + * @when command tries to transfer + * @then execute failed + */ +TEST_F(DetachRoleTest, InvalidCase) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given DetachRole + * @when deletion of account role fails + * @then execute fails() + */ +TEST_F(DetachRoleTest, InvalidCaseWhenDeleteAccountRoleFails) { + EXPECT_CALL( + *wsv_command, + deleteAccountRole(detach_role->accountId(), detach_role->roleName())) + .WillOnce(Return(makeEmptyError())); + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class GrantPermissionTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + expected_permission = can_add_my_signatory; + role_permissions = {can_grant + expected_permission}; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().grantPermission(kAccountId, expected_permission)); + grant_permission = + getConcreteCommand(command); + } + std::shared_ptr grant_permission; + std::string expected_permission; +}; + +/** + * @given GrantPermission and all parameters are valid + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(GrantPermissionTest, ValidCase) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(role_permissions)); + EXPECT_CALL(*wsv_command, + insertAccountGrantablePermission(grant_permission->accountId(), + creator->accountId(), + expected_permission)) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given GrantPermission and creator has not role permissions + * @when command tries to transfer + * @then execute failed + */ +TEST_F(GrantPermissionTest, InvalidCaseWhenNoPermissions) { + EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) + .WillOnce(Return(admin_roles)); + EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) + .WillOnce(Return(boost::none)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given GrantPermission + * @when command tries to grant permission but insertion fails + * @then execute() fails + */ +TEST_F(GrantPermissionTest, InvalidCaseWhenInsertGrantablePermissionFails) { + EXPECT_CALL(*wsv_command, + insertAccountGrantablePermission(grant_permission->accountId(), + creator->accountId(), + expected_permission)) + .WillOnce(Return(makeEmptyError())); + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class RevokePermissionTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + expected_permission = can_add_my_signatory; + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().revokePermission(kAccountId, expected_permission)); + revoke_permission = + getConcreteCommand(command); + } + + std::shared_ptr revoke_permission; + std::string expected_permission; +}; + +/** + * @given RevokePermission and all parameters are valid + * @when command tries to transfer + * @then execute succeses + */ +TEST_F(RevokePermissionTest, ValidCase) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + revoke_permission->accountId(), kAdminId, expected_permission)) + .WillOnce(Return(true)); + EXPECT_CALL(*wsv_command, + deleteAccountGrantablePermission(revoke_permission->accountId(), + creator->accountId(), + expected_permission)) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given RevokePermission and creator has not grantable permissions + * @when command tries to transfer + * @then execute failed + */ +TEST_F(RevokePermissionTest, InvalidCaseNoPermissions) { + EXPECT_CALL( + *wsv_query, + hasAccountGrantablePermission( + revoke_permission->accountId(), kAdminId, expected_permission)) + .WillOnce(Return(false)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given RevokePermission + * @when deleting permission fails + * @then execute fails + */ +TEST_F(RevokePermissionTest, InvalidCaseDeleteAccountPermissionvFails) { + EXPECT_CALL(*wsv_command, + deleteAccountGrantablePermission(revoke_permission->accountId(), + creator->accountId(), + expected_permission)) + .WillOnce(Return(makeEmptyError())); + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} + +class SetAccountDetailTest : public CommandValidateExecuteTest { + public: + void SetUp() override { + CommandValidateExecuteTest::SetUp(); + + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().setAccountDetail(kAdminId, kKey, kValue)); + set_aacount_detail = + getConcreteCommand(command); + + role_permissions = {can_set_quorum}; + } + + const std::string kKey = "key"; + const std::string kValue = "val"; + const std::string kNeededPermission = can_set_my_account_detail; + + std::shared_ptr set_aacount_detail; +}; + +/** + * @given SetAccountDetail and all parameters are valid + * @when creator is setting details to their account + * @then successfully execute the command + */ +TEST_F(SetAccountDetailTest, ValidWhenSetOwnAccount) { + EXPECT_CALL(*wsv_command, + setAccountKV(set_aacount_detail->accountId(), + creator->accountId(), + set_aacount_detail->key(), + set_aacount_detail->value())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given SetAccountDetail + * @when creator is setting details to their account + * @then execute fails + */ +TEST_F(SetAccountDetailTest, InValidWhenOtherCreator) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().setAccountDetail(kAccountId, kKey, kValue)); + set_aacount_detail = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, set_aacount_detail->accountId(), kNeededPermission)) + .WillOnce(Return(false)); + ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); +} + +/** + * @given SetAccountDetail + * @when creator is setting details to their account + * @then successfully execute the command + */ +TEST_F(SetAccountDetailTest, ValidWhenHasPermissions) { + // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder + command = buildCommand( + TestTransactionBuilder().setAccountDetail(kAccountId, kKey, kValue)); + set_aacount_detail = + getConcreteCommand(command); + + EXPECT_CALL(*wsv_query, + hasAccountGrantablePermission( + kAdminId, set_aacount_detail->accountId(), kNeededPermission)) + .WillOnce(Return(true)); + EXPECT_CALL(*wsv_command, + setAccountKV(set_aacount_detail->accountId(), + creator->accountId(), + set_aacount_detail->key(), + set_aacount_detail->value())) + .WillOnce(Return(WsvCommandResult())); + ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); +} + +/** + * @given SetAccountDetail + * @when command tries to set details, but setting key-value fails + * @then execute fails + */ +TEST_F(SetAccountDetailTest, InvalidWhenSetAccountKVFails) { + EXPECT_CALL(*wsv_command, + setAccountKV(set_aacount_detail->accountId(), + creator->accountId(), + set_aacount_detail->key(), + set_aacount_detail->value())) + .WillOnce(Return(makeEmptyError())); + ASSERT_NO_THROW(checkErrorCase(execute(command))); +} diff --git a/test/module/irohad/model/CMakeLists.txt b/test/module/irohad/model/CMakeLists.txt index 5a862ecd3c..5c041f0414 100644 --- a/test/module/irohad/model/CMakeLists.txt +++ b/test/module/irohad/model/CMakeLists.txt @@ -48,13 +48,6 @@ target_link_libraries(model_operators_test model ) -addtest(command_validate_execute_test command_validate_execute_test.cpp) -target_link_libraries(command_validate_execute_test - model - command_execution - shared_model_stateless_validation - ) - addtest(json_command_converter_test converters/json_commands_test.cpp) target_link_libraries(json_command_converter_test json_model_converters diff --git a/test/module/irohad/model/command_validate_execute_test.cpp b/test/module/irohad/model/command_validate_execute_test.cpp deleted file mode 100644 index f4b35a5b64..0000000000 --- a/test/module/irohad/model/command_validate_execute_test.cpp +++ /dev/null @@ -1,2017 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "backend/protobuf/from_old_model.hpp" -#include "builders/default_builders.hpp" -#include "execution/command_executor.hpp" -#include "framework/result_fixture.hpp" -#include "model/commands/add_asset_quantity.hpp" -#include "model/commands/add_peer.hpp" -#include "model/commands/add_signatory.hpp" -#include "model/commands/append_role.hpp" -#include "model/commands/create_account.hpp" -#include "model/commands/create_asset.hpp" -#include "model/commands/create_domain.hpp" -#include "model/commands/create_role.hpp" -#include "model/commands/detach_role.hpp" -#include "model/commands/grant_permission.hpp" -#include "model/commands/remove_signatory.hpp" -#include "model/commands/revoke_permission.hpp" -#include "model/commands/set_account_detail.hpp" -#include "model/commands/set_quorum.hpp" -#include "model/commands/subtract_asset_quantity.hpp" -#include "model/commands/transfer_asset.hpp" -#include "validators/permissions.hpp" -#include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" - -using ::testing::AllOf; -using ::testing::AtLeast; -using ::testing::Return; -using ::testing::StrictMock; -using ::testing::_; - -using namespace iroha; -using namespace iroha::ametsuchi; -using namespace iroha::model; -using namespace framework::expected; -using namespace shared_model::permissions; - -class CommandValidateExecuteTest : public ::testing::Test { - public: - void SetUp() override { - wsv_query = std::make_shared>(); - wsv_command = std::make_shared>(); - - executor = std::make_shared( - iroha::CommandExecutor(wsv_query, wsv_command)); - validator = std::make_shared( - iroha::CommandValidator(wsv_query)); - - shared_model::builder::AccountBuilder< - shared_model::proto::AccountBuilder, - shared_model::validation::FieldValidator>() - .accountId(admin_id) - .domainId(domain_id) - .quorum(1) - .build() - .match( - [&](expected::Value< - std::shared_ptr> &v) { - creator = v.value; - }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - shared_model::builder::AccountBuilder< - shared_model::proto::AccountBuilder, - shared_model::validation::FieldValidator>() - .accountId(account_id) - .domainId(domain_id) - .quorum(1) - .build() - .match( - [&](expected::Value< - std::shared_ptr> &v) { - account = v.value; - }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - default_domain = clone(shared_model::proto::DomainBuilder() - .domainId(domain_id) - .defaultRole(admin_role) - .build()); - } - - iroha::ExecutionResult validateAndExecute() { - shared_model::proto::Command new_command = - shared_model::proto::from_old(*command); - validator->setCreatorAccountId(creator->accountId()); - executor->setCreatorAccountId(creator->accountId()); - - if (boost::apply_visitor(*validator, new_command.get())) { - return boost::apply_visitor(*executor, new_command.get()); - } - return expected::makeError( - iroha::ExecutionError{"Validate", "validation of a command failed"}); - } - - iroha::ExecutionResult execute() { - shared_model::proto::Command new_command = - shared_model::proto::from_old(*command); - executor->setCreatorAccountId(creator->accountId()); - return boost::apply_visitor(*executor, new_command.get()); - } - - /// return result with empty error message - WsvCommandResult makeEmptyError() { - return WsvCommandResult(iroha::expected::makeError("")); - } - - /// Returns error from result or throws error in case result contains value - iroha::ExecutionResult::ErrorType checkErrorCase( - const iroha::ExecutionResult &result) { - return boost::get(result); - } - - Amount max_amount{ - std::numeric_limits::max(), 2}; - std::string admin_id = "admin@test", account_id = "test@test", - asset_id = "coin#test", domain_id = "test", - description = "test transfer"; - - std::string admin_role = "admin"; - - std::vector admin_roles = {admin_role}; - std::vector role_permissions; - std::shared_ptr default_domain; - - std::shared_ptr wsv_query; - std::shared_ptr wsv_command; - - std::shared_ptr creator, account; - - std::shared_ptr command; - - std::shared_ptr executor; - std::shared_ptr validator; -}; - -class AddAssetQuantityTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - shared_model::builder::AssetBuilder< - shared_model::proto::AssetBuilder, - shared_model::validation::FieldValidator>() - .assetId(asset_id) - .domainId(domain_id) - .precision(2) - .build() - .match( - [&](expected::Value> - &v) { asset = v.value; }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - shared_model::builder::AmountBuilder< - shared_model::proto::AmountBuilder, - shared_model::validation::FieldValidator>() - .intValue(150) - .precision(2) - .build() - .match( - [&](expected::Value< - std::shared_ptr> &v) { - balance = v.value; - }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - shared_model::builder::AccountAssetBuilder< - shared_model::proto::AccountAssetBuilder, - shared_model::validation::FieldValidator>() - .assetId(asset_id) - .accountId(account_id) - .balance(*balance) - .build() - .match( - [&](expected::Value< - std::shared_ptr> &v) { - wallet = v.value; - }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - add_asset_quantity = std::make_shared(); - add_asset_quantity->account_id = creator->accountId(); - Amount amount(350, 2); - add_asset_quantity->amount = amount; - add_asset_quantity->asset_id = asset_id; - - command = add_asset_quantity; - role_permissions = {can_add_asset_qty}; - } - - std::shared_ptr balance; - std::shared_ptr asset; - std::shared_ptr wallet; - - std::shared_ptr add_asset_quantity; -}; - -TEST_F(AddAssetQuantityTest, ValidWhenNewWallet) { - // Add asset first time - no wallet - // When there is no wallet - new accountAsset will be created - EXPECT_CALL(*wsv_query, getAccountAsset(add_asset_quantity->account_id, _)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL(*wsv_query, getAsset(add_asset_quantity->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->account_id)) - .WillOnce(Return(account)); - EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL(*wsv_query, getAccountRoles(creator->accountId())) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(AddAssetQuantityTest, ValidWhenExistingWallet) { - // There is already asset- there is a wallet - // When there is a wallet - no new accountAsset created - EXPECT_CALL(*wsv_query, - getAccountAsset(add_asset_quantity->account_id, - add_asset_quantity->asset_id)) - .WillOnce(Return(wallet)); - - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->account_id)) - .WillOnce(Return(account)); - EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(AddAssetQuantityTest, InvalidWhenNoRoles) { - // Creator has no roles - EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->account_id)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(AddAssetQuantityTest, InvalidWhenZeroAmount) { - // Amount is zero - Amount amount(0); - add_asset_quantity->amount = amount; - EXPECT_CALL(*wsv_query, getAsset(asset->assetId())).WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccountRoles(creator->accountId())) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(AddAssetQuantityTest, InvalidWhenWrongPrecision) { - // Amount is with wrong precision (must be 2) - Amount amount(add_asset_quantity->amount.getIntValue(), 30); - add_asset_quantity->amount = amount; - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AddAssetQuantity - * @when command references non-existing account - * @then execute fails and returns false - */ -TEST_F(AddAssetQuantityTest, InvalidWhenNoAccount) { - // Account to add does not exist - EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(AddAssetQuantityTest, InvalidWhenNoAsset) { - // Asset doesn't exist - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - add_asset_quantity->asset_id = "noass"; - - EXPECT_CALL(*wsv_query, getAsset(add_asset_quantity->asset_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AddAssetQuantity - * @when command adds value which overflows account balance - * @then execute fails and returns false - */ -TEST_F(AddAssetQuantityTest, InvalidWhenAssetAdditionFails) { - // amount overflows - add_asset_quantity->amount = max_amount; - - EXPECT_CALL(*wsv_query, - getAccountAsset(add_asset_quantity->account_id, - add_asset_quantity->asset_id)) - .WillOnce(Return(wallet)); - - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->account_id)) - .WillOnce(Return(account)); - EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -class SubtractAssetQuantityTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - shared_model::builder::AmountBuilder< - shared_model::proto::AmountBuilder, - shared_model::validation::FieldValidator>() - .intValue(150ul) - .precision(2) - .build() - .match( - [&](expected::Value< - std::shared_ptr> &v) { - balance = v.value; - }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - ; - - shared_model::builder::AssetBuilder< - shared_model::proto::AssetBuilder, - shared_model::validation::FieldValidator>() - .assetId(asset_id) - .domainId(domain_id) - .precision(2) - .build() - .match( - [&](expected::Value> - &v) { asset = v.value; }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - shared_model::builder::AccountAssetBuilder< - shared_model::proto::AccountAssetBuilder, - shared_model::validation::FieldValidator>() - .assetId(asset_id) - .accountId(account_id) - .balance(*balance) - .build() - .match( - [&](expected::Value< - std::shared_ptr> &v) { - wallet = v.value; - }, - [](expected::Error> &e) { - FAIL() << *e.error; - }); - - subtract_asset_quantity = std::make_shared(); - subtract_asset_quantity->account_id = creator->accountId(); - Amount amount(100, 2); - subtract_asset_quantity->amount = amount; - subtract_asset_quantity->asset_id = asset_id; - - command = subtract_asset_quantity; - role_permissions = {can_subtract_asset_qty}; - } - - std::shared_ptr balance; - std::shared_ptr asset; - std::shared_ptr wallet; - - std::shared_ptr subtract_asset_quantity; -}; - -/** - * @given SubtractAssetQuantity - * @when account doesn't have wallet of target asset - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenNoWallet) { - // Subtract asset - no wallet - // When there is no wallet - Failed - EXPECT_CALL(*wsv_query, - getAccountAsset(subtract_asset_quantity->account_id, - subtract_asset_quantity->asset_id)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when correct arguments - * @then executor will be passed - */ -TEST_F(SubtractAssetQuantityTest, ValidWhenExistingWallet) { - // There is already asset- there is a wallet - // When there is a wallet - no new accountAsset created - EXPECT_CALL(*wsv_query, - getAccountAsset(subtract_asset_quantity->account_id, - subtract_asset_quantity->asset_id)) - .WillOnce(Return(wallet)); - - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when arguments amount is greater than wallet's amount - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenOverAmount) { - Amount amount(1204, 2); - subtract_asset_quantity->amount = amount; - EXPECT_CALL(*wsv_query, - getAccountAsset(subtract_asset_quantity->account_id, - subtract_asset_quantity->asset_id)) - .WillOnce(Return(wallet)); - - EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when account doesn't have role - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenNoRoles) { - // Creator has no roles - EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->account_id)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when arguments amount is zero - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenZeroAmount) { - // Amount is zero - Amount amount(0); - subtract_asset_quantity->amount = amount; - EXPECT_CALL(*wsv_query, getAsset(asset->assetId())).WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccountRoles(creator->accountId())) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when arguments amount precision is invalid - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenWrongPrecision) { - // Amount is with wrong precision (must be 2) - Amount amount(subtract_asset_quantity->amount.getIntValue(), 30); - subtract_asset_quantity->amount = amount; - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getAsset(asset_id)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when account doesn't exist - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenNoAccount) { - // Account to subtract doesn't exist - subtract_asset_quantity->account_id = "noacc"; - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SubtractAssetQuantity - * @when asset doesn't exist - * @then executor will be failed - */ -TEST_F(SubtractAssetQuantityTest, InvalidWhenNoAsset) { - // Asset doesn't exist - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - subtract_asset_quantity->asset_id = "noass"; - - EXPECT_CALL(*wsv_query, getAsset(subtract_asset_quantity->asset_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -class AddSignatoryTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - add_signatory = std::make_shared(); - add_signatory->account_id = account_id; - add_signatory->pubkey.fill(1); // Such Pubkey exist - role_permissions = {can_add_signatory}; - command = add_signatory; - } - - std::shared_ptr add_signatory; -}; - -TEST_F(AddSignatoryTest, ValidWhenCreatorHasPermissions) { - // Creator has role permissions to add signatory - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_my_signatory)) - .WillOnce(Return(true)); - EXPECT_CALL( - *wsv_command, - insertSignatory(shared_model::crypto::PublicKey( - {add_signatory->pubkey.begin(), add_signatory->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL(*wsv_command, - insertAccountSignatory(add_signatory->account_id, - shared_model::crypto::PublicKey( - {add_signatory->pubkey.begin(), - add_signatory->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(AddSignatoryTest, ValidWhenSameAccount) { - // When creator is adding public keys to his account - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - add_signatory->account_id = creator->accountId(); - - EXPECT_CALL( - *wsv_command, - insertSignatory(shared_model::crypto::PublicKey( - {add_signatory->pubkey.begin(), add_signatory->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL(*wsv_command, - insertAccountSignatory(add_signatory->account_id, - shared_model::crypto::PublicKey( - {add_signatory->pubkey.begin(), - add_signatory->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(AddSignatoryTest, InvalidWhenNoPermissions) { - // Creator has no permission - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_my_signatory)) - .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(AddSignatoryTest, InvalidWhenNoAccount) { - // Add to nonexistent account - add_signatory->account_id = "noacc"; - - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_my_signatory)) - .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(AddSignatoryTest, InvalidWhenSameKey) { - // Add same signatory - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, add_signatory->account_id, can_add_my_signatory)) - .WillOnce(Return(true)); - add_signatory->pubkey.fill(2); - EXPECT_CALL( - *wsv_command, - insertSignatory(shared_model::crypto::PublicKey( - {add_signatory->pubkey.begin(), add_signatory->pubkey.end()}))) - .WillOnce(Return(makeEmptyError())); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -class CreateAccountTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - create_account = std::make_shared(); - create_account->account_name = "test"; - create_account->domain_id = domain_id; - create_account->pubkey.fill(2); - - command = create_account; - role_permissions = {can_create_account}; - } - - std::shared_ptr create_account; -}; - -TEST_F(CreateAccountTest, ValidWhenNewAccount) { - // Valid case - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getDomain(domain_id)) - .WillOnce(Return(default_domain)); - - EXPECT_CALL( - *wsv_command, - insertSignatory(shared_model::crypto::PublicKey( - {create_account->pubkey.begin(), create_account->pubkey.end()}))) - .Times(1) - .WillOnce(Return(WsvCommandResult())); - - EXPECT_CALL(*wsv_command, insertAccount(_)) - .WillOnce(Return(WsvCommandResult())); - - EXPECT_CALL(*wsv_command, - insertAccountSignatory(account_id, - shared_model::crypto::PublicKey( - {create_account->pubkey.begin(), - create_account->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL(*wsv_command, insertAccountRole(account_id, admin_role)) - .WillOnce(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(CreateAccountTest, InvalidWhenNoPermissions) { - // Creator has no permission - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(CreateAccountTest, InvalidWhenLongName) { - // Not valid name for account - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - create_account->account_name = - "aAccountNameMustBeLessThan64characters00000000000000000000000000"; - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(CreateAccountTest, InvalidWhenNameWithSystemSymbols) { - // Not valid name for account (system symbols) - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - create_account->account_name = "test@"; - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given CreateAccountCommand - * @when command tries to create account in a non-existing domain - * @then execute fails and returns false - */ -TEST_F(CreateAccountTest, InvalidWhenNoDomain) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getDomain(domain_id)).WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -class CreateAssetTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - create_asset = std::make_shared(); - create_asset->asset_name = "fcoin"; - create_asset->domain_id = domain_id; - create_asset->precision = 2; - - command = create_asset; - role_permissions = {can_create_asset}; - } - - std::shared_ptr create_asset; -}; - -TEST_F(CreateAssetTest, ValidWhenCreatorHasPermissions) { - // Creator is money creator - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - - EXPECT_CALL(*wsv_command, insertAsset(_)) - .WillOnce(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(CreateAssetTest, InvalidWhenNoPermissions) { - // Creator has no permissions - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given CreateAsset - * @when command tries to create asset, but insertion fails - * @then execute() fails - */ -TEST_F(CreateAssetTest, InvalidWhenAssetInsertionFails) { - EXPECT_CALL(*wsv_command, insertAsset(_)).WillOnce(Return(makeEmptyError())); - - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class CreateDomainTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - create_domain = std::make_shared(); - create_domain->domain_id = "cn"; - create_domain->user_default_role = "default"; - - command = create_domain; - role_permissions = {can_create_domain}; - } - - std::shared_ptr create_domain; -}; - -TEST_F(CreateDomainTest, ValidWhenCreatorHasPermissions) { - // Valid case - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - - EXPECT_CALL(*wsv_command, insertDomain(_)) - .WillOnce(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(CreateDomainTest, InvalidWhenNoPermissions) { - // Creator has no permissions - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given CreateDomain - * @when command tries to create domain, but insertion fails - * @then execute() fails - */ -TEST_F(CreateDomainTest, InvalidWhenDomainInsertionFails) { - EXPECT_CALL(*wsv_command, insertDomain(_)).WillOnce(Return(makeEmptyError())); - - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class RemoveSignatoryTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - pubkey_t creator_key, account_key; - creator_key.fill(0x1); - account_key.fill(0x2); - - account_pubkeys = { - shared_model::interface::types::PubkeyType(account_key.to_string())}; - many_pubkeys = { - shared_model::interface::types::PubkeyType(creator_key.to_string()), - shared_model::interface::types::PubkeyType(account_key.to_string())}; - - remove_signatory = std::make_shared(); - remove_signatory->account_id = account_id; - remove_signatory->pubkey.fill(1); - - command = remove_signatory; - role_permissions = {can_remove_signatory}; - } - - std::vector account_pubkeys; - std::vector many_pubkeys; - std::shared_ptr remove_signatory; -}; - -TEST_F(RemoveSignatoryTest, ValidWhenMultipleKeys) { - // Creator is admin - // Add same signatory - - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->account_id)) - .WillOnce(Return(many_pubkeys)); - - EXPECT_CALL(*wsv_command, - deleteAccountSignatory(remove_signatory->account_id, - shared_model::crypto::PublicKey( - {remove_signatory->pubkey.begin(), - remove_signatory->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL( - *wsv_command, - deleteSignatory(shared_model::crypto::PublicKey( - {remove_signatory->pubkey.begin(), remove_signatory->pubkey.end()}))) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(RemoveSignatoryTest, InvalidWhenSingleKey) { - // Creator is admin - - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->account_id)) - .WillOnce(Return(account_pubkeys)); - - // delete methods must not be called because the account quorum is 1. - EXPECT_CALL(*wsv_command, - deleteAccountSignatory(remove_signatory->account_id, - shared_model::crypto::PublicKey( - {remove_signatory->pubkey.begin(), - remove_signatory->pubkey.end()}))) - .Times(0); - EXPECT_CALL( - *wsv_command, - deleteSignatory(shared_model::crypto::PublicKey( - {remove_signatory->pubkey.begin(), remove_signatory->pubkey.end()}))) - .Times(0); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissions) { - // Creator has no permissions - // Add same signatory - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(false)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(RemoveSignatoryTest, InvalidWhenNoKey) { - // Remove signatory not present in account - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(true)); - remove_signatory->pubkey.fill(0xF); - - EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->account_id)) - - .WillOnce(Return(account_pubkeys)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given RemoveSignatory - * @when command tries to remove signatory from non-existing account - * @then execute fails and returns false - */ -TEST_F(RemoveSignatoryTest, InvalidWhenNoAccount) { - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->account_id)) - .WillOnce(Return(many_pubkeys)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given RemoveSignatory - * @when command tries to remove signatory from account which does not have any - * signatories - * @then execute fails and returns false - */ -TEST_F(RemoveSignatoryTest, InvalidWhenNoSignatories) { - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given RemoveSignatory - * @when command tries to remove signatory from non-existing account and it has - * no signatories - * @then execute fails and returns false - */ -TEST_F(RemoveSignatoryTest, InvalidWhenNoAccountAndSignatories) { - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, remove_signatory->account_id, can_remove_my_signatory)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccount(remove_signatory->account_id)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given RemoveSignatory - * @when command tries to remove signatory from creator's account but has no - * permissions and no grantable permissions to do that - * @then execute fails and returns false - */ -TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissionToRemoveFromSelf) { - remove_signatory->account_id = creator->accountId(); - - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(std::vector{})); - EXPECT_CALL(*wsv_query, getAccountRoles(creator->accountId())) - .WillOnce(Return(std::vector{admin_role})); - EXPECT_CALL( - *wsv_query, - hasAccountGrantablePermission(admin_id, admin_id, can_remove_my_signatory)) - .WillOnce(Return(false)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given RemoveSignatory - * @when command tries to remove signatory but deletion fails - * @then execute() fails - */ -TEST_F(RemoveSignatoryTest, InvalidWhenAccountSignatoryDeletionFails) { - EXPECT_CALL(*wsv_command, - deleteAccountSignatory(remove_signatory->account_id, - shared_model::crypto::PublicKey( - {remove_signatory->pubkey.begin(), - remove_signatory->pubkey.end()}))) - .WillOnce(Return(makeEmptyError())); - - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class SetQuorumTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - pubkey_t creator_key, account_key; - creator_key.fill(0x1); - account_key.fill(0x2); - account_pubkeys = { - shared_model::interface::types::PubkeyType(creator_key.to_string()), - shared_model::interface::types::PubkeyType(account_key.to_string())}; - set_quorum = std::make_shared(); - set_quorum->account_id = account_id; - set_quorum->new_quorum = 2; - - command = set_quorum; - role_permissions = {can_set_quorum}; - } - - std::vector account_pubkeys; - std::shared_ptr set_quorum; -}; - -TEST_F(SetQuorumTest, ValidWhenCreatorHasPermissions) { - // Creator is admin - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, set_quorum->account_id, can_set_my_quorum)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccount(set_quorum->account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_query, getSignatories(set_quorum->account_id)) - .WillOnce(Return(account_pubkeys)); - - EXPECT_CALL(*wsv_command, updateAccount(_)) - .WillOnce(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(SetQuorumTest, ValidWhenSameAccount) { - // Creator is the account - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - set_quorum->account_id = creator->accountId(); - EXPECT_CALL(*wsv_query, getAccount(set_quorum->account_id)) - .WillOnce(Return(account)); - EXPECT_CALL(*wsv_query, getSignatories(set_quorum->account_id)) - .WillOnce(Return(account_pubkeys)); - EXPECT_CALL(*wsv_command, updateAccount(_)) - .WillOnce(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(SetQuorumTest, InvalidWhenNoPermissions) { - // Creator has no permissions - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, set_quorum->account_id, can_set_my_quorum)) - .WillOnce(Return(false)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(SetQuorumTest, InvalidWhenNoAccount) { - // No such account exists - set_quorum->account_id = "noacc"; - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, set_quorum->account_id, can_set_my_quorum)) - .WillOnce(Return(false)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SetQuorum - * @when command tries to set quorum for non-existing account - * @then execute fails and returns false - */ -TEST_F(SetQuorumTest, InvalidWhenNoAccountButPassedPermissions) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - set_quorum->account_id = creator->accountId(); - EXPECT_CALL(*wsv_query, getSignatories(set_quorum->account_id)) - .WillOnce(Return(account_pubkeys)); - - EXPECT_CALL(*wsv_query, getAccount(set_quorum->account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given SetQuorum - * @when command tries to set quorum for account which does not have any - * signatories - * @then execute fails and returns false - */ -TEST_F(SetQuorumTest, InvalidWhenNoSignatories) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - set_quorum->account_id = creator->accountId(); - EXPECT_CALL(*wsv_query, getSignatories(set_quorum->account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(SetQuorumTest, InvalidWhenNotEnoughSignatories) { - // Creator is the account - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - set_quorum->account_id = creator->accountId(); - EXPECT_CALL(*wsv_query, getAccount(set_quorum->account_id)).Times(0); - pubkey_t key; - key.fill(0x1); - std::vector acc_pubkeys = { - shared_model::interface::types::PubkeyType(key.to_string())}; - EXPECT_CALL(*wsv_query, getSignatories(set_quorum->account_id)) - .WillOnce(Return(acc_pubkeys)); - EXPECT_CALL(*wsv_command, updateAccount(_)).Times(0); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -class TransferAssetTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - asset = clone(shared_model::proto::AssetBuilder() - .assetId(asset_id) - .domainId(domain_id) - .precision(2) - .build()); - - balance = clone(shared_model::proto::AmountBuilder() - .intValue(150) - .precision(2) - .build()); - - src_wallet = clone(shared_model::proto::AccountAssetBuilder() - .assetId(asset_id) - .accountId(admin_id) - .balance(*balance) - .build()); - - dst_wallet = clone(shared_model::proto::AccountAssetBuilder() - .assetId(asset_id) - .accountId(account_id) - .balance(*balance) - .build()); - - transfer_asset = std::make_shared(); - transfer_asset->src_account_id = admin_id; - transfer_asset->dest_account_id = account_id; - transfer_asset->asset_id = asset_id; - transfer_asset->description = description; - Amount amount(150, 2); - transfer_asset->amount = amount; - command = transfer_asset; - role_permissions = {can_transfer, can_receive}; - } - - std::shared_ptr balance; - std::shared_ptr asset; - std::shared_ptr src_wallet, dst_wallet; - - std::shared_ptr transfer_asset; -}; - -TEST_F(TransferAssetTest, ValidWhenNewWallet) { - // When there is no wallet - new accountAsset will be created - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, getAccountAsset(transfer_asset->dest_account_id, _)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(src_wallet)); - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(transfer_asset->dest_account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) - .Times(2) - .WillRepeatedly(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(TransferAssetTest, ValidWhenExistingWallet) { - // When there is a wallet - no new accountAsset created - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, - getAccountAsset(transfer_asset->dest_account_id, - transfer_asset->asset_id)) - .WillOnce(Return(dst_wallet)); - - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(src_wallet)); - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(transfer_asset->dest_account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) - .Times(2) - .WillRepeatedly(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(TransferAssetTest, InvalidWhenNoPermissions) { - // Creator has no permissions - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(TransferAssetTest, InvalidWhenNoDestAccount) { - // No destination account exists - transfer_asset->dest_account_id = "noacc"; - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(TransferAssetTest, InvalidWhenNoSrcAccountAsset) { - // No source account asset exists - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given TransferAsset - * @when command tries to transfer asset from non-existing account - * @then execute fails and returns false - */ -TEST_F(TransferAssetTest, InvalidWhenNoSrcAccountAssetDuringExecute) { - // No source account asset exists - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .Times(2) - .WillOnce(Return(src_wallet)) - .WillOnce(Return(boost::none)); - EXPECT_CALL(*wsv_query, getAccount(transfer_asset->dest_account_id)) - .WillOnce(Return(account)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given TransferAsset - * @when command tries to transfer non-existent asset - * @then isValid fails and returns false - */ -TEST_F(TransferAssetTest, InvalidWhenNoAssetDuringValidation) { - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given TransferAsset - * @when command tries to transfer non-existent asset - * @then execute fails and returns false - */ -TEST_F(TransferAssetTest, InvalidWhenNoAssetId) { - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)) - .WillOnce(Return(boost::none)); - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(src_wallet)); - EXPECT_CALL(*wsv_query, - getAccountAsset(transfer_asset->dest_account_id, - transfer_asset->asset_id)) - .WillOnce(Return(dst_wallet)); - EXPECT_CALL(*wsv_query, getAccount(transfer_asset->dest_account_id)) - .WillOnce(Return(account)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(TransferAssetTest, InvalidWhenInsufficientFunds) { - // No sufficient funds - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - Amount amount(155, 2); - - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .WillOnce(Return(src_wallet)); - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(transfer_asset->dest_account_id)) - .WillOnce(Return(boost::none)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given TransferAsset - * @when command tries to transfer amount which is less than source balance - * @then execute fails and returns false - */ -TEST_F(TransferAssetTest, InvalidWhenInsufficientFundsDuringExecute) { - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .WillOnce(Return(src_wallet)); - EXPECT_CALL(*wsv_query, - getAccountAsset(transfer_asset->dest_account_id, - transfer_asset->asset_id)) - .WillOnce(Return(dst_wallet)); - - // More than account balance - transfer_asset->amount = Amount(155, 2); - - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -TEST_F(TransferAssetTest, InvalidWhenWrongPrecision) { - // Amount has wrong precision - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->src_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - - Amount amount(transfer_asset->amount.getIntValue(), 30); - transfer_asset->amount = amount; - - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given TransferAsset - * @when command tries to transfer amount with wrong precision - * @then execute fails and returns false - */ -TEST_F(TransferAssetTest, InvalidWhenWrongPrecisionDuringExecute) { - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .WillOnce(Return(src_wallet)); - EXPECT_CALL(*wsv_query, - getAccountAsset(transfer_asset->dest_account_id, - transfer_asset->asset_id)) - .WillOnce(Return(dst_wallet)); - - Amount amount(transfer_asset->amount.getIntValue(), 30); - transfer_asset->amount = amount; - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -/** - * @given TransferAsset - * @when command tries to transfer asset which overflows destination balance - * @then execute fails and returns false - */ -TEST_F(TransferAssetTest, InvalidWhenAmountOverflow) { - std::shared_ptr max_balance = clone( - shared_model::proto::AmountBuilder() - .intValue( - std::numeric_limits::max()) - .precision(2) - .build()); - - src_wallet = clone(shared_model::proto::AccountAssetBuilder() - .assetId(src_wallet->assetId()) - .accountId(src_wallet->accountId()) - .balance(*max_balance) - .build()); - - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .WillOnce(Return(asset)); - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .WillOnce(Return(src_wallet)); - EXPECT_CALL(*wsv_query, - getAccountAsset(transfer_asset->dest_account_id, - transfer_asset->asset_id)) - .WillOnce(Return(dst_wallet)); - - // More than account balance - transfer_asset->amount = (max_amount - Amount(100, 2)).value(); - - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -TEST_F(TransferAssetTest, InvalidWhenCreatorHasNoPermission) { - // Transfer creator is not connected to account - transfer_asset->src_account_id = account_id; - transfer_asset->dest_account_id = admin_id; - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission(admin_id, account_id, can_transfer_my_assets)) - .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(TransferAssetTest, ValidWhenCreatorHasPermission) { - // Transfer creator is not connected to account - transfer_asset->src_account_id = account_id; - transfer_asset->dest_account_id = admin_id; - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission(admin_id, account_id, can_transfer_my_assets)) - .WillOnce(Return(true)); - - EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->dest_account_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - - EXPECT_CALL(*wsv_query, getAccountAsset(transfer_asset->dest_account_id, _)) - .WillOnce(Return(boost::none)); - - EXPECT_CALL( - *wsv_query, - getAccountAsset(transfer_asset->src_account_id, transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(src_wallet)); - EXPECT_CALL(*wsv_query, getAsset(transfer_asset->asset_id)) - .Times(2) - .WillRepeatedly(Return(asset)); - EXPECT_CALL(*wsv_query, getAccount(transfer_asset->dest_account_id)) - .WillOnce(Return(account)); - - EXPECT_CALL(*wsv_command, upsertAccountAsset(_)) - .Times(2) - .WillRepeatedly(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -class AddPeerTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - - add_peer = std::make_shared(); - add_peer->peer.address = "iroha_node:10001"; - add_peer->peer.pubkey.fill(4); - - command = add_peer; - role_permissions = {can_add_peer}; - } - - std::shared_ptr add_peer; -}; - -TEST_F(AddPeerTest, ValidCase) { - // Valid case - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_command, insertPeer(_)).WillOnce(Return(WsvCommandResult())); - - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(AddPeerTest, InvalidCaseWhenNoPermissions) { - // Valid case - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AddPeer - * @when command tries to insert peer but insertion fails - * @then execute returns false - */ -TEST_F(AddPeerTest, InvalidCaseWhenInsertPeerFails) { - EXPECT_CALL(*wsv_command, insertPeer(_)).WillOnce(Return(makeEmptyError())); - - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class CreateRoleTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - std::set perm = {can_create_role}; - create_role = std::make_shared("master", perm); - command = create_role; - role_permissions = {can_create_role}; - } - std::shared_ptr create_role; -}; - -TEST_F(CreateRoleTest, ValidCase) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillRepeatedly(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillRepeatedly(Return(role_permissions)); - EXPECT_CALL(*wsv_command, insertRole(create_role->role_name)) - .WillOnce(Return(WsvCommandResult())); - EXPECT_CALL( - *wsv_command, - insertRolePermissions(create_role->role_name, create_role->permissions)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(CreateRoleTest, InvalidCaseWhenNoPermissions) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillRepeatedly(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillRepeatedly(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -TEST_F(CreateRoleTest, InvalidCaseWhenRoleSuperset) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillRepeatedly(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillRepeatedly(Return(role_permissions)); - std::set perms = {can_add_peer, can_append_role}; - command = std::make_shared("master", perms); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given CreateRole - * @when command tries to create new role, but insertion fails - * @then execute returns false - */ -TEST_F(CreateRoleTest, InvalidCaseWhenRoleInsertionFails) { - EXPECT_CALL(*wsv_command, insertRole(create_role->role_name)) - .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class AppendRoleTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - exact_command = std::make_shared("yoda", "master"); - command = exact_command; - role_permissions = {can_append_role}; - } - std::shared_ptr exact_command; -}; - -TEST_F(AppendRoleTest, ValidCase) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .Times(2) - .WillRepeatedly(Return(admin_roles)); - - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillRepeatedly(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getRolePermissions("master")) - .WillOnce(Return(role_permissions)); - - EXPECT_CALL( - *wsv_command, - insertAccountRole(exact_command->account_id, exact_command->role_name)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(AppendRoleTest, InvalidCaseNoPermissions) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AppendRole - * @when command tries to append non-existing role - * @then execute() fails and returns false - */ -TEST_F(AppendRoleTest, InvalidCaseNoAccountRole) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .Times(2) - .WillOnce(Return(admin_roles)) - .WillOnce((Return(boost::none))); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getRolePermissions("master")) - .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AppendRole - * @when command tries to append non-existing role and creator does not have any - * roles - * @then execute() fails and returns false - */ -TEST_F(AppendRoleTest, InvalidCaseNoAccountRoleAndNoPermission) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .Times(2) - .WillOnce(Return(admin_roles)) - .WillOnce((Return(boost::none))); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_query, getRolePermissions("master")) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AppendRole - * @when command tries to append role, but creator account does not have - * necessary permission - * @then execute() fails and returns false - */ -TEST_F(AppendRoleTest, InvalidCaseRoleHasNoPermissions) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .Times(2) - .WillOnce(Return(admin_roles)) - .WillOnce((Return(admin_roles))); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .Times(2) - .WillOnce(Return(role_permissions)) - .WillOnce(Return(boost::none)); - EXPECT_CALL(*wsv_query, getRolePermissions("master")) - .WillOnce(Return(role_permissions)); - - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given AppendRole - * @when command tries to append role, but insertion of account fails - * @then execute() fails - */ -TEST_F(AppendRoleTest, InvalidCaseInsertAccountRoleFails) { - EXPECT_CALL( - *wsv_command, - insertAccountRole(exact_command->account_id, exact_command->role_name)) - .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class DetachRoleTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - exact_command = std::make_shared("yoda", "master"); - command = exact_command; - role_permissions = {can_detach_role}; - } - std::shared_ptr exact_command; -}; - -TEST_F(DetachRoleTest, ValidCase) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL( - *wsv_command, - deleteAccountRole(exact_command->account_id, exact_command->role_name)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(DetachRoleTest, InvalidCase) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given DetachRole - * @when deletion of account role fails - * @then execute fails() - */ -TEST_F(DetachRoleTest, InvalidCaseWhenDeleteAccountRoleFails) { - EXPECT_CALL( - *wsv_command, - deleteAccountRole(exact_command->account_id, exact_command->role_name)) - .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class GrantPermissionTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - const auto perm = "can_add_signatory"; - exact_command = std::make_shared("yoda", perm); - command = exact_command; - // It is different from 'perm' due to realisation of old/new model. See - // GrantablePermissions in primitive.proto - new_model_permission = "can_add_my_signatory"; - role_permissions = {can_grant + new_model_permission}; - } - std::shared_ptr exact_command; - std::string new_model_permission; -}; - -TEST_F(GrantPermissionTest, ValidCase) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(role_permissions)); - EXPECT_CALL(*wsv_command, - insertAccountGrantablePermission(exact_command->account_id, - creator->accountId(), - new_model_permission)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(GrantPermissionTest, InvalidCaseWhenNoPermissions) { - EXPECT_CALL(*wsv_query, getAccountRoles(admin_id)) - .WillOnce(Return(admin_roles)); - EXPECT_CALL(*wsv_query, getRolePermissions(admin_role)) - .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given GrantPermission - * @when command tries to grant permission but insertion fails - * @then execute() fails - */ -TEST_F(GrantPermissionTest, InvalidCaseWhenInsertGrantablePermissionFails) { - EXPECT_CALL(*wsv_command, - insertAccountGrantablePermission(exact_command->account_id, - creator->accountId(), - new_model_permission)) - .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class RevokePermissionTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - exact_command = - std::make_shared("yoda", "can_add_signatory"); - new_model_permission = "can_add_my_signatory"; - command = exact_command; - } - std::shared_ptr exact_command; - std::string new_model_permission; -}; - -TEST_F(RevokePermissionTest, ValidCase) { - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - exact_command->account_id, admin_id, new_model_permission)) - .WillOnce(Return(true)); - EXPECT_CALL(*wsv_command, - deleteAccountGrantablePermission(exact_command->account_id, - creator->accountId(), - new_model_permission)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -TEST_F(RevokePermissionTest, InvalidCaseNoPermissions) { - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - exact_command->account_id, admin_id, new_model_permission)) - .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @given RevokePermission - * @when deleting permission fails - * @then execute fails - */ -TEST_F(RevokePermissionTest, InvalidCaseDeleteAccountPermissionvFails) { - EXPECT_CALL(*wsv_command, - deleteAccountGrantablePermission(exact_command->account_id, - creator->accountId(), - new_model_permission)) - .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute())); -} - -class SetAccountDetailTest : public CommandValidateExecuteTest { - public: - void SetUp() override { - CommandValidateExecuteTest::SetUp(); - cmd = std::make_shared(); - cmd->account_id = admin_id; - cmd->key = "key"; - cmd->value = "val"; - command = cmd; - role_permissions = {can_set_quorum}; - } - std::shared_ptr cmd; - std::string needed_permission = can_set_my_account_detail; -}; - -/** - * @when creator is setting details to their account - * @then successfully execute the command - */ -TEST_F(SetAccountDetailTest, ValidWhenSetOwnAccount) { - EXPECT_CALL( - *wsv_command, - setAccountKV(cmd->account_id, creator->accountId(), cmd->key, cmd->value)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -/** - * @when creator is setting details to their account - * @then successfully execute the command - */ -TEST_F(SetAccountDetailTest, InValidWhenOtherCreator) { - cmd->account_id = account_id; - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, cmd->account_id, needed_permission)) - .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute())); -} - -/** - * @when creator is setting details to their account - * @then successfully execute the command - */ -TEST_F(SetAccountDetailTest, ValidWhenHasPermissions) { - cmd->account_id = account_id; - EXPECT_CALL(*wsv_query, - hasAccountGrantablePermission( - admin_id, cmd->account_id, needed_permission)) - .WillOnce(Return(true)); - EXPECT_CALL( - *wsv_command, - setAccountKV(cmd->account_id, creator->accountId(), cmd->key, cmd->value)) - .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute())); -} - -/** - * @given SetAccountDetail - * @when command tries to set details, but setting key-value fails - * @then execute fails - */ -TEST_F(SetAccountDetailTest, InvalidWhenSetAccountKVFails) { - EXPECT_CALL( - *wsv_command, - setAccountKV(cmd->account_id, creator->accountId(), cmd->key, cmd->value)) - .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute())); -} From ae6f3a2286c3c76601e246ff1348c522b194c7c6 Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 26 Apr 2018 08:24:49 +0300 Subject: [PATCH 061/110] Feature/rework wsv query command test with shm (#1253) rework wsv_query_command_test with shared_model Signed-off-by: Alexey Chernyshov --- .../ametsuchi/wsv_query_command_test.cpp | 222 +++++++++++------- .../protobuf/test_account_builder.hpp | 29 +++ .../builders/protobuf/test_domain_builder.hpp | 29 +++ .../builders/protobuf/test_peer_builder.hpp | 29 +++ 4 files changed, 218 insertions(+), 91 deletions(-) create mode 100644 test/module/shared_model/builders/protobuf/test_account_builder.hpp create mode 100644 test/module/shared_model/builders/protobuf/test_domain_builder.hpp create mode 100644 test/module/shared_model/builders/protobuf/test_peer_builder.hpp diff --git a/test/module/irohad/ametsuchi/wsv_query_command_test.cpp b/test/module/irohad/ametsuchi/wsv_query_command_test.cpp index ed66cb7e75..0b7450ed27 100644 --- a/test/module/irohad/ametsuchi/wsv_query_command_test.cpp +++ b/test/module/irohad/ametsuchi/wsv_query_command_test.cpp @@ -1,5 +1,5 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. * http://soramitsu.co.jp * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,12 +18,10 @@ #include "ametsuchi/impl/postgres_wsv_command.hpp" #include "ametsuchi/impl/postgres_wsv_query.hpp" #include "framework/result_fixture.hpp" -#include "backend/protobuf/from_old_model.hpp" -#include "model/account.hpp" -#include "model/asset.hpp" -#include "model/domain.hpp" -#include "model/peer.hpp" #include "module/irohad/ametsuchi/ametsuchi_fixture.hpp" +#include "module/shared_model/builders/protobuf/test_account_builder.hpp" +#include "module/shared_model/builders/protobuf/test_domain_builder.hpp" +#include "module/shared_model/builders/protobuf/test_peer_builder.hpp" namespace iroha { namespace ametsuchi { @@ -33,12 +31,15 @@ namespace iroha { class WsvQueryCommandTest : public AmetsuchiTest { public: WsvQueryCommandTest() { - domain.domain_id = "domain"; - domain.default_role = role; - account.domain_id = domain.domain_id; - account.account_id = "id@" + account.domain_id; - account.quorum = 1; - account.json_data = R"({"id@domain": {"key": "value"}})"; + domain = clone( + TestDomainBuilder().domainId("domain").defaultRole(role).build()); + + account = clone(TestAccountBuilder() + .domainId(domain->domainId()) + .accountId("id@" + domain->domainId()) + .quorum(1) + .jsonData(R"({"id@domain": {"key": "value"}})") + .build()); } void SetUp() override { @@ -59,8 +60,8 @@ namespace iroha { } std::string role = "role", permission = "permission"; - model::Account account; - model::Domain domain; + std::unique_ptr account; + std::unique_ptr domain; std::unique_ptr postgres_connection; std::unique_ptr wsv_transaction; @@ -71,6 +72,11 @@ namespace iroha { class RoleTest : public WsvQueryCommandTest {}; + /** + * @given WSV command and valid role name + * @when trying to insert new role + * @then role is successfully inserted + */ TEST_F(RoleTest, InsertRoleWhenValidName) { ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); auto roles = query->getRoles(); @@ -79,6 +85,11 @@ namespace iroha { ASSERT_EQ(role, roles->front()); } + /** + * @given WSV command and invalid role name + * @when trying to insert new role + * @then role is failed + */ TEST_F(RoleTest, InsertRoleWhenInvalidName) { ASSERT_NO_THROW( checkErrorCase(command->insertRole(std::string(46, 'a')))); @@ -95,6 +106,11 @@ namespace iroha { } }; + /** + * @given WSV command and role exists and valid permissions + * @when trying to insert role permissions + * @then RolePermissions are inserted + */ TEST_F(RolePermissionsTest, InsertRolePermissionsWhenRoleExists) { ASSERT_NO_THROW( checkValueCase(command->insertRolePermissions(role, {permission}))); @@ -105,6 +121,11 @@ namespace iroha { ASSERT_EQ(permission, permissions->front()); } + /** + * @given WSV command and role doesn't exist and valid permissions + * @when trying to insert role permissions + * @then RolePermissions are not inserted + */ TEST_F(RolePermissionsTest, InsertRolePermissionsWhenNoRole) { auto new_role = role + " "; ASSERT_NO_THROW(checkErrorCase( @@ -119,8 +140,7 @@ namespace iroha { void SetUp() override { WsvQueryCommandTest::SetUp(); ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); - ASSERT_NO_THROW(checkValueCase( - command->insertDomain(shared_model::proto::from_old(domain)))); + ASSERT_NO_THROW(checkValueCase(command->insertDomain(*domain))); } }; @@ -130,11 +150,10 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertAccountWithJSONData) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); - auto acc = query->getAccount(account.account_id); + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); + auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); - ASSERT_EQ(account.json_data, acc.value()->jsonData()); + ASSERT_EQ(account->jsonData(), acc.value()->jsonData()); } /** @@ -143,11 +162,10 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertNewJSONDataAccount) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); ASSERT_NO_THROW(checkValueCase(command->setAccountKV( - account.account_id, account.account_id, "id", "val"))); - auto acc = query->getAccount(account.account_id); + account->accountId(), account->accountId(), "id", "val"))); + auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); ASSERT_EQ(R"({"id@domain": {"id": "val", "key": "value"}})", acc.value()->jsonData()); @@ -159,11 +177,10 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertNewJSONDataToOtherAccount) { + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); - ASSERT_NO_THROW(checkValueCase( - command->setAccountKV(account.account_id, "admin", "id", "val"))); - auto acc = query->getAccount(account.account_id); + command->setAccountKV(account->accountId(), "admin", "id", "val"))); + auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); ASSERT_EQ(R"({"admin": {"id": "val"}, "id@domain": {"key": "value"}})", acc.value()->jsonData()); @@ -175,11 +192,10 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertNewComplexJSONDataAccount) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); ASSERT_NO_THROW(checkValueCase(command->setAccountKV( - account.account_id, account.account_id, "id", "[val1, val2]"))); - auto acc = query->getAccount(account.account_id); + account->accountId(), account->accountId(), "id", "[val1, val2]"))); + auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); ASSERT_EQ(R"({"id@domain": {"id": "[val1, val2]", "key": "value"}})", acc.value()->jsonData()); @@ -191,11 +207,10 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, UpdateAccountJSONData) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); ASSERT_NO_THROW(checkValueCase(command->setAccountKV( - account.account_id, account.account_id, "key", "val2"))); - auto acc = query->getAccount(account.account_id); + account->accountId(), account->accountId(), "key", "val2"))); + auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); ASSERT_EQ(R"({"id@domain": {"key": "val2"}})", acc.value()->jsonData()); } @@ -222,25 +237,33 @@ namespace iroha { void SetUp() override { WsvQueryCommandTest::SetUp(); ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); - ASSERT_NO_THROW(checkValueCase( - command->insertDomain(shared_model::proto::from_old(domain)))); - ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); + ASSERT_NO_THROW(checkValueCase(command->insertDomain(*domain))); + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); } }; + /** + * @given WSV command and account exists and valid account role + * @when trying to insert account + * @then account role is inserted + */ TEST_F(AccountRoleTest, InsertAccountRoleWhenAccountRoleExist) { - ASSERT_NO_THROW( - checkValueCase(command->insertAccountRole(account.account_id, role))); + ASSERT_NO_THROW(checkValueCase( + command->insertAccountRole(account->accountId(), role))); - auto roles = query->getAccountRoles(account.account_id); + auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(1, roles->size()); ASSERT_EQ(role, roles->front()); } + /** + * @given WSV command and account does not exist and valid account role + * @when trying to insert account + * @then account role is not inserted + */ TEST_F(AccountRoleTest, InsertAccountRoleWhenNoAccount) { - auto account_id = account.account_id + " "; + auto account_id = account->accountId() + " "; ASSERT_NO_THROW( checkErrorCase(command->insertAccountRole(account_id, role))); @@ -249,12 +272,17 @@ namespace iroha { ASSERT_EQ(0, roles->size()); } + /** + * @given WSV command and account exists and invalid account role + * @when trying to insert account + * @then account role is not inserted + */ TEST_F(AccountRoleTest, InsertAccountRoleWhenNoRole) { auto new_role = role + " "; ASSERT_NO_THROW(checkErrorCase( - command->insertAccountRole(account.account_id, new_role))); + command->insertAccountRole(account->accountId(), new_role))); - auto roles = query->getAccountRoles(account.account_id); + auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(0, roles->size()); } @@ -265,11 +293,11 @@ namespace iroha { * @then role is detached */ TEST_F(AccountRoleTest, DeleteAccountRoleWhenExist) { - ASSERT_NO_THROW( - checkValueCase(command->insertAccountRole(account.account_id, role))); - ASSERT_NO_THROW( - checkValueCase(command->deleteAccountRole(account.account_id, role))); - auto roles = query->getAccountRoles(account.account_id); + ASSERT_NO_THROW(checkValueCase( + command->insertAccountRole(account->accountId(), role))); + ASSERT_NO_THROW(checkValueCase( + command->deleteAccountRole(account->accountId(), role))); + auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(0, roles->size()); } @@ -280,10 +308,10 @@ namespace iroha { * @then nothing is deleted */ TEST_F(AccountRoleTest, DeleteAccountRoleWhenNoAccount) { - ASSERT_NO_THROW( - checkValueCase(command->insertAccountRole(account.account_id, role))); + ASSERT_NO_THROW(checkValueCase( + command->insertAccountRole(account->accountId(), role))); ASSERT_NO_THROW(checkValueCase(command->deleteAccountRole("no", role))); - auto roles = query->getAccountRoles(account.account_id); + auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(1, roles->size()); } @@ -294,85 +322,99 @@ namespace iroha { * @then nothing is deleted */ TEST_F(AccountRoleTest, DeleteAccountRoleWhenNoRole) { - ASSERT_NO_THROW( - checkValueCase(command->insertAccountRole(account.account_id, role))); - ASSERT_NO_THROW( - checkValueCase(command->deleteAccountRole(account.account_id, "no"))); - auto roles = query->getAccountRoles(account.account_id); + ASSERT_NO_THROW(checkValueCase( + command->insertAccountRole(account->accountId(), role))); + ASSERT_NO_THROW(checkValueCase( + command->deleteAccountRole(account->accountId(), "no"))); + auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(1, roles->size()); } class AccountGrantablePermissionTest : public WsvQueryCommandTest { public: - AccountGrantablePermissionTest() { - permittee_account = account; - permittee_account.account_id = "id2@" + permittee_account.domain_id; - permittee_account.quorum = 1; - } - void SetUp() override { WsvQueryCommandTest::SetUp(); + + permittee_account = + clone(TestAccountBuilder() + .domainId(domain->domainId()) + .accountId("id2@" + domain->domainId()) + .quorum(1) + .jsonData(R"({"id@domain": {"key": "value"}})") + .build()); + ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); - ASSERT_NO_THROW(checkValueCase( - command->insertDomain(shared_model::proto::from_old(domain)))); - ASSERT_NO_THROW(checkValueCase( - command->insertAccount(shared_model::proto::from_old(account)))); - ASSERT_NO_THROW(checkValueCase(command->insertAccount( - shared_model::proto::from_old(permittee_account)))); + ASSERT_NO_THROW(checkValueCase(command->insertDomain(*domain))); + ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); + ASSERT_NO_THROW( + checkValueCase(command->insertAccount(*permittee_account))); } - model::Account permittee_account; + std::shared_ptr permittee_account; }; + /** + * @given WSV command and account exists and valid grantable permissions + * @when trying to insert grantable permissions + * @then grantable permissions are inserted + */ TEST_F(AccountGrantablePermissionTest, InsertAccountGrantablePermissionWhenAccountsExist) { ASSERT_NO_THROW(checkValueCase(command->insertAccountGrantablePermission( - permittee_account.account_id, account.account_id, permission))); + permittee_account->accountId(), account->accountId(), permission))); ASSERT_TRUE(query->hasAccountGrantablePermission( - permittee_account.account_id, account.account_id, permission)); + permittee_account->accountId(), account->accountId(), permission)); } + /** + * @given WSV command and invalid permittee and valid grantable permissions + * @when trying to insert grantable permissions + * @then grantable permissions are not inserted + */ TEST_F(AccountGrantablePermissionTest, InsertAccountGrantablePermissionWhenNoPermitteeAccount) { - auto permittee_account_id = permittee_account.account_id + " "; + auto permittee_account_id = permittee_account->accountId() + " "; ASSERT_NO_THROW(checkErrorCase(command->insertAccountGrantablePermission( - permittee_account_id, account.account_id, permission))); + permittee_account_id, account->accountId(), permission))); ASSERT_FALSE(query->hasAccountGrantablePermission( - permittee_account_id, account.account_id, permission)); + permittee_account_id, account->accountId(), permission)); } TEST_F(AccountGrantablePermissionTest, InsertAccountGrantablePermissionWhenNoAccount) { - auto account_id = account.account_id + " "; + auto account_id = account->accountId() + " "; ASSERT_NO_THROW(checkErrorCase(command->insertAccountGrantablePermission( - permittee_account.account_id, account_id, permission))); + permittee_account->accountId(), account_id, permission))); ASSERT_FALSE(query->hasAccountGrantablePermission( - permittee_account.account_id, account_id, permission)); + permittee_account->accountId(), account_id, permission)); } + /** + * @given WSV command to delete grantable permission with valid parameters + * @when trying to delete grantable permissions + * @then grantable permissions are deleted + */ TEST_F(AccountGrantablePermissionTest, DeleteAccountGrantablePermissionWhenAccountsPermissionExist) { ASSERT_NO_THROW(checkValueCase(command->deleteAccountGrantablePermission( - permittee_account.account_id, account.account_id, permission))); + permittee_account->accountId(), account->accountId(), permission))); ASSERT_FALSE(query->hasAccountGrantablePermission( - permittee_account.account_id, account.account_id, permission)); + permittee_account->accountId(), account->accountId(), permission)); } class DeletePeerTest : public WsvQueryCommandTest { public: - DeletePeerTest() { - peer = model::Peer(); - } - void SetUp() override { WsvQueryCommandTest::SetUp(); + + peer = clone(TestPeerBuilder().build()); } - model::Peer peer; + std::unique_ptr peer; }; /** @@ -381,11 +423,9 @@ namespace iroha { * @then peer is successfully deleted */ TEST_F(DeletePeerTest, DeletePeerValidWhenPeerExists) { - ASSERT_NO_THROW(checkValueCase( - command->insertPeer(shared_model::proto::from_old(peer)))); + ASSERT_NO_THROW(checkValueCase(command->insertPeer(*peer))); - ASSERT_NO_THROW(checkValueCase( - command->deletePeer(shared_model::proto::from_old(peer)))); + ASSERT_NO_THROW(checkValueCase(command->deletePeer(*peer))); } class GetAssetTest : public WsvQueryCommandTest {}; diff --git a/test/module/shared_model/builders/protobuf/test_account_builder.hpp b/test/module/shared_model/builders/protobuf/test_account_builder.hpp new file mode 100644 index 0000000000..1389a3daed --- /dev/null +++ b/test/module/shared_model/builders/protobuf/test_account_builder.hpp @@ -0,0 +1,29 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "builders/protobuf/common_objects/proto_account_builder.hpp" + +#ifndef IROHA_TEST_ACCOUNT_BUILDER_HPP +#define IROHA_TEST_ACCOUNT_BUILDER_HPP + +/** + * Builder alias, to build shared model proto block object avoiding validation + * and "required fields" check + */ +using TestAccountBuilder = shared_model::proto::AccountBuilder; + +#endif //IROHA_TEST_ACCOUNT_BUILDER_HPP diff --git a/test/module/shared_model/builders/protobuf/test_domain_builder.hpp b/test/module/shared_model/builders/protobuf/test_domain_builder.hpp new file mode 100644 index 0000000000..257538beae --- /dev/null +++ b/test/module/shared_model/builders/protobuf/test_domain_builder.hpp @@ -0,0 +1,29 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "builders/protobuf/common_objects/proto_domain_builder.hpp" + +#ifndef IROHA_TEST_DOMAIN_BUILDER_HPP +#define IROHA_TEST_DOMAIN_BUILDER_HPP + +/** + * Builder alias, to build shared model proto block object avoiding validation + * and "required fields" check + */ +using TestDomainBuilder = shared_model::proto::DomainBuilder; + +#endif //IROHA_TEST_DOMAIN_BUILDER_HPP diff --git a/test/module/shared_model/builders/protobuf/test_peer_builder.hpp b/test/module/shared_model/builders/protobuf/test_peer_builder.hpp new file mode 100644 index 0000000000..af5c75d130 --- /dev/null +++ b/test/module/shared_model/builders/protobuf/test_peer_builder.hpp @@ -0,0 +1,29 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "builders/protobuf/common_objects/proto_peer_builder.hpp" + +#ifndef IROHA_TEST_PEER_BUILDER_HPP +#define IROHA_TEST_PEER_BUILDER_HPP + +/** + * Builder alias, to build shared model proto block object avoiding validation + * and "required fields" check + */ +using TestPeerBuilder = shared_model::proto::PeerBuilder; + +#endif //IROHA_TEST_PEER_BUILDER_HPP From 4f7bbe1467862721243d04742b736ec328a8f435 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Thu, 26 Apr 2018 09:15:17 +0300 Subject: [PATCH 062/110] Python/Java/Android bindings (#1258) * python + java + android bindings Signed-off-by: Artyom Bakhtin * switch off bindings by default Signed-off-by: Artyom Bakhtin * cleanup Signed-off-by: Artyom Bakhtin * fix curl flags Signed-off-by: Artyom Bakhtin * fixes Signed-off-by: Artyom Bakhtin * add protobuf-generated python files Signed-off-by: Artyom Bakhtin * refactor naming Signed-off-by: Artyom Bakhtin * Dockerfile fixes Signed-off-by: Artyom Bakhtin * more fixes Signed-off-by: Artyom Bakhtin --- .jenkinsci/bindings.groovy | 79 ++++++++++++++++++++----- .jenkinsci/debug-build.groovy | 8 ++- .jenkinsci/docker-pull-or-build.groovy | 55 ++++++++++------- .jenkinsci/remote-files-differ.groovy | 10 ++++ Jenkinsfile | 82 +++++++++++++++++++++++--- docker/android/Dockerfile | 52 ++++++++++++++++ docker/android/entrypoint.sh | 33 +++++++++++ docker/develop/aarch64/Dockerfile | 57 ++++++++++++------ docker/develop/armv7l/Dockerfile | 57 ++++++++++++------ docker/develop/x86_64/Dockerfile | 57 ++++++++++++------ 10 files changed, 392 insertions(+), 98 deletions(-) create mode 100644 .jenkinsci/remote-files-differ.groovy create mode 100644 docker/android/Dockerfile create mode 100644 docker/android/entrypoint.sh diff --git a/.jenkinsci/bindings.groovy b/.jenkinsci/bindings.groovy index 4f20c09bb0..afc89afc82 100644 --- a/.jenkinsci/bindings.groovy +++ b/.jenkinsci/bindings.groovy @@ -1,27 +1,74 @@ #!/usr/bin/env groovy -def doBindings() { - def cmake_options = "" - if (params.JavaBindings) { - cmake_options += " -DSWIG_JAVA=ON " - } - if (params.PythonBindings) { - cmake_options += " -DSWIG_PYTHON=ON " - } - // In case language specific options were not set, - // build for each language - if (!params.JavaBindings && !params.PythonBindings) { - cmake_options += " -DSWIG_JAVA=ON -DSWIG_PYTHON=ON " - } +def doJavaBindings(buildType=Release) { + def currentPath = sh(script: "pwd", returnStdout: true).trim() + def commit = env.GIT_COMMIT + def artifactsPath = sprintf('%1$s/java-bindings-%2$s-%3$s-%4$s.zip', + [currentPath, buildType, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)]) sh """ cmake \ -H. \ -Bbuild \ - -DCMAKE_BUILD_TYPE=Release \ - ${cmake_options} + -DCMAKE_BUILD_TYPE=$buildType \ + -DSWIG_JAVA=ON + """ + sh "cd build; make -j${params.PARALLELISM} irohajava" + sh "zip -j $artifactsPath build/shared_model/bindings/*.java build/shared_model/bindings/libirohajava.so" + sh "cp $artifactsPath /tmp/bindings-artifact" + return artifactsPath +} + +def doPythonBindings(buildType=Release) { + def currentPath = sh(script: "pwd", returnStdout: true).trim() + def commit = env.GIT_COMMIT + def supportPython2 = "OFF" + def artifactsPath = sprintf('%1$s/python-bindings-%2$s-%3$s-%4$s-%5$s.zip', + [currentPath, env.PBVersion, buildType, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)]) + // do not use preinstalled libed25519 + sh "rm -rf /usr/local/include/ed25519*; unlink /usr/local/lib/libed25519.so; rm -f /usr/local/lib/libed25519.so.1.2.2" + if (env.PBVersion == "python2") { supportPython2 = "ON" } + sh """ + cmake \ + -H. \ + -Bbuild \ + -DCMAKE_BUILD_TYPE=$buildType \ + -DSWIG_PYTHON=ON \ + -DSUPPORT_PYTHON2=$supportPython2 """ sh "cmake --build build --target python_tests" - sh "cd build; make -j${params.PARALLELISM} irohajava irohapy" + sh "cd build; make -j${params.PARALLELISM} irohapy" + sh "protoc --proto_path=schema --python_out=build/shared_model/bindings block.proto primitive.proto commands.proto queries.proto responses.proto endpoint.proto" + sh "${env.PBVersion} -m grpc_tools.protoc --proto_path=schema --python_out=build/shared_model/bindings --grpc_python_out=build/shared_model/bindings endpoint.proto yac.proto ordering.proto loader.proto" + sh "zip -j $artifactsPath build/shared_model/bindings/*.py build/shared_model/bindings/*.so" + sh "cp $artifactsPath /tmp/bindings-artifact" + return artifactsPath +} + +def doAndroidBindings(abiVersion) { + def currentPath = sh(script: "pwd", returnStdout: true).trim() + def commit = env.GIT_COMMIT + def artifactsPath = sprintf('%1$s/android-bindings-%2$s-%3$s-%4$s-%5$s-%6$s.zip', + [currentPath, "\$PLATFORM", abiVersion, "\$BUILD_TYPE_A", sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)]) + sh """ + (cd /iroha; git init; git remote add origin https://github.com/hyperledger/iroha.git; \ + git fetch --depth 1 origin develop; git checkout -t origin/develop) + """ + sh """ + . /entrypoint.sh; \ + sed -i.bak "s~find_package(JNI REQUIRED)~SET(CMAKE_SWIG_FLAGS \\\${CMAKE_SWIG_FLAGS} -package \${PACKAGE})~" /iroha/shared_model/bindings/CMakeLists.txt; \ + # TODO: might not be needed in the future + sed -i.bak "/target_include_directories(\\\${SWIG_MODULE_irohajava_REAL_NAME} PUBLIC/,+3d" /iroha/shared_model/bindings/CMakeLists.txt; \ + sed -i.bak "s~swig_link_libraries(irohajava~swig_link_libraries(irohajava \"/protobuf/.build/lib\${PROTOBUF_LIB_NAME}.a\" \"\${NDK_PATH}/platforms/android-$abiVersion/\${ARCH}/usr/\${LIBP}/liblog.so\"~" /iroha/shared_model/bindings/CMakeLists.txt; \ + sed -i.bak "s~find_library(protobuf_LIBRARY protobuf)~find_library(protobuf_LIBRARY \${PROTOBUF_LIB_NAME})~" /iroha/cmake/Modules/Findprotobuf.cmake; \ + sed -i.bak "s~find_program(protoc_EXECUTABLE protoc~set(protoc_EXECUTABLE \"/protobuf/host_build/protoc\"~" /iroha/cmake/Modules/Findprotobuf.cmake; \ + cmake -H/iroha/shared_model -B/iroha/shared_model/build -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=$abiVersion -DCMAKE_ANDROID_ARCH_ABI=\$PLATFORM \ + -DANDROID_NDK=\$NDK_PATH -DCMAKE_ANDROID_STL_TYPE=c++_static -DCMAKE_BUILD_TYPE=\$BUILD_TYPE_A -DTESTING=OFF \ + -DSHARED_MODEL_DISABLE_COMPATIBILITY=ON -DSWIG_JAVA=ON -DCMAKE_PREFIX_PATH=\$DEPS_DIR + """ + sh "cmake --build /iroha/shared_model/build --target irohajava -- -j${params.PARALLELISM}" + sh "zip -j $artifactsPath /iroha/shared_model/build/bindings/*.java /iroha/shared_model/build/bindings/libirohajava.so" + sh "cp $artifactsPath /tmp/bindings-artifact" + return artifactsPath } return this diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index fc55ee7bb7..c340ad429e 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -3,6 +3,7 @@ def doDebugBuild(coverageEnabled=false) { def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" def parallelism = params.PARALLELISM + def platform = sh(script: 'uname -m', returnStdout: true).trim() // params are always null unless job is started // this is the case for the FIRST build only. // So just set this to same value as default. @@ -20,8 +21,11 @@ def doDebugBuild(coverageEnabled=false) { + " -e POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" + " --name ${env.IROHA_POSTGRES_HOST}" + " --network=${env.IROHA_NETWORK}") - - def iC = dPullOrBuild.dockerPullOrUpdate() + def iC = dPullOrBuild.dockerPullOrUpdate("${platform}-develop", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/develop/${platform}/Dockerfile", + ['PARALLELISM': params.PARALLELISM]) iC.inside("" + " -e IROHA_POSTGRES_HOST=${env.IROHA_POSTGRES_HOST}" + " -e IROHA_POSTGRES_PORT=${env.IROHA_POSTGRES_PORT}" diff --git a/.jenkinsci/docker-pull-or-build.groovy b/.jenkinsci/docker-pull-or-build.groovy index 403e3e3303..86e78c9a11 100644 --- a/.jenkinsci/docker-pull-or-build.groovy +++ b/.jenkinsci/docker-pull-or-build.groovy @@ -10,37 +10,50 @@ def remoteFilesDiffer(f1, f2) { return true } -def dockerPullOrUpdate() { - def platform = sh(script: 'uname -m', returnStdout: true).trim() - def commit = sh(script: "echo ${BRANCH_NAME} | md5sum | cut -c 1-8", returnStdout: true).trim() - if (remoteFilesDiffer("https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", - "https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile")) { - iC = docker.build("hyperledger/iroha:${commit}", "--build-arg PARALLELISM=${parallelism} -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") - // develop branch Docker image has been modified - if (BRANCH_NAME == 'develop') { - docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { - iC.push("${platform}-develop") - } +def buildOptionsString(options) { + def s = '' + if (options) { + options.each { k, v -> + s += "--build-arg ${k}=${v} " } } + return s +} + +def dockerPullOrUpdate(imageName, currentDockerfileURL, previousDockerfileURL, referenceDockerfileURL, buildOptions=null) { + buildOptions = buildOptionsString(buildOptions) + def commit = sh(script: "echo ${BRANCH_NAME} | md5sum | cut -c 1-8", returnStdout: true).trim() + if (remoteFilesDiffer(currentDockerfileURL, previousDockerfileURL)) { + // Dockerfile has been changed compared to the previous commit + // Worst case scenario. We cannot count on the local cache + // because Dockerfile may contain apt-get entries that would try to update + // from invalid (stale) addresses + iC = docker.build("hyperledger/iroha:${commit}-${BUILD_NUMBER}", "${buildOptions} --no-cache -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + } else { - // reuse develop branch Docker image - if (BRANCH_NAME == 'develop') { - iC = docker.image("hyperledger/iroha:${platform}-develop") - iC.pull() + // first commit in this branch or Dockerfile modified + if (remoteFilesDiffer(currentDockerfileURL, referenceDockerfileURL)) { + // if we're lucky to build on the same agent, image will be built using cache + iC = docker.build("hyperledger/iroha:${commit}-${BUILD_NUMBER}", "$buildOptions -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") } else { - // first commit in this branch or Dockerfile modified - if (remoteFilesDiffer("https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", - "https://raw.githubusercontent.com/hyperledger/iroha/develop/docker/develop/${platform}/Dockerfile")) { - iC = docker.build("hyperledger/iroha:${commit}", "--build-arg PARALLELISM=${parallelism} -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + // try pulling image from Dockerhub, probably image is already there + def testExitCode = sh(script: "docker pull hyperledger/iroha:${imageName}", returnStatus: true) + if (testExitCode != 0) { + // image does not (yet) exist on Dockerhub. Build it + iC = docker.build("hyperledger/iroha:${commit}-${BUILD_NUMBER}", "$buildOptions --no-cache -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") } - // reuse develop branch Docker image else { - iC = docker.image("hyperledger/iroha:${platform}-develop") + // no difference found compared to both previous and reference Dockerfile + iC = docker.image("hyperledger/iroha:${imageName}") } } } + if (BRANCH_NAME ==~ /develop|master/) { + docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { + iC.push(imageName) + } + } return iC } diff --git a/.jenkinsci/remote-files-differ.groovy b/.jenkinsci/remote-files-differ.groovy new file mode 100644 index 0000000000..6ea43fdf27 --- /dev/null +++ b/.jenkinsci/remote-files-differ.groovy @@ -0,0 +1,10 @@ +#!/usr/bin/env groovy + +def remoteFilesDiffer(f1, f2) { + sh "curl -sSL -o /tmp/${env.GIT_COMMIT}/f1 --create-dirs ${f1}" + sh "curl -sSL -o /tmp/${env.GIT_COMMIT}/f2 ${f2}" + diffExitCode = sh(script: "diff -q /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}/f2", returnStatus: true) + return diffExitCode != 0 +} + +return this diff --git a/Jenkinsfile b/Jenkinsfile index 13097fbc79..39ac57b250 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -19,8 +19,14 @@ properties([parameters([ booleanParam(defaultValue: false, description: 'Whether it is a triggered build', name: 'Nightly'), booleanParam(defaultValue: false, description: 'Whether build docs or not', name: 'Doxygen'), booleanParam(defaultValue: false, description: 'Whether build Java bindings', name: 'JavaBindings'), + choice(choices: 'Release\nDebug', description: 'Java Bindings Build Type', name: 'JBBuildType'), booleanParam(defaultValue: false, description: 'Whether build Python bindings', name: 'PythonBindings'), - booleanParam(defaultValue: false, description: 'Whether build bindings only w/o Iroha itself', name: 'BindingsOnly'), + choice(choices: 'Release\nDebug', description: 'Python Bindings Build Type', name: 'PBBuildType'), + choice(choices: 'python3\npython2', description: 'Python Bindings Version', name: 'PBVersion'), + booleanParam(defaultValue: false, description: 'Whether build Android bindings', name: 'AndroidBindings'), + choice(choices: '26\n25\n24\n23\n22\n21\n20\n19\n18\n17\n16\n15\n14', description: 'Android Bindings ABI Version', name: 'ABABIVersion'), + choice(choices: 'Release\nDebug', description: 'Android Bindings Build Type', name: 'ABBuildType'), + choice(choices: 'arm64-v8a\narmeabi-v7a\narmeabi\nx86_64\nx86', description: 'Android Bindings Platform', name: 'ABPlatform'), string(defaultValue: '4', description: 'How much parallelism should we exploit. "4" is optimal for machines with modest amount of memory and at least 4 cores', name: 'PARALLELISM')])]) @@ -34,6 +40,7 @@ pipeline { DOCKERHUB = credentials('DOCKERHUB') DOCKER_BASE_IMAGE_DEVELOP = 'hyperledger/iroha:develop' DOCKER_BASE_IMAGE_RELEASE = 'hyperledger/iroha:latest' + GIT_RAW_BASE_URL = "https://raw.githubusercontent.com/hyperledger/iroha" IROHA_NETWORK = "iroha-0${CHANGE_ID}-${GIT_COMMIT}-${BUILD_NUMBER}" IROHA_POSTGRES_HOST = "pg-0${CHANGE_ID}-${GIT_COMMIT}-${BUILD_NUMBER}" @@ -385,22 +392,81 @@ pipeline { stage('Build bindings') { when { anyOf { - expression { return params.BindingsOnly } expression { return params.PythonBindings } expression { return params.JavaBindings } + expression { return params.AndroidBindings } } } agent { label 'x86_64' } + environment { + JAVA_HOME = '/usr/lib/jvm/java-8-oracle' + } steps { script { def bindings = load ".jenkinsci/bindings.groovy" + def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" def platform = sh(script: 'uname -m', returnStdout: true).trim() - sh "curl -L -o /tmp/${env.GIT_COMMIT}/Dockerfile --create-dirs https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile" - iC = docker.build("hyperledger/iroha-develop:${GIT_COMMIT}-${BUILD_NUMBER}", "-f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT} --build-arg PARALLELISM=${PARALLELISM}") - sh "rm -rf /tmp/${env.GIT_COMMIT}" - iC.inside { - def scmVars = checkout scm - bindings.doBindings() + if (params.JavaBindings) { + iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/develop/x86_64/Dockerfile", + ['PARALLELISM': params.PARALLELISM]) + iC.inside("-v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { + bindings.doJavaBindings(params.JBBuildType) + } + } + if (params.PythonBindings) { + iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/develop/x86_64/Dockerfile", + ['PARALLELISM': params.PARALLELISM]) + iC.inside("-v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { + bindings.doPythonBindings(params.PBBuildType) + } + } + if (params.AndroidBindings) { + iC = dPullOrBuild.dockerPullOrUpdate("android-${params.ABPlatform}-${params.ABBuildType}", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/android/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/android/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/android/Dockerfile", + ['PARALLELISM': params.PARALLELISM, 'PLATFORM': params.ABPlatform, 'BUILD_TYPE': params.ABBuildType]) + sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh ${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/android/entrypoint.sh" + sh "chmod +x /tmp/${env.GIT_COMMIT}/entrypoint.sh" + iC.inside("-v /tmp/${env.GIT_COMMIT}/entrypoint.sh:/entrypoint.sh:ro -v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { + bindings.doAndroidBindings(params.ABABIVersion) + } + } + } + } + post { + always { + timeout(time: 600, unit: "SECONDS") { + script { + try { + if (currentBuild.currentResult == "SUCCESS") { + def artifacts = load ".jenkinsci/artifacts.groovy" + def commit = env.GIT_COMMIT + if (params.JavaBindings) { + javaBindingsFilePaths = [ '/tmp/${GIT_COMMIT}/bindings-artifact/java-bindings-*.zip' ] + artifacts.uploadArtifacts(javaBindingsFilePaths, '/iroha/bindings/java') + } + if (params.PythonBindings) { + pythonBindingsFilePaths = [ '/tmp/${GIT_COMMIT}/bindings-artifact/python-bindings-*.zip' ] + artifacts.uploadArtifacts(pythonBindingsFilePaths, '/iroha/bindings/python') + } + if (params.AndroidBindings) { + androidBindingsFilePaths = [ '/tmp/${GIT_COMMIT}/bindings-artifact/android-bindings-*.zip' ] + artifacts.uploadArtifacts(androidBindingsFilePaths, '/iroha/bindings/android') + } + } + } + finally { + sh "rm -rf /tmp/${env.GIT_COMMIT}" + cleanWs() + } + } } } } diff --git a/docker/android/Dockerfile b/docker/android/Dockerfile new file mode 100644 index 0000000000..eb70b69ddb --- /dev/null +++ b/docker/android/Dockerfile @@ -0,0 +1,52 @@ +# using fresh 18.04 as it contains suitable `cmake` in repos +FROM ubuntu:18.04 + +# number of concurrent threads during build +# usage: docker build --build-arg PARALLELISM=8 -t name/name . +ARG PARALLELISM=1 +ARG BUILD_TYPE_A +ENV BUILD_TYPE_A=${BUILD_TYPE_A:-Release} +ARG VERSION +ENV VERSION=${VERSION:-26} +ARG PACKAGE +ENV PACKAGE=${PACKAGE:-jp.co.soramitsu.iroha.android} +# valid platforms: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64 +ARG PLATFORM +ENV PLATFORM=${PLATFORM:-x86_64} + +ENV NDK_PATH="/android-ndk/android-ndk-r16b" +ENV DEPS_DIR="/iroha/dependencies" + +RUN apt-get update && \ + apt-get -y install --no-install-recommends git curl apt-utils software-properties-common libpthread-stubs0-dev libpcre3-dev \ + unzip zip build-essential automake libtool ca-certificates ccache zlib1g-dev libcurl4-openssl-dev libc6-dbg cmake; \ + rm -rf /var/lib/apt/lists/* + +RUN set -e; mkdir -p $DEPS_DIR/include $DEPS_DIR/lib + +# boost 1.66 +RUN set -e; \ + curl -L -o /tmp/boost_1_66_0.tar.gz https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz; \ + tar -zxf /tmp/boost_1_66_0.tar.gz -C /tmp; mv /tmp/boost_1_66_0/boost $DEPS_DIR/include; rm -f /tmp/boost_1_66_0.tar.gz + +# install android-ndk-r16b +RUN set -e; \ + curl -L -o /tmp/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip; unzip -q /tmp/android-ndk.zip -d /android-ndk; rm -f /tmp/android-ndk.zip + +# protobuf +RUN set -ex; \ + git clone https://github.com/google/protobuf; \ + (cd ./protobuf ; git checkout b5fbb742af122b565925987e65c08957739976a7); \ + cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE_A -H./protobuf/cmake -B./protobuf/host_build; \ + VERBOSE=1 cmake --build ./protobuf/host_build -- -j$PARALLELISM; \ + sed -i.bak "s~COMMAND js_embed~COMMAND \"$PWD/protobuf/host_build/js_embed\"~" ./protobuf/cmake/libprotoc.cmake; \ + LDFLAGS="-llog -landroid" cmake -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=$VERSION -DCMAKE_ANDROID_ARCH_ABI=$PLATFORM -DANDROID_NDK=$NDK_PATH -DCMAKE_ANDROID_STL_TYPE=c++_static -DCMAKE_INSTALL_PREFIX=$DEPS_DIR -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE="$BUILD_TYPE_A" -H./protobuf/cmake -B./protobuf/.build; \ + VERBOSE=1 cmake --build ./protobuf/.build --target install -- -j$PARALLELISM + +# ed25519 +RUN set -e; \ + git clone git://github.com/hyperledger/iroha-ed25519; \ + (cd ./iroha-ed25519 ; git checkout e7188b8393dbe5ac54378610d53630bd4a180038); \ + cmake -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=$VERSION -DCMAKE_ANDROID_ARCH_ABI=$PLATFORM -DANDROID_NDK=$NDK_PATH -DCMAKE_ANDROID_STL_TYPE=c++_static -DCMAKE_INSTALL_PREFIX=$DEPS_DIR -DTESTING=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE_A -DBUILD=STATIC -H./iroha-ed25519 -B./iroha-ed25519/build; \ + VERBOSE=1 cmake --build ./iroha-ed25519/build --target install -- -j$PARALLELISM; \ + mv "$DEPS_DIR"/lib/static/libed25519.a "$DEPS_DIR"/lib; rmdir "$DEPS_DIR"/lib/static/ diff --git a/docker/android/entrypoint.sh b/docker/android/entrypoint.sh new file mode 100644 index 0000000000..10ff2ba2d4 --- /dev/null +++ b/docker/android/entrypoint.sh @@ -0,0 +1,33 @@ +#!/bin/bash +export LIBP=lib +case "$PLATFORM" in + armeabi) + export ARCH=arch-arm + ;; + armeabi-v7a) + export ARCH=arch-arm + ;; + arm64-v8a) + export ARCH=arch-arm64 + ;; + x86) + export ARCH=arch-x86 + ;; + x86_64) + export ARCH=arch-x86_64 + export LIBP=lib64 + ;; + *) + echo Wrong ABI name: "$PLATFORM" + exit 1 + ;; +esac + +if [ "$BUILD_TYPE_A" = "Release" ]; then + export PROTOBUF_LIB_NAME=protobuf +elif [ "$BUILD_TYPE_A" = "Debug" ]; then + export PROTOBUF_LIB_NAME=protobufd +else + echo "Unknown build type: $BUILD_TYPE_A" + exit 1 +fi diff --git a/docker/develop/aarch64/Dockerfile b/docker/develop/aarch64/Dockerfile index a9c84165e4..2eb33f6f1d 100644 --- a/docker/develop/aarch64/Dockerfile +++ b/docker/develop/aarch64/Dockerfile @@ -23,17 +23,21 @@ RUN set -e; \ automake libtool \ # dev dependencies libssl-dev zlib1g-dev libcurl4-openssl-dev libc6-dbg golang \ - # CircleCI dependencies - git ssh tar gzip ca-certificates python3 python3-pip python3-setuptools \ + # CI dependencies + git ssh tar gzip ca-certificates \ + # Pythons + python-pip python3-pip python3-setuptools python-dev \ + # SWIG dependencies + libpcre3-dev autoconf bison \ # other - wget curl file unzip gdb iputils-ping vim ccache \ - gcovr cppcheck doxygen graphviz graphviz-dev; \ + wget curl file gdb ccache \ + gcovr cppcheck doxygen graphviz graphviz-dev unzip zip; \ apt-get -y clean -# install cmake 3.7.2 +# install cmake 3.10.2 RUN set -e; \ git clone https://gitlab.kitware.com/cmake/cmake.git /tmp/cmake; \ - (cd /tmp/cmake ; git checkout 35413bf2c1b33980afd418030af27f184872af6b); \ + (cd /tmp/cmake ; git checkout c1e087a9d3af74299d7681c9f9de59e5977a1539); \ (cd /tmp/cmake ; /tmp/cmake/bootstrap --system-curl --parallel=${PARALLELISM} --enable-ccache); \ make -j${PARALLELISM} -C /tmp/cmake; \ make -C /tmp/cmake install; \ @@ -202,15 +206,6 @@ RUN set -e; \ ldconfig; \ rm -rf /tmp/tbb -# install docker -ENV DOCKER_VERSION=17.06.0-ce -RUN set -e; \ - curl -L -o /tmp/docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz; \ - tar -xz -C /tmp -f /tmp/docker-${DOCKER_VERSION}.tgz; \ - mv /tmp/docker/* /usr/bin; \ - rm /tmp/docker-${DOCKER_VERSION}.tgz; \ - rm -rf /tmp/docker - # install sonar cli ENV SONAR_CLI_VERSION=3.0.3.778 RUN set -e; \ @@ -235,10 +230,38 @@ RUN set -e; \ rm -rf /tmp/ed25519 # fetch lcov reports converter -RUN curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py +RUN set -e; \ + curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py + +RUN set -e; \ + add-apt-repository -y ppa:webupd8team/java; \ + apt-get update; \ + echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections; \ + apt-get -y install oracle-java8-installer; \ + java -version + +# Build SWIG +RUN set -e; \ + curl -L -o /tmp/swig-3.0.12.tar.gz https://github.com/swig/swig/archive/rel-3.0.12.tar.gz; \ + tar -C /tmp -zxf /tmp/swig-3.0.12.tar.gz; \ + cd /tmp/swig-rel-3.0.12; \ + ./autogen.sh && ./configure && make -j${PARALLELISM}; \ + make install; \ + rm -rf /tmp/swig-rel-3.0.12 + +RUN set -e; \ + add-apt-repository -y ppa:jonathonf/python-3.6; \ + apt-get update; \ + apt-get -y install python3.6-dev + +# python bindings dependencies +RUN set -e; \ + pip install grpcio_tools; \ + pip3 install grpcio_tools # install lcov -RUN curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install +RUN set -e; \ + curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install # non-interactive adduser # -m = create home dir diff --git a/docker/develop/armv7l/Dockerfile b/docker/develop/armv7l/Dockerfile index 1f668a872e..2eb33f6f1d 100644 --- a/docker/develop/armv7l/Dockerfile +++ b/docker/develop/armv7l/Dockerfile @@ -23,17 +23,21 @@ RUN set -e; \ automake libtool \ # dev dependencies libssl-dev zlib1g-dev libcurl4-openssl-dev libc6-dbg golang \ - # CircleCI dependencies - git ssh tar gzip ca-certificates python3 python3-pip python3-setuptools \ + # CI dependencies + git ssh tar gzip ca-certificates \ + # Pythons + python-pip python3-pip python3-setuptools python-dev \ + # SWIG dependencies + libpcre3-dev autoconf bison \ # other - wget curl file unzip gdb iputils-ping vim ccache \ - gcovr cppcheck doxygen graphviz graphviz-dev; \ + wget curl file gdb ccache \ + gcovr cppcheck doxygen graphviz graphviz-dev unzip zip; \ apt-get -y clean -# install cmake 3.7.2 +# install cmake 3.10.2 RUN set -e; \ git clone https://gitlab.kitware.com/cmake/cmake.git /tmp/cmake; \ - (cd /tmp/cmake ; git checkout 35413bf2c1b33980afd418030af27f184872af6b); \ + (cd /tmp/cmake ; git checkout c1e087a9d3af74299d7681c9f9de59e5977a1539); \ (cd /tmp/cmake ; /tmp/cmake/bootstrap --system-curl --parallel=${PARALLELISM} --enable-ccache); \ make -j${PARALLELISM} -C /tmp/cmake; \ make -C /tmp/cmake install; \ @@ -202,15 +206,6 @@ RUN set -e; \ ldconfig; \ rm -rf /tmp/tbb -# install docker -ENV DOCKER_VERSION=17.06.0-ce -RUN set -e; \ - curl -L -o /tmp/docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/armhf/docker-${DOCKER_VERSION}.tgz; \ - tar -xz -C /tmp -f /tmp/docker-${DOCKER_VERSION}.tgz; \ - mv /tmp/docker/* /usr/bin; \ - rm /tmp/docker-${DOCKER_VERSION}.tgz; \ - rm -rf /tmp/docker - # install sonar cli ENV SONAR_CLI_VERSION=3.0.3.778 RUN set -e; \ @@ -235,10 +230,38 @@ RUN set -e; \ rm -rf /tmp/ed25519 # fetch lcov reports converter -RUN curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py +RUN set -e; \ + curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py + +RUN set -e; \ + add-apt-repository -y ppa:webupd8team/java; \ + apt-get update; \ + echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections; \ + apt-get -y install oracle-java8-installer; \ + java -version + +# Build SWIG +RUN set -e; \ + curl -L -o /tmp/swig-3.0.12.tar.gz https://github.com/swig/swig/archive/rel-3.0.12.tar.gz; \ + tar -C /tmp -zxf /tmp/swig-3.0.12.tar.gz; \ + cd /tmp/swig-rel-3.0.12; \ + ./autogen.sh && ./configure && make -j${PARALLELISM}; \ + make install; \ + rm -rf /tmp/swig-rel-3.0.12 + +RUN set -e; \ + add-apt-repository -y ppa:jonathonf/python-3.6; \ + apt-get update; \ + apt-get -y install python3.6-dev + +# python bindings dependencies +RUN set -e; \ + pip install grpcio_tools; \ + pip3 install grpcio_tools # install lcov -RUN curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install +RUN set -e; \ + curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install # non-interactive adduser # -m = create home dir diff --git a/docker/develop/x86_64/Dockerfile b/docker/develop/x86_64/Dockerfile index a9c84165e4..2eb33f6f1d 100644 --- a/docker/develop/x86_64/Dockerfile +++ b/docker/develop/x86_64/Dockerfile @@ -23,17 +23,21 @@ RUN set -e; \ automake libtool \ # dev dependencies libssl-dev zlib1g-dev libcurl4-openssl-dev libc6-dbg golang \ - # CircleCI dependencies - git ssh tar gzip ca-certificates python3 python3-pip python3-setuptools \ + # CI dependencies + git ssh tar gzip ca-certificates \ + # Pythons + python-pip python3-pip python3-setuptools python-dev \ + # SWIG dependencies + libpcre3-dev autoconf bison \ # other - wget curl file unzip gdb iputils-ping vim ccache \ - gcovr cppcheck doxygen graphviz graphviz-dev; \ + wget curl file gdb ccache \ + gcovr cppcheck doxygen graphviz graphviz-dev unzip zip; \ apt-get -y clean -# install cmake 3.7.2 +# install cmake 3.10.2 RUN set -e; \ git clone https://gitlab.kitware.com/cmake/cmake.git /tmp/cmake; \ - (cd /tmp/cmake ; git checkout 35413bf2c1b33980afd418030af27f184872af6b); \ + (cd /tmp/cmake ; git checkout c1e087a9d3af74299d7681c9f9de59e5977a1539); \ (cd /tmp/cmake ; /tmp/cmake/bootstrap --system-curl --parallel=${PARALLELISM} --enable-ccache); \ make -j${PARALLELISM} -C /tmp/cmake; \ make -C /tmp/cmake install; \ @@ -202,15 +206,6 @@ RUN set -e; \ ldconfig; \ rm -rf /tmp/tbb -# install docker -ENV DOCKER_VERSION=17.06.0-ce -RUN set -e; \ - curl -L -o /tmp/docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz; \ - tar -xz -C /tmp -f /tmp/docker-${DOCKER_VERSION}.tgz; \ - mv /tmp/docker/* /usr/bin; \ - rm /tmp/docker-${DOCKER_VERSION}.tgz; \ - rm -rf /tmp/docker - # install sonar cli ENV SONAR_CLI_VERSION=3.0.3.778 RUN set -e; \ @@ -235,10 +230,38 @@ RUN set -e; \ rm -rf /tmp/ed25519 # fetch lcov reports converter -RUN curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py +RUN set -e; \ + curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py + +RUN set -e; \ + add-apt-repository -y ppa:webupd8team/java; \ + apt-get update; \ + echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections; \ + apt-get -y install oracle-java8-installer; \ + java -version + +# Build SWIG +RUN set -e; \ + curl -L -o /tmp/swig-3.0.12.tar.gz https://github.com/swig/swig/archive/rel-3.0.12.tar.gz; \ + tar -C /tmp -zxf /tmp/swig-3.0.12.tar.gz; \ + cd /tmp/swig-rel-3.0.12; \ + ./autogen.sh && ./configure && make -j${PARALLELISM}; \ + make install; \ + rm -rf /tmp/swig-rel-3.0.12 + +RUN set -e; \ + add-apt-repository -y ppa:jonathonf/python-3.6; \ + apt-get update; \ + apt-get -y install python3.6-dev + +# python bindings dependencies +RUN set -e; \ + pip install grpcio_tools; \ + pip3 install grpcio_tools # install lcov -RUN curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install +RUN set -e; \ + curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install # non-interactive adduser # -m = create home dir From 22102741a9e40138bf5e0a7c9efb11b257c2b936 Mon Sep 17 00:00:00 2001 From: Kitsu Date: Thu, 26 Apr 2018 19:34:48 +0300 Subject: [PATCH 063/110] Add result utilities (#1263) Signed-off-by: Kitsu --- libs/common/result.hpp | 61 ++++++ test/framework/result_fixture.hpp | 28 ++- .../irohad/ametsuchi/ametsuchi_test.cpp | 2 +- .../ametsuchi/wsv_query_command_test.cpp | 89 ++++---- .../command_validate_execute_test.cpp | 202 +++++++++--------- test/module/libs/common/result_test.cpp | 107 +++++++++- 6 files changed, 324 insertions(+), 165 deletions(-) diff --git a/libs/common/result.hpp b/libs/common/result.hpp index 2cfdf119b0..a5eca3846d 100644 --- a/libs/common/result.hpp +++ b/libs/common/result.hpp @@ -18,6 +18,7 @@ #ifndef IROHA_RESULT_HPP #define IROHA_RESULT_HPP +#include #include #include "common/visitor.hpp" @@ -106,8 +107,68 @@ namespace iroha { std::forward(value_func), std::forward(error_func)); } + + /** + * Lazy error AND-chaining + * Works by the following table (aka boolean lazy AND): + * err1 * any -> err1 + * val1 * err2 -> err2 + * val1 * val2 -> val2 + * + * @param new_res second chain argument + * @return new_res if this Result contains a value + * otherwise return this + */ + template + constexpr Result and_res(const Result &new_res) const + noexcept { + return visit_in_place( + *this, + [res = new_res](ValueType) { return res; }, + [](ErrorType err) -> Result { return err; }); + } + + /** + * Lazy error OR-chaining + * Works by the following table (aka boolean lazy OR): + * val1 * any -> val1 + * err1 * val2 -> val2 + * err1 * err2 -> err2 + * + * @param new_res second chain argument + * @return new_res if this Result contains a error + * otherwise return this + */ + template + constexpr Result or_res(const Result &new_res) const + noexcept { + return visit_in_place( + *this, + [](ValueType val) -> Result { return val; }, + [res = new_res](ErrorType) { return res; }); + } }; + template + using ValueOf = typename ResultType::ValueType; + template + using ErrorOf = typename ResultType::ErrorType; + + /** + * Get a new result with the copied value or mapped error + * @param res base Result for getting new one + * @param map callback for error mapping + * @return result with changed error + */ + template + Result map_error(const Result &res, Fn &&map) noexcept { + return visit_in_place(res, + [](Value val) -> Result { return val; }, + [map](Error err) -> Result { + return Error{map(err.error)}; + }); + } + // Factory methods for avoiding type specification template Value makeValue(T &&value) { diff --git a/test/framework/result_fixture.hpp b/test/framework/result_fixture.hpp index 1c773afce6..c2e69f068e 100644 --- a/test/framework/result_fixture.hpp +++ b/test/framework/result_fixture.hpp @@ -22,22 +22,34 @@ namespace framework { namespace expected { + template + using ValueOf = iroha::expected::ValueOf; + template + using ErrorOf = iroha::expected::ErrorOf; /** - * @throws bad_get exception if result contains error - * @return value from result + * @return optional with value if present + * otherwise none */ template - typename ResultType::ValueType checkValueCase(const ResultType &result) { - return boost::get(result); + boost::optional> val(const ResultType &res) noexcept { + using RetType = boost::optional>; + return iroha::visit_in_place( + res, + [](ValueOf v) { return RetType(v); }, + [](ErrorOf e) -> RetType { return {}; }); } /** - * @throws bad_get exception if result contains value - * @return error from result + * @return optional with error if present + * otherwise none */ template - typename ResultType::ErrorType checkErrorCase(const ResultType &result) { - return boost::get(result); + boost::optional> err(const ResultType &res) noexcept { + using RetType = boost::optional>; + return iroha::visit_in_place( + res, + [](ValueOf v) -> RetType { return {}; }, + [](ErrorOf e) { return RetType(e); }); } } // namespace expected } // namespace framework diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index 314aeec479..42bf5f1175 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -46,7 +46,7 @@ using AmountBuilder = shared_model::builder::AmountBuilderWithoutValidator; std::shared_ptr getAmount( const shared_model::builder::BuilderResult &result) { - return framework::expected::checkValueCase(result).value; + return framework::expected::val(result)->value; } /** diff --git a/test/module/irohad/ametsuchi/wsv_query_command_test.cpp b/test/module/irohad/ametsuchi/wsv_query_command_test.cpp index 0b7450ed27..f277d51d2a 100644 --- a/test/module/irohad/ametsuchi/wsv_query_command_test.cpp +++ b/test/module/irohad/ametsuchi/wsv_query_command_test.cpp @@ -78,7 +78,7 @@ namespace iroha { * @then role is successfully inserted */ TEST_F(RoleTest, InsertRoleWhenValidName) { - ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); + ASSERT_TRUE(val(command->insertRole(role))); auto roles = query->getRoles(); ASSERT_TRUE(roles); ASSERT_EQ(1, roles->size()); @@ -91,8 +91,7 @@ namespace iroha { * @then role is failed */ TEST_F(RoleTest, InsertRoleWhenInvalidName) { - ASSERT_NO_THROW( - checkErrorCase(command->insertRole(std::string(46, 'a')))); + ASSERT_TRUE(err(command->insertRole(std::string(46, 'a')))); auto roles = query->getRoles(); ASSERT_TRUE(roles); @@ -102,7 +101,7 @@ namespace iroha { class RolePermissionsTest : public WsvQueryCommandTest { void SetUp() override { WsvQueryCommandTest::SetUp(); - ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); + ASSERT_TRUE(val(command->insertRole(role))); } }; @@ -112,8 +111,7 @@ namespace iroha { * @then RolePermissions are inserted */ TEST_F(RolePermissionsTest, InsertRolePermissionsWhenRoleExists) { - ASSERT_NO_THROW( - checkValueCase(command->insertRolePermissions(role, {permission}))); + ASSERT_TRUE(val(command->insertRolePermissions(role, {permission}))); auto permissions = query->getRolePermissions(role); ASSERT_TRUE(permissions); @@ -128,8 +126,7 @@ namespace iroha { */ TEST_F(RolePermissionsTest, InsertRolePermissionsWhenNoRole) { auto new_role = role + " "; - ASSERT_NO_THROW(checkErrorCase( - command->insertRolePermissions(new_role, {permission}))); + ASSERT_TRUE(err(command->insertRolePermissions(new_role, {permission}))); auto permissions = query->getRolePermissions(new_role); ASSERT_TRUE(permissions); @@ -139,8 +136,8 @@ namespace iroha { class AccountTest : public WsvQueryCommandTest { void SetUp() override { WsvQueryCommandTest::SetUp(); - ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); - ASSERT_NO_THROW(checkValueCase(command->insertDomain(*domain))); + ASSERT_TRUE(val(command->insertRole(role))); + ASSERT_TRUE(val(command->insertDomain(*domain))); } }; @@ -150,7 +147,7 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertAccountWithJSONData) { - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); + ASSERT_TRUE(val(command->insertAccount(*account))); auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); ASSERT_EQ(account->jsonData(), acc.value()->jsonData()); @@ -162,8 +159,8 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertNewJSONDataAccount) { - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); - ASSERT_NO_THROW(checkValueCase(command->setAccountKV( + ASSERT_TRUE(val(command->insertAccount(*account))); + ASSERT_TRUE(val(command->setAccountKV( account->accountId(), account->accountId(), "id", "val"))); auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); @@ -177,8 +174,8 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertNewJSONDataToOtherAccount) { - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); - ASSERT_NO_THROW(checkValueCase( + ASSERT_TRUE(val(command->insertAccount(*account))); + ASSERT_TRUE(val( command->setAccountKV(account->accountId(), "admin", "id", "val"))); auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); @@ -192,8 +189,8 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, InsertNewComplexJSONDataAccount) { - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); - ASSERT_NO_THROW(checkValueCase(command->setAccountKV( + ASSERT_TRUE(val(command->insertAccount(*account))); + ASSERT_TRUE(val(command->setAccountKV( account->accountId(), account->accountId(), "id", "[val1, val2]"))); auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); @@ -207,8 +204,8 @@ namespace iroha { * @then get account and check json data is the same */ TEST_F(AccountTest, UpdateAccountJSONData) { - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); - ASSERT_NO_THROW(checkValueCase(command->setAccountKV( + ASSERT_TRUE(val(command->insertAccount(*account))); + ASSERT_TRUE(val(command->setAccountKV( account->accountId(), account->accountId(), "key", "val2"))); auto acc = query->getAccount(account->accountId()); ASSERT_TRUE(acc); @@ -236,9 +233,9 @@ namespace iroha { class AccountRoleTest : public WsvQueryCommandTest { void SetUp() override { WsvQueryCommandTest::SetUp(); - ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); - ASSERT_NO_THROW(checkValueCase(command->insertDomain(*domain))); - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); + ASSERT_TRUE(val(command->insertRole(role))); + ASSERT_TRUE(val(command->insertDomain(*domain))); + ASSERT_TRUE(val(command->insertAccount(*account))); } }; @@ -248,8 +245,7 @@ namespace iroha { * @then account role is inserted */ TEST_F(AccountRoleTest, InsertAccountRoleWhenAccountRoleExist) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccountRole(account->accountId(), role))); + ASSERT_TRUE(val(command->insertAccountRole(account->accountId(), role))); auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); @@ -264,8 +260,7 @@ namespace iroha { */ TEST_F(AccountRoleTest, InsertAccountRoleWhenNoAccount) { auto account_id = account->accountId() + " "; - ASSERT_NO_THROW( - checkErrorCase(command->insertAccountRole(account_id, role))); + ASSERT_TRUE(err(command->insertAccountRole(account_id, role))); auto roles = query->getAccountRoles(account_id); ASSERT_TRUE(roles); @@ -279,8 +274,8 @@ namespace iroha { */ TEST_F(AccountRoleTest, InsertAccountRoleWhenNoRole) { auto new_role = role + " "; - ASSERT_NO_THROW(checkErrorCase( - command->insertAccountRole(account->accountId(), new_role))); + ASSERT_TRUE( + err(command->insertAccountRole(account->accountId(), new_role))); auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); @@ -293,10 +288,8 @@ namespace iroha { * @then role is detached */ TEST_F(AccountRoleTest, DeleteAccountRoleWhenExist) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccountRole(account->accountId(), role))); - ASSERT_NO_THROW(checkValueCase( - command->deleteAccountRole(account->accountId(), role))); + ASSERT_TRUE(val(command->insertAccountRole(account->accountId(), role))); + ASSERT_TRUE(val(command->deleteAccountRole(account->accountId(), role))); auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(0, roles->size()); @@ -308,9 +301,8 @@ namespace iroha { * @then nothing is deleted */ TEST_F(AccountRoleTest, DeleteAccountRoleWhenNoAccount) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccountRole(account->accountId(), role))); - ASSERT_NO_THROW(checkValueCase(command->deleteAccountRole("no", role))); + ASSERT_TRUE(val(command->insertAccountRole(account->accountId(), role))); + ASSERT_TRUE(val(command->deleteAccountRole("no", role))); auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(1, roles->size()); @@ -322,10 +314,8 @@ namespace iroha { * @then nothing is deleted */ TEST_F(AccountRoleTest, DeleteAccountRoleWhenNoRole) { - ASSERT_NO_THROW(checkValueCase( - command->insertAccountRole(account->accountId(), role))); - ASSERT_NO_THROW(checkValueCase( - command->deleteAccountRole(account->accountId(), "no"))); + ASSERT_TRUE(val(command->insertAccountRole(account->accountId(), role))); + ASSERT_TRUE(val(command->deleteAccountRole(account->accountId(), "no"))); auto roles = query->getAccountRoles(account->accountId()); ASSERT_TRUE(roles); ASSERT_EQ(1, roles->size()); @@ -344,11 +334,10 @@ namespace iroha { .jsonData(R"({"id@domain": {"key": "value"}})") .build()); - ASSERT_NO_THROW(checkValueCase(command->insertRole(role))); - ASSERT_NO_THROW(checkValueCase(command->insertDomain(*domain))); - ASSERT_NO_THROW(checkValueCase(command->insertAccount(*account))); - ASSERT_NO_THROW( - checkValueCase(command->insertAccount(*permittee_account))); + ASSERT_TRUE(val(command->insertRole(role))); + ASSERT_TRUE(val(command->insertDomain(*domain))); + ASSERT_TRUE(val(command->insertAccount(*account))); + ASSERT_TRUE(val(command->insertAccount(*permittee_account))); } std::shared_ptr permittee_account; @@ -361,7 +350,7 @@ namespace iroha { */ TEST_F(AccountGrantablePermissionTest, InsertAccountGrantablePermissionWhenAccountsExist) { - ASSERT_NO_THROW(checkValueCase(command->insertAccountGrantablePermission( + ASSERT_TRUE(val(command->insertAccountGrantablePermission( permittee_account->accountId(), account->accountId(), permission))); ASSERT_TRUE(query->hasAccountGrantablePermission( @@ -376,7 +365,7 @@ namespace iroha { TEST_F(AccountGrantablePermissionTest, InsertAccountGrantablePermissionWhenNoPermitteeAccount) { auto permittee_account_id = permittee_account->accountId() + " "; - ASSERT_NO_THROW(checkErrorCase(command->insertAccountGrantablePermission( + ASSERT_TRUE(err(command->insertAccountGrantablePermission( permittee_account_id, account->accountId(), permission))); ASSERT_FALSE(query->hasAccountGrantablePermission( @@ -386,7 +375,7 @@ namespace iroha { TEST_F(AccountGrantablePermissionTest, InsertAccountGrantablePermissionWhenNoAccount) { auto account_id = account->accountId() + " "; - ASSERT_NO_THROW(checkErrorCase(command->insertAccountGrantablePermission( + ASSERT_TRUE(err(command->insertAccountGrantablePermission( permittee_account->accountId(), account_id, permission))); ASSERT_FALSE(query->hasAccountGrantablePermission( @@ -400,7 +389,7 @@ namespace iroha { */ TEST_F(AccountGrantablePermissionTest, DeleteAccountGrantablePermissionWhenAccountsPermissionExist) { - ASSERT_NO_THROW(checkValueCase(command->deleteAccountGrantablePermission( + ASSERT_TRUE(val(command->deleteAccountGrantablePermission( permittee_account->accountId(), account->accountId(), permission))); ASSERT_FALSE(query->hasAccountGrantablePermission( @@ -423,9 +412,9 @@ namespace iroha { * @then peer is successfully deleted */ TEST_F(DeletePeerTest, DeletePeerValidWhenPeerExists) { - ASSERT_NO_THROW(checkValueCase(command->insertPeer(*peer))); + ASSERT_TRUE(val(command->insertPeer(*peer))); - ASSERT_NO_THROW(checkValueCase(command->deletePeer(*peer))); + ASSERT_TRUE(val(command->deletePeer(*peer))); } class GetAssetTest : public WsvQueryCommandTest {}; diff --git a/test/module/irohad/execution/command_validate_execute_test.cpp b/test/module/irohad/execution/command_validate_execute_test.cpp index f460a5c2ec..1058cb9749 100644 --- a/test/module/irohad/execution/command_validate_execute_test.cpp +++ b/test/module/irohad/execution/command_validate_execute_test.cpp @@ -26,9 +26,9 @@ #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "validators/permissions.hpp" +using ::testing::_; using ::testing::Return; using ::testing::StrictMock; -using ::testing::_; using namespace iroha; using namespace iroha::ametsuchi; @@ -250,7 +250,7 @@ TEST_F(AddAssetQuantityTest, ValidWhenNewWallet) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -272,7 +272,7 @@ TEST_F(AddAssetQuantityTest, ValidWhenExistingWallet) { .WillOnce(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -283,7 +283,7 @@ TEST_F(AddAssetQuantityTest, ValidWhenExistingWallet) { TEST_F(AddAssetQuantityTest, InvalidWhenNoRoles) { EXPECT_CALL(*wsv_query, getAccountRoles(add_asset_quantity->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -304,7 +304,7 @@ TEST_F(AddAssetQuantityTest, InvalidWhenWrongPrecision) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -322,7 +322,7 @@ TEST_F(AddAssetQuantityTest, InvalidWhenNoAccount) { EXPECT_CALL(*wsv_query, getAccount(add_asset_quantity->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -346,7 +346,7 @@ TEST_F(AddAssetQuantityTest, InvalidWhenNoAsset) { EXPECT_CALL(*wsv_query, getAsset(add_asset_quantity->assetId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -373,7 +373,7 @@ TEST_F(AddAssetQuantityTest, InvalidWhenAssetAdditionFails) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } class SubtractAssetQuantityTest : public CommandValidateExecuteTest { @@ -410,7 +410,7 @@ TEST_F(SubtractAssetQuantityTest, InvalidWhenNoWallet) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -430,7 +430,7 @@ TEST_F(SubtractAssetQuantityTest, ValidWhenExistingWallet) { .WillOnce(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -457,7 +457,7 @@ TEST_F(SubtractAssetQuantityTest, InvalidWhenOverAmount) { .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -468,7 +468,7 @@ TEST_F(SubtractAssetQuantityTest, InvalidWhenOverAmount) { TEST_F(SubtractAssetQuantityTest, InvalidWhenNoRoles) { EXPECT_CALL(*wsv_query, getAccountRoles(subtract_asset_quantity->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -489,7 +489,7 @@ TEST_F(SubtractAssetQuantityTest, InvalidWhenWrongPrecision) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getAsset(kAssetId)).WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -505,7 +505,7 @@ TEST_F(SubtractAssetQuantityTest, InvalidWhenNoAccount) { getConcreteCommand( command); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -528,7 +528,7 @@ TEST_F(SubtractAssetQuantityTest, InvalidWhenNoAsset) { EXPECT_CALL(*wsv_query, getAsset(subtract_asset_quantity->assetId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } class AddSignatoryTest : public CommandValidateExecuteTest { @@ -564,7 +564,7 @@ TEST_F(AddSignatoryTest, ValidWhenCreatorHasPermissions) { insertAccountSignatory(add_signatory->accountId(), add_signatory->pubkey())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -590,7 +590,7 @@ TEST_F(AddSignatoryTest, ValidWhenSameAccount) { add_signatory->pubkey())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -604,7 +604,7 @@ TEST_F(AddSignatoryTest, InvalidWhenNoPermissions) { kAdminId, add_signatory->accountId(), can_add_my_signatory)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -614,8 +614,8 @@ TEST_F(AddSignatoryTest, InvalidWhenNoPermissions) { */ TEST_F(AddSignatoryTest, InvalidWhenNoAccount) { // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = - buildCommand(TestTransactionBuilder().addSignatory(kNoAcountId, kPubKey1)); + command = buildCommand( + TestTransactionBuilder().addSignatory(kNoAcountId, kPubKey1)); add_signatory = getConcreteCommand(command); @@ -624,7 +624,7 @@ TEST_F(AddSignatoryTest, InvalidWhenNoAccount) { kAdminId, add_signatory->accountId(), can_add_my_signatory)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -646,7 +646,7 @@ TEST_F(AddSignatoryTest, InvalidWhenSameKey) { EXPECT_CALL(*wsv_command, insertSignatory(add_signatory->pubkey())) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } class CreateAccountTest : public CommandValidateExecuteTest { @@ -696,7 +696,7 @@ TEST_F(CreateAccountTest, ValidWhenNewAccount) { EXPECT_CALL(*wsv_command, insertAccountRole(kAccountId, kAdminRole)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -708,7 +708,7 @@ TEST_F(CreateAccountTest, InvalidWhenNoPermissions) { // Creator has no permission EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -723,7 +723,7 @@ TEST_F(CreateAccountTest, InvalidWhenNoDomain) { .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getDomain(kDomainId)).WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } class CreateAssetTest : public CommandValidateExecuteTest { @@ -756,7 +756,7 @@ TEST_F(CreateAssetTest, ValidWhenCreatorHasPermissions) { EXPECT_CALL(*wsv_command, insertAsset(_)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -770,7 +770,7 @@ TEST_F(CreateAssetTest, InvalidWhenNoPermissions) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -781,7 +781,7 @@ TEST_F(CreateAssetTest, InvalidWhenNoPermissions) { TEST_F(CreateAssetTest, InvalidWhenAssetInsertionFails) { EXPECT_CALL(*wsv_command, insertAsset(_)).WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class CreateDomainTest : public CommandValidateExecuteTest { @@ -815,7 +815,7 @@ TEST_F(CreateDomainTest, ValidWhenCreatorHasPermissions) { EXPECT_CALL(*wsv_command, insertDomain(_)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -826,7 +826,7 @@ TEST_F(CreateDomainTest, ValidWhenCreatorHasPermissions) { TEST_F(CreateDomainTest, InvalidWhenNoPermissions) { EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -837,7 +837,7 @@ TEST_F(CreateDomainTest, InvalidWhenNoPermissions) { TEST_F(CreateDomainTest, InvalidWhenDomainInsertionFails) { EXPECT_CALL(*wsv_command, insertDomain(_)).WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class RemoveSignatoryTest : public CommandValidateExecuteTest { @@ -891,7 +891,7 @@ TEST_F(RemoveSignatoryTest, ValidWhenMultipleKeys) { .WillOnce(Return(WsvCommandResult())); EXPECT_CALL(*wsv_command, deleteSignatory(remove_signatory->pubkey())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -920,7 +920,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenSingleKey) { EXPECT_CALL(*wsv_command, deleteSignatory(remove_signatory->pubkey())) .Times(0); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -935,7 +935,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissions) { kAdminId, remove_signatory->accountId(), can_remove_my_signatory)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -966,7 +966,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoKey) { getSignatories(wrong_key_remove_signatory->accountId())) .WillOnce(Return(account_pubkeys)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(wrong_key_command))); + ASSERT_TRUE(err(validateAndExecute(wrong_key_command))); } /** @@ -987,7 +987,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoAccount) { EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) .WillOnce(Return(many_pubkeys)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1009,7 +1009,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoSignatories) { EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1031,7 +1031,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoAccountAndSignatories) { EXPECT_CALL(*wsv_query, getSignatories(remove_signatory->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1056,7 +1056,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenNoPermissionToRemoveFromSelf) { kAdminId, kAdminId, can_remove_my_signatory)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1070,7 +1070,7 @@ TEST_F(RemoveSignatoryTest, InvalidWhenAccountSignatoryDeletionFails) { remove_signatory->pubkey())) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class SetQuorumTest : public CommandValidateExecuteTest { @@ -1118,7 +1118,7 @@ TEST_F(SetQuorumTest, ValidWhenCreatorHasPermissions) { EXPECT_CALL(*wsv_command, updateAccount(_)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1138,7 +1138,7 @@ TEST_F(SetQuorumTest, ValidWhenSameAccount) { EXPECT_CALL(*wsv_command, updateAccount(_)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(creator_command))); + ASSERT_TRUE(val(validateAndExecute(creator_command))); } /** * @given SetQuorum and creator has not grantable permissions @@ -1151,7 +1151,7 @@ TEST_F(SetQuorumTest, InvalidWhenNoPermissions) { kAdminId, set_quorum->accountId(), can_set_my_quorum)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** * @given SetQuorum and account parameter is invalid @@ -1160,7 +1160,8 @@ TEST_F(SetQuorumTest, InvalidWhenNoPermissions) { */ TEST_F(SetQuorumTest, InvalidWhenNoAccount) { // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = buildCommand(TestTransactionBuilder().setAccountQuorum(kNoAcountId, 2)); + command = + buildCommand(TestTransactionBuilder().setAccountQuorum(kNoAcountId, 2)); set_quorum = getConcreteCommand(command); EXPECT_CALL(*wsv_query, @@ -1168,7 +1169,7 @@ TEST_F(SetQuorumTest, InvalidWhenNoAccount) { kAdminId, set_quorum->accountId(), can_set_my_quorum)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1187,7 +1188,7 @@ TEST_F(SetQuorumTest, InvalidWhenNoAccountButPassedPermissions) { EXPECT_CALL(*wsv_query, getAccount(creator_set_quorum->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(creator_command))); + ASSERT_TRUE(err(validateAndExecute(creator_command))); } /** @@ -1204,7 +1205,7 @@ TEST_F(SetQuorumTest, InvalidWhenNoSignatories) { EXPECT_CALL(*wsv_query, getSignatories(creator_set_quorum->accountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(creator_command))); + ASSERT_TRUE(err(validateAndExecute(creator_command))); } /** @@ -1226,7 +1227,7 @@ TEST_F(SetQuorumTest, InvalidWhenNotEnoughSignatories) { .WillOnce(Return(acc_pubkeys)); EXPECT_CALL(*wsv_command, updateAccount(_)).Times(0); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(creator_command))); + ASSERT_TRUE(err(validateAndExecute(creator_command))); } class TransferAssetTest : public CommandValidateExecuteTest { @@ -1292,7 +1293,7 @@ TEST_F(TransferAssetTest, ValidWhenNewWallet) { .Times(2) .WillRepeatedly(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1330,7 +1331,7 @@ TEST_F(TransferAssetTest, ValidWhenExistingWallet) { .Times(2) .WillRepeatedly(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1374,7 +1375,7 @@ TEST_F(TransferAssetTest, ValidWhenCreatorHasPermission) { .Times(2) .WillRepeatedly(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1387,7 +1388,7 @@ TEST_F(TransferAssetTest, InvalidWhenNoPermissions) { EXPECT_CALL(*wsv_query, getAccountRoles(transfer_asset->srcAccountId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1410,7 +1411,7 @@ TEST_F(TransferAssetTest, InvalidWhenNoDestAccount) { EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1434,7 +1435,7 @@ TEST_F(TransferAssetTest, InvalidWhenNoSrcAccountAsset) { transfer_asset->assetId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1463,7 +1464,7 @@ TEST_F(TransferAssetTest, InvalidWhenNoSrcAccountAssetDuringExecute) { EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) .WillOnce(Return(account)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1483,7 +1484,7 @@ TEST_F(TransferAssetTest, InvalidWhenNoAssetDuringValidation) { EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1515,7 +1516,7 @@ TEST_F(TransferAssetTest, InvalidWhenNoAssetId) { EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) .WillOnce(Return(account)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1547,7 +1548,7 @@ TEST_F(TransferAssetTest, InvalidWhenInsufficientFunds) { EXPECT_CALL(*wsv_query, getAccount(transfer_asset->destAccountId())) .WillOnce(Return(account)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1573,7 +1574,7 @@ TEST_F(TransferAssetTest, InvalidWhenInsufficientFundsDuringExecute) { transfer_asset->assetId())) .WillOnce(Return(dst_wallet)); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } /** @@ -1599,7 +1600,7 @@ TEST_F(TransferAssetTest, InvalidWhenWrongPrecision) { EXPECT_CALL(*wsv_query, getAsset(transfer_asset->assetId())) .WillOnce(Return(asset)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1625,7 +1626,7 @@ TEST_F(TransferAssetTest, InvalidWhenWrongPrecisionDuringExecute) { transfer_asset->assetId())) .WillOnce(Return(dst_wallet)); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } /** @@ -1659,7 +1660,7 @@ TEST_F(TransferAssetTest, InvalidWhenAmountOverflow) { transfer_asset->assetId())) .WillOnce(Return(max_wallet)); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } /** @@ -1679,7 +1680,7 @@ TEST_F(TransferAssetTest, InvalidWhenCreatorHasNoPermission) { hasAccountGrantablePermission( kAdminId, kAccountId, can_transfer_my_assets)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } class AddPeerTest : public CommandValidateExecuteTest { @@ -1708,7 +1709,7 @@ TEST_F(AddPeerTest, ValidCase) { .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_command, insertPeer(_)).WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1722,7 +1723,7 @@ TEST_F(AddPeerTest, InvalidCaseWhenNoPermissions) { .WillOnce(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1733,7 +1734,7 @@ TEST_F(AddPeerTest, InvalidCaseWhenNoPermissions) { TEST_F(AddPeerTest, InvalidCaseWhenInsertPeerFails) { EXPECT_CALL(*wsv_command, insertPeer(_)).WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class CreateRoleTest : public CommandValidateExecuteTest { @@ -1745,7 +1746,8 @@ class CreateRoleTest : public CommandValidateExecuteTest { role_permissions = {can_create_role}; // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = buildCommand(TestTransactionBuilder().createRole(kAccountId, perm)); + command = + buildCommand(TestTransactionBuilder().createRole(kAccountId, perm)); create_role = getConcreteCommand(command); } @@ -1768,7 +1770,7 @@ TEST_F(CreateRoleTest, ValidCase) { insertRolePermissions(create_role->roleName(), create_role->rolePermissions())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1781,7 +1783,7 @@ TEST_F(CreateRoleTest, InvalidCaseWhenNoPermissions) { .WillRepeatedly(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillRepeatedly(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1792,14 +1794,14 @@ TEST_F(CreateRoleTest, InvalidCaseWhenNoPermissions) { TEST_F(CreateRoleTest, InvalidCaseWhenRoleSuperset) { // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder std::set master_perms = {can_add_peer, can_append_role}; - command = - buildCommand(TestTransactionBuilder().createRole(kMasterRole, master_perms)); + command = buildCommand( + TestTransactionBuilder().createRole(kMasterRole, master_perms)); EXPECT_CALL(*wsv_query, getAccountRoles(kAdminId)) .WillRepeatedly(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillRepeatedly(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1810,7 +1812,7 @@ TEST_F(CreateRoleTest, InvalidCaseWhenRoleSuperset) { TEST_F(CreateRoleTest, InvalidCaseWhenRoleInsertionFails) { EXPECT_CALL(*wsv_command, insertRole(create_role->roleName())) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class AppendRoleTest : public CommandValidateExecuteTest { @@ -1821,8 +1823,8 @@ class AppendRoleTest : public CommandValidateExecuteTest { role_permissions = {can_append_role}; // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = - buildCommand(TestTransactionBuilder().appendRole(kAccountId, kMasterRole)); + command = buildCommand( + TestTransactionBuilder().appendRole(kAccountId, kMasterRole)); append_role = getConcreteCommand(command); } @@ -1849,7 +1851,7 @@ TEST_F(AppendRoleTest, ValidCase) { *wsv_command, insertAccountRole(append_role->accountId(), append_role->roleName())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1862,7 +1864,7 @@ TEST_F(AppendRoleTest, InvalidCaseNoPermissions) { .WillOnce(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1879,7 +1881,7 @@ TEST_F(AppendRoleTest, InvalidCaseNoAccountRole) { .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1898,7 +1900,7 @@ TEST_F(AppendRoleTest, InvalidCaseNoAccountRoleAndNoPermission) { .WillOnce(Return(role_permissions)); EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1919,7 +1921,7 @@ TEST_F(AppendRoleTest, InvalidCaseRoleHasNoPermissions) { EXPECT_CALL(*wsv_query, getRolePermissions(kMasterRole)) .WillOnce(Return(role_permissions)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1932,7 +1934,7 @@ TEST_F(AppendRoleTest, InvalidCaseInsertAccountRoleFails) { *wsv_command, insertAccountRole(append_role->accountId(), append_role->roleName())) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class DetachRoleTest : public CommandValidateExecuteTest { @@ -1943,8 +1945,8 @@ class DetachRoleTest : public CommandValidateExecuteTest { role_permissions = {can_detach_role}; // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = - buildCommand(TestTransactionBuilder().detachRole(kAccountId, kMasterRole)); + command = buildCommand( + TestTransactionBuilder().detachRole(kAccountId, kMasterRole)); detach_role = getConcreteCommand(command); } @@ -1965,7 +1967,7 @@ TEST_F(DetachRoleTest, ValidCase) { *wsv_command, deleteAccountRole(detach_role->accountId(), detach_role->roleName())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -1978,7 +1980,7 @@ TEST_F(DetachRoleTest, InvalidCase) { .WillOnce(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -1991,7 +1993,7 @@ TEST_F(DetachRoleTest, InvalidCaseWhenDeleteAccountRoleFails) { *wsv_command, deleteAccountRole(detach_role->accountId(), detach_role->roleName())) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class GrantPermissionTest : public CommandValidateExecuteTest { @@ -2003,8 +2005,8 @@ class GrantPermissionTest : public CommandValidateExecuteTest { role_permissions = {can_grant + expected_permission}; // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = buildCommand( - TestTransactionBuilder().grantPermission(kAccountId, expected_permission)); + command = buildCommand(TestTransactionBuilder().grantPermission( + kAccountId, expected_permission)); grant_permission = getConcreteCommand(command); } @@ -2027,7 +2029,7 @@ TEST_F(GrantPermissionTest, ValidCase) { creator->accountId(), expected_permission)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -2040,7 +2042,7 @@ TEST_F(GrantPermissionTest, InvalidCaseWhenNoPermissions) { .WillOnce(Return(admin_roles)); EXPECT_CALL(*wsv_query, getRolePermissions(kAdminRole)) .WillOnce(Return(boost::none)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -2054,7 +2056,7 @@ TEST_F(GrantPermissionTest, InvalidCaseWhenInsertGrantablePermissionFails) { creator->accountId(), expected_permission)) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class RevokePermissionTest : public CommandValidateExecuteTest { @@ -2065,8 +2067,8 @@ class RevokePermissionTest : public CommandValidateExecuteTest { expected_permission = can_add_my_signatory; // TODO 2018-04-20 Alexey Chernyshov - IR-1276 - rework with CommandBuilder - command = buildCommand( - TestTransactionBuilder().revokePermission(kAccountId, expected_permission)); + command = buildCommand(TestTransactionBuilder().revokePermission( + kAccountId, expected_permission)); revoke_permission = getConcreteCommand(command); } @@ -2091,7 +2093,7 @@ TEST_F(RevokePermissionTest, ValidCase) { creator->accountId(), expected_permission)) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -2105,7 +2107,7 @@ TEST_F(RevokePermissionTest, InvalidCaseNoPermissions) { hasAccountGrantablePermission( revoke_permission->accountId(), kAdminId, expected_permission)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -2119,7 +2121,7 @@ TEST_F(RevokePermissionTest, InvalidCaseDeleteAccountPermissionvFails) { creator->accountId(), expected_permission)) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } class SetAccountDetailTest : public CommandValidateExecuteTest { @@ -2155,7 +2157,7 @@ TEST_F(SetAccountDetailTest, ValidWhenSetOwnAccount) { set_aacount_detail->key(), set_aacount_detail->value())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -2174,7 +2176,7 @@ TEST_F(SetAccountDetailTest, InValidWhenOtherCreator) { hasAccountGrantablePermission( kAdminId, set_aacount_detail->accountId(), kNeededPermission)) .WillOnce(Return(false)); - ASSERT_NO_THROW(checkErrorCase(validateAndExecute(command))); + ASSERT_TRUE(err(validateAndExecute(command))); } /** @@ -2199,7 +2201,7 @@ TEST_F(SetAccountDetailTest, ValidWhenHasPermissions) { set_aacount_detail->key(), set_aacount_detail->value())) .WillOnce(Return(WsvCommandResult())); - ASSERT_NO_THROW(checkValueCase(validateAndExecute(command))); + ASSERT_TRUE(val(validateAndExecute(command))); } /** @@ -2214,5 +2216,5 @@ TEST_F(SetAccountDetailTest, InvalidWhenSetAccountKVFails) { set_aacount_detail->key(), set_aacount_detail->value())) .WillOnce(Return(makeEmptyError())); - ASSERT_NO_THROW(checkErrorCase(execute(command))); + ASSERT_TRUE(err(execute(command))); } diff --git a/test/module/libs/common/result_test.cpp b/test/module/libs/common/result_test.cpp index c5335bd3d6..61cf7117b7 100644 --- a/test/module/libs/common/result_test.cpp +++ b/test/module/libs/common/result_test.cpp @@ -158,6 +158,102 @@ TEST(ResultTest, ResultVoidError) { makeFailCase>(kErrorCaseMessage)); } +/** + * @given Pair of results with some values + * @when and_res function is invoked + * @then result contains the last value + */ +TEST(ResultTest, AndResWithValVal) { + Result result = makeValue(5); + Result new_res = makeValue(4); + result.and_res(new_res).match([](Value v) { ASSERT_EQ(4, v.value); }, + makeFailCase>(kErrorCaseMessage)); +} + +/** + * @given Pair of results: first with error, second with value + * @when and_res function is invoked + * @then result contains the first error + */ +TEST(ResultTest, AndResWithErrVal) { + Result result = makeError(5); + Result new_res = makeValue(4); + result.and_res(new_res).match(makeFailCase>(kValueCaseMessage), + [](Error e) { ASSERT_EQ(5, e.error); }); +} + +/** + * @given Pair of results: first with value, second with error + * @when and_res function is invoked + * @then result contains the second error + */ +TEST(ResultTest, AndResWithValErr) { + Result result = makeValue(5); + Result new_res = makeError(4); + result.and_res(new_res).match(makeFailCase>(kValueCaseMessage), + [](Error e) { ASSERT_EQ(4, e.error); }); +} + +/** + * @given Pair of results with some values + * @when or_res function is invoked + * @then result contains the first value + */ +TEST(ResultTest, OrResWithValVal) { + Result result = makeValue(5); + Result new_res = makeValue(4); + result.or_res(new_res).match([](Value v) { ASSERT_EQ(5, v.value); }, + makeFailCase>(kErrorCaseMessage)); +} + +/** + * @given Pair of results: first with error, second with value + * @when or_res function is invoked + * @then result contains the second value + */ +TEST(ResultTest, OrResWithErrVal) { + Result result = makeError(5); + Result new_res = makeValue(4); + result.or_res(new_res).match([](Value v) { ASSERT_EQ(4, v.value); }, + makeFailCase>(kErrorCaseMessage)); +} + +/** + * @given Pair of results with some errors + * @when or_res function is invoked + * @then result contains the last value + */ +TEST(ResultTest, OrResWithErrErr) { + Result result = makeError(5); + Result new_res = makeError(4); + result.or_res(new_res).match(makeFailCase>(kValueCaseMessage), + [](Error e) { ASSERT_EQ(4, e.error); }); +} + +/** + * @given Result with some error and some function + * @when map_error function is invoked + * @then result contains error after function application + */ +TEST(ResultTest, MapError) { + Result result = makeError(5); + map_error(result, [](auto i) { return i * 2; }) + .match(makeFailCase>(kValueCaseMessage), + [](Error e) { ASSERT_EQ(10, e.error); }); +} + +/** + * @given Result with some error and some function + * @when map_error function is invoked + * @then result contains the same error + */ +TEST(ResultTest, MapErrorBlank) { + Result result = makeValue(5); + map_error(result, [](auto i) { return i * 2; }) + .match([](Value v) { ASSERT_EQ(5, v.value); }, + makeFailCase>(kErrorCaseMessage)); +} + /// Polymorphic result tests /// Base and Derived are classes, which can be used to test polymorphic behavior @@ -188,7 +284,7 @@ TEST(PolyMorphicResultTest, PolymorphicValueConstruction) { [](Value> &v) { ASSERT_EQ(1, v.value->getNumber()); }, - makeFailCase>>(kErrorCaseMessage)); + makeFailCase>>(kErrorCaseMessage)); } /** @@ -199,9 +295,8 @@ TEST(PolyMorphicResultTest, PolymorphicValueConstruction) { TEST(PolyMorphicResultTest, PolymorphicErrorConstruction) { PolymorphicResult result = makeError(std::make_shared(kErrorMessage)); - result.match( - makeFailCase>>(kValueCaseMessage), - [](Error> &e) { - ASSERT_EQ(kErrorMessage, *e.error); - }); + result.match(makeFailCase>>(kValueCaseMessage), + [](Error> &e) { + ASSERT_EQ(kErrorMessage, *e.error); + }); } From 1c639d722ea3712a2292401d10a047360bc5206a Mon Sep 17 00:00:00 2001 From: Kitsu Date: Thu, 26 Apr 2018 19:56:40 +0300 Subject: [PATCH 064/110] Use pubkey as identifier in SignatureSetType (#1193) Signed-off-by: Kitsu --- .../common_objects/signable_hash.hpp | 35 +++++++++------- .../irohad/consensus/yac/CMakeLists.txt | 2 + .../yac/supermajority_checker_test.cpp | 42 +++++++++++++++++++ 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/shared_model/interfaces/common_objects/signable_hash.hpp b/shared_model/interfaces/common_objects/signable_hash.hpp index 40c091533b..da16dd7cc4 100644 --- a/shared_model/interfaces/common_objects/signable_hash.hpp +++ b/shared_model/interfaces/common_objects/signable_hash.hpp @@ -18,7 +18,6 @@ #ifndef IROHA_SHARED_MODEL_SIGNABLE_HASH_HPP #define IROHA_SHARED_MODEL_SIGNABLE_HASH_HPP -#include #include #include "interfaces/common_objects/signature.hpp" @@ -28,23 +27,28 @@ namespace shared_model { namespace interface { /** - * Hash class for SigWrapper type. It's required since std::unordered_set - * uses hash inside and it should be declared explicitly for user-defined - * types. + * Property class for SignatureSetType that contains hashing and comparison + * operations. */ - class SignableHash { + class SignatureSetTypeOps { public: /** - * Operator which actually calculates hash. Uses boost::hash_combine to - * calculate hash from several fields. - * @param sig - item to find hash from - * @return calculated hash + * @param sig is item to find hash from + * @return calculated hash of public key */ size_t operator()(const types::SignatureType &sig) const { - std::size_t seed = 0; - boost::hash_combine(seed, sig->publicKey().blob()); - boost::hash_combine(seed, sig->signedData().blob()); - return seed; + return std::hash{}(sig->publicKey().hex()); + } + + /** + * Function for set elements uniqueness by public key + * @param lhs + * @param rhs + * @return true, if public keys are the same + */ + bool operator()(const types::SignatureType &lhs, + const types::SignatureType &rhs) const { + return lhs->publicKey() == rhs->publicKey(); } }; /** @@ -54,8 +58,9 @@ namespace shared_model { * limitations: it requires to have write access for elements for some * internal operations. */ - using SignatureSetType = - std::unordered_set; + using SignatureSetType = std::unordered_set; } // namespace interface } // namespace shared_model diff --git a/test/module/irohad/consensus/yac/CMakeLists.txt b/test/module/irohad/consensus/yac/CMakeLists.txt index d216caa87a..3cf40ea7c0 100644 --- a/test/module/irohad/consensus/yac/CMakeLists.txt +++ b/test/module/irohad/consensus/yac/CMakeLists.txt @@ -102,4 +102,6 @@ target_link_libraries(yac_crypto_provider_test addtest(supermajority_checker_test supermajority_checker_test.cpp) target_link_libraries(supermajority_checker_test yac + shared_model_cryptography + shared_model_stateless_validation ) diff --git a/test/module/irohad/consensus/yac/supermajority_checker_test.cpp b/test/module/irohad/consensus/yac/supermajority_checker_test.cpp index 4ff61d4624..1714cb3c90 100644 --- a/test/module/irohad/consensus/yac/supermajority_checker_test.cpp +++ b/test/module/irohad/consensus/yac/supermajority_checker_test.cpp @@ -17,7 +17,14 @@ #include +#include "backend/protobuf/common_objects/signature.hpp" +#include "builders/protobuf/common_objects/proto_peer_builder.hpp" +#include "builders/protobuf/common_objects/proto_signature_builder.hpp" #include "consensus/yac/impl/supermajority_checker_impl.hpp" +#include "cryptography/public_key.hpp" +#include "cryptography/signed.hpp" +#include "interfaces/common_objects/peer.hpp" +#include "interfaces/common_objects/types.hpp" #include "logger/logger.hpp" using namespace iroha::consensus::yac; @@ -87,3 +94,38 @@ TEST_F(SupermajorityCheckerTest, RejectProofNegativeCase) { ASSERT_FALSE(hasReject(5, 6, 7)); ASSERT_FALSE(hasReject(6, 6, 7)); } + +/** + * @given a pair of peers and a pair different signatures by the first peer + * @when hasSupermajority is called + * @then it return false + */ +TEST_F(SupermajorityCheckerTest, PublicKeyUniqueness) { + using namespace shared_model::crypto; + std::vector> peers; + auto make_peer_key = [&peers](const std::string &key) { + PublicKey pub_key(key); + peers.emplace_back(clone(shared_model::proto::PeerBuilder() + .address("localhost") + .pubkey(pub_key) + .build())); + return pub_key; + }; + + auto peer_key = make_peer_key(std::string(32, '0')); + make_peer_key(std::string(32, '1')); + + auto make_sig = [](const PublicKey &peer_key, const std::string &sig) { + return shared_model::interface::types::SignatureType( + std::static_pointer_cast( + std::make_shared( + shared_model::proto::SignatureBuilder() + .publicKey(peer_key) + .signedData(Signed(sig)) + .build()))); + }; + shared_model::interface::SignatureSetType signatures{make_sig(peer_key, "1"), + make_sig(peer_key, "2")}; + + ASSERT_FALSE(hasSupermajority(signatures, peers)); +} From cedecbbf4f0c0242c59c8bd8f079c27dd390997a Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Thu, 26 Apr 2018 21:09:54 +0300 Subject: [PATCH 065/110] Fix artifacts uploading (#1262) * Fix aritfacts uploading Signed-off-by: Artyom Bakhtin * Fix comment Signed-off-by: Artyom Bakhtin --- .jenkinsci/debug-build.groovy | 5 +---- .jenkinsci/mac-release-build.groovy | 1 + .jenkinsci/release-build.groovy | 7 ++++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index c340ad429e..67b03a09c4 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -32,8 +32,7 @@ def doDebugBuild(coverageEnabled=false) { + " -e IROHA_POSTGRES_USER=${env.IROHA_POSTGRES_USER}" + " -e IROHA_POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" + " --network=${env.IROHA_NETWORK}" - + " -v /var/jenkins/ccache:${CCACHE_DIR}" - + " -v /tmp/${GIT_COMMIT}-${BUILD_NUMBER}:/tmp/${GIT_COMMIT}") { + + " -v /var/jenkins/ccache:${CCACHE_DIR}") { def scmVars = checkout scm def cmakeOptions = "" @@ -88,8 +87,6 @@ def doDebugBuild(coverageEnabled=false) { sh "python /tmp/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false } - // copy built binaries to the volume - sh "cp ./build/bin/* /tmp/${GIT_COMMIT}/" } } diff --git a/.jenkinsci/mac-release-build.groovy b/.jenkinsci/mac-release-build.groovy index b799e19200..bcc58c989a 100644 --- a/.jenkinsci/mac-release-build.groovy +++ b/.jenkinsci/mac-release-build.groovy @@ -20,6 +20,7 @@ def doReleaseBuild(coverageEnabled=false) { -DCMAKE_BUILD_TYPE=Release \ -DIROHA_VERSION=${env.IROHA_VERSION} + mv ./build/iroha-${env.IROHA_VERSION}-*.tar.gz ./build/iroha.tar.gz cmake --build build --target package -- -j${params.PARALLELISM} ccache --show-stats """ diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index 9a2a3d6e50..8daf3ae5f1 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -45,13 +45,14 @@ def doReleaseBuild() { sh "cmake --build build --target package -- -j${parallelism}" sh "ccache --show-stats" - // copy build package to the volume - sh "cp ./build/iroha-*.deb /tmp/${GIT_COMMIT}/iroha.deb" + // move build package to the volume + sh "mv ./build/iroha-*.deb /tmp/${GIT_COMMIT}/iroha.deb" + sh "mv ./build/*.tar.gz /tmp/${GIT_COMMIT}/iroha.tar.gz" } sh "curl -L -o /tmp/${env.GIT_COMMIT}/Dockerfile --create-dirs https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/release/${platform}/Dockerfile" sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/release/${platform}/entrypoint.sh" - sh "cp /tmp/${GIT_COMMIT}-${BUILD_NUMBER}/iroha.deb /tmp/${env.GIT_COMMIT}" + sh "mv /tmp/${GIT_COMMIT}-${BUILD_NUMBER}/iroha.deb /tmp/${env.GIT_COMMIT}" sh "chmod +x /tmp/${env.GIT_COMMIT}/entrypoint.sh" iCRelease = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}-release", "--no-cache -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { From 4fd8c6931e45af489a8e5bf51f367962af8a3f21 Mon Sep 17 00:00:00 2001 From: luckychess Date: Thu, 26 Apr 2018 22:54:20 +0300 Subject: [PATCH 066/110] Tests for ordering service (#1206): - Test for concurrent proposal generation - Ordering service destructor test - Fix member variables naming - Fix ordering servcice logger initialization Signed-off-by: luckychess --- .../irohad/ordering/ordering_service_test.cpp | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/test/module/irohad/ordering/ordering_service_test.cpp b/test/module/irohad/ordering/ordering_service_test.cpp index bd0f6400f7..f34857ef58 100644 --- a/test/module/irohad/ordering/ordering_service_test.cpp +++ b/test/module/irohad/ordering/ordering_service_test.cpp @@ -177,7 +177,6 @@ TEST_F(OrderingServiceTest, ValidWhenProposalSizeStrategy) { TEST_F(OrderingServiceTest, ValidWhenTimerStrategy) { // Init => proposal timer 400 ms => 10 tx by 50 ms => 2 proposals in 1 second - EXPECT_CALL(*fake_persistent_state, saveProposalHeight(_)) .Times(2) .WillRepeatedly(Return(true)); @@ -239,3 +238,77 @@ TEST_F(OrderingServiceTest, BrokenPersistentState) { std::unique_lock lk(m); cv.wait_for(lk, 2s); } + +/** + * @given Ordering service up and running + * @when Send 1000 transactions from each of 2 threads + * @then Ordering service should not crash + */ +TEST_F(OrderingServiceTest, ConcurrentGenerateProposal) { + const auto max_proposal = 1; + const auto commit_delay = 100; + EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) + .Times(1) + .WillOnce(Return(boost::optional(1))); + EXPECT_CALL(*fake_persistent_state, saveProposalHeight(_)) + .WillRepeatedly(Return(false)); + + auto ordering_service = std::make_shared( + wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + + auto on_tx = [&]() { + for (int i = 0; i < 1000; ++i) { + ordering_service->onTransaction(getTx()); + } + }; + + const auto num_threads = 2; + + std::vector threads; + for (int i = 0; i < num_threads; ++i) { + threads.emplace_back(std::thread(on_tx)); + } + + for (int i = 0; i < num_threads; ++i) { + threads.at(i).join(); + } +} + +/** + * @given Ordering service up and running + * @when Send 1000 transactions from a separate thread and perform 5 second + * delay during generateProposal() so destructor of OrderingServiceImpl is + * called before generateProposal() finished + * @then Ordering service should not crash and publishProposal() should not be + * called after destructor call + */ +TEST_F(OrderingServiceTest, GenerateProposalDestructor) { + const auto max_proposal = 100000; + const auto commit_delay = 100; + EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) + .Times(1) + .WillOnce(Return(boost::optional(1))); + EXPECT_CALL(*fake_persistent_state, saveProposalHeight(_)) + .WillRepeatedly(InvokeWithoutArgs([] { + std::this_thread::sleep_for(5s); + return true; + })); + EXPECT_CALL(*wsv, getLedgerPeers()) + .WillRepeatedly(Return(std::vector{peer})); + + { + EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(AtLeast(1)); + OrderingServiceImpl ordering_service( + wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + + auto on_tx = [&]() { + for (int i = 0; i < 1000; ++i) { + ordering_service.onTransaction(getTx()); + } + }; + + std::thread thread(on_tx); + thread.join(); + } + EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(0); +} From 3ed25d74edebb35df0da4b76063637a1de5906dc Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Fri, 27 Apr 2018 10:56:09 +0300 Subject: [PATCH 067/110] fix mac release build (#1278) Signed-off-by: Artyom Bakhtin --- .jenkinsci/mac-release-build.groovy | 4 ++-- Jenkinsfile | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.jenkinsci/mac-release-build.groovy b/.jenkinsci/mac-release-build.groovy index bcc58c989a..02125d2632 100644 --- a/.jenkinsci/mac-release-build.groovy +++ b/.jenkinsci/mac-release-build.groovy @@ -19,9 +19,9 @@ def doReleaseBuild(coverageEnabled=false) { -DPACKAGE_TGZ=ON \ -DCMAKE_BUILD_TYPE=Release \ -DIROHA_VERSION=${env.IROHA_VERSION} - - mv ./build/iroha-${env.IROHA_VERSION}-*.tar.gz ./build/iroha.tar.gz + cmake --build build --target package -- -j${params.PARALLELISM} + mv ./build/iroha-${env.IROHA_VERSION}-*.tar.gz ./build/iroha.tar.gz ccache --show-stats """ } diff --git a/Jenkinsfile b/Jenkinsfile index 39ac57b250..9f08b8cfdf 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -340,7 +340,8 @@ pipeline { } } stage('MacOS') { - when { expression { return params.MacOS } } + when { expression { return params.MacOS } } + agent { label 'mac' } steps { script { def releaseBuild = load ".jenkinsci/mac-release-build.groovy" From 3404b17969f5899698f5683831d636865cab1b55 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Sat, 28 Apr 2018 12:02:48 +0300 Subject: [PATCH 068/110] Improve Ordering Gate behavior on out of order commits and proposals (#1243) Previously ordering gate was not correctly handling proposals which would arrive before corresponding commits, and block height of the ledger was not used in deciding what to do with them. Also, there was a race condition on concurrent queue when someone was popping from the queue and another thread was accessing it, the proposal could be skipped by both threads. Now we have Rx based concurrency, where each new commit or proposal event is handled by separate thread, which processes them in order, and block height is stored inside event. This means that we minimize number of shared variables between different events. Signed-off-by: Nikita Alekseev --- irohad/main/application.cpp | 14 +- irohad/main/impl/ordering_init.cpp | 13 +- irohad/main/impl/ordering_init.hpp | 14 +- irohad/ordering/impl/ordering_gate_impl.cpp | 71 ++++-- irohad/ordering/impl/ordering_gate_impl.hpp | 34 ++- irohad/simulator/impl/simulator.cpp | 13 +- .../ordering/ordering_gate_service_test.cpp | 9 +- .../irohad/ordering/ordering_gate_test.cpp | 227 ++++++++++++------ 8 files changed, 274 insertions(+), 121 deletions(-) diff --git a/irohad/main/application.cpp b/irohad/main/application.cpp index b919553864..1fe494b299 100644 --- a/irohad/main/application.cpp +++ b/irohad/main/application.cpp @@ -157,8 +157,11 @@ void Irohad::initValidators() { * Initializing ordering gate */ void Irohad::initOrderingGate() { - ordering_gate = ordering_init.initOrderingGate( - wsv, max_proposal_size_, proposal_delay_, ordering_service_storage_); + ordering_gate = ordering_init.initOrderingGate(wsv, + max_proposal_size_, + proposal_delay_, + ordering_service_storage_, + storage->getBlockQuery()); log_->info("[Init] => init ordering gate - [{}]", logger::logBool(ordering_gate)); } @@ -190,12 +193,7 @@ void Irohad::initBlockLoader() { */ void Irohad::initConsensusGate() { consensus_gate = yac_init.initConsensusGate( - wsv, - simulator, - block_loader, - keypair, - vote_delay_, - load_delay_); + wsv, simulator, block_loader, keypair, vote_delay_, load_delay_); log_->info("[Init] => consensus gate"); } diff --git a/irohad/main/impl/ordering_init.cpp b/irohad/main/impl/ordering_init.cpp index 64bc56400c..4febfa2ad3 100644 --- a/irohad/main/impl/ordering_init.cpp +++ b/irohad/main/impl/ordering_init.cpp @@ -22,8 +22,12 @@ namespace iroha { namespace network { auto OrderingInit::createGate( - std::shared_ptr transport) { - auto gate = std::make_shared(transport); + std::shared_ptr transport, + std::shared_ptr block_query) { + auto height = block_query->getTopBlocks(1).as_blocking().last()->height(); + auto gate = + std::make_shared(transport, height); + log_->info("Creating Ordering Gate with initial height {}", height); transport->subscribe(gate); return gate; } @@ -48,7 +52,8 @@ namespace iroha { size_t max_size, std::chrono::milliseconds delay_milliseconds, std::shared_ptr - persistent_state) { + persistent_state, + std::shared_ptr block_query) { auto ledger_peers = wsv->getLedgerPeers(); if (not ledger_peers or ledger_peers.value().empty()) { log_->error( @@ -68,7 +73,7 @@ namespace iroha { ordering_service_transport, persistent_state); ordering_service_transport->subscribe(ordering_service); - ordering_gate = createGate(ordering_gate_transport); + ordering_gate = createGate(ordering_gate_transport, block_query); return ordering_gate; } } // namespace network diff --git a/irohad/main/impl/ordering_init.hpp b/irohad/main/impl/ordering_init.hpp index bd8828be1d..8149866bbd 100644 --- a/irohad/main/impl/ordering_init.hpp +++ b/irohad/main/impl/ordering_init.hpp @@ -18,6 +18,7 @@ #ifndef IROHA_ORDERING_INIT_HPP #define IROHA_ORDERING_INIT_HPP +#include "ametsuchi/block_query.hpp" #include "ametsuchi/peer_query.hpp" #include "logger/logger.hpp" #include "ordering/impl/ordering_gate_impl.hpp" @@ -41,9 +42,12 @@ namespace iroha { /** * Init effective realisation of ordering gate (client of ordering * service) - * @param network_address - address of ordering service + * @param transport - object which will be notified + * about incoming proposals and send transactions + * @param block_query - block store to get last block height */ - auto createGate(std::shared_ptr); + auto createGate(std::shared_ptr transport, + std::shared_ptr block_query); /** * Init ordering service @@ -67,14 +71,16 @@ namespace iroha { * @param loop - handler of async events * @param max_size - limitation of proposal size * @param delay_milliseconds - delay before emitting proposal - * @return effective realisation of OrderingGate + * @param block_query - block store to get last block height + * @return efficient implementation of OrderingGate */ std::shared_ptr initOrderingGate( std::shared_ptr wsv, size_t max_size, std::chrono::milliseconds delay_milliseconds, std::shared_ptr - persistent_state); + persistent_state, + std::shared_ptr block_query); std::shared_ptr ordering_service; std::shared_ptr ordering_gate; diff --git a/irohad/ordering/impl/ordering_gate_impl.cpp b/irohad/ordering/impl/ordering_gate_impl.cpp index 3770102227..1daf800f9d 100644 --- a/irohad/ordering/impl/ordering_gate_impl.cpp +++ b/irohad/ordering/impl/ordering_gate_impl.cpp @@ -15,10 +15,12 @@ * limitations under the License. */ +#include #include #include "ordering/impl/ordering_gate_impl.hpp" +#include "interfaces/iroha_internal/block.hpp" #include "interfaces/iroha_internal/proposal.hpp" #include "interfaces/transaction.hpp" @@ -32,8 +34,13 @@ namespace iroha { } OrderingGateImpl::OrderingGateImpl( - std::shared_ptr transport) - : transport_(std::move(transport)), log_(logger::log("OrderingGate")) {} + std::shared_ptr transport, + shared_model::interface::types::HeightType initial_height, + bool run_async) + : transport_(std::move(transport)), + last_block_height_(initial_height), + log_(logger::log("OrderingGate")), + run_async_(run_async) {} void OrderingGateImpl::propagateTransaction( std::shared_ptr @@ -51,27 +58,61 @@ namespace iroha { void OrderingGateImpl::setPcs( const iroha::network::PeerCommunicationService &pcs) { - pcs_subscriber_ = pcs.on_commit().subscribe([this](auto) { - // TODO: 05/03/2018 @muratovv rework behavior of queue with respect to - // block height IR-1042 - unlock_next_.store(true); - this->tryNextRound(); + log_->info("setPcs"); - }); + auto top_block_height = + pcs.on_commit() + .transform([](const Commit &commit) { + // find height of last commited block + return commit.as_blocking().last()->height(); + }) + .start_with(last_block_height_); + + auto subscribe = [&](auto merge_strategy) { + pcs_subscriber_ = merge_strategy(net_proposals_.get_observable()) + .subscribe([this](const auto &t) { + this->tryNextRound(std::get<1>(t)); + }); + }; + + if (run_async_) { + subscribe([&top_block_height](auto observable) { + return observable.combine_latest(rxcpp::synchronize_new_thread(), + top_block_height); + }); + } else { + subscribe([&top_block_height](auto observable) { + return observable.combine_latest(top_block_height); + }); + } } void OrderingGateImpl::onProposal( std::shared_ptr proposal) { - log_->info("Received new proposal"); + log_->info("Received new proposal, height: {}", proposal->height()); proposal_queue_.push(std::move(proposal)); - tryNextRound(); + std::lock_guard lock(proposal_mutex_); + net_proposals_.get_subscriber().on_next(0); } - void OrderingGateImpl::tryNextRound() { - if (not proposal_queue_.empty() and unlock_next_.exchange(false)) { - std::shared_ptr next_proposal; - proposal_queue_.try_pop(next_proposal); - log_->info("Pass the proposal to pipeline"); + void OrderingGateImpl::tryNextRound( + shared_model::interface::types::HeightType last_block_height) { + log_->debug("TryNextRound"); + std::shared_ptr next_proposal; + while (proposal_queue_.try_pop(next_proposal)) { + // check for old proposal + if (next_proposal->height() < last_block_height + 1) { + log_->debug("Old proposal, discarding"); + continue; + } + // check for new proposal + if (next_proposal->height() > last_block_height + 1) { + log_->debug("Proposal newer than last block, keeping in queue"); + proposal_queue_.push(next_proposal); + break; + } + log_->info("Pass the proposal to pipeline height {}", + next_proposal->height()); proposals_.get_subscriber().on_next(next_proposal); } } diff --git a/irohad/ordering/impl/ordering_gate_impl.hpp b/irohad/ordering/impl/ordering_gate_impl.hpp index a455160535..b00b9a770d 100644 --- a/irohad/ordering/impl/ordering_gate_impl.hpp +++ b/irohad/ordering/impl/ordering_gate_impl.hpp @@ -20,9 +20,11 @@ #include "network/ordering_gate.hpp" -#include +#include + #include +#include "interfaces/common_objects/types.hpp" #include "logger/logger.hpp" #include "network/impl/async_grpc_client.hpp" #include "network/ordering_gate_transport.hpp" @@ -55,8 +57,16 @@ namespace iroha { class OrderingGateImpl : public network::OrderingGate, public network::OrderingGateNotification { public: - explicit OrderingGateImpl( - std::shared_ptr transport); + /** + * @param transport - network communication layer + * @param initial_height - height of the last block stored on this peer + * @param run_async - whether proposals should be handled + * asynchronously (on separate thread). Default is true. + */ + OrderingGateImpl( + std::shared_ptr transport, + shared_model::interface::types::HeightType initial_height, + bool run_async = true); void propagateTransaction( std::shared_ptr @@ -75,16 +85,23 @@ namespace iroha { private: /** * Try to push proposal for next consensus round + * @param - last_block_height - what is the last block stored on this + * peer, or for which commit was received. If block is newer than + * currently stored proposals, proposals are discarded. If it is older, + * newer proposals are propagated in order */ - void tryNextRound(); + void tryNextRound( + shared_model::interface::types::HeightType last_block_height); rxcpp::subjects::subject< std::shared_ptr> proposals_; + + rxcpp::subjects::subject + net_proposals_; std::shared_ptr transport_; - /// invariant: true if proposal can be pushed to subscribers - std::atomic_bool unlock_next_{true}; + std::mutex proposal_mutex_; /// queue with all proposals received from ordering service tbb::concurrent_priority_queue< @@ -92,10 +109,15 @@ namespace iroha { ProposalComparator> proposal_queue_; + /// last commited block height + shared_model::interface::types::HeightType last_block_height_; + /// subscription of pcs::on_commit rxcpp::composite_subscription pcs_subscriber_; logger::Logger log_; + + bool run_async_; }; } // namespace ordering } // namespace iroha diff --git a/irohad/simulator/impl/simulator.cpp b/irohad/simulator/impl/simulator.cpp index 436bd0ccf6..6404589ffc 100644 --- a/irohad/simulator/impl/simulator.cpp +++ b/irohad/simulator/impl/simulator.cpp @@ -31,7 +31,8 @@ namespace iroha { std::shared_ptr statefulValidator, std::shared_ptr factory, std::shared_ptr blockQuery, - std::shared_ptr> crypto_signer) + std::shared_ptr> + crypto_signer) : validator_(std::move(statefulValidator)), ametsuchi_factory_(std::move(factory)), block_queries_(std::move(blockQuery)), @@ -65,8 +66,10 @@ namespace iroha { const shared_model::interface::Proposal &proposal) { log_->info("process proposal"); // Get last block from local ledger - block_queries_->getTopBlocks(1).as_blocking().subscribe( - [this](auto block) { last_block = block; }); + block_queries_->getTopBlocks(1) + .subscribe_on(rxcpp::observe_on_new_thread()) + .as_blocking() + .subscribe([this](auto block) { last_block = block; }); if (not last_block) { log_->warn("Could not fetch last block"); return; @@ -97,8 +100,8 @@ namespace iroha { const shared_model::interface::Proposal &proposal) { log_->info("process verified proposal"); - // TODO: Alexey Chernyshov IR-1011 2018-03-08 rework BlockBuilder logic, so - // that this cast will not be needed + // TODO: Alexey Chernyshov IR-1011 2018-03-08 rework BlockBuilder logic, + // so that this cast will not be needed auto proto_txs = proposal.transactions() | boost::adaptors::transformed([](const auto &polymorphic_tx) { diff --git a/test/module/irohad/ordering/ordering_gate_service_test.cpp b/test/module/irohad/ordering/ordering_gate_service_test.cpp index f4212109ec..147b8bcb05 100644 --- a/test/module/irohad/ordering/ordering_gate_service_test.cpp +++ b/test/module/irohad/ordering/ordering_gate_service_test.cpp @@ -54,7 +54,7 @@ class OrderingGateServiceTest : public ::testing::Test { EXPECT_CALL(*pcs_, on_commit()) .WillRepeatedly(Return(commit_subject_.get_observable())); gate_transport = std::make_shared(address); - gate = std::make_shared(gate_transport); + gate = std::make_shared(gate_transport, 1, false); gate->setPcs(*pcs_); gate_transport->subscribe(gate); @@ -110,14 +110,14 @@ class OrderingGateServiceTest : public ::testing::Test { }); gate->on_proposal().subscribe([this](auto proposal) { proposals.push_back(proposal); - // emulate commit event after receiving the proposal to perform next // round inside the peer. std::shared_ptr block = std::make_shared( - TestBlockBuilder().build()); + TestBlockBuilder().height(proposal->height()).build()); commit_subject_.get_subscriber().on_next( rxcpp::observable<>::just(block)); + }); wrapper.subscribe(); return wrapper; @@ -136,8 +136,7 @@ class OrderingGateServiceTest : public ::testing::Test { .build() .signAndAddSignature( shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair()) - ); + generateKeypair())); gate->propagateTransaction(tx); // otherwise tx may come unordered std::this_thread::sleep_for(20ms); diff --git a/test/module/irohad/ordering/ordering_gate_test.cpp b/test/module/irohad/ordering/ordering_gate_test.cpp index d34f2d3c18..5e3036e69b 100644 --- a/test/module/irohad/ordering/ordering_gate_test.cpp +++ b/test/module/irohad/ordering/ordering_gate_test.cpp @@ -38,6 +38,8 @@ using ::testing::_; using ::testing::InvokeWithoutArgs; using ::testing::Return; +using shared_model::interface::types::HeightType; + class MockOrderingGateTransportGrpcService : public proto::OrderingServiceTransportGrpc::Service { public: @@ -61,36 +63,26 @@ class OrderingGateTest : public ::testing::Test { } void SetUp() override { - thread = std::thread([this] { - grpc::ServerBuilder builder; - int port = 0; - builder.AddListeningPort( - "0.0.0.0:0", grpc::InsecureServerCredentials(), &port); - - builder.RegisterService(fake_service.get()); - - server = builder.BuildAndStart(); - auto address = "0.0.0.0:" + std::to_string(port); - // Initialize components after port has been bind - transport = std::make_shared(address); - gate_impl = std::make_shared(transport); - transport->subscribe(gate_impl); - - ASSERT_NE(port, 0); - ASSERT_TRUE(server); - cv.notify_one(); - server->Wait(); - }); - - std::unique_lock lock(m); - cv.wait_for(lock, std::chrono::seconds(1)); + grpc::ServerBuilder builder; + int port = 0; + builder.AddListeningPort( + "0.0.0.0:0", grpc::InsecureServerCredentials(), &port); + + builder.RegisterService(fake_service.get()); + + server = builder.BuildAndStart(); + auto address = "0.0.0.0:" + std::to_string(port); + // Initialize components after port has been bind + transport = std::make_shared(address); + gate_impl = std::make_shared(transport, 1, false); + transport->subscribe(gate_impl); + + ASSERT_NE(port, 0); + ASSERT_TRUE(server); } void TearDown() override { server->Shutdown(); - if (thread.joinable()) { - thread.join(); - } } std::unique_ptr server; @@ -98,7 +90,6 @@ class OrderingGateTest : public ::testing::Test { std::shared_ptr transport; std::shared_ptr gate_impl; std::shared_ptr fake_service; - std::thread thread; std::condition_variable cv; std::mutex m; }; @@ -137,6 +128,12 @@ TEST_F(OrderingGateTest, ProposalReceivedByGateWhenSent) { auto wrapper = make_test_subscriber(gate_impl->on_proposal(), 1); wrapper.subscribe(); + auto pcs = std::make_shared(); + rxcpp::subjects::subject commit_subject; + EXPECT_CALL(*pcs, on_commit()) + .WillOnce(Return(commit_subject.get_observable())); + gate_impl->setPcs(*pcs); + grpc::ServerContext context; auto tx = shared_model::proto::TransactionBuilder() .createdTime(iroha::time::now()) @@ -161,6 +158,40 @@ TEST_F(OrderingGateTest, ProposalReceivedByGateWhenSent) { ASSERT_TRUE(wrapper.validate()); } +class QueueBehaviorTest : public ::testing::Test { + public: + QueueBehaviorTest() : ordering_gate(transport, 1, false){}; + + void SetUp() override { + transport = std::make_shared(); + pcs = std::make_shared(); + EXPECT_CALL(*pcs, on_commit()) + .WillOnce(Return(commit_subject.get_observable())); + + ordering_gate.setPcs(*pcs); + ordering_gate.on_proposal().subscribe( + [&](auto val) { messages.push_back(val); }); + } + + std::shared_ptr transport; + std::shared_ptr pcs; + rxcpp::subjects::subject commit_subject; + OrderingGateImpl ordering_gate; + std::vector messages; + + void pushCommit(HeightType height) { + commit_subject.get_subscriber().on_next(rxcpp::observable<>::just( + std::static_pointer_cast( + std::make_shared( + TestBlockBuilder().height(height).build())))); + } + + void pushProposal(HeightType height) { + ordering_gate.onProposal(std::make_shared( + TestProposalBuilder().height(height).build())); + }; +}; + /** * @given Initialized OrderingGate * AND MockPeerCommunicationService @@ -168,19 +199,7 @@ TEST_F(OrderingGateTest, ProposalReceivedByGateWhenSent) { * AND one commit in node * @then Check that send round appears after commit */ -TEST(OrderingGateQueueBehaviour, SendManyProposals) { - std::shared_ptr transport = - std::make_shared(); - - std::shared_ptr pcs = - std::make_shared(); - rxcpp::subjects::subject commit_subject; - EXPECT_CALL(*pcs, on_commit()) - .WillOnce(Return(commit_subject.get_observable())); - - OrderingGateImpl ordering_gate(transport); - ordering_gate.setPcs(*pcs); - +TEST_F(QueueBehaviorTest, SendManyProposals) { auto wrapper_before = make_test_subscriber(ordering_gate.on_proposal(), 1); wrapper_before.subscribe(); @@ -205,7 +224,7 @@ TEST(OrderingGateQueueBehaviour, SendManyProposals) { .build()); auto proposal2 = std::make_shared( shared_model::proto::ProposalBuilder() - .height(2) + .height(3) .createdTime(iroha::time::now()) .transactions(txs) .build()); @@ -216,7 +235,8 @@ TEST(OrderingGateQueueBehaviour, SendManyProposals) { ASSERT_TRUE(wrapper_before.validate()); std::shared_ptr block = - std::make_shared(TestBlockBuilder().build()); + std::make_shared( + TestBlockBuilder().height(2).build()); commit_subject.get_subscriber().on_next(rxcpp::observable<>::just(block)); @@ -229,47 +249,106 @@ TEST(OrderingGateQueueBehaviour, SendManyProposals) { * @when Receive proposals in random order * @then on_proposal output is ordered */ -TEST(OrderingGateQueueBehaviour, ReceiveUnordered) { - std::shared_ptr transport = - std::make_shared(); +TEST_F(QueueBehaviorTest, ReceiveUnordered) { + // this will set unlock_next_ to false, so proposals 3 and 4 are enqueued + pushProposal(2); - std::shared_ptr pcs = - std::make_shared(); - rxcpp::subjects::subject commit_subject; - EXPECT_CALL(*pcs, on_commit()) - .WillOnce(Return(commit_subject.get_observable())); + pushProposal(4); + pushProposal(3); - auto pushCommit = [&] { - commit_subject.get_subscriber().on_next(rxcpp::observable<>::just( - std::static_pointer_cast( - std::make_shared( - TestBlockBuilder().build())))); - }; + pushCommit(2); + pushCommit(3); - OrderingGateImpl ordering_gate(transport); - ordering_gate.setPcs(*pcs); + ASSERT_EQ(3, messages.size()); + ASSERT_EQ(2, messages.at(0)->height()); + ASSERT_EQ(3, messages.at(1)->height()); + ASSERT_EQ(4, messages.at(2)->height()); +} - auto pushProposal = [&](auto height) { - ordering_gate.onProposal(std::make_shared( - TestProposalBuilder().height(height).build())); - }; +/** + * @given Initialized OrderingGate + * AND MockPeerCommunicationService + * @when Receive commits which are newer than existing proposals + * @then on_proposal is not invoked on proposals + * which are older than last committed block + */ +TEST_F(QueueBehaviorTest, DiscardOldProposals) { + pushProposal(2); + pushProposal(3); - std::vector messages; - ordering_gate.on_proposal().subscribe([&](auto val) { - messages.push_back(val); - }); + pushProposal(4); + pushProposal(5); + pushCommit(4); - // this will set unlock_next_ to false, so proposals 4 and 3 are enqueued - pushProposal(2); + // proposals 2 and 3 must not be forwarded down the pipeline. + EXPECT_EQ(2, messages.size()); + ASSERT_EQ(2, messages.at(0)->height()); + ASSERT_EQ(5, messages.at(1)->height()); +} +/** + * @given Initialized OrderingGate + * AND MockPeerCommunicationService + * @when Proposals are newer than received commits + * @then newer proposals are kept in queue + */ +TEST_F(QueueBehaviorTest, KeepNewerProposals) { + pushProposal(2); + pushProposal(3); pushProposal(4); + + pushCommit(2); + + // proposal 3 must be forwarded down the pipeline, 4 kept in queue. + EXPECT_EQ(2, messages.size()); + EXPECT_EQ(2, messages.at(0)->height()); + EXPECT_EQ(3, messages.at(1)->height()); + + pushCommit(3); + // Now proposal 4 is forwarded to the pipeline + EXPECT_EQ(3, messages.size()); + EXPECT_EQ(4, messages.at(2)->height()); +} + +/** + * @given Initialized OrderingGate + * AND MockPeerCommunicationService + * @when commit is received before any proposals + * @then old proposals are discarded and new is propagated + */ +TEST_F(QueueBehaviorTest, CommitBeforeProposal) { + pushCommit(4); + + // Old proposals should be discarded + pushProposal(2); pushProposal(3); + pushProposal(4); - pushCommit(); - pushCommit(); + EXPECT_EQ(0, messages.size()); - ASSERT_EQ(3, messages.size()); - ASSERT_EQ(2, messages.at(0)->height()); - ASSERT_EQ(3, messages.at(1)->height()); - ASSERT_EQ(4, messages.at(2)->height()); + // should be propagated + pushProposal(5); + + // should not be propagated + pushProposal(6); + + EXPECT_EQ(1, messages.size()); + EXPECT_EQ(5, messages.at(0)->height()); +} + +/** + * @given Initialized OrderingGate + * AND MockPeerCommunicationService + * @when commit is received which newer than all proposals + * @then all proposals are discarded and none are propagated + */ +TEST_F(QueueBehaviorTest, CommitNewerThanAllProposals) { + pushProposal(2); + // Old proposals should be discarded + pushProposal(3); + pushProposal(4); + + pushCommit(4); + EXPECT_EQ(1, messages.size()); + EXPECT_EQ(2, messages.at(0)->height()); } From 71ec6709505007edb681d4577dc0643e3a0892e8 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Sun, 29 Apr 2018 12:37:15 +0300 Subject: [PATCH 069/110] CI fixes (#1282) * Rework Docker images naming scheme Signed-off-by: Artyom Bakhtin * fix docker pull Signed-off-by: Artyom Bakhtin * missing bracket Signed-off-by: Artyom Bakhtin --- .jenkinsci/debug-build.groovy | 124 ++++---- .jenkinsci/docker-pull-or-build.groovy | 13 +- .jenkinsci/linux-post-step.groovy | 4 +- .jenkinsci/release-build.groovy | 8 +- .jenkinsci/selected-branches-coverage.groovy | 4 +- Jenkinsfile | 77 ++--- .../iroha-standalone-nodes/iroha-deploy.yml | 2 +- docker/develop/{aarch64 => }/Dockerfile | 0 docker/develop/armv7l/Dockerfile | 283 ------------------ docker/develop/x86_64/Dockerfile | 283 ------------------ docker/docker-compose.yml | 38 ++- docker/manifest.yaml | 28 +- docker/release/{aarch64 => }/Dockerfile | 0 docker/release/armv7l/Dockerfile | 15 - docker/release/armv7l/entrypoint.sh | 4 - docker/release/{aarch64 => }/entrypoint.sh | 0 docker/release/x86_64/Dockerfile | 15 - docker/release/x86_64/entrypoint.sh | 4 - 18 files changed, 144 insertions(+), 758 deletions(-) rename docker/develop/{aarch64 => }/Dockerfile (100%) delete mode 100644 docker/develop/armv7l/Dockerfile delete mode 100644 docker/develop/x86_64/Dockerfile rename docker/release/{aarch64 => }/Dockerfile (100%) delete mode 100644 docker/release/armv7l/Dockerfile delete mode 100755 docker/release/armv7l/entrypoint.sh rename docker/release/{aarch64 => }/entrypoint.sh (100%) delete mode 100644 docker/release/x86_64/Dockerfile delete mode 100755 docker/release/x86_64/entrypoint.sh diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index 67b03a09c4..4de8d28592 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -15,74 +15,74 @@ def doDebugBuild(coverageEnabled=false) { parallelism = 1 } sh "docker network create ${env.IROHA_NETWORK}" - - docker.image('postgres:9.5').run("" + def iC = dPullOrBuild.dockerPullOrUpdate("${platform}-develop-build", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", + ['PARALLELISM': parallelism]) + docker.image('postgres:9.5').withRun("" + " -e POSTGRES_USER=${env.IROHA_POSTGRES_USER}" + " -e POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" + " --name ${env.IROHA_POSTGRES_HOST}" - + " --network=${env.IROHA_NETWORK}") - def iC = dPullOrBuild.dockerPullOrUpdate("${platform}-develop", - "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile", - "${env.GIT_RAW_BASE_URL}/develop/docker/develop/${platform}/Dockerfile", - ['PARALLELISM': params.PARALLELISM]) - iC.inside("" - + " -e IROHA_POSTGRES_HOST=${env.IROHA_POSTGRES_HOST}" - + " -e IROHA_POSTGRES_PORT=${env.IROHA_POSTGRES_PORT}" - + " -e IROHA_POSTGRES_USER=${env.IROHA_POSTGRES_USER}" - + " -e IROHA_POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" - + " --network=${env.IROHA_NETWORK}" - + " -v /var/jenkins/ccache:${CCACHE_DIR}") { - - def scmVars = checkout scm - def cmakeOptions = "" - if ( coverageEnabled ) { - cmakeOptions = " -DCOVERAGE=ON " - } - env.IROHA_VERSION = "0x${scmVars.GIT_COMMIT}" - env.IROHA_HOME = "/opt/iroha" - env.IROHA_BUILD = "${env.IROHA_HOME}/build" + + " --network=${env.IROHA_NETWORK}") { + iC.inside("" + + " -e IROHA_POSTGRES_HOST=${env.IROHA_POSTGRES_HOST}" + + " -e IROHA_POSTGRES_PORT=${env.IROHA_POSTGRES_PORT}" + + " -e IROHA_POSTGRES_USER=${env.IROHA_POSTGRES_USER}" + + " -e IROHA_POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" + + " --network=${env.IROHA_NETWORK}" + + " -v /var/jenkins/ccache:${CCACHE_DIR}" + + " -v /tmp/${GIT_COMMIT}-${BUILD_NUMBER}:/tmp/${GIT_COMMIT}") { - sh """ - ccache --version - ccache --show-stats - ccache --zero-stats - ccache --max-size=5G - """ - sh """ - cmake \ - -DTESTING=ON \ - -H. \ - -Bbuild \ - -DCMAKE_BUILD_TYPE=Debug \ - -DIROHA_VERSION=${env.IROHA_VERSION} \ - ${cmakeOptions} - """ - sh "cmake --build build -- -j${parallelism}" - sh "ccache --show-stats" - if ( coverageEnabled ) { - sh "cmake --build build --target coverage.init.info" - } - def testExitCode = sh(script: 'cmake --build build --target test', returnStatus: true) - if (testExitCode != 0) { - currentBuild.result = "UNSTABLE" - } - if ( coverageEnabled ) { - sh "cmake --build build --target cppcheck" - // Sonar - if (env.CHANGE_ID != null) { - sh """ - sonar-scanner \ - -Dsonar.github.disableInlineComments \ - -Dsonar.github.repository='hyperledger/iroha' \ - -Dsonar.analysis.mode=preview \ - -Dsonar.login=${SONAR_TOKEN} \ - -Dsonar.projectVersion=${BUILD_TAG} \ - -Dsonar.github.oauth=${SORABOT_TOKEN} \ - -Dsonar.github.pullRequest=${CHANGE_ID} - """ + def scmVars = checkout scm + def cmakeOptions = "" + if ( coverageEnabled ) { + cmakeOptions = " -DCOVERAGE=ON " } + env.IROHA_VERSION = "0x${scmVars.GIT_COMMIT}" + env.IROHA_HOME = "/opt/iroha" + env.IROHA_BUILD = "${env.IROHA_HOME}/build" + sh """ + ccache --version + ccache --show-stats + ccache --zero-stats + ccache --max-size=5G + """ + sh """ + cmake \ + -DTESTING=ON \ + -H. \ + -Bbuild \ + -DCMAKE_BUILD_TYPE=Debug \ + -DIROHA_VERSION=${env.IROHA_VERSION} \ + ${cmakeOptions} + """ + sh "cmake --build build -- -j${parallelism}" + sh "ccache --show-stats" + if ( coverageEnabled ) { + sh "cmake --build build --target coverage.init.info" + } + def testExitCode = sh(script: 'CTEST_OUTPUT_ON_FAILURE=1 cmake --build build --target test', returnStatus: true) + if (testExitCode != 0) { + currentBuild.result = "UNSTABLE" + } + if ( coverageEnabled ) { + sh "cmake --build build --target cppcheck" + // Sonar + if (env.CHANGE_ID != null) { + sh """ + sonar-scanner \ + -Dsonar.github.disableInlineComments \ + -Dsonar.github.repository='hyperledger/iroha' \ + -Dsonar.analysis.mode=preview \ + -Dsonar.login=${SONAR_TOKEN} \ + -Dsonar.projectVersion=${BUILD_TAG} \ + -Dsonar.github.oauth=${SORABOT_TOKEN} \ + -Dsonar.github.pullRequest=${CHANGE_ID} + """ + } + } sh "cmake --build build --target coverage.info" sh "python /tmp/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false diff --git a/.jenkinsci/docker-pull-or-build.groovy b/.jenkinsci/docker-pull-or-build.groovy index 86e78c9a11..ac8f57ccf3 100644 --- a/.jenkinsci/docker-pull-or-build.groovy +++ b/.jenkinsci/docker-pull-or-build.groovy @@ -4,10 +4,7 @@ def remoteFilesDiffer(f1, f2) { sh "curl -L -o /tmp/${env.GIT_COMMIT}/f1 --create-dirs ${f1}" sh "curl -L -o /tmp/${env.GIT_COMMIT}/f2 ${f2}" diffExitCode = sh(script: "diff -q /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}/f2", returnStatus: true) - if (diffExitCode == 0) { - return false - } - return true + return diffExitCode != 0 } def buildOptionsString(options) { @@ -22,7 +19,11 @@ def buildOptionsString(options) { def dockerPullOrUpdate(imageName, currentDockerfileURL, previousDockerfileURL, referenceDockerfileURL, buildOptions=null) { buildOptions = buildOptionsString(buildOptions) - def commit = sh(script: "echo ${BRANCH_NAME} | md5sum | cut -c 1-8", returnStdout: true).trim() + // GIT_PREVIOUS_COMMIT is null for first PR build + if (!previousDockerfileURL) { + previousDockerfileURL = currentDockerfileURL + } + def commit = sh(script: "echo ${GIT_LOCAL_BRANCH} | md5sum | cut -c 1-8", returnStdout: true).trim() if (remoteFilesDiffer(currentDockerfileURL, previousDockerfileURL)) { // Dockerfile has been changed compared to the previous commit // Worst case scenario. We cannot count on the local cache @@ -49,7 +50,7 @@ def dockerPullOrUpdate(imageName, currentDockerfileURL, previousDockerfileURL, r } } } - if (BRANCH_NAME ==~ /develop|master/) { + if (GIT_LOCAL_BRANCH ==~ /develop|master/) { docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { iC.push(imageName) } diff --git a/.jenkinsci/linux-post-step.groovy b/.jenkinsci/linux-post-step.groovy index 3d27278b8d..2cd92a675b 100644 --- a/.jenkinsci/linux-post-step.groovy +++ b/.jenkinsci/linux-post-step.groovy @@ -1,12 +1,12 @@ def linuxPostStep() { timeout(time: 600, unit: "SECONDS") { try { - if (currentBuild.currentResult == "SUCCESS" && BRANCH_NAME ==~ /(master|develop)/) { + if (currentBuild.currentResult == "SUCCESS" && GIT_LOCAL_BRANCH ==~ /(master|develop)/) { def artifacts = load ".jenkinsci/artifacts.groovy" def commit = env.GIT_COMMIT def platform = sh(script: 'uname -m', returnStdout: true).trim() filePaths = [ '/tmp/${GIT_COMMIT}-${BUILD_NUMBER}/*' ] - artifacts.uploadArtifacts(filePaths, sprintf('/iroha/linux/%4$s/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6), platform])) + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/linux/%4$s/%1$s-%2$s-%3$s', [GIT_LOCAL_BRANCH, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6), platform])) } } finally { diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index 8daf3ae5f1..54e0ca5031 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -14,7 +14,7 @@ def doReleaseBuild() { } def platform = sh(script: 'uname -m', returnStdout: true).trim() sh "mkdir /tmp/${env.GIT_COMMIT}-${BUILD_NUMBER} || true" - iC = docker.image("hyperledger/iroha:${platform}-develop") + iC = docker.image("hyperledger/iroha:${platform}-develop-build") iC.pull() iC.inside("" + " -v /tmp/${GIT_COMMIT}-${BUILD_NUMBER}:/tmp/${GIT_COMMIT}" @@ -56,10 +56,10 @@ def doReleaseBuild() { sh "chmod +x /tmp/${env.GIT_COMMIT}/entrypoint.sh" iCRelease = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}-release", "--no-cache -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { - if (env.BRANCH_NAME == 'develop') { - iCRelease.push("${platform}-develop-latest") + if (env.GIT_LOCAL_BRANCH == 'develop') { + iCRelease.push("${platform}-develop") } - else if (env.BRANCH_NAME == 'master') { + else if (env.GIT_LOCAL_BRANCH == 'master') { iCRelease.push("${platform}-latest") } } diff --git a/.jenkinsci/selected-branches-coverage.groovy b/.jenkinsci/selected-branches-coverage.groovy index dce5d5ae70..1dd04792dd 100644 --- a/.jenkinsci/selected-branches-coverage.groovy +++ b/.jenkinsci/selected-branches-coverage.groovy @@ -3,10 +3,10 @@ def selectedBranchesCoverage(branches, PRCoverage=true) { // trigger coverage if branch is either develop or master, or it is a PR if (PRCoverage) { - return env.BRANCH_NAME in branches || env.CHANGE_ID != null + return env.GIT_LOCAL_BRANCH in branches || env.CHANGE_ID != null } else { - return env.BRANCH_NAME in branches + return env.GIT_LOCAL_BRANCH in branches } } diff --git a/Jenkinsfile b/Jenkinsfile index 9f08b8cfdf..6cdc884c7c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -16,7 +16,6 @@ properties([parameters([ booleanParam(defaultValue: false, description: '', name: 'ARMv7'), booleanParam(defaultValue: false, description: '', name: 'ARMv8'), booleanParam(defaultValue: true, description: '', name: 'MacOS'), - booleanParam(defaultValue: false, description: 'Whether it is a triggered build', name: 'Nightly'), booleanParam(defaultValue: false, description: 'Whether build docs or not', name: 'Doxygen'), booleanParam(defaultValue: false, description: 'Whether build Java bindings', name: 'JavaBindings'), choice(choices: 'Release\nDebug', description: 'Java Bindings Build Type', name: 'JBBuildType'), @@ -36,10 +35,6 @@ pipeline { CCACHE_RELEASE_DIR = '/opt/.ccache-release' SORABOT_TOKEN = credentials('SORABOT_TOKEN') SONAR_TOKEN = credentials('SONAR_TOKEN') - CODECOV_TOKEN = credentials('CODECOV_TOKEN') - DOCKERHUB = credentials('DOCKERHUB') - DOCKER_BASE_IMAGE_DEVELOP = 'hyperledger/iroha:develop' - DOCKER_BASE_IMAGE_RELEASE = 'hyperledger/iroha:latest' GIT_RAW_BASE_URL = "https://raw.githubusercontent.com/hyperledger/iroha" IROHA_NETWORK = "iroha-0${CHANGE_ID}-${GIT_COMMIT}-${BUILD_NUMBER}" @@ -49,49 +44,26 @@ pipeline { IROHA_POSTGRES_PORT = 5432 } - triggers { - parameterizedCron(''' -0 23 * * * %BUILD_TYPE=Release; Linux=True; MacOS=True; ARMv7=False; ARMv8=True; Nightly=True; Doxygen=False; JavaBindings=False; PythonBindings=False; BindingsOnly=False; PARALLELISM=4 - ''') - } options { buildDiscarder(logRotator(numToKeepStr: '20')) } agent any stages { - stage ('Stop bad job builds') { + stage ('Stop same job builds') { agent { label 'master' } steps { script { - if (BRANCH_NAME != "develop") { - if (params.Nightly) { - // Stop this job running if it is nightly but not the develop it should be - def tmp = load ".jenkinsci/cancel-nightly-except-develop.groovy" - tmp.cancelThisJob() - } - else { - // Stop same job running builds if it is commit/PR build and not triggered as nightly - def builds = load ".jenkinsci/cancel-builds-same-job.groovy" - builds.cancelSameJobBuilds() - } - } - else { - if (!params.Nightly) { - // Stop same job running builds if it is develop but it is not nightly - def builds = load ".jenkinsci/cancel-builds-same-job.groovy" - builds.cancelSameJobBuilds() - } + if (GIT_LOCAL_BRANCH != "develop") { + def builds = load ".jenkinsci/cancel-builds-same-job.groovy" + builds.cancelSameJobBuilds() } } } } stage('Build Debug') { when { - allOf { - expression { params.BUILD_TYPE == 'Debug' } - expression { return !params.BindingsOnly } - } + expression { params.BUILD_TYPE == 'Debug' } } parallel { stage ('Linux') { @@ -107,7 +79,7 @@ pipeline { else { debugBuild.doDebugBuild() } - if (BRANCH_NAME ==~ /(master|develop)/) { + if (GIT_LOCAL_BRANCH ==~ /(master|develop)/) { releaseBuild = load ".jenkinsci/release-build.groovy" releaseBuild.doReleaseBuild() } @@ -135,7 +107,7 @@ pipeline { else { debugBuild.doDebugBuild() } - if (BRANCH_NAME ==~ /(master|develop)/) { + if (GIT_LOCAL_BRANCH ==~ /(master|develop)/) { releaseBuild = load ".jenkinsci/release-build.groovy" releaseBuild.doReleaseBuild() } @@ -163,7 +135,7 @@ pipeline { else { debugBuild.doDebugBuild() } - if (BRANCH_NAME ==~ /(master|develop)/) { + if (GIT_LOCAL_BRANCH ==~ /(master|develop)/) { releaseBuild = load ".jenkinsci/release-build.groovy" releaseBuild.doReleaseBuild() } @@ -245,7 +217,7 @@ pipeline { sh "python /usr/local/bin/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false } - if (BRANCH_NAME ==~ /(master|develop)/) { + if (GIT_LOCAL_BRANCH ==~ /(master|develop)/) { releaseBuild = load ".jenkinsci/mac-release-build.groovy" releaseBuild.doReleaseBuild() } @@ -256,11 +228,11 @@ pipeline { script { timeout(time: 600, unit: "SECONDS") { try { - if (currentBuild.currentResult == "SUCCESS" && BRANCH_NAME ==~ /(master|develop)/) { + if (currentBuild.currentResult == "SUCCESS" && GIT_LOCAL_BRANCH ==~ /(master|develop)/) { def artifacts = load ".jenkinsci/artifacts.groovy" def commit = env.GIT_COMMIT filePaths = [ '\$(pwd)/build/*.tar.gz' ] - artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [GIT_LOCAL_BRANCH, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) } } finally { @@ -279,10 +251,7 @@ pipeline { } stage('Build Release') { when { - allOf { - expression { params.BUILD_TYPE == 'Release' } - expression { return ! params.BindingsOnly } - } + expression { params.BUILD_TYPE == 'Release' } } parallel { stage('Linux') { @@ -353,11 +322,11 @@ pipeline { script { timeout(time: 600, unit: "SECONDS") { try { - if (currentBuild.currentResult == "SUCCESS" && BRANCH_NAME ==~ /(master|develop)/) { + if (currentBuild.currentResult == "SUCCESS" && GIT_LOCAL_BRANCH ==~ /(master|develop)/) { def artifacts = load ".jenkinsci/artifacts.groovy" def commit = env.GIT_COMMIT filePaths = [ '\$(pwd)/build/*.tar.gz' ] - artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [BRANCH_NAME, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) + artifacts.uploadArtifacts(filePaths, sprintf('/iroha/macos/%1$s-%2$s-%3$s', [GIT_LOCAL_BRANCH, sh(script: 'date "+%Y%m%d"', returnStdout: true).trim(), commit.substring(0,6)])) } } finally { @@ -374,7 +343,7 @@ pipeline { when { allOf { expression { return params.Doxygen } - expression { BRANCH_NAME ==~ /(master|develop)/ } + expression { GIT_LOCAL_BRANCH ==~ /(master|develop)/ } } } // build docs on any vacant node. Prefer `x86_64` over @@ -408,20 +377,20 @@ pipeline { def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" def platform = sh(script: 'uname -m', returnStdout: true).trim() if (params.JavaBindings) { - iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop", - "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile", - "${env.GIT_RAW_BASE_URL}/develop/docker/develop/x86_64/Dockerfile", + iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop-build", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", ['PARALLELISM': params.PARALLELISM]) iC.inside("-v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { bindings.doJavaBindings(params.JBBuildType) } } if (params.PythonBindings) { - iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop", - "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/${platform}/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/${platform}/Dockerfile", - "${env.GIT_RAW_BASE_URL}/develop/docker/develop/x86_64/Dockerfile", + iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop-build", + "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", ['PARALLELISM': params.PARALLELISM]) iC.inside("-v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { bindings.doPythonBindings(params.PBBuildType) diff --git a/deploy/ansible/playbooks/iroha-standalone-nodes/iroha-deploy.yml b/deploy/ansible/playbooks/iroha-standalone-nodes/iroha-deploy.yml index be332ff798..42a106b882 100644 --- a/deploy/ansible/playbooks/iroha-standalone-nodes/iroha-deploy.yml +++ b/deploy/ansible/playbooks/iroha-standalone-nodes/iroha-deploy.yml @@ -12,4 +12,4 @@ changed_when: False roles: - { role: docker, tags: docker } - - { role: iroha-standalone-deploy-node } + - { role: iroha-standalone-deploy-node, tags: iroha-standalone-deploy-node } diff --git a/docker/develop/aarch64/Dockerfile b/docker/develop/Dockerfile similarity index 100% rename from docker/develop/aarch64/Dockerfile rename to docker/develop/Dockerfile diff --git a/docker/develop/armv7l/Dockerfile b/docker/develop/armv7l/Dockerfile deleted file mode 100644 index 2eb33f6f1d..0000000000 --- a/docker/develop/armv7l/Dockerfile +++ /dev/null @@ -1,283 +0,0 @@ -FROM ubuntu:16.04 - -# number of concurrent threads during build -# usage: docker build --build-arg PARALLELISM=8 -t name/name . -ARG PARALLELISM=1 -ARG CMAKE_BUILD_TYPE=Release - -ENV IROHA_HOME /opt/iroha -ENV IROHA_BUILD /opt/iroha/build - -RUN apt-get update && \ - apt-get -y --no-install-recommends install apt-utils software-properties-common; \ - apt-get -y clean - - -# add git repository -RUN add-apt-repository -y ppa:git-core/ppa && \ - apt-get update - - -RUN set -e; \ - apt-get -y --no-install-recommends install build-essential python-software-properties \ - automake libtool \ - # dev dependencies - libssl-dev zlib1g-dev libcurl4-openssl-dev libc6-dbg golang \ - # CI dependencies - git ssh tar gzip ca-certificates \ - # Pythons - python-pip python3-pip python3-setuptools python-dev \ - # SWIG dependencies - libpcre3-dev autoconf bison \ - # other - wget curl file gdb ccache \ - gcovr cppcheck doxygen graphviz graphviz-dev unzip zip; \ - apt-get -y clean - -# install cmake 3.10.2 -RUN set -e; \ - git clone https://gitlab.kitware.com/cmake/cmake.git /tmp/cmake; \ - (cd /tmp/cmake ; git checkout c1e087a9d3af74299d7681c9f9de59e5977a1539); \ - (cd /tmp/cmake ; /tmp/cmake/bootstrap --system-curl --parallel=${PARALLELISM} --enable-ccache); \ - make -j${PARALLELISM} -C /tmp/cmake; \ - make -C /tmp/cmake install; \ - ldconfig; \ - rm -rf /tmp/cmake - -# install boost 1.65.1 -RUN set -e; \ - git clone https://github.com/boostorg/boost /tmp/boost; \ - (cd /tmp/boost ; git checkout 436ad1dfcfc7e0246141beddd11c8a4e9c10b146); \ - (cd /tmp/boost ; git submodule update --init --recursive); \ - (cd /tmp/boost ; /tmp/boost/bootstrap.sh --with-libraries=system,filesystem); \ - (cd /tmp/boost ; /tmp/boost/b2 headers); \ - (cd /tmp/boost ; /tmp/boost/b2 cxxflags="-std=c++14" -j ${PARALLELISM} install); \ - ldconfig; \ - rm -rf /tmp/boost - -# install protobuf -RUN set -e; \ - git clone https://github.com/google/protobuf /tmp/protobuf; \ - (cd /tmp/protobuf ; git checkout 80a37e0782d2d702d52234b62dd4b9ec74fd2c95); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -Dprotobuf_BUILD_TESTS=OFF \ - -Dprotobuf_BUILD_SHARED_LIBS=ON \ - -H/tmp/protobuf/cmake \ - -B/tmp/protobuf/.build; \ - cmake --build /tmp/protobuf/.build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/protobuf - -# install gflags -RUN set -e; \ - git clone https://github.com/gflags/gflags /tmp/gflags; \ - (cd /tmp/gflags ; git checkout f8a0efe03aa69b3336d8e228b37d4ccb17324b88); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/gflags \ - -B/tmp/gflags/build; \ - cmake --build /tmp/gflags/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/gflags - -# install c-ares -RUN set -e; \ - git clone https://github.com/c-ares/c-ares /tmp/c-ares; \ - (cd /tmp/c-ares ; git checkout 3be1924221e1326df520f8498d704a5c4c8d0cce); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/c-ares \ - -B/tmp/c-ares/build; \ - cmake --build /tmp/c-ares/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/c-ares - -# install grpc -RUN set -e; \ - git clone https://github.com/grpc/grpc /tmp/grpc; \ - cd /tmp/grpc; \ - git checkout bfcbad3b86c7912968dc8e64f2121c920dad4dfb; \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DgRPC_BENCHMARK_PROVIDER="" \ - -DgRPC_ZLIB_PROVIDER=package \ - -DgRPC_CARES_PROVIDER=package \ - -DgRPC_SSL_PROVIDER=package \ - -DgRPC_PROTOBUF_PROVIDER=package \ - -DgRPC_GFLAGS_PROVIDER=package \ - -DBUILD_SHARED_LIBS=ON \ - -H/tmp/grpc \ - -B/tmp/grpc/.build; \ - cd /tmp/grpc/.build; \ - make -j${PARALLELISM} gpr grpc grpc++ grpc_cpp_plugin; \ - # copy libs to /usr/local/lib - cp libgpr.so libgrpc.so libgrpc++.so libgrpc_plugin_support.so /usr/local/lib; \ - cp grpc_cpp_plugin /usr/local/bin; \ - cp -R ../include /usr/local; \ - ldconfig; \ - rm -rf /tmp/grpc - -# install gtest -RUN set -e; \ - git clone https://github.com/google/googletest /tmp/googletest; \ - (cd /tmp/googletest ; git checkout ec44c6c1675c25b9827aacd08c02433cccde7780); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/googletest \ - -B/tmp/googletest/build; \ - cmake --build /tmp/googletest/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/googletest - -# install spdlog v0.16.3 -RUN set -e; \ - git clone https://github.com/gabime/spdlog /tmp/spdlog; \ - (cd /tmp/spdlog ; git checkout ccd675a286f457068ee8c823f8207f13c2325b26); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DSPDLOG_BUILD_TESTING=OFF -H/tmp/spdlog -B/tmp/spdlog/build; \ - cmake --build /tmp/spdlog/build --target install; \ - rm -rf /tmp/spdlog - -# install rxcpp -RUN set -e; \ - git clone https://github.com/Reactive-Extensions/RxCpp /tmp/RxCpp; \ - (cd /tmp/RxCpp ; git checkout 1b2e0589f19cb34d8cd58803677701dcf2161876); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/RxCpp \ - -B/tmp/RxCpp/build; \ - cmake --build /tmp/RxCpp/build --target install; \ - rm -rf /tmp/RxCpp - -# install rapidjson -RUN set -e; \ - git clone https://github.com/miloyip/rapidjson /tmp/rapidjson; \ - (cd /tmp/rapidjson ; git checkout f54b0e47a08782a6131cc3d60f94d038fa6e0a51); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DRAPIDJSON_BUILD_EXAMPLES=OFF \ - -H/tmp/rapidjson \ - -B/tmp/rapidjson/build; \ - cmake --build /tmp/rapidjson/build --target install; \ - ldconfig; \ - rm -rf /tmp/rapidjson - -# install libpq -RUN set -e; \ - git clone --progress https://git.postgresql.org/git/postgresql.git /tmp/postgresql; \ - cd /tmp/postgresql; \ - git checkout 029386ccbddd0a33d481b94e511f5219b03e6636; \ - ./configure --without-readline --prefix=/usr/local; \ - # build - make -j${PARALLELISM} -C src/bin/pg_config; \ - make -j${PARALLELISM} -C src/interfaces/libpq; \ - make -j${PARALLELISM} -C src/backend/utils fmgroids.h; \ - cp src/backend/utils/fmgroids.h src/include/utils/fmgroids.h; \ - # install - make -C src/bin/pg_config install; \ - make -C src/interfaces/libpq install; \ - make -C src/include install; \ - ldconfig; \ - # remove - rm -rf /tmp/postgresql - -# install pqxx -RUN set -e; \ - git clone https://github.com/jtv/libpqxx /tmp/libpqxx; \ - (cd /tmp/libpqxx ; git checkout 5b17abce5ac2b1a2f8278718405b7ade8bb30ae9); \ - curl -L -o /tmp/libpqxx/config/config.guess 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=6b2374c79506ee82a8b440f6d1ca293e2e2e2463'; \ - curl -L -o /tmp/libpqxx/config/config.sub 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=6b2374c79506ee82a8b440f6d1ca293e2e2e2463'; \ - (cd /tmp/libpqxx ; /tmp/libpqxx/configure --disable-documentation --with-pic); \ - make -j${PARALLELISM} -C /tmp/libpqxx; \ - make -C /tmp/libpqxx install; \ - ldconfig; \ - rm -rf /tmp/libpqxx - -# install tbb -RUN set -e; \ - git clone https://github.com/01org/tbb /tmp/tbb; \ - (cd /tmp/tbb ; git checkout eb6336ad29450f2a64af5123ca1b9429ff6bc11d); \ - make -j${PARALLELISM} -C /tmp/tbb tbb_build_prefix=build; \ - cp /tmp/tbb/build/build_debug/*.so* /usr/local/lib; \ - cp /tmp/tbb/build/build_release/*.so* /usr/local/lib; \ - cp -r /tmp/tbb/include/* /usr/local/include; \ - ldconfig; \ - rm -rf /tmp/tbb - -# install sonar cli -ENV SONAR_CLI_VERSION=3.0.3.778 -RUN set -e; \ - mkdir -p /opt/sonar; \ - curl -L -o /tmp/sonar.zip https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_CLI_VERSION}-linux.zip; \ - unzip -o -d /tmp/sonar-scanner /tmp/sonar.zip; \ - mv /tmp/sonar-scanner/sonar-scanner-${SONAR_CLI_VERSION}-linux /opt/sonar/scanner; \ - ln -s -f /opt/sonar/scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner; \ - rm -rf /tmp/sonar* - -# install ed25519 -RUN set -e; \ - git clone git://github.com/hyperledger/iroha-ed25519.git /tmp/ed25519; \ - (cd /tmp/ed25519 ; git checkout e7188b8393dbe5ac54378610d53630bd4a180038); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DTESTING=OFF \ - -H/tmp/ed25519 \ - -B/tmp/ed25519/build; \ - cmake --build /tmp/ed25519/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/ed25519 - -# fetch lcov reports converter -RUN set -e; \ - curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py - -RUN set -e; \ - add-apt-repository -y ppa:webupd8team/java; \ - apt-get update; \ - echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections; \ - apt-get -y install oracle-java8-installer; \ - java -version - -# Build SWIG -RUN set -e; \ - curl -L -o /tmp/swig-3.0.12.tar.gz https://github.com/swig/swig/archive/rel-3.0.12.tar.gz; \ - tar -C /tmp -zxf /tmp/swig-3.0.12.tar.gz; \ - cd /tmp/swig-rel-3.0.12; \ - ./autogen.sh && ./configure && make -j${PARALLELISM}; \ - make install; \ - rm -rf /tmp/swig-rel-3.0.12 - -RUN set -e; \ - add-apt-repository -y ppa:jonathonf/python-3.6; \ - apt-get update; \ - apt-get -y install python3.6-dev - -# python bindings dependencies -RUN set -e; \ - pip install grpcio_tools; \ - pip3 install grpcio_tools - -# install lcov -RUN set -e; \ - curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install - -# non-interactive adduser -# -m = create home dir -# -s = set default shell -# iroha-ci = username -# -u = userid, default for Ubuntu is 1000 -# -U = create a group same as username -# no password -RUN useradd -ms /bin/bash iroha-ci -u 1000 -U - -WORKDIR /opt/iroha -RUN set -e; \ - chmod -R 777 /opt/iroha; \ - mkdir -p /tmp/ccache -m 777; \ - ccache --clear - - -USER iroha-ci -CMD ["/bin/bash"] diff --git a/docker/develop/x86_64/Dockerfile b/docker/develop/x86_64/Dockerfile deleted file mode 100644 index 2eb33f6f1d..0000000000 --- a/docker/develop/x86_64/Dockerfile +++ /dev/null @@ -1,283 +0,0 @@ -FROM ubuntu:16.04 - -# number of concurrent threads during build -# usage: docker build --build-arg PARALLELISM=8 -t name/name . -ARG PARALLELISM=1 -ARG CMAKE_BUILD_TYPE=Release - -ENV IROHA_HOME /opt/iroha -ENV IROHA_BUILD /opt/iroha/build - -RUN apt-get update && \ - apt-get -y --no-install-recommends install apt-utils software-properties-common; \ - apt-get -y clean - - -# add git repository -RUN add-apt-repository -y ppa:git-core/ppa && \ - apt-get update - - -RUN set -e; \ - apt-get -y --no-install-recommends install build-essential python-software-properties \ - automake libtool \ - # dev dependencies - libssl-dev zlib1g-dev libcurl4-openssl-dev libc6-dbg golang \ - # CI dependencies - git ssh tar gzip ca-certificates \ - # Pythons - python-pip python3-pip python3-setuptools python-dev \ - # SWIG dependencies - libpcre3-dev autoconf bison \ - # other - wget curl file gdb ccache \ - gcovr cppcheck doxygen graphviz graphviz-dev unzip zip; \ - apt-get -y clean - -# install cmake 3.10.2 -RUN set -e; \ - git clone https://gitlab.kitware.com/cmake/cmake.git /tmp/cmake; \ - (cd /tmp/cmake ; git checkout c1e087a9d3af74299d7681c9f9de59e5977a1539); \ - (cd /tmp/cmake ; /tmp/cmake/bootstrap --system-curl --parallel=${PARALLELISM} --enable-ccache); \ - make -j${PARALLELISM} -C /tmp/cmake; \ - make -C /tmp/cmake install; \ - ldconfig; \ - rm -rf /tmp/cmake - -# install boost 1.65.1 -RUN set -e; \ - git clone https://github.com/boostorg/boost /tmp/boost; \ - (cd /tmp/boost ; git checkout 436ad1dfcfc7e0246141beddd11c8a4e9c10b146); \ - (cd /tmp/boost ; git submodule update --init --recursive); \ - (cd /tmp/boost ; /tmp/boost/bootstrap.sh --with-libraries=system,filesystem); \ - (cd /tmp/boost ; /tmp/boost/b2 headers); \ - (cd /tmp/boost ; /tmp/boost/b2 cxxflags="-std=c++14" -j ${PARALLELISM} install); \ - ldconfig; \ - rm -rf /tmp/boost - -# install protobuf -RUN set -e; \ - git clone https://github.com/google/protobuf /tmp/protobuf; \ - (cd /tmp/protobuf ; git checkout 80a37e0782d2d702d52234b62dd4b9ec74fd2c95); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -Dprotobuf_BUILD_TESTS=OFF \ - -Dprotobuf_BUILD_SHARED_LIBS=ON \ - -H/tmp/protobuf/cmake \ - -B/tmp/protobuf/.build; \ - cmake --build /tmp/protobuf/.build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/protobuf - -# install gflags -RUN set -e; \ - git clone https://github.com/gflags/gflags /tmp/gflags; \ - (cd /tmp/gflags ; git checkout f8a0efe03aa69b3336d8e228b37d4ccb17324b88); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/gflags \ - -B/tmp/gflags/build; \ - cmake --build /tmp/gflags/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/gflags - -# install c-ares -RUN set -e; \ - git clone https://github.com/c-ares/c-ares /tmp/c-ares; \ - (cd /tmp/c-ares ; git checkout 3be1924221e1326df520f8498d704a5c4c8d0cce); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/c-ares \ - -B/tmp/c-ares/build; \ - cmake --build /tmp/c-ares/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/c-ares - -# install grpc -RUN set -e; \ - git clone https://github.com/grpc/grpc /tmp/grpc; \ - cd /tmp/grpc; \ - git checkout bfcbad3b86c7912968dc8e64f2121c920dad4dfb; \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DgRPC_BENCHMARK_PROVIDER="" \ - -DgRPC_ZLIB_PROVIDER=package \ - -DgRPC_CARES_PROVIDER=package \ - -DgRPC_SSL_PROVIDER=package \ - -DgRPC_PROTOBUF_PROVIDER=package \ - -DgRPC_GFLAGS_PROVIDER=package \ - -DBUILD_SHARED_LIBS=ON \ - -H/tmp/grpc \ - -B/tmp/grpc/.build; \ - cd /tmp/grpc/.build; \ - make -j${PARALLELISM} gpr grpc grpc++ grpc_cpp_plugin; \ - # copy libs to /usr/local/lib - cp libgpr.so libgrpc.so libgrpc++.so libgrpc_plugin_support.so /usr/local/lib; \ - cp grpc_cpp_plugin /usr/local/bin; \ - cp -R ../include /usr/local; \ - ldconfig; \ - rm -rf /tmp/grpc - -# install gtest -RUN set -e; \ - git clone https://github.com/google/googletest /tmp/googletest; \ - (cd /tmp/googletest ; git checkout ec44c6c1675c25b9827aacd08c02433cccde7780); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/googletest \ - -B/tmp/googletest/build; \ - cmake --build /tmp/googletest/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/googletest - -# install spdlog v0.16.3 -RUN set -e; \ - git clone https://github.com/gabime/spdlog /tmp/spdlog; \ - (cd /tmp/spdlog ; git checkout ccd675a286f457068ee8c823f8207f13c2325b26); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DSPDLOG_BUILD_TESTING=OFF -H/tmp/spdlog -B/tmp/spdlog/build; \ - cmake --build /tmp/spdlog/build --target install; \ - rm -rf /tmp/spdlog - -# install rxcpp -RUN set -e; \ - git clone https://github.com/Reactive-Extensions/RxCpp /tmp/RxCpp; \ - (cd /tmp/RxCpp ; git checkout 1b2e0589f19cb34d8cd58803677701dcf2161876); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -H/tmp/RxCpp \ - -B/tmp/RxCpp/build; \ - cmake --build /tmp/RxCpp/build --target install; \ - rm -rf /tmp/RxCpp - -# install rapidjson -RUN set -e; \ - git clone https://github.com/miloyip/rapidjson /tmp/rapidjson; \ - (cd /tmp/rapidjson ; git checkout f54b0e47a08782a6131cc3d60f94d038fa6e0a51); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DRAPIDJSON_BUILD_EXAMPLES=OFF \ - -H/tmp/rapidjson \ - -B/tmp/rapidjson/build; \ - cmake --build /tmp/rapidjson/build --target install; \ - ldconfig; \ - rm -rf /tmp/rapidjson - -# install libpq -RUN set -e; \ - git clone --progress https://git.postgresql.org/git/postgresql.git /tmp/postgresql; \ - cd /tmp/postgresql; \ - git checkout 029386ccbddd0a33d481b94e511f5219b03e6636; \ - ./configure --without-readline --prefix=/usr/local; \ - # build - make -j${PARALLELISM} -C src/bin/pg_config; \ - make -j${PARALLELISM} -C src/interfaces/libpq; \ - make -j${PARALLELISM} -C src/backend/utils fmgroids.h; \ - cp src/backend/utils/fmgroids.h src/include/utils/fmgroids.h; \ - # install - make -C src/bin/pg_config install; \ - make -C src/interfaces/libpq install; \ - make -C src/include install; \ - ldconfig; \ - # remove - rm -rf /tmp/postgresql - -# install pqxx -RUN set -e; \ - git clone https://github.com/jtv/libpqxx /tmp/libpqxx; \ - (cd /tmp/libpqxx ; git checkout 5b17abce5ac2b1a2f8278718405b7ade8bb30ae9); \ - curl -L -o /tmp/libpqxx/config/config.guess 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=6b2374c79506ee82a8b440f6d1ca293e2e2e2463'; \ - curl -L -o /tmp/libpqxx/config/config.sub 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=6b2374c79506ee82a8b440f6d1ca293e2e2e2463'; \ - (cd /tmp/libpqxx ; /tmp/libpqxx/configure --disable-documentation --with-pic); \ - make -j${PARALLELISM} -C /tmp/libpqxx; \ - make -C /tmp/libpqxx install; \ - ldconfig; \ - rm -rf /tmp/libpqxx - -# install tbb -RUN set -e; \ - git clone https://github.com/01org/tbb /tmp/tbb; \ - (cd /tmp/tbb ; git checkout eb6336ad29450f2a64af5123ca1b9429ff6bc11d); \ - make -j${PARALLELISM} -C /tmp/tbb tbb_build_prefix=build; \ - cp /tmp/tbb/build/build_debug/*.so* /usr/local/lib; \ - cp /tmp/tbb/build/build_release/*.so* /usr/local/lib; \ - cp -r /tmp/tbb/include/* /usr/local/include; \ - ldconfig; \ - rm -rf /tmp/tbb - -# install sonar cli -ENV SONAR_CLI_VERSION=3.0.3.778 -RUN set -e; \ - mkdir -p /opt/sonar; \ - curl -L -o /tmp/sonar.zip https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_CLI_VERSION}-linux.zip; \ - unzip -o -d /tmp/sonar-scanner /tmp/sonar.zip; \ - mv /tmp/sonar-scanner/sonar-scanner-${SONAR_CLI_VERSION}-linux /opt/sonar/scanner; \ - ln -s -f /opt/sonar/scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner; \ - rm -rf /tmp/sonar* - -# install ed25519 -RUN set -e; \ - git clone git://github.com/hyperledger/iroha-ed25519.git /tmp/ed25519; \ - (cd /tmp/ed25519 ; git checkout e7188b8393dbe5ac54378610d53630bd4a180038); \ - cmake \ - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DTESTING=OFF \ - -H/tmp/ed25519 \ - -B/tmp/ed25519/build; \ - cmake --build /tmp/ed25519/build --target install -- -j${PARALLELISM}; \ - ldconfig; \ - rm -rf /tmp/ed25519 - -# fetch lcov reports converter -RUN set -e; \ - curl -L -o /tmp/lcov_cobertura.py https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/8c55cd11f80a21e7e46f20f8c81fcde0bf11f5e5/lcov_cobertura/lcov_cobertura.py - -RUN set -e; \ - add-apt-repository -y ppa:webupd8team/java; \ - apt-get update; \ - echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections; \ - apt-get -y install oracle-java8-installer; \ - java -version - -# Build SWIG -RUN set -e; \ - curl -L -o /tmp/swig-3.0.12.tar.gz https://github.com/swig/swig/archive/rel-3.0.12.tar.gz; \ - tar -C /tmp -zxf /tmp/swig-3.0.12.tar.gz; \ - cd /tmp/swig-rel-3.0.12; \ - ./autogen.sh && ./configure && make -j${PARALLELISM}; \ - make install; \ - rm -rf /tmp/swig-rel-3.0.12 - -RUN set -e; \ - add-apt-repository -y ppa:jonathonf/python-3.6; \ - apt-get update; \ - apt-get -y install python3.6-dev - -# python bindings dependencies -RUN set -e; \ - pip install grpcio_tools; \ - pip3 install grpcio_tools - -# install lcov -RUN set -e; \ - curl -L -o /tmp/lcov-1.13.tar.gz https://github.com/linux-test-project/lcov/releases/download/v1.13/lcov-1.13.tar.gz; cd /tmp; tar zxf lcov-1.13.tar.gz; cd lcov-1.13; make install - -# non-interactive adduser -# -m = create home dir -# -s = set default shell -# iroha-ci = username -# -u = userid, default for Ubuntu is 1000 -# -U = create a group same as username -# no password -RUN useradd -ms /bin/bash iroha-ci -u 1000 -U - -WORKDIR /opt/iroha -RUN set -e; \ - chmod -R 777 /opt/iroha; \ - mkdir -p /tmp/ccache -m 777; \ - ccache --clear - - -USER iroha-ci -CMD ["/bin/bash"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 8bc958647b..0e020e3964 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,35 +1,33 @@ -version: '3' +version: '2' services: - node: - image: hyperledger/iroha-docker-develop:v1 + iroha: + image: hyperledger/iroha:develop + container_name: iroha ports: - - "${IROHA_PORT}:50051" - - "${DEBUGGER_PORT}:20000" + - "50051:50051" environment: - - IROHA_POSTGRES_HOST=${COMPOSE_PROJECT_NAME}_postgres_1 + - IROHA_POSTGRES_HOST=iroha-postgres - IROHA_POSTGRES_PORT=5432 - IROHA_POSTGRES_USER=iroha - - IROHA_POSTGRES_PASSWORD=helloworld - - CCACHE_DIR=/tmp/ccache - # export G_ID=$(id -g $(whoami)) - # export U_ID=$(id -g $(whoami)) - user: ${U_ID:-0}:${G_ID:-0} + - IROHA_POSTGRES_PASSWORD=iroha depends_on: - postgres tty: true + environment: + - KEY=node0 volumes: - - ../:/opt/iroha - - ccache-data:/tmp/ccache - working_dir: /opt/iroha - cap_add: - - SYS_PTRACE + # as configured in example/config.sample + - /tmp/block_store + - ./iroha/example:/opt/iroha_data + restart: always postgres: image: postgres:9.5 + container_name: iroha-postgres environment: - POSTGRES_USER=iroha - - IROHA_POSTGRES_PASSWORD=helloworld - -volumes: - ccache-data: + - POSTGRES_PASSWORD=iroha + expose: + - 5432 + restart: always diff --git a/docker/manifest.yaml b/docker/manifest.yaml index f7ece5d19f..f43a6e1eee 100644 --- a/docker/manifest.yaml +++ b/docker/manifest.yaml @@ -2,20 +2,20 @@ image: hyperledger/iroha:latest manifests: - - image: hyperledger/iroha:x86_64 + image: hyperledger/iroha:x86_64-latest platform: architecture: amd64 os: linux features: - sse - - image: hyperledger/iroha:armv7l + image: hyperledger/iroha:armv7l-latest platform: architecture: arm os: linux variant: v7 - - image: hyperledger/iroha:aarch64 + image: hyperledger/iroha:aarch64-latest platform: architecture: arm64 os: linux @@ -41,3 +41,25 @@ manifests: platform: architecture: arm64 os: linux + +# develop branch, build env +image: hyperledger/iroha:develop-build +manifests: + - + image: hyperledger/iroha:x86_64-develop-build + platform: + architecture: amd64 + os: linux + features: + - sse + - + image: hyperledger/iroha:armv7l-develop-build + platform: + architecture: arm + os: linux + variant: v7 + - + image: hyperledger/iroha:aarch64-develop-build + platform: + architecture: arm64 + os: linux diff --git a/docker/release/aarch64/Dockerfile b/docker/release/Dockerfile similarity index 100% rename from docker/release/aarch64/Dockerfile rename to docker/release/Dockerfile diff --git a/docker/release/armv7l/Dockerfile b/docker/release/armv7l/Dockerfile deleted file mode 100644 index c07120cb32..0000000000 --- a/docker/release/armv7l/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update; \ - apt-get install -y libc-ares-dev - -#Install iroha -COPY iroha.deb /tmp/iroha.deb -RUN apt-get install -y /tmp/iroha.deb; \ - rm -f /tmp/iroha.deb - -WORKDIR /opt/iroha_data - -COPY entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] -CMD ["/sbin/init"] diff --git a/docker/release/armv7l/entrypoint.sh b/docker/release/armv7l/entrypoint.sh deleted file mode 100755 index 709e3d9bbc..0000000000 --- a/docker/release/armv7l/entrypoint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -echo key=$KEY -echo $PWD -irohad --genesis_block genesis.block --config config.sample --keypair_name $KEY diff --git a/docker/release/aarch64/entrypoint.sh b/docker/release/entrypoint.sh similarity index 100% rename from docker/release/aarch64/entrypoint.sh rename to docker/release/entrypoint.sh diff --git a/docker/release/x86_64/Dockerfile b/docker/release/x86_64/Dockerfile deleted file mode 100644 index c07120cb32..0000000000 --- a/docker/release/x86_64/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update; \ - apt-get install -y libc-ares-dev - -#Install iroha -COPY iroha.deb /tmp/iroha.deb -RUN apt-get install -y /tmp/iroha.deb; \ - rm -f /tmp/iroha.deb - -WORKDIR /opt/iroha_data - -COPY entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] -CMD ["/sbin/init"] diff --git a/docker/release/x86_64/entrypoint.sh b/docker/release/x86_64/entrypoint.sh deleted file mode 100755 index 709e3d9bbc..0000000000 --- a/docker/release/x86_64/entrypoint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -echo key=$KEY -echo $PWD -irohad --genesis_block genesis.block --config config.sample --keypair_name $KEY From ec6ee168cc9dd61e4dd8658845ee799c6a63af17 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Sun, 29 Apr 2018 14:47:10 +0300 Subject: [PATCH 070/110] CI release build path hotfix Signed-off-by: Artyom Bakhtin --- .jenkinsci/release-build.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index 54e0ca5031..0dbbc48699 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -50,8 +50,8 @@ def doReleaseBuild() { sh "mv ./build/*.tar.gz /tmp/${GIT_COMMIT}/iroha.tar.gz" } - sh "curl -L -o /tmp/${env.GIT_COMMIT}/Dockerfile --create-dirs https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/release/${platform}/Dockerfile" - sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh https://raw.githubusercontent.com/hyperledger/iroha/${env.GIT_COMMIT}/docker/release/${platform}/entrypoint.sh" + sh "curl -L -o /tmp/${env.GIT_COMMIT}/Dockerfile --create-dirs ${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/release/Dockerfile" + sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh ${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/release/entrypoint.sh" sh "mv /tmp/${GIT_COMMIT}-${BUILD_NUMBER}/iroha.deb /tmp/${env.GIT_COMMIT}" sh "chmod +x /tmp/${env.GIT_COMMIT}/entrypoint.sh" iCRelease = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}-release", "--no-cache -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") From 74f3828d31a79eb38b04a9f8366d4bbf00c81f34 Mon Sep 17 00:00:00 2001 From: Igor Egorov <36847043+igor-egorov@users.noreply.github.com> Date: Mon, 30 Apr 2018 16:50:24 +0300 Subject: [PATCH 071/110] Improve ITF (#1056) The first bunch of Integration Test Framework improvements Benefits: Docstrings are added to public methods of ITF. Destruction of ITF now will cause call of done (dropStorage) if no custom deleter was provided. Added regression test that uses the rest previously unused ITF methods. Added test for sequential initialization of two Iroha instances (test simulates the crash of the first instance - ITF destructed without a call of done). Added test for double call of done. Signed-off-by: Igor Egorov --- irohad/main/server_runner.cpp | 6 + irohad/main/server_runner.hpp | 5 + test/CMakeLists.txt | 1 + .../integration_test_framework.cpp | 121 +++++++--- .../integration_test_framework.hpp | 219 +++++++++++------- .../integration_framework/test_irohad.hpp | 6 + .../acceptance/transfer_asset_test.cpp | 2 +- test/integration/pipeline/test_irohad.hpp | 0 test/regression/CMakeLists.txt | 6 + test/regression/regression_test.cpp | 83 +++++++ 10 files changed, 329 insertions(+), 120 deletions(-) create mode 100644 test/integration/pipeline/test_irohad.hpp create mode 100644 test/regression/CMakeLists.txt create mode 100644 test/regression/regression_test.cpp diff --git a/irohad/main/server_runner.cpp b/irohad/main/server_runner.cpp index 110f8ea11e..c7b2a1db1e 100644 --- a/irohad/main/server_runner.cpp +++ b/irohad/main/server_runner.cpp @@ -65,3 +65,9 @@ void ServerRunner::waitForServersReady() { serverInstanceCV_.wait(lock); } } + +void ServerRunner::shutdown() { + if (serverInstance_) { + serverInstance_->Shutdown(); + } +} diff --git a/irohad/main/server_runner.hpp b/irohad/main/server_runner.hpp index 04de6ad1d5..d633d89f03 100644 --- a/irohad/main/server_runner.hpp +++ b/irohad/main/server_runner.hpp @@ -53,6 +53,11 @@ class ServerRunner { */ void waitForServersReady(); + /** + * Ask grpc server to terminate. + */ + void shutdown(); + private: std::unique_ptr serverInstance_; std::mutex waitForServer_; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5e3038d2ff..cd9ea35c24 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,6 +20,7 @@ set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test_bin) add_subdirectory(module) add_subdirectory(framework) add_subdirectory(integration) +add_subdirectory(regression) add_subdirectory(system) if(BENCHMARKING) diff --git a/test/framework/integration_framework/integration_test_framework.cpp b/test/framework/integration_framework/integration_test_framework.cpp index 9af9197f8f..6ae70729dd 100644 --- a/test/framework/integration_framework/integration_test_framework.cpp +++ b/test/framework/integration_framework/integration_test_framework.cpp @@ -18,13 +18,22 @@ #include "framework/integration_framework/integration_test_framework.hpp" #include + +#include "backend/protobuf/block.hpp" +#include "backend/protobuf/queries/proto_query.hpp" +#include "backend/protobuf/query_responses/proto_query_response.hpp" +#include "backend/protobuf/transaction.hpp" +#include "backend/protobuf/transaction_responses/proto_tx_response.hpp" #include "builders/protobuf/block.hpp" #include "builders/protobuf/proposal.hpp" #include "builders/protobuf/transaction.hpp" #include "common/files.hpp" -#include "cryptography/hash_providers/sha3_256.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" +#include "cryptography/default_hash_provider.hpp" #include "datetime/time.hpp" -// TODO (@l4l) IR-874 create more comfort way for permssion-dependent proto +#include "framework/integration_framework/iroha_instance.hpp" +#include "framework/integration_framework/test_irohad.hpp" +// TODO (@l4l) IR-874 create more comfort way for permission-dependent proto // building #include "validators/permissions.hpp" @@ -39,35 +48,23 @@ namespace integration_framework { const std::string IntegrationTestFramework::kAdminId = "admin@test"; const std::string IntegrationTestFramework::kAssetName = "coin"; + IntegrationTestFramework::IntegrationTestFramework( + size_t maximum_proposal_size, + std::function + deleter) + : maximum_proposal_size_(maximum_proposal_size), deleter_(deleter) {} + IntegrationTestFramework::~IntegrationTestFramework() { - pqxx::lazyconnection connection(iroha_instance_->pg_conn_); - const auto drop = R"( -DROP TABLE IF EXISTS account_has_signatory; -DROP TABLE IF EXISTS account_has_asset; -DROP TABLE IF EXISTS role_has_permissions; -DROP TABLE IF EXISTS account_has_roles; -DROP TABLE IF EXISTS account_has_grantable_permissions; -DROP TABLE IF EXISTS account; -DROP TABLE IF EXISTS asset; -DROP TABLE IF EXISTS domain; -DROP TABLE IF EXISTS signatory; -DROP TABLE IF EXISTS peer; -DROP TABLE IF EXISTS role; -DROP TABLE IF EXISTS height_by_hash; -DROP TABLE IF EXISTS height_by_account_set; -DROP TABLE IF EXISTS index_by_creator_height; -DROP TABLE IF EXISTS index_by_id_height_asset; -)"; - - pqxx::work txn(connection); - txn.exec(drop); - txn.commit(); - connection.disconnect(); - - iroha::remove_dir_contents(iroha_instance_->block_store_dir_); + if (deleter_) { + deleter_(*this); + } + // the code below should be executed anyway in order to prevent app hang + if (iroha_instance_ and iroha_instance_->instance_) { + iroha_instance_->instance_->terminate(); + } } - IntegrationTestFramework &IntegrationTestFramework::setInitialState( + shared_model::proto::Block IntegrationTestFramework::defaultBlock( const shared_model::crypto::Keypair &key) { auto genesis_tx = shared_model::proto::TransactionBuilder() @@ -75,8 +72,8 @@ DROP TABLE IF EXISTS index_by_id_height_asset; .createdTime(iroha::time::now()) .addPeer("0.0.0.0:50541", key.publicKey()) .createRole(kDefaultRole, - // TODO (@l4l) IR-874 create more confort way for - // permssion-dependent proto building + // TODO (@l4l) IR-874 create more comfort way for + // permission-dependent proto building std::vector{ shared_model::permissions::role_perm_group.begin(), shared_model::permissions::role_perm_group.end()}) @@ -90,18 +87,24 @@ DROP TABLE IF EXISTS index_by_id_height_asset; .transactions( std::vector{genesis_tx}) .height(1) - .prevHash(Sha3_256::makeHash(Blob(""))) + .prevHash(DefaultHashProvider::makeHash(Blob(""))) .createdTime(iroha::time::now()) .build() .signAndAddSignature(key); - return setInitialState(key, genesis_block); + return genesis_block; + } + + IntegrationTestFramework &IntegrationTestFramework::setInitialState( + const Keypair &keypair) { + return setInitialState(keypair, + IntegrationTestFramework::defaultBlock(keypair)); } IntegrationTestFramework &IntegrationTestFramework::setInitialState( const Keypair &keypair, const shared_model::interface::Block &block) { log_->info("init state"); // peer initialization - iroha_instance_->initPipeline(keypair, maximum_block_size_); + iroha_instance_->initPipeline(keypair, maximum_proposal_size_); log_->info("created pipeline"); // iroha_instance_->clearLedger(); // log_->info("cleared ledger"); @@ -150,23 +153,75 @@ DROP TABLE IF EXISTS index_by_id_height_asset; return shared_model::proto::TransactionResponse(std::move(response)); } + IntegrationTestFramework &IntegrationTestFramework::sendTx( + const shared_model::proto::Transaction &tx, + std::function + validation) { + log_->info("send transaction"); + iroha_instance_->getIrohaInstance()->getCommandService()->Torii( + tx.getTransport()); + // fetch status of transaction + shared_model::proto::TransactionResponse status = getTxStatus(tx.hash()); + + // check validation function + validation(status); + return *this; + } + IntegrationTestFramework &IntegrationTestFramework::sendTx( const shared_model::proto::Transaction &tx) { sendTx(tx, [](const auto &) {}); return *this; } + IntegrationTestFramework &IntegrationTestFramework::sendQuery( + const shared_model::proto::Query &qry, + std::function + validation) { + log_->info("send query"); + + iroha::protocol::QueryResponse response; + iroha_instance_->getIrohaInstance()->getQueryService()->Find( + qry.getTransport(), response); + auto query_response = + shared_model::proto::QueryResponse(std::move(response)); + + validation(query_response); + return *this; + } + IntegrationTestFramework &IntegrationTestFramework::sendQuery( const shared_model::proto::Query &qry) { sendQuery(qry, [](const auto &) {}); return *this; } + IntegrationTestFramework &IntegrationTestFramework::checkProposal( + std::function validation) { + log_->info("check proposal"); + // fetch first proposal from proposal queue + ProposalType proposal; + fetchFromQueue( + proposal_queue_, proposal, proposal_waiting, "missed proposal"); + validation(proposal); + return *this; + } + IntegrationTestFramework &IntegrationTestFramework::skipProposal() { checkProposal([](const auto &) {}); return *this; } + IntegrationTestFramework &IntegrationTestFramework::checkBlock( + std::function validation) { + // fetch first from block queue + log_->info("check block"); + BlockType block; + fetchFromQueue(block_queue_, block, block_waiting, "missed block"); + validation(block); + return *this; + } + IntegrationTestFramework &IntegrationTestFramework::skipBlock() { checkBlock([](const auto &) {}); return *this; diff --git a/test/framework/integration_framework/integration_test_framework.hpp b/test/framework/integration_framework/integration_test_framework.hpp index 62d1e063d5..1d5d0a4181 100644 --- a/test/framework/integration_framework/integration_test_framework.hpp +++ b/test/framework/integration_framework/integration_test_framework.hpp @@ -18,28 +18,32 @@ #ifndef IROHA_INTEGRATION_FRAMEWORK_HPP #define IROHA_INTEGRATION_FRAMEWORK_HPP -#include #include #include #include +#include #include #include #include #include -#include "crypto/keys_manager_impl.hpp" -#include "cryptography/blob.hpp" -#include "cryptography/ed25519_sha3_impl/internal/sha3_hash.hpp" -#include "cryptography/keypair.hpp" + +#include #include "framework/integration_framework/iroha_instance.hpp" #include "framework/integration_framework/test_irohad.hpp" #include "logger/logger.hpp" -#include "backend/protobuf/block.hpp" -#include "backend/protobuf/proposal.hpp" -#include "backend/protobuf/queries/proto_query.hpp" -#include "backend/protobuf/query_responses/proto_query_response.hpp" -#include "backend/protobuf/transaction.hpp" -#include "backend/protobuf/transaction_responses/proto_tx_response.hpp" +namespace shared_model { + namespace crypto { + class Keypair; + } + namespace interface { + class Block; + class Proposal; + } + namespace proto { + class Block; + } +} namespace integration_framework { @@ -51,41 +55,143 @@ namespace integration_framework { using BlockType = std::shared_ptr; public: - IntegrationTestFramework(size_t maximum_block_size = 10) - : maximum_block_size_(maximum_block_size) {} + /** + * Construct test framework instance + * @param maximum_proposal_size - (default = 10) Maximum amount of + * transactions per proposal + * @param destructor_lambda - (default nullptr) Pointer to function which + * receives pointer to constructed instance of Integration Test Framework. + * If specified, then will be called instead of default destructor's code + */ + explicit IntegrationTestFramework( + size_t maximum_proposal_size = 10, + std::function deleter = + [](IntegrationTestFramework &itf) { itf.done(); }); + ~IntegrationTestFramework(); + + /** + * Construct default genesis block. + * + * Genesis block contains single transaction that + * creates a single role (kDefaultRole), domain (kDefaultDomain), + * account (kAdminName) and asset (kAssetName). + * @param key - signing key + * @return signed genesis block + */ + static shared_model::proto::Block defaultBlock( + const shared_model::crypto::Keypair &key); + + /** + * Initialize Iroha instance with default genesis block and provided signing + * key + * @param keypair - signing key + * @return this + */ IntegrationTestFramework &setInitialState( const shared_model::crypto::Keypair &keypair); + + /** + * Initialize Iroha instance with provided genesis block and signing key + * @param keypair - signing key + * @param block - genesis block used for iroha initialization + * @return this + */ IntegrationTestFramework &setInitialState( const shared_model::crypto::Keypair &keypair, const shared_model::interface::Block &block); - template - IntegrationTestFramework &sendTx(const shared_model::proto::Transaction &tx, - Lambda validation); + /** + * Send transaction to Iroha and validate its status + * @param tx - transaction for sending + * @param validation - callback for transaction status validation that + * receives object of type \relates shared_model::proto::TransactionResponse + * by reference + * @return this + */ + IntegrationTestFramework &sendTx( + const shared_model::proto::Transaction &tx, + std::function + validation); + + /** + * Send transaction to Iroha without status validation + * @param tx - transaction for sending + * @return this + */ IntegrationTestFramework &sendTx( const shared_model::proto::Transaction &tx); + + /** + * Check current status of transaction + * @param hash - hash of transaction to check + * @return TransactonResponse object + */ shared_model::proto::TransactionResponse getTxStatus( const shared_model::crypto::Hash &hash); - template - IntegrationTestFramework &sendQuery(const shared_model::proto::Query &qry, - Lambda validation); + /** + * Send query to Iroha and validate the response + * @param qry - query to be requested + * @param validation - callback for query result check that receives object + * of type \relates shared_model::proto::QueryResponse by reference + * @return this + */ + IntegrationTestFramework &sendQuery( + const shared_model::proto::Query &qry, + std::function + validation); + + /** + * Send query to Iroha without response validation + * @param qry - query to be requested + * @return this + */ IntegrationTestFramework &sendQuery(const shared_model::proto::Query &qry); - template - IntegrationTestFramework &checkProposal(Lambda validation); + /** + * Request next proposal from queue and serve it with custom handler + * @param validation - callback that receives object of type \relates + * std::shared_ptr by reference + * @return this + */ + IntegrationTestFramework &checkProposal( + std::function validation); + + /** + * Request next proposal from queue and skip it + * @return this + */ IntegrationTestFramework &skipProposal(); - template - IntegrationTestFramework &checkBlock(Lambda validation); + /** + * Request next block from queue and serve it with custom handler + * @param validation - callback that receives object of type \relates + * std::shared_ptr by reference + * @return this + */ + IntegrationTestFramework &checkBlock( + std::function validation); + + /** + * Request next block from queue and skip it + * @return this + */ IntegrationTestFramework &skipBlock(); /** - * Shutdown iroha + * Shutdown ITF instance */ void done(); + static const std::string kDefaultDomain; + static const std::string kDefaultRole; + + static const std::string kAdminName; + static const std::string kAdminId; + static const std::string kAssetName; + + protected: /** * general way to fetch object from concurrent queue * @tparam Queue - Type of queue @@ -94,7 +200,7 @@ namespace integration_framework { * @param queue - queue instance for fetching * @param ref_for_insertion - reference to insert object * @param wait - time of waiting - * @param error_reason - reason if thehre is no appeared object at all + * @param error_reason - reason if there is no appeared object at all */ template void fetchFromQueue(Queue &queue, @@ -102,14 +208,6 @@ namespace integration_framework { const WaitTime &wait, const std::string &error_reason); - static const std::string kDefaultDomain; - static const std::string kDefaultRole; - - static const std::string kAdminName; - static const std::string kAdminId; - static const std::string kAssetName; - - protected: tbb::concurrent_queue proposal_queue_; tbb::concurrent_queue block_queue_; std::shared_ptr iroha_instance_ = @@ -124,66 +222,15 @@ namespace integration_framework { /// maximum time of waiting before appearing next committed block const milliseconds block_waiting = milliseconds(20000); - size_t maximum_block_size_; + size_t maximum_proposal_size_; private: logger::Logger log_ = logger::log("IntegrationTestFramework"); std::mutex queue_mu; std::condition_variable queue_cond; + std::function deleter_; }; - template - IntegrationTestFramework &IntegrationTestFramework::sendTx( - const shared_model::proto::Transaction &tx, Lambda validation) { - log_->info("send transaction"); - iroha_instance_->getIrohaInstance()->getCommandService()->Torii( - tx.getTransport()); - // fetch status of transaction - shared_model::proto::TransactionResponse status = getTxStatus(tx.hash()); - - // check validation function - validation(status); - return *this; - } - - template - IntegrationTestFramework &IntegrationTestFramework::sendQuery( - const shared_model::proto::Query &qry, Lambda validation) { - log_->info("send query"); - - iroha::protocol::QueryResponse response; - iroha_instance_->getIrohaInstance()->getQueryService()->Find( - qry.getTransport(), response); - auto query_response = - shared_model::proto::QueryResponse(std::move(response)); - - validation(query_response); - return *this; - } - - template - IntegrationTestFramework &IntegrationTestFramework::checkBlock( - Lambda validation) { - // fetch first from block queue - log_->info("check block"); - BlockType block; - fetchFromQueue(block_queue_, block, block_waiting, "missed block"); - validation(block); - return *this; - } - - template - IntegrationTestFramework &IntegrationTestFramework::checkProposal( - Lambda validation) { - log_->info("check proposal"); - // fetch first proposal from proposal queue - ProposalType proposal; - fetchFromQueue( - proposal_queue_, proposal, proposal_waiting, "missed proposal"); - validation(proposal); - return *this; - } - template void IntegrationTestFramework::fetchFromQueue( Queue &queue, diff --git a/test/framework/integration_framework/test_irohad.hpp b/test/framework/integration_framework/test_irohad.hpp index cf356dcbe9..e5f66157f4 100644 --- a/test/framework/integration_framework/test_irohad.hpp +++ b/test/framework/integration_framework/test_irohad.hpp @@ -76,6 +76,12 @@ namespace integration_framework { }); log_->info("===> iroha initialized"); } + + void terminate() { + if (internal_server) { + internal_server->shutdown(); + } + } }; } // namespace integration_framework diff --git a/test/integration/acceptance/transfer_asset_test.cpp b/test/integration/acceptance/transfer_asset_test.cpp index b7ecaa9e26..a64fb35e7c 100644 --- a/test/integration/acceptance/transfer_asset_test.cpp +++ b/test/integration/acceptance/transfer_asset_test.cpp @@ -306,7 +306,7 @@ TEST_F(TransferAsset, LongDesc) { .skipProposal() .skipBlock() .sendTx(invalid_tx, - [](shared_model::proto::TransactionResponse &status) { + [](const shared_model::proto::TransactionResponse &status) { // check if returned status is as expected ASSERT_NO_THROW(boost::get(status.get())); }) diff --git a/test/integration/pipeline/test_irohad.hpp b/test/integration/pipeline/test_irohad.hpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/regression/CMakeLists.txt b/test/regression/CMakeLists.txt new file mode 100644 index 0000000000..c3e22283c7 --- /dev/null +++ b/test/regression/CMakeLists.txt @@ -0,0 +1,6 @@ +addtest(regression_test regression_test.cpp) + +target_link_libraries(regression_test + application + integration_framework + ) diff --git a/test/regression/regression_test.cpp b/test/regression/regression_test.cpp new file mode 100644 index 0000000000..119908265c --- /dev/null +++ b/test/regression/regression_test.cpp @@ -0,0 +1,83 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "builders/protobuf/transaction.hpp" +#include "cryptography/crypto_provider/crypto_defaults.hpp" +#include "framework/integration_framework/integration_test_framework.hpp" +#include "interfaces/utils/specified_visitor.hpp" + +constexpr auto kUser = "user@test"; +constexpr auto kAsset = "asset#domain"; +const auto kAdminKeypair = + shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); + +/** + * @given ITF instance with Iroha + * @when existing ITF instance was not gracefully shutdown + * @then following ITF instantiation should not cause any errors + */ +TEST(RegressionTest, SequentialInitialization) { + auto tx = shared_model::proto::TransactionBuilder() + .createdTime(iroha::time::now()) + .creatorAccountId(kUser) + .addAssetQuantity(kUser, kAsset, "1.0") + .build() + .signAndAddSignature( + shared_model::crypto::DefaultCryptoAlgorithmType:: + generateKeypair()); + + auto checkStatelessValid = [](auto &status) { + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface:: + SpecifiedVisitor(), + status.get())); + }; + auto checkProposal = [](auto &proposal) { + ASSERT_EQ(proposal->transactions().size(), 1); + }; + auto checkBlock = [](auto &block) { + ASSERT_EQ(block->transactions().size(), 0); + }; + { + integration_framework::IntegrationTestFramework(10, [](auto &) {}) + .setInitialState(kAdminKeypair) + .sendTx(tx, checkStatelessValid) + .skipProposal() + .skipBlock(); + } + { + integration_framework::IntegrationTestFramework() + .setInitialState(kAdminKeypair) + .sendTx(tx, checkStatelessValid) + .checkProposal(checkProposal) + .checkBlock(checkBlock) + .done(); + } +} + +/** + * @given ITF instance with Iroha + * @when done method is called twice + * @then no errors are caused as the result + */ +TEST(RegressionTest, DoubleCallOfDone) { + integration_framework::IntegrationTestFramework itf; + itf.setInitialState(kAdminKeypair).done(); + itf.done(); +} From c93d30efb2a6f8e74837fbd4778e63b33a21bacd Mon Sep 17 00:00:00 2001 From: Kitsu Date: Tue, 1 May 2018 15:41:50 +0300 Subject: [PATCH 072/110] Use observable for OS proposal timeout (#1273) Signed-off-by: Kitsu --- irohad/main/impl/ordering_init.cpp | 19 +-- .../ordering/impl/ordering_service_impl.cpp | 24 +-- .../ordering/impl/ordering_service_impl.hpp | 26 +-- test/integration/CMakeLists.txt | 1 + test/integration/transport/CMakeLists.txt | 9 + .../transport}/ordering_gate_service_test.cpp | 99 +++++------ test/module/irohad/ordering/CMakeLists.txt | 7 - .../irohad/ordering/ordering_service_test.cpp | 156 ++++++++---------- 8 files changed, 136 insertions(+), 205 deletions(-) create mode 100644 test/integration/transport/CMakeLists.txt rename test/{module/irohad/ordering => integration/transport}/ordering_gate_service_test.cpp (80%) diff --git a/irohad/main/impl/ordering_init.cpp b/irohad/main/impl/ordering_init.cpp index 4febfa2ad3..8026947707 100644 --- a/irohad/main/impl/ordering_init.cpp +++ b/irohad/main/impl/ordering_init.cpp @@ -1,18 +1,6 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include "main/impl/ordering_init.hpp" @@ -42,7 +30,8 @@ namespace iroha { return std::make_shared( wsv, max_size, - delay_milliseconds.count(), + rxcpp::observable<>::interval(delay_milliseconds, + rxcpp::observe_on_new_thread()), transport, persistent_state); } diff --git a/irohad/ordering/impl/ordering_service_impl.cpp b/irohad/ordering/impl/ordering_service_impl.cpp index ed65a6dbce..84bded1186 100644 --- a/irohad/ordering/impl/ordering_service_impl.cpp +++ b/irohad/ordering/impl/ordering_service_impl.cpp @@ -1,18 +1,6 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include "ordering/impl/ordering_service_impl.hpp" @@ -30,14 +18,13 @@ namespace iroha { OrderingServiceImpl::OrderingServiceImpl( std::shared_ptr wsv, size_t max_size, - size_t delay_milliseconds, + rxcpp::observable proposal_timeout, std::shared_ptr transport, std::shared_ptr persistent_state, bool is_async) : wsv_(wsv), max_size_(max_size), - delay_milliseconds_(delay_milliseconds), transport_(transport), persistent_state_(persistent_state) { log_ = logger::log("OrderingServiceImpl"); @@ -46,10 +33,7 @@ namespace iroha { proposal_height_ = persistent_state_->loadProposalHeight().value(); rxcpp::observable timer = - rxcpp::observable<>::interval( - std::chrono::milliseconds(delay_milliseconds_), - rxcpp::observe_on_new_thread()) - .map([](auto) { return ProposalEvent::kTimerEvent; }); + proposal_timeout.map([](auto) { return ProposalEvent::kTimerEvent; }); auto subscribe = [&](auto merge_strategy) { handle_ = merge_strategy(rxcpp::observable<>::from( diff --git a/irohad/ordering/impl/ordering_service_impl.hpp b/irohad/ordering/impl/ordering_service_impl.hpp index 0549274c87..88b3948d7c 100644 --- a/irohad/ordering/impl/ordering_service_impl.hpp +++ b/irohad/ordering/impl/ordering_service_impl.hpp @@ -1,18 +1,6 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #ifndef IROHA_ORDERING_SERVICE_IMPL_HPP @@ -44,11 +32,12 @@ namespace iroha { */ class OrderingServiceImpl : public network::OrderingService { public: + using TimeoutType = long; /** * Constructor * @param wsv interface for fetching peers from world state view * @param max_size maximum size of proposal - * @param delay_milliseconds timeout for proposal generation + * @param proposal_timeout observable timeout for proposal creation * @param transport receive transactions and publish proposals * @param persistent_state storage for auxiliary information * @param is_async whether proposals are generated in a separate thread @@ -56,7 +45,7 @@ namespace iroha { OrderingServiceImpl( std::shared_ptr wsv, size_t max_size, - size_t delay_milliseconds, + rxcpp::observable proposal_timeout, std::shared_ptr transport, std::shared_ptr persistent_state, @@ -103,11 +92,6 @@ namespace iroha { */ const size_t max_size_; - /** - * wait for specified time if queue is empty - */ - const size_t delay_milliseconds_; - std::shared_ptr transport_; /** diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index ded6a88c2a..a63e3c16a3 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -18,3 +18,4 @@ add_subdirectory(acceptance) add_subdirectory(consensus) add_subdirectory(pipeline) +add_subdirectory(transport) diff --git a/test/integration/transport/CMakeLists.txt b/test/integration/transport/CMakeLists.txt new file mode 100644 index 0000000000..8d8617e791 --- /dev/null +++ b/test/integration/transport/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright Soramitsu Co., Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +addtest(ordering_gate_service_test ordering_gate_service_test.cpp) +target_link_libraries(ordering_gate_service_test + ordering_service + shared_model_stateless_validation + shared_model_cryptography_model + ) diff --git a/test/module/irohad/ordering/ordering_gate_service_test.cpp b/test/integration/transport/ordering_gate_service_test.cpp similarity index 80% rename from test/module/irohad/ordering/ordering_gate_service_test.cpp rename to test/integration/transport/ordering_gate_service_test.cpp index 147b8bcb05..108cd57dd1 100644 --- a/test/module/irohad/ordering/ordering_gate_service_test.cpp +++ b/test/integration/transport/ordering_gate_service_test.cpp @@ -20,9 +20,9 @@ #include "builders/protobuf/common_objects/proto_peer_builder.hpp" #include "builders/protobuf/transaction.hpp" #include "framework/test_subscriber.hpp" -#include "mock_ordering_service_persistent_state.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/network/network_mocks.hpp" +#include "module/irohad/ordering/mock_ordering_service_persistent_state.hpp" #include "module/shared_model/builders/protobuf/test_block_builder.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "ordering/impl/ordering_gate_impl.hpp" @@ -59,7 +59,6 @@ class OrderingGateServiceTest : public ::testing::Test { gate_transport->subscribe(gate); service_transport = std::make_shared(); - counter = 2; wsv = std::make_shared(); } @@ -69,6 +68,16 @@ class OrderingGateServiceTest : public ::testing::Test { std::make_shared(); } + void initOs(size_t max_proposal) { + service = + std::make_shared(wsv, + max_proposal, + proposal_timeout.get_observable(), + service_transport, + fake_persistent_state); + service_transport->subscribe(service); + } + void start() { std::mutex mtx; std::condition_variable cv; @@ -104,10 +113,6 @@ class OrderingGateServiceTest : public ::testing::Test { TestSubscriber> init( size_t times) { auto wrapper = make_test_subscriber(gate->on_proposal(), times); - gate->on_proposal().subscribe([this](auto) { - counter--; - cv.notify_one(); - }); gate->on_proposal().subscribe([this](auto proposal) { proposals.push_back(proposal); // emulate commit event after receiving the proposal to perform next @@ -117,7 +122,8 @@ class OrderingGateServiceTest : public ::testing::Test { TestBlockBuilder().height(proposal->height()).build()); commit_subject_.get_subscriber().on_next( rxcpp::observable<>::just(block)); - + counter--; + cv.notify_one(); }); wrapper.subscribe(); return wrapper; @@ -142,6 +148,15 @@ class OrderingGateServiceTest : public ::testing::Test { std::this_thread::sleep_for(20ms); } + void makeProposalTimeout() { + proposal_timeout.get_subscriber().on_next(0); + } + + void waitForGate() { + std::unique_lock lk(m); + cv.wait_for(lk, 10s, [this] { return counter == 0; }); + } + std::string address{"0.0.0.0:50051"}; std::shared_ptr gate; std::shared_ptr service; @@ -150,6 +165,7 @@ class OrderingGateServiceTest : public ::testing::Test { /// commits for Ordering Service std::shared_ptr pcs_; rxcpp::subjects::subject commit_subject_; + rxcpp::subjects::subject proposal_timeout; std::vector> proposals; std::atomic counter; @@ -166,24 +182,20 @@ class OrderingGateServiceTest : public ::testing::Test { }; /** - * @given Ordering service + * @given Ordering Service * @when Send 8 transactions * AND 2 transactions to OS * @then Received proposal with 8 transactions * AND proposal with 2 transactions */ -TEST_F(OrderingGateServiceTest, SplittingBunchTransactions) { - // 8 transaction -> proposal -> 2 transaction -> proposal - EXPECT_CALL(*wsv, getLedgerPeers()) - .WillRepeatedly(Return(std::vector{peer})); - +TEST_F(OrderingGateServiceTest, DISABLED_SplittingBunchTransactions) { const size_t max_proposal = 100; - const size_t commit_delay = 400; + EXPECT_CALL(*wsv, getLedgerPeers()) + .WillRepeatedly(Return(std::vector{peer})); EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(2))); - EXPECT_CALL(*fake_persistent_state, saveProposalHeight(3)) .Times(1) .WillOnce(Return(true)); @@ -191,52 +203,40 @@ TEST_F(OrderingGateServiceTest, SplittingBunchTransactions) { .Times(1) .WillOnce(Return(true)); - service = std::make_shared(wsv, - max_proposal, - commit_delay, - service_transport, - fake_persistent_state); - service_transport->subscribe(service); - + initOs(max_proposal); start(); - std::unique_lock lk(m); auto wrapper = init(2); + counter = 2; for (size_t i = 0; i < 8; ++i) { send_transaction(i + 1); } - cv.wait_for(lk, 10s); + makeProposalTimeout(); send_transaction(9); send_transaction(10); - cv.wait_for(lk, 10s); + makeProposalTimeout(); - std::this_thread::sleep_for(1s); + waitForGate(); ASSERT_EQ(proposals.size(), 2); ASSERT_EQ(proposals.at(0)->transactions().size(), 8); ASSERT_EQ(proposals.at(1)->transactions().size(), 2); - ASSERT_EQ(counter, 0); ASSERT_TRUE(wrapper.validate()); } /** - * @given ordering service - * @when a bunch of transaction has arrived - * @then split transactions on to two proposal + * @given Ordering Service with max proposal 5 + * @when Two bunches of 5 tx has been sent + * @then Transactions are splitted in two proposals by 5 tx each */ -TEST_F(OrderingGateServiceTest, ProposalsReceivedWhenProposalSize) { - // commits on the fulfilling proposal queue - // 10 transaction -> proposal with 5 -> proposal with 5 - EXPECT_CALL(*wsv, getLedgerPeers()) - .WillRepeatedly(Return(std::vector{peer})); - +TEST_F(OrderingGateServiceTest, DISABLED_ProposalsReceivedWhenProposalSize) { const size_t max_proposal = 5; - const size_t commit_delay = 1000; + EXPECT_CALL(*wsv, getLedgerPeers()) + .WillRepeatedly(Return(std::vector{peer})); EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(2))); - EXPECT_CALL(*fake_persistent_state, saveProposalHeight(3)) .Times(1) .WillOnce(Return(true)); @@ -244,29 +244,18 @@ TEST_F(OrderingGateServiceTest, ProposalsReceivedWhenProposalSize) { .Times(1) .WillOnce(Return(true)); - service = std::make_shared(wsv, - max_proposal, - commit_delay, - service_transport, - fake_persistent_state); - service_transport->subscribe(service); - + initOs(max_proposal); start(); - std::unique_lock lk(m); auto wrapper = init(2); + counter = 2; for (size_t i = 0; i < 10; ++i) { send_transaction(i + 1); } - // long == something wrong - cv.wait_for(lk, 10s, [this]() { return counter == 0; }); - - ASSERT_TRUE(wrapper.validate()); + waitForGate(); ASSERT_EQ(proposals.size(), 2); - ASSERT_EQ(counter, 0); - - for (auto &&proposal : proposals) { - ASSERT_EQ(proposal->transactions().size(), 5); - } + ASSERT_EQ(proposals.at(0)->transactions().size(), 5); + ASSERT_EQ(proposals.at(1)->transactions().size(), 5); + ASSERT_TRUE(wrapper.validate()); } diff --git a/test/module/irohad/ordering/CMakeLists.txt b/test/module/irohad/ordering/CMakeLists.txt index 943e5d3519..6193e3b988 100644 --- a/test/module/irohad/ordering/CMakeLists.txt +++ b/test/module/irohad/ordering/CMakeLists.txt @@ -24,10 +24,3 @@ target_link_libraries(ordering_gate_test shared_model_cryptography_model shared_model_stateless_validation ) - -addtest(ordering_gate_service_test ordering_gate_service_test.cpp) -target_link_libraries(ordering_gate_service_test - ordering_service - shared_model_stateless_validation - shared_model_cryptography_model - ) diff --git a/test/module/irohad/ordering/ordering_service_test.cpp b/test/module/irohad/ordering/ordering_service_test.cpp index f34857ef58..e8ca3b585c 100644 --- a/test/module/irohad/ordering/ordering_service_test.cpp +++ b/test/module/irohad/ordering/ordering_service_test.cpp @@ -1,18 +1,6 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include @@ -42,8 +30,6 @@ using ::testing::Invoke; using ::testing::InvokeWithoutArgs; using ::testing::Return; -static logger::Logger log_ = logger::testLog("OrderingService"); - class MockOrderingServiceTransport : public network::OrderingServiceTransport { public: void subscribe(std::shared_ptr @@ -93,13 +79,18 @@ class OrderingServiceTest : public ::testing::Test { generateKeypair())); } - auto initOs(size_t max_proposal, size_t commit_delay) { - return std::make_shared(wsv, - max_proposal, - commit_delay, - fake_transport, - fake_persistent_state, - false); + auto initOs(size_t max_proposal) { + return std::make_shared( + wsv, + max_proposal, + proposal_timeout.get_observable(), + fake_transport, + fake_persistent_state, + false); + } + + void makeProposalTimeout() { + proposal_timeout.get_subscriber().on_next(0); } std::shared_ptr fake_transport; @@ -109,24 +100,25 @@ class OrderingServiceTest : public ::testing::Test { std::string address{"0.0.0.0:50051"}; std::shared_ptr peer; std::shared_ptr wsv; + rxcpp::subjects::subject proposal_timeout; }; +/** + * @given OrderingService and MockOrderingServiceTransport + * @when publishProposal is called at transport + * @then publishProposalProxy is called + */ TEST_F(OrderingServiceTest, SimpleTest) { - // Direct publishProposal call, used for basic case test and for debug - // simplicity - const size_t max_proposal = 5; - const size_t commit_delay = 1000; EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(2))); + EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(1); - auto ordering_service = initOs(max_proposal, commit_delay); + auto ordering_service = initOs(max_proposal); fake_transport->subscribe(ordering_service); - EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(1); - fake_transport->publishProposal( std::make_unique( TestProposalBuilder() @@ -136,9 +128,17 @@ TEST_F(OrderingServiceTest, SimpleTest) { {}); } +/** + * @given OrderingService with max_proposal==5 and only self peer + * and MockOrderingServiceTransport + * and MockOrderingServicePersistentState + * @when OrderingService::onTransaction called 10 times + * @then publishProposalProxy called twice + * and proposal height was loaded once and saved twice + */ TEST_F(OrderingServiceTest, ValidWhenProposalSizeStrategy) { const size_t max_proposal = 5; - const size_t commit_delay = 1000; + const size_t tx_num = 10; EXPECT_CALL(*fake_persistent_state, saveProposalHeight(_)) .Times(2) @@ -146,85 +146,64 @@ TEST_F(OrderingServiceTest, ValidWhenProposalSizeStrategy) { EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(2))); - - auto ordering_service = initOs(max_proposal, commit_delay); - fake_transport->subscribe(ordering_service); - - // Init => proposal size 5 => 2 proposals after 10 transactions - size_t call_count = 0; EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)) - .Times(2) - .WillRepeatedly(InvokeWithoutArgs([&] { - ++call_count; - cv.notify_one(); - })); - - shared_model::proto::PeerBuilder builder; - - auto key = shared_model::crypto::PublicKey(peer->pubkey().toString()); - auto tmp = builder.address(peer->address()).pubkey(key).build(); - + .Times(tx_num / max_proposal); EXPECT_CALL(*wsv, getLedgerPeers()) .WillRepeatedly(Return(std::vector{peer})); - for (size_t i = 0; i < 10; ++i) { + auto ordering_service = initOs(max_proposal); + fake_transport->subscribe(ordering_service); + + for (size_t i = 0; i < tx_num; ++i) { ordering_service->onTransaction(getTx()); } - - std::unique_lock lock(m); - cv.wait_for(lock, 10s, [&] { return call_count == 2; }); } +/** + * @given OrderingService with big enough max_proposal and only self peer + * and MockOrderingServiceTransport + * and MockOrderingServicePersistentState + * @when OrderingService::onTransaction called 8 times + * and after triggered timeout + * and then repeat with 2 onTransaction calls + * @then publishProposalProxy called twice + * and proposal height was loaded once and saved twice + */ TEST_F(OrderingServiceTest, ValidWhenTimerStrategy) { - // Init => proposal timer 400 ms => 10 tx by 50 ms => 2 proposals in 1 second + const size_t max_proposal = 100; + EXPECT_CALL(*fake_persistent_state, saveProposalHeight(_)) .Times(2) .WillRepeatedly(Return(true)); - shared_model::proto::PeerBuilder builder; - - auto key = shared_model::crypto::PublicKey(peer->pubkey().toString()); - auto tmp = builder.address(peer->address()).pubkey(key).build(); - - EXPECT_CALL(*wsv, getLedgerPeers()) - .WillRepeatedly(Return(std::vector{peer})); - - const size_t max_proposal = 100; - const size_t commit_delay = 400; - EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(2))); + EXPECT_CALL(*wsv, getLedgerPeers()) + .WillRepeatedly(Return(std::vector{peer})); + EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(2); - auto ordering_service = initOs(max_proposal, commit_delay); + auto ordering_service = initOs(max_proposal); fake_transport->subscribe(ordering_service); - EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)) - .Times(2) - .WillRepeatedly(InvokeWithoutArgs([&] { - log_->info("Proposal send to grpc"); - cv.notify_one(); - })); - for (size_t i = 0; i < 8; ++i) { ordering_service->onTransaction(getTx()); } - - std::unique_lock lk(m); - cv.wait_for(lk, 10s); + makeProposalTimeout(); ordering_service->onTransaction(getTx()); ordering_service->onTransaction(getTx()); - cv.wait_for(lk, 10s); + makeProposalTimeout(); } /** - * @given Ordering service and the persistent state that cannot save proposals + * @given Ordering service and the persistent state that cannot save + * proposals * @when onTransaction is called * @then no published proposal */ TEST_F(OrderingServiceTest, BrokenPersistentState) { const size_t max_proposal = 1; - const size_t commit_delay = 100; + EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(1))); @@ -232,11 +211,9 @@ TEST_F(OrderingServiceTest, BrokenPersistentState) { .Times(1) .WillRepeatedly(Return(false)); - auto ordering_service = initOs(max_proposal, commit_delay); + auto ordering_service = initOs(max_proposal); ordering_service->onTransaction(getTx()); - - std::unique_lock lk(m); - cv.wait_for(lk, 2s); + makeProposalTimeout(); } /** @@ -246,15 +223,13 @@ TEST_F(OrderingServiceTest, BrokenPersistentState) { */ TEST_F(OrderingServiceTest, ConcurrentGenerateProposal) { const auto max_proposal = 1; - const auto commit_delay = 100; EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(1))); EXPECT_CALL(*fake_persistent_state, saveProposalHeight(_)) .WillRepeatedly(Return(false)); - auto ordering_service = std::make_shared( - wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + auto ordering_service = initOs(max_proposal); auto on_tx = [&]() { for (int i = 0; i < 1000; ++i) { @@ -272,6 +247,7 @@ TEST_F(OrderingServiceTest, ConcurrentGenerateProposal) { for (int i = 0; i < num_threads; ++i) { threads.at(i).join(); } + makeProposalTimeout(); } /** @@ -284,7 +260,7 @@ TEST_F(OrderingServiceTest, ConcurrentGenerateProposal) { */ TEST_F(OrderingServiceTest, GenerateProposalDestructor) { const auto max_proposal = 100000; - const auto commit_delay = 100; + const auto commit_delay = 100ms; EXPECT_CALL(*fake_persistent_state, loadProposalHeight()) .Times(1) .WillOnce(Return(boost::optional(1))); @@ -299,7 +275,13 @@ TEST_F(OrderingServiceTest, GenerateProposalDestructor) { { EXPECT_CALL(*fake_transport, publishProposalProxy(_, _)).Times(AtLeast(1)); OrderingServiceImpl ordering_service( - wsv, max_proposal, commit_delay, fake_transport, fake_persistent_state); + wsv, + max_proposal, + rxcpp::observable<>::interval(commit_delay, + rxcpp::observe_on_new_thread()), + fake_transport, + fake_persistent_state, + true); auto on_tx = [&]() { for (int i = 0; i < 1000; ++i) { From 307e3995d949ad175f885978ce2e0587a98d80fb Mon Sep 17 00:00:00 2001 From: Arseniy Fokin Date: Wed, 2 May 2018 15:59:06 +0700 Subject: [PATCH 073/110] Change paths to use Shared Model in NPM (#1285) * Change pathes to use Shared Model * Return missing libs Signed-off-by: Arseniy Fokin --- shared_model/packages/javascript/binding.gyp | 48 ++++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/shared_model/packages/javascript/binding.gyp b/shared_model/packages/javascript/binding.gyp index 644d6fd768..d687b77dd7 100644 --- a/shared_model/packages/javascript/binding.gyp +++ b/shared_model/packages/javascript/binding.gyp @@ -1,6 +1,6 @@ { 'variables': { - 'iroha_home_dir': '../../../' + 'iroha_lib_dir': '../../' }, 'targets': [ { @@ -11,18 +11,17 @@ 'action_name': 'configure', 'message': 'Generate CMake build configuration for shared_model...', 'inputs': [ - '<(iroha_home_dir)/shared_model/bindings/CMakeLists.txt' + '<(iroha_lib_dir)/bindings/CMakeLists.txt' ], 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/Makefile', + '<(SHARED_INTERMEDIATE_DIR)/bindings/Makefile', ], 'action': [ 'cmake', - '-H<(iroha_home_dir)', + '-H<(iroha_lib_dir)', '-B<(SHARED_INTERMEDIATE_DIR)', '-DSWIG_NODE=ON', '-DENABLE_LIBS_PACKAGING=OFF', - '-DSHARED_MODEL_DISABLE_COMPATIBILITY=ON', '-DCMAKE_POSITION_INDEPENDENT_CODE=ON', '-DCMAKE_BUILD_TYPE=Release' ], @@ -31,12 +30,12 @@ 'action_name': 'build', 'message': 'Build shared_model libraries by CMake...', 'inputs': [ - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/Makefile', + '<(SHARED_INTERMEDIATE_DIR)/bindings/Makefile', ], 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/bindingsJAVASCRIPT_wrap.cxx', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/libirohanode.a', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/libbindings.a' + '<(SHARED_INTERMEDIATE_DIR)/bindings/bindingsJAVASCRIPT_wrap.cxx', + '<(SHARED_INTERMEDIATE_DIR)/bindings/libirohanode.a', + '<(SHARED_INTERMEDIATE_DIR)/bindings/libbindings.a' ], 'action': [ 'cmake', @@ -53,20 +52,19 @@ 'copies': [ { 'files': [ - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/libirohanode.a', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/libbindings.a', + '<(SHARED_INTERMEDIATE_DIR)/bindings/libirohanode.a', + '<(SHARED_INTERMEDIATE_DIR)/bindings/libbindings.a', + '<(SHARED_INTERMEDIATE_DIR)/generator/libgenerator.a', + '<(SHARED_INTERMEDIATE_DIR)/amount/libiroha_amount.a', '<(SHARED_INTERMEDIATE_DIR)/schema/libschema.a', - '<(SHARED_INTERMEDIATE_DIR)/libs/generator/libgenerator.a', - '<(SHARED_INTERMEDIATE_DIR)/libs/amount/libiroha_amount.a', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/validators/libshared_model_stateless_validation.a', - # Cryptography libs - '<(SHARED_INTERMEDIATE_DIR)/shared_model/cryptography/ed25519_sha3_impl/libshared_model_cryptography.a', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/cryptography/ed25519_sha3_impl/internal/libhash.a', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/cryptography/ed25519_sha3_impl/internal/libed25519_crypto.a', - '<(SHARED_INTERMEDIATE_DIR)/shared_model/cryptography/model_impl/libshared_model_cryptography_model.a', + '<(SHARED_INTERMEDIATE_DIR)/validators/libshared_model_stateless_validation.a', + '<(SHARED_INTERMEDIATE_DIR)/cryptography/ed25519_sha3_impl/libshared_model_cryptography.a', + '<(SHARED_INTERMEDIATE_DIR)/cryptography/ed25519_sha3_impl/internal/libhash.a', + '<(SHARED_INTERMEDIATE_DIR)/cryptography/ed25519_sha3_impl/internal/libed25519_crypto.a', + '<(SHARED_INTERMEDIATE_DIR)/cryptography/model_impl/libshared_model_cryptography_model.a', # Third-party libraries - '<(iroha_home_dir)/external/src/hyperledger_ed25519-build/libed25519.a' + '<(iroha_lib_dir)/external/src/hyperledger_ed25519-build/libed25519.a' ], 'destination': '<(PRODUCT_DIR)' } @@ -76,12 +74,14 @@ 'target_name': '<(module_name)', 'dependencies': [ 'shared_model' ], 'include_dirs': [ - '<(iroha_home_dir)/shared_model', - '<(iroha_home_dir)/libs', - '<(iroha_home_dir)/schema' + '<(iroha_lib_dir)', + # TODO: Remove these include directories when Shared Model + # will be completely separated from Iroha + '<(iroha_lib_dir)/../schema', + '<(iroha_lib_dir)/../libs' ], 'sources': [ - '<(SHARED_INTERMEDIATE_DIR)/shared_model/bindings/bindingsJAVASCRIPT_wrap.cxx' + '<(SHARED_INTERMEDIATE_DIR)/bindings/bindingsJAVASCRIPT_wrap.cxx' ], 'cflags_cc': ['-std=c++14', '-fexceptions', '-DDISABLE_BACKWARD'], 'cflags_cc!': ['-fno-rtti'], From 6d07cf612864f424be07cc24c02bd9177e296c45 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bikbaev Date: Thu, 3 May 2018 11:17:31 +0300 Subject: [PATCH 074/110] fix: fixed docker image in getting_started, removed trailing spaces (#1292) Signed-off-by: Vyacheslav Bikbaev --- docs/source/getting_started/index.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index dc966ebded..4d7b8cb580 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -15,7 +15,7 @@ things simple, we will use Docker. Prerequisites ------------- For this guide, you need a computer running Unix-like system with ``docker`` -installed. You can read how to install it on a +installed. You can read how to install it on a `Docker's website `_. .. note:: Please note that you can use Iroha without ``docker`` as well. You @@ -76,10 +76,10 @@ Configuring Iroha Network this guide. Now we need to configure our Iroha network. This includes creating a -configuration file, generating keypairs for a users, writing a list of peers +configuration file, generating keypairs for a users, writing a list of peers and creating a genesis block. However, we have prepared an example -configuration for this guide, so you can start playing with Iroha faster. -In order to get those files, you need to clone the +configuration for this guide, so you can start playing with Iroha faster. +In order to get those files, you need to clone the `Iroha repository `_ from Github. .. code-block:: shell @@ -103,7 +103,7 @@ command -v blockstore:/tmp/block_store \ --network=iroha-network \ --entrypoint=/bin/bash \ - hyperledger/iroha:x86_64-develop-latest + hyperledger/iroha:develop Let's look in detail what this command does: @@ -119,7 +119,7 @@ Let's look in detail what this command does: - ``--entrypoint=/bin/bash \`` Because ``hyperledger/iroha`` has the custom script which runs after starting the container, we want to override it so we can start Iroha Daemon manually. -- ``hyperledger/iroha:x86_64-develop-latest`` is the image which has the ``develop`` +- ``hyperledger/iroha:develop`` is the image which has the ``develop`` branch. Launching Iroha Daemon @@ -178,7 +178,7 @@ account to work with Iroha. .. note:: Full account name has a ``@`` symbol between name and domain. Note that the keypair has the same name. - + Creating the First Transaction ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ Quantity (add_ast_qty)``, enter Account ID – ``admin@test``, asset ID – .. note:: Full asset name has a ``#`` symbol between name and domain. -Let's transfer 100.50 ``coolcoins`` from ``admin@test`` to ``test@test`` +Let's transfer 100.50 ``coolcoins`` from ``admin@test`` to ``test@test`` by adding one more command and choosing ``5. Transfer Assets (tran_ast)``. Enter Source Account and Destination Account, in our case ``admin@test`` and ``test@test``, Asset ID (``coolcoin#test``), integer part and precision @@ -225,7 +225,7 @@ Congratulations! You have submitted your first transaction to Iroha. Creating the First Query ^^^^^^^^^^^^^^^^^^^^^^^^ -Now let's check if ``coolcoins`` were successfully transferred from +Now let's check if ``coolcoins`` were successfully transferred from ``admin@test`` to ``test@test``. Choose ``2. New query (qry)``. ``7. Get Account's Assets (get_acc_ast)`` can help you to check if ``test@test`` now has ``coolcoin``. Form a query in a similar way you did with @@ -257,7 +257,7 @@ Account, in our case ``admin@test`` and ``test@test``, Asset ID (``coolcoin#test``), integer part and precision (``10000000`` and ``2`` accordingly). Send a transaction to Iroha peer as you did before. Well, it says -.. code:: +.. code:: [2018-03-21 12:58:40.791297963][th:520][info] TransactionResponseHandler Transaction successfully sent Congratulation, your transaction was accepted for processing. @@ -269,11 +269,11 @@ had successfully cheated Iroha? Let's try to see transaction's status. Choose you can get in the console after the previous command. Let's send it to Iroha. It replies with: -.. code:: +.. code:: Transaction has not passed stateful validation. Apparently no. Our transaction was not accepted because it did not pass stateful validation and ``coolcoins`` were not transferred. You can check -the status of ``admin@test`` and ``test@test`` with queries to be sure +the status of ``admin@test`` and ``test@test`` with queries to be sure (like we did earlier). From cd65d95ae8194e9f18a585b3daf79425e114bdfc Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 3 May 2018 16:41:33 +0300 Subject: [PATCH 075/110] Make block loader, consensus, ordering service use own peer query (#1293) Signed-off-by: Andrei Lebedev --- irohad/main/application.cpp | 19 +++++++++++-------- irohad/main/application.hpp | 5 +---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/irohad/main/application.cpp b/irohad/main/application.cpp index 1fe494b299..b383b48233 100644 --- a/irohad/main/application.cpp +++ b/irohad/main/application.cpp @@ -126,10 +126,8 @@ bool Irohad::restoreWsv() { /** * Initializing peer query interface */ -void Irohad::initPeerQuery() { - wsv = std::make_shared(storage->getWsvQuery()); - - log_->info("[Init] => peer query"); +std::unique_ptr Irohad::initPeerQuery() { + return std::make_unique(storage->getWsvQuery()); } /** @@ -157,7 +155,7 @@ void Irohad::initValidators() { * Initializing ordering gate */ void Irohad::initOrderingGate() { - ordering_gate = ordering_init.initOrderingGate(wsv, + ordering_gate = ordering_init.initOrderingGate(initPeerQuery(), max_proposal_size_, proposal_delay_, ordering_service_storage_, @@ -183,7 +181,8 @@ void Irohad::initSimulator() { * Initializing block loader */ void Irohad::initBlockLoader() { - block_loader = loader_init.initBlockLoader(wsv, storage->getBlockQuery()); + block_loader = + loader_init.initBlockLoader(initPeerQuery(), storage->getBlockQuery()); log_->info("[Init] => block loader"); } @@ -192,8 +191,12 @@ void Irohad::initBlockLoader() { * Initializing consensus gate */ void Irohad::initConsensusGate() { - consensus_gate = yac_init.initConsensusGate( - wsv, simulator, block_loader, keypair, vote_delay_, load_delay_); + consensus_gate = yac_init.initConsensusGate(initPeerQuery(), + simulator, + block_loader, + keypair, + vote_delay_, + load_delay_); log_->info("[Init] => consensus gate"); } diff --git a/irohad/main/application.hpp b/irohad/main/application.hpp index 59daf94786..77ca494c09 100644 --- a/irohad/main/application.hpp +++ b/irohad/main/application.hpp @@ -112,7 +112,7 @@ class Irohad { virtual void initStorage(); - virtual void initPeerQuery(); + virtual std::unique_ptr initPeerQuery(); virtual void initCryptoProvider(); @@ -158,9 +158,6 @@ class Irohad { std::shared_ptr stateful_validator; std::shared_ptr chain_validator; - // peer query - std::shared_ptr wsv; - // WSV restorer std::shared_ptr wsv_restorer_; From 85b65e4aa60fa9296ac3b168c33814e7df0fb77d Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 3 May 2018 17:39:36 +0300 Subject: [PATCH 076/110] Remove signature generator and random_number with rand_r (#1294) Signed-off-by: Andrei Lebedev --- irohad/model/generators/CMakeLists.txt | 1 - .../generators/impl/signature_generator.cpp | 35 ------------------- libs/generator/generator.cpp | 5 --- libs/generator/generator.hpp | 5 --- .../converters/json_query_factory_test.cpp | 15 ++------ 5 files changed, 2 insertions(+), 59 deletions(-) delete mode 100644 irohad/model/generators/impl/signature_generator.cpp diff --git a/irohad/model/generators/CMakeLists.txt b/irohad/model/generators/CMakeLists.txt index 90df2ed84f..7c05584618 100644 --- a/irohad/model/generators/CMakeLists.txt +++ b/irohad/model/generators/CMakeLists.txt @@ -16,7 +16,6 @@ # add_library(model_generators - impl/signature_generator.cpp impl/block_generator.cpp impl/transaction_generator.cpp impl/command_generator.cpp diff --git a/irohad/model/generators/impl/signature_generator.cpp b/irohad/model/generators/impl/signature_generator.cpp deleted file mode 100644 index e5ea681e27..0000000000 --- a/irohad/model/generators/impl/signature_generator.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "model/generators/signature_generator.hpp" - -namespace iroha { - namespace model { - namespace generators { - - Signature generateSignature(size_t seed) { - Signature sign; - // sign.pubkey - sign.pubkey = generator::random_blob(seed); - sign.signature = generator::random_blob( - generator::random_number(0, seed)); - return sign; - } - - } // namespace generators - } // namespace model -} // namespace iroha diff --git a/libs/generator/generator.cpp b/libs/generator/generator.cpp index a5af77d2f2..7e2ffbcdc1 100644 --- a/libs/generator/generator.cpp +++ b/libs/generator/generator.cpp @@ -19,11 +19,6 @@ namespace generator { - int64_t random_number(int64_t min, int64_t max) { - uint32_t SEED_ = 1337; - return min + (rand_r(&SEED_) % (max - min)); - } - std::string randomString(size_t len) { std::string str(len, 0); std::generate_n( diff --git a/libs/generator/generator.hpp b/libs/generator/generator.hpp index 2d78bd821a..43ac3816b5 100644 --- a/libs/generator/generator.hpp +++ b/libs/generator/generator.hpp @@ -24,11 +24,6 @@ namespace generator { - /** - * returns a number in a range [min, max) - */ - int64_t random_number(int64_t min, int64_t max); - template iroha::blob_t random_blob(size_t seed) { iroha::blob_t v; diff --git a/test/module/irohad/model/converters/json_query_factory_test.cpp b/test/module/irohad/model/converters/json_query_factory_test.cpp index 5d5826fee3..226e9a4895 100644 --- a/test/module/irohad/model/converters/json_query_factory_test.cpp +++ b/test/module/irohad/model/converters/json_query_factory_test.cpp @@ -101,8 +101,7 @@ TEST(QuerySerializerTest, DeserializeGetAccountAssetsWhenValid) { })"; auto res = querySerializer.deserialize(json_query); ASSERT_TRUE(res); - auto casted = - std::static_pointer_cast(*res); + auto casted = std::static_pointer_cast(*res); ASSERT_EQ("test@test", casted->account_id); ASSERT_EQ("coin#test", casted->asset_id); } @@ -127,8 +126,7 @@ TEST(QuerySerializerTest, DeserializeGetAccountDetailWhenValid) { })"; auto res = querySerializer.deserialize(json_query); ASSERT_TRUE(res); - auto casted = - std::static_pointer_cast(*res); + auto casted = std::static_pointer_cast(*res); ASSERT_EQ("test@test", casted->account_id); } @@ -162,7 +160,6 @@ TEST(QuerySerialzierTest, DeserializeGetTransactionsWithInvalidHash) { QueryGenerator queryGenerator; const auto val = queryGenerator.generateGetTransactions(0, "123", 0, {valid_size_hash}); - val->signature = generateSignature(42); const auto json = queryFactory.serialize(val); auto json_doc_opt = iroha::model::converters::stringToJson(json); ASSERT_TRUE(json_doc_opt); @@ -194,7 +191,6 @@ TEST(QuerySerializerTest, SerializeGetAccount) { JsonQueryFactory queryFactory; QueryGenerator queryGenerator; auto val = queryGenerator.generateGetAccount(0, "123", 0, "test"); - val->signature = generateSignature(42); auto json = queryFactory.serialize(val); auto ser_val = queryFactory.deserialize(json); ASSERT_TRUE(ser_val); @@ -207,7 +203,6 @@ TEST(QuerySerializerTest, SerializeGetAccountAssets) { QueryGenerator queryGenerator; auto val = queryGenerator.generateGetAccountAssets(0, "123", 0, "test", "coin"); - val->signature = generateSignature(42); auto json = queryFactory.serialize(val); auto ser_val = queryFactory.deserialize(json); ASSERT_TRUE(ser_val); @@ -219,7 +214,6 @@ TEST(QuerySerializerTest, SerializeGetAccountTransactions) { JsonQueryFactory queryFactory; QueryGenerator queryGenerator; auto val = queryGenerator.generateGetAccountTransactions(0, "123", 0, "test"); - val->signature = generateSignature(42); auto json = queryFactory.serialize(val); auto ser_val = queryFactory.deserialize(json); ASSERT_TRUE(ser_val); @@ -233,7 +227,6 @@ TEST(QuerySerializerTest, SerialiizeGetTransactions) { hash1[0] = 1, hash2[0] = 2; auto val = queryGenerator.generateGetTransactions(0, "admin", 0, {hash1, hash2}); - val->signature = generateSignature(42); runQueryTest(val); } @@ -241,7 +234,6 @@ TEST(QuerySerializerTest, SerializeGetSignatories) { JsonQueryFactory queryFactory; QueryGenerator queryGenerator; auto val = queryGenerator.generateGetSignatories(0, "123", 0, "test"); - val->signature = generateSignature(42); auto json = queryFactory.serialize(val); auto ser_val = queryFactory.deserialize(json); ASSERT_TRUE(ser_val); @@ -252,20 +244,17 @@ TEST(QuerySerializerTest, SerializeGetSignatories) { TEST(QuerySerializerTest, get_asset_info) { QueryGenerator queryGenerator; auto val = queryGenerator.generateGetAssetInfo(); - val->signature = generateSignature(42); runQueryTest(val); } TEST(QuerySerializerTest, get_roles) { QueryGenerator queryGenerator; auto val = queryGenerator.generateGetRoles(); - val->signature = generateSignature(42); runQueryTest(val); } TEST(QuerySerializerTest, get_role_permissions) { QueryGenerator queryGenerator; auto val = queryGenerator.generateGetRolePermissions(); - val->signature = generateSignature(42); runQueryTest(val); } From 039f74ad821cbc3ea3a2448de595eaa3d9e64cb9 Mon Sep 17 00:00:00 2001 From: Dumitru Date: Thu, 3 May 2018 22:32:55 +0200 Subject: [PATCH 077/110] Refactor/move query execution (#1246) * Move QueryProcessor out of model Signed-off-by: Dumitru * Link query_execution Signed-off-by: Dumitru * Resolve conflicts Signed-off-by: Dumitru * Improve codestyle Signed-off-by: Dumitru * Refactor CMakeLists.txt Signed-off-by: Dumitru --- irohad/ametsuchi/CMakeLists.txt | 3 +- irohad/execution/CMakeLists.txt | 9 ++ .../impl/query_execution.cpp | 13 +- irohad/execution/query_execution.hpp | 135 +++++++++++++++++ irohad/model/CMakeLists.txt | 2 +- irohad/model/query_execution.hpp | 138 ------------------ irohad/torii/processor/CMakeLists.txt | 1 - .../processor/impl/query_processor_impl.cpp | 8 +- .../torii/processor/query_processor_impl.hpp | 2 +- test/module/iroha-cli/CMakeLists.txt | 1 + test/module/irohad/model/model_mocks.hpp | 2 +- test/module/irohad/torii/CMakeLists.txt | 1 + .../irohad/torii/processor/CMakeLists.txt | 1 + .../torii/processor/query_processor_test.cpp | 12 +- test/module/irohad/validation/CMakeLists.txt | 5 +- .../irohad/validation/query_execution.cpp | 11 +- 16 files changed, 175 insertions(+), 169 deletions(-) rename irohad/{model => execution}/impl/query_execution.cpp (97%) create mode 100644 irohad/execution/query_execution.hpp diff --git a/irohad/ametsuchi/CMakeLists.txt b/irohad/ametsuchi/CMakeLists.txt index 80d078380e..4f37c62781 100644 --- a/irohad/ametsuchi/CMakeLists.txt +++ b/irohad/ametsuchi/CMakeLists.txt @@ -18,9 +18,8 @@ target_link_libraries(ametsuchi pqxx libs_common command_execution - boost + query_execution shared_model_interfaces shared_model_proto_backend - shared_model_proto_builders shared_model_stateless_validation ) diff --git a/irohad/execution/CMakeLists.txt b/irohad/execution/CMakeLists.txt index 8ba23e30ec..6ad5799e4a 100644 --- a/irohad/execution/CMakeLists.txt +++ b/irohad/execution/CMakeLists.txt @@ -29,3 +29,12 @@ target_link_libraries(command_execution rxcpp shared_model_default_builders ) + +add_library(query_execution + impl/query_execution.cpp + ) + +target_link_libraries(query_execution + rxcpp + shared_model_default_builders + ) diff --git a/irohad/model/impl/query_execution.cpp b/irohad/execution/impl/query_execution.cpp similarity index 97% rename from irohad/model/impl/query_execution.cpp rename to irohad/execution/impl/query_execution.cpp index e623cfa666..40d5866f88 100644 --- a/irohad/model/impl/query_execution.cpp +++ b/irohad/execution/impl/query_execution.cpp @@ -15,15 +15,15 @@ * limitations under the License. */ -#include "model/query_execution.hpp" +#include "execution/query_execution.hpp" #include #include "execution/common_executor.hpp" #include "validators/permissions.hpp" -using namespace iroha::model; using namespace shared_model::permissions; +using namespace iroha; using namespace iroha::ametsuchi; // TODO: 28/03/2018 x3medima17 remove poly wrapper, IR-1011 @@ -271,7 +271,7 @@ QueryProcessingFactory::executeGetAccountAssets( } QueryProcessingFactory::QueryResponseBuilderDone -iroha::model::QueryProcessingFactory::executeGetAccountDetail( +QueryProcessingFactory::executeGetAccountDetail( const shared_model::interface::GetAccountDetail &query) { auto acct_detail = _wsvQuery->getAccountDetail(query.accountId()); if (not acct_detail) { @@ -282,7 +282,7 @@ iroha::model::QueryProcessingFactory::executeGetAccountDetail( } QueryProcessingFactory::QueryResponseBuilderDone -iroha::model::QueryProcessingFactory::executeGetAccountAssetTransactions( +QueryProcessingFactory::executeGetAccountAssetTransactions( const shared_model::interface::GetAccountAssetTransactions &query) { auto acc_asset_tx = _blockQuery->getAccountAssetTransactions( query.accountId(), query.assetId()); @@ -313,7 +313,7 @@ QueryProcessingFactory::executeGetAccountTransactions( } QueryProcessingFactory::QueryResponseBuilderDone -iroha::model::QueryProcessingFactory::executeGetTransactions( +QueryProcessingFactory::executeGetTransactions( const shared_model::interface::GetTransactions &q, const shared_model::interface::types::AccountIdType &accountId) { const std::vector &hashes = q.transactionHashes(); @@ -348,7 +348,8 @@ QueryProcessingFactory::executeGetSignatories( } std::shared_ptr -QueryProcessingFactory::execute(const shared_model::interface::Query &query) { +QueryProcessingFactory::validateAndExecute( + const shared_model::interface::Query &query) { const auto &query_hash = query.hash(); QueryResponseBuilderDone builder; // TODO: 29/04/2018 x3medima18, Add visitor class, IR-1185 diff --git a/irohad/execution/query_execution.hpp b/irohad/execution/query_execution.hpp new file mode 100644 index 0000000000..e8bf548e23 --- /dev/null +++ b/irohad/execution/query_execution.hpp @@ -0,0 +1,135 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef IROHA_QUERY_EXECUTION_HPP +#define IROHA_QUERY_EXECUTION_HPP + +#include "ametsuchi/block_query.hpp" +#include "ametsuchi/wsv_query.hpp" +#include "builders/protobuf/builder_templates/query_response_template.hpp" + +namespace shared_model { + namespace interface { + class QueryResponse; + class Query; + } // namespace interface +} // namespace shared_model + +namespace iroha { + + /** + * Converting model objects to protobuf and vice versa + */ + class QueryProcessingFactory { + using QueryResponseBuilder = + shared_model::proto::TemplateQueryResponseBuilder<0>; + + using QueryResponseBuilderDone = + shared_model::proto::TemplateQueryResponseBuilder<1>; + + public: + /** + * Execute and validate query. + * + * @param query + * @return shared pointer to query response + */ + std::shared_ptr validateAndExecute( + const shared_model::interface::Query &query); + /** + * + * @param wsvQuery + * @param blockQuery + */ + QueryProcessingFactory(std::shared_ptr wsvQuery, + std::shared_ptr blockQuery); + + private: + bool validate(const shared_model::interface::Query &query, + const shared_model::interface::GetAssetInfo &get_asset_info); + + bool validate(const shared_model::interface::Query &query, + const shared_model::interface::GetRoles &get_roles); + + bool validate(const shared_model::interface::Query &query, + const shared_model::interface::GetRolePermissions + &get_role_permissions); + + bool validate( + const shared_model::interface::Query &query, + const shared_model::interface::GetAccountAssets &get_account_assets); + + bool validate(const shared_model::interface::Query &query, + const shared_model::interface::GetAccount &get_account); + + bool validate( + const shared_model::interface::Query &query, + const shared_model::interface::GetSignatories &get_signatories); + + bool validate(const shared_model::interface::Query &query, + const shared_model::interface::GetAccountTransactions + &get_account_transactions); + + bool validate(const shared_model::interface::Query &query, + const shared_model::interface::GetAccountAssetTransactions + &get_account_asset_transactions); + + bool validate( + const shared_model::interface::Query &query, + const shared_model::interface::GetAccountDetail &get_account_detail); + + bool validate( + const shared_model::interface::Query &query, + const shared_model::interface::GetTransactions &get_transactions); + + QueryResponseBuilderDone executeGetAssetInfo( + const shared_model::interface::GetAssetInfo &get_asset_info); + + QueryResponseBuilderDone executeGetRoles( + const shared_model::interface::GetRoles &query); + + QueryResponseBuilderDone executeGetRolePermissions( + const shared_model::interface::GetRolePermissions &query); + + QueryResponseBuilderDone executeGetAccountAssets( + const shared_model::interface::GetAccountAssets &query); + + QueryResponseBuilderDone executeGetAccountDetail( + const shared_model::interface::GetAccountDetail &query); + + QueryResponseBuilderDone executeGetAccount( + const shared_model::interface::GetAccount &query); + + QueryResponseBuilderDone executeGetSignatories( + const shared_model::interface::GetSignatories &query); + + QueryResponseBuilderDone executeGetAccountAssetTransactions( + const shared_model::interface::GetAccountAssetTransactions &query); + + QueryResponseBuilderDone executeGetAccountTransactions( + const shared_model::interface::GetAccountTransactions &query); + + QueryResponseBuilderDone executeGetTransactions( + const shared_model::interface::GetTransactions &query, + const shared_model::interface::types::AccountIdType &accountId); + + std::shared_ptr _wsvQuery; + std::shared_ptr _blockQuery; + }; + +} // namespace iroha + +#endif // IROHA_QUERY_EXECUTION_HPP diff --git a/irohad/model/CMakeLists.txt b/irohad/model/CMakeLists.txt index a35be78ca2..77c02c7715 100644 --- a/irohad/model/CMakeLists.txt +++ b/irohad/model/CMakeLists.txt @@ -29,8 +29,8 @@ target_link_libraries(sha3_hash add_library(model model_crypto_provider_impl.cpp impl/model_operators.cpp - impl/query_execution.cpp ) + target_link_libraries(model hash sha3_hash diff --git a/irohad/model/query_execution.hpp b/irohad/model/query_execution.hpp index 1801aec757..e69de29bb2 100644 --- a/irohad/model/query_execution.hpp +++ b/irohad/model/query_execution.hpp @@ -1,138 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef IROHA_QUERY_EXECUTION_HPP -#define IROHA_QUERY_EXECUTION_HPP - -#include "ametsuchi/block_query.hpp" -#include "ametsuchi/wsv_query.hpp" -#include "builders/protobuf/builder_templates/query_response_template.hpp" - -namespace shared_model { - namespace interface { - class QueryResponse; - class Query; - } // namespace interface -} // namespace shared_model - -namespace iroha { - namespace model { - - /** - * Converting business objects to protobuf and vice versa - */ - class QueryProcessingFactory { - using QueryResponseBuilder = - shared_model::proto::TemplateQueryResponseBuilder<0>; - - using QueryResponseBuilderDone = - shared_model::proto::TemplateQueryResponseBuilder<1>; - - public: - /** - * Execute and validate query. - * - * @param query - * @return - */ - std::shared_ptr execute( - const shared_model::interface::Query &query); - /** - * - * @param wsvQuery - * @param blockQuery - */ - QueryProcessingFactory(std::shared_ptr wsvQuery, - std::shared_ptr blockQuery); - - private: - bool validate( - const shared_model::interface::Query &query, - const shared_model::interface::GetAssetInfo &get_asset_info); - - bool validate(const shared_model::interface::Query &query, - const shared_model::interface::GetRoles &get_roles); - - bool validate(const shared_model::interface::Query &query, - const shared_model::interface::GetRolePermissions - &get_role_permissions); - - bool validate( - const shared_model::interface::Query &query, - const shared_model::interface::GetAccountAssets &get_account_assets); - - bool validate(const shared_model::interface::Query &query, - const shared_model::interface::GetAccount &get_account); - - bool validate( - const shared_model::interface::Query &query, - const shared_model::interface::GetSignatories &get_signatories); - - bool validate(const shared_model::interface::Query &query, - const shared_model::interface::GetAccountTransactions - &get_account_transactions); - - bool validate(const shared_model::interface::Query &query, - const shared_model::interface::GetAccountAssetTransactions - &get_account_asset_transactions); - - bool validate( - const shared_model::interface::Query &query, - const shared_model::interface::GetAccountDetail &get_account_detail); - - bool validate( - const shared_model::interface::Query &query, - const shared_model::interface::GetTransactions &get_transactions); - - QueryResponseBuilderDone executeGetAssetInfo( - const shared_model::interface::GetAssetInfo &get_asset_info); - - QueryResponseBuilderDone executeGetRoles( - const shared_model::interface::GetRoles &query); - - QueryResponseBuilderDone executeGetRolePermissions( - const shared_model::interface::GetRolePermissions &query); - - QueryResponseBuilderDone executeGetAccountAssets( - const shared_model::interface::GetAccountAssets &query); - - QueryResponseBuilderDone executeGetAccountDetail( - const shared_model::interface::GetAccountDetail &query); - - QueryResponseBuilderDone executeGetAccount( - const shared_model::interface::GetAccount &query); - - QueryResponseBuilderDone executeGetSignatories( - const shared_model::interface::GetSignatories &query); - - QueryResponseBuilderDone executeGetAccountAssetTransactions( - const shared_model::interface::GetAccountAssetTransactions &query); - - QueryResponseBuilderDone executeGetAccountTransactions( - const shared_model::interface::GetAccountTransactions &query); - - QueryResponseBuilderDone executeGetTransactions( - const shared_model::interface::GetTransactions &q, - const shared_model::interface::types::AccountIdType &accountId); - - std::shared_ptr _wsvQuery; - std::shared_ptr _blockQuery; - }; - - } // namespace model -} // namespace iroha - -#endif // IROHA_QUERY_EXECUTION_HPP diff --git a/irohad/torii/processor/CMakeLists.txt b/irohad/torii/processor/CMakeLists.txt index dfe629f093..f94dc05d3b 100644 --- a/irohad/torii/processor/CMakeLists.txt +++ b/irohad/torii/processor/CMakeLists.txt @@ -4,7 +4,6 @@ add_library(processors ) target_link_libraries(processors PUBLIC - model rxcpp logger endpoint diff --git a/irohad/torii/processor/impl/query_processor_impl.cpp b/irohad/torii/processor/impl/query_processor_impl.cpp index 3fa59f47cb..15038881f9 100644 --- a/irohad/torii/processor/impl/query_processor_impl.cpp +++ b/irohad/torii/processor/impl/query_processor_impl.cpp @@ -71,8 +71,7 @@ namespace iroha { const auto &sig = *qry.signatures().begin(); const auto &wsv_query = storage_->getWsvQuery(); - auto qpf = - model::QueryProcessingFactory(wsv_query, storage_->getBlockQuery()); + auto qpf = QueryProcessingFactory(wsv_query, storage_->getBlockQuery()); auto signatories = wsv_query->getSignatories(qry.creatorAccountId()); if (not signatories) { return false; @@ -90,9 +89,8 @@ namespace iroha { } const auto &wsv_query = storage_->getWsvQuery(); - auto qpf = - model::QueryProcessingFactory(wsv_query, storage_->getBlockQuery()); - auto qpf_response = qpf.execute(*qry); + auto qpf = QueryProcessingFactory(wsv_query, storage_->getBlockQuery()); + auto qpf_response = qpf.validateAndExecute(*qry); auto qry_resp = std::static_pointer_cast( qpf_response); diff --git a/irohad/torii/processor/query_processor_impl.hpp b/irohad/torii/processor/query_processor_impl.hpp index cad6de234a..d1c977be49 100644 --- a/irohad/torii/processor/query_processor_impl.hpp +++ b/irohad/torii/processor/query_processor_impl.hpp @@ -19,7 +19,7 @@ #define IROHA_QUERY_PROCESSOR_IMPL_HPP #include "ametsuchi/storage.hpp" -#include "model/query_execution.hpp" +#include "execution/query_execution.hpp" #include "torii/processor/query_processor.hpp" namespace iroha { diff --git a/test/module/iroha-cli/CMakeLists.txt b/test/module/iroha-cli/CMakeLists.txt index 8ff164a3a5..fd78e36041 100644 --- a/test/module/iroha-cli/CMakeLists.txt +++ b/test/module/iroha-cli/CMakeLists.txt @@ -20,6 +20,7 @@ target_link_libraries(client_test client processors server_runner + query_execution ) target_include_directories(client_test PUBLIC ${PROJECT_SOURCE_DIR}/iroha-cli diff --git a/test/module/irohad/model/model_mocks.hpp b/test/module/irohad/model/model_mocks.hpp index d53da60240..094fb6db20 100644 --- a/test/module/irohad/model/model_mocks.hpp +++ b/test/module/irohad/model/model_mocks.hpp @@ -21,8 +21,8 @@ #include #include "ametsuchi/wsv_command.hpp" #include "ametsuchi/wsv_query.hpp" +#include "execution/query_execution.hpp" #include "model/command.hpp" -#include "model/query_execution.hpp" namespace iroha { namespace model { diff --git a/test/module/irohad/torii/CMakeLists.txt b/test/module/irohad/torii/CMakeLists.txt index 1abd0ee1d9..5c1b5c4f9e 100644 --- a/test/module/irohad/torii/CMakeLists.txt +++ b/test/module/irohad/torii/CMakeLists.txt @@ -31,6 +31,7 @@ target_link_libraries(torii_queries_test query_client server_runner processors + query_execution ) addtest(query_service_test query_service_test.cpp) diff --git a/test/module/irohad/torii/processor/CMakeLists.txt b/test/module/irohad/torii/processor/CMakeLists.txt index 3a909ef1ea..07aee2ade0 100644 --- a/test/module/irohad/torii/processor/CMakeLists.txt +++ b/test/module/irohad/torii/processor/CMakeLists.txt @@ -10,4 +10,5 @@ addtest(query_processor_test query_processor_test.cpp) target_link_libraries(query_processor_test processors shared_model_cryptography + query_execution ) diff --git a/test/module/irohad/torii/processor/query_processor_test.cpp b/test/module/irohad/torii/processor/query_processor_test.cpp index 98fc386ba5..ed5652de9f 100644 --- a/test/module/irohad/torii/processor/query_processor_test.cpp +++ b/test/module/irohad/torii/processor/query_processor_test.cpp @@ -19,8 +19,8 @@ #include "builders/protobuf/common_objects/proto_account_builder.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" #include "cryptography/keypair.hpp" +#include "execution/query_execution.hpp" #include "framework/test_subscriber.hpp" -#include "model/query_execution.hpp" #include "module/irohad/ametsuchi/ametsuchi_mocks.hpp" #include "module/irohad/validation/validation_mocks.hpp" #include "module/shared_model/builders/protobuf/test_query_builder.hpp" @@ -65,8 +65,8 @@ TEST_F(QueryProcessorTest, QueryProcessorWhereInvokeInvalidQuery) { auto wsv_queries = std::make_shared(); auto block_queries = std::make_shared(); auto storage = std::make_shared(); - auto qpf = std::make_unique(wsv_queries, - block_queries); + auto qpf = + std::make_unique(wsv_queries, block_queries); iroha::torii::QueryProcessorImpl qpi(storage); @@ -111,14 +111,14 @@ TEST_F(QueryProcessorTest, QueryProcessorWhereInvokeInvalidQuery) { /** * @given account, ametsuchi queries and query processing factory * @when signed with wrong key - * @then Query Processor should return StatefullFailed + * @then Query Processor should return StatefulFailed */ TEST_F(QueryProcessorTest, QueryProcessorWithWrongKey) { auto wsv_queries = std::make_shared(); auto block_queries = std::make_shared(); auto storage = std::make_shared(); - auto qpf = std::make_unique(wsv_queries, - block_queries); + auto qpf = + std::make_unique(wsv_queries, block_queries); iroha::torii::QueryProcessorImpl qpi(storage); diff --git a/test/module/irohad/validation/CMakeLists.txt b/test/module/irohad/validation/CMakeLists.txt index 209e0d65c7..c679cf40a4 100644 --- a/test/module/irohad/validation/CMakeLists.txt +++ b/test/module/irohad/validation/CMakeLists.txt @@ -15,8 +15,9 @@ # limitations under the License. # -addtest(query_execution query_execution.cpp) -target_link_libraries(query_execution +addtest(query_execution_test query_execution.cpp) +target_link_libraries(query_execution_test + query_execution shared_model_interfaces shared_model_stateless_validation ) diff --git a/test/module/irohad/validation/query_execution.cpp b/test/module/irohad/validation/query_execution.cpp index a5dc422626..df10082124 100644 --- a/test/module/irohad/validation/query_execution.cpp +++ b/test/module/irohad/validation/query_execution.cpp @@ -25,10 +25,10 @@ #include "builders/protobuf/common_objects/proto_account_builder.hpp" #include "builders/protobuf/common_objects/proto_amount_builder.hpp" #include "builders/protobuf/common_objects/proto_asset_builder.hpp" +#include "execution/query_execution.hpp" #include "framework/test_subscriber.hpp" -#include "validators/permissions.hpp" -#include "model/query_execution.hpp" #include "module/shared_model/builders/protobuf/test_query_builder.hpp" +#include "validators/permissions.hpp" using ::testing::AllOf; using ::testing::AtLeast; @@ -36,6 +36,7 @@ using ::testing::Return; using ::testing::StrictMock; using ::testing::_; +using namespace iroha; using namespace iroha::ametsuchi; using namespace iroha::model; using namespace framework::test_subscriber; @@ -76,7 +77,7 @@ class QueryValidateExecuteTest : public ::testing::Test { std::shared_ptr validateAndExecute( const shared_model::interface::Query &query) { - return factory->execute(query); + return factory->validateAndExecute(query); } /** @@ -85,9 +86,7 @@ class QueryValidateExecuteTest : public ::testing::Test { * @return wrapper with created transaction */ wTransaction makeTransaction(std::string creator) { - return clone(TestTransactionBuilder() - .creatorAccountId(creator) - .build()); + return clone(TestTransactionBuilder().creatorAccountId(creator).build()); } /** From 883389c54af8b2659f0e9633e0220a591e6572cf Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Fri, 4 May 2018 10:22:48 +0300 Subject: [PATCH 078/110] Fix build library script for linux. (#1289) * Fix javas build library script for linux. * Add executable permissions for build_library.sh Signed-off-by: Fedor Muratov --- example/java/build_library.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) mode change 100644 => 100755 example/java/build_library.sh diff --git a/example/java/build_library.sh b/example/java/build_library.sh old mode 100644 new mode 100755 index ed2f5aef9a..2c4b0a7d28 --- a/example/java/build_library.sh +++ b/example/java/build_library.sh @@ -6,8 +6,13 @@ mkdir dist # build native library ./prepare.sh -cp build/shared_model/bindings/libirohajava.jnilib dist/libirohajava.jnilib +unamestr=`uname` +if [[ "$unamestr" == 'Linux' ]]; then + cp build/shared_model/bindings/libirohajava.so dist/libirohajava.so +elif [[ "$unamestr" == 'Darwin' ]]; then + cp build/shared_model/bindings/libirohajava.jnilib dist/libirohajava.jnilib +fi # build jar gradle jar From c9b56f92b6b4adec9795b32e2b5ab3c70b8b2d36 Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Fri, 4 May 2018 15:46:22 +0300 Subject: [PATCH 079/110] Remove clearSignatures method (#1298) * Remove clearSignatures method and usage Signed-off-by: Fedor Muratov --- irohad/consensus/yac/impl/yac_gate_impl.cpp | 1 - shared_model/backend/protobuf/block.hpp | 5 ----- shared_model/backend/protobuf/queries/proto_query.hpp | 5 ----- shared_model/backend/protobuf/transaction.hpp | 5 ----- shared_model/interfaces/base/signable.hpp | 6 ------ 5 files changed, 22 deletions(-) diff --git a/irohad/consensus/yac/impl/yac_gate_impl.cpp b/irohad/consensus/yac/impl/yac_gate_impl.cpp index 9006c10d95..d22e561b9d 100644 --- a/irohad/consensus/yac/impl/yac_gate_impl.cpp +++ b/irohad/consensus/yac/impl/yac_gate_impl.cpp @@ -131,7 +131,6 @@ namespace iroha { } void YacGateImpl::copySignatures(const CommitMessage &commit) { - current_block_.second->clearSignatures(); for (const auto &vote : commit.votes) { auto sig = vote.hash.block_signature; current_block_.second->addSignature(sig->signedData(), diff --git a/shared_model/backend/protobuf/block.hpp b/shared_model/backend/protobuf/block.hpp index 13f7a1c865..4a01cf9e70 100644 --- a/shared_model/backend/protobuf/block.hpp +++ b/shared_model/backend/protobuf/block.hpp @@ -91,11 +91,6 @@ namespace shared_model { return true; } - bool clearSignatures() override { - signatures_->clear(); - return (signatures_->size() == 0); - } - interface::types::TimestampType createdTime() const override { return payload_.created_time(); } diff --git a/shared_model/backend/protobuf/queries/proto_query.hpp b/shared_model/backend/protobuf/queries/proto_query.hpp index ba4cb5686c..c882033cb2 100644 --- a/shared_model/backend/protobuf/queries/proto_query.hpp +++ b/shared_model/backend/protobuf/queries/proto_query.hpp @@ -135,11 +135,6 @@ namespace shared_model { return true; } - bool clearSignatures() override { - signatures_->clear(); - return (signatures_->size() == 0); - } - interface::types::TimestampType createdTime() const override { return proto_->payload().created_time(); } diff --git a/shared_model/backend/protobuf/transaction.hpp b/shared_model/backend/protobuf/transaction.hpp index 3a6b374d90..f68a237a7c 100644 --- a/shared_model/backend/protobuf/transaction.hpp +++ b/shared_model/backend/protobuf/transaction.hpp @@ -83,11 +83,6 @@ namespace shared_model { return true; } - bool clearSignatures() override { - signatures_->clear(); - return (signatures_->size() == 0); - } - interface::types::TimestampType createdTime() const override { return payload_.created_time(); } diff --git a/shared_model/interfaces/base/signable.hpp b/shared_model/interfaces/base/signable.hpp index 4eda8dd900..26727aa93e 100644 --- a/shared_model/interfaces/base/signable.hpp +++ b/shared_model/interfaces/base/signable.hpp @@ -70,12 +70,6 @@ namespace shared_model { virtual bool addSignature(const crypto::Signed &signed_blob, const crypto::PublicKey &public_key) = 0; - /** - * Clear object's signatures - * @return true, if signatures were cleared - */ - virtual bool clearSignatures() = 0; - /** * @return time of creation */ From 8f9b7b9215fac6f11d20a9ce25ce8446351c939b Mon Sep 17 00:00:00 2001 From: kamilsa Date: Fri, 4 May 2018 15:55:24 +0300 Subject: [PATCH 080/110] Feature/update signature type (#1248) * Add ranges Signed-off-by: kamilsa --- .../yac/impl/supermajority_checker_impl.cpp | 13 ++-- .../yac/impl/supermajority_checker_impl.hpp | 10 +-- .../yac/impl/yac_hash_provider_impl.cpp | 2 +- .../consensus/yac/supermajority_checker.hpp | 8 ++- .../synchronizer/impl/synchronizer_impl.cpp | 2 +- .../processor/impl/query_processor_impl.cpp | 33 +-------- .../impl/stateful_validator_impl.cpp | 8 +-- .../impl/stateful_validator_impl.hpp | 2 +- shared_model/backend/protobuf/block.hpp | 19 +++--- .../backend/protobuf/queries/proto_query.hpp | 9 ++- shared_model/backend/protobuf/transaction.hpp | 14 ++-- shared_model/interfaces/base/signable.hpp | 46 +++++++++++-- .../common_objects/signable_hash.hpp | 67 ------------------- .../interfaces/common_objects/types.hpp | 8 +-- .../interfaces/iroha_internal/block.hpp | 4 +- shared_model/interfaces/queries/query.hpp | 2 +- shared_model/interfaces/transaction.hpp | 7 +- shared_model/utils/polymorphic_wrapper.hpp | 4 ++ shared_model/validators/field_validator.cpp | 6 +- shared_model/validators/field_validator.hpp | 8 +-- .../yac/supermajority_checker_test.cpp | 21 ++---- .../irohad/consensus/yac/yac_gate_test.cpp | 7 +- .../module/irohad/consensus/yac/yac_mocks.hpp | 6 +- .../validation/chain_validation_test.cpp | 6 +- .../cryptography/crypto_usage_test.cpp | 20 +++--- 25 files changed, 135 insertions(+), 197 deletions(-) delete mode 100644 shared_model/interfaces/common_objects/signable_hash.hpp diff --git a/irohad/consensus/yac/impl/supermajority_checker_impl.cpp b/irohad/consensus/yac/impl/supermajority_checker_impl.cpp index 597be726fd..e40ba8658a 100644 --- a/irohad/consensus/yac/impl/supermajority_checker_impl.cpp +++ b/irohad/consensus/yac/impl/supermajority_checker_impl.cpp @@ -17,16 +17,17 @@ #include "consensus/yac/impl/supermajority_checker_impl.hpp" #include "interfaces/common_objects/peer.hpp" +#include "interfaces/common_objects/signature.hpp" namespace iroha { namespace consensus { namespace yac { bool SupermajorityCheckerImpl::hasSupermajority( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType &signatures, const std::vector> &peers) const { - return checkSize(signatures.size(), peers.size()) + return checkSize(boost::size(signatures), peers.size()) and peersSubset(signatures, peers); } @@ -40,17 +41,19 @@ namespace iroha { } bool SupermajorityCheckerImpl::peersSubset( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType &signatures, const std::vector> &peers) const { return std::all_of( - signatures.begin(), signatures.end(), [&peers](auto signature) { + signatures.begin(), + signatures.end(), + [&peers](const auto &signature) { return std::find_if( peers.begin(), peers.end(), [&signature](const std::shared_ptr< shared_model::interface::Peer> &peer) { - return signature->publicKey() == peer->pubkey(); + return signature.publicKey() == peer->pubkey(); }) != peers.end(); }); diff --git a/irohad/consensus/yac/impl/supermajority_checker_impl.hpp b/irohad/consensus/yac/impl/supermajority_checker_impl.hpp index a1ab775c31..894df51ac8 100644 --- a/irohad/consensus/yac/impl/supermajority_checker_impl.hpp +++ b/irohad/consensus/yac/impl/supermajority_checker_impl.hpp @@ -35,14 +35,16 @@ namespace iroha { * @return true on supermajority is achieved or false otherwise */ virtual bool hasSupermajority( - const shared_model::interface::SignatureSetType &signatures, - const std::vector> &peers) - const override; + const shared_model::interface::types::SignatureRangeType + &signatures, + const std::vector> + &peers) const override; virtual bool checkSize(uint64_t current, uint64_t all) const override; virtual bool peersSubset( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType + &signatures, const std::vector> &peers) const override; diff --git a/irohad/consensus/yac/impl/yac_hash_provider_impl.cpp b/irohad/consensus/yac/impl/yac_hash_provider_impl.cpp index 4198774c41..59e602929e 100644 --- a/irohad/consensus/yac/impl/yac_hash_provider_impl.cpp +++ b/irohad/consensus/yac/impl/yac_hash_provider_impl.cpp @@ -30,7 +30,7 @@ namespace iroha { result.proposal_hash = hex_hash; result.block_hash = hex_hash; const auto &sig = *block.signatures().begin(); - result.block_signature = clone(*sig); + result.block_signature = clone(sig); return result; } diff --git a/irohad/consensus/yac/supermajority_checker.hpp b/irohad/consensus/yac/supermajority_checker.hpp index ad6d158547..5226a98605 100644 --- a/irohad/consensus/yac/supermajority_checker.hpp +++ b/irohad/consensus/yac/supermajority_checker.hpp @@ -19,7 +19,7 @@ #define IROHA_CONSENSUS_SUPERMAJORITY_CHECKER_HPP #include -#include "interfaces/common_objects/signable_hash.hpp" +#include "interfaces/common_objects/types.hpp" namespace shared_model { namespace interface { @@ -46,7 +46,8 @@ namespace iroha { * @return true on supermajority is achieved or false otherwise */ virtual bool hasSupermajority( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType + &signatures, const std::vector> &peers) const = 0; @@ -65,7 +66,8 @@ namespace iroha { * @return true if is subset or false otherwise */ virtual bool peersSubset( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType + &signatures, const std::vector> &peers) const = 0; diff --git a/irohad/synchronizer/impl/synchronizer_impl.cpp b/irohad/synchronizer/impl/synchronizer_impl.cpp index 6134311656..9b87528d1d 100644 --- a/irohad/synchronizer/impl/synchronizer_impl.cpp +++ b/irohad/synchronizer/impl/synchronizer_impl.cpp @@ -84,7 +84,7 @@ namespace iroha { return; } auto chain = blockLoader_->retrieveBlocks( - shared_model::crypto::PublicKey(signature->publicKey())); + shared_model::crypto::PublicKey(signature.publicKey())); // Check chain last commit auto is_chain_end_expected = chain.as_blocking().last()->hash() == commit_message->hash(); diff --git a/irohad/torii/processor/impl/query_processor_impl.cpp b/irohad/torii/processor/impl/query_processor_impl.cpp index 15038881f9..01e4e93205 100644 --- a/irohad/torii/processor/impl/query_processor_impl.cpp +++ b/irohad/torii/processor/impl/query_processor_impl.cpp @@ -16,37 +16,9 @@ */ #include "torii/processor/query_processor_impl.hpp" -#include "backend/protobuf/from_old_model.hpp" -#include "backend/protobuf/query_responses/proto_query_response.hpp" namespace iroha { namespace torii { - - /** - * Checks if public keys are subset of given signaturies - * @param signatures user signatories, an iterable collection - * @param public_keys vector of public keys - * @return true if user has needed signatories, false instead - */ - bool signaturesSubset( - const shared_model::interface::SignatureSetType &signatures, - const std::vector &public_keys) { - // TODO 09/10/17 Lebedev: simplify the subset verification IR-510 - // #goodfirstissue - // TODO 30/04/2018 x3medima17: remove code duplication in query_processor - // IR-1192 and stateful_validator - std::unordered_set txPubkeys; - for (auto sign : signatures) { - txPubkeys.insert(sign->publicKey().toString()); - } - return std::all_of(public_keys.begin(), - public_keys.end(), - [&txPubkeys](const auto &public_key) { - return txPubkeys.find(public_key.toString()) - != txPubkeys.end(); - }); - } - /** * Builds QueryResponse that contains StatefulError * @param hash - original query hash @@ -76,8 +48,9 @@ namespace iroha { if (not signatories) { return false; } - bool result = signaturesSubset({sig}, *signatories); - return result; + return std::find( + signatories->begin(), signatories->end(), sig.publicKey()) + != signatories->end(); } void QueryProcessorImpl::queryHandle( diff --git a/irohad/validation/impl/stateful_validator_impl.cpp b/irohad/validation/impl/stateful_validator_impl.cpp index 979552e70f..0d9b1854f9 100644 --- a/irohad/validation/impl/stateful_validator_impl.cpp +++ b/irohad/validation/impl/stateful_validator_impl.cpp @@ -39,7 +39,7 @@ namespace iroha { [&](const auto &account) { // Check if tx creator has account and has quorum to // execute transaction - return tx.signatures().size() >= account->quorum() + return boost::size(tx.signatures()) >= account->quorum() ? queries.getSignatories(tx.creatorAccountId()) : boost::none; } @@ -93,13 +93,13 @@ namespace iroha { } bool StatefulValidatorImpl::signaturesSubset( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType &signatures, const std::vector &public_keys) { // TODO 09/10/17 Lebedev: simplify the subset verification IR-510 // #goodfirstissue std::unordered_set txPubkeys; - for (auto sign : signatures) { - txPubkeys.insert(sign->publicKey().toString()); + for (auto &sign : signatures) { + txPubkeys.insert(sign.publicKey().toString()); } return std::all_of(public_keys.begin(), public_keys.end(), diff --git a/irohad/validation/impl/stateful_validator_impl.hpp b/irohad/validation/impl/stateful_validator_impl.hpp index 17cd7a8fb4..cce734f676 100644 --- a/irohad/validation/impl/stateful_validator_impl.hpp +++ b/irohad/validation/impl/stateful_validator_impl.hpp @@ -53,7 +53,7 @@ namespace iroha { * pubkeys */ bool signaturesSubset( - const shared_model::interface::SignatureSetType &signatures, + const shared_model::interface::types::SignatureRangeType &signatures, const std::vector &public_keys); logger::Logger log_; diff --git a/shared_model/backend/protobuf/block.hpp b/shared_model/backend/protobuf/block.hpp index 4a01cf9e70..df169cb245 100644 --- a/shared_model/backend/protobuf/block.hpp +++ b/shared_model/backend/protobuf/block.hpp @@ -64,7 +64,7 @@ namespace shared_model { return *blob_; } - const interface::SignatureSetType &signatures() const override { + interface::types::SignatureRangeType signatures() const override { return *signatures_; } @@ -75,11 +75,11 @@ namespace shared_model { const crypto::PublicKey &public_key) override { // if already has such signature if (std::find_if(signatures_->begin(), - signatures_->end(), - [&signed_blob, &public_key](auto signature) { - return signature->signedData() == signed_blob - and signature->publicKey() == public_key; - }) != signatures_->end()) { + signatures_->end(), + [&public_key](const auto &signature) { + return signature.publicKey() == public_key; + }) + != signatures_->end()) { return false; } @@ -126,11 +126,10 @@ namespace shared_model { return interface::types::HashType(proto_->payload().prev_block_hash()); }}; - const Lazy signatures_{[this] { - interface::SignatureSetType sigs; + const Lazy> signatures_{[this] { + SignatureSetType sigs; for (const auto &sig : proto_->signatures()) { - auto curr = detail::makePolymorphic(sig); - sigs.insert(curr); + sigs.emplace(sig); } return sigs; }}; diff --git a/shared_model/backend/protobuf/queries/proto_query.hpp b/shared_model/backend/protobuf/queries/proto_query.hpp index c882033cb2..d23afeb14a 100644 --- a/shared_model/backend/protobuf/queries/proto_query.hpp +++ b/shared_model/backend/protobuf/queries/proto_query.hpp @@ -19,7 +19,6 @@ #define IROHA_SHARED_MODEL_PROTO_QUERY_HPP #include - #include "backend/protobuf/common_objects/signature.hpp" #include "backend/protobuf/common_objects/trivial_proto.hpp" #include "interfaces/queries/query.hpp" @@ -119,7 +118,7 @@ namespace shared_model { } // ------------------------| Signable override |------------------------- - const interface::SignatureSetType &signatures() const override { + interface::types::SignatureRangeType signatures() const override { return *signatures_; } @@ -151,10 +150,10 @@ namespace shared_model { const Lazy payload_{ [this] { return makeBlob(proto_->payload()); }}; - const Lazy signatures_{[this] { - interface::SignatureSetType set; + const Lazy> signatures_{[this] { + SignatureSetType set; if (proto_->has_signature()) { - set.emplace(new Signature(proto_->signature())); + set.emplace(proto_->signature()); } return set; }}; diff --git a/shared_model/backend/protobuf/transaction.hpp b/shared_model/backend/protobuf/transaction.hpp index f68a237a7c..6b38db0bc2 100644 --- a/shared_model/backend/protobuf/transaction.hpp +++ b/shared_model/backend/protobuf/transaction.hpp @@ -21,7 +21,6 @@ #include "interfaces/transaction.hpp" #include - #include "backend/protobuf/commands/proto_command.hpp" #include "backend/protobuf/common_objects/signature.hpp" #include "block.pb.h" @@ -58,7 +57,7 @@ namespace shared_model { return *blobTypePayload_; } - const interface::SignatureSetType &signatures() const override { + interface::types::SignatureRangeType signatures() const override { return *signatures_; } @@ -67,9 +66,8 @@ namespace shared_model { // if already has such signature if (std::find_if(signatures_->begin(), signatures_->end(), - [&signed_blob, &public_key](auto signature) { - return signature->signedData() == signed_blob - and signature->publicKey() == public_key; + [&public_key](const auto& signature) { + return signature.publicKey() == public_key; }) != signatures_->end()) { return false; @@ -109,11 +107,11 @@ namespace shared_model { const Lazy blobTypePayload_{ [this] { return makeBlob(payload_); }}; - const Lazy signatures_{[this] { + const Lazy> signatures_{[this] { return boost::accumulate(proto_->signatures(), - interface::SignatureSetType{}, + SignatureSetType{}, [](auto &&acc, const auto &sig) { - acc.emplace(new Signature(sig)); + acc.emplace(sig); return std::forward(acc); }); }}; diff --git a/shared_model/interfaces/base/signable.hpp b/shared_model/interfaces/base/signable.hpp index 26727aa93e..51f7f10d90 100644 --- a/shared_model/interfaces/base/signable.hpp +++ b/shared_model/interfaces/base/signable.hpp @@ -18,10 +18,11 @@ #ifndef IROHA_SIGNABLE_HPP #define IROHA_SIGNABLE_HPP +#include #include +#include #include "cryptography/default_hash_provider.hpp" -#include "interfaces/common_objects/signable_hash.hpp" #include "interfaces/common_objects/signature.hpp" #include "interfaces/common_objects/types.hpp" #include "utils/string_builder.hpp" @@ -60,7 +61,7 @@ namespace shared_model { /** * @return attached signatures */ - virtual const SignatureSetType &signatures() const = 0; + virtual types::SignatureRangeType signatures() const = 0; /** * Attach signature to object @@ -92,7 +93,7 @@ namespace shared_model { */ bool operator==(const Model &rhs) const override { return this->hash() == rhs.hash() - and this->signatures() == rhs.signatures() + and boost::equal(this->signatures(), rhs.signatures()) and this->createdTime() == rhs.createdTime(); } @@ -110,10 +111,47 @@ namespace shared_model { .init("Signable") .append("created_time", std::to_string(createdTime())) .appendAll(signatures(), - [](auto &signature) { return signature->toString(); }) + [](auto &signature) { return signature.toString(); }) .finalize(); } + protected: + /** + * Type of set of signatures + * + * Note: we can't use const SignatureType due to unordered_set + * limitations: it requires to have write access for elements for some + * internal operations. + */ + + protected: + class SignatureSetTypeOps { + public: + /** + * @param sig is item to find hash from + * @return calculated hash of public key + */ + template + size_t operator()(const T &sig) const { + return std::hash{}(sig.publicKey().hex()); + } + + /** + * Function for set elements uniqueness by public key + * @param lhs + * @param rhs + * @return true, if public keys are the same + */ + template + bool operator()(const T &lhs, const T &rhs) const { + return lhs.publicKey() == rhs.publicKey(); + } + }; + + template + using SignatureSetType = + std::unordered_set; + private: mutable boost::optional hash_; }; diff --git a/shared_model/interfaces/common_objects/signable_hash.hpp b/shared_model/interfaces/common_objects/signable_hash.hpp deleted file mode 100644 index da16dd7cc4..0000000000 --- a/shared_model/interfaces/common_objects/signable_hash.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef IROHA_SHARED_MODEL_SIGNABLE_HASH_HPP -#define IROHA_SHARED_MODEL_SIGNABLE_HASH_HPP - -#include - -#include "interfaces/common_objects/signature.hpp" -#include "interfaces/common_objects/types.hpp" - -namespace shared_model { - - namespace interface { - /** - * Property class for SignatureSetType that contains hashing and comparison - * operations. - */ - class SignatureSetTypeOps { - public: - /** - * @param sig is item to find hash from - * @return calculated hash of public key - */ - size_t operator()(const types::SignatureType &sig) const { - return std::hash{}(sig->publicKey().hex()); - } - - /** - * Function for set elements uniqueness by public key - * @param lhs - * @param rhs - * @return true, if public keys are the same - */ - bool operator()(const types::SignatureType &lhs, - const types::SignatureType &rhs) const { - return lhs->publicKey() == rhs->publicKey(); - } - }; - /** - * Type of set of signatures - * - * Note: we can't use const SignatureType due to unordered_set - * limitations: it requires to have write access for elements for some - * internal operations. - */ - using SignatureSetType = std::unordered_set; - } // namespace interface -} // namespace shared_model - -#endif // IROHA_SHARED_MODEL_SIGNABLE_HASH_HPP diff --git a/shared_model/interfaces/common_objects/types.hpp b/shared_model/interfaces/common_objects/types.hpp index f175c9d8e0..b2d4b47227 100644 --- a/shared_model/interfaces/common_objects/types.hpp +++ b/shared_model/interfaces/common_objects/types.hpp @@ -18,6 +18,7 @@ #ifndef IROHA_SHARED_MODEL_TYPES_HPP #define IROHA_SHARED_MODEL_TYPES_HPP +#include #include #include #include @@ -64,10 +65,9 @@ namespace shared_model { using PermissionSetType = std::set; /// Type of Quorum used in transaction and set quorum using QuorumType = uint32_t; - /// Type of transaction signature - // TODO Alexey Chernyshov 2018-03-28 - remove PolymorphicWrapper here - // https://soramitsu.atlassian.net/browse/IR-1175 - using SignatureType = detail::PolymorphicWrapper; + /// Type of signature range, which returns when signatures are invoked + using SignatureRangeType = boost::any_range; /// Type of timestamp using TimestampType = uint64_t; /// Type of peer address diff --git a/shared_model/interfaces/iroha_internal/block.hpp b/shared_model/interfaces/iroha_internal/block.hpp index ff39d7f526..d2e9a46a87 100644 --- a/shared_model/interfaces/iroha_internal/block.hpp +++ b/shared_model/interfaces/iroha_internal/block.hpp @@ -76,7 +76,7 @@ namespace shared_model { std::for_each( signatures().begin(), signatures().end(), [&old_block](auto &sig) { std::unique_ptr old_sig( - sig->makeOldModel()); + sig.makeOldModel()); old_block->sigs.emplace_back(*old_sig); }); return old_block; @@ -94,7 +94,7 @@ namespace shared_model { .append("transactions") .appendAll(transactions(), [](auto &tx) { return tx->toString(); }) .append("signatures") - .appendAll(signatures(), [](auto &sig) { return sig->toString(); }) + .appendAll(signatures(), [](auto &sig) { return sig.toString(); }) .finalize(); } }; diff --git a/shared_model/interfaces/queries/query.hpp b/shared_model/interfaces/queries/query.hpp index 897b7bfda2..cb36c1ffa3 100644 --- a/shared_model/interfaces/queries/query.hpp +++ b/shared_model/interfaces/queries/query.hpp @@ -114,7 +114,7 @@ namespace shared_model { // for_each cycle will assign last signature for old // model. Also, if in new model absence at least one // signature, this part will be worked correctly. - auto old_sig = signature_wrapper->makeOldModel(); + auto old_sig = signature_wrapper.makeOldModel(); old_model->signature = *old_sig; delete old_sig; }); diff --git a/shared_model/interfaces/transaction.hpp b/shared_model/interfaces/transaction.hpp index 994ed49d97..69c408a1d8 100644 --- a/shared_model/interfaces/transaction.hpp +++ b/shared_model/interfaces/transaction.hpp @@ -73,8 +73,9 @@ namespace shared_model { std::for_each(signatures().begin(), signatures().end(), [oldStyleTransaction](auto &sig) { - oldStyleTransaction->signatures.emplace_back( - *sig->makeOldModel()); + std::unique_ptr up_sig( + sig.makeOldModel()); + oldStyleTransaction->signatures.emplace_back(*up_sig); }); return oldStyleTransaction; @@ -91,7 +92,7 @@ namespace shared_model { .appendAll(commands(), [](auto &command) { return command->toString(); }) .append("signatures") - .appendAll(signatures(), [](auto &sig) { return sig->toString(); }) + .appendAll(signatures(), [](auto &sig) { return sig.toString(); }) .finalize(); } }; diff --git a/shared_model/utils/polymorphic_wrapper.hpp b/shared_model/utils/polymorphic_wrapper.hpp index 1ac9ec2fe3..e6a90db995 100644 --- a/shared_model/utils/polymorphic_wrapper.hpp +++ b/shared_model/utils/polymorphic_wrapper.hpp @@ -105,6 +105,10 @@ namespace shared_model { return *ptr_ == *rhs.ptr_; } + bool operator!=(const PolymorphicWrapper &rhs) const { + return not (*ptr_ == *rhs.ptr_); + } + /** * Mutable wrapped object pointer * @return pointer for wrapped object diff --git a/shared_model/validators/field_validator.cpp b/shared_model/validators/field_validator.cpp index 725def24e3..80a1392a03 100644 --- a/shared_model/validators/field_validator.cpp +++ b/shared_model/validators/field_validator.cpp @@ -292,11 +292,11 @@ namespace shared_model { void FieldValidator::validateSignatures( ReasonsGroupType &reason, - const interface::SignatureSetType &signatures, + const interface::types::SignatureRangeType &signatures, const crypto::Blob &source) const { for (const auto &signature : signatures) { - const auto &sign = signature->signedData(); - const auto &pkey = signature->publicKey(); + const auto &sign = signature.signedData(); + const auto &pkey = signature.publicKey(); bool is_valid = true; if (sign.blob().size() != 64) { diff --git a/shared_model/validators/field_validator.hpp b/shared_model/validators/field_validator.hpp index 4376b9d44b..3ee0c4e50c 100644 --- a/shared_model/validators/field_validator.hpp +++ b/shared_model/validators/field_validator.hpp @@ -23,7 +23,6 @@ #include "datetime/time.hpp" #include "interfaces/base/signable.hpp" #include "interfaces/commands/command.hpp" -#include "interfaces/common_objects/signable_hash.hpp" #include "interfaces/transaction.hpp" #include "validators/answer.hpp" @@ -129,9 +128,10 @@ namespace shared_model { void validateCounter(ReasonsGroupType &reason, const interface::types::CounterType &counter) const; - void validateSignatures(ReasonsGroupType &reason, - const interface::SignatureSetType &signatures, - const crypto::Blob &source) const; + void validateSignatures( + ReasonsGroupType &reason, + const interface::types::SignatureRangeType &signatures, + const crypto::Blob &source) const; void validateDescription( ReasonsGroupType &reason, diff --git a/test/module/irohad/consensus/yac/supermajority_checker_test.cpp b/test/module/irohad/consensus/yac/supermajority_checker_test.cpp index 1714cb3c90..5429d18fee 100644 --- a/test/module/irohad/consensus/yac/supermajority_checker_test.cpp +++ b/test/module/irohad/consensus/yac/supermajority_checker_test.cpp @@ -21,11 +21,8 @@ #include "builders/protobuf/common_objects/proto_peer_builder.hpp" #include "builders/protobuf/common_objects/proto_signature_builder.hpp" #include "consensus/yac/impl/supermajority_checker_impl.hpp" -#include "cryptography/public_key.hpp" -#include "cryptography/signed.hpp" -#include "interfaces/common_objects/peer.hpp" -#include "interfaces/common_objects/types.hpp" #include "logger/logger.hpp" +#include "module/shared_model/builders/protobuf/test_block_builder.hpp" using namespace iroha::consensus::yac; @@ -115,17 +112,9 @@ TEST_F(SupermajorityCheckerTest, PublicKeyUniqueness) { auto peer_key = make_peer_key(std::string(32, '0')); make_peer_key(std::string(32, '1')); - auto make_sig = [](const PublicKey &peer_key, const std::string &sig) { - return shared_model::interface::types::SignatureType( - std::static_pointer_cast( - std::make_shared( - shared_model::proto::SignatureBuilder() - .publicKey(peer_key) - .signedData(Signed(sig)) - .build()))); - }; - shared_model::interface::SignatureSetType signatures{make_sig(peer_key, "1"), - make_sig(peer_key, "2")}; + auto block = TestBlockBuilder().build(); + block.addSignature(Signed("1"), peer_key); + block.addSignature(Signed("2"), peer_key); - ASSERT_FALSE(hasSupermajority(signatures, peers)); + ASSERT_FALSE(hasSupermajority(block.signatures(), peers)); } diff --git a/test/module/irohad/consensus/yac/yac_gate_test.cpp b/test/module/irohad/consensus/yac/yac_gate_test.cpp index d49c966bf5..98ef083568 100644 --- a/test/module/irohad/consensus/yac/yac_gate_test.cpp +++ b/test/module/irohad/consensus/yac/yac_gate_test.cpp @@ -57,8 +57,7 @@ class YacGateTest : public ::testing::Test { .signAndAddSignature(keypair); expected_block = clone(tmp); - const auto &wrapped_sig = *(expected_block->signatures().begin()); - const auto &signature = *wrapped_sig; + const auto &signature = *(expected_block->signatures().begin()); expected_hash.block_signature = clone(signature); message.hash = expected_hash; @@ -187,7 +186,7 @@ TEST_F(YacGateTest, LoadBlockWhenDifferentCommit) { // load block auto sig = expected_block->signatures().begin(); - auto &pubkey = (*sig)->publicKey(); + auto &pubkey = sig->publicKey(); EXPECT_CALL(*block_loader, retrieveBlock(pubkey, expected_block->hash())) .WillOnce(Return(expected_block)); @@ -240,7 +239,7 @@ TEST_F(YacGateTest, LoadBlockWhenDifferentCommitFailFirst) { // load block auto sig = expected_block->signatures().begin(); - auto &pubkey = (*sig)->publicKey(); + auto &pubkey = sig->publicKey(); EXPECT_CALL(*block_loader, retrieveBlock(pubkey, expected_block->hash())) .WillOnce(Return(boost::none)) .WillOnce(Return(expected_block)); diff --git a/test/module/irohad/consensus/yac/yac_mocks.hpp b/test/module/irohad/consensus/yac/yac_mocks.hpp index e517ecfb9c..7e47109c97 100644 --- a/test/module/irohad/consensus/yac/yac_mocks.hpp +++ b/test/module/irohad/consensus/yac/yac_mocks.hpp @@ -224,13 +224,15 @@ namespace iroha { public: MOCK_CONST_METHOD2( hasSupermajority, - bool(const shared_model::interface::SignatureSetType &signatures, + bool(const shared_model::interface::types::SignatureRangeType + &signatures, const std::vector< std::shared_ptr> &peers)); MOCK_CONST_METHOD2(checkSize, bool(uint64_t current, uint64_t all)); MOCK_CONST_METHOD2( peersSubset, - bool(const shared_model::interface::SignatureSetType &signatures, + bool(const shared_model::interface::types::SignatureRangeType + &signatures, const std::vector< std::shared_ptr> &peers)); MOCK_CONST_METHOD3( diff --git a/test/module/irohad/validation/chain_validation_test.cpp b/test/module/irohad/validation/chain_validation_test.cpp index 6352bee226..f14c4df853 100644 --- a/test/module/irohad/validation/chain_validation_test.cpp +++ b/test/module/irohad/validation/chain_validation_test.cpp @@ -76,8 +76,7 @@ TEST_F(ChainValidationTest, ValidCase) { // Valid previous hash, has supermajority, correct peers subset => valid auto block = getBlockBuilder().build(); - EXPECT_CALL(*supermajority_checker, - hasSupermajority(testing::Ref(block.signatures()), _)) + EXPECT_CALL(*supermajority_checker, hasSupermajority(block.signatures(), _)) .WillOnce(Return(true)); EXPECT_CALL(*query, getPeers()).WillOnce(Return(peers)); @@ -118,8 +117,7 @@ TEST_F(ChainValidationTest, FailWhenNoSupermajority) { // Valid previous hash, no supermajority, correct peers subset => invalid auto block = getBlockBuilder().build(); - EXPECT_CALL(*supermajority_checker, - hasSupermajority(testing::Ref(block.signatures()), _)) + EXPECT_CALL(*supermajority_checker, hasSupermajority(block.signatures(), _)) .WillOnce(Return(false)); EXPECT_CALL(*query, getPeers()).WillOnce(Return(peers)); diff --git a/test/module/shared_model/cryptography/crypto_usage_test.cpp b/test/module/shared_model/cryptography/crypto_usage_test.cpp index a32b312d39..e426eec7ec 100644 --- a/test/module/shared_model/cryptography/crypto_usage_test.cpp +++ b/test/module/shared_model/cryptography/crypto_usage_test.cpp @@ -65,17 +65,15 @@ class CryptoUsageTest : public ::testing::Test { template bool verify(const T &signable) const { - return signable.signatures().size() > 0 - and std::all_of( - signable.signatures().begin(), - signable.signatures().end(), - [&signable](const shared_model::detail::PolymorphicWrapper< - shared_model::interface::Signature> &signature) { - return shared_model::crypto::CryptoVerifier<>::verify( - signature->signedData(), - signable.payload(), - signature->publicKey()); - }); + return boost::size(signable.signatures()) > 0 + and std::all_of(signable.signatures().begin(), + signable.signatures().end(), + [&signable](const auto &signature) { + return shared_model::crypto::CryptoVerifier<>::verify( + signature.signedData(), + signable.payload(), + signature.publicKey()); + }); } Blob data; From 4a02401964f7b7aee8a6dbae1e6bfb1ad3ec4994 Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Fri, 4 May 2018 17:28:03 +0300 Subject: [PATCH 081/110] YAC Rx timer dependency (#1280) * Remove delay parameter from invokeAfterDelay; * Add initYac method to localize ctor changes in tests * Use the same thread for each timer subscription * Add doc to coordination Signed-off-by: Andrei Lebedev --- irohad/consensus/yac/impl/timer_impl.cpp | 15 +++--- irohad/consensus/yac/impl/timer_impl.hpp | 19 +++++--- irohad/consensus/yac/impl/yac.cpp | 14 ++---- irohad/consensus/yac/timer.hpp | 6 +-- irohad/consensus/yac/yac.hpp | 9 +--- irohad/main/impl/consensus_init.cpp | 35 ++++++++++++-- irohad/main/impl/consensus_init.hpp | 2 +- .../consensus/consensus_sunny_day.cpp | 46 ++++++++----------- .../irohad/consensus/yac/timer_test.cpp | 24 ++++++---- .../module/irohad/consensus/yac/yac_mocks.hpp | 21 ++++----- .../consensus/yac/yac_rainy_day_test.cpp | 21 ++------- .../yac/yac_simple_cold_case_test.cpp | 42 +++-------------- .../consensus/yac/yac_sunny_day_test.cpp | 34 ++------------ .../consensus/yac/yac_unknown_peer_test.cpp | 7 +-- 14 files changed, 118 insertions(+), 177 deletions(-) diff --git a/irohad/consensus/yac/impl/timer_impl.cpp b/irohad/consensus/yac/impl/timer_impl.cpp index 429866f25b..cc152018e8 100644 --- a/irohad/consensus/yac/impl/timer_impl.cpp +++ b/irohad/consensus/yac/impl/timer_impl.cpp @@ -21,17 +21,18 @@ namespace iroha { namespace consensus { namespace yac { - void TimerImpl::invokeAfterDelay(uint64_t millis, - std::function handler) { + TimerImpl::TimerImpl( + std::function()> invoke_delay) + : invoke_delay_(std::move(invoke_delay)) {} + + void TimerImpl::invokeAfterDelay(std::function handler) { deny(); - handler_ = std::move(handler); - timer = rxcpp::observable<>::timer(std::chrono::milliseconds(millis)); - handle = timer.subscribe_on(rxcpp::observe_on_new_thread()) - .subscribe([this](auto) { handler_(); }); + handle_ = invoke_delay_().subscribe( + [handler{std::move(handler)}](auto) { handler(); }); } void TimerImpl::deny() { - handle.unsubscribe(); + handle_.unsubscribe(); } TimerImpl::~TimerImpl() { diff --git a/irohad/consensus/yac/impl/timer_impl.hpp b/irohad/consensus/yac/impl/timer_impl.hpp index 9304d268c3..e38081a7bf 100644 --- a/irohad/consensus/yac/impl/timer_impl.hpp +++ b/irohad/consensus/yac/impl/timer_impl.hpp @@ -26,21 +26,26 @@ namespace iroha { namespace yac { class TimerImpl : public Timer { public: - TimerImpl() = default; + /// Delay observable type + using TimeoutType = long; + + /** + * Constructor + * @param invoke_delay cold observable which specifies invoke strategy + */ + explicit TimerImpl( + std::function()> invoke_delay); TimerImpl(const TimerImpl &) = delete; TimerImpl &operator=(const TimerImpl &) = delete; - void invokeAfterDelay(uint64_t millis, - std::function handler) override; + void invokeAfterDelay(std::function handler) override; void deny() override; ~TimerImpl() override; private: - std::function handler_; - - rxcpp::observable timer; - rxcpp::composite_subscription handle; + std::function()> invoke_delay_; + rxcpp::composite_subscription handle_; }; } // namespace yac } // namespace consensus diff --git a/irohad/consensus/yac/impl/yac.cpp b/irohad/consensus/yac/impl/yac.cpp index aaec12c54f..68d5539c15 100644 --- a/irohad/consensus/yac/impl/yac.cpp +++ b/irohad/consensus/yac/impl/yac.cpp @@ -54,24 +54,21 @@ namespace iroha { std::shared_ptr network, std::shared_ptr crypto, std::shared_ptr timer, - ClusterOrdering order, - uint64_t delay) { + ClusterOrdering order) { return std::make_shared( - vote_storage, network, crypto, timer, order, delay); + vote_storage, network, crypto, timer, order); } Yac::Yac(YacVoteStorage vote_storage, std::shared_ptr network, std::shared_ptr crypto, std::shared_ptr timer, - ClusterOrdering order, - uint64_t delay) + ClusterOrdering order) : vote_storage_(std::move(vote_storage)), network_(std::move(network)), crypto_(std::move(crypto)), timer_(std::move(timer)), - cluster_order_(order), - delay_(delay) { + cluster_order_(order){ log_ = logger::log("YAC"); } @@ -137,8 +134,7 @@ namespace iroha { network_->send_vote(cluster_order_.currentLeader(), vote); cluster_order_.switchToNext(); if (cluster_order_.hasNext()) { - timer_->invokeAfterDelay(delay_, - [this, vote] { this->votingStep(vote); }); + timer_->invokeAfterDelay([this, vote] { this->votingStep(vote); }); } } diff --git a/irohad/consensus/yac/timer.hpp b/irohad/consensus/yac/timer.hpp index a99cfc4c39..8ee95b9312 100644 --- a/irohad/consensus/yac/timer.hpp +++ b/irohad/consensus/yac/timer.hpp @@ -30,12 +30,10 @@ namespace iroha { class Timer { public: /** - * Invoke handler after delay - * @param millis - number of milliseconds before invoking + * Invoke handler with class-specific strategy * @param handler - function, that will be invoked */ - virtual void invokeAfterDelay(uint64_t millis, - std::function handler) = 0; + virtual void invokeAfterDelay(std::function handler) = 0; /** * Stop timer diff --git a/irohad/consensus/yac/yac.hpp b/irohad/consensus/yac/yac.hpp index bdc499c06e..b3d3e92cb6 100644 --- a/irohad/consensus/yac/yac.hpp +++ b/irohad/consensus/yac/yac.hpp @@ -48,15 +48,13 @@ namespace iroha { std::shared_ptr network, std::shared_ptr crypto, std::shared_ptr timer, - ClusterOrdering order, - uint64_t delay); + ClusterOrdering order); Yac(YacVoteStorage vote_storage, std::shared_ptr network, std::shared_ptr crypto, std::shared_ptr timer, - ClusterOrdering order, - uint64_t delay); + ClusterOrdering order); // ------|Hash gate|------ @@ -133,9 +131,6 @@ namespace iroha { // ------|One round|------ ClusterOrdering cluster_order_; - // ------|Constants|------ - const uint64_t delay_; - // ------|Logger|------ logger::Logger log_; }; diff --git a/irohad/main/impl/consensus_init.cpp b/irohad/main/impl/consensus_init.cpp index 29da71f8b3..40984c9f10 100644 --- a/irohad/main/impl/consensus_init.cpp +++ b/irohad/main/impl/consensus_init.cpp @@ -45,8 +45,34 @@ namespace iroha { return crypto; } - auto YacInit::createTimer() { - return std::make_shared(); + auto YacInit::createTimer(std::chrono::milliseconds delay_milliseconds) { + return std::make_shared([delay_milliseconds] { + // static factory with a single thread + // + // observe_on_new_thread -- coordination which creates new thread with + // observe_on strategy -- all subsequent operations will be performed + // on this thread. + // + // scheduler owns a timeline that is exposed by the now() method. + // scheduler is also a factory for workers in that timeline. + // + // coordination is a factory for coordinators and has a scheduler. + // + // coordinator has a worker, and is a factory for coordinated + // observables, subscribers and schedulable functions. + // + // A new thread scheduler is created + // by calling .create_coordinator().get_scheduler() + // + // static allows to reuse the same thread in subsequent calls to this + // lambda + static rxcpp::observe_on_one_worker coordination( + rxcpp::observe_on_new_thread() + .create_coordinator() + .get_scheduler()); + return rxcpp::observable<>::timer( + std::chrono::milliseconds(delay_milliseconds), coordination); + }); } auto YacInit::createHashProvider() { @@ -60,9 +86,8 @@ namespace iroha { return Yac::create(YacVoteStorage(), createNetwork(), createCryptoProvider(keypair), - createTimer(), - initial_order, - delay_milliseconds.count()); + createTimer(delay_milliseconds), + initial_order); } std::shared_ptr YacInit::initConsensusGate( diff --git a/irohad/main/impl/consensus_init.hpp b/irohad/main/impl/consensus_init.hpp index ef50028753..dd2a82700e 100644 --- a/irohad/main/impl/consensus_init.hpp +++ b/irohad/main/impl/consensus_init.hpp @@ -48,7 +48,7 @@ namespace iroha { auto createCryptoProvider(const shared_model::crypto::Keypair &keypair); - auto createTimer(); + auto createTimer(std::chrono::milliseconds delay_milliseconds); auto createHashProvider(); diff --git a/test/integration/consensus/consensus_sunny_day.cpp b/test/integration/consensus/consensus_sunny_day.cpp index abeeb80601..413b8d8ece 100644 --- a/test/integration/consensus/consensus_sunny_day.cpp +++ b/test/integration/consensus/consensus_sunny_day.cpp @@ -42,7 +42,8 @@ class FixedCryptoProvider : public MockYacCryptoProvider { // TODO 15.04.2018 x3medima17 IR-1189: move to separate class auto size = shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair() - .publicKey().size(); + .publicKey() + .size(); // TODO 16.04.2018 x3medima17 IR-977: add sizes std::string key(size, 0); std::copy(public_key.begin(), public_key.end(), key.begin()); @@ -60,7 +61,6 @@ class FixedCryptoProvider : public MockYacCryptoProvider { class ConsensusSunnyDayTest : public ::testing::Test { public: - std::thread thread; std::unique_ptr server; std::shared_ptr network; std::shared_ptr crypto; @@ -73,40 +73,32 @@ class ConsensusSunnyDayTest : public ::testing::Test { void SetUp() override { network = std::make_shared(); crypto = std::make_shared(std::to_string(my_num)); - timer = std::make_shared(); + timer = std::make_shared([this] { + // static factory with a single thread + // see YacInit::createTimer in consensus_init.cpp + static rxcpp::observe_on_one_worker coordination( + rxcpp::observe_on_new_thread().create_coordinator().get_scheduler()); + return rxcpp::observable<>::timer(std::chrono::milliseconds(delay), + coordination); + }); auto order = ClusterOrdering::create(default_peers); ASSERT_TRUE(order); - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, order.value(), delay); + yac = Yac::create(YacVoteStorage(), network, crypto, timer, order.value()); network->subscribe(yac); - std::mutex mtx; - std::condition_variable cv; - - thread = std::thread([&cv, this] { - grpc::ServerBuilder builder; - int port = 0; - builder.AddListeningPort( - my_peer->address(), grpc::InsecureServerCredentials(), &port); - builder.RegisterService(network.get()); - server = builder.BuildAndStart(); - ASSERT_TRUE(server); - ASSERT_NE(port, 0); - cv.notify_one(); - server->Wait(); - }); - - // wait until server woke up - std::unique_lock lock(mtx); - cv.wait(lock); + grpc::ServerBuilder builder; + int port = 0; + builder.AddListeningPort( + my_peer->address(), grpc::InsecureServerCredentials(), &port); + builder.RegisterService(network.get()); + server = builder.BuildAndStart(); + ASSERT_TRUE(server); + ASSERT_NE(port, 0); } void TearDown() override { server->Shutdown(); - if (thread.joinable()) { - thread.join(); - } } static uint64_t my_num, delay_before, delay_after; diff --git a/test/module/irohad/consensus/yac/timer_test.cpp b/test/module/irohad/consensus/yac/timer_test.cpp index 3eed8b8e23..c97c17aebc 100644 --- a/test/module/irohad/consensus/yac/timer_test.cpp +++ b/test/module/irohad/consensus/yac/timer_test.cpp @@ -24,41 +24,45 @@ using namespace iroha::consensus::yac; class TimerTest : public ::testing::Test { protected: void SetUp() override { - timer = std::make_shared(); + timer = std::make_shared( + [this] { return invoke_delay.get_observable(); }); } void TearDown() override { timer.reset(); } + void invokeTimer() { + invoke_delay.get_subscriber().on_next(0); + } + public: + rxcpp::subjects::subject invoke_delay; std::shared_ptr timer; }; TEST_F(TimerTest, NothingInvokedWhenDenied) { int status = 0; - timer->invokeAfterDelay(50, [&status]() { status = 1; }); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + timer->invokeAfterDelay([&status] { status = 1; }); timer->deny(); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); + invokeTimer(); ASSERT_EQ(status, 0); } TEST_F(TimerTest, FirstInvokedWhenOneSubmitted) { int status = 0; - timer->invokeAfterDelay(10, [&status]() { status = 1; }); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); + timer->invokeAfterDelay([&status] { status = 1; }); + invokeTimer(); ASSERT_EQ(status, 1); } TEST_F(TimerTest, SecondInvokedWhenTwoSubmitted) { int status = 0; - timer->invokeAfterDelay(10, [&status]() { status = 1; }); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - timer->invokeAfterDelay(10, [&status]() { status = 2; }); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); + timer->invokeAfterDelay([&status] { status = 1; }); + timer->invokeAfterDelay([&status] { status = 2; }); + invokeTimer(); ASSERT_EQ(status, 2); } diff --git a/test/module/irohad/consensus/yac/yac_mocks.hpp b/test/module/irohad/consensus/yac/yac_mocks.hpp index 7e47109c97..36992fd860 100644 --- a/test/module/irohad/consensus/yac/yac_mocks.hpp +++ b/test/module/irohad/consensus/yac/yac_mocks.hpp @@ -100,8 +100,7 @@ namespace iroha { class MockTimer : public Timer { public: - void invokeAfterDelay(uint64_t millis, - std::function handler) override { + void invokeAfterDelay(std::function handler) override { handler(); } @@ -245,7 +244,6 @@ namespace iroha { std::shared_ptr network; std::shared_ptr crypto; std::shared_ptr timer; - uint64_t delay = 100500; std::shared_ptr yac; // ------|Round|------ @@ -265,18 +263,17 @@ namespace iroha { timer = std::make_shared(); auto ordering = ClusterOrdering::create(default_peers); ASSERT_TRUE(ordering); - yac = Yac::create(YacVoteStorage(), - network, - crypto, - timer, - ordering.value(), - delay); - network->subscribe(yac); - }; + initYac(ordering.value()); + } void TearDown() override { network->release(); - }; + } + + void initYac(ClusterOrdering ordering) { + yac = Yac::create(YacVoteStorage(), network, crypto, timer, ordering); + network->subscribe(yac); + } }; } // namespace yac } // namespace consensus diff --git a/test/module/irohad/consensus/yac/yac_rainy_day_test.cpp b/test/module/irohad/consensus/yac/yac_rainy_day_test.cpp index 98889ff8d8..28d1a87929 100644 --- a/test/module/irohad/consensus/yac/yac_rainy_day_test.cpp +++ b/test/module/irohad/consensus/yac/yac_rainy_day_test.cpp @@ -41,12 +41,7 @@ TEST_F(YacTest, InvalidCaseWhenNotReceiveSupermajority) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_commit(_, _)).Times(0); EXPECT_CALL(*network, send_reject(_, _)).Times(my_peers.size()); @@ -84,12 +79,7 @@ TEST_F(YacTest, InvalidCaseWhenDoesNotVerify) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_reject(_, _)).Times(0); @@ -128,12 +118,7 @@ TEST_F(YacTest, ValidCaseWhenReceiveOnVoteAfterReject) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_commit(_, _)).Times(0); EXPECT_CALL(*network, send_reject(_, _)) diff --git a/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp b/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp index 2476988ade..c889266f26 100644 --- a/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp +++ b/test/module/irohad/consensus/yac/yac_simple_cold_case_test.cpp @@ -30,40 +30,13 @@ using ::testing::_; using ::testing::An; using ::testing::AtLeast; -using ::testing::Return; using ::testing::Invoke; +using ::testing::Return; using namespace iroha::consensus::yac; using namespace framework::test_subscriber; using namespace std; -/** - * Test provide use case for init yac object - */ -TEST_F(YacTest, YacWhenInit) { - cout << "----------|Just init object|----------" << endl; - - MockYacNetwork network_; - - MockYacCryptoProvider crypto_; - - MockTimer timer_; - - auto fake_delay_ = 100500; - - auto order = ClusterOrdering::create(default_peers); - ASSERT_TRUE(order); - - auto yac_ = Yac::create(YacVoteStorage(), - std::make_shared(network_), - std::make_shared(crypto_), - std::make_shared(timer_), - *order, - fake_delay_); - - network_.subscribe(yac_); -} - /** * Test provide scenario when yac vote for hash */ @@ -181,14 +154,14 @@ TEST_F(YacTest, YacWhenColdStartAndAchieveCommitMessage) { * @then commit is sent to the network before notifying subscribers */ TEST_F(YacTest, PropagateCommitBeforeNotifyingSubscribersApplyVote) { - EXPECT_CALL(*crypto, verify(An())).Times(default_peers.size()) + EXPECT_CALL(*crypto, verify(An())) + .Times(default_peers.size()) .WillRepeatedly(Return(true)); std::vector messages; EXPECT_CALL(*network, send_commit(_, _)) .Times(default_peers.size()) - .WillRepeatedly(Invoke([&](const auto &, const auto &msg) { - messages.push_back(msg); - })); + .WillRepeatedly(Invoke( + [&](const auto &, const auto &msg) { messages.push_back(msg); })); yac->on_commit().subscribe([&](auto msg) { // verify that commits are already sent to the network @@ -215,9 +188,8 @@ TEST_F(YacTest, PropagateCommitBeforeNotifyingSubscribersApplyReject) { std::vector messages; EXPECT_CALL(*network, send_commit(_, _)) .Times(default_peers.size()) - .WillRepeatedly(Invoke([&](const auto &, const auto &msg) { - messages.push_back(msg); - })); + .WillRepeatedly(Invoke( + [&](const auto &, const auto &msg) { messages.push_back(msg); })); yac->on_commit().subscribe([&](auto msg) { // verify that commits are already sent to the network diff --git a/test/module/irohad/consensus/yac/yac_sunny_day_test.cpp b/test/module/irohad/consensus/yac/yac_sunny_day_test.cpp index c78c85bf14..c79e93e1fb 100644 --- a/test/module/irohad/consensus/yac/yac_sunny_day_test.cpp +++ b/test/module/irohad/consensus/yac/yac_sunny_day_test.cpp @@ -41,12 +41,7 @@ TEST_F(YacTest, ValidCaseWhenReceiveSupermajority) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_commit(_, _)).Times(my_peers.size()); EXPECT_CALL(*network, send_reject(_, _)).Times(0); @@ -76,12 +71,7 @@ TEST_F(YacTest, ValidCaseWhenReceiveCommit) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); YacHash my_hash("proposal_hash", "block_hash"); auto wrapper = make_test_subscriber(yac->on_commit(), 1); @@ -118,13 +108,9 @@ TEST_F(YacTest, ValidCaseWhenReceiveCommitTwice) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; EXPECT_CALL(*timer, deny()).Times(2); - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); YacHash my_hash("proposal_hash", "block_hash"); auto wrapper = make_test_subscriber(yac->on_commit(), 1); @@ -166,12 +152,7 @@ TEST_F(YacTest, ValidCaseWhenSoloConsensus) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_commit(_, _)).Times(my_peers.size()); EXPECT_CALL(*network, send_reject(_, _)).Times(0); @@ -214,12 +195,7 @@ TEST_F(YacTest, ValidCaseWhenVoteAfterCommit) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_commit(_, _)).Times(0); EXPECT_CALL(*network, send_reject(_, _)).Times(0); diff --git a/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp b/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp index 8c9cc0fa01..fdf8a80da5 100644 --- a/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp +++ b/test/module/irohad/consensus/yac/yac_unknown_peer_test.cpp @@ -73,12 +73,7 @@ TEST_F(YacTest, UnknownVoteAfterCommit) { auto my_order = ClusterOrdering::create(my_peers); ASSERT_TRUE(my_order); - // delay preference - uint64_t wait_seconds = 10; - delay = wait_seconds * 1000; - - yac = Yac::create( - YacVoteStorage(), network, crypto, timer, my_order.value(), delay); + initYac(my_order.value()); EXPECT_CALL(*network, send_commit(_, _)).Times(0); EXPECT_CALL(*network, send_reject(_, _)).Times(0); From 681b48d4124a40ba1af6d7618aabc0ac422a59cf Mon Sep 17 00:00:00 2001 From: victordrobny Date: Mon, 7 May 2018 04:51:00 +0300 Subject: [PATCH 082/110] Add configurable size to libs/cache (#1287) * Add configurable size to libs/cache Signed-off-by: Victor Drobny --- libs/cache/cache.hpp | 34 +++++++++++++++++---------- test/module/libs/cache/cache_test.cpp | 21 +++++++++++++++++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/libs/cache/cache.hpp b/libs/cache/cache.hpp index 6dce9e7002..fb52bd9dd2 100644 --- a/libs/cache/cache.hpp +++ b/libs/cache/cache.hpp @@ -25,22 +25,30 @@ namespace iroha { namespace cache { - /** - * Cache for arbitrary types - * @tparam KeyType type of key objects - * @tparam ValueType type of value objects - * @tparam KeyHash hasher for keys - */ - template > - class Cache - : public AbstractCache> { + /** + * Cache for arbitrary types + * @tparam KeyType type of key objects + * @tparam ValueType type of value objects + * @tparam KeyHash hasher for keys + */ + template > + class Cache : public AbstractCache> { public: + Cache(uint32_t max_handler_map_size_high = 20000, + uint32_t max_handler_map_size_low = 10000) + : max_handler_map_size_high_(max_handler_map_size_high), + max_handler_map_size_low_(max_handler_map_size_low) {} + uint32_t getIndexSizeHighImpl() const { - return MAX_HANDLER_MAP_SIZE_HIGH; + return max_handler_map_size_high_; } uint32_t getIndexSizeLowImpl() const { - return MAX_HANDLER_MAP_SIZE_LOW; + return max_handler_map_size_low_; } uint32_t getCacheItemCountImpl() const { @@ -77,8 +85,8 @@ namespace iroha { * TODO 27/10/2017 luckychess Values are quite random and should be tuned * for better performance and may be even move to config IR-579 */ - const uint32_t MAX_HANDLER_MAP_SIZE_HIGH = 20000; - const uint32_t MAX_HANDLER_MAP_SIZE_LOW = 10000; + const uint32_t max_handler_map_size_high_; + const uint32_t max_handler_map_size_low_; }; } // namespace cache } // namespace iroha diff --git a/test/module/libs/cache/cache_test.cpp b/test/module/libs/cache/cache_test.cpp index cc390238c0..825fc77d0d 100644 --- a/test/module/libs/cache/cache_test.cpp +++ b/test/module/libs/cache/cache_test.cpp @@ -170,3 +170,24 @@ TEST(CacheTest, CustomHasher) { ASSERT_TRUE(val); ASSERT_EQ(val.value(), value); } + +/** + * @given initialized cache with given parameters + * @when insert cache.getIndexSizeHigh() items into it + 1 + * @then after the last insertion amount of items should decrease to + * cache.getIndexSizeLow() + */ +TEST(CacheTest, InsertCustomSize) { + Cache cache(1, 1); + cache.addItem("key", "value"); + ASSERT_EQ(cache.getCacheItemCount(), cache.getIndexSizeHigh()); + auto val = cache.findItem("key"); + ASSERT_TRUE(val); + ASSERT_EQ(val.value(), "value"); + cache.addItem("key2", "value2"); + ASSERT_EQ(cache.getCacheItemCount(), cache.getIndexSizeLow()); + val = cache.findItem("key"); + ASSERT_FALSE(val); + ASSERT_TRUE(cache.findItem("key2")); + ASSERT_EQ(cache.findItem("key2").value(), "value2"); +} From 90f767b5f527a9644e0d4903cc1460d0a171c50c Mon Sep 17 00:00:00 2001 From: Sergei Date: Mon, 7 May 2018 14:34:00 +0700 Subject: [PATCH 083/110] add on_commit observable to storage (#1291) Signed-off-by: Moonraker --- irohad/ametsuchi/impl/storage_impl.cpp | 6 ++++++ irohad/ametsuchi/impl/storage_impl.hpp | 14 +++++++++++--- irohad/ametsuchi/storage.hpp | 14 ++++++++++++-- test/module/irohad/ametsuchi/ametsuchi_mocks.hpp | 3 +++ test/module/irohad/ametsuchi/ametsuchi_test.cpp | 4 ++++ 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/irohad/ametsuchi/impl/storage_impl.cpp b/irohad/ametsuchi/impl/storage_impl.cpp index 150c30f948..564187c53f 100644 --- a/irohad/ametsuchi/impl/storage_impl.cpp +++ b/irohad/ametsuchi/impl/storage_impl.cpp @@ -126,6 +126,8 @@ namespace iroha { const auto &top_hash) { return true; }); log_->info("block inserted: {}", inserted); commit(std::move(storage.value)); + notifier_.get_subscriber().on_next( + std::shared_ptr(clone(block))); }, [&](expected::Error &error) { log_->error(error.error); @@ -283,5 +285,9 @@ DROP TABLE IF EXISTS index_by_id_height_asset; std::shared_ptr StorageImpl::getBlockQuery() const { return blocks_; } + rxcpp::observable> + StorageImpl::on_commit() { + return notifier_.get_observable(); + } } // namespace ametsuchi } // namespace iroha diff --git a/irohad/ametsuchi/impl/storage_impl.hpp b/irohad/ametsuchi/impl/storage_impl.hpp index db05de7358..5ea53adb95 100644 --- a/irohad/ametsuchi/impl/storage_impl.hpp +++ b/irohad/ametsuchi/impl/storage_impl.hpp @@ -20,8 +20,8 @@ #include "ametsuchi/storage.hpp" -#include #include +#include #include #include #include "logger/logger.hpp" @@ -61,7 +61,8 @@ namespace iroha { * @param blocks - block for insertion * @return true if all blocks are inserted */ - virtual bool insertBlock(const shared_model::interface::Block &block) override; + virtual bool insertBlock( + const shared_model::interface::Block &block) override; /** * Insert blocks without validation @@ -69,7 +70,8 @@ namespace iroha { * @return true if inserted */ virtual bool insertBlocks( - const std::vector> &blocks) override; + const std::vector> + &blocks) override; virtual void dropStorage() override; @@ -79,6 +81,9 @@ namespace iroha { std::shared_ptr getBlockQuery() const override; + rxcpp::observable> + on_commit() override; + ~StorageImpl() override; protected: @@ -115,6 +120,9 @@ namespace iroha { logger::Logger log_; + rxcpp::subjects::subject> + notifier_; + protected: const std::string init_ = R"( CREATE TABLE IF NOT EXISTS role ( diff --git a/irohad/ametsuchi/storage.hpp b/irohad/ametsuchi/storage.hpp index 0678591684..f9d84b2959 100644 --- a/irohad/ametsuchi/storage.hpp +++ b/irohad/ametsuchi/storage.hpp @@ -18,6 +18,7 @@ #ifndef IROHA_AMETSUCHI_H #define IROHA_AMETSUCHI_H +#include #include #include "ametsuchi/mutable_factory.hpp" #include "ametsuchi/temporary_factory.hpp" @@ -27,7 +28,7 @@ namespace shared_model { namespace interface { class Block; } -} +} // namespace shared_model namespace iroha { @@ -58,7 +59,16 @@ namespace iroha { * @param blocks - collection of blocks for insertion * @return true if inserted */ - virtual bool insertBlocks(const std::vector> &blocks) = 0; + virtual bool insertBlocks( + const std::vector> + &blocks) = 0; + + /** + * method called when block is written to the storage + * @return observable with the Block committed + */ + virtual rxcpp::observable> + on_commit() = 0; /** * Remove all information from ledger diff --git a/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp b/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp index 827c004b83..effb87a23c 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp +++ b/test/module/irohad/ametsuchi/ametsuchi_mocks.hpp @@ -232,6 +232,9 @@ namespace iroha { bool(const std::vector< std::shared_ptr> &)); MOCK_METHOD0(dropStorage, void(void)); + MOCK_METHOD0( + on_commit, + rxcpp::observable>()); void commit(std::unique_ptr storage) override { doCommit(storage.get()); diff --git a/test/module/irohad/ametsuchi/ametsuchi_test.cpp b/test/module/irohad/ametsuchi/ametsuchi_test.cpp index 42bf5f1175..bc99c6f5b3 100644 --- a/test/module/irohad/ametsuchi/ametsuchi_test.cpp +++ b/test/module/irohad/ametsuchi/ametsuchi_test.cpp @@ -621,6 +621,8 @@ TEST_F(AmetsuchiTest, TestingStorageWhenInsertBlock) { "=> insert block " "=> assert that inserted"); ASSERT_TRUE(storage); + auto wrapper = make_test_subscriber(storage->on_commit(), 1); + wrapper.subscribe(); auto wsv = storage->getWsvQuery(); ASSERT_EQ(0, wsv->getPeers().value().size()); @@ -636,6 +638,8 @@ TEST_F(AmetsuchiTest, TestingStorageWhenInsertBlock) { log->info("Drop ledger"); storage->dropStorage(); + + ASSERT_TRUE(wrapper.validate()); } TEST_F(AmetsuchiTest, TestingStorageWhenDropAll) { From c32c081f517f41ecffeda17123a0290b512053e3 Mon Sep 17 00:00:00 2001 From: Sergei Date: Mon, 7 May 2018 14:34:23 +0700 Subject: [PATCH 084/110] add can_get_blocks permission (#1288) * add can_get_blocks permission Signed-off-by: Moonraker * add can_get_blocks to genesis block Signed-off-by: Moonraker --- example/genesis.block | 3 ++- schema/primitive.proto | 1 + shared_model/validators/permissions.hpp | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/example/genesis.block b/example/genesis.block index 464d26bd50..bb30df3c22 100644 --- a/example/genesis.block +++ b/example/genesis.block @@ -30,7 +30,8 @@ "can_get_roles", "can_read_assets", "can_remove_signatory", - "can_set_quorum" + "can_set_quorum", + "can_get_blocks" ] } }, diff --git a/schema/primitive.proto b/schema/primitive.proto index cc2355221f..e930eb7516 100644 --- a/schema/primitive.proto +++ b/schema/primitive.proto @@ -63,6 +63,7 @@ enum RolePermission { can_get_domain_acc_ast_txs = 34; can_get_my_txs = 35; can_get_all_txs = 36; + can_get_blocks = 42; // Grant permissions can_grant_can_set_my_quorum = 37; diff --git a/shared_model/validators/permissions.hpp b/shared_model/validators/permissions.hpp index 876f89a610..605885e6a1 100644 --- a/shared_model/validators/permissions.hpp +++ b/shared_model/validators/permissions.hpp @@ -115,6 +115,9 @@ namespace shared_model { const std::string can_get_my_txs = "can_get_my_txs"; const std::string can_get_all_txs = "can_get_all_txs"; + /* Blocks */ + const std::string can_get_blocks = "can_get_blocks"; + /* ~~~~~~~~ Groups ~~~~~~~~ */ const std::set read_self_group = {can_get_my_account, can_get_my_signatories, @@ -132,7 +135,8 @@ namespace shared_model { can_get_all_acc_ast_txs, can_get_all_txs, can_get_roles, - can_read_assets}; + can_read_assets, + can_get_blocks}; const std::set read_domain_group = { can_get_domain_accounts, @@ -250,7 +254,8 @@ namespace shared_model { can_remove_my_signatory, can_set_my_quorum, can_set_my_account_detail, - can_transfer_my_assets}; + can_transfer_my_assets, + can_get_blocks}; } // namespace shared_model } // namespace permissions From e662fc4bb9c4b51a6e2a79ba243cce378954faf7 Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Mon, 7 May 2018 19:01:23 +0300 Subject: [PATCH 085/110] * Fix operator== for signatures type in old-fashion model and sh_m (#1302) * Fix operator== for signatures type in old-fashion model and sh_m * Fix ::addSignature for tx and block Signed-off-by: Fedor Muratov --- irohad/model/impl/model_operators.cpp | 2 +- shared_model/backend/protobuf/block.hpp | 2 +- shared_model/backend/protobuf/transaction.hpp | 2 +- .../interfaces/common_objects/signature.hpp | 3 +- .../model/operators/model_operators_test.cpp | 10 +++- .../shared_model/cryptography/CMakeLists.txt | 5 ++ .../cryptography/security_signatures_test.cpp | 58 +++++++++++++++++++ 7 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 test/module/shared_model/cryptography/security_signatures_test.cpp diff --git a/irohad/model/impl/model_operators.cpp b/irohad/model/impl/model_operators.cpp index 5e2e5256d9..89eb627738 100644 --- a/irohad/model/impl/model_operators.cpp +++ b/irohad/model/impl/model_operators.cpp @@ -201,7 +201,7 @@ namespace iroha { /* Signature */ bool Signature::operator==(const Signature &rhs) const { - return rhs.pubkey == pubkey && rhs.signature == signature; + return rhs.pubkey == pubkey; } /* Transaction */ diff --git a/shared_model/backend/protobuf/block.hpp b/shared_model/backend/protobuf/block.hpp index df169cb245..826bd59a3e 100644 --- a/shared_model/backend/protobuf/block.hpp +++ b/shared_model/backend/protobuf/block.hpp @@ -127,7 +127,7 @@ namespace shared_model { }}; const Lazy> signatures_{[this] { - SignatureSetType sigs; + SignatureSetType sigs; for (const auto &sig : proto_->signatures()) { sigs.emplace(sig); } diff --git a/shared_model/backend/protobuf/transaction.hpp b/shared_model/backend/protobuf/transaction.hpp index 6b38db0bc2..41a6517cdd 100644 --- a/shared_model/backend/protobuf/transaction.hpp +++ b/shared_model/backend/protobuf/transaction.hpp @@ -66,7 +66,7 @@ namespace shared_model { // if already has such signature if (std::find_if(signatures_->begin(), signatures_->end(), - [&public_key](const auto& signature) { + [&public_key](const auto &signature) { return signature.publicKey() == public_key; }) != signatures_->end()) { diff --git a/shared_model/interfaces/common_objects/signature.hpp b/shared_model/interfaces/common_objects/signature.hpp index f0b43a1a57..f3d5ff0e3f 100644 --- a/shared_model/interfaces/common_objects/signature.hpp +++ b/shared_model/interfaces/common_objects/signature.hpp @@ -58,8 +58,7 @@ namespace shared_model { virtual const SignedType &signedData() const = 0; bool operator==(const Signature &rhs) const override { - return publicKey() == rhs.publicKey() - and signedData() == rhs.signedData(); + return publicKey() == rhs.publicKey(); } #ifndef DISABLE_BACKWARD diff --git a/test/module/irohad/model/operators/model_operators_test.cpp b/test/module/irohad/model/operators/model_operators_test.cpp index 8f27c9a17b..059d4ca1ba 100644 --- a/test/module/irohad/model/operators/model_operators_test.cpp +++ b/test/module/irohad/model/operators/model_operators_test.cpp @@ -313,7 +313,15 @@ TEST(ModelOperatorTest, SignatureTest) { ASSERT_EQ(sig1, sig2); sig1.signature[0] = 0x23; - ASSERT_NE(sig1, sig2); + + // equals because public keys are same + ASSERT_EQ(sig1, sig2); + + auto sig3 = createSignature(); + sig3.pubkey[0] = 0x23; + + // not equals because public keys are different + ASSERT_NE(sig1, sig3); } // -----|Transaction|----- diff --git a/test/module/shared_model/cryptography/CMakeLists.txt b/test/module/shared_model/cryptography/CMakeLists.txt index 4c7d50cb05..f704652d62 100644 --- a/test/module/shared_model/cryptography/CMakeLists.txt +++ b/test/module/shared_model/cryptography/CMakeLists.txt @@ -10,3 +10,8 @@ target_link_libraries(crypto_usage_test schema iroha_amount ) + +addtest(security_signatures_test security_signatures_test.cpp) +target_link_libraries(security_signatures_test + shared_model_proto_builders + ) diff --git a/test/module/shared_model/cryptography/security_signatures_test.cpp b/test/module/shared_model/cryptography/security_signatures_test.cpp new file mode 100644 index 0000000000..6be8824a5b --- /dev/null +++ b/test/module/shared_model/cryptography/security_signatures_test.cpp @@ -0,0 +1,58 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "module/shared_model/builders/protobuf/test_block_builder.hpp" +#include "module/shared_model/builders/protobuf/test_signature_builder.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" + +/** + * @given Two signatures with same pub key but different signed + * @when Invoke operator== + * @then Expect true + */ +TEST(SecuritySignature, SignatureOperatorEqual) { + auto first_signature = + TestSignatureBuilder() + .publicKey(shared_model::crypto::PublicKey("one")) + .signedData(shared_model::crypto::Signed("signed_one")) + .build(); + + auto second_signature = + TestSignatureBuilder() + .publicKey(shared_model::crypto::PublicKey("one")) + .signedData(shared_model::crypto::Signed("signed_two")) + .build(); + + ASSERT_TRUE(first_signature == second_signature); +} + +/** + * @given Transaction with given signature + * @when Invoke ::addSignature with same public key but different signed + * @then Expect that second signature wasn't added + */ +TEST(SecuritySignature, TransactionAddsignature) { + auto tx = TestTransactionBuilder().build(); + ASSERT_TRUE(tx.addSignature(shared_model::crypto::Signed("sign_one"), + shared_model::crypto::PublicKey("key_one"))); + ASSERT_FALSE(tx.addSignature(shared_model::crypto::Signed("sign_two"), + shared_model::crypto::PublicKey("key_one"))); +} + +/** + * @given Block with given signature + * @when Invoke ::addSignature with same public key but different signed + * @then Expect that second signature wasn't added + */ +TEST(SecuritySignature, BlockAddSignature) { + auto block = TestBlockBuilder().build(); + ASSERT_TRUE(block.addSignature(shared_model::crypto::Signed("sign_one"), + shared_model::crypto::PublicKey("key_one"))); + ASSERT_FALSE(block.addSignature(shared_model::crypto::Signed("sign_two"), + shared_model::crypto::PublicKey("key_one"))); +} From e4cb14915bbd0ad6b322fcf1bf68287d69d0e4bb Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Wed, 9 May 2018 01:38:19 +0300 Subject: [PATCH 086/110] Fix consensus sunny day test (#1310) * Fix wakeup in consensus sunny day test * Fix file descriptors not being closed in iroha-ed25519 randombytes Signed-off-by: Andrei Lebedev --- cmake/Modules/Finded25519.cmake | 6 ++++ patch/close.patch | 29 +++++++++++++++++++ .../consensus/consensus_sunny_day.cpp | 15 ++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 patch/close.patch diff --git a/cmake/Modules/Finded25519.cmake b/cmake/Modules/Finded25519.cmake index bb50631f50..4db83c862f 100644 --- a/cmake/Modules/Finded25519.cmake +++ b/cmake/Modules/Finded25519.cmake @@ -16,10 +16,16 @@ set(VERSION e7188b8393dbe5ac54378610d53630bd4a180038) set_target_description(ed25519 "Digital signature algorithm" ${URL} ${VERSION}) if (NOT ed25519_FOUND) + if (NOT WIN32) + find_package(Git REQUIRED) + set(PATCH_RANDOM ${GIT_EXECUTABLE} apply ${PROJECT_SOURCE_DIR}/patch/close.patch || true) + endif () + externalproject_add(hyperledger_ed25519 GIT_REPOSITORY ${URL} GIT_TAG ${VERSION} CMAKE_ARGS -DTESTING=OFF -DBUILD=STATIC + PATCH_COMMAND ${PATCH_RANDOM} BUILD_BYPRODUCTS ${EP_PREFIX}/src/hyperledger_ed25519-build/libed25519.a INSTALL_COMMAND "" # remove install step TEST_COMMAND "" # remove test step diff --git a/patch/close.patch b/patch/close.patch new file mode 100644 index 0000000000..3138b895b6 --- /dev/null +++ b/patch/close.patch @@ -0,0 +1,29 @@ +diff --git a/lib/randombytes/random/random.c b/lib/randombytes/random/random.c +index e5eca79..e6e862e 100644 +--- a/lib/randombytes/random/random.c ++++ b/lib/randombytes/random/random.c +@@ -13,6 +13,7 @@ int randombytes(unsigned char *p, int len) { + while (completed < len) { + ssize_t result = read(source, p + completed, len - completed); + if (result < 0) { ++ close(source); + return ED25519_ERROR; + } + completed += result; +diff --git a/lib/randombytes/urandom/urandom.c b/lib/randombytes/urandom/urandom.c +index ecad2cf..5b4ec0d 100644 +--- a/lib/randombytes/urandom/urandom.c ++++ b/lib/randombytes/urandom/urandom.c +@@ -9,9 +9,12 @@ int randombytes(unsigned char *p, int len) { + } else { + ssize_t result = read(source, p, len); + if (result < 0) { ++ close(source); + return ED25519_ERROR; /* something went wrong */ + } + } + ++ close(source); ++ + return ED25519_SUCCESS; + } diff --git a/test/integration/consensus/consensus_sunny_day.cpp b/test/integration/consensus/consensus_sunny_day.cpp index 413b8d8ece..1e40bdf539 100644 --- a/test/integration/consensus/consensus_sunny_day.cpp +++ b/test/integration/consensus/consensus_sunny_day.cpp @@ -26,6 +26,7 @@ #include "module/shared_model/builders/protobuf/test_signature_builder.hpp" using ::testing::An; +using ::testing::InvokeWithoutArgs; using ::testing::Return; using namespace iroha::consensus::yac; @@ -114,7 +115,7 @@ class ConsensusSunnyDayTest : public ::testing::Test { } if (num_peers == 1) { delay_before = 0; - delay_after = 50; + delay_after = 5 * 1000; } else { delay_before = 10 * 1000; delay_after = 3 * default_peers.size() + 10 * 1000; @@ -130,13 +131,19 @@ std::vector> ConsensusSunnyDayTest::default_peers; TEST_F(ConsensusSunnyDayTest, SunnyDayTest) { + std::condition_variable cv; auto wrapper = make_test_subscriber(yac->on_commit(), 1); wrapper.subscribe( [](auto hash) { std::cout << "^_^ COMMITTED!!!" << std::endl; }); EXPECT_CALL(*crypto, verify(An())) .Times(1) - .WillRepeatedly(Return(true)); + .WillRepeatedly(DoAll(InvokeWithoutArgs([&cv] { + // wake up after commit is received from the + // network so that it is safe to shutdown + cv.notify_one(); + }), + Return(true))); EXPECT_CALL(*crypto, verify(An())).WillRepeatedly(Return(true)); // Wait for other peers to start @@ -148,7 +155,9 @@ TEST_F(ConsensusSunnyDayTest, SunnyDayTest) { ASSERT_TRUE(order); yac->vote(my_hash, *order); - std::this_thread::sleep_for(std::chrono::milliseconds(delay_after)); + std::mutex m; + std::unique_lock lk(m); + cv.wait_for(lk, std::chrono::milliseconds(delay_after)); ASSERT_TRUE(wrapper.validate()); } From 653a876004c2838c8e8ddcefebda46df4663584b Mon Sep 17 00:00:00 2001 From: victordrobny Date: Wed, 9 May 2018 14:19:35 +0300 Subject: [PATCH 087/110] update grpc and protobuf versions (#1217) * update grpc and protobuf versions Signed-off-by: Victor Drobny --- cmake/Modules/Findgrpc.cmake | 4 +-- cmake/Modules/Findprotobuf.cmake | 2 +- docker/develop/Dockerfile | 8 ++--- docker/develop/armv7l/Dockerfile | 0 docker/develop/x86_64/Dockerfile | 0 docs/source/guides/dependencies.rst | 2 +- patch/fix-protobuf-package-include.patch | 36 ------------------- .../packages/android/android-build.sh | 4 +-- shared_model/packages/ios/ios-build.sh | 4 +-- .../scripts/install-dependencies.sh | 5 +-- snap/snapcraft.yaml | 4 +-- 11 files changed, 16 insertions(+), 53 deletions(-) create mode 100644 docker/develop/armv7l/Dockerfile create mode 100644 docker/develop/x86_64/Dockerfile delete mode 100644 patch/fix-protobuf-package-include.patch diff --git a/cmake/Modules/Findgrpc.cmake b/cmake/Modules/Findgrpc.cmake index cc32a12ff0..5bf71b0f49 100644 --- a/cmake/Modules/Findgrpc.cmake +++ b/cmake/Modules/Findgrpc.cmake @@ -26,7 +26,7 @@ find_package_handle_standard_args(grpc DEFAULT_MSG ) set(URL https://github.com/grpc/grpc) -set(VERSION bfcbad3b86c7912968dc8e64f2121c920dad4dfb) +set(VERSION bd44e485f69d70ca4095cea92decd98de3892aa6) # Release 1.11.0 set_target_description(grpc "Remote Procedure Call library" ${URL} ${VERSION}) if (NOT grpc_FOUND) @@ -40,8 +40,6 @@ if (NOT grpc_FOUND) -DProtobuf_DIR=${EP_PREFIX}/src/google_protobuf-build/lib/cmake/protobuf -DgRPC_ZLIB_PROVIDER=package -DBUILD_SHARED_LIBS=ON - PATCH_COMMAND - ${GIT_EXECUTABLE} apply ${PROJECT_SOURCE_DIR}/patch/fix-protobuf-package-include.patch || true BUILD_BYPRODUCTS ${EP_PREFIX}/src/grpc_grpc-build/grpc_cpp_plugin ${EP_PREFIX}/src/grpc_grpc-build/${CMAKE_SHARED_LIBRARY_PREFIX}gpr${CMAKE_SHARED_LIBRARY_SUFFIX} diff --git a/cmake/Modules/Findprotobuf.cmake b/cmake/Modules/Findprotobuf.cmake index ac033a5391..0b7d61e338 100644 --- a/cmake/Modules/Findprotobuf.cmake +++ b/cmake/Modules/Findprotobuf.cmake @@ -19,7 +19,7 @@ find_package_handle_standard_args(protobuf DEFAULT_MSG ) set(URL https://github.com/google/protobuf.git) -set(VERSION 80a37e0782d2d702d52234b62dd4b9ec74fd2c95) +set(VERSION 106ffc04be1abf3ff3399f54ccf149815b287dd9) # Protocol Buffers v3.5.1 set_target_description(protobuf "Protocol buffers library" ${URL} ${VERSION}) if (NOT protobuf_FOUND) diff --git a/docker/develop/Dockerfile b/docker/develop/Dockerfile index 2eb33f6f1d..ff3c3a3bca 100644 --- a/docker/develop/Dockerfile +++ b/docker/develop/Dockerfile @@ -55,10 +55,10 @@ RUN set -e; \ ldconfig; \ rm -rf /tmp/boost -# install protobuf +# install protobuf v3.5.1 RUN set -e; \ git clone https://github.com/google/protobuf /tmp/protobuf; \ - (cd /tmp/protobuf ; git checkout 80a37e0782d2d702d52234b62dd4b9ec74fd2c95); \ + (cd /tmp/protobuf ; git checkout 106ffc04be1abf3ff3399f54ccf149815b287dd9); \ cmake \ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ -Dprotobuf_BUILD_TESTS=OFF \ @@ -93,11 +93,11 @@ RUN set -e; \ ldconfig; \ rm -rf /tmp/c-ares -# install grpc +# install grpc 1.11.0 RUN set -e; \ git clone https://github.com/grpc/grpc /tmp/grpc; \ cd /tmp/grpc; \ - git checkout bfcbad3b86c7912968dc8e64f2121c920dad4dfb; \ + git checkout bd44e485f69d70ca4095cea92decd98de3892aa6; \ cmake \ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ -DgRPC_BENCHMARK_PROVIDER="" \ diff --git a/docker/develop/armv7l/Dockerfile b/docker/develop/armv7l/Dockerfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docker/develop/x86_64/Dockerfile b/docker/develop/x86_64/Dockerfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/source/guides/dependencies.rst b/docs/source/guides/dependencies.rst index 6fdc99c511..b959ec9c2f 100644 --- a/docs/source/guides/dependencies.rst +++ b/docs/source/guides/dependencies.rst @@ -226,7 +226,7 @@ Installation on macOS CMAKE_BUILD_TYPE="Release" git clone https://github.com/google/protobuf /tmp/protobuf; - (cd /tmp/protobuf ; git checkout 80a37e0782d2d702d52234b62dd4b9ec74fd2c95); + (cd /tmp/protobuf ; git checkout 106ffc04be1abf3ff3399f54ccf149815b287dd9); cmake \ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ -Dprotobuf_BUILD_TESTS=OFF \ diff --git a/patch/fix-protobuf-package-include.patch b/patch/fix-protobuf-package-include.patch deleted file mode 100644 index e749a39d2a..0000000000 --- a/patch/fix-protobuf-package-include.patch +++ /dev/null @@ -1,36 +0,0 @@ -From a277fd504e6e8978bbb5e088cc45961e2a804694 Mon Sep 17 00:00:00 2001 -From: Andrei Lebedev -Date: Sun, 17 Sep 2017 10:34:22 +0800 -Subject: [PATCH] Fix protobuf_generate_grpc_cpp when package is not located in - usr/local - ---- - CMakeLists.txt | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index a5a7fad..4205a7e 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -203,16 +203,17 @@ elseif("${gRPC_PROTOBUF_PROVIDER}" STREQUAL "package") - if(TARGET protobuf::protoc) - set(_gRPC_PROTOBUF_PROTOC protobuf::protoc) - set(_gRPC_PROTOBUF_PROTOC_EXECUTABLE $) -+ get_target_property(PROTOBUF_WELLKNOWN_IMPORT_DIR protobuf::libprotoc INTERFACE_INCLUDE_DIRECTORIES) - else() - set(_gRPC_PROTOBUF_PROTOC ${PROTOBUF_PROTOC_EXECUTABLE}) - set(_gRPC_PROTOBUF_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE}) -+ set(PROTOBUF_WELLKNOWN_IMPORT_DIR ${PROTOBUF_INCLUDE_DIRS}) - endif() - set(_gRPC_FIND_PROTOBUF "if(NOT Protobuf_FOUND AND NOT PROTOBUF_FOUND)\n find_package(Protobuf ${gRPC_PROTOBUF_PACKAGE_TYPE})\nendif()") - endif() - if(PROTOBUF_FOUND) - include_directories(${PROTOBUF_INCLUDE_DIRS}) - endif() -- set(PROTOBUF_WELLKNOWN_IMPORT_DIR /usr/local/include) - endif() - - if("${gRPC_SSL_PROVIDER}" STREQUAL "module") --- -2.7.4 - diff --git a/shared_model/packages/android/android-build.sh b/shared_model/packages/android/android-build.sh index e6359c87cc..c84eeca0e6 100755 --- a/shared_model/packages/android/android-build.sh +++ b/shared_model/packages/android/android-build.sh @@ -80,9 +80,9 @@ fi tar xf ./boost_1_66_0.tar.gz cp -R ./boost_1_66_0/boost "$DEPS_DIR"/include -# protobuf +# protobuf v3.5.1 git clone https://github.com/google/protobuf -(cd ./protobuf ; git checkout b5fbb742af122b565925987e65c08957739976a7) +(cd ./protobuf ; git checkout 106ffc04be1abf3ff3399f54ccf149815b287dd9) cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -H./protobuf/cmake -B./protobuf/host_build # build for host to get js_embed VERBOSE=1 cmake --build ./protobuf/host_build -- -j"$CORES" # to be able to run js_embed we need its host version diff --git a/shared_model/packages/ios/ios-build.sh b/shared_model/packages/ios/ios-build.sh index e4a336d583..a798c2fcf6 100755 --- a/shared_model/packages/ios/ios-build.sh +++ b/shared_model/packages/ios/ios-build.sh @@ -78,10 +78,10 @@ curl -OL https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar. tar xf ./boost_1_66_0.tar.gz cp -R ./boost_1_66_0/boost "$DEPS_DIR"/include -# protobuf +# protobuf v3.5.1 git clone https://github.com/google/protobuf (cd ./protobuf; -git checkout 80a37e0782d2d702d52234b62dd4b9ec74fd2c95) +git checkout 106ffc04be1abf3ff3399f54ccf149815b287dd9) cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -Dprotobuf_BUILD_TESTS=OFF -H./protobuf/cmake -B./protobuf/host_build # build for host to get js_embed VERBOSE=1 cmake --build ./protobuf/host_build -- -j"$CORES" # to be able to run js_embed we need its host version diff --git a/shared_model/packages/javascript/scripts/install-dependencies.sh b/shared_model/packages/javascript/scripts/install-dependencies.sh index 27cc229bcf..41f17879aa 100755 --- a/shared_model/packages/javascript/scripts/install-dependencies.sh +++ b/shared_model/packages/javascript/scripts/install-dependencies.sh @@ -20,8 +20,9 @@ git clone https://github.com/boostorg/boost /tmp/boost; \ (cd /tmp/boost ; sudo /tmp/boost/b2 link=static cxxflags="-std=c++14" -j "$(getconf _NPROCESSORS_ONLN)" install); \ rm -rf /tmp/boost -# Protobuf (static) -git clone --depth 1 --branch v3.5.1 https://github.com/google/protobuf +# Protobuf (static) v3.5.1 +git clone https://github.com/google/protobuf cd protobuf +git checkout 106ffc04be1abf3ff3399f54ccf149815b287dd9 cmake -Hcmake/ -Bbuild -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release sudo cmake --build build/ --target install -- -j"$(getconf _NPROCESSORS_ONLN)" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 554f11256b..fc482af82d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -60,7 +60,7 @@ parts: ./b2 cxxflags="-std=c++14" install protobuf: source: https://github.com/google/protobuf.git - source-commit: 80a37e0782d2d702d52234b62dd4b9ec74fd2c95 + source-commit: 106ffc04be1abf3ff3399f54ccf149815b287dd9 # Protocol Buffers v3.5.1 source-subdir: cmake plugin: cmake configflags: [-Dprotobuf_BUILD_TESTS=OFF, -Dprotobuf_BUILD_SHARED_LIBS=ON] @@ -79,7 +79,7 @@ parts: after: [cmake] grpc: source: https://github.com/grpc/grpc.git - source-commit: bfcbad3b86c7912968dc8e64f2121c920dad4dfb + source-commit: bd44e485f69d70ca4095cea92decd98de3892aa6 # Release 1.11.0 plugin: cmake configflags: - -DgRPC_ZLIB_PROVIDER=package From d85b160a802c159658d42705cd57b962fe7f16dc Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 10 May 2018 15:03:57 +0300 Subject: [PATCH 088/110] Fix gRPC libs not being installed in Dockerfile (#1325) Signed-off-by: Andrei Lebedev --- docker/develop/Dockerfile | 10 ++-------- docker/develop/armv7l/Dockerfile | 0 docker/develop/x86_64/Dockerfile | 0 3 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 docker/develop/armv7l/Dockerfile delete mode 100644 docker/develop/x86_64/Dockerfile diff --git a/docker/develop/Dockerfile b/docker/develop/Dockerfile index ff3c3a3bca..5d480fc386 100644 --- a/docker/develop/Dockerfile +++ b/docker/develop/Dockerfile @@ -96,8 +96,7 @@ RUN set -e; \ # install grpc 1.11.0 RUN set -e; \ git clone https://github.com/grpc/grpc /tmp/grpc; \ - cd /tmp/grpc; \ - git checkout bd44e485f69d70ca4095cea92decd98de3892aa6; \ + (cd /tmp/grpc ; git checkout bd44e485f69d70ca4095cea92decd98de3892aa6); \ cmake \ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ -DgRPC_BENCHMARK_PROVIDER="" \ @@ -109,12 +108,7 @@ RUN set -e; \ -DBUILD_SHARED_LIBS=ON \ -H/tmp/grpc \ -B/tmp/grpc/.build; \ - cd /tmp/grpc/.build; \ - make -j${PARALLELISM} gpr grpc grpc++ grpc_cpp_plugin; \ - # copy libs to /usr/local/lib - cp libgpr.so libgrpc.so libgrpc++.so libgrpc_plugin_support.so /usr/local/lib; \ - cp grpc_cpp_plugin /usr/local/bin; \ - cp -R ../include /usr/local; \ + cmake --build /tmp/grpc/.build --target install -- -j${PARALLELISM}; \ ldconfig; \ rm -rf /tmp/grpc diff --git a/docker/develop/armv7l/Dockerfile b/docker/develop/armv7l/Dockerfile deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docker/develop/x86_64/Dockerfile b/docker/develop/x86_64/Dockerfile deleted file mode 100644 index e69de29bb2..0000000000 From 7956b46e0f03d29ab9438896f9d4cf4984fac16e Mon Sep 17 00:00:00 2001 From: Balasubramanian Date: Thu, 10 May 2018 07:07:12 -0500 Subject: [PATCH 089/110] Fixed boost linking (#1326) Signed-off-by: Ashwin Balasubramanian --- irohad/execution/CMakeLists.txt | 1 + libs/common/CMakeLists.txt | 5 +++++ libs/parser/CMakeLists.txt | 4 ++++ test/module/libs/converter/CMakeLists.txt | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/irohad/execution/CMakeLists.txt b/irohad/execution/CMakeLists.txt index 6ad5799e4a..708fac7bc5 100644 --- a/irohad/execution/CMakeLists.txt +++ b/irohad/execution/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(common_execution ) target_link_libraries(common_execution rxcpp + boost ) add_library(command_execution diff --git a/libs/common/CMakeLists.txt b/libs/common/CMakeLists.txt index fd3718fba2..8ceddbb477 100644 --- a/libs/common/CMakeLists.txt +++ b/libs/common/CMakeLists.txt @@ -4,9 +4,14 @@ add_library(libs_common target_link_libraries(libs_common logger + boost ) add_library(common INTERFACE) + +target_link_libraries(common INTERFACE + boost + ) target_include_directories(common INTERFACE ${PROJECT_SOURCE_DIR}/libs/common ) diff --git a/libs/parser/CMakeLists.txt b/libs/parser/CMakeLists.txt index 43748a1782..d7cc70534f 100644 --- a/libs/parser/CMakeLists.txt +++ b/libs/parser/CMakeLists.txt @@ -1 +1,5 @@ add_library(parser STATIC parser.cpp) + +target_link_libraries( parser + boost + ) diff --git a/test/module/libs/converter/CMakeLists.txt b/test/module/libs/converter/CMakeLists.txt index 7dcfa20ba7..e2c192e281 100644 --- a/test/module/libs/converter/CMakeLists.txt +++ b/test/module/libs/converter/CMakeLists.txt @@ -1 +1,5 @@ addtest(string_converter_test string_converter_test.cpp) + +target_link_libraries(string_converter_test + common + ) From c44902750c2952284222ee762ac73f3de2f7e75e Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 10 May 2018 17:33:12 +0300 Subject: [PATCH 090/110] Fix transaction processor test stability (#1320) Signed-off-by: Andrei Lebedev --- .../processor/transaction_processor_test.cpp | 104 +++--------------- 1 file changed, 14 insertions(+), 90 deletions(-) diff --git a/test/module/irohad/torii/processor/transaction_processor_test.cpp b/test/module/irohad/torii/processor/transaction_processor_test.cpp index d465d9423d..6664d4ea8e 100644 --- a/test/module/irohad/torii/processor/transaction_processor_test.cpp +++ b/test/module/irohad/torii/processor/transaction_processor_test.cpp @@ -1,18 +1,6 @@ /** - * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include @@ -103,14 +91,7 @@ class TransactionProcessorTest : public ::testing::Test { TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { std::vector txs; for (size_t i = 0; i < proposal_size; i++) { - auto &&tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId("admin@ru") - .addAssetQuantity("admin@tu", "coin#coin", "1.0") - .build() - .signAndAddSignature( - shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair()); + auto &&tx = TestTransactionBuilder().createdTime(i).build(); txs.push_back(tx); status_map[tx.hash()] = status_builder.notReceived().txHash(tx.hash()).build(); @@ -131,11 +112,7 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { // create proposal and notify about it auto proposal = std::make_shared( - shared_model::proto::ProposalBuilder() - .height(2) - .createdTime(iroha::time::now()) - .transactions(txs) - .build()); + TestProposalBuilder().transactions(txs).build()); prop_notifier.get_subscriber().on_next(proposal); prop_notifier.get_subscriber().on_completed(); @@ -156,14 +133,7 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnProposalTest) { TEST_F(TransactionProcessorTest, TransactionProcessorBlockCreatedTest) { std::vector txs; for (size_t i = 0; i < proposal_size; i++) { - auto &&tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId("admin@ru") - .addAssetQuantity("admin@tu", "coin#coin", "1.0") - .build() - .signAndAddSignature( - shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair()); + auto &&tx = TestTransactionBuilder().createdTime(i).build(); txs.push_back(tx); status_map[tx.hash()] = status_builder.notReceived().txHash(tx.hash()).build(); @@ -186,21 +156,12 @@ TEST_F(TransactionProcessorTest, TransactionProcessorBlockCreatedTest) { // 1. Create proposal and notify transaction processor about it auto proposal = std::make_shared( - shared_model::proto::ProposalBuilder() - .height(2) - .createdTime(iroha::time::now()) - .transactions(txs) - .build()); + TestProposalBuilder().transactions(txs).build()); prop_notifier.get_subscriber().on_next(proposal); prop_notifier.get_subscriber().on_completed(); - auto block = TestBlockBuilder() - .height(1) - .createdTime(iroha::time::now()) - .transactions(txs) - .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) - .build(); + auto block = TestBlockBuilder().transactions(txs).build(); // 2. Create block and notify transaction processor about it rxcpp::subjects::subject> @@ -230,14 +191,7 @@ TEST_F(TransactionProcessorTest, TransactionProcessorBlockCreatedTest) { TEST_F(TransactionProcessorTest, TransactionProcessorOnCommitTest) { std::vector txs; for (size_t i = 0; i < proposal_size; i++) { - auto &&tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId("admin@ru") - .addAssetQuantity("admin@tu", "coin#coin", "1.0") - .build() - .signAndAddSignature( - shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair()); + auto &&tx = TestTransactionBuilder().createdTime(i).build(); txs.push_back(tx); status_map[tx.hash()] = status_builder.notReceived().txHash(tx.hash()).build(); @@ -261,21 +215,12 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnCommitTest) { // 1. Create proposal and notify transaction processor about it auto proposal = std::make_shared( - shared_model::proto::ProposalBuilder() - .height(2) - .createdTime(iroha::time::now()) - .transactions(txs) - .build()); + TestProposalBuilder().transactions(txs).build()); prop_notifier.get_subscriber().on_next(proposal); prop_notifier.get_subscriber().on_completed(); - auto block = TestBlockBuilder() - .height(1) - .createdTime(iroha::time::now()) - .transactions(txs) - .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) - .build(); + auto block = TestBlockBuilder().transactions(txs).build(); // 2. Create block and notify transaction processor about it Commit single_commit = rxcpp::observable<>::just( @@ -300,14 +245,7 @@ TEST_F(TransactionProcessorTest, TransactionProcessorOnCommitTest) { TEST_F(TransactionProcessorTest, TransactionProcessorInvalidTxsTest) { std::vector block_txs; for (size_t i = 0; i < block_size; i++) { - auto &&tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId("admin@ru") - .addAssetQuantity("admin@tu", "coin#coin", "1.0") - .build() - .signAndAddSignature( - shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair()); + auto &&tx = TestTransactionBuilder().createdTime(i).build(); block_txs.push_back(tx); status_map[tx.hash()] = status_builder.notReceived().txHash(tx.hash()).build(); @@ -317,14 +255,7 @@ TEST_F(TransactionProcessorTest, TransactionProcessorInvalidTxsTest) { invalid_txs; // transactions will be stateful invalid if appeared // in proposal but didn't appear in block for (size_t i = block_size; i < proposal_size; i++) { - auto &&tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId("admin@ru") - .addAssetQuantity("admin@tu", "coin#coin", "1.0") - .build() - .signAndAddSignature( - shared_model::crypto::DefaultCryptoAlgorithmType:: - generateKeypair()); + auto &&tx = TestTransactionBuilder().createdTime(i).build(); invalid_txs.push_back(tx); status_map[tx.hash()] = status_builder.notReceived().txHash(tx.hash()).build(); @@ -346,21 +277,14 @@ TEST_F(TransactionProcessorTest, TransactionProcessorInvalidTxsTest) { }); auto proposal = std::make_shared( - shared_model::proto::ProposalBuilder() - .height(2) - .createdTime(iroha::time::now()) + TestProposalBuilder() .transactions(boost::join(block_txs, invalid_txs)) .build()); prop_notifier.get_subscriber().on_next(proposal); prop_notifier.get_subscriber().on_completed(); - auto block = TestBlockBuilder() - .height(1) - .createdTime(iroha::time::now()) - .transactions(block_txs) - .prevHash(shared_model::crypto::Hash(std::string(32, '0'))) - .build(); + auto block = TestBlockBuilder().transactions(block_txs).build(); Commit single_commit = rxcpp::observable<>::just( std::shared_ptr(clone(block))); From 717ba8d0f60ddad0c77263e3059937eda665211f Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Fri, 11 May 2018 10:42:00 +0300 Subject: [PATCH 091/110] revert docker-compose.yml (#1331) Signed-off-by: Artyom Bakhtin --- docker/docker-compose.yml | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 0e020e3964..95803e4084 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,33 +1,35 @@ -version: '2' +version: '3' services: - iroha: - image: hyperledger/iroha:develop - container_name: iroha + node: + image: hyperledger/iroha:develop-build ports: - - "50051:50051" + - "${IROHA_PORT}:50051" + - "${DEBUGGER_PORT}:20000" environment: - - IROHA_POSTGRES_HOST=iroha-postgres + - IROHA_POSTGRES_HOST=${COMPOSE_PROJECT_NAME}_postgres_1 - IROHA_POSTGRES_PORT=5432 - IROHA_POSTGRES_USER=iroha - - IROHA_POSTGRES_PASSWORD=iroha + - IROHA_POSTGRES_PASSWORD=helloworld + - CCACHE_DIR=/tmp/ccache + # export G_ID=$(id -g $(whoami)) + # export U_ID=$(id -g $(whoami)) + user: ${U_ID:-0}:${G_ID:-0} depends_on: - postgres tty: true - environment: - - KEY=node0 volumes: - # as configured in example/config.sample - - /tmp/block_store - - ./iroha/example:/opt/iroha_data - restart: always + - ../:/opt/iroha + - ccache-data:/tmp/ccache + working_dir: /opt/iroha + cap_add: + - SYS_PTRACE postgres: image: postgres:9.5 - container_name: iroha-postgres environment: - POSTGRES_USER=iroha - - POSTGRES_PASSWORD=iroha - expose: - - 5432 - restart: always + - IROHA_POSTGRES_PASSWORD=helloworld + +volumes: + ccache-data: From 950b0109a64e79238145d742027a574f70412fe1 Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Sat, 12 May 2018 09:11:06 +0300 Subject: [PATCH 092/110] Experimental MSVC shared model build (#1297) * Shared model MSVC build - Use ciso646 - No dependency download support due to link issues * Fix ninja and MSBuild; remove common warnings * Fix toProtoAmount conversion not masking upper bits Signed-off-by: Andrei Lebedev --- cmake/Modules/Finded25519.cmake | 16 ++++++++-- cmake/functions.cmake | 18 +++++++++-- libs/amount/amount.hpp | 1 + libs/common/byteutils.hpp | 7 +++-- libs/common/result.hpp | 2 ++ libs/common/types.hpp | 1 + shared_model/CMakeLists.txt | 8 +++-- .../protobuf/common_objects/amount.hpp | 18 ++++++++--- shared_model/cmake/dependencies.cmake | 30 +++++++++++++++++-- .../interfaces/base/model_primitive.hpp | 2 ++ 10 files changed, 86 insertions(+), 17 deletions(-) diff --git a/cmake/Modules/Finded25519.cmake b/cmake/Modules/Finded25519.cmake index 4db83c862f..23414de25f 100644 --- a/cmake/Modules/Finded25519.cmake +++ b/cmake/Modules/Finded25519.cmake @@ -12,7 +12,12 @@ find_package_handle_standard_args(ed25519 DEFAULT_MSG ) set(URL https://github.com/hyperledger/iroha-ed25519) -set(VERSION e7188b8393dbe5ac54378610d53630bd4a180038) +if (MSVC) + # trunk/1.2 with windows-specific changes + set(VERSION 31bb9b50e01b21ea2c21d33929e20934be4665b4) +else() + set(VERSION e7188b8393dbe5ac54378610d53630bd4a180038) +endif() set_target_description(ed25519 "Digital signature algorithm" ${URL} ${VERSION}) if (NOT ed25519_FOUND) @@ -26,7 +31,7 @@ if (NOT ed25519_FOUND) GIT_TAG ${VERSION} CMAKE_ARGS -DTESTING=OFF -DBUILD=STATIC PATCH_COMMAND ${PATCH_RANDOM} - BUILD_BYPRODUCTS ${EP_PREFIX}/src/hyperledger_ed25519-build/libed25519.a + BUILD_BYPRODUCTS ${EP_PREFIX}/src/hyperledger_ed25519-build/${CMAKE_STATIC_LIBRARY_PREFIX}ed25519${CMAKE_STATIC_LIBRARY_SUFFIX} INSTALL_COMMAND "" # remove install step TEST_COMMAND "" # remove test step UPDATE_COMMAND "" # remove update step @@ -38,6 +43,13 @@ if (NOT ed25519_FOUND) file(MAKE_DIRECTORY ${ed25519_INCLUDE_DIR}) link_directories(${binary_dir}) + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(ed25519 PROPERTIES + IMPORTED_LOCATION_DEBUG ${binary_dir}/Debug/${CMAKE_STATIC_LIBRARY_PREFIX}ed25519${CMAKE_STATIC_LIBRARY_SUFFIX} + IMPORTED_LOCATION_RELEASE ${binary_dir}/Release/${CMAKE_STATIC_LIBRARY_PREFIX}ed25519${CMAKE_STATIC_LIBRARY_SUFFIX} + ) + endif() + add_dependencies(ed25519 hyperledger_ed25519) endif () diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 2b9368c6c8..ebfcaadea7 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -31,11 +31,16 @@ function(addtest test_name SOURCES) NAME ${test_name} COMMAND $ ${test_xml_output} ) - strictmode(${test_name}) + if (NOT MSVC) + # protobuf generates warnings at the moment + strictmode(${test_name}) + endif () if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")) target_compile_options(${test_name} PRIVATE -Wno-inconsistent-missing-override) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # do nothing, but also don't spam warning on each test else () message(AUTHOR_WARNING "Unknown compiler: building target ${target} with default options") endif () @@ -51,10 +56,17 @@ endfunction() function(compile_proto_to_cpp PROTO) string(REGEX REPLACE "\\.proto$" ".pb.h" GEN_PB_HEADER ${PROTO}) string(REGEX REPLACE "\\.proto$" ".pb.cc" GEN_PB ${PROTO}) + if (MSVC) + set(GEN_COMMAND "${Protobuf_PROTOC_EXECUTABLE}") + set(GEN_ARGS ${Protobuf_INCLUDE_DIR}) + else() + set(GEN_COMMAND ${CMAKE_COMMAND} -E env LD_LIBRARY_PATH=${protobuf_LIBRARY_DIR}:$ENV{LD_LIBRARY_PATH} "${protoc_EXECUTABLE}") + set(GEN_ARGS ${protobuf_INCLUDE_DIR}) + endif() add_custom_command( OUTPUT ${IROHA_SCHEMA_DIR}/${GEN_PB_HEADER} ${IROHA_SCHEMA_DIR}/${GEN_PB} - COMMAND ${CMAKE_COMMAND} -E env LD_LIBRARY_PATH=${protobuf_LIBRARY_DIR}:$ENV{LD_LIBRARY_PATH} "${protoc_EXECUTABLE}" - ARGS -I${protobuf_INCLUDE_DIR} -I. --cpp_out=${IROHA_SCHEMA_DIR} ${PROTO} + COMMAND ${GEN_COMMAND} + ARGS -I${GEN_ARGS} -I. --cpp_out=${IROHA_SCHEMA_DIR} ${PROTO} DEPENDS protoc WORKING_DIRECTORY ${IROHA_SCHEMA_DIR} ) diff --git a/libs/amount/amount.hpp b/libs/amount/amount.hpp index cc27ef9414..3a472d1d9f 100644 --- a/libs/amount/amount.hpp +++ b/libs/amount/amount.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/libs/common/byteutils.hpp b/libs/common/byteutils.hpp index 1920492cff..294988ad44 100644 --- a/libs/common/byteutils.hpp +++ b/libs/common/byteutils.hpp @@ -70,10 +70,11 @@ namespace iroha { for (size_t i = 0; i < result.length(); ++i) { std::string byte = str.substr(i * 2, 2); try { - result.at(i) = std::stoul(byte, nullptr, 16); - } catch (const std::invalid_argument &e) { + result.at(i) = + static_cast(std::stoul(byte, nullptr, 16)); + } catch (const std::invalid_argument &) { return boost::none; - } catch (const std::out_of_range &e) { + } catch (const std::out_of_range &) { return boost::none; } } diff --git a/libs/common/result.hpp b/libs/common/result.hpp index a5eca3846d..3e3ed3184a 100644 --- a/libs/common/result.hpp +++ b/libs/common/result.hpp @@ -18,6 +18,8 @@ #ifndef IROHA_RESULT_HPP #define IROHA_RESULT_HPP +#include + #include #include diff --git a/libs/common/types.hpp b/libs/common/types.hpp index 3967db07b7..e20d01ba98 100644 --- a/libs/common/types.hpp +++ b/libs/common/types.hpp @@ -19,6 +19,7 @@ #define IROHA_COMMON_TYPES_HPP #include +#include #include #include #include diff --git a/shared_model/CMakeLists.txt b/shared_model/CMakeLists.txt index 080f740356..09a9070edd 100644 --- a/shared_model/CMakeLists.txt +++ b/shared_model/CMakeLists.txt @@ -25,9 +25,11 @@ include_directories( if (NOT IROHA_ROOT_PROJECT) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) - set(CMAKE_CXX_FLAGS "-std=c++14 -Wall") - set(CMAKE_CXX_FLAGS_RELEASE "-O3") - set(CMAKE_CXX_FLAGS_DEBUG "-g -Wextra -Wno-unused-parameter -Wno-deprecated-declarations -O0") + if (NOT MSVC) + set(CMAKE_CXX_FLAGS "-std=c++14 -Wall") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") + set(CMAKE_CXX_FLAGS_DEBUG "-g -Wextra -Wno-unused-parameter -Wno-deprecated-declarations -O0") + endif () if(CMAKE_GENERATOR MATCHES "Make") set(MAKE "$(MAKE)") diff --git a/shared_model/backend/protobuf/common_objects/amount.hpp b/shared_model/backend/protobuf/common_objects/amount.hpp index c4bb090f0d..0817a2000c 100644 --- a/shared_model/backend/protobuf/common_objects/amount.hpp +++ b/shared_model/backend/protobuf/common_objects/amount.hpp @@ -58,10 +58,20 @@ namespace shared_model { ValueType &value, const boost::multiprecision::uint256_t &amount) noexcept { constexpr auto offset = 64u; - value.set_first((amount >> offset * 3).template convert_to()); - value.set_second((amount >> offset * 2).template convert_to()); - value.set_third((amount >> offset).template convert_to()); - value.set_fourth(amount.template convert_to()); + constexpr boost::multiprecision::uint256_t mask_bits = + std::numeric_limits::max(); + auto convert = [&](auto i) { + // Select two middle bits from 011011 and offset = 2 + // 011011 >> (2 * 1) = 000110 + // Have to mask 2 high bits to prevent any overflows + // 000110 & 000011 = 000010 + return ((amount >> (offset * i)) & mask_bits) + .template convert_to(); + }; + value.set_first(convert(3)); + value.set_second(convert(2)); + value.set_third(convert(1)); + value.set_fourth(convert(0)); } class Amount final : public CopyableProto + #include "utils/string_builder.hpp" #include "common/cloneable.hpp" From b2d84d83471848b64ce122674c57db247ef359ab Mon Sep 17 00:00:00 2001 From: Dumitru Date: Sat, 12 May 2018 13:55:16 +0300 Subject: [PATCH 093/110] Python docs (#1329) * Python docs Signed-off-by: Dumitru * Intructions Signed-off-by: Dumitru --- shared_model/packages/python/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shared_model/packages/python/README.md b/shared_model/packages/python/README.md index d769c7ea82..e0c53985b1 100644 --- a/shared_model/packages/python/README.md +++ b/shared_model/packages/python/README.md @@ -1,4 +1,5 @@ # Python client library example +***Default branch that is going to be built is develop, if you want to build other branch, please set it in setup.py*** ## How to install iroha python library To install latest release: @@ -10,7 +11,12 @@ To install developer version: pip install -i https://testpypi.python.org/pypi iroha ``` -## How to build iroha +## How to build and install iroha locally +```bash +python setup.py install +``` + +## How to build and publish iroha Creating MacOS wheel and publishing it: ```bash python setup.py bdist_wheel From f5377c9bc766118bb8df0e99b10ede10dea95af6 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Mon, 14 May 2018 09:12:32 +0300 Subject: [PATCH 094/110] CI fixes (#1290) * replace GIT_PREVIOUS_COMMIT variable Signed-off-by: Artyom Bakhtin * fix ARMv7 build parallelism Signed-off-by: Artyom Bakhtin * check `when` before `agent` Signed-off-by: Artyom Bakhtin * fixes + comments Signed-off-by: Artyom Bakhtin --- .jenkinsci/debug-build.groovy | 16 +++++---- .jenkinsci/docker-pull-or-build.groovy | 4 --- .jenkinsci/previous-commit.groovy | 9 +++++ .jenkinsci/release-build.groovy | 4 +-- Jenkinsfile | 50 ++++++++++++++++++++------ 5 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 .jenkinsci/previous-commit.groovy diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index 4de8d28592..6bf916eaf3 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -2,24 +2,26 @@ def doDebugBuild(coverageEnabled=false) { def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" + def pCommit = load ".jenkinsci/previous-commit.groovy" def parallelism = params.PARALLELISM def platform = sh(script: 'uname -m', returnStdout: true).trim() + def previousCommit = pCommit.previousCommitOrCurrent() // params are always null unless job is started // this is the case for the FIRST build only. // So just set this to same value as default. // This is a known bug. See https://issues.jenkins-ci.org/browse/JENKINS-41929 - if (parallelism == null) { + if (!parallelism) { parallelism = 4 } - if ("arm7" in env.NODE_NAME) { + if (env.NODE_NAME.contains('arm7')) { parallelism = 1 } sh "docker network create ${env.IROHA_NETWORK}" def iC = dPullOrBuild.dockerPullOrUpdate("${platform}-develop-build", "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${previousCommit}/docker/develop/Dockerfile", "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", - ['PARALLELISM': parallelism]) + ['PARALLELISM': parallelism]) docker.image('postgres:9.5').withRun("" + " -e POSTGRES_USER=${env.IROHA_POSTGRES_USER}" + " -e POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" @@ -82,10 +84,10 @@ def doDebugBuild(coverageEnabled=false) { -Dsonar.github.pullRequest=${CHANGE_ID} """ } + sh "cmake --build build --target coverage.info" + sh "python /tmp/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" + cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false } - sh "cmake --build build --target coverage.info" - sh "python /tmp/lcov_cobertura.py build/reports/coverage.info -o build/reports/coverage.xml" - cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: '**/build/reports/coverage.xml', conditionalCoverageTargets: '75, 50, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '75, 50, 0', maxNumberOfBuilds: 50, methodCoverageTargets: '75, 50, 0', onlyStable: false, zoomCoverageChart: false } } } diff --git a/.jenkinsci/docker-pull-or-build.groovy b/.jenkinsci/docker-pull-or-build.groovy index ac8f57ccf3..9511aa139a 100644 --- a/.jenkinsci/docker-pull-or-build.groovy +++ b/.jenkinsci/docker-pull-or-build.groovy @@ -19,10 +19,6 @@ def buildOptionsString(options) { def dockerPullOrUpdate(imageName, currentDockerfileURL, previousDockerfileURL, referenceDockerfileURL, buildOptions=null) { buildOptions = buildOptionsString(buildOptions) - // GIT_PREVIOUS_COMMIT is null for first PR build - if (!previousDockerfileURL) { - previousDockerfileURL = currentDockerfileURL - } def commit = sh(script: "echo ${GIT_LOCAL_BRANCH} | md5sum | cut -c 1-8", returnStdout: true).trim() if (remoteFilesDiffer(currentDockerfileURL, previousDockerfileURL)) { // Dockerfile has been changed compared to the previous commit diff --git a/.jenkinsci/previous-commit.groovy b/.jenkinsci/previous-commit.groovy new file mode 100644 index 0000000000..5a3916005e --- /dev/null +++ b/.jenkinsci/previous-commit.groovy @@ -0,0 +1,9 @@ +#!/usr/bin/env groovy + +def previousCommitOrCurrent() { + // GIT_PREVIOUS_COMMIT is null on first PR build + // regardless Jenkins docs saying it equals the current one on first build in branch + return !env.GIT_PREVIOUS_COMMIT ? env.GIT_COMMIT : env.GIT_PREVIOUS_COMMIT +} + +return this diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index 0dbbc48699..4ed14c0854 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -6,10 +6,10 @@ def doReleaseBuild() { // this is the case for the FIRST build only. // So just set this to same value as default. // This is a known bug. See https://issues.jenkins-ci.org/browse/JENKINS-41929 - if (parallelism == null) { + if (!parallelism) { parallelism = 4 } - if ("arm7" in env.NODE_NAME) { + if (env.NODE_NAME.contains('arm7')) { parallelism = 1 } def platform = sh(script: 'uname -m', returnStdout: true).trim() diff --git a/Jenkinsfile b/Jenkinsfile index 6cdc884c7c..4c2e668b19 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -67,7 +67,10 @@ pipeline { } parallel { stage ('Linux') { - when { expression { return params.Linux } } + when { + beforeAgent true + expression { return params.Linux } + } agent { label 'x86_64' } steps { script { @@ -95,7 +98,10 @@ pipeline { } } stage('ARMv7') { - when { expression { return params.ARMv7 } } + when { + beforeAgent true + expression { return params.ARMv7 } + } agent { label 'armv7' } steps { script { @@ -123,7 +129,10 @@ pipeline { } } stage('ARMv8') { - when { expression { return params.ARMv8 } } + when { + beforeAgent true + expression { return params.ARMv8 } + } agent { label 'armv8' } steps { script { @@ -151,7 +160,10 @@ pipeline { } } stage('MacOS'){ - when { expression { return params.MacOS } } + when { + beforeAgent true + expression { return params.MacOS } + } agent { label 'mac' } steps { script { @@ -255,7 +267,10 @@ pipeline { } parallel { stage('Linux') { - when { expression { return params.Linux } } + when { + beforeAgent true + expression { return params.Linux } + } agent { label 'x86_64' } steps { script { @@ -273,7 +288,10 @@ pipeline { } } stage('ARMv7') { - when { expression { return params.ARMv7 } } + when { + beforeAgent true + expression { return params.ARMv7 } + } agent { label 'armv7' } steps { script { @@ -291,7 +309,10 @@ pipeline { } } stage('ARMv8') { - when { expression { return params.ARMv8 } } + when { + beforeAgent true + expression { return params.ARMv8 } + } agent { label 'armv8' } steps { script { @@ -309,7 +330,10 @@ pipeline { } } stage('MacOS') { - when { expression { return params.MacOS } } + when { + beforeAgent true + expression { return params.MacOS } + } agent { label 'mac' } steps { script { @@ -341,6 +365,7 @@ pipeline { } stage('Build docs') { when { + beforeAgent true allOf { expression { return params.Doxygen } expression { GIT_LOCAL_BRANCH ==~ /(master|develop)/ } @@ -361,6 +386,7 @@ pipeline { } stage('Build bindings') { when { + beforeAgent true anyOf { expression { return params.PythonBindings } expression { return params.JavaBindings } @@ -375,11 +401,13 @@ pipeline { script { def bindings = load ".jenkinsci/bindings.groovy" def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" + def pCommit = load ".jenkinsci/previous-commit.groovy" def platform = sh(script: 'uname -m', returnStdout: true).trim() + def previousCommit = pCommit.previousCommitOrCurrent() if (params.JavaBindings) { iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop-build", "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${previousCommit}/docker/develop/Dockerfile", "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", ['PARALLELISM': params.PARALLELISM]) iC.inside("-v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { @@ -389,7 +417,7 @@ pipeline { if (params.PythonBindings) { iC = dPullOrBuild.dockerPullOrUpdate("$platform-develop-build", "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/develop/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/develop/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${previousCommit}/docker/develop/Dockerfile", "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", ['PARALLELISM': params.PARALLELISM]) iC.inside("-v /tmp/${env.GIT_COMMIT}/bindings-artifact:/tmp/bindings-artifact") { @@ -399,7 +427,7 @@ pipeline { if (params.AndroidBindings) { iC = dPullOrBuild.dockerPullOrUpdate("android-${params.ABPlatform}-${params.ABBuildType}", "${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/android/Dockerfile", - "${env.GIT_RAW_BASE_URL}/${env.GIT_PREVIOUS_COMMIT}/docker/android/Dockerfile", + "${env.GIT_RAW_BASE_URL}/${previousCommit}/docker/android/Dockerfile", "${env.GIT_RAW_BASE_URL}/develop/docker/android/Dockerfile", ['PARALLELISM': params.PARALLELISM, 'PLATFORM': params.ABPlatform, 'BUILD_TYPE': params.ABBuildType]) sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh ${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/android/entrypoint.sh" From 2976fac0ba657335ffde3ca6167aed77aeced49c Mon Sep 17 00:00:00 2001 From: Fedor Muratov Date: Mon, 14 May 2018 12:26:40 +0200 Subject: [PATCH 095/110] Add prefix with type of test for Ctest names (#1307) Signed-off-by: Fedor Muratov --- cmake/functions.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/functions.cmake b/cmake/functions.cmake index ebfcaadea7..00d73b9540 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -27,8 +27,15 @@ function(addtest test_name SOURCES) add_executable(${test_name} ${SOURCES}) target_link_libraries(${test_name} gtest gmock) target_include_directories(${test_name} PUBLIC ${PROJECT_SOURCE_DIR}/test) + + # fetch directory after test in source dir call + # for example: + # "/Users/user/iroha/test/integration/acceptance" + # match to "integration" + string(REGEX REPLACE ".*test\\/([a-zA-Z]+).*" "\\1" output ${CMAKE_CURRENT_SOURCE_DIR}) + add_test( - NAME ${test_name} + NAME "${output}_${test_name}" COMMAND $ ${test_xml_output} ) if (NOT MSVC) From 8c31e78a5f98ae1e89273b4a1e836c014c63dadc Mon Sep 17 00:00:00 2001 From: Igor Egorov <36847043+igor-egorov@users.noreply.github.com> Date: Mon, 14 May 2018 13:44:02 +0300 Subject: [PATCH 096/110] Add Java Bindings Tests (#1311) The total number of tests for commands is 96, queries - 47. --- .../shared_model/bindings/BuilderTest.java | 1001 ++++++++++++++++- .../shared_model/bindings/QueryTest.java | 500 +++++++- 2 files changed, 1416 insertions(+), 85 deletions(-) diff --git a/test/module/shared_model/bindings/BuilderTest.java b/test/module/shared_model/bindings/BuilderTest.java index f91d1f509b..c537b0a1d1 100644 --- a/test/module/shared_model/bindings/BuilderTest.java +++ b/test/module/shared_model/bindings/BuilderTest.java @@ -1,5 +1,11 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; import java.math.BigInteger; @@ -27,6 +33,95 @@ public class BuilderTest { private Keypair keys; private ModelTransactionBuilder builder; + + /* Stateless validation rules are listed + * here https://github.com/hyperledger/iroha/pull/1148 + */ + + // Symbols of type 1 (format [a-z_0-9]{1,32}) are used + // as account_name, asset_name and role_id. + private final String[] validNameSymbols1 = { + "a", + "asset", + "234234", + "_", + "_123", + "123_23", + "234asset_", + "__", + "12345678901234567890123456789012" + }; + private final String[] invalidNameSymbols1 = { + "", + "A", + "assetV", + "asSet", + "asset%", + "^123", + "verylongassetname_thenameislonger", + "verylongassetname_thenameislongerthanitshouldbe", + "assset-01" + }; + + // Symbols of type 2 (format [A-Za-z0-9_]{1,64}) + // are used as key identifier for setAccountDetail command + private final String[] validNameSymbols2 = { + "a", + "A", + "1", + "_", + "Key", + "Key0_", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid" + }; + private final String[] invalidNameSymbols2 = { + "", + "Key&", + "key-30", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid1", + "@@@" + }; + + private final String[] validDomains = { + "test", + "u9EEA432F", + "a-hyphen", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad", + "endWith0", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad" + }; + + private final String[] invalidDomains = { + "", + " ", + " ", + "9start.with.digit", + "-startWithDash", + "@.is.not.allowed", + "no space is allowed", + "endWith-", + "label.endedWith-.is.not.allowed", + "aLabelMustNotExceeds63charactersALabelMustNotExceeds63characters", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPadP", + "257.257.257.257", + "domain#domain", + "asd@asd", + "ab..cd" + }; + + private final String[] invalidKeysBytes = { + "", + "a", + "1111111111111111111111111111111", + "111111111111111111111111111111111" + }; + ModelTransactionBuilder base() { return new ModelTransactionBuilder() .createdTime(BigInteger.valueOf(System.currentTimeMillis())) @@ -37,6 +132,33 @@ void setAddPeer() { builder.addPeer("123.123.123.123", keys.publicKey()); } + Blob proto(UnsignedTx tx) { + return new ModelProtoTransaction().signAndAddSignature(tx, keys); + } + + /** + * Performs check that Blob contains valid proto Transaction + * @param serialized blob with binary data for check + * @return true if valid + */ + private boolean checkProtoTx(Blob serialized) { + ByteVector blob = serialized.blob(); + byte bs[] = new byte[(int)blob.size()]; + + for (int i = 0; i < blob.size(); i++) { + bs[i] = (byte)blob.get(i); + } + + try { + BlockOuterClass.Transaction.parseFrom(bs); + } catch (InvalidProtocolBufferException e) { + System.out.print("Exception: "); + System.out.println(e.getMessage()); + return false; + } + return true; + } + @BeforeEach void setUp() { keys = new ModelCrypto().generateKeypair(); @@ -49,10 +171,20 @@ void emptyTx() { assertThrows(IllegalArgumentException.class, builder::build); } + /* ====================== AddPeer Tests ====================== */ + + @Test + void addPeer() { + for (String domain: validDomains) { + UnsignedTx tx = builder.addPeer(domain + ":123", keys.publicKey()).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + @Test void outdatedAddPeer() { setAddPeer(); - for (BigInteger i : new BigInteger[]{BigInteger.valueOf(0), + for (BigInteger i: new BigInteger[]{BigInteger.valueOf(0), BigInteger.valueOf(System.currentTimeMillis() - 100_000_000), BigInteger.valueOf(System.currentTimeMillis() + 1000)}) { builder.createdTime(i); @@ -63,108 +195,887 @@ void outdatedAddPeer() { @Test void addPeerWithInvalidCreator() { setAddPeer(); - for (String i : new String[]{"", "invalid", "@invalid", "invalid@"}) { - builder.creatorAccountId(i); + for (String account: invalidNameSymbols1) { + builder.creatorAccountId(account + "@test"); assertThrows(IllegalArgumentException.class, builder::build); } } @Test - void addPeerWithInvalidKeySize() { + void addPeerWithEmptyCreator() { + setAddPeer(); + builder.creatorAccountId(""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void addPeerWithInvalidCreatorDomain() { setAddPeer(); - for (String i : new String[]{"", "a", "1111111111111111111111111111111", "111111111111111111111111111111111"}) { - ModelTransactionBuilder builder = base().addPeer("123.123.123.123", new PublicKey(i)); + for (String domain: invalidDomains) { + builder.creatorAccountId("admin@" + domain); assertThrows(IllegalArgumentException.class, builder::build); } } @Test - void addPeerWithInvalidHost() { + void addPeerWithInvalidKeySize() { setAddPeer(); - for (String i : new String[]{"257.257.257.257", "host#host", "asd@asd", "ab..cd"}) { - ModelTransactionBuilder builder = base().addPeer(i, keys.publicKey()); + for (String key: invalidKeysBytes) { + ModelTransactionBuilder builder = base().addPeer("123.123.123.123", new PublicKey(key)); assertThrows(IllegalArgumentException.class, builder::build); } } - Blob proto(UnsignedTx tx) { - return new ModelProtoTransaction().signAndAddSignature(tx, keys); + @Test + void addPeerWithInvalidDomain() { + setAddPeer(); + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().addPeer(domain, keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } } - /** - * Performs check that Blob contains valid proto Transaction - * @param serialized blob with binary data for check - * @return true if valid - */ - private boolean checkProtoTx(Blob serialized) { - ByteVector blob = serialized.blob(); - byte bs[] = new byte[(int)blob.size()]; + /* ====================== AddSignatory Tests ====================== */ - for (int i = 0; i < blob.size(); i++) { - bs[i] = (byte)blob.get(i); + @Test + void addSignatory() { + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = accountName + "@" + domain; + UnsignedTx tx = builder.addSignatory(accountId, keys.publicKey()).build(); + assertTrue(checkProtoTx(proto(tx))); + } } + } - try { - BlockOuterClass.Transaction.parseFrom(bs); - } catch (InvalidProtocolBufferException e) { - System.out.print("Exception: "); - System.out.println(e.getMessage()); - return false; + @Test + void addSignatoryInvalidAccountName() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@domain"; + ModelTransactionBuilder builder = base().addSignatory(accountId, keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); } - return true; } @Test - void addPeer() { - UnsignedTx tx = builder.addPeer("123.123.123.123:123", keys.publicKey()).build(); - assertTrue(checkProtoTx(proto(tx))); + void addSignatoryEmptyAccountId() { + ModelTransactionBuilder builder = base().addSignatory("", keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); } @Test - void addSignatory() { - UnsignedTx tx = builder.addSignatory("admin@test", keys.publicKey()).build(); - assertTrue(checkProtoTx(proto(tx))); + void addSignatoryInvalidDomain() { + for (String domain: invalidDomains) { + String accountId = "user@" + domain; + ModelTransactionBuilder builder = base().addSignatory(accountId, keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } } + @Test + void addSignatoryInvalidKey() { + for (String invalidKeyBytes: invalidKeysBytes) { + ModelTransactionBuilder builder = base().addSignatory("admin@test", new PublicKey(invalidKeyBytes)); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== AddAssetQuantity Tests ====================== */ + @Test void addAssetQuantity() { UnsignedTx tx = builder.addAssetQuantity("admin@test", "asset#domain", "12.345").build(); assertTrue(checkProtoTx(proto(tx))); } + @Test + void addAssetQuantityValidAccountsAndAssets() { + for (String domain: validDomains) { + for (String name: validNameSymbols1) { + UnsignedTx tx = builder.addAssetQuantity(name + "@" + domain, name + "#" + domain, "100").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void addAssetQuantityInvalidAccountDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().addAssetQuantity("admin@" + domain, "asset#test", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void addAssetQuantityInvalidAssetDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().addAssetQuantity("admin@test", "asset#" + domain, "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void addAssetZeroQuantity() { + ModelTransactionBuilder builder = base().addAssetQuantity("admin@test", "asset#domain", "0"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void addAssetQuantityInvalidAccountName() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().addAssetQuantity(accountId, "asset#domain", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void addAssetQuantityEmptyAccount() { + ModelTransactionBuilder builder = base().addAssetQuantity("", "asset#test", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void addAssetQuantityInvalidAssetName() { + for (String assetName: invalidNameSymbols1) { + String assetId = assetName + "#test"; + ModelTransactionBuilder builder = base().addAssetQuantity("account@test", assetId, "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void addAssetQuantityEmptyAsset() { + ModelTransactionBuilder builder = base().addAssetQuantity("account@test", "", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void addAssetQuantityInvalidAmount() { + for (String amount: new String[]{"", "-12", "-13.45", "chars", "chars10"}) { + ModelTransactionBuilder builder = base().addAssetQuantity("account@test", "asset#test", amount); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== RemoveSignatory Tests ====================== */ + @Test void removeSignatory() { - UnsignedTx tx = builder.removeSignatory("admin@test", keys.publicKey()).build(); - assertTrue(checkProtoTx(proto(tx))); + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = accountName + "@" + domain; + UnsignedTx tx = builder.removeSignatory(accountId, keys.publicKey()).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void removeSignatoryEmptyAccount() { + ModelTransactionBuilder builder = base().removeSignatory("", keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void removeSignatoryInvalidAccount() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().removeSignatory(accountId, keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void removeSignatoryInvalidAccountDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().removeSignatory("admin@" + domain, keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void removeSignatoryInvalidKey() { + for (String invalidKeyBytes: invalidKeysBytes) { + ModelTransactionBuilder builder = base().removeSignatory("admin@test", new PublicKey(invalidKeyBytes)); + assertThrows(IllegalArgumentException.class, builder::build); + } } + /* ====================== CreateAccount Tests ====================== */ + @Test void createAccount() { - UnsignedTx tx = builder.createAccount("admin", "domain", keys.publicKey()).build(); - assertTrue(checkProtoTx(proto(tx))); + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedTx tx = builder.createAccount(accountName, domain, keys.publicKey()).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void createAccountInvalidAccountName() { + for (String accountName: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().createAccount(accountName, "domain", keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void createAccountInvalidDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().createAccount("admin", domain, keys.publicKey()); + assertThrows(IllegalArgumentException.class, builder::build); + } } + @Test + void createAccountInvalidKey() { + for (String invalidKeyBytes: invalidKeysBytes) { + ModelTransactionBuilder builder = base().createAccount("admin", "test", new PublicKey(invalidKeyBytes)); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== CreateDomain Tests ====================== */ + @Test void createDomain() { - UnsignedTx tx = builder.createDomain("domain", "role").build(); - assertTrue(checkProtoTx(proto(tx))); + for (String role: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedTx tx = builder.createDomain(domain, role).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void createDomainInvalidDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().createDomain(domain, "role"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void createDomainInvalidRole() { + for (String role: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().createDomain("domain", role); + assertThrows(IllegalArgumentException.class, builder::build); + } } + /* ====================== SetAccountQuorum Tests ====================== */ + + @Test void setAccountQuorum() { - UnsignedTx tx = builder.setAccountQuorum("admin@test", 123).build(); - assertTrue(checkProtoTx(proto(tx))); + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = accountName + "@" + domain; + UnsignedTx tx = builder.setAccountQuorum(accountId, 128).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void setAccountQuorumInvalidAccount() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().setAccountQuorum(accountId, 123); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void setAccountQuorumInvalidDomain() { + for (String domain: invalidDomains) { + String accountId = "admin@" + domain; + ModelTransactionBuilder builder = base().setAccountQuorum(accountId, 123); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void setAccountQuorumEmptyAccount() { + ModelTransactionBuilder builder = base().setAccountQuorum("", 123); + assertThrows(IllegalArgumentException.class, builder::build); } + @Test + void setAccountQuorumInvalidQuantity() { + for (int quorumSize: new int[]{0, 129, -100}) { + ModelTransactionBuilder builder = base().setAccountQuorum("admin@test", quorumSize); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== TransferAsset Tests ====================== */ + @Test void transferAsset() { - UnsignedTx tx = builder.transferAsset("from@test", "to@test", "asset#test", "description", "123.456").build(); - assertTrue(checkProtoTx(proto(tx))); + for (String domain: validDomains) { + for (int i = 0; i < validNameSymbols1.length; i++) { + String from = validNameSymbols1[i] + "@" + domain; + String to = validNameSymbols1[(i + 1) % validNameSymbols1.length] + "@" + domain; + String asset = validNameSymbols1[(i + 2) % validNameSymbols1.length] + "#" + domain; + UnsignedTx tx = builder.transferAsset(from, to, asset, "description", "123.456").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void transferAssetWithValidName() { + for (String assetName: validNameSymbols1) { + String assetId = assetName + "#test"; + UnsignedTx tx = builder.transferAsset("from@test", "to@test", assetId, "description", "100").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + + @Test + void transferAssetWithInvalidName() { + for (String assetName: invalidNameSymbols1) { + String assetId = assetName + "#test"; + ModelTransactionBuilder builder = base().transferAsset("from@test", "to@test", assetId, "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void transferAssetWithInvalidFromAccount() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().transferAsset(accountId, "to@test", "asset#test", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void transferAssetWithInvalidToAccount() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().transferAsset("from@test", accountId, "asset#test", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void transferAssetWithEmptyFromAccount() { + ModelTransactionBuilder builder = base().transferAsset("", "to@test", "asset#test", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void transferAssetWithEmptyToAccount() { + ModelTransactionBuilder builder = base().transferAsset("from@test", "", "asset#test", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void transferAssetWithInvalidFromDomain() { + for (String domain: invalidDomains) { + String accountId = "from@" + domain; + ModelTransactionBuilder builder = base().transferAsset(accountId, "to@test", "asset#test", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void transferAssetWithInvalidToDomain() { + for (String domain: invalidDomains) { + String accountId = "to@" + domain; + ModelTransactionBuilder builder = base().transferAsset("from@test", accountId, "asset#test", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void transferAssetWithInvalidAssetDomain() { + for (String domain: invalidDomains) { + String assetId = "asset#" + domain; + ModelTransactionBuilder builder = base().transferAsset("from@test", "to@test", assetId, "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void transferAssetWithEmptyAssetName() { + ModelTransactionBuilder builder = base().transferAsset("from@test", "to@test", "", "description", "100"); + assertThrows(IllegalArgumentException.class, builder::build); } + @Test + void transferAssetDescriptionBoundaryValues() { + for (String description1: new String[]{"", "abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde1234"}) { + UnsignedTx tx = builder.transferAsset("from@test", "to@test", "asset#test", description1, "100").build(); + assertTrue(checkProtoTx(proto(tx))); + } + + String description2 = "abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde12345"; + ModelTransactionBuilder builder = base().transferAsset("from@test", "to@test", "asset#test", description2, "100"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void transferAssetMaximumAmount() { + BigInteger base = new BigInteger("2"); + BigInteger one = new BigInteger("1"); + BigInteger maxUint256 = base.pow(256).subtract(one); + BigInteger oversizedInt = maxUint256.add(one); + + String maxAmount1 = maxUint256.toString(); + String maxAmount2 = maxAmount1.substring(0, 10) + "." + maxAmount1.substring(10, maxAmount1.length()); + + for (String amount: new String[]{maxAmount1, maxAmount2}) { + UnsignedTx tx = builder.transferAsset("from@test", "to@test", "asset#test", "description", amount).build(); + assertTrue(checkProtoTx(proto(tx))); + } + + ModelTransactionBuilder mtb = base().transferAsset("from@test", "to@test", "asset#test", "description", oversizedInt.toString()); + assertThrows(IllegalArgumentException.class, mtb::build); + } + + + /* ====================== SetAccountDetail Tests ====================== */ + @Test void setAccountDetail() { - UnsignedTx tx = builder.setAccountDetail("admin@test", "fyodor", "kek").build(); + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = accountName + "@" + domain; + UnsignedTx tx = builder.setAccountDetail(accountId, "fyodor", "kek").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void setAccountDetailInvalidAccount() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().setAccountDetail(accountId, "fyodor", "true"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void setAccountDetailEmptyAccount() { + ModelTransactionBuilder builder = base().setAccountDetail("", "fyodor", "true"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void setAccountDetailInvalidAccountDomain() { + for (String domain: invalidDomains) { + String accountId = "admin@" + domain; + ModelTransactionBuilder builder = base().setAccountDetail(accountId, "fyodor", "true"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void setAccountDetailValidKey() { + for (String key: validNameSymbols2) { + UnsignedTx tx = builder.setAccountDetail("admin@test", key, "true").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + + @Test + void setAccountDetailInvalidKey() { + for (String key: invalidNameSymbols2) { + ModelTransactionBuilder builder = base().setAccountDetail("admin@test", key, "true"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void setAccountDetailValidValue() { + int length = 4 * 1024 * 1024; + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) { + sb.append("a"); + } + + for (String value: new String[]{"", sb.toString()}) { + UnsignedTx tx = builder.setAccountDetail("admin@test", "fyodor", value).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + + @Test + void setAccountDetailWithOversizedValue() { + int length = 4 * 1024 * 1024 + 1; + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) { + sb.append("a"); + } + + ModelTransactionBuilder builder = base().setAccountDetail("admin@test", "fyodor", sb.toString()); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== AppendRole Tests ====================== */ + + @Test + void appendRole() { + for (String account: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = account + "@" + domain; + UnsignedTx tx = builder.appendRole(accountId, account).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void appendRoleInvalidAccount() { + for (String account: invalidNameSymbols1) { + String accountId = account + "@test"; + ModelTransactionBuilder builder = base().appendRole(accountId, "user"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void appendRoleInvalidDomain() { + for (String domain: invalidDomains) { + String accountId = "admin@" + domain; + ModelTransactionBuilder builder = base().appendRole(accountId, "user"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void appendRoleWithInvalidName() { + for (String role: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().appendRole("admin@test", role); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + + /* ====================== CreateAsset Tests ====================== */ + + @Test + void createAsset() { + for (String assetName: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedTx tx = builder.createAsset(assetName, domain, (short) 6).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void createAssetWithInvalidName() { + for (String asset: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().createAsset(asset, "test", (short) 6); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void createAssetWithInvalidDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().createAsset("asset", domain, (short) 6); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void createAssetWithZeroPrecision() { + UnsignedTx tx = builder.createAsset("asset", "test", (short) 0).build(); assertTrue(checkProtoTx(proto(tx))); } + + /* ====================== CreateRole Tests ====================== */ + + @Test + void createRole() { + StringVector permissions = new StringVector(); + permissions.add("can_receive"); + permissions.add("can_get_roles"); + assertTrue(permissions.size() == 2); + + for (String role: validNameSymbols1) { + UnsignedTx tx = builder.createRole(role, permissions).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + + @Test + void createRoleWithInvalidName() { + StringVector permissions = new StringVector(); + permissions.add("can_receive"); + permissions.add("can_get_roles"); + assertTrue(permissions.size() == 2); + + for (String role: invalidNameSymbols1) { + ModelTransactionBuilder mtb = base().createRole(role, permissions); + assertThrows(IllegalArgumentException.class, mtb::build); + } + } + + @Test + void createRoleEmptyPermissions() { + StringVector permissions = new StringVector(); + + ModelTransactionBuilder builder = new ModelTransactionBuilder(); + builder.createRole("new_role", permissions); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* Disabled till IR-1267 will be fixed. */ + /* Please run this test on mac host after enabling, + because the test was passing on Linux host and failing on macOs. + */ + @Disabled + @Test + void createRoleWrongPermissions() { + StringVector permissions = new StringVector(); + permissions.add("wrong_permission"); + permissions.add("can_receive"); + + ModelTransactionBuilder builder = base().createRole("new_role", permissions); + assertThrows(IllegalArgumentException.class, builder::build); + } + + + /* Test differs from the previous by the order of permissions' mames in vector. + * Test is disabled because there is no exception thrown when it should be. + */ + /* Disabled till IR-1267 will be fixed. */ + @Disabled + @Test + void createRoleWrongPermissions2() { + StringVector permissions = new StringVector(); + permissions.add("can_receive"); + permissions.add("wrong_permission"); + + ModelTransactionBuilder builder = base().createRole("new_role", permissions); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== DetachRole Tests ====================== */ + + @Test + void detachRole() { + for (String name: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = name + "@" + domain; + UnsignedTx tx = builder.detachRole(accountId, name).build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void detachRoleInvalidAccountName() { + for (String accountName: invalidNameSymbols1) { + String accountId = accountName + "@test"; + ModelTransactionBuilder builder = base().detachRole(accountId, "role"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void detachRoleInvalidDomain() { + for (String domain: invalidDomains) { + String accountId = "admin@" + domain; + ModelTransactionBuilder builder = base().detachRole(accountId, "role"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void detachRoleWithEmptyAccount() { + ModelTransactionBuilder builder = base().detachRole("", "role"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void detachRoleWithInvalidName() { + for (String role: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().detachRole("admin@test", role); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== GrantPermission Tests ====================== */ + + @Test + void grantPermission() { + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + String accountId = accountName + "@" + domain; + UnsignedTx tx = builder.grantPermission(accountId, "can_set_my_quorum").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void grantPermissionInvalidAccount() { + for (String accountName: invalidNameSymbols1) { + for (String domain: validDomains) { + String accountId = accountName + "@" + domain; + ModelTransactionBuilder builder = base().grantPermission(accountId, "can_set_my_quorum"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + } + + @Test + void grantPermissionEmptyAccount() { + ModelTransactionBuilder builder = base().grantPermission("", "can_set_my_quorum"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + // TODO igor-egorov, 14.05.2018 IR-1267 + // Please test using clang on macOS before enabling + // This test does not fail on Linux with GCC 5.4.0 + @Disabled + @Test + void grantPermissionWithInvalidName() { + String permissions[] = { + "", + "random", + "can_read_assets" // non-grantable permission + }; + + for (String permission: permissions) { + ModelTransactionBuilder builder = base().grantPermission("admin@test", permission); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== RevokePermission Tests ====================== */ + + @Test + void revokePermission() { + for (String accountName: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedTx tx = builder.revokePermission(accountName + "@" + domain, "can_set_my_quorum").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void revokePermissionInvalidAccount() { + for (String accountName: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().revokePermission(accountName + "@test", "can_set_my_quorum"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void revokePermissionInvalidDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().revokePermission("admin@" + domain, "can_set_my_quorum"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void revokePermissionEmptyAccount() { + ModelTransactionBuilder builder = base().revokePermission("", "can_set_my_quorum"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + // TODO igor-egorov, 14.05.2018 IR-1267 + // Please test using clang on macOS before enabling + // This test does not fail on Linux with GCC 5.4.0 + @Disabled + @Test + void revokePermissionWithInvalidName() { + String permissions[] = { + "", + "random", + "can_read_assets" // non-grantable permission + }; + + for (String permission: permissions) { + ModelTransactionBuilder builder = base().revokePermission("admin@test", permission); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== SubtractAssetQuantity Tests ====================== */ + + @Test + void subtractAssetQuantity() { + for (String name: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedTx tx = builder.subtractAssetQuantity(name + "@" + domain, name + "#" + domain, "10.22").build(); + assertTrue(checkProtoTx(proto(tx))); + } + } + } + + @Test + void subtractAssetQuantityInvalidAccount() { + for (String account: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().subtractAssetQuantity(account + "@test", "coin#test", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void subtractAssetQuantityInvalidAccountDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().subtractAssetQuantity("admin@" + domain, "coin#test", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void subtractAssetQuantityInvalidAsset() { + for (String asset: invalidNameSymbols1) { + ModelTransactionBuilder builder = base().subtractAssetQuantity("admin@test", asset + "#test", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void subtractAssetQuantityInvalidAssetDomain() { + for (String domain: invalidDomains) { + ModelTransactionBuilder builder = base().subtractAssetQuantity("admin@test", "coin#" + domain, "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void subtractAssetQuantityEmptyAccount() { + ModelTransactionBuilder builder = base().subtractAssetQuantity("", "coin#test", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void subtractAssetQuantityEmptyAsset() { + ModelTransactionBuilder builder = base().subtractAssetQuantity("admin@test", "", "10"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void subtractAssetQuantityInvalidAmount() { + String invalidAmounts[] = { + "", + "0", + "chars", + "-10", + "10chars", + "10.10.10" + }; + + for (String amount: invalidAmounts) { + ModelTransactionBuilder builder = base().subtractAssetQuantity("admin@test", "coin#test", amount); + assertThrows(IllegalArgumentException.class, builder::build); + } + } } diff --git a/test/module/shared_model/bindings/QueryTest.java b/test/module/shared_model/bindings/QueryTest.java index 2f14305e8b..0c5ef9bd9c 100644 --- a/test/module/shared_model/bindings/QueryTest.java +++ b/test/module/shared_model/bindings/QueryTest.java @@ -1,5 +1,11 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; import java.math.BigInteger; @@ -27,12 +33,123 @@ public class QueryTest { private Keypair keys; private ModelQueryBuilder builder; + // Symbols of type 1 (format [a-z_0-9]{1,32}) are used + // as account_name, asset_name and role_id. + private final String[] validNameSymbols1 = { + "a", + "asset", + "234234", + "_", + "_123", + "123_23", + "234asset_", + "__", + "12345678901234567890123456789012" + }; + private final String[] invalidNameSymbols1 = { + "", + "A", + "assetV", + "asSet", + "asset%", + "^123", + "verylongassetname_thenameislonger", + "verylongassetname_thenameislongerthanitshouldbe", + "assset-01" + }; + + // Symbols of type 2 (format [A-Za-z0-9_]{1,64}) + // are used as key identifier for setAccountDetail command + private final String[] validNameSymbols2 = { + "a", + "A", + "1", + "_", + "Key", + "Key0_", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid" + }; + private final String[] invalidNameSymbols2 = { + "", + "Key&", + "key-30", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid1", + "@@@" + }; + + private final String[] validDomains = { + "test", + "u9EEA432F", + "a-hyphen", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad", + "endWith0", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad" + }; + + private final String[] invalidDomains = { + "", + " ", + " ", + "9start.with.digit", + "-startWithDash", + "@.is.not.allowed", + "no space is allowed", + "endWith-", + "label.endedWith-.is.not.allowed", + "aLabelMustNotExceeds63charactersALabelMustNotExceeds63characters", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPadP", + "257.257.257.257", + "domain#domain", + "asd@asd", + "ab..cd" + }; + + private final String[] invalidKeysBytes = { + "", + "a", + "1111111111111111111111111111111", + "111111111111111111111111111111111" + }; + ModelQueryBuilder base() { return new ModelQueryBuilder().queryCounter(BigInteger.valueOf(123)) .createdTime(BigInteger.valueOf(System.currentTimeMillis())) .creatorAccountId("admin@test"); } + Blob proto(UnsignedQuery query) { + return new ModelProtoQuery().signAndAddSignature(query, keys); + } + + /** + * Performs check that Blob contains valid proto Query + * @param serialized blob with binary data for check + * @return true if valid + */ + private boolean checkProtoQuery(Blob serialized) { + ByteVector blob = serialized.blob(); + byte bs[] = new byte[(int)blob.size()]; + + for (int i = 0; i < blob.size(); i++) { + bs[i] = (byte)blob.get(i); + } + + try { + Queries.Query.parseFrom(bs); + } catch (InvalidProtocolBufferException e) { + System.out.print("Exception: "); + System.out.println(e.getMessage()); + return false; + } + return true; + } + void setGetAccount() { builder.getAccount("user@test"); } @@ -49,8 +166,11 @@ void emptyQuery() { assertThrows(IllegalArgumentException.class, builder::build); } + /* ====================== GetAccount Tests ====================== */ + + @Test - void outdatedAddPeer() { + void outdatedGetAccount() { setGetAccount(); for (BigInteger i : new BigInteger[]{BigInteger.valueOf(0), BigInteger.valueOf(System.currentTimeMillis() - 100_000_000), @@ -63,87 +183,302 @@ void outdatedAddPeer() { @Test void getAccountWithInvalidCreator() { setGetAccount(); - for (String i : new String[]{"", "invalid", "@invalid", "invalid@"}) { - builder.creatorAccountId(i); - assertThrows(IllegalArgumentException.class, builder::build); + for (String accountName: invalidNameSymbols1) { + for (String domain: validDomains) { + ModelQueryBuilder builder = base().creatorAccountId(accountName + "@" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } } } - Blob proto(UnsignedQuery query) { - return new ModelProtoQuery().signAndAddSignature(query, keys); + @Test + void getAccountWithInvalidCreatorDomain() { + setGetAccount(); + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().creatorAccountId("user@" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } } - /** - * Performs check that Blob contains valid proto Query - * @param serialized blob with binary data for check - * @return true if valid - */ - private boolean checkProtoQuery(Blob serialized) { - ByteVector blob = serialized.blob(); - byte bs[] = new byte[(int)blob.size()]; + @Test + void getAccountWithEmptyCreator() { + setGetAccount(); + builder.creatorAccountId(""); + assertThrows(IllegalArgumentException.class, builder::build); + } - for (int i = 0; i < blob.size(); i++) { - bs[i] = (byte)blob.get(i); + @Test + void getAccount() { + for (String accountName: validNameSymbols1) { + UnsignedQuery query = builder.getAccount(accountName + "@test").build(); + assertTrue(checkProtoQuery(proto(query))); } + } - try { - Queries.Query.parseFrom(bs); - } catch (InvalidProtocolBufferException e) { - System.out.print("Exception: "); - System.out.println(e.getMessage()); - return false; + @Test + void getAccountWithInvalidName() { + for (String accountName: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccount(accountName + "@test"); + assertThrows(IllegalArgumentException.class, builder::build); } - return true; } @Test - void getAccount() { - UnsignedQuery query = builder.getAccount("user@test").build(); - assertTrue(checkProtoQuery(proto(query))); + void getAccountWithInvalidDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccount("admin@" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } } + /* ====================== GetSignatories Tests ====================== */ + @Test void getSignatories() { - UnsignedQuery query = builder.getSignatories("user@test").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String account: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedQuery query = builder.getSignatories(account + "@" + domain).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } } + @Test + void getSignatoriesInvalidAccount() { + for (String account: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getSignatories(account + "@test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getSignatoriesEmptyAccount() { + builder.getSignatories(""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void getSignatoriesInvalidDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getSignatories("user@" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + /* ====================== GetAccountTransactions Tests ====================== */ + @Test void getAccountTransactions() { - UnsignedQuery query = builder.getAccountTransactions("user@test").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String account: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedQuery query = builder.getAccountTransactions(account + "@" + domain).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } + } + + @Test + void getAccountTransactionsInvalidName() { + for (String account: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccountTransactions(account + "@test"); + assertThrows(IllegalArgumentException.class, builder::build); + } } + @Test + void getAccountTransactionsInvalidDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccountTransactions("user@" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountTransactionsEmptyAccount() { + ModelQueryBuilder builder = base().getAccountTransactions(""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== GetAccountAssetTransactions Tests ====================== */ + @Test void getAccountAssetTransactions() { - UnsignedQuery query = builder.getAccountAssetTransactions("user@test", "coin#test").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String name: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedQuery query = builder.getAccountAssetTransactions(name + "@" + domain, name + "#" + domain).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } + } + + @Test + void getAccountAssetTransactionsInvalidAccountName() { + for (String account: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccountAssetTransactions(account + "@test", "coin#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountAssetTransactionsInvalidAccountDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccountAssetTransactions("user@" + domain, "coin#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } } + @Test + void getAccountAssetTransactionsEmptyAccount() { + ModelQueryBuilder builder = base().getAccountAssetTransactions("", "coin#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void getAccountAssetTransactionsInvalidAssetName() { + for (String asset: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccountAssetTransactions("user@test", asset + "#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountAssetTransactionsInvalidAssetDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccountAssetTransactions("user@test", "coin#" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountAssetTransactionsEmptyAsset() { + ModelQueryBuilder builder = base().getAccountAssetTransactions("user@test", ""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== GetAccountAssets Tests ====================== */ + @Test void getAccountAssets() { - UnsignedQuery query = builder.getAccountAssets("user@test", "coin#test").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String name: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedQuery query = builder.getAccountAssets(name + "@" + domain, name + "#" + domain).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } + } + + @Test + void getAccountAssetsWithInvalidAccountName() { + for (String account: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccountAssets(account + "@test", "coin#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountAssetsWithInvalidAccountDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccountAssets("user@" + domain, "coin#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountAssetsWithEmptyAccount() { + ModelQueryBuilder builder = base().getAccountAssets("", "coin#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + + @Test + void getAccountAssetsWithInvalidAssetName() { + for (String asset: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccountAssets("user@test", asset + "#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountAssetsWithInvalidAssetDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccountAssets("user@test", "coin#" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } } + @Test + void getAccountAssetsWithEmptyAsset() { + ModelQueryBuilder builder = base().getAccountAssets("user@test", ""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== GetRoles Tests ====================== */ + @Test void getRoles() { UnsignedQuery query = builder.getRoles().build(); assertTrue(checkProtoQuery(proto(query))); } + /* ====================== GetAssetInfo Tests ====================== */ + @Test void getAssetInfo() { - UnsignedQuery query = builder.getAssetInfo("coin#test").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String asset: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedQuery query = builder.getAssetInfo(asset + "#" + domain).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } } + @Test + void getAssetInfoWithInvalidName() { + for (String asset: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAssetInfo(asset + "#test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAssetInfoWithInvalidDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAssetInfo("coin#" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAssetInfoWithEmptyName() { + ModelQueryBuilder builder = base().getAssetInfo(""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== GetRolePermissions Tests ====================== */ + @Test void getRolePermissions() { - UnsignedQuery query = builder.getRolePermissions("user").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String role: validNameSymbols1) { + UnsignedQuery query = builder.getRolePermissions(role).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } + + @Test + void getRolePermissionsWithInvalidName() { + for (String role: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getRolePermissions(role); + assertThrows(IllegalArgumentException.class, builder::build); + } } + @Test + void getRolePermissionsWithEmptyName() { + ModelQueryBuilder builder = base().getRolePermissions(""); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== GetTransactions Tests ====================== */ + @Test void getTransactions() { HashVector hv = new HashVector(); @@ -156,9 +491,94 @@ void getTransactions() { assertTrue(checkProtoQuery(proto(query))); } + // The following four tests are disabled because there is a need to + // clarify desired behavior. + // TODO igor-egorov, 08.05.2018, IR-1322 + @Disabled + @Test + void getTransactionsWithEmptyVector() { + ModelQueryBuilder builder = base().getTransactions(new HashVector()); + assertThrows(IllegalArgumentException.class, builder::build); + } + + // TODO igor-egorov, 08.05.2018, IR-1325 + @Disabled + @Test + void getTransactionsWithInvalidHashSizes() { + String hashes[] = { + "", + "1", + "1234567890123456789012345678901", + "123456789012345678901234567890123" + }; + + for (String hash: hashes) { + HashVector hv = new HashVector(); + hv.add(new Hash(hash)); + ModelQueryBuilder builder = base().getTransactions(hv); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + // TODO igor-egorov, 08.05.2018, IR-1325 + @Disabled + @Test + void getTransactionsWithOneValidAndOneInvalidHash1() { + Hash valid = new Hash("12345678901234567890123456789012"); + Hash invalid = new Hash("1"); + + HashVector hv = new HashVector(); + hv.add(valid); + hv.add(invalid); + ModelQueryBuilder builder = base().getTransactions(hv); + assertThrows(IllegalArgumentException.class, builder::build); + } + + // TODO igor-egorov, 08.05.2018, IR-1325 + @Disabled + @Test + void getTransactionsWithOneValidAndOneInvalidHash2() { + Hash valid = new Hash("12345678901234567890123456789012"); + Hash invalid = new Hash("1"); + + HashVector hv = new HashVector(); + hv.add(invalid); + hv.add(valid); + ModelQueryBuilder builder = base().getTransactions(hv); + assertThrows(IllegalArgumentException.class, builder::build); + } + + /* ====================== GetAccountDetail Tests ====================== */ + @Test void getAccountDetail() { - UnsignedQuery query = builder.getAccountDetail("user@test").build(); - assertTrue(checkProtoQuery(proto(query))); + for (String account: validNameSymbols1) { + for (String domain: validDomains) { + UnsignedQuery query = builder.getAccountDetail(account + "@" + domain).build(); + assertTrue(checkProtoQuery(proto(query))); + } + } + } + + @Test + void getAccountDetailWithInvalidName() { + for (String account: invalidNameSymbols1) { + ModelQueryBuilder builder = base().getAccountDetail(account + "@test"); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountDetailWithInvalidDomain() { + for (String domain: invalidDomains) { + ModelQueryBuilder builder = base().getAccountDetail("user@" + domain); + assertThrows(IllegalArgumentException.class, builder::build); + } + } + + @Test + void getAccountDetailWithEmptyName() { + ModelQueryBuilder builder = base().getAccountDetail(""); + assertThrows(IllegalArgumentException.class, builder::build); } } From 5bfbebce0816403daa93bf068945a0739bb53c28 Mon Sep 17 00:00:00 2001 From: Igor Egorov <36847043+igor-egorov@users.noreply.github.com> Date: Mon, 14 May 2018 14:37:23 +0300 Subject: [PATCH 097/110] Update names of docker images (#1337) * Ansible paths are updated * ReadTheDocs sources are updated * Docker hub repository description is set Signed-off-by: Igor Egorov --- .../ansible/roles/iroha-cluster-deploy-node/defaults/main.yml | 4 ++-- .../roles/iroha-standalone-deploy-node/defaults/main.yml | 4 ++-- docs/source/guides/build.rst | 4 ++-- docs/source/guides/deployment.rst | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/deploy/ansible/roles/iroha-cluster-deploy-node/defaults/main.yml b/deploy/ansible/roles/iroha-cluster-deploy-node/defaults/main.yml index cdcda7679c..1804f0a11b 100644 --- a/deploy/ansible/roles/iroha-cluster-deploy-node/defaults/main.yml +++ b/deploy/ansible/roles/iroha-cluster-deploy-node/defaults/main.yml @@ -7,7 +7,7 @@ iroha_net: iroha_network # name of docker network containerConfPath: /opt/iroha_data # path to folder with config files inside docker container - irohaDockerImage: hyperledger/iroha-docker # docker image name - irohaDockerImageTag: develop_latest # docker image tag + irohaDockerImage: hyperledger/iroha # docker image name + irohaDockerImageTag: develop # docker image tag dbDockerImage: postgres dbDockerImageTag: 9.5 diff --git a/deploy/ansible/roles/iroha-standalone-deploy-node/defaults/main.yml b/deploy/ansible/roles/iroha-standalone-deploy-node/defaults/main.yml index 15a0c7c26d..b719450d0e 100644 --- a/deploy/ansible/roles/iroha-standalone-deploy-node/defaults/main.yml +++ b/deploy/ansible/roles/iroha-standalone-deploy-node/defaults/main.yml @@ -7,7 +7,7 @@ iroha_net: iroha_network # name of docker network containerConfPath: /opt/iroha_data - irohaDockerImage: hyperledger/iroha-docker # docker image name - irohaDockerImageTag: develop_latest # docker image tag + irohaDockerImage: hyperledger/iroha # docker image name + irohaDockerImageTag: develop # docker image tag dbDockerImage: postgres dbDockerImageTag: 9.5 diff --git a/docs/source/guides/build.rst b/docs/source/guides/build.rst index beaee71092..2a46387808 100644 --- a/docs/source/guides/build.rst +++ b/docs/source/guides/build.rst @@ -57,8 +57,8 @@ After you execute this script, following things happen: 1. The script checks if you don't have containers with Iroha already running. Successful completion finishes with the new container shell. -2. The script will download ``iroha-docker-develop`` and ``postgres`` images. -``iroha-docker-develop`` image contains all development dependencies and is +2. The script will download ``hyperledger/iroha:develop-build`` and ``postgres`` images. +``hyperledger/iroha:develop-build`` image contains all development dependencies and is based on top of ``ubuntu:16.04``. ``postgres`` image is required for starting and running Iroha. 3. Two containers are created and launched. diff --git a/docs/source/guides/deployment.rst b/docs/source/guides/deployment.rst index 04ab566ebe..40dd732a5a 100644 --- a/docs/source/guides/deployment.rst +++ b/docs/source/guides/deployment.rst @@ -70,7 +70,7 @@ In order to run Iroha peer as a single instance in Docker, you should pull the i .. code-block:: shell - docker pull hyperledger/iroha-docker:latest + docker pull hyperledger/iroha:latest .. Hint:: Use *latest* tag for latest stable release, and *develop* for latest development version @@ -138,7 +138,7 @@ If they are met, you can move forward with the following command: -e KEY='node0' \ # Docker network name --network=iroha-network \ - hyperledger/iroha-docker:latest + hyperledger/iroha:latest Running multiple instances (peer network) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From d873dca2b2b358413a1a64ee6a282d795293e0e8 Mon Sep 17 00:00:00 2001 From: Igor Egorov <36847043+igor-egorov@users.noreply.github.com> Date: Mon, 14 May 2018 14:42:34 +0300 Subject: [PATCH 098/110] Add Python Tests (#1332) The total number of tests for commands is 98, queries - 45. Signed-off-by: Igor Egorov --- .../shared_model/bindings/builder-test.py | 692 ++++++++++++++++-- .../shared_model/bindings/query-test.py | 392 +++++++++- 2 files changed, 1002 insertions(+), 82 deletions(-) diff --git a/test/module/shared_model/bindings/builder-test.py b/test/module/shared_model/bindings/builder-test.py index 057d59732e..429d8af667 100644 --- a/test/module/shared_model/bindings/builder-test.py +++ b/test/module/shared_model/bindings/builder-test.py @@ -1,3 +1,8 @@ +# +# Copyright Soramitsu Co., Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + import iroha import unittest import time @@ -9,43 +14,103 @@ # TODO luckychess 8.08.2018 add test for number of methods # in interface and proto implementation IR-1080 -class BuilderTest(unittest.TestCase): - def test_empty_tx(self): - with self.assertRaises(ValueError): - iroha.ModelTransactionBuilder().build() - def generate_base(self): - return iroha.ModelTransactionBuilder()\ - .createdTime(int(time.time() * 1000))\ - .creatorAccountId("admin@test")\ +# Symbols of type 1 (format [a-z_0-9]{1,32}) are used +# as account_name, asset_name and role_id. +VALID_NAMES_1 = [ + "a", + "asset", + "234234", + "_", + "_123", + "123_23", + "234asset_", + "__", + "12345678901234567890123456789012" +] - def setUp(self): - self.keys = iroha.ModelCrypto().generateKeypair() - self.builder = self.generate_base() +INVALID_NAMES_1 = [ + "", + "A", + "assetV", + "asSet", + "asset%", + "^123", + "verylongassetname_thenameislonger", + "verylongassetname_thenameislongerthanitshouldbe", + "assset-01" +] - def set_add_peer(self): - self.builder.addPeer("123.123.123.123", self.keys.publicKey()) +# Symbols of type 2 (format [A-Za-z0-9_]{1,64}) +# are used as key identifier for setAccountDetail command +VALID_NAMES_2 = [ + "a", + "A", + "1", + "_", + "Key", + "Key0_", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid" +] - def test_outdated_add_peer(self): - self.set_add_peer() - for i in [0, int((time.time() - 100000) * 1000), int((time.time() + 1) * 1000)]: - with self.assertRaises(ValueError): - self.builder.createdTime(i).build() +INVALID_NAMES_2 = [ + "", + "Key&", + "key-30", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid1", + "@@@" +] - def test_add_peer_with_invalid_creator(self): - self.set_add_peer() - for s in ["invalid", "@invalid", "invalid"]: - with self.assertRaises(ValueError): - self.builder.creatorAccountId(s).build() +VALID_DOMAINS = [ + "test", + "u9EEA432F", + "a-hyphen", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad", + "endWith0", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad" +] - def test_add_peer_with_invalid_key_size(self): - for k in ['9' * 13, '9' * (len(self.keys.publicKey().blob()) - 1), '9' * (len(self.keys.publicKey().blob()) + 1), '']: - with self.assertRaises(ValueError): - self.generate_base().addPeer("123.123.123.123", iroha.PublicKey(k)).build() +INVALID_DOMAINS = [ + "", + " ", + " ", + "9start.with.digit", + "-startWithDash", + "@.is.not.allowed", + "no space is allowed", + "endWith-", + "label.endedWith-.is.not.allowed", + "aLabelMustNotExceeds63charactersALabelMustNotExceeds63characters", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPadP", + "257.257.257.257", + "domain#domain", + "asd@asd", + "ab..cd" +] + +INVALID_KEYS = [ + "", + "a", + "1" * 31, + "1" * 33 +] - def test_add_peer_with_invalid_host(self): - for k in ["257.257.257.257", "host#host", "asd@asd", 'a' * 257, "ab..cd"]: - with self.assertRaises(ValueError) as err: - self.generate_base().addPeer(k, self.keys.publicKey()).build() +class BuilderTest(unittest.TestCase): + + def setUp(self): + self.keys = iroha.ModelCrypto().generateKeypair() + self.pub_key = self.keys.publicKey() + self.builder = self.base() + + def base(self): + return iroha.ModelTransactionBuilder()\ + .createdTime(int(time.time() * 1000))\ + .creatorAccountId("admin@test") def proto(self, tx): return iroha.ModelProtoTransaction().signAndAddSignature(tx, self.keys) @@ -62,41 +127,580 @@ def check_proto_tx(self, blob): return False return True + def set_add_peer(self): + self.builder.addPeer("123.123.123.123", self.keys.publicKey()) + + def test_empty_tx(self): + with self.assertRaises(ValueError): + iroha.ModelTransactionBuilder().build() + + # ====================== AddPeer Tests ====================== + def test_add_peer(self): tx = self.builder.addPeer("123.123.123.123:123", self.keys.publicKey()).build() self.assertTrue(self.check_proto_tx(self.proto(tx))) + def test_add_peer_valid_domains(self): + for domain in VALID_DOMAINS: + tx = self.builder.addPeer("{}:123".format(domain), self.keys.publicKey()).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_outdated_add_peer(self): + self.set_add_peer() + for i in [0, int((time.time() - 100000) * 1000), int((time.time() + 1) * 1000)]: + with self.assertRaises(ValueError): + self.builder.createdTime(i).build() + + def test_add_peer_with_invalid_creator(self): + self.set_add_peer() + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.builder.creatorAccountId("{}@test".format(name)).build() + + def test_add_peer_with_invalid_creator_domain(self): + self.set_add_peer() + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.builder.creatorAccountId("admin@{}".format(domain)).build() + + def test_add_peer_with_empty_creator(self): + self.set_add_peer() + with self.assertRaises(ValueError): + self.builder.creatorAccountId("").build() + + def test_add_peer_with_invalid_key_size(self): + for k in INVALID_KEYS: + with self.assertRaises(ValueError): + self.base().addPeer("123.123.123.123", iroha.PublicKey(k)).build() + + def test_add_peer_with_invalid_domain(self): + for k in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().addPeer(k, self.keys.publicKey()).build() + + # ====================== AddSignatory Tests ====================== + def test_add_signatory(self): - tx = self.builder.addSignatory("admin@test", self.keys.publicKey()).build() - self.assertTrue(self.check_proto_tx(self.proto(tx))) + for name in VALID_NAMES_1: + for domain in VALID_DOMAINS: + tx = self.builder.addSignatory("{}@{}".format(name, domain), self.keys.publicKey()).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_add_signatory_invalid_account_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().addSignatory("{}@test".format(name), self.keys.publicKey()).build() + + def test_add_signatory_empty_account(self): + with self.assertRaises(ValueError): + self.base().addSignatory("", self.keys.publicKey()).build() + + def test_add_signatory_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().addSignatory("admin@{}".format(domain), self.keys.publicKey()).build() + + def test_add_signatory_invalid_key(self): + for key in INVALID_KEYS: + with self.assertRaises(ValueError): + self.base().addSignatory("admin@test", iroha.PublicKey(key)).build() + + # ====================== AddAssetQuantity Tests ====================== def test_add_asset_quantity(self): tx = self.builder.addAssetQuantity("admin@test", "asset#domain", "12.345").build() self.assertTrue(self.check_proto_tx(self.proto(tx))) + def test_add_asset_quantity_valid_account_and_asset(self): + for name in VALID_NAMES_1: + for domain in VALID_DOMAINS: + tx = self.builder.addAssetQuantity("{}@{}".format(name, domain), "{}#{}".format(name, domain), "100").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_add_asset_quantity_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().addAssetQuantity("{}@test".format(name), "coin#test", "10").build() + + def test_add_asset_quantity_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().addAssetQuantity("admin@{}".format(domain), "coin#test", "10").build() + + def test_add_asset_quantity_empty_account(self): + with self.assertRaises(ValueError): + self.base().addAssetQuantity("", "coin#test", "10").build() + + def test_add_asset_quantity_invalid_asset(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().addAssetQuantity("admin@test", "{}#test".format(name), "10").build() + + def test_add_asset_quantity_invalid_asset_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().addAssetQuantity("admin@test", "coin#{}".format(domain), "10").build() + + def test_add_asset_quantity_empty_asset(self): + with self.assertRaises(ValueError): + self.base().addAssetQuantity("admin@test", "", "10").build() + + def test_add_asset_quantity_invalid_amount(self): + for amount in ["", "-12", "-13.45", "chars", "chars10"]: + with self.assertRaises(ValueError): + self.base().addAssetQuantity("admin@test", "coin#test", amount).build() + + # ====================== RemoveSignatory Tests ====================== + def test_remove_signatory(self): - tx = self.builder.removeSignatory("admin@test", self.keys.publicKey()).build() - self.assertTrue(self.check_proto_tx(self.proto(tx))) + for name in VALID_NAMES_1: + for domain in VALID_DOMAINS: + tx = self.builder.removeSignatory("{}@{}".format(name, domain), self.keys.publicKey()).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_remove_signatory_empty_account(self): + with self.assertRaises(ValueError): + self.base().removeSignatory("", self.keys.publicKey()).build() + + def test_remove_signatory_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().removeSignatory("{}@test".format(name), self.keys.publicKey()).build() + + def test_remove_signatory_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().removeSignatory("admin@{}".format(domain), self.keys.publicKey()).build() + + def test_remove_signatory_invalid_key(self): + for key in INVALID_KEYS: + with self.assertRaises(ValueError): + self.base().removeSignatory("admin@test", iroha.PublicKey(key)).build() + + # ====================== CreateAccount Tests ====================== def test_create_account(self): - tx = self.builder.createAccount("admin", "domain", self.keys.publicKey()).build() - self.assertTrue(self.check_proto_tx(self.proto(tx))) + for name in VALID_NAMES_1: + for domain in VALID_DOMAINS: + tx = self.builder.createAccount(name, domain, self.keys.publicKey()).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_create_account_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().createAccount(name, "domain", self.keys.publicKey()).build() + + def test_create_account_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().createAccount("admin", domain, self.keys.publicKey()).build() + + def test_create_account_invalid_key(self): + for key in INVALID_KEYS: + with self.assertRaises(ValueError): + self.base().createAccount("admin", "test", iroha.PublicKey(key)).build() + + # ====================== CreateDomain Tests ====================== def test_create_domain(self): - tx = self.builder.createDomain("domain", "role").build() - self.assertTrue(self.check_proto_tx(self.proto(tx))) + for domain in VALID_DOMAINS: + for role in VALID_NAMES_1: + tx = self.builder.createDomain(domain, role).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_create_domain_with_invalid_name(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().createDomain(domain, "role").build() + + def test_create_domain_invalid_role(self): + for role in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().createDomain("test", role).build() + + # ====================== SetAccountQuorum Tests ====================== def test_set_account_quorum(self): - tx = self.builder.setAccountQuorum("admin@test", 123).build() - self.assertTrue(self.check_proto_tx(self.proto(tx))) + for name in VALID_NAMES_1: + for domain in VALID_DOMAINS: + tx = self.builder.setAccountQuorum("{}@{}".format(name, domain), 128).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_set_account_quorum_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().setAccountQuorum("{}@test".format(name), 123).build() + + def test_set_account_quorum_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().setAccountQuorum("admin@{}".format(domain), 123).build() + + def test_set_account_quorum_empty_account(self): + with self.assertRaises(ValueError): + self.base().setAccountQuorum("", 123).build() + + def test_set_account_quorum_invalid_quantity(self): + with self.assertRaises(OverflowError): + self.base().setAccountQuorum("admin@test", -100).build() + + for amount in [0, 129]: + with self.assertRaises(ValueError): + self.base().setAccountQuorum("admin@test", amount).build() + + # ====================== TransferAsset Tests ====================== def test_transfer_asset(self): - tx = self.builder.transferAsset("from@test", "to@test", "asset#test", "description", "123.456").build() - self.assertTrue(self.check_proto_tx(self.proto(tx))) + for domain in VALID_DOMAINS: + for i in range(0, len(VALID_NAMES_1)): + from_acc = "{}@{}".format(VALID_NAMES_1[i], domain) + to = "{}@{}".format(VALID_NAMES_1[(i + 1) % len(VALID_NAMES_1)], domain) + asset = "{}#{}".format(VALID_NAMES_1[(i + 2) % len(VALID_NAMES_1)], domain) + tx = self.builder.transferAsset(from_acc, to, asset, "description", "123.456").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_transfer_asset_with_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "to@test", "{}#test".format(name), "description", "100").build() + + def test_transfer_asset_with_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "to@test", "coin#{}".format(domain), "description", "100").build() + + def test_transfer_asset_with_empty_name(self): + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "to@test", "", "description", "100").build() + + def test_transfer_asset_invalid_from_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().transferAsset("{}@test".format(name), "to@test", "coin#test", "description", "100").build() + + def test_transfer_asset_invalid_from_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().transferAsset("from@{}".format(domain), "to@test", "coin#test", "description", "100").build() + + def test_transfer_asset_empty_from_account(self): + with self.assertRaises(ValueError): + self.base().transferAsset("", "to@test", "coin#test", "description", "100").build() + + def test_transfer_asset_invalid_to_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "{}@test".format(name), "coin#test", "description", "100").build() + + def test_transfer_asset_invalid_to_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "to@{}".format(domain), "coin#test", "description", "1").build() + + def test_transfer_asset_empty_to_account(self): + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "", "coin#test", "description", "1").build() + + def test_transfer_asset_description_valid_values(self): + for descr in ["", "a" * 64]: + tx = self.builder.transferAsset("from@test", "to@test", "coin#test", descr, "1").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_transfer_asset_invalid_description(self): + descr = "a" * 65 + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "to@test", "coin#test", descr, "1").build() + + def test_transfer_asset_maximum_amount(self): + max_uint_256 = str(2 ** 256 - 1) + max_uint_256_2 = max_uint_256[:10] + '.' + max_uint_256[10:] + oversized = str(2 ** 256) + + for amount in [max_uint_256, max_uint_256_2]: + tx = self.builder.transferAsset("from@test", "to@test", "coin#test", "descr", amount).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + with self.assertRaises(ValueError): + self.base().transferAsset("from@test", "to@test", "coin#test", "descr", oversized).build() + + # ====================== SetAccountDetail Tests ====================== def test_set_account_detail(self): - tx = self.builder.setAccountDetail("admin@test", "fyodor", "kek").build() + for name in VALID_NAMES_1: + for domain in VALID_DOMAINS: + tx = self.builder.setAccountDetail("{}@{}".format(name, domain), "fyodor", "kek").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_set_account_detail_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().setAccountDetail("{}@test".format(name), "fyodor", "true").build() + + def test_set_account_detail_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().setAccountDetail("admin@{}".format(domain), "fyodor", "true").build() + + def test_set_account_detail_empty_account(self): + with self.assertRaises(ValueError): + self.base().setAccountDetail("", "fyodor", "true").build() + + def test_set_account_detail_valid_key(self): + for key in VALID_NAMES_2: + tx = self.builder.setAccountDetail("admin@test", key, "true").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_set_account_detail_invalid_key(self): + for key in INVALID_NAMES_2: + with self.assertRaises(ValueError): + self.base().setAccountDetail("admin@test", key, "true").build() + + def test_set_account_detail_valid_value(self): + length = 4 * 1024 * 1024 + value = "a" * length + + for v in ["", value]: + tx = self.builder.setAccountDetail("admin@test", "fyodor", v).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_set_account_detail_oversized_value(self): + length = 4 * 1024 * 1024 + 1 + value = "a" * length + + with self.assertRaises(ValueError): + self.base().setAccountDetail("admin@test", "fyodor", value).build() + + # ====================== AppendRole Tests ====================== + + def test_append_role(self): + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + tx = self.builder.appendRole("{}@{}".format(name, domain), name).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_append_role_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().appendRole("{}@test".format(name), "user").build() + + def test_append_role_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().appendRole("admin@{}".format(domain), "user").build() + + def test_append_role_empty_account(self): + with self.assertRaises(ValueError): + self.base().appendRole("", "user").build() + + def test_append_role_with_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().appendRole("admin@test", name).build() + + # ====================== CreateAsset Tests ====================== + + def test_create_asset(self): + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + tx = self.builder.createAsset(name, domain, 6).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_create_asset_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().createAsset(name, "test", 6).build() + + def test_create_asset_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().createAsset("asset", domain, 6).build() + + def test_create_asset_zero_precision(self): + tx = self.builder.createAsset("asset", "test", 0).build() self.assertTrue(self.check_proto_tx(self.proto(tx))) + # ====================== CreateRole Tests ====================== + + def test_create_role(self): + permissions = iroha.StringVector() + permissions.append("can_receive") + permissions.append("can_get_roles") + self.assertTrue(permissions.size() == 2) + + for name in VALID_NAMES_1: + tx = self.builder.createRole(name, permissions).build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_create_role_with_invalid_name(self): + permissions = iroha.StringVector() + permissions.append("can_receive") + permissions.append("can_get_roles") + + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().createRole(name, permissions).build() + + def test_create_role_with_empty_permissions(self): + permissions = iroha.StringVector() + self.assertTrue(permissions.size() == 0) + + with self.assertRaises(ValueError): + self.base().createRole("user", permissions).build() + + # TODO igor-egorov, 11.05.2018, IR-1267 + @unittest.skip("Disabled till IR-1267 will be fixed") + def test_create_role_wrong_permissions(self): + permissions = iroha.StringVector() + permissions.append("wrong_permission") + permissions.append("can_receive") + + with self.assertRaises(ValueError): + self.base().createRole("user", permissions).build() + + # TODO igor-egorov, 11.05.2018, IR-1267 + @unittest.skip("Disabled till IR-1267 will be fixed") + def test_create_role_wrong_permissions_2(self): + permissions = iroha.StringVector() + permissions.append("can_receive") + permissions.append("wrong_permission") + + with self.assertRaises(ValueError): + self.base().createRole("user", permissions).build() + + # ====================== DetachRole Tests ====================== + + def test_detach_role(self): + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + tx = self.builder.detachRole("{}@{}".format(name, domain), "role").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_detach_role_with_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().detachRole("{}@test".format(name), "role").build() + + def test_detach_role_with_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().detachRole("admin@{}".format(domain), "role").build() + + def test_detach_role_with_empty_account(self): + with self.assertRaises(ValueError): + self.base().detachRole("", "role").build() + + def test_detach_role_with_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().detachRole("admin@test", name).build() + + # ====================== GrantPermission Tests ====================== + + def test_grant_permission(self): + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + tx = self.builder.grantPermission("{}@{}".format(name, domain), "can_set_my_quorum").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_grant_permission_empty_account(self): + with self.assertRaises(ValueError): + self.base().grantPermission("", "can_set_my_quorum").build() + + def test_grant_permission_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().grantPermission("{}@test".format(name), "can_set_my_quorum").build() + + def test_grant_permission_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().grantPermission("admin@{}".format(domain), "can_set_my_quorum").build() + + def test_grant_permission_with_invalid_name(self): + permissions = [ + "", + "random", + "can_read_assets" # non-grantable permission + ] + + for perm in permissions: + with self.assertRaises(ValueError): + self.base().grantPermission("admin@test", perm).build() + + # ====================== RevokePermission Tests ====================== + + def test_revoke_permission(self): + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + tx = self.builder.revokePermission("{}@{}".format(name, domain), "can_set_my_quorum").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_revoke_permission_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().revokePermission("{}@test".format(name), "can_set_my_quorum").build() + + def test_revoke_permission_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().revokePermission("admin@{}".format(domain), "can_set_my_quorum").build() + + def test_revoke_permission_empty_account(self): + with self.assertRaises(ValueError): + self.base().revokePermission("", "can_set_my_quorum").build() + + def test_revoke_permission_with_invalid_name(self): + permissions = [ + "", + "random", + "can_read_assets" # non-grantable permission + ] + + for perm in permissions: + with self.assertRaises(ValueError): + self.base().revokePermission("admin@test", perm).build() + + # ====================== SubtractAssetQuantity Tests ====================== + + def test_subtract_asset_quantity(self): + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + tx = self.builder.subtractAssetQuantity("{}@{}".format(name, domain), "{}#{}".format(name, domain), "10").build() + self.assertTrue(self.check_proto_tx(self.proto(tx))) + + def test_subtract_asset_quantity_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("{}@test".format(name), "coin#test", "10").build() + + def test_subtract_asset_quantity_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("admin@{}".format(domain), "coin#test", "10").build() + + def test_subtract_asset_quantity_with_empty_account(self): + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("", "coin#test", "10").build() + + def test_subtract_asset_quantity_invalid_asset_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("admin@test", "{}#test".format(name), "10").build() + + def test_subtract_asset_quantity_invalid_asset_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("admin@test", "coin#{}".format(domain), "10").build() + + def test_subtract_asset_quantity_empty_account(self): + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("admin@test", "", "10").build() + + def test_subtract_asset_quantity_invalid_amount(self): + amounts = ["", "0", "chars", "-10", "10chars", "10.10.10"] + for amount in amounts: + with self.assertRaises(ValueError): + self.base().subtractAssetQuantity("admin@test", "coin#test", amount).build() + if __name__ == '__main__': unittest.main() diff --git a/test/module/shared_model/bindings/query-test.py b/test/module/shared_model/bindings/query-test.py index a85854d1f4..42d38faa8e 100644 --- a/test/module/shared_model/bindings/query-test.py +++ b/test/module/shared_model/bindings/query-test.py @@ -1,3 +1,8 @@ +# +# Copyright Soramitsu Co., Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + import iroha import unittest import time @@ -8,34 +13,105 @@ # TODO luckychess 8.08.2018 add test for number of methods # in interface and proto implementation IR-1080 -class BuilderTest(unittest.TestCase): - def test_empty_query(self): - with self.assertRaises(ValueError): - iroha.ModelQueryBuilder().build() +# Symbols of type 1 (format [a-z_0-9]{1,32}) are used +# as account_name, asset_name and role_id. +VALID_NAMES_1 = [ + "a", + "asset", + "234234", + "_", + "_123", + "123_23", + "234asset_", + "__", + "12345678901234567890123456789012" +] - def generate_base(self): - return iroha.ModelQueryBuilder().queryCounter(123)\ - .createdTime(int(time.time() * 1000))\ - .creatorAccountId("admin@test")\ +INVALID_NAMES_1 = [ + "", + "A", + "assetV", + "asSet", + "asset%", + "^123", + "verylongassetname_thenameislonger", + "verylongassetname_thenameislongerthanitshouldbe", + "assset-01" +] + +# Symbols of type 2 (format [A-Za-z0-9_]{1,64}) +# are used as key identifier for setAccountDetail command +VALID_NAMES_2 = [ + "a", + "A", + "1", + "_", + "Key", + "Key0_", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid" +] + +INVALID_NAMES_2 = [ + "", + "Key&", + "key-30", + "verylongAndValidKeyName___1110100010___veryveryveryverylongvalid1", + "@@@" +] + +VALID_DOMAINS = [ + "test", + "u9EEA432F", + "a-hyphen", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad", + "endWith0", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad" +] + +INVALID_DOMAINS = [ + "", + " ", + " ", + "9start.with.digit", + "-startWithDash", + "@.is.not.allowed", + "no space is allowed", + "endWith-", + "label.endedWith-.is.not.allowed", + "aLabelMustNotExceeds63charactersALabelMustNotExceeds63characters", + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." + + "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPadP", + "257.257.257.257", + "domain#domain", + "asd@asd", + "ab..cd" +] + +INVALID_KEYS = [ + "", + "a", + "1" * 31, + "1" * 33 +] + +class BuilderTest(unittest.TestCase): def setUp(self): self.keys = iroha.ModelCrypto().generateKeypair() - self.builder = self.generate_base() + self.builder = self.base() def set_get_account(self): self.builder.getAccount("user@test") - def test_outdated_add_peer(self): - self.set_get_account() - for i in [0, int((time.time() - 100000) * 1000), int((time.time() + 1) * 1000)]: - with self.assertRaises(ValueError): - self.builder.createdTime(i).build() - - def test_add_peer_with_invalid_creator(self): - self.set_get_account() - for s in ["invalid", "@invalid", "invalid"]: - with self.assertRaises(ValueError): - self.builder.creatorAccountId(s).build() + def base(self): + return iroha.ModelQueryBuilder().queryCounter(123)\ + .createdTime(int(time.time() * 1000))\ + .creatorAccountId("admin@test") def proto(self, query): return iroha.ModelProtoQuery().signAndAddSignature(query, self.keys) @@ -46,51 +122,291 @@ def check_proto_query(self, blob): tmp = ''.join(map(chr, blob.blob())) else: tmp = bytes(blob.blob()) - qry.Query.FromString(tmp) + qry.Query.FromString(tmp) except DecodeError as e: print(e) return False return True + def test_empty_query(self): + with self.assertRaises(ValueError): + iroha.ModelQueryBuilder().build() + + # ====================== GetAccount Tests ====================== + def test_get_account(self): - query = self.builder.getAccount("user@test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getAccount("{}@{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_outdated_get_account(self): + self.set_get_account() + for i in [0, int((time.time() - 100000) * 1000), int((time.time() + 1) * 1000)]: + with self.assertRaises(ValueError): + self.builder.createdTime(i).build() + + def test_get_account_with_invalid_creator(self): + self.set_get_account() + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.builder.creatorAccountId("{}@test".format(name)).build() + + def test_get_account_with_invalid_creator_domain(self): + self.set_get_account() + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.builder.creatorAccountId("admin@{}".format(domain)).build() + + def test_get_account_with_empty_creator_domain(self): + self.set_get_account() + with self.assertRaises(ValueError): + self.builder.creatorAccountId("").build() + + def test_get_account_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccount("{}@test".format(name)).build() + + def test_get_account_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccount("admin@{}".format(domain)).build() + + def test_get_account_with_empty_name(self): + with self.assertRaises(ValueError): + self.base().getAccount("").build() + + # ====================== GetSignatories Tests ====================== def test_get_signatories(self): - query = self.builder.getSignatories("user@test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getSignatories("{}@{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_signatories_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getSignatories("{}@test".format(name)).build() + + def test_get_signatories_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getSignatories("admin@{}".format(domain)).build() + + def test_get_signatories_empty_account(self): + with self.assertRaises(ValueError): + self.base().getSignatories("").build() + + # ====================== GetAccountTransactions Tests ====================== def test_get_account_transactions(self): - query = self.builder.getAccountTransactions("user@test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getAccountTransactions("{}@{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_account_transactions_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccountTransactions("{}@test".format(name)).build() + + def test_get_account_transactions_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccountTransactions("admin@{}".format(domain)).build() + + def test_get_account_transactions_with_empty_account(self): + with self.assertRaises(ValueError): + self.base().getAccountTransactions("").build() + + # ====================== GetAccountAssetTransactions Tests ====================== def test_get_account_asset_transactions(self): - query = self.builder.getAccountAssetTransactions("user@test", "coin#test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getAccountAssetTransactions("{}@{}".format(name, domain), "{}#{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_account_asset_transactions_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccountAssetTransactions("{}@test".format(name), "coin#test").build() + + def test_get_account_asset_transactions_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccountAssetTransactions("admin@{}".format(domain), "coin#test").build() + + def test_get_account_asset_transactions_empty_account(self): + with self.assertRaises(ValueError): + self.base().getAccountAssetTransactions("", "coin#test").build() + + def test_get_account_asset_transactions_invalid_asset_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccountAssetTransactions("admin@test", "{}#test".format(name)).build() + + def test_get_account_asset_transactions_invalid_asset_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccountAssetTransactions("admin@test", "admin#{}".format(domain)).build() + + def test_get_account_asset_transactions_empty_asset(self): + with self.assertRaises(ValueError): + self.base().getAccountAssetTransactions("admin@test", "").build() + + # ====================== GetAccountAssets Tests ====================== def test_get_account_assets(self): - query = self.builder.getAccountAssets("user@test", "coin#test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getAccountAssets("{}@{}".format(name, domain), "{}#{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_account_assets_invalid_account(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccountAssets("{}@test".format(name), "coin#test").build() + + def test_get_account_assets_invalid_account_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccountAssets("admin@{}".format(domain), "coin#test").build() + + def test_get_account_assets_empty_account(self): + with self.assertRaises(ValueError): + self.base().getAccountAssets("", "coin#test").build() + + def test_get_account_assets_invalid_asset_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccountAssets("admin@test", "{}#test".format(name)).build() + + def test_get_account_assets_invalid_asset_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccountAssets("admin@test", "admin#{}".format(domain)).build() + + def test_get_account_assets_empty_asset(self): + with self.assertRaises(ValueError): + self.base().getAccountAssets("admin@test", "").build() + + # ====================== GetRoles Tests ====================== def test_get_roles(self): query = self.builder.getRoles().build() self.assertTrue(self.check_proto_query(self.proto(query))) + # ====================== GetAssetInfo Tests ====================== + def test_get_asset_info(self): - query = self.builder.getAssetInfo("coin#test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getAssetInfo("{}#{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_asset_info_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAssetInfo("{}#test".format(name)).build() + + def test_get_asset_info_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAssetInfo("admin#{}".format(domain)).build() + + def test_get_asset_info_empty_asset_name(self): + with self.assertRaises(ValueError): + self.base().getAssetInfo("").build() + + # ====================== GetRolePermissions Tests ====================== def test_get_role_permissions(self): - query = self.builder.getRolePermissions("user").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for name in VALID_NAMES_1: + query = self.builder.getRolePermissions(name).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_role_permissions_with_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getRolePermissions(name).build() + + # ====================== GetTransactions Tests ====================== def test_get_transactions(self): - query = self.builder.getTransactions([iroha.Hash("1" * 32), iroha.Hash("2" * 32)]).build() + hv = iroha.HashVector() + hv.append(iroha.Hash("1" * 32)) + hv.append(iroha.Hash("2" * 32)) + self.assertTrue(hv.size() == 2) + + query = self.builder.getTransactions(hv).build() self.assertTrue(self.check_proto_query(self.proto(query))) + # TODO igor-egorov, 11.05.2018, IR-1322 + @unittest.skip("IR-1322") + def test_get_transactions_with_empty_vector(self): + with self.assertRaises(ValueError): + self.base().getTransactions(iroha.HashVector()).build() + + # TODO igor-egorov, 11.05.2018, IR-1325 + @unittest.skip("IR-1325") + def test_get_transactions_with_invalid_hash_sizes(self): + hashes = [ + "", + "1", + "1" * 31, + "1" * 33 + ] + for h in hashes: + hv = iroha.HashVector() + hv.append(iroha.Hash(h)) + with self.assertRaises(ValueError): + self.base().getTransactions(hv).build() + + # TODO igor-egorov, 11.05.2018, IR-1325 + @unittest.skip("IR-1325") + def test_get_transactions_with_one_valid_and_one_invalid_hash_1(self): + hv = iroha.HashVector() + hv.append(iroha.Hash("1" * 32)) + hv.append(iroha.Hash("1")) + + with self.assertRaises(ValueError): + self.base().getTransactions(hv).build() + + # TODO igor-egorov, 11.05.2018, IR-1325 + @unittest.skip("IR-1325") + def test_get_transactions_with_one_valid_and_one_invalid_hash_2(self): + hv = iroha.HashVector() + hv.append(iroha.Hash("1")) + hv.append(iroha.Hash("1" * 32)) + + with self.assertRaises(ValueError): + self.base().getTransactions(hv).build() + + + # ====================== GetAccountDetail Tests ====================== + def test_get_account_detail(self): - query = self.builder.getAccountDetail("user@test").build() - self.assertTrue(self.check_proto_query(self.proto(query))) + for domain in VALID_DOMAINS: + for name in VALID_NAMES_1: + query = self.builder.getAccountDetail("{}@{}".format(name, domain)).build() + self.assertTrue(self.check_proto_query(self.proto(query))) + + def test_get_account_detail_invalid_name(self): + for name in INVALID_NAMES_1: + with self.assertRaises(ValueError): + self.base().getAccountDetail("{}@test".format(name)).build() + + def test_get_account_detail_invalid_domain(self): + for domain in INVALID_DOMAINS: + with self.assertRaises(ValueError): + self.base().getAccountDetail("admin@{}".format(domain)).build() + + def test_get_account_detail_with_empty_name(self): + with self.assertRaises(ValueError): + self.base().getAccountDetail("").build() if __name__ == '__main__': unittest.main() From d756bafab39e29c91e7087c9f6d5b3df57fa19c2 Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Tue, 15 May 2018 11:30:55 +0300 Subject: [PATCH 099/110] automate docker manifest uploading (#1328) Signed-off-by: Artyom Bakhtin --- .jenkinsci/debug-build.groovy | 22 +++++++++++++- .jenkinsci/docker-manifest.groovy | 28 ++++++++++++++++++ .jenkinsci/docker-pull-or-build.groovy | 10 +++---- .jenkinsci/release-build.groovy | 41 ++++++++++++++++++++++++-- Jenkinsfile | 1 + 5 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 .jenkinsci/docker-manifest.groovy diff --git a/.jenkinsci/debug-build.groovy b/.jenkinsci/debug-build.groovy index 6bf916eaf3..8616097d6b 100644 --- a/.jenkinsci/debug-build.groovy +++ b/.jenkinsci/debug-build.groovy @@ -2,6 +2,7 @@ def doDebugBuild(coverageEnabled=false) { def dPullOrBuild = load ".jenkinsci/docker-pull-or-build.groovy" + def manifest = load ".jenkinsci/docker-manifest.groovy" def pCommit = load ".jenkinsci/previous-commit.groovy" def parallelism = params.PARALLELISM def platform = sh(script: 'uname -m', returnStdout: true).trim() @@ -22,6 +23,25 @@ def doDebugBuild(coverageEnabled=false) { "${env.GIT_RAW_BASE_URL}/${previousCommit}/docker/develop/Dockerfile", "${env.GIT_RAW_BASE_URL}/develop/docker/develop/Dockerfile", ['PARALLELISM': parallelism]) + + if (GIT_LOCAL_BRANCH == 'develop' && manifest.manifestSupportEnabled()) { + manifest.manifestCreate("${DOCKER_REGISTRY_BASENAME}:develop-build", + ["${DOCKER_REGISTRY_BASENAME}:x86_64-develop-build", + "${DOCKER_REGISTRY_BASENAME}:armv7l-develop-build", + "${DOCKER_REGISTRY_BASENAME}:aarch64-develop-build"]) + manifest.manifestAnnotate("${DOCKER_REGISTRY_BASENAME}:develop-build", + [ + [manifest: "${DOCKER_REGISTRY_BASENAME}:x86_64-develop-build", + arch: 'amd64', os: 'linux', osfeatures: [], variant: ''], + [manifest: "${DOCKER_REGISTRY_BASENAME}:armv7l-develop-build", + arch: 'arm', os: 'linux', osfeatures: [], variant: 'v7'], + [manifest: "${DOCKER_REGISTRY_BASENAME}:aarch64-develop-build", + arch: 'arm64', os: 'linux', osfeatures: [], variant: ''] + ]) + withCredentials([usernamePassword(credentialsId: 'docker-hub-credentials', usernameVariable: 'login', passwordVariable: 'password')]) { + manifest.manifestPush("${DOCKER_REGISTRY_BASENAME}:develop-build", login, password) + } + } docker.image('postgres:9.5').withRun("" + " -e POSTGRES_USER=${env.IROHA_POSTGRES_USER}" + " -e POSTGRES_PASSWORD=${env.IROHA_POSTGRES_PASSWORD}" @@ -76,7 +96,7 @@ def doDebugBuild(coverageEnabled=false) { sh """ sonar-scanner \ -Dsonar.github.disableInlineComments \ - -Dsonar.github.repository='hyperledger/iroha' \ + -Dsonar.github.repository='${DOCKER_REGISTRY_BASENAME}' \ -Dsonar.analysis.mode=preview \ -Dsonar.login=${SONAR_TOKEN} \ -Dsonar.projectVersion=${BUILD_TAG} \ diff --git a/.jenkinsci/docker-manifest.groovy b/.jenkinsci/docker-manifest.groovy new file mode 100644 index 0000000000..c7b7c7c73b --- /dev/null +++ b/.jenkinsci/docker-manifest.groovy @@ -0,0 +1,28 @@ +#!/usr/bin/env groovy + +def manifestSupportEnabled() { + def dockerVersion = sh(script: "docker -v", returnStdout: true).trim() + def experimentalEnabled = sh(script: "grep -i experimental ~/.docker/config.json", returnStatus: true) + return experimentalEnabled == 0 && dockerVersion ==~ /^Docker version 18.*$/ + +} + +def manifestCreate(manifestListName, manifests) { + sh "docker manifest create ${manifestListName} ${manifests.join(' ')}" +} + +def manifestAnnotate(manifestListName, manifestsWithFeatures) { + manifestsWithFeatures.each { + sh """ + docker manifest annotate ${manifestListName} ${it['manifest']} --arch "${it['arch']}" \ + --os "${it['os']}" --os-features "${it['osfeatures'].join(',')}" --variant "${it['variant']}" + """ + } +} + +def manifestPush(manifestListName, dockerRegistryLogin, dockerRegistryPassword) { + sh "docker login -u '${dockerRegistryLogin}' -p '${dockerRegistryPassword}'" + sh "docker manifest push --purge ${manifestListName}" +} + +return this diff --git a/.jenkinsci/docker-pull-or-build.groovy b/.jenkinsci/docker-pull-or-build.groovy index 9511aa139a..d699ac40bb 100644 --- a/.jenkinsci/docker-pull-or-build.groovy +++ b/.jenkinsci/docker-pull-or-build.groovy @@ -25,24 +25,24 @@ def dockerPullOrUpdate(imageName, currentDockerfileURL, previousDockerfileURL, r // Worst case scenario. We cannot count on the local cache // because Dockerfile may contain apt-get entries that would try to update // from invalid (stale) addresses - iC = docker.build("hyperledger/iroha:${commit}-${BUILD_NUMBER}", "${buildOptions} --no-cache -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + iC = docker.build("${DOCKER_REGISTRY_BASENAME}:${commit}-${BUILD_NUMBER}", "${buildOptions} --no-cache -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") } else { // first commit in this branch or Dockerfile modified if (remoteFilesDiffer(currentDockerfileURL, referenceDockerfileURL)) { // if we're lucky to build on the same agent, image will be built using cache - iC = docker.build("hyperledger/iroha:${commit}-${BUILD_NUMBER}", "$buildOptions -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + iC = docker.build("${DOCKER_REGISTRY_BASENAME}:${commit}-${BUILD_NUMBER}", "$buildOptions -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") } else { // try pulling image from Dockerhub, probably image is already there - def testExitCode = sh(script: "docker pull hyperledger/iroha:${imageName}", returnStatus: true) + def testExitCode = sh(script: "docker pull ${DOCKER_REGISTRY_BASENAME}:${imageName}", returnStatus: true) if (testExitCode != 0) { // image does not (yet) exist on Dockerhub. Build it - iC = docker.build("hyperledger/iroha:${commit}-${BUILD_NUMBER}", "$buildOptions --no-cache -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") + iC = docker.build("${DOCKER_REGISTRY_BASENAME}:${commit}-${BUILD_NUMBER}", "$buildOptions --no-cache -f /tmp/${env.GIT_COMMIT}/f1 /tmp/${env.GIT_COMMIT}") } else { // no difference found compared to both previous and reference Dockerfile - iC = docker.image("hyperledger/iroha:${imageName}") + iC = docker.image("${DOCKER_REGISTRY_BASENAME}:${imageName}") } } } diff --git a/.jenkinsci/release-build.groovy b/.jenkinsci/release-build.groovy index 4ed14c0854..5e92053772 100644 --- a/.jenkinsci/release-build.groovy +++ b/.jenkinsci/release-build.groovy @@ -2,6 +2,7 @@ def doReleaseBuild() { def parallelism = params.PARALLELISM + def manifest = load ".jenkinsci/docker-manifest.groovy" // params are always null unless job is started // this is the case for the FIRST build only. // So just set this to same value as default. @@ -14,7 +15,7 @@ def doReleaseBuild() { } def platform = sh(script: 'uname -m', returnStdout: true).trim() sh "mkdir /tmp/${env.GIT_COMMIT}-${BUILD_NUMBER} || true" - iC = docker.image("hyperledger/iroha:${platform}-develop-build") + iC = docker.image("${DOCKER_REGISTRY_BASENAME}:${platform}-develop-build") iC.pull() iC.inside("" + " -v /tmp/${GIT_COMMIT}-${BUILD_NUMBER}:/tmp/${GIT_COMMIT}" @@ -54,13 +55,49 @@ def doReleaseBuild() { sh "curl -L -o /tmp/${env.GIT_COMMIT}/entrypoint.sh ${env.GIT_RAW_BASE_URL}/${env.GIT_COMMIT}/docker/release/entrypoint.sh" sh "mv /tmp/${GIT_COMMIT}-${BUILD_NUMBER}/iroha.deb /tmp/${env.GIT_COMMIT}" sh "chmod +x /tmp/${env.GIT_COMMIT}/entrypoint.sh" - iCRelease = docker.build("hyperledger/iroha:${GIT_COMMIT}-${BUILD_NUMBER}-release", "--no-cache -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") + iCRelease = docker.build("${DOCKER_REGISTRY_BASENAME}:${GIT_COMMIT}-${BUILD_NUMBER}-release", "--no-cache -f /tmp/${env.GIT_COMMIT}/Dockerfile /tmp/${env.GIT_COMMIT}") docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') { if (env.GIT_LOCAL_BRANCH == 'develop') { iCRelease.push("${platform}-develop") + if (manifest.manifestSupportEnabled()) { + manifest.manifestCreate("${DOCKER_REGISTRY_BASENAME}:develop", + ["${DOCKER_REGISTRY_BASENAME}:x86_64-develop", + "${DOCKER_REGISTRY_BASENAME}:armv7l-develop", + "${DOCKER_REGISTRY_BASENAME}:aarch64-develop"]) + manifest.manifestAnnotate("${DOCKER_REGISTRY_BASENAME}:develop", + [ + [manifest: "${DOCKER_REGISTRY_BASENAME}:x86_64-develop", + arch: 'amd64', os: 'linux', osfeatures: [], variant: ''], + [manifest: "${DOCKER_REGISTRY_BASENAME}:armv7l-develop", + arch: 'arm', os: 'linux', osfeatures: [], variant: 'v7'], + [manifest: "${DOCKER_REGISTRY_BASENAME}:aarch64-develop", + arch: 'arm64', os: 'linux', osfeatures: [], variant: ''] + ]) + withCredentials([usernamePassword(credentialsId: 'docker-hub-credentials', usernameVariable: 'login', passwordVariable: 'password')]) { + manifest.manifestPush("${DOCKER_REGISTRY_BASENAME}:develop", login, password) + } + } } else if (env.GIT_LOCAL_BRANCH == 'master') { iCRelease.push("${platform}-latest") + if (manifest.manifestSupportEnabled()) { + manifest.manifestCreate("${DOCKER_REGISTRY_BASENAME}:latest", + ["${DOCKER_REGISTRY_BASENAME}:x86_64-latest", + "${DOCKER_REGISTRY_BASENAME}:armv7l-latest", + "${DOCKER_REGISTRY_BASENAME}:aarch64-latest"]) + manifest.manifestAnnotate("${DOCKER_REGISTRY_BASENAME}:latest", + [ + [manifest: "${DOCKER_REGISTRY_BASENAME}:x86_64-latest", + arch: 'amd64', os: 'linux', osfeatures: [], variant: ''], + [manifest: "${DOCKER_REGISTRY_BASENAME}:armv7l-latest", + arch: 'arm', os: 'linux', osfeatures: [], variant: 'v7'], + [manifest: "${DOCKER_REGISTRY_BASENAME}:aarch64-latest", + arch: 'arm64', os: 'linux', osfeatures: [], variant: ''] + ]) + withCredentials([usernamePassword(credentialsId: 'docker-hub-credentials', usernameVariable: 'login', passwordVariable: 'password')]) { + manifest.manifestPush("${DOCKER_REGISTRY_BASENAME}:latest", login, password) + } + } } } sh "docker rmi ${iCRelease.id}" diff --git a/Jenkinsfile b/Jenkinsfile index 4c2e668b19..c4362644e0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,6 +36,7 @@ pipeline { SORABOT_TOKEN = credentials('SORABOT_TOKEN') SONAR_TOKEN = credentials('SONAR_TOKEN') GIT_RAW_BASE_URL = "https://raw.githubusercontent.com/hyperledger/iroha" + DOCKER_REGISTRY_BASENAME = "hyperledger/iroha" IROHA_NETWORK = "iroha-0${CHANGE_ID}-${GIT_COMMIT}-${BUILD_NUMBER}" IROHA_POSTGRES_HOST = "pg-0${CHANGE_ID}-${GIT_COMMIT}-${BUILD_NUMBER}" From a1ed3859cdae34ad4c9a8f274d096e4285ddb2ea Mon Sep 17 00:00:00 2001 From: victordrobny Date: Thu, 17 May 2018 06:05:31 +0300 Subject: [PATCH 100/110] Feature/amount different precision (#1204) * Amount operations with different precisions Signed-off-by: Victor Drobny --- irohad/execution/CMakeLists.txt | 1 + irohad/execution/command_executor.hpp | 2 +- irohad/execution/impl/command_executor.cpp | 78 ++++---- shared_model/CMakeLists.txt | 1 + shared_model/utils/CMakeLists.txt | 4 + shared_model/utils/amount_utils.cpp | 135 ++++++++++++++ shared_model/utils/amount_utils.hpp | 108 +++++------ test/module/shared_model/CMakeLists.txt | 6 + .../module/shared_model/amount_utils_test.cpp | 169 ++++++++++++++++++ 9 files changed, 407 insertions(+), 97 deletions(-) create mode 100644 shared_model/utils/CMakeLists.txt create mode 100644 shared_model/utils/amount_utils.cpp create mode 100644 test/module/shared_model/amount_utils_test.cpp diff --git a/irohad/execution/CMakeLists.txt b/irohad/execution/CMakeLists.txt index 708fac7bc5..c473317a5e 100644 --- a/irohad/execution/CMakeLists.txt +++ b/irohad/execution/CMakeLists.txt @@ -29,6 +29,7 @@ target_link_libraries(command_execution common_execution rxcpp shared_model_default_builders + shared_model_amount_utils ) add_library(query_execution diff --git a/irohad/execution/command_executor.hpp b/irohad/execution/command_executor.hpp index 7e7731967c..c8fbdb69be 100644 --- a/irohad/execution/command_executor.hpp +++ b/irohad/execution/command_executor.hpp @@ -141,7 +141,7 @@ namespace iroha { std::shared_ptr commands; shared_model::interface::types::AccountIdType creator_account_id; - shared_model::builder::DefaultAmountBuilder amount_builder_; + shared_model::builder::AmountBuilderWithoutValidator amount_builder_; shared_model::builder::DefaultAccountAssetBuilder account_asset_builder_; shared_model::builder::DefaultAccountBuilder account_builder_; shared_model::builder::DefaultAssetBuilder asset_builder_; diff --git a/irohad/execution/impl/command_executor.cpp b/irohad/execution/impl/command_executor.cpp index bb790c483a..90475c8f04 100644 --- a/irohad/execution/impl/command_executor.cpp +++ b/irohad/execution/impl/command_executor.cpp @@ -24,6 +24,8 @@ #include "utils/amount_utils.hpp" #include "validators/permissions.hpp" +using namespace shared_model::detail; + namespace iroha { expected::Error makeExecutionError( @@ -62,16 +64,18 @@ namespace iroha { (boost::format("asset %s is absent") % command->assetId()).str(), command_name); } - auto precision = asset.value()->precision(); - if (command->amount().precision() != precision) { + auto precision = asset.value()->precision(); + if (command->amount().precision() > precision) { return makeExecutionError( - (boost::format("precision mismatch: expected %d, but got %d") + (boost::format("command precision is greater than asset precision: " + "expected %d, but got %d") % precision % command->amount().precision()) .str(), command_name); } - + auto command_amount = + makeAmountWithPrecision(command->amount(), asset.value()->precision()); if (not queries->getAccount(command->accountId())) { return makeExecutionError( (boost::format("account %s is absent") % command->accountId()).str(), @@ -80,9 +84,11 @@ namespace iroha { auto account_asset = queries->getAccountAsset(command->accountId(), command->assetId()); - auto new_balance = amount_builder_.precision(command->amount().precision()) - .intValue(command->amount().intValue()) - .build(); + auto new_balance = command_amount | [this](const auto &amount) { + return amount_builder_.precision(amount->precision()) + .intValue(amount->intValue()) + .build(); + }; using AccountAssetResult = expected::Result, iroha::ExecutionError>; @@ -354,14 +360,16 @@ namespace iroha { command_name); } auto precision = asset.value()->precision(); - - if (command->amount().precision() != precision) { + if (command->amount().precision() > precision) { return makeExecutionError( - (boost::format("precision mismatch: expected %d, but got %d") + (boost::format("command precision is greater than asset precision: " + "expected %d, but got %d") % precision % command->amount().precision()) .str(), command_name); } + auto command_amount = + makeAmountWithPrecision(command->amount(), asset.value()->precision()); auto account_asset = queries->getAccountAsset(command->accountId(), command->assetId()); if (not account_asset) { @@ -370,14 +378,16 @@ namespace iroha { .str(), command_name); } - auto account_asset_new = - (account_asset.value()->balance() - command->amount()) | - [this, &account_asset](const auto &new_balance) { - return account_asset_builder_.balance(*new_balance) - .accountId(account_asset.value()->accountId()) - .assetId(account_asset.value()->assetId()) - .build(); - }; + auto account_asset_new = command_amount | + [&account_asset](const auto &amount) { + return account_asset.value()->balance() - *amount; + } + | [this, &account_asset](const auto &new_balance) { + return account_asset_builder_.balance(*new_balance) + .accountId(account_asset.value()->accountId()) + .assetId(account_asset.value()->assetId()) + .build(); + }; return account_asset_new.match( [&](const expected::Value< @@ -417,23 +427,29 @@ namespace iroha { .str(), command_name); } - // Precision for both wallets auto precision = asset.value()->precision(); - if (command->amount().precision() != precision) { + if (command->amount().precision() > precision) { return makeExecutionError( - (boost::format("precision %d is wrong") % precision).str(), + (boost::format("command precision is greater than asset precision: " + "expected %d, but got %d") + % precision % command->amount().precision()) + .str(), command_name); } + auto command_amount = + makeAmountWithPrecision(command->amount(), asset.value()->precision()); // Set new balance for source account - auto src_account_asset_new = - (src_account_asset.value()->balance() - command->amount()) | - [this, &src_account_asset](const auto &new_src_balance) { - return account_asset_builder_ - .assetId(src_account_asset.value()->assetId()) - .accountId(src_account_asset.value()->accountId()) - .balance(*new_src_balance) - .build(); - }; + auto src_account_asset_new = command_amount | + [&src_account_asset](const auto &amount) { + return src_account_asset.value()->balance() - *amount; + } + | [this, &src_account_asset](const auto &new_src_balance) { + return account_asset_builder_ + .assetId(src_account_asset.value()->assetId()) + .accountId(src_account_asset.value()->accountId()) + .balance(*new_src_balance) + .build(); + }; return src_account_asset_new.match( [&](const expected::Value< std::shared_ptr> @@ -861,7 +877,7 @@ namespace iroha { return false; } // Amount is formed wrong - if (command.amount().precision() != asset.value()->precision()) { + if (command.amount().precision() > asset.value()->precision()) { return false; } auto account_asset = diff --git a/shared_model/CMakeLists.txt b/shared_model/CMakeLists.txt index 09a9070edd..bc1ade0296 100644 --- a/shared_model/CMakeLists.txt +++ b/shared_model/CMakeLists.txt @@ -66,6 +66,7 @@ add_subdirectory(builders) add_subdirectory(converters) add_subdirectory(cryptography) add_subdirectory(interfaces) +add_subdirectory(utils) add_subdirectory(validators) if (NOT IROHA_ROOT_PROJECT) diff --git a/shared_model/utils/CMakeLists.txt b/shared_model/utils/CMakeLists.txt new file mode 100644 index 0000000000..9301746fc9 --- /dev/null +++ b/shared_model/utils/CMakeLists.txt @@ -0,0 +1,4 @@ + +add_library(shared_model_amount_utils + amount_utils.cpp + ) diff --git a/shared_model/utils/amount_utils.cpp b/shared_model/utils/amount_utils.cpp new file mode 100644 index 0000000000..44f98d8ea5 --- /dev/null +++ b/shared_model/utils/amount_utils.cpp @@ -0,0 +1,135 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/amount_utils.hpp" +#include + +namespace shared_model { + namespace detail { + const boost::multiprecision::uint256_t ten = 10; + + boost::multiprecision::uint256_t increaseValuePrecision( + boost::multiprecision::uint256_t value, int degree) { + return value * pow(ten, degree); + } + + /** + * Sums up two amounts. + * Result is returned + * @param a left term + * @param b right term + */ + iroha::expected::PolymorphicResult + operator+(const shared_model::interface::Amount &a, + const shared_model::interface::Amount &b) { + auto max_precision = std::max(a.precision(), b.precision()); + auto val_a = + increaseValuePrecision(a.intValue(), max_precision - a.precision()); + auto val_b = + increaseValuePrecision(b.intValue(), max_precision - b.precision()); + if (val_a < a.intValue() || val_b < b.intValue() || val_a + val_b < val_a + || val_a + val_b < val_b) { + return iroha::expected::makeError(std::make_shared( + (boost::format("addition overflows (%s + %s)") % a.intValue().str() + % b.intValue().str()) + .str())); + } + return shared_model::builder::AmountBuilderWithoutValidator() + .precision(max_precision) + .intValue(val_a + val_b) + .build(); + } + + /** + * Subtracts two amounts. + * Result is returned + * @param a left term + * @param b right term + */ + iroha::expected::PolymorphicResult + operator-(const shared_model::interface::Amount &a, + const shared_model::interface::Amount &b) { + // check if a greater than b + if (a.intValue() < b.intValue()) { + return iroha::expected::makeError(std::make_shared( + (boost::format("minuend is smaller than subtrahend (%s - %s)") + % a.intValue().str() % b.intValue().str()) + .str())); + } + auto max_precision = std::max(a.precision(), b.precision()); + auto val_a = + increaseValuePrecision(a.intValue(), max_precision - a.precision()); + auto val_b = + increaseValuePrecision(b.intValue(), max_precision - b.precision()); + if (val_a < a.intValue() || val_b < b.intValue()) { + return iroha::expected::makeError( + std::make_shared("new precision overflows number")); + } + return shared_model::builder::AmountBuilderWithoutValidator() + .precision(max_precision) + .intValue(val_a - val_b) + .build(); + } + + /** + * Make amount with bigger precision + * Result is returned + * @param a amount + * @param b right term + */ + iroha::expected::PolymorphicResult + makeAmountWithPrecision(const shared_model::interface::Amount &amount, + const int new_precision) { + if (amount.precision() > new_precision) { + return iroha::expected::makeError(std::make_shared( + (boost::format("new precision is smaller than current (%d < %d)") + % new_precision % amount.precision()) + .str())); + } + auto val_amount = increaseValuePrecision( + amount.intValue(), new_precision - amount.precision()); + if (val_amount < amount.intValue()) { + return iroha::expected::makeError( + std::make_shared("operation overflows number")); + } + return shared_model::builder::AmountBuilderWithoutValidator() + .precision(new_precision) + .intValue(val_amount) + .build(); + } + + int compareAmount(const shared_model::interface::Amount &a, + const shared_model::interface::Amount &b) { + if (a.precision() == b.precision()) { + return (a.intValue() < b.intValue()) + ? -1 + : (a.intValue() > b.intValue()) ? 1 : 0; + } + // when different precisions transform to have the same scale + auto max_precision = std::max(a.precision(), b.precision()); + + auto val1 = + increaseValuePrecision(a.intValue(), max_precision - a.precision()); + auto val2 = + increaseValuePrecision(b.intValue(), max_precision - b.precision()); + return (val1 < val2) ? -1 : (val1 > val2) ? 1 : 0; + } + } // namespace detail +} // namespace shared_model diff --git a/shared_model/utils/amount_utils.hpp b/shared_model/utils/amount_utils.hpp index d967d0cc9c..781ae98a86 100644 --- a/shared_model/utils/amount_utils.hpp +++ b/shared_model/utils/amount_utils.hpp @@ -18,74 +18,52 @@ #ifndef IROHA_AMOUNT_UTILS_HPP #define IROHA_AMOUNT_UTILS_HPP +#include + +#include "builders/default_builders.hpp" #include "builders/protobuf/common_objects/proto_amount_builder.hpp" +#include "common/result.hpp" -/** - * Sums up two amounts. - * Requires to have the same scale. - * Otherwise nullopt is returned - * @param a left term - * @param b right term - */ -iroha::expected::Result, - std::shared_ptr> -operator+(const shared_model::interface::Amount &a, - const shared_model::interface::Amount &b) { - // check precisions - if (a.precision() != b.precision()) { - return iroha::expected::makeError( - std::make_shared("precision mismatch")); - } - if (a.intValue() + b.intValue() < a.intValue() - || a.intValue() + b.intValue() < b.intValue()) { - return iroha::expected::makeError( - std::make_shared("addition overflows")); - } - return shared_model::builder::AmountBuilderWithoutValidator() - .precision(a.precision()) - .intValue(a.intValue() + b.intValue()) - .build(); -} +namespace shared_model { + namespace detail { + boost::multiprecision::uint256_t increaseValuePrecision( + boost::multiprecision::uint256_t value, int degree); -/** - * Subtracts two amounts. - * Requires to have the same scale. - * Otherwise nullopt is returned - * @param a left term - * @param b right term - */ -iroha::expected::Result, - std::shared_ptr> -operator-(const shared_model::interface::Amount &a, - const shared_model::interface::Amount &b) { - // check precisions - if (a.precision() != b.precision()) { - return iroha::expected::makeError( - std::make_shared("precision mismatch")); - } - // check if a greater than b - if (a.intValue() < b.intValue()) { - return iroha::expected::makeError( - std::make_shared("minuend is smaller than subtrahend")); - } - return shared_model::builder::AmountBuilderWithoutValidator() - .precision(a.precision()) - .intValue(a.intValue() - b.intValue()) - .build(); -} + /** + * Sums up two amounts. + * Result is returned + * @param a left term + * @param b right term + */ + iroha::expected::PolymorphicResult + operator+(const shared_model::interface::Amount &a, + const shared_model::interface::Amount &b); + + /** + * Subtracts two amounts. + * Result is returned + * @param a left term + * @param b right term + */ + iroha::expected::PolymorphicResult + operator-(const shared_model::interface::Amount &a, + const shared_model::interface::Amount &b); -int compareAmount(const shared_model::interface::Amount &a, - const shared_model::interface::Amount &b) { - if (a.precision() == b.precision()) { - return (a.intValue() < b.intValue()) - ? -1 - : (a.intValue() > b.intValue()) ? 1 : 0; - } - // when different precisions transform to have the same scale - auto max_precision = std::max(a.precision(), b.precision()); - auto val1 = a.intValue() * (int)std::pow(10, max_precision - a.precision()); - auto val2 = b.intValue() * (int)std::pow(10, max_precision - b.precision()); - return (val1 < val2) ? -1 : (val1 > val2) ? 1 : 0; -} + /** + * Make amount with bigger precision + * Result is returned + * @param a amount + * @param b right term + */ + iroha::expected::PolymorphicResult + makeAmountWithPrecision(const shared_model::interface::Amount &amount, + const int new_precision); + int compareAmount(const shared_model::interface::Amount &a, + const shared_model::interface::Amount &b); + } // namespace detail +} // namespace shared_model #endif // IROHA_AMOUNT_UTILS_HPP diff --git a/test/module/shared_model/CMakeLists.txt b/test/module/shared_model/CMakeLists.txt index c3221c213d..aac86f3bde 100644 --- a/test/module/shared_model/CMakeLists.txt +++ b/test/module/shared_model/CMakeLists.txt @@ -35,3 +35,9 @@ AddTest(reference_holder_test target_link_libraries(reference_holder_test boost ) + +AddTest(amount_utils_test amount_utils_test.cpp) +target_link_libraries(amount_utils_test + shared_model_default_builders + shared_model_amount_utils + ) diff --git a/test/module/shared_model/amount_utils_test.cpp b/test/module/shared_model/amount_utils_test.cpp new file mode 100644 index 0000000000..1d070bb530 --- /dev/null +++ b/test/module/shared_model/amount_utils_test.cpp @@ -0,0 +1,169 @@ +/** + * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. + * http://soramitsu.co.jp + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "utils/amount_utils.hpp" + +using namespace shared_model::detail; + +class AmountTest : public testing::Test {}; + +/** + * @given two amounts + * @when tries to sum it up + * @then correct amount is given + */ +TEST_F(AmountTest, PlusTest) { + iroha::expected::Result, + std::shared_ptr> + a = shared_model::builder::DefaultAmountBuilder::fromString("1234.567"); + + iroha::expected::Result, + std::shared_ptr> + b = shared_model::builder::DefaultAmountBuilder::fromString("100"); + + a.match( + [&b](const iroha::expected::Value< + std::shared_ptr> &a_value) { + b.match( + [&a_value](const iroha::expected::Value> &b_value) { + auto c = *a_value.value + *b_value.value; + c.match( + [](const auto &c_value) { + ASSERT_EQ(c_value.value->intValue(), 1334567); + ASSERT_EQ(c_value.value->precision(), 3); + }, + [](const iroha::expected::Error> + &e) { FAIL() << *e.error; }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); +} + +/** + * @given two amounts + * @when tries to subtract it up + * @then correct amount is given + */ +TEST_F(AmountTest, MinusTest) { + iroha::expected::Result, + std::shared_ptr> + a = shared_model::builder::DefaultAmountBuilder::fromString("1234.567"); + + iroha::expected::Result, + std::shared_ptr> + b = shared_model::builder::DefaultAmountBuilder::fromString("100"); + + a.match( + [&b](const iroha::expected::Value< + std::shared_ptr> &a_value) { + b.match( + [&a_value](const iroha::expected::Value> &b_value) { + auto c = *a_value.value - *b_value.value; + c.match( + [](const auto &c_value) { + ASSERT_EQ(c_value.value->intValue(), 1134567); + ASSERT_EQ(c_value.value->precision(), 3); + }, + [](const iroha::expected::Error> + &e) { FAIL() << *e.error; }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); +} + +/** + * @given an amount + * @when tries change its precision + * @then correct amount is given + */ +TEST_F(AmountTest, PrecisionTest) { + iroha::expected::Result, + std::shared_ptr> + a = shared_model::builder::DefaultAmountBuilder::fromString("1234.567"); + + a.match( + [](const iroha::expected::Value< + std::shared_ptr> &a_value) { + auto c = makeAmountWithPrecision(*a_value.value, 4); + c.match( + [](const iroha::expected::Value< + std::shared_ptr> &c_value) { + ASSERT_EQ(c_value.value->intValue(), 12345670); + ASSERT_EQ(c_value.value->precision(), 4); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); +} + +/** + * @given two amounts which sum overflows amount type + * @when tries to sum it up + * @then an error occurs + */ +TEST_F(AmountTest, PlusOverflowsTest) { + const std::string &uint256_halfmax = + "723700557733226221397318656304299424082937404160253525246609900049457060" + "2495.0"; // 2**252 - 1 + iroha::expected::Result, + std::shared_ptr> + a = shared_model::builder::DefaultAmountBuilder::fromString(uint256_halfmax); + + iroha::expected::Result, + std::shared_ptr> + b = shared_model::builder::DefaultAmountBuilder::fromString("100.00"); + + a.match( + [&b](const iroha::expected::Value< + std::shared_ptr> &a_value) { + b.match( + [&a_value](const iroha::expected::Value> &b_value) { + auto c = *a_value.value + *b_value.value; + c.match( + [](const auto &c_value) { + FAIL() << "Operation successful but shouldn't"; + }, + [](const iroha::expected::Error> + &e) { SUCCEED() << *e.error; }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); + }, + [](const iroha::expected::Error> &e) { + FAIL() << *e.error; + }); +} From 0d932224887e100f0dd0cf102f11bc360a85b645 Mon Sep 17 00:00:00 2001 From: Andrei Lebedev Date: Thu, 17 May 2018 10:51:01 +0300 Subject: [PATCH 101/110] Reduce integration test execution time (#1338) * Remove default proposal size, disable timers in IrohaInstance * Add logging if tx with hash not found * Reduce code duplication, add acceptance fixture * Add docs to acceptance fixture, edit create role tests * Remove string literals Signed-off-by: Andrei Lebedev --- .../ametsuchi/impl/postgres_block_query.cpp | 1 + test/framework/base_tx.hpp | 65 ------- .../integration_test_framework.hpp | 6 +- .../integration_framework/iroha_instance.cpp | 10 +- test/integration/acceptance/CMakeLists.txt | 86 ++++----- .../acceptance/acceptance_fixture.cpp | 109 ++++++++++++ .../acceptance/acceptance_fixture.hpp | 115 ++++++++++++ .../acceptance/add_asset_qty_test.cpp | 133 +++++--------- .../acceptance/create_account_test.cpp | 118 ++++--------- .../acceptance/create_domain_test.cpp | 124 ++++--------- .../acceptance/create_role_test.cpp | 130 +++++--------- .../acceptance/get_transactions_test.cpp | 83 +++------ .../acceptance/invalid_fields_test.cpp | 67 ++----- .../acceptance/subtract_asset_qty_test.cpp | 127 +++++--------- .../acceptance/transfer_asset_test.cpp | 166 ++++++++---------- .../acceptance/tx_acceptance_test.cpp | 118 +++++-------- test/integration/acceptance/tx_heavy_data.cpp | 98 ++--------- test/integration/pipeline/pipeline_test.cpp | 4 +- .../shared_model/validators/validators.hpp | 3 - test/regression/regression_test.cpp | 11 +- 20 files changed, 643 insertions(+), 931 deletions(-) delete mode 100644 test/framework/base_tx.hpp create mode 100644 test/integration/acceptance/acceptance_fixture.cpp create mode 100644 test/integration/acceptance/acceptance_fixture.hpp diff --git a/irohad/ametsuchi/impl/postgres_block_query.cpp b/irohad/ametsuchi/impl/postgres_block_query.cpp index b6434788c5..ac2529d02c 100644 --- a/irohad/ametsuchi/impl/postgres_block_query.cpp +++ b/irohad/ametsuchi/impl/postgres_block_query.cpp @@ -101,6 +101,7 @@ namespace iroha { -> boost::optional< shared_model::interface::types::HeightType> { if (result.size() == 0) { + log_->info("No block with transaction {}", hash.toString()); return boost::none; } return result[0] diff --git a/test/framework/base_tx.hpp b/test/framework/base_tx.hpp deleted file mode 100644 index 3ee5f59979..0000000000 --- a/test/framework/base_tx.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "backend/protobuf/transaction.hpp" -#include "builders/protobuf/transaction.hpp" -#include "cryptography/public_key.hpp" -#include "datetime/time.hpp" -#include "framework/integration_framework/integration_test_framework.hpp" - -namespace framework { - /** - * Creates a set of transactions for user creation - * @param user is username of new user - * @param key is a public key of new user - * @return pre-built transaction - */ - static inline auto createUser(const std::string &user, - const shared_model::crypto::PublicKey &key) { - return shared_model::proto::TransactionBuilder() - .createAccount( - user, - integration_framework::IntegrationTestFramework::kDefaultDomain, - key) - .creatorAccountId( - integration_framework::IntegrationTestFramework::kAdminId) - .createdTime(iroha::time::now()); - } - - /** - * Creates a set of transactions for user creation with specified permissions - * @param user is username of new user - * @param key is a public key of new user - * @param role_id is new role of the user - * @param perms is a collections of permissions of the user - * @return pre-build transaction - */ - static inline auto createUserWithPerms( - const std::string &user, - const shared_model::crypto::PublicKey &key, - const std::string role_id, - std::vector perms) { - const auto user_id = user + "@" - + integration_framework::IntegrationTestFramework::kDefaultDomain; - return createUser(user, key) - .detachRole( - user_id, - integration_framework::IntegrationTestFramework::kDefaultRole) - .createRole(role_id, perms) - .appendRole(user_id, role_id); - } -} // namespace framework diff --git a/test/framework/integration_framework/integration_test_framework.hpp b/test/framework/integration_framework/integration_test_framework.hpp index 1d5d0a4181..3d6b96dba5 100644 --- a/test/framework/integration_framework/integration_test_framework.hpp +++ b/test/framework/integration_framework/integration_test_framework.hpp @@ -57,14 +57,14 @@ namespace integration_framework { public: /** * Construct test framework instance - * @param maximum_proposal_size - (default = 10) Maximum amount of - * transactions per proposal + * @param maximum_proposal_size - Maximum number of transactions per + * proposal * @param destructor_lambda - (default nullptr) Pointer to function which * receives pointer to constructed instance of Integration Test Framework. * If specified, then will be called instead of default destructor's code */ explicit IntegrationTestFramework( - size_t maximum_proposal_size = 10, + size_t maximum_proposal_size, std::function deleter = [](IntegrationTestFramework &itf) { itf.done(); }); diff --git a/test/framework/integration_framework/iroha_instance.cpp b/test/framework/integration_framework/iroha_instance.cpp index d178ddb2a3..e8ab64f815 100644 --- a/test/framework/integration_framework/iroha_instance.cpp +++ b/test/framework/integration_framework/iroha_instance.cpp @@ -33,9 +33,13 @@ namespace integration_framework { pg_conn_(getPostgreCredsOrDefault()), torii_port_(11501), internal_port_(50541), - proposal_delay_(5000ms), - vote_delay_(5000ms), - load_delay_(5000ms) {} + // proposal_timeout results in non-deterministic behavior due + // to thread scheduling and network + proposal_delay_(1h), + // not required due to solo consensus + vote_delay_(0ms), + // same as above + load_delay_(0ms) {} void IrohaInstance::makeGenesis(const shared_model::interface::Block &block) { instance_->storage->dropStorage(); diff --git a/test/integration/acceptance/CMakeLists.txt b/test/integration/acceptance/CMakeLists.txt index 03e1cef83c..7a1b183a2e 100644 --- a/test/integration/acceptance/CMakeLists.txt +++ b/test/integration/acceptance/CMakeLists.txt @@ -14,83 +14,59 @@ # See the License for the specific language governing permissions and # limitations under the License. # - -addtest(tx_acceptance_test tx_acceptance_test.cpp) -target_link_libraries(tx_acceptance_test - application - raw_block_loader - integration_framework - shared_model_stateless_validation - ) - -addtest(get_transactions_test get_transactions_test.cpp) -target_link_libraries(get_transactions_test - application +add_library(acceptance_fixture acceptance_fixture.cpp) +target_link_libraries(acceptance_fixture + gtest integration_framework shared_model_proto_builders - shared_model_stateless_validation ) addtest(add_asset_qty_test add_asset_qty_test.cpp) target_link_libraries(add_asset_qty_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation + acceptance_fixture ) -addtest(create_role_test create_role_test.cpp) -target_link_libraries(create_role_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation +addtest(create_account_test create_account_test.cpp) +target_link_libraries(create_account_test + acceptance_fixture ) -addtest(invalid_fields_test invalid_fields_test.cpp) -target_link_libraries(invalid_fields_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation +addtest(create_domain_test create_domain_test.cpp) +target_link_libraries(create_domain_test + acceptance_fixture ) -addtest(transfer_asset_test transfer_asset_test.cpp) -target_link_libraries(transfer_asset_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation +addtest(create_role_test create_role_test.cpp) +target_link_libraries(create_role_test + acceptance_fixture ) -addtest(create_domain_test create_domain_test.cpp) -target_link_libraries(create_domain_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation +addtest(get_transactions_test get_transactions_test.cpp) +target_link_libraries(get_transactions_test + acceptance_fixture + ) + +addtest(invalid_fields_test invalid_fields_test.cpp) +target_link_libraries(invalid_fields_test + acceptance_fixture ) addtest(subtract_asset_qty_test subtract_asset_qty_test.cpp) target_link_libraries(subtract_asset_qty_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation + acceptance_fixture ) -addtest(create_account_test create_account_test.cpp) -target_link_libraries(create_account_test - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation +addtest(transfer_asset_test transfer_asset_test.cpp) +target_link_libraries(transfer_asset_test + acceptance_fixture + ) + +addtest(tx_acceptance_test tx_acceptance_test.cpp) +target_link_libraries(tx_acceptance_test + acceptance_fixture ) addtest(tx_heavy_data tx_heavy_data.cpp) target_link_libraries(tx_heavy_data - application - integration_framework - shared_model_proto_builders - shared_model_stateless_validation + acceptance_fixture ) diff --git a/test/integration/acceptance/acceptance_fixture.cpp b/test/integration/acceptance/acceptance_fixture.cpp new file mode 100644 index 0000000000..b414fc978c --- /dev/null +++ b/test/integration/acceptance/acceptance_fixture.cpp @@ -0,0 +1,109 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "integration/acceptance/acceptance_fixture.hpp" + +#include "datetime/time.hpp" +#include "framework/integration_framework/integration_test_framework.hpp" +#include "interfaces/utils/specified_visitor.hpp" + +AcceptanceFixture::AcceptanceFixture() + : kUser("user"), + kRole("role"), + kDomain(integration_framework::IntegrationTestFramework::kDefaultDomain), + kAsset(integration_framework::IntegrationTestFramework::kAssetName + "#" + + integration_framework::IntegrationTestFramework::kDefaultDomain), + kUserId( + kUser + "@" + + integration_framework::IntegrationTestFramework::kDefaultDomain), + kAdminKeypair( + shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()), + kUserKeypair( + shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()), + checkStatelessInvalid([](auto &status) { + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::SpecifiedVisitor< + shared_model::interface::StatelessFailedTxResponse>(), + status.get())); + }) {} + +TestUnsignedTransactionBuilder AcceptanceFixture::createUser( + const std::string &user, const shared_model::crypto::PublicKey &key) { + return TestUnsignedTransactionBuilder() + .createAccount( + user, + integration_framework::IntegrationTestFramework::kDefaultDomain, + key) + .creatorAccountId( + integration_framework::IntegrationTestFramework::kAdminId) + .createdTime(iroha::time::now()); +} + +TestUnsignedTransactionBuilder AcceptanceFixture::createUserWithPerms( + const std::string &user, + const shared_model::crypto::PublicKey &key, + const std::string &role_id, + std::vector perms) { + const auto user_id = user + "@" + + integration_framework::IntegrationTestFramework::kDefaultDomain; + return createUser(user, key) + .detachRole(user_id, + integration_framework::IntegrationTestFramework::kDefaultRole) + .createRole(role_id, perms) + .appendRole(user_id, role_id); +} + +shared_model::proto::Transaction AcceptanceFixture::makeUserWithPerms( + const std::string &role_name, const std::vector &perms) { + return createUserWithPerms(kUser, kUserKeypair.publicKey(), role_name, perms) + .build() + .signAndAddSignature(kAdminKeypair); +} + +shared_model::proto::Transaction AcceptanceFixture::makeUserWithPerms( + const std::vector &perms) { + return makeUserWithPerms(kRole, perms); +} + +template +auto AcceptanceFixture::base(Builder builder) -> decltype( + builder.creatorAccountId(std::string()).createdTime(uint64_t())) { + return builder.creatorAccountId(kUserId).createdTime(iroha::time::now()); +} + +template auto AcceptanceFixture::base( + TestUnsignedTransactionBuilder builder) + -> decltype( + builder.creatorAccountId(std::string()).createdTime(uint64_t())); +template auto AcceptanceFixture::base( + TestUnsignedQueryBuilder builder) + -> decltype( + builder.creatorAccountId(std::string()).createdTime(uint64_t())); + +auto AcceptanceFixture::baseTx() + -> decltype(base(TestUnsignedTransactionBuilder())) { + return base(TestUnsignedTransactionBuilder()); +} + +auto AcceptanceFixture::baseQry() + -> decltype(base(TestUnsignedQueryBuilder())) { + return base(TestUnsignedQueryBuilder()); +} + +template +auto AcceptanceFixture::complete(Builder builder) + -> decltype(builder.build().signAndAddSignature( + std::declval())) { + return builder.build().signAndAddSignature(kUserKeypair); +} + +template auto AcceptanceFixture::complete( + TestUnsignedTransactionBuilder builder) + -> decltype(builder.build().signAndAddSignature( + std::declval())); +template auto AcceptanceFixture::complete( + TestUnsignedQueryBuilder builder) + -> decltype(builder.build().signAndAddSignature( + std::declval())); diff --git a/test/integration/acceptance/acceptance_fixture.hpp b/test/integration/acceptance/acceptance_fixture.hpp new file mode 100644 index 0000000000..0f5ad76d68 --- /dev/null +++ b/test/integration/acceptance/acceptance_fixture.hpp @@ -0,0 +1,115 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef IROHA_ACCEPTANCE_FIXTURE_HPP +#define IROHA_ACCEPTANCE_FIXTURE_HPP + +#include +#include +#include +#include +#include "cryptography/keypair.hpp" +#include "module/shared_model/builders/protobuf/test_query_builder.hpp" +#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" + +namespace shared_model { + namespace proto { + class TransactionResponse; + } // namespace proto +} // namespace shared_model + +/** + * Common values (user, domain, asset) + * and methods (create user, base transaction) for acceptance tests + */ +class AcceptanceFixture : public ::testing::Test { + public: + AcceptanceFixture(); + + /** + * Creates a set of transactions for user creation + * @param user is username of new user + * @param key is a public key of new user + * @return pre-built transaction + */ + TestUnsignedTransactionBuilder createUser( + const std::string &user, const shared_model::crypto::PublicKey &key); + + /** + * Creates a set of transactions for user creation with specified permissions + * @param user is username of new user + * @param key is a public key of new user + * @param role_id is new role of the user + * @param perms is a collections of permissions of the user + * @return pre-build transaction + */ + TestUnsignedTransactionBuilder createUserWithPerms( + const std::string &user, + const shared_model::crypto::PublicKey &key, + const std::string &role_id, + std::vector perms); + + /** + * Creates the transaction with the user creation commands + * @param role_name is a name of the role + * @param perms are the permissions of the user + * @return built tx and a hash of its payload + */ + shared_model::proto::Transaction makeUserWithPerms( + const std::string &role_name, const std::vector &perms); + + /** + * Creates the transaction with the user creation commands + * @param perms are the permissions of the user + * @return built tx and a hash of its payload + */ + shared_model::proto::Transaction makeUserWithPerms( + const std::vector &perms); + + /** + * Add default user creator account id and current created time to builder + * @tparam Builder type (transaction, query) + * @param builder object to modify + * @return builder containing creator account id and created time + */ + template + auto base(Builder builder) -> decltype( + builder.creatorAccountId(std::string()).createdTime(uint64_t())); + + /** + * Create valid base pre-built transaction + * @return pre-built tx + */ + auto baseTx() -> decltype(base(TestUnsignedTransactionBuilder())); + + /** + * Create valid base pre-built query + * @return pre-built query + */ + auto baseQry() -> decltype(base(TestUnsignedQueryBuilder())); + + /** + * Completes pre-built object + * @param builder is a pre-built object + * @return built object + */ + template + auto complete(Builder builder) + -> decltype(builder.build().signAndAddSignature( + std::declval())); + + const std::string kUser; + const std::string kRole; + const std::string kDomain; + const std::string kAsset; + const std::string kUserId; + const shared_model::crypto::Keypair kAdminKeypair; + const shared_model::crypto::Keypair kUserKeypair; + + const std::function + checkStatelessInvalid; +}; + +#endif // IROHA_ACCEPTANCE_FIXTURE_HPP diff --git a/test/integration/acceptance/add_asset_qty_test.cpp b/test/integration/acceptance/add_asset_qty_test.cpp index c6c14ecf8f..53559ac3ac 100644 --- a/test/integration/acceptance/add_asset_qty_test.cpp +++ b/test/integration/acceptance/add_asset_qty_test.cpp @@ -1,76 +1,24 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include -#include "backend/protobuf/transaction.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class AddAssetQuantity : public ::testing::Test { +class AddAssetQuantity : public AcceptanceFixture { public: - /** - * Creates the transaction with the user creation commands - * @param perms are the permissions of the user - * @return built tx and a hash of its payload - */ auto makeUserWithPerms(const std::vector &perms = { shared_model::permissions::can_add_asset_qty}) { - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), "role"s, perms) - .build() - .signAndAddSignature(kAdminKeypair); + return AcceptanceFixture::makeUserWithPerms(perms); } - /** - * Create valid base pre-built transaction - * @return pre-built tx - */ - auto baseTx() { - return TestUnsignedTransactionBuilder() - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); - } - - /** - * Completes pre-built transaction - * @param builder is a pre-built tx - * @return built tx - */ - template - auto completeTx(TestTransactionBuilder builder) { - return builder.build().signAndAddSignature(kUserKeypair); - } - - const std::string kUser = "user"s; - const std::string kAsset = IntegrationTestFramework::kAssetName + "#test"; - const std::string kUserId = kUser + "@test"; const std::string kAmount = "1.0"; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); }; /** @@ -79,12 +27,12 @@ class AddAssetQuantity : public ::testing::Test { * @then there is the tx in proposal */ TEST_F(AddAssetQuantity, Basic) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().addAssetQuantity(kUserId, kAsset, kAmount))) + .sendTx(complete(baseTx().addAssetQuantity(kUserId, kAsset, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) @@ -97,12 +45,12 @@ TEST_F(AddAssetQuantity, Basic) { * @then there is no tx in proposal */ TEST_F(AddAssetQuantity, NoPermissions) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().addAssetQuantity(kUserId, kAsset, kAmount))) + .sendTx(complete(baseTx().addAssetQuantity(kUserId, kAsset, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -116,13 +64,13 @@ TEST_F(AddAssetQuantity, NoPermissions) { * (aka skipProposal throws) */ TEST_F(AddAssetQuantity, NegativeAmount) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().addAssetQuantity(kUserId, kAsset, "-1.0"))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().addAssetQuantity(kUserId, kAsset, "-1.0")), + checkStatelessInvalid); } /** @@ -132,13 +80,13 @@ TEST_F(AddAssetQuantity, NegativeAmount) { * (aka skipProposal throws) */ TEST_F(AddAssetQuantity, ZeroAmount) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().addAssetQuantity(kUserId, kAsset, "0.0"))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().addAssetQuantity(kUserId, kAsset, "0.0")), + checkStatelessInvalid); } /** @@ -149,23 +97,23 @@ TEST_F(AddAssetQuantity, ZeroAmount) { * second */ TEST_F(AddAssetQuantity, Uint256DestOverflow) { - const std::string &uint256_halfmax = + std::string uint256_halfmax = "723700557733226221397318656304299424082937404160253525246609900049457060" "2495.0"; // 2**252 - 1 - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() // Add first half of the maximum - .sendTx(completeTx( - baseTx().addAssetQuantity(kUserId, kAsset, uint256_halfmax))) + .sendTx( + complete(baseTx().addAssetQuantity(kUserId, kAsset, uint256_halfmax))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) // Add second half of the maximum - .sendTx(completeTx( - baseTx().addAssetQuantity(kUserId, kAsset, uint256_halfmax))) + .sendTx( + complete(baseTx().addAssetQuantity(kUserId, kAsset, uint256_halfmax))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -174,18 +122,17 @@ TEST_F(AddAssetQuantity, Uint256DestOverflow) { /** * @given some user with all required permissions - * @when execute tx with AddAssetQuantity command with inexistent account + * @when execute tx with AddAssetQuantity command with nonexistent account * @then there is an empty proposal */ -TEST_F(AddAssetQuantity, InexistentAccount) { - const std::string &inexistent = "inexist@test"s; - IntegrationTestFramework() +TEST_F(AddAssetQuantity, NonexistentAccount) { + std::string nonexistent = "inexist@test"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx( - completeTx(baseTx().addAssetQuantity(inexistent, kAsset, kAmount))) + .sendTx(complete(baseTx().addAssetQuantity(nonexistent, kAsset, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -194,18 +141,18 @@ TEST_F(AddAssetQuantity, InexistentAccount) { /** * @given some user with all required permissions - * @when execute tx with AddAssetQuantity command with inexistent asset + * @when execute tx with AddAssetQuantity command with nonexistent asset * @then there is an empty proposal */ -TEST_F(AddAssetQuantity, InexistentAsset) { - const std::string &inexistent = "inexist#test"s; - IntegrationTestFramework() +TEST_F(AddAssetQuantity, NonexistentAsset) { + std::string nonexistent = "inexist#test"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() .sendTx( - completeTx(baseTx().addAssetQuantity(kUserId, inexistent, kAmount))) + complete(baseTx().addAssetQuantity(kUserId, nonexistent, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -218,12 +165,12 @@ TEST_F(AddAssetQuantity, InexistentAsset) { * @then there is no tx in proposal */ TEST_F(AddAssetQuantity, OtherUser) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().addAssetQuantity( + .sendTx(complete(baseTx().addAssetQuantity( IntegrationTestFramework::kAdminId, kAsset, kAmount))) .skipProposal() .checkBlock( @@ -241,12 +188,12 @@ TEST_F(AddAssetQuantity, OtherDomain) { const auto kNewRole = "newrl"; const auto kNewDomain = "newdom"; const auto kNewUser = "newusr"; - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(2) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) // Generate new domain, new user and an asset .sendTx( - shared_model::proto::TransactionBuilder() + TestUnsignedTransactionBuilder() .creatorAccountId( integration_framework::IntegrationTestFramework::kAdminId) .createdTime(iroha::time::now()) @@ -266,6 +213,6 @@ TEST_F(AddAssetQuantity, OtherDomain) { // Make sure everything is committed .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) - .sendTx(completeTx(baseTx().addAssetQuantity(kNewUser, kAsset, kAmount))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().addAssetQuantity(kNewUser, kAsset, kAmount)), + checkStatelessInvalid); } diff --git a/test/integration/acceptance/create_account_test.cpp b/test/integration/acceptance/create_account_test.cpp index 9945ad7c6c..cd3ddef3a8 100644 --- a/test/integration/acceptance/create_account_test.cpp +++ b/test/integration/acceptance/create_account_test.cpp @@ -1,76 +1,24 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include -#include "backend/protobuf/transaction.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class CreateAccount : public ::testing::Test { +class CreateAccount : public AcceptanceFixture { public: - /** - * Creates the transaction with the user creation commands - * @param perms are the permissions of the user - * @return built tx and a hash of its payload - */ auto makeUserWithPerms(const std::vector &perms = { shared_model::permissions::can_create_account}) { - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), "role"s, perms) - .build() - .signAndAddSignature(kAdminKeypair); + return AcceptanceFixture::makeUserWithPerms(perms); } - /** - * Create valid base pre-built transaction - * @return pre-built tx - */ - auto baseTx() { - return TestUnsignedTransactionBuilder() - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); - } - - /** - * Completes pre-built transaction - * @param builder is a pre-built tx - * @return built tx - */ - template - auto completeTx(TestTransactionBuilder builder) { - return builder.build().signAndAddSignature(kUserKeypair); - } - - const std::string kUser = "user"s; - const std::string kNewUser = "userone"s; - const std::string kDomain = IntegrationTestFramework::kDefaultDomain; - const std::string kUserId = kUser + "@" + kDomain; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); + const std::string kNewUser = "userone"; const crypto::Keypair kNewUserKeypair = crypto::DefaultCryptoAlgorithmType::generateKeypair(); }; @@ -81,12 +29,12 @@ class CreateAccount : public ::testing::Test { * @then there is the tx in proposal */ TEST_F(CreateAccount, Basic) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( + .sendTx(complete(baseTx().createAccount( kNewUser, kDomain, kNewUserKeypair.publicKey()))) .skipProposal() .checkBlock( @@ -100,12 +48,12 @@ TEST_F(CreateAccount, Basic) { * @then there is no tx in proposal */ TEST_F(CreateAccount, NoPermissions) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( + .sendTx(complete(baseTx().createAccount( kNewUser, kDomain, kNewUserKeypair.publicKey()))) .skipProposal() .checkBlock( @@ -115,18 +63,18 @@ TEST_F(CreateAccount, NoPermissions) { /** * @given some user with can_create_account permission - * @when execute tx with CreateAccount command with inexistent domain + * @when execute tx with CreateAccount command with nonexistent domain * @then there is no tx in proposal */ TEST_F(CreateAccount, NoDomain) { - const std::string inexistent_domain = "asdf"s; - IntegrationTestFramework() + const std::string nonexistent_domain = "asdf"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( - kNewUser, inexistent_domain, kNewUserKeypair.publicKey()))) + .sendTx(complete(baseTx().createAccount( + kNewUser, nonexistent_domain, kNewUserKeypair.publicKey()))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -138,15 +86,15 @@ TEST_F(CreateAccount, NoDomain) { * @when execute tx with CreateAccount command with already existing username * @then there is no tx in proposal */ -TEST_F(CreateAccount, ExistentName) { - const std::string &existent_name = kUser; - IntegrationTestFramework() +TEST_F(CreateAccount, ExistingName) { + std::string existing_name = kUser; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( - existent_name, kDomain, kNewUserKeypair.publicKey()))) + .sendTx(complete(baseTx().createAccount( + existing_name, kDomain, kNewUserKeypair.publicKey()))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -159,12 +107,12 @@ TEST_F(CreateAccount, ExistentName) { * @then there is the tx in proposal */ TEST_F(CreateAccount, MaxLenName) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( + .sendTx(complete(baseTx().createAccount( std::string(32, 'a'), kDomain, kNewUserKeypair.publicKey()))) .skipProposal() .checkBlock( @@ -179,14 +127,14 @@ TEST_F(CreateAccount, MaxLenName) { * (aka skipProposal throws) */ TEST_F(CreateAccount, TooLongName) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( - std::string(33, 'a'), kDomain, kNewUserKeypair.publicKey()))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().createAccount( + std::string(33, 'a'), kDomain, kNewUserKeypair.publicKey())), + checkStatelessInvalid); } /** @@ -196,13 +144,13 @@ TEST_F(CreateAccount, TooLongName) { * (aka skipProposal throws) */ TEST_F(CreateAccount, EmptyName) { - const std::string &empty_name = ""; - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + std::string empty_name = ""; + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createAccount( - empty_name, kDomain, kNewUserKeypair.publicKey()))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().createAccount( + empty_name, kDomain, kNewUserKeypair.publicKey())), + checkStatelessInvalid); } diff --git a/test/integration/acceptance/create_domain_test.cpp b/test/integration/acceptance/create_domain_test.cpp index e70b036629..e67a8f5fc8 100644 --- a/test/integration/acceptance/create_domain_test.cpp +++ b/test/integration/acceptance/create_domain_test.cpp @@ -1,76 +1,24 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include -#include "backend/protobuf/transaction.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class CreateDomain : public ::testing::Test { +class CreateDomain : public AcceptanceFixture { public: - /** - * Creates the transaction with the user creation commands - * @param perms are the permissions of the user - * @return built tx - */ auto makeUserWithPerms(const std::vector &perms = { shared_model::permissions::can_create_domain}) { - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), kRole, perms) - .build() - .signAndAddSignature(kAdminKeypair); + return AcceptanceFixture::makeUserWithPerms(perms); } - /** - * Create valid base pre-built transaction - * @return pre-built tx - */ - auto baseTx() { - return TestUnsignedTransactionBuilder() - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); - } - - /** - * Completes pre-built transaction - * @param builder is a pre-built tx - * @return built tx - */ - template - auto completeTx(TestTransactionBuilder builder) { - return builder.build().signAndAddSignature(kUserKeypair); - } - - const std::string kRole = "role"s; - const std::string kUser = "user"s; const std::string kNewDomain = "newdomain"; - const std::string kUserId = kUser + "@test"; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); }; /** @@ -79,12 +27,12 @@ class CreateDomain : public ::testing::Test { * @then there is the tx in proposal */ TEST_F(CreateDomain, Basic) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(kNewDomain, kRole))) + .sendTx(complete(baseTx().createDomain(kNewDomain, kRole))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) @@ -97,12 +45,12 @@ TEST_F(CreateDomain, Basic) { * @then there is no tx in proposal */ TEST_F(CreateDomain, NoPermissions) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(kNewDomain, kRole))) + .sendTx(complete(baseTx().createDomain(kNewDomain, kRole))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -111,17 +59,17 @@ TEST_F(CreateDomain, NoPermissions) { /** * @given some user with can_create_domain permission - * @when execute tx with CreateDomain command with inexistent role + * @when execute tx with CreateDomain command with nonexistent role * @then there is no tx in proposal */ TEST_F(CreateDomain, NoRole) { - const std::string inexistent_role = "asdf"s; - IntegrationTestFramework() + const std::string nonexistent_role = "asdf"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(kNewDomain, inexistent_role))) + .sendTx(complete(baseTx().createDomain(kNewDomain, nonexistent_role))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -133,14 +81,14 @@ TEST_F(CreateDomain, NoRole) { * @when execute tx with CreateDomain command with already existing domain * @then there is no tx in proposal */ -TEST_F(CreateDomain, ExistentName) { - const std::string &existing_domain = IntegrationTestFramework::kDefaultDomain; - IntegrationTestFramework() +TEST_F(CreateDomain, ExistingName) { + std::string existing_domain = IntegrationTestFramework::kDefaultDomain; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(existing_domain, kRole))) + .sendTx(complete(baseTx().createDomain(existing_domain, kRole))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -159,12 +107,12 @@ TEST_F(CreateDomain, MaxLenName) { "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad"; - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(maxLongDomain, kRole))) + .sendTx(complete(baseTx().createDomain(maxLongDomain, kRole))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) @@ -178,19 +126,13 @@ TEST_F(CreateDomain, MaxLenName) { * (aka skipProposal throws) */ TEST_F(CreateDomain, TooLongName) { - std::string tooLongDomain = - // 256 characters string - "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." - "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." - "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPad." - "maxLabelLengthIs63paddingPaddingPaddingPaddingPaddingPaddingPads"; - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(std::string(257, 'a'), kRole))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().createDomain(std::string(257, 'a'), kRole)), + checkStatelessInvalid); } /** @@ -200,14 +142,14 @@ TEST_F(CreateDomain, TooLongName) { * (aka skipProposal throws) */ TEST_F(CreateDomain, EmptyName) { - const std::string &empty_name = ""; - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + std::string empty_name = ""; + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(empty_name, kRole))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().createDomain(empty_name, kRole)), + checkStatelessInvalid); } /** @@ -217,12 +159,12 @@ TEST_F(CreateDomain, EmptyName) { * (aka skipProposal throws) */ TEST_F(CreateDomain, DISABLED_EmptyRoleName) { - const std::string &empty_name = ""; - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + std::string empty_name = ""; + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().createDomain(kNewDomain, empty_name))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().createDomain(kNewDomain, empty_name)), + checkStatelessInvalid); } diff --git a/test/integration/acceptance/create_role_test.cpp b/test/integration/acceptance/create_role_test.cpp index f116046400..25b7280053 100644 --- a/test/integration/acceptance/create_role_test.cpp +++ b/test/integration/acceptance/create_role_test.cpp @@ -1,61 +1,31 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include #include "backend/protobuf/transaction.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" #include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class CreateRole : public ::testing::Test { +class CreateRole : public AcceptanceFixture { public: - /** - * Creates the transaction with the user creation commands - * @param perms are the permissions of the user - * @return built tx and a hash of its payload - */ auto makeUserWithPerms(const std::vector &perms = { shared_model::permissions::can_get_my_txs, shared_model::permissions::can_create_role}) { - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), kNewRole, perms) - .build() - .signAndAddSignature(kAdminKeypair); + return AcceptanceFixture::makeUserWithPerms(kNewRole, perms); } - /** - * Create valid base pre-built transaction with CreateRole command - * @param perms is a permission list - * @param role_name is a name of the role - * @return pre-built tx - */ auto baseTx(const std::vector &perms, const std::string &role_name) { - return TestUnsignedTransactionBuilder() - .createRole(role_name, perms) - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); + return AcceptanceFixture::baseTx().createRole(role_name, perms); } auto baseTx(const std::vector &perms = { @@ -63,24 +33,7 @@ class CreateRole : public ::testing::Test { return baseTx(perms, kRole); } - /** - * Completes pre-built transaction - * @param builder is a pre-built tx - * @return built tx - */ - template - auto completeTx(TestTransactionBuilder builder) { - return builder.build().signAndAddSignature(kUserKeypair); - } - - const std::string kRole = "role"s; - const std::string kUser = "user"s; - const std::string kNewRole = "rl"s; - const std::string kUserId = kUser + "@test"; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); + const std::string kNewRole = "rl"; }; /** @@ -89,12 +42,12 @@ class CreateRole : public ::testing::Test { * @then there is the tx in proposal */ TEST_F(CreateRole, Basic) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx())) + .sendTx(complete(baseTx())) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) @@ -107,12 +60,12 @@ TEST_F(CreateRole, Basic) { * @then there is an empty verified proposal */ TEST_F(CreateRole, HaveNoPerms) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx())) + .sendTx(complete(baseTx())) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) .done(); @@ -125,14 +78,13 @@ TEST_F(CreateRole, HaveNoPerms) { * (aka skipProposal throws) */ TEST_F(CreateRole, EmptyRole) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx( - completeTx(baseTx({shared_model::permissions::can_get_my_txs}, ""))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx({shared_model::permissions::can_get_my_txs}, "")), + checkStatelessInvalid); } /** @@ -142,13 +94,12 @@ TEST_F(CreateRole, EmptyRole) { * (aka skipProposal throws) */ TEST_F(CreateRole, EmptyPerms) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx({}))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx({})), checkStatelessInvalid); } /** @@ -158,14 +109,14 @@ TEST_F(CreateRole, EmptyPerms) { * (aka skipProposal throws) */ TEST_F(CreateRole, LongRoleName) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx({shared_model::permissions::can_get_my_txs}, - std::string(33, 'a')))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx({shared_model::permissions::can_get_my_txs}, + std::string(33, 'a'))), + checkStatelessInvalid); } /** @@ -174,13 +125,13 @@ TEST_F(CreateRole, LongRoleName) { * @then the tx is comitted */ TEST_F(CreateRole, MaxLenRoleName) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx({shared_model::permissions::can_get_my_txs}, - std::string(32, 'a')))) + .sendTx(complete(baseTx({shared_model::permissions::can_get_my_txs}, + std::string(32, 'a')))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) @@ -188,32 +139,37 @@ TEST_F(CreateRole, MaxLenRoleName) { } /** + * TODO 15/05/2018 andrei: IR-1267 fix builders setting default value for + * nonexisting permissions * @given some user with can_create_role permission - * @when execute tx with CreateRole command with inexistent permission name + * @when execute tx with CreateRole command with nonexistent permission name * @then the tx hasn't passed stateless validation * (aka skipProposal throws) */ -TEST_F(CreateRole, DISABLED_InexistentPerm) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) +TEST_F(CreateRole, DISABLED_NonexistentPerm) { + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx({"this_permission_doesnt_exist"}))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx({"this_permission_doesnt_exist"})), + checkStatelessInvalid); } /** * @given some user with can_create_role permission - * @when execute tx with CreateRole command with existent role name + * @when execute tx with CreateRole command with existing role name * @then there is an empty verified proposal */ -TEST_F(CreateRole, DISABLED_ExistingRole) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) +TEST_F(CreateRole, ExistingRole) { + IntegrationTestFramework(1) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx())); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete( + baseTx({shared_model::permissions::can_get_my_txs}, kNewRole))) + .skipProposal() + .checkBlock( + [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }); } diff --git a/test/integration/acceptance/get_transactions_test.cpp b/test/integration/acceptance/get_transactions_test.cpp index 86545af38d..1319e8f644 100644 --- a/test/integration/acceptance/get_transactions_test.cpp +++ b/test/integration/acceptance/get_transactions_test.cpp @@ -1,49 +1,33 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include #include "backend/protobuf/transaction.hpp" #include "builders/protobuf/queries.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "interfaces/utils/specified_visitor.hpp" #include "utils/query_error_response_visitor.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class GetTransactions : public ::testing::Test { +class GetTransactions : public AcceptanceFixture { public: /** * Creates the transaction with the user creation commands * @param perms are the permissions of the user * @return built tx and a hash of its payload */ - auto makeUserWithPerms(const std::vector &perms) { + auto makeUserWithPerms(const std::vector &perms = { + shared_model::permissions::can_get_my_txs}) { auto new_perms = perms; new_perms.push_back(shared_model::permissions::can_set_quorum); - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), kNewRole, new_perms) - .build() - .signAndAddSignature(kAdminKeypair); + return AcceptanceFixture::makeUserWithPerms(kNewRole, new_perms); } /** @@ -52,12 +36,7 @@ class GetTransactions : public ::testing::Test { * Note: It should affect the ledger minimally */ auto dummyTx() { - return shared_model::proto::TransactionBuilder() - .setAccountQuorum(kUserId, 1) - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()) - .build() - .signAndAddSignature(kUserKeypair); + return complete(AcceptanceFixture::baseTx().setAccountQuorum(kUserId, 1)); } /** @@ -66,22 +45,11 @@ class GetTransactions : public ::testing::Test { * @return built query */ auto makeQuery(const crypto::Hash &hash) { - return proto::QueryBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId(kUserId) - .queryCounter(1) - .getTransactions(std::vector{hash}) - .build() - .signAndAddSignature(kUserKeypair); + return complete(baseQry().queryCounter(1).getTransactions( + std::vector{hash})); } - const std::string kUser = "user"s; - const std::string kNewRole = "rl"s; - const std::string kUserId = kUser + "@test"; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); + const std::string kNewRole = "rl"; }; /** @@ -98,7 +66,7 @@ TEST_F(GetTransactions, HaveNoGetPerms) { }; auto dummy_tx = dummyTx(); - IntegrationTestFramework() + IntegrationTestFramework(2) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_read_assets})) .sendTx(dummy_tx) @@ -124,7 +92,7 @@ TEST_F(GetTransactions, HaveGetAllTx) { ASSERT_EQ(*resp.value()->transactions()[0].operator->(), dummy_tx); }; - IntegrationTestFramework() + IntegrationTestFramework(2) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_get_all_txs})) .sendTx(dummy_tx) @@ -150,9 +118,9 @@ TEST_F(GetTransactions, HaveGetMyTx) { ASSERT_EQ(*resp.value()->transactions()[0].operator->(), dummy_tx); }; - IntegrationTestFramework() + IntegrationTestFramework(2) .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) + .sendTx(makeUserWithPerms()) .sendTx(dummy_tx) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) @@ -175,28 +143,27 @@ TEST_F(GetTransactions, InvalidSignatures) { interface::StatefulFailedErrorResponse>>(resp->get())); }; - auto query = proto::QueryBuilder() - .createdTime(iroha::time::now()) - .creatorAccountId(kUserId) + auto query = baseQry() .queryCounter(1) .getTransactions(std::vector{dummy_tx.hash()}) .build() .signAndAddSignature( crypto::DefaultCryptoAlgorithmType::generateKeypair()); - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) + .sendTx(makeUserWithPerms()) + .skipBlock() .sendQuery(query, check) .done(); } /** * @given some user with only can_get_my_txs permission - * @when query GetTransactions with inexistent hash + * @when query GetTransactions with nonexistent hash * @then TransactionsResponse with no transactions */ -TEST_F(GetTransactions, InexistentHash) { +TEST_F(GetTransactions, NonexistentHash) { auto check = [](auto &status) { auto resp = boost::apply_visitor( interface::SpecifiedVisitor(), @@ -205,9 +172,9 @@ TEST_F(GetTransactions, InexistentHash) { ASSERT_EQ(resp.value()->transactions().size(), 0); }; - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms({shared_model::permissions::can_get_my_txs})) + .sendTx(makeUserWithPerms()) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) .sendQuery(makeQuery(crypto::Hash(std::string(32, '0'))), check) @@ -228,8 +195,8 @@ TEST_F(GetTransactions, OtherUserTx) { ASSERT_EQ(resp.value()->transactions().size(), 0); }; - auto tx = makeUserWithPerms({shared_model::permissions::can_get_my_txs}); - IntegrationTestFramework() + auto tx = makeUserWithPerms(); + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(tx) .checkBlock( diff --git a/test/integration/acceptance/invalid_fields_test.cpp b/test/integration/acceptance/invalid_fields_test.cpp index 3d4eb57753..69f5ceb5b2 100644 --- a/test/integration/acceptance/invalid_fields_test.cpp +++ b/test/integration/acceptance/invalid_fields_test.cpp @@ -1,42 +1,17 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include -#include "backend/protobuf/transaction.hpp" #include "block.pb.h" -#include "builders/protobuf/transaction.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "interfaces/utils/specified_visitor.hpp" -#include "module/shared_model/validators/validators.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class InvalidField : public ::testing::Test { - public: - const std::string kUser = "user"s; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); -}; +class InvalidField : public AcceptanceFixture {}; /** * @given tx with CreateAccount command and invalid signature size @@ -44,25 +19,14 @@ class InvalidField : public ::testing::Test { * @then Torii returns stateless fail */ TEST_F(InvalidField, Signature) { - auto tx = proto::TransactionBuilder() - .createAccount(kUser, "test", kUserKeypair.publicKey()) - .creatorAccountId("admin@test") - .createdTime(iroha::time::now()) - .build() - .signAndAddSignature(kAdminKeypair) - .getTransport(); + auto tx = complete(baseTx()).getTransport(); // extend signature to invalid size auto sig = tx.mutable_signatures(0)->mutable_signature(); sig->resize(sig->size() + 1, 'a'); - auto check = [](auto &resp) { - ASSERT_TRUE(boost::apply_visitor( - interface::SpecifiedVisitor(), - resp.get())); - }; - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) - .sendTx(proto::Transaction(tx), check) + .sendTx(proto::Transaction(tx), checkStatelessInvalid) .done(); } @@ -72,24 +36,13 @@ TEST_F(InvalidField, Signature) { * @then Torii returns stateless fail */ TEST_F(InvalidField, Pubkey) { - auto tx = proto::TransactionBuilder() - .createAccount(kUser, "test", kUserKeypair.publicKey()) - .creatorAccountId("admin@test") - .createdTime(iroha::time::now()) - .build() - .signAndAddSignature(kAdminKeypair) - .getTransport(); + auto tx = complete(baseTx()).getTransport(); // extend public key to invalid size auto pkey = tx.mutable_signatures(0)->mutable_pubkey(); pkey->resize(pkey->size() + 1, 'a'); - auto check = [](auto &resp) { - ASSERT_TRUE(boost::apply_visitor( - interface::SpecifiedVisitor(), - resp.get())); - }; - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) - .sendTx(proto::Transaction(tx), check) + .sendTx(proto::Transaction(tx), checkStatelessInvalid) .done(); } diff --git a/test/integration/acceptance/subtract_asset_qty_test.cpp b/test/integration/acceptance/subtract_asset_qty_test.cpp index 7df25dee1f..dd48600264 100644 --- a/test/integration/acceptance/subtract_asset_qty_test.cpp +++ b/test/integration/acceptance/subtract_asset_qty_test.cpp @@ -1,34 +1,20 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include #include "backend/protobuf/transaction.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class SubtractAssetQuantity : public ::testing::Test { +class SubtractAssetQuantity : public AcceptanceFixture { public: /** * Creates the transaction with the user creation commands @@ -38,47 +24,17 @@ class SubtractAssetQuantity : public ::testing::Test { auto makeUserWithPerms(const std::vector &perms = { shared_model::permissions::can_subtract_asset_qty, shared_model::permissions::can_add_asset_qty}) { - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), "role"s, perms) - .build() - .signAndAddSignature(kAdminKeypair); - } - - /** - * Create valid base pre-built transaction - * @return pre-built tx - */ - auto baseTx() { - return TestUnsignedTransactionBuilder() - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); - } - - /** - * Completes pre-built transaction - * @param builder is a pre-built tx - * @return built tx - */ - template - auto completeTx(TestTransactionBuilder builder) { - return builder.build().signAndAddSignature(kUserKeypair); + return AcceptanceFixture::makeUserWithPerms(perms); } /** * @return built tx that adds kAmount assets to the users */ auto replenish() { - return completeTx(baseTx().addAssetQuantity(kUserId, kAsset, kAmount)); + return complete(baseTx().addAssetQuantity(kUserId, kAsset, kAmount)); } - const std::string kUser = "user"s; - const std::string kAsset = IntegrationTestFramework::kAssetName + "#test"; - const std::string kUserId = kUser + "@test"; const std::string kAmount = "1.0"; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); }; /** @@ -87,14 +43,16 @@ class SubtractAssetQuantity : public ::testing::Test { * @then there is the tx in proposal */ TEST_F(SubtractAssetQuantity, Everything) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) + .skipProposal() + .skipBlock() .sendTx(replenish()) .skipProposal() .skipBlock() .sendTx( - completeTx(baseTx().subtractAssetQuantity(kUserId, kAsset, kAmount))) + complete(baseTx().subtractAssetQuantity(kUserId, kAsset, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) @@ -108,14 +66,15 @@ TEST_F(SubtractAssetQuantity, Everything) { * @then there is no tx in proposal */ TEST_F(SubtractAssetQuantity, Overdraft) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) + .skipProposal() + .skipBlock() .sendTx(replenish()) .skipProposal() .skipBlock() - .sendTx( - completeTx(baseTx().subtractAssetQuantity(kUserId, kAsset, "2.0"))) + .sendTx(complete(baseTx().subtractAssetQuantity(kUserId, kAsset, "2.0"))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -128,14 +87,16 @@ TEST_F(SubtractAssetQuantity, Overdraft) { * @then there is no tx in proposal */ TEST_F(SubtractAssetQuantity, NoPermissions) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms({shared_model::permissions::can_add_asset_qty})) + .skipProposal() + .skipBlock() .sendTx(replenish()) .skipProposal() .skipBlock() .sendTx( - completeTx(baseTx().subtractAssetQuantity(kUserId, kAsset, kAmount))) + complete(baseTx().subtractAssetQuantity(kUserId, kAsset, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -149,15 +110,14 @@ TEST_F(SubtractAssetQuantity, NoPermissions) { * (aka skipProposal throws) */ TEST_F(SubtractAssetQuantity, NegativeAmount) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(2) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .sendTx(replenish()) .skipProposal() .skipBlock() - .sendTx( - completeTx(baseTx().subtractAssetQuantity(kUserId, kAsset, "-1.0"))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().subtractAssetQuantity(kUserId, kAsset, "-1.0")), + checkStatelessInvalid); } /** @@ -167,32 +127,33 @@ TEST_F(SubtractAssetQuantity, NegativeAmount) { * (aka skipProposal throws) */ TEST_F(SubtractAssetQuantity, ZeroAmount) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(2) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) .sendTx(replenish()) .skipProposal() .skipBlock() - .sendTx( - completeTx(baseTx().subtractAssetQuantity(kUserId, kAsset, "0.0"))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(complete(baseTx().subtractAssetQuantity(kUserId, kAsset, "0.0")), + checkStatelessInvalid); } /** * @given some user with all required permissions - * @when execute tx with SubtractAssetQuantity command with inexistent account + * @when execute tx with SubtractAssetQuantity command with nonexitent account * @then there is an empty proposal */ -TEST_F(SubtractAssetQuantity, InexistentAccount) { - const std::string &inexistent = "inexist@test"s; - IntegrationTestFramework() +TEST_F(SubtractAssetQuantity, NonexistentAccount) { + std::string nonexistent = "inexist@test"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) + .skipProposal() + .skipBlock() .sendTx(replenish()) .skipProposal() .skipBlock() - .sendTx(completeTx( - baseTx().subtractAssetQuantity(inexistent, kAsset, kAmount))) + .sendTx(complete( + baseTx().subtractAssetQuantity(nonexistent, kAsset, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -201,19 +162,21 @@ TEST_F(SubtractAssetQuantity, InexistentAccount) { /** * @given some user with all required permissions - * @when execute tx with SubtractAssetQuantity command with inexistent asset + * @when execute tx with SubtractAssetQuantity command with nonexistent asset * @then there is an empty proposal */ -TEST_F(SubtractAssetQuantity, InexistentAsset) { - const std::string &inexistent = "inexist#test"s; - IntegrationTestFramework() +TEST_F(SubtractAssetQuantity, NonexistentAsset) { + std::string nonexistent = "inexist#test"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) + .skipProposal() + .skipBlock() .sendTx(replenish()) .skipProposal() .skipBlock() - .sendTx(completeTx( - baseTx().subtractAssetQuantity(kUserId, inexistent, kAmount))) + .sendTx(complete( + baseTx().subtractAssetQuantity(kUserId, nonexistent, kAmount))) .skipProposal() .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) @@ -226,13 +189,15 @@ TEST_F(SubtractAssetQuantity, InexistentAsset) { * @then there is no tx in proposal */ TEST_F(SubtractAssetQuantity, OtherUser) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) + .skipProposal() + .skipBlock() .sendTx(replenish()) .skipProposal() .skipBlock() - .sendTx(completeTx(baseTx().subtractAssetQuantity( + .sendTx(complete(baseTx().subtractAssetQuantity( IntegrationTestFramework::kAdminId, kAsset, kAmount))) .skipProposal() .checkBlock( diff --git a/test/integration/acceptance/transfer_asset_test.cpp b/test/integration/acceptance/transfer_asset_test.cpp index a64fb35e7c..34f87e42e5 100644 --- a/test/integration/acceptance/transfer_asset_test.cpp +++ b/test/integration/acceptance/transfer_asset_test.cpp @@ -1,39 +1,22 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include "acceptance_fixture.hpp" #include "backend/protobuf/transaction.hpp" #include "builders/protobuf/queries.hpp" #include "builders/protobuf/transaction.hpp" #include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "interfaces/utils/specified_visitor.hpp" -#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "utils/query_error_response_visitor.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class TransferAsset : public ::testing::Test { +class TransferAsset : public AcceptanceFixture { public: /** * Creates the transaction with the user creation commands @@ -44,7 +27,7 @@ class TransferAsset : public ::testing::Test { const crypto::Keypair &key, const std::vector &perms, const std::string &role) { - return framework::createUserWithPerms(user, key.publicKey(), role, perms) + return createUserWithPerms(user, key.publicKey(), role, perms) .build() .signAndAddSignature(kAdminKeypair); } @@ -86,17 +69,14 @@ class TransferAsset : public ::testing::Test { return builder.build().signAndAddSignature(kUser1Keypair); } - const std::string kAsset = IntegrationTestFramework::kAssetName + "#test"; - const std::string kAmount = "1.0"s; - const std::string kDesc = "description"s; - const std::string kUser1 = "userone"s; - const std::string kUser2 = "usertwo"s; - const std::string kRole1 = "roleone"s; - const std::string kRole2 = "roletwo"s; + const std::string kAmount = "1.0"; + const std::string kDesc = "description"; + const std::string kUser1 = "userone"; + const std::string kUser2 = "usertwo"; + const std::string kRole1 = "roleone"; + const std::string kRole2 = "roletwo"; const std::string kUser1Id = kUser1 + "@test"; const std::string kUser2Id = kUser2 + "@test"; - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); const crypto::Keypair kUser1Keypair = crypto::DefaultCryptoAlgorithmType::generateKeypair(); const crypto::Keypair kUser2Keypair = @@ -113,18 +93,15 @@ class TransferAsset : public ::testing::Test { * @then there is the tx in proposal */ TEST_F(TransferAsset, Basic) { - IntegrationTestFramework() + IntegrationTestFramework(4) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) - .skipProposal() - .skipBlock() .sendTx(completeTx( baseTx().transferAsset(kUser1Id, kUser2Id, kAsset, kDesc, kAmount))) - .skipProposal() .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + [](auto &block) { ASSERT_EQ(block->transactions().size(), 4); }) .done(); } @@ -134,13 +111,17 @@ TEST_F(TransferAsset, Basic) { * @then there is an empty proposal */ TEST_F(TransferAsset, WithOnlyCanTransferPerm) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, {shared_model::permissions::can_transfer}, kRole1)) + .skipProposal() + .skipBlock() .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) + .skipProposal() + .skipBlock() .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() .skipBlock() @@ -159,13 +140,17 @@ TEST_F(TransferAsset, WithOnlyCanTransferPerm) { * @then there is an empty proposal */ TEST_F(TransferAsset, WithOnlyCanReceivePerm) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, {shared_model::permissions::can_receive}, kRole1)) + .skipProposal() + .skipBlock() .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) + .skipProposal() + .skipBlock() .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() .skipBlock() @@ -180,19 +165,21 @@ TEST_F(TransferAsset, WithOnlyCanReceivePerm) { /** * @given some user with all required permissions - * @when execute tx with TransferAsset command to inexistent destination + * @when execute tx with TransferAsset command to nonexistent destination * @then there is an empty proposal */ -TEST_F(TransferAsset, InexistentDest) { - const std::string &inexistent = "inexist@test"s; - IntegrationTestFramework() +TEST_F(TransferAsset, NonexistentDest) { + std::string nonexistent = "inexist@test"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) + .skipProposal() + .skipBlock() .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() .skipBlock() .sendTx(baseTx() - .transferAsset(kUser1Id, inexistent, kAsset, kDesc, kAmount) + .transferAsset(kUser1Id, nonexistent, kAsset, kDesc, kAmount) .build() .signAndAddSignature(kUser1Keypair)) .checkBlock( @@ -202,22 +189,27 @@ TEST_F(TransferAsset, InexistentDest) { /** * @given pair of users with all required permissions - * @when execute tx with TransferAsset command with inexistent asset + * @when execute tx with TransferAsset command with nonexistent asset * @then there is an empty proposal */ -TEST_F(TransferAsset, InexistentAsset) { - const std::string &inexistent = "inexist#test"s; - IntegrationTestFramework() +TEST_F(TransferAsset, NonexistentAsset) { + std::string nonexistent = "inexist#test"; + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) + .skipProposal() + .skipBlock() .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) + .skipProposal() + .skipBlock() .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() .skipBlock() - .sendTx(baseTx() - .transferAsset(kUser1Id, kUser2Id, inexistent, kDesc, kAmount) - .build() - .signAndAddSignature(kUser1Keypair)) + .sendTx( + baseTx() + .transferAsset(kUser1Id, kUser2Id, nonexistent, kDesc, kAmount) + .build() + .signAndAddSignature(kUser1Keypair)) .checkBlock( [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }) .done(); @@ -230,8 +222,8 @@ TEST_F(TransferAsset, InexistentAsset) { * (aka skipProposal throws) */ TEST_F(TransferAsset, NegativeAmount) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(3) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) @@ -240,8 +232,8 @@ TEST_F(TransferAsset, NegativeAmount) { .sendTx(baseTx() .transferAsset(kUser1Id, kUser2Id, kAsset, kDesc, "-1.0") .build() - .signAndAddSignature(kUser1Keypair)); - ASSERT_ANY_THROW(itf.skipProposal()); + .signAndAddSignature(kUser1Keypair), + checkStatelessInvalid); } /** @@ -251,8 +243,8 @@ TEST_F(TransferAsset, NegativeAmount) { * (aka skipProposal throws) */ TEST_F(TransferAsset, ZeroAmount) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(3) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) @@ -261,8 +253,8 @@ TEST_F(TransferAsset, ZeroAmount) { .sendTx(baseTx() .transferAsset(kUser1Id, kUser2Id, kAsset, kDesc, "0.0") .build() - .signAndAddSignature(kUser1Keypair)); - ASSERT_ANY_THROW(itf.skipProposal()); + .signAndAddSignature(kUser1Keypair), + checkStatelessInvalid); } /** @@ -271,18 +263,15 @@ TEST_F(TransferAsset, ZeroAmount) { * @then it passed to the proposal */ TEST_F(TransferAsset, EmptyDesc) { - IntegrationTestFramework() + IntegrationTestFramework(4) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) - .skipProposal() - .skipBlock() .sendTx(completeTx( baseTx().transferAsset(kUser1Id, kUser2Id, kAsset, "", kAmount))) - .skipProposal() .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + [](auto &block) { ASSERT_EQ(block->transactions().size(), 4); }) .done(); } @@ -296,20 +285,14 @@ TEST_F(TransferAsset, LongDesc) { std::string long_desc(100000, 'a'); auto invalid_tx = completeTx( baseTx().transferAsset(kUser1Id, kUser2Id, kAsset, long_desc, kAmount)); - using ExpectedStatusType = shared_model::detail::PolymorphicWrapper< - shared_model::interface::StatelessFailedTxResponse>; - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(3) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() .skipBlock() - .sendTx(invalid_tx, - [](const shared_model::proto::TransactionResponse &status) { - // check if returned status is as expected - ASSERT_NO_THROW(boost::get(status.get())); - }) + .sendTx(invalid_tx, checkStatelessInvalid) .done(); } @@ -319,10 +302,14 @@ TEST_F(TransferAsset, LongDesc) { * @then there is an empty proposal */ TEST_F(TransferAsset, MoreThanHas) { - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) + .skipProposal() + .skipBlock() .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) + .skipProposal() + .skipBlock() .sendTx(addAssets(kUser1, kUser1Keypair, "50.0")) .skipProposal() .skipBlock() @@ -343,24 +330,31 @@ TEST_F(TransferAsset, MoreThanHas) { * second */ TEST_F(TransferAsset, Uint256DestOverflow) { - const std::string &uint256_halfmax = + std::string uint256_halfmax = "723700557733226221397318656304299424082937404160253525246609900049457060" "2495.0"; // 2**252 - 1 - IntegrationTestFramework() + IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) + .skipProposal() + .skipBlock() .sendTx(makeUserWithPerms(kUser2, kUser2Keypair, kPerms, kRole2)) + .skipProposal() + .skipBlock() .sendTx(addAssets(kUser1, kUser1Keypair, uint256_halfmax)) .skipProposal() .skipBlock() // Send first half of the maximum .sendTx(completeTx(baseTx().transferAsset( kUser1Id, kUser2Id, kAsset, kDesc, uint256_halfmax))) + .skipProposal() + .checkBlock( + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) // Restore self balance .sendTx(addAssets(kUser1, kUser1Keypair, uint256_halfmax)) .skipProposal() .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) // Send second half of the maximum .sendTx(completeTx(baseTx().transferAsset( kUser1Id, kUser2Id, kAsset, kDesc, uint256_halfmax))) @@ -378,15 +372,15 @@ TEST_F(TransferAsset, Uint256DestOverflow) { * (aka skipProposal throws) */ TEST_F(TransferAsset, SourceIsDest) { - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(2) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx(addAssets(kUser1, kUser1Keypair)) .skipProposal() .skipBlock() - .sendTx(completeTx( - baseTx().transferAsset(kUser1Id, kUser1Id, kAsset, kDesc, kAmount))); - ASSERT_ANY_THROW(itf.skipProposal()); + .sendTx(completeTx(baseTx().transferAsset( + kUser1Id, kUser1Id, kAsset, kDesc, kAmount)), + checkStatelessInvalid); } /** @@ -399,7 +393,7 @@ TEST_F(TransferAsset, InterDomain) { const auto kNewRole = "newrl"; const auto kNewDomain = "newdom"; const auto kUser2Id = kUser2 + "@" + kNewDomain; - IntegrationTestFramework() + IntegrationTestFramework(4) .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms(kUser1, kUser1Keypair, kPerms, kRole1)) .sendTx( @@ -420,13 +414,9 @@ TEST_F(TransferAsset, InterDomain) { .build() .signAndAddSignature(kAdminKeypair)) .sendTx(addAssets(kUser1, kUser1Keypair, kAmount)) - .skipProposal() - .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 3); }) .sendTx(completeTx( baseTx().transferAsset(kUser1Id, kUser2Id, kAsset, kDesc, kAmount))) - .skipProposal() .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }) + [](auto &block) { ASSERT_EQ(block->transactions().size(), 4); }) .done(); } diff --git a/test/integration/acceptance/tx_acceptance_test.cpp b/test/integration/acceptance/tx_acceptance_test.cpp index 03c5f8c085..2a01e3452d 100644 --- a/test/integration/acceptance/tx_acceptance_test.cpp +++ b/test/integration/acceptance/tx_acceptance_test.cpp @@ -1,53 +1,36 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ -#include "backend/protobuf/transaction.hpp" -#include "builders/protobuf/queries.hpp" -#include "builders/protobuf/transaction.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" #include "framework/integration_framework/integration_test_framework.hpp" -#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" -#include "responses.pb.h" +#include "integration/acceptance/acceptance_fixture.hpp" +#include "interfaces/utils/specified_visitor.hpp" -constexpr auto kAdmin = "admin@test"; -constexpr auto kNonUser = "nonuser@test"; -constexpr auto kAsset = "coin#test"; -const shared_model::crypto::Keypair kAdminKeypair = - shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair(); -auto checkStatelessValid = [](auto &status) { - ASSERT_NO_THROW( - boost::get>(status.get())); -}; -auto checkStatelessInvalid = [](auto &status) { - ASSERT_NO_THROW( - boost::get>(status.get())); -}; -auto checkProposal = [](auto &proposal) { - ASSERT_EQ(proposal->transactions().size(), 1); +class AcceptanceTest : public AcceptanceFixture { + public: + const std::string kAdmin = "admin@test"; + const std::string kNonUser = "nonuser@test"; -}; -auto checkStatefulInvalid = [](auto &block) { - ASSERT_EQ(block->transactions().size(), 0); -}; -auto checkStatefulValid = [](auto &block) { - ASSERT_EQ(block->transactions().size(), 1); + const std::function + checkStatelessValid = [](auto &status) { + ASSERT_TRUE(boost::apply_visitor( + shared_model::interface::SpecifiedVisitor< + shared_model::interface::StatelessValidTxResponse>(), + status.get())); + }; + const std::function &)> + checkProposal = + [](auto &proposal) { ASSERT_EQ(proposal->transactions().size(), 1); }; + const std::function &)> + checkStatefulInvalid = + [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }; + const std::function &)> + checkStatefulValid = + [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }; }; /** @@ -56,8 +39,8 @@ auto checkStatefulValid = [](auto &block) { * @then receive STATELESS_VALIDATION_SUCCESS status * AND STATEFUL_VALIDATION_FAILED on that tx */ -TEST(AcceptanceTest, NonExistentCreatorAccountId) { - auto tx = shared_model::proto::TransactionBuilder() +TEST_F(AcceptanceTest, NonExistentCreatorAccountId) { + auto tx = TestUnsignedTransactionBuilder() .createdTime(iroha::time::now()) .creatorAccountId(kNonUser) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -78,8 +61,8 @@ TEST(AcceptanceTest, NonExistentCreatorAccountId) { * @then receive STATELESS_VALIDATION_SUCCESS status * AND STATEFUL_VALIDATION_SUCCESS on that tx */ -TEST(AcceptanceTest, Transaction1HourOld) { - auto tx = shared_model::proto::TransactionBuilder() +TEST_F(AcceptanceTest, Transaction1HourOld) { + auto tx = TestUnsignedTransactionBuilder() .createdTime(iroha::time::now(std::chrono::hours(-1))) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") @@ -99,8 +82,8 @@ TEST(AcceptanceTest, Transaction1HourOld) { * @then receive STATELESS_VALIDATION_SUCCESS status * AND STATEFUL_VALIDATION_SUCCESS on that tx */ -TEST(AcceptanceTest, DISABLED_TransactionLess24HourOld) { - auto tx = shared_model::proto::TransactionBuilder() +TEST_F(AcceptanceTest, DISABLED_TransactionLess24HourOld) { + auto tx = TestUnsignedTransactionBuilder() .createdTime(iroha::time::now(std::chrono::hours(24) - std::chrono::minutes(1))) .creatorAccountId(kAdmin) @@ -120,15 +103,7 @@ TEST(AcceptanceTest, DISABLED_TransactionLess24HourOld) { * @when sending transactions with an more than 24 hour old UNIX time * @then receive STATELESS_VALIDATION_FAILED status */ -TEST(AcceptanceTest, TransactionMore24HourOld) { - ASSERT_ANY_THROW( - auto tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now(std::chrono::hours(24) - + std::chrono::minutes(1))) - .creatorAccountId(kAdmin) - .addAssetQuantity(kAdmin, kAsset, "1.0") - .build() - .signAndAddSignature(kAdminKeypair);); +TEST_F(AcceptanceTest, TransactionMore24HourOld) { auto tx = TestUnsignedTransactionBuilder() .createdTime(iroha::time::now(std::chrono::hours(24) + std::chrono::minutes(1))) @@ -148,8 +123,8 @@ TEST(AcceptanceTest, TransactionMore24HourOld) { * @then receive STATELESS_VALIDATION_SUCCESS status * AND STATEFUL_VALIDATION_SUCCESS on that tx */ -TEST(AcceptanceTest, Transaction5MinutesFromFuture) { - auto tx = shared_model::proto::TransactionBuilder() +TEST_F(AcceptanceTest, Transaction5MinutesFromFuture) { + auto tx = TestUnsignedTransactionBuilder() .createdTime(iroha::time::now(std::chrono::minutes(5) - std::chrono::seconds(10))) .creatorAccountId(kAdmin) @@ -170,14 +145,7 @@ TEST(AcceptanceTest, Transaction5MinutesFromFuture) { * @when sending transactions with an 10 minutes from future UNIX time * @then receive STATELESS_VALIDATION_FAILED status */ -TEST(AcceptanceTest, Transaction10MinutesFromFuture) { - ASSERT_ANY_THROW( - auto tx = shared_model::proto::TransactionBuilder() - .createdTime(iroha::time::now(std::chrono::minutes(10))) - .creatorAccountId(kAdmin) - .addAssetQuantity(kAdmin, kAsset, "1.0") - .build() - .signAndAddSignature(kAdminKeypair);); +TEST_F(AcceptanceTest, Transaction10MinutesFromFuture) { auto tx = TestUnsignedTransactionBuilder() .createdTime(iroha::time::now(std::chrono::minutes(10))) .creatorAccountId(kAdmin) @@ -195,7 +163,7 @@ TEST(AcceptanceTest, Transaction10MinutesFromFuture) { * @when sending transactions with an empty public Key * @then receive STATELESS_VALIDATION_FAILED status */ -TEST(AcceptanceTest, TransactionEmptyPubKey) { +TEST_F(AcceptanceTest, TransactionEmptyPubKey) { shared_model::proto::Transaction tx = TestTransactionBuilder() .createdTime(iroha::time::now()) @@ -217,7 +185,7 @@ TEST(AcceptanceTest, TransactionEmptyPubKey) { * @when sending transactions with an empty signedBlob * @then receive STATELESS_VALIDATION_FAILED status */ -TEST(AcceptanceTest, TransactionEmptySignedblob) { +TEST_F(AcceptanceTest, TransactionEmptySignedblob) { shared_model::proto::Transaction tx = TestTransactionBuilder() .createdTime(iroha::time::now()) @@ -236,7 +204,7 @@ TEST(AcceptanceTest, TransactionEmptySignedblob) { * @when sending transactions with Invalid PublicKey * @then receive STATELESS_VALIDATION_FAILED status */ -TEST(AcceptanceTest, TransactionInvalidPublicKey) { +TEST_F(AcceptanceTest, TransactionInvalidPublicKey) { shared_model::proto::Transaction tx = TestTransactionBuilder() .createdTime(iroha::time::now()) @@ -258,7 +226,7 @@ TEST(AcceptanceTest, TransactionInvalidPublicKey) { * @when sending transactions with Invalid SignedBlock * @then receive STATELESS_VALIDATION_FAILED status */ -TEST(AcceptanceTest, TransactionInvalidSignedBlob) { +TEST_F(AcceptanceTest, TransactionInvalidSignedBlob) { shared_model::proto::Transaction tx = TestTransactionBuilder() .createdTime(iroha::time::now()) @@ -286,9 +254,9 @@ TEST(AcceptanceTest, TransactionInvalidSignedBlob) { * @then receive STATELESS_VALIDATION_SUCCESS status * AND STATEFUL_VALIDATION_SUCCESS on that tx */ -TEST(AcceptanceTest, TransactionValidSignedBlob) { +TEST_F(AcceptanceTest, TransactionValidSignedBlob) { shared_model::proto::Transaction tx = - shared_model::proto::TransactionBuilder() + TestUnsignedTransactionBuilder() .createdTime(iroha::time::now()) .creatorAccountId(kAdmin) .addAssetQuantity(kAdmin, kAsset, "1.0") diff --git a/test/integration/acceptance/tx_heavy_data.cpp b/test/integration/acceptance/tx_heavy_data.cpp index 20cd6da77f..eb22794a15 100644 --- a/test/integration/acceptance/tx_heavy_data.cpp +++ b/test/integration/acceptance/tx_heavy_data.cpp @@ -1,40 +1,21 @@ /** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 */ #include #include #include -#include "builders/protobuf/queries.hpp" -#include "builders/protobuf/transaction.hpp" -#include "cryptography/crypto_provider/crypto_defaults.hpp" -#include "datetime/time.hpp" -#include "framework/base_tx.hpp" #include "framework/integration_framework/integration_test_framework.hpp" +#include "integration/acceptance/acceptance_fixture.hpp" #include "interfaces/utils/specified_visitor.hpp" -#include "module/shared_model/builders/protobuf/test_query_builder.hpp" -#include "module/shared_model/builders/protobuf/test_transaction_builder.hpp" #include "validators/permissions.hpp" -using namespace std::string_literals; using namespace integration_framework; using namespace shared_model; -class HeavyTransactionTest : public ::testing::Test { +class HeavyTransactionTest : public AcceptanceFixture { public: /** * Creates the transaction with the user creation commands @@ -45,20 +26,7 @@ class HeavyTransactionTest : public ::testing::Test { const std::vector &perms = { shared_model::permissions::role_perm_group.begin(), shared_model::permissions::role_perm_group.end()}) { - return framework::createUserWithPerms( - kUser, kUserKeypair.publicKey(), "role"s, perms) - .build() - .signAndAddSignature(kAdminKeypair); - } - - /** - * Create valid base pre-built transaction - * @return pre-built tx - */ - auto baseTx() { - return TestUnsignedTransactionBuilder() - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); + return AcceptanceFixture::makeUserWithPerms(perms); } /** @@ -80,34 +48,13 @@ class HeavyTransactionTest : public ::testing::Test { return std::string(quantity, 'F'); } - /** - * Sign pre-built object - * @param builder is a pre-built signable object - * @return completed object - */ - template - auto complete(Builder builder) { - return builder.build().signAndAddSignature(kUserKeypair); - } - /** * Create valid basis of pre-built query * @return query stub with counter, creator and time */ auto baseQuery() { - return TestUnsignedQueryBuilder() - .queryCounter(1) - .creatorAccountId(kUserId) - .createdTime(iroha::time::now()); + return baseQry().queryCounter(1); } - - const std::string kUser = "user"s; - const std::string kUserId = - kUser + "@"s + IntegrationTestFramework::kDefaultDomain; - const crypto::Keypair kUserKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); - const crypto::Keypair kAdminKeypair = - crypto::DefaultCryptoAlgorithmType::generateKeypair(); }; /** @@ -118,50 +65,43 @@ class HeavyTransactionTest : public ::testing::Test { * @then transaction have been passed */ TEST_F(HeavyTransactionTest, DISABLED_ManyLargeTxes) { - IntegrationTestFramework itf; + auto number_of_txes = 4u; + IntegrationTestFramework itf(number_of_txes + 1); - itf.setInitialState(kAdminKeypair) - .sendTx(makeUserWithPerms()) - .skipProposal() - .checkBlock([](auto &b) { ASSERT_EQ(b->transactions().size(), 1); }); + itf.setInitialState(kAdminKeypair).sendTx(makeUserWithPerms()); - auto number_of_txes = 4u; for (auto i = 0u; i < number_of_txes; ++i) { itf.sendTx(complete(setAcountDetailTx("foo_" + std::to_string(i), generateData(2 * 1024 * 1024)))); } itf.skipProposal() - .checkBlock( - [&](auto &b) { ASSERT_EQ(b->transactions().size(), number_of_txes); }) + .checkBlock([&](auto &b) { + ASSERT_EQ(b->transactions().size(), number_of_txes + 1); + }) .done(); } /** + * TODO: enable the test when performance issues are solved + * IR-1264 14/05/2018 andrei * @given some user with all required permissions * @when send tx with many addAccountDetails with large data inside * @then transaction is passed */ -TEST_F(HeavyTransactionTest, VeryLargeTxWithManyCommands) { +TEST_F(HeavyTransactionTest, DISABLED_VeryLargeTxWithManyCommands) { auto big_data = generateData(3 * 1024 * 1024); auto large_tx_builder = setAcountDetailTx("foo_1", big_data) .setAccountDetail(kUserId, "foo_2", big_data) .setAccountDetail(kUserId, "foo_3", big_data); - IntegrationTestFramework itf; - itf.setInitialState(kAdminKeypair) + IntegrationTestFramework(2) + .setInitialState(kAdminKeypair) .sendTx(makeUserWithPerms()) - // in itf tx build from large_tx_build will pass in Torii but - // in production the transaction will be failed before - // stateless validation because of size. .sendTx(complete(large_tx_builder)) .skipProposal() .checkBlock( - [](auto &block) { ASSERT_EQ(block->transactions().size(), 1); }); - // this sleep method is a temporary work-around - // because BlockLoaderImpl Failed to retrieve top block - // TODO: IR-1264 neewy 19/04/2018 - std::this_thread::sleep_for(std::chrono::seconds(10)); - itf.done(); + [](auto &block) { ASSERT_EQ(block->transactions().size(), 2); }) + .done(); } /** diff --git a/test/integration/pipeline/pipeline_test.cpp b/test/integration/pipeline/pipeline_test.cpp index c94adbef95..2a9f49c574 100644 --- a/test/integration/pipeline/pipeline_test.cpp +++ b/test/integration/pipeline/pipeline_test.cpp @@ -54,7 +54,7 @@ TEST(PipelineIntegrationTest, SendQuery) { shared_model::interface::StatefulFailedErrorResponse>(), status.get())); }; - integration_framework::IntegrationTestFramework() + integration_framework::IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendQuery(query, check) .done(); @@ -88,7 +88,7 @@ TEST(PipelineIntegrationTest, SendTx) { auto checkBlock = [](auto &block) { ASSERT_EQ(block->transactions().size(), 0); }; - integration_framework::IntegrationTestFramework() + integration_framework::IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(tx, checkStatelessValid) .checkProposal(checkProposal) diff --git a/test/module/shared_model/validators/validators.hpp b/test/module/shared_model/validators/validators.hpp index 29c8d2f991..3ceefbca90 100644 --- a/test/module/shared_model/validators/validators.hpp +++ b/test/module/shared_model/validators/validators.hpp @@ -18,9 +18,6 @@ #ifndef IROHA_VALIDATOR_MOCKS_HPP #define IROHA_VALIDATOR_MOCKS_HPP -#include -#include "interfaces/transaction.hpp" - namespace shared_model { namespace validation { diff --git a/test/regression/regression_test.cpp b/test/regression/regression_test.cpp index 119908265c..566fb6d2ce 100644 --- a/test/regression/regression_test.cpp +++ b/test/regression/regression_test.cpp @@ -43,9 +43,8 @@ TEST(RegressionTest, SequentialInitialization) { auto checkStatelessValid = [](auto &status) { ASSERT_TRUE(boost::apply_visitor( - shared_model::interface:: - SpecifiedVisitor(), + shared_model::interface::SpecifiedVisitor< + shared_model::interface::StatelessValidTxResponse>(), status.get())); }; auto checkProposal = [](auto &proposal) { @@ -55,14 +54,14 @@ TEST(RegressionTest, SequentialInitialization) { ASSERT_EQ(block->transactions().size(), 0); }; { - integration_framework::IntegrationTestFramework(10, [](auto &) {}) + integration_framework::IntegrationTestFramework(1, [](auto &) {}) .setInitialState(kAdminKeypair) .sendTx(tx, checkStatelessValid) .skipProposal() .skipBlock(); } { - integration_framework::IntegrationTestFramework() + integration_framework::IntegrationTestFramework(1) .setInitialState(kAdminKeypair) .sendTx(tx, checkStatelessValid) .checkProposal(checkProposal) @@ -77,7 +76,7 @@ TEST(RegressionTest, SequentialInitialization) { * @then no errors are caused as the result */ TEST(RegressionTest, DoubleCallOfDone) { - integration_framework::IntegrationTestFramework itf; + integration_framework::IntegrationTestFramework itf(1); itf.setInitialState(kAdminKeypair).done(); itf.done(); } From bc7ac25e4b47872ea80da195488f55113d91ba47 Mon Sep 17 00:00:00 2001 From: Nikita Alekseev Date: Thu, 17 May 2018 13:39:01 +0300 Subject: [PATCH 102/110] Add explicit type in result match (#1343) Signed-off-by: Nikita Alekseev --- .../module/shared_model/amount_utils_test.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/test/module/shared_model/amount_utils_test.cpp b/test/module/shared_model/amount_utils_test.cpp index 1d070bb530..f21100f305 100644 --- a/test/module/shared_model/amount_utils_test.cpp +++ b/test/module/shared_model/amount_utils_test.cpp @@ -45,7 +45,8 @@ TEST_F(AmountTest, PlusTest) { shared_model::interface::Amount>> &b_value) { auto c = *a_value.value + *b_value.value; c.match( - [](const auto &c_value) { + [](const iroha::expected::Value> &c_value) { ASSERT_EQ(c_value.value->intValue(), 1334567); ASSERT_EQ(c_value.value->precision(), 3); }, @@ -83,7 +84,8 @@ TEST_F(AmountTest, MinusTest) { shared_model::interface::Amount>> &b_value) { auto c = *a_value.value - *b_value.value; c.match( - [](const auto &c_value) { + [](const iroha::expected::Value> &c_value) { ASSERT_EQ(c_value.value->intValue(), 1134567); ASSERT_EQ(c_value.value->precision(), 3); }, @@ -136,10 +138,11 @@ TEST_F(AmountTest, PrecisionTest) { TEST_F(AmountTest, PlusOverflowsTest) { const std::string &uint256_halfmax = "723700557733226221397318656304299424082937404160253525246609900049457060" - "2495.0"; // 2**252 - 1 + "2495.0"; // 2**252 - 1 iroha::expected::Result, std::shared_ptr> - a = shared_model::builder::DefaultAmountBuilder::fromString(uint256_halfmax); + a = shared_model::builder::DefaultAmountBuilder::fromString( + uint256_halfmax); iroha::expected::Result, std::shared_ptr> @@ -147,17 +150,18 @@ TEST_F(AmountTest, PlusOverflowsTest) { a.match( [&b](const iroha::expected::Value< - std::shared_ptr> &a_value) { + std::shared_ptr> &a_value) { b.match( [&a_value](const iroha::expected::Value> &b_value) { + shared_model::interface::Amount>> &b_value) { auto c = *a_value.value + *b_value.value; c.match( - [](const auto &c_value) { + [](const iroha::expected::Value> &c_value) { FAIL() << "Operation successful but shouldn't"; }, [](const iroha::expected::Error> - &e) { SUCCEED() << *e.error; }); + &e) { SUCCEED() << *e.error; }); }, [](const iroha::expected::Error> &e) { FAIL() << *e.error; From 95037d50d92f92025259592c5481565a98c89b2c Mon Sep 17 00:00:00 2001 From: Vyacheslav Bikbaev Date: Thu, 17 May 2018 16:27:17 +0300 Subject: [PATCH 103/110] fix: trailing spaces, license, links (#1344) Signed-off-by: Vyacheslav Bikbaev --- README.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e7ba224bc9..50ca4195ab 100644 --- a/README.md +++ b/README.md @@ -33,19 +33,17 @@ For more information, such as how to use client libraries in your target program ## Need help? -* Join [telegram chat](https://t.me/joinchat/AgzrTUCZ6edlj6V612n5JQ) where the maintainers team is able to help you -* Communicate in Gitter chat with our development community [![Join the chat at https://gitter.im/hyperledger-iroha/Lobby](https://badges.gitter.im/hyperledger-iroha/Lobby.svg)](https://gitter.im/hyperledger-iroha/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +* Join [telegram chat](https://t.me/hyperledgeriroha) where the maintainers team is able to help you +* Communicate in Gitter chat with our development community [![Join the chat at https://gitter.im/hyperledger-iroha/Lobby](https://badges.gitter.im/hyperledger-iroha/Lobby.svg)](https://gitter.im/hyperledger-iroha/Lobby) * Submit issues via GitHub Iroha repository * Join [HyperLedger RocketChat](https://chat.hyperledger.org) #iroha channel to discuss your concerns and proposals * Use mailing list to spread your word within Iroha development community [hyperledger-iroha@lists.hyperledger.org](mailto:hyperledger-iroha@lists.hyperledger.org) ## License -Copyright 2016 – 2018 Soramitsu Co., Ltd. - -Iroha codebase is licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except -in compliance with the License. You may obtain a copy of the +Iroha codebase is licensed under the Apache License, +Version 2.0 (the "License"); you may not use this file except +in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -54,6 +52,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -Iroha documentation files are made available under the Creative Commons -Attribution 4.0 International License (CC-BY-4.0), available at -http://creativecommons.org/licenses/by/4.0/ \ No newline at end of file +Iroha documentation files are made available under the Creative Commons +Attribution 4.0 International License (CC-BY-4.0), available at +http://creativecommons.org/licenses/by/4.0/ From 2374ce623d2772afd1170be4ec98de54c3826aee Mon Sep 17 00:00:00 2001 From: luckychess Date: Wed, 18 Apr 2018 12:21:27 +0300 Subject: [PATCH 104/110] Fix segfaults in streaming (#1303): - Move condition variable back to local level - Use shared_ptr for local variables - Add mutex to tx processor - Add more debug logs - Handle more corner cases in StatusStream() - Improve cache usage - Add logging for replay transaction case - Add comments for locks in transaction processor - Fix processing of new transaction statuses in CommandService Signed-off-by: luckychess --- irohad/torii/command_client.cpp | 8 +- irohad/torii/command_client.hpp | 3 + irohad/torii/command_service.hpp | 2 +- irohad/torii/impl/command_service.cpp | 107 +++++++++++------- .../impl/transaction_processor_impl.cpp | 28 ++++- .../processor/transaction_processor_impl.hpp | 7 +- libs/cache/abstract_cache.hpp | 5 +- .../irohad/torii/torii_service_test.cpp | 9 +- 8 files changed, 111 insertions(+), 58 deletions(-) diff --git a/irohad/torii/command_client.cpp b/irohad/torii/command_client.cpp index ce9aa2b418..81816c0613 100644 --- a/irohad/torii/command_client.cpp +++ b/irohad/torii/command_client.cpp @@ -17,6 +17,7 @@ limitations under the License. #include "block.pb.h" #include "network/impl/grpc_channel_builder.hpp" +#include "common/byteutils.hpp" #include "torii/command_client.hpp" namespace torii { @@ -28,7 +29,8 @@ namespace torii { : ip_(ip), port_(port), stub_(iroha::network::createClient( - ip + ":" + std::to_string(port))) {} + ip + ":" + std::to_string(port))), + log_(logger::log("CommandSyncClient")) {} CommandSyncClient::CommandSyncClient(const CommandSyncClient &rhs) : CommandSyncClient(rhs.ip_, rhs.port_) {} @@ -69,8 +71,12 @@ namespace torii { std::unique_ptr > reader( stub_->StatusStream(&context, tx)); while (reader->Read(&resp)) { + log_->debug("received new status: {}, hash {}", + resp.tx_status(), + iroha::bytestringToHexstring(resp.tx_hash())); response.push_back(resp); } + reader->Finish(); } void CommandSyncClient::swap(CommandSyncClient &lhs, CommandSyncClient &rhs) { diff --git a/irohad/torii/command_client.hpp b/irohad/torii/command_client.hpp index 1d4ee2d620..ec915d15c4 100644 --- a/irohad/torii/command_client.hpp +++ b/irohad/torii/command_client.hpp @@ -22,6 +22,8 @@ limitations under the License. #include #include +#include "logger/logger.hpp" + namespace torii { /** @@ -67,6 +69,7 @@ namespace torii { std::string ip_; size_t port_; std::unique_ptr stub_; + logger::Logger log_; }; } // namespace torii diff --git a/irohad/torii/command_service.hpp b/irohad/torii/command_service.hpp index 8f24618c64..5a37627ac6 100644 --- a/irohad/torii/command_service.hpp +++ b/irohad/torii/command_service.hpp @@ -125,7 +125,7 @@ namespace torii { override; private: - void checkCacheAndSend( + bool checkCacheAndSend( const boost::optional &resp, grpc::ServerWriter &response_writer) const; diff --git a/irohad/torii/impl/command_service.cpp b/irohad/torii/impl/command_service.cpp index 135fec821d..1004ccdfbf 100644 --- a/irohad/torii/impl/command_service.cpp +++ b/irohad/torii/impl/command_service.cpp @@ -51,21 +51,7 @@ namespace torii { std::static_pointer_cast( iroha_response); auto tx_hash = proto_response->transactionHash(); - auto res = cache_->findItem(tx_hash); - if (not res) { - // TODO 05/03/2018 andrei IR-1046 Server-side shared model object - // factories with move semantics - auto response = shared_model::proto::TransactionStatusBuilder() - .txHash(tx_hash) - .notReceived() - .build(); - cache_->addItem(tx_hash, response.getTransport()); - return; - } - - auto proto_status = proto_response->getTransport().tx_status(); - res->set_tx_status(proto_status); - cache_->addItem(tx_hash, *res); + cache_->addItem(tx_hash, proto_response->getTransport()); }); } @@ -84,6 +70,8 @@ namespace torii { &iroha_tx) { tx_hash = iroha_tx.value.hash(); if (cache_->findItem(tx_hash)) { + log_->warn("Found transaction {} in cache, ignoring", + tx_hash.hex()); return; } @@ -92,7 +80,6 @@ namespace torii { response.set_tx_status( iroha::protocol::TxStatus::STATELESS_VALIDATION_SUCCESS); - cache_->addItem(tx_hash, response); // Send transaction to iroha tx_processor_->transactionHandle( std::make_shared( @@ -115,7 +102,9 @@ namespace torii { iroha::protocol::TxStatus::STATELESS_VALIDATION_FAILED); response.set_error_message(std::move(error.error)); }); - + log_->debug("Torii: adding item to cache: {}, status {} ", + tx_hash.hex(), + response.tx_status()); cache_->addItem(tx_hash, response); } @@ -143,6 +132,9 @@ namespace torii { iroha::bytestringToHexstring(request.tx_hash())); response.set_tx_status(iroha::protocol::TxStatus::NOT_RECEIVED); } + log_->debug("Status: adding item to cache: {}, status {}", + tx_hash.hex(), + response.tx_status()); cache_->addItem(tx_hash, response); } } @@ -159,20 +151,25 @@ namespace torii { iroha::protocol::TxStatusRequest const &request, grpc::ServerWriter &response_writer) { auto resp = cache_->findItem(shared_model::crypto::Hash(request.tx_hash())); - checkCacheAndSend(resp, response_writer); - - bool finished = false; + if (checkCacheAndSend(resp, response_writer)) { + return; + } + auto finished = std::make_shared>(false); auto subscription = rxcpp::composite_subscription(); - auto request_hash = shared_model::crypto::Hash(request.tx_hash()); + auto request_hash = + std::make_shared(request.tx_hash()); - /// condition variable to ensure that current method will not return before + /// Condition variable to ensure that current method will not return before /// transaction is processed or a timeout reached. It blocks current thread /// and waits for thread from subscribe() to unblock. - std::condition_variable cv; + auto cv = std::make_shared(); + + log_->debug("StatusStream before subscribe(), hash: {}", + request_hash->hex()); tx_processor_->transactionNotifier() .filter([&request_hash](auto response) { - return response->transactionHash() == request_hash; + return response->transactionHash() == *request_hash; }) .subscribe( subscription, @@ -181,14 +178,17 @@ namespace torii { auto proto_response = std::static_pointer_cast< shared_model::proto::TransactionResponse>(iroha_response); + log_->debug("subscribe new status: {}, hash {}", + proto_response->toString(), + proto_response->transactionHash().hex()); + iroha::protocol::ToriiResponse resp_sub = proto_response->getTransport(); if (isFinalStatus(resp_sub.tx_status())) { response_writer.WriteLast(resp_sub, grpc::WriteOptions()); - subscription.unsubscribe(); - finished = true; - cv.notify_one(); + *finished = true; + cv->notify_one(); } else { response_writer.Write(resp_sub); } @@ -196,31 +196,57 @@ namespace torii { std::mutex wait_subscription; std::unique_lock lock(wait_subscription); + + log_->debug("StatusStream waiting start, hash: {}", request_hash->hex()); + /// we expect that start_tx_processing_duration_ will be enough /// to at least start tx processing. /// Otherwise we think there is no such tx at all. - cv.wait_for(lock, start_tx_processing_duration_); - if (not finished) { + cv->wait_for(lock, start_tx_processing_duration_); + + log_->debug("StatusStream waiting finish, hash: {}", request_hash->hex()); + + if (not *finished) { if (not resp) { - subscription.unsubscribe(); + log_->warn("StatusStream request processing timeout, hash: {}", + request_hash->hex()); // TODO 05/03/2018 andrei IR-1046 Server-side shared model object // factories with move semantics auto resp_none = shared_model::proto::TransactionStatusBuilder() - .txHash(request_hash) + .txHash(*request_hash) .notReceived() .build(); response_writer.WriteLast(resp_none.getTransport(), grpc::WriteOptions()); } else { - log_->info( + log_->debug( "Tx processing was started but unfinished, awaiting more, hash: {}", - request_hash.hex()); + request_hash->hex()); /// We give it 2*proposal_delay time until timeout. - cv.wait_for(lock, 2 * proposal_delay_); + cv->wait_for(lock, 2 * proposal_delay_); + + /// status can be in the cache if it was finalized before we subscribed + if (not *finished) { + log_->debug("Transaction {} still not finished", request_hash->hex()); + + auto cache_second_check = + cache_->findItem(shared_model::crypto::Hash(request.tx_hash())); + log_->debug("Status in cache: {}", cache_second_check->tx_status()); + + /// final status means the case from a comment above + /// if it's not - let's ignore it for now + if (isFinalStatus(cache_second_check->tx_status())) { + log_->warn("Transaction was finalized before subscription"); + response_writer.WriteLast(*resp, grpc::WriteOptions()); + } + } } } else { - log_->warn("Command processing timeout, hash: {}", request_hash.hex()); + log_->debug("StatusStream request processed successfully, hash: {}", + request_hash->hex()); } + subscription.unsubscribe(); + log_->debug("StatusStream unsubscribed"); } grpc::Status CommandService::StatusStream( @@ -231,19 +257,22 @@ namespace torii { return grpc::Status::OK; } - void CommandService::checkCacheAndSend( + bool CommandService::checkCacheAndSend( const boost::optional &resp, grpc::ServerWriter &response_writer) const { if (resp) { if (isFinalStatus(resp->tx_status())) { + log_->debug("Transaction {} in service cache and final", + iroha::bytestringToHexstring(resp->tx_hash())); response_writer.WriteLast(*resp, grpc::WriteOptions()); - return; + return true; } + log_->debug("Transaction {} in service cache and not final", + iroha::bytestringToHexstring(resp->tx_hash())); response_writer.Write(*resp); - } else { - log_->debug("Transaction miss service cache"); } + return false; } bool CommandService::isFinalStatus( diff --git a/irohad/torii/processor/impl/transaction_processor_impl.cpp b/irohad/torii/processor/impl/transaction_processor_impl.cpp index 228cdf3c1a..cc2a2c2fea 100644 --- a/irohad/torii/processor/impl/transaction_processor_impl.cpp +++ b/irohad/torii/processor/impl/transaction_processor_impl.cpp @@ -36,8 +36,13 @@ namespace iroha { for (const auto &tx : model_proposal->transactions()) { auto hash = tx->hash(); proposal_set_.insert(hash); + log_->info("on proposal stateless success: {}", hash.hex()); + // different on_next() calls (this one and below) can happen in + // different threads and we don't expect emitting them concurrently + std::lock_guard lock(notifier_mutex_); notifier_.get_subscriber().on_next( - status_builder_.statelessValidationSuccess() + shared_model::builder::DefaultTransactionStatusBuilder() + .statelessValidationSuccess() .txHash(hash) .build()); } @@ -53,8 +58,11 @@ namespace iroha { if (this->proposal_set_.find(hash) != proposal_set_.end()) { proposal_set_.erase(hash); candidate_set_.insert(hash); + log_->info("on commit stateful success: {}", hash.hex()); + std::lock_guard lock(notifier_mutex_); notifier_.get_subscriber().on_next( - status_builder_.statefulValidationSuccess() + shared_model::builder::DefaultTransactionStatusBuilder() + .statefulValidationSuccess() .txHash(hash) .build()); } @@ -62,17 +70,25 @@ namespace iroha { }, // on complete [this]() { - for (auto& tx_hash : proposal_set_) { + for (auto &tx_hash : proposal_set_) { + log_->info("on commit stateful failed: {}", tx_hash.hex()); + std::lock_guard lock(notifier_mutex_); notifier_.get_subscriber().on_next( - status_builder_.statefulValidationFailed() + shared_model::builder::DefaultTransactionStatusBuilder() + .statefulValidationFailed() .txHash(tx_hash) .build()); } proposal_set_.clear(); - for (auto tx_hash : candidate_set_) { + for (auto &tx_hash : candidate_set_) { + log_->info("on commit committed: {}", tx_hash.hex()); + std::lock_guard lock(notifier_mutex_); notifier_.get_subscriber().on_next( - status_builder_.committed().txHash(tx_hash).build()); + shared_model::builder::DefaultTransactionStatusBuilder() + .committed() + .txHash(tx_hash) + .build()); } candidate_set_.clear(); }); diff --git a/irohad/torii/processor/transaction_processor_impl.hpp b/irohad/torii/processor/transaction_processor_impl.hpp index 3bb14dd1eb..261fcc90b6 100644 --- a/irohad/torii/processor/transaction_processor_impl.hpp +++ b/irohad/torii/processor/transaction_processor_impl.hpp @@ -18,6 +18,7 @@ #ifndef IROHA_TRANSACTION_PROCESSOR_STUB_HPP #define IROHA_TRANSACTION_PROCESSOR_STUB_HPP +#include #include "builders/default_builders.hpp" #include "interfaces/transaction_responses/tx_response.hpp" #include "logger/logger.hpp" @@ -60,9 +61,11 @@ namespace iroha { std::shared_ptr> notifier_; - shared_model::builder::DefaultTransactionStatusBuilder status_builder_; - logger::Logger log_; + + /// prevents from emitting new tx statuses from different threads + /// in parallel + std::mutex notifier_mutex_; }; } // namespace torii } // namespace iroha diff --git a/libs/cache/abstract_cache.hpp b/libs/cache/abstract_cache.hpp index 1e575f9a70..fdab575acf 100644 --- a/libs/cache/abstract_cache.hpp +++ b/libs/cache/abstract_cache.hpp @@ -69,7 +69,7 @@ namespace iroha { * @param value - value to insert */ void addItem(const KeyType &key, const ValueType &value) { - std::lock_guard lock(add_item_mutex_); + std::lock_guard lock(access_mutex_); underlying().addItemImpl(key, value); } @@ -79,6 +79,7 @@ namespace iroha { * @return Optional of ValueType */ boost::optional findItem(const KeyType &key) const { + std::lock_guard lock(access_mutex_); return constUnderlying().findItemImpl(key); } @@ -90,7 +91,7 @@ namespace iroha { return static_cast(*this); } - std::mutex add_item_mutex_; + mutable std::mutex access_mutex_; }; } // namespace cache } // namespace iroha diff --git a/test/module/irohad/torii/torii_service_test.cpp b/test/module/irohad/torii/torii_service_test.cpp index 212f7079ab..7f8d3fa1f2 100644 --- a/test/module/irohad/torii/torii_service_test.cpp +++ b/test/module/irohad/torii/torii_service_test.cpp @@ -335,11 +335,6 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { using namespace shared_model; auto client = torii::CommandSyncClient(Ip, Port); - - auto new_tx = TestTransactionBuilder() - .creatorAccountId("accountA") - .build(); - auto iroha_tx = proto::TransactionBuilder() .creatorAccountId("a@domain") .setAccountQuorum("a@domain", 2) @@ -359,7 +354,7 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { client.StatusStream(tx_request, torii_response); }); - client.Torii(new_tx.getTransport()); + client.Torii(iroha_tx.getTransport()); std::vector txs; txs.push_back(iroha_tx); @@ -391,7 +386,7 @@ TEST_F(ToriiServiceTest, StreamingFullPipelineTest) { block_notifier_.get_subscriber().on_completed(); t.join(); - ASSERT_GE(torii_response.size(), 3); + ASSERT_GE(torii_response.size(), 2); ASSERT_EQ(torii_response.back().tx_status(), iroha::protocol::TxStatus::COMMITTED); } From 0c4f014eaf364fa2451d50e4d35740433a59f7b4 Mon Sep 17 00:00:00 2001 From: Dumitru Date: Thu, 17 May 2018 19:03:33 +0300 Subject: [PATCH 105/110] Remove makeOldModel (#1346) * Remove makeOldModel Signed-off-by: Dumitru * Remove from old model Signed-off-by: Dumitru * Remove from_old file Signed-off-by: Dumitru --- iroha-cli/client.cpp | 19 +-- iroha-cli/client.hpp | 16 +-- .../impl/interactive_query_cli.cpp | 12 +- .../impl/interactive_transaction_cli.cpp | 21 +-- iroha-cli/main.cpp | 31 +++- .../ametsuchi/impl/mutable_storage_impl.cpp | 1 - .../generators/impl/transaction_generator.cpp | 19 ++- .../backend/protobuf/from_old_model.hpp | 134 ------------------ test/module/iroha-cli/client_test.cpp | 15 +- .../converters/pb_query_factory_test.cpp | 7 +- 10 files changed, 87 insertions(+), 188 deletions(-) delete mode 100644 shared_model/backend/protobuf/from_old_model.hpp diff --git a/iroha-cli/client.cpp b/iroha-cli/client.cpp index 0e4a0f86af..a9cb123342 100644 --- a/iroha-cli/client.cpp +++ b/iroha-cli/client.cpp @@ -16,6 +16,9 @@ */ #include "client.hpp" + +#include "backend/protobuf/queries/proto_query.hpp" +#include "backend/protobuf/transaction.hpp" #include "model/converters/json_query_factory.hpp" #include "model/converters/json_transaction_factory.hpp" #include "model/converters/pb_query_factory.hpp" @@ -27,13 +30,12 @@ namespace iroha_cli { : command_client_(target_ip, port), query_client_(target_ip, port) {} CliClient::Response CliClient::sendTx( - iroha::model::Transaction tx) { + const shared_model::interface::Transaction &tx) { + const auto proto_tx = + static_cast(tx); CliClient::Response response; - // Convert to protobuf - iroha::model::converters::PbTransactionFactory factory; - auto pb_tx = factory.serialize(tx); // Send to iroha: - response.status = command_client_.Torii(pb_tx); + response.status = command_client_.Torii(proto_tx.getTransport()); // TODO 12/10/2017 neewy implement return of real transaction status IR-494 response.answer = TxStatus::OK; @@ -55,13 +57,14 @@ namespace iroha_cli { } CliClient::Response CliClient::sendQuery( - std::shared_ptr query) { + const shared_model::interface::Query &query) { CliClient::Response response; // Convert to proto and send to Iroha iroha::model::converters::PbQueryFactory pb_factory; - auto pb_query = pb_factory.serialize(query); + auto proto_query = static_cast(query); iroha::protocol::QueryResponse query_response; - response.status = query_client_.Find(pb_query.value(), query_response); + response.status = + query_client_.Find(proto_query.getTransport(), query_response); response.answer = query_response; return response; } diff --git a/iroha-cli/client.hpp b/iroha-cli/client.hpp index 1458b86923..16c41c4abd 100644 --- a/iroha-cli/client.hpp +++ b/iroha-cli/client.hpp @@ -23,12 +23,12 @@ #include "torii/command_client.hpp" #include "torii/query_client.hpp" -namespace iroha { - namespace model { - struct Query; - struct Transaction; - } -} +namespace shared_model { + namespace interface { + class Transaction; + class Query; + } // namespace interface +} // namespace shared_model namespace iroha_cli { @@ -50,7 +50,7 @@ namespace iroha_cli { * @return */ CliClient::Response sendTx( - iroha::model::Transaction tx); + const shared_model::interface::Transaction &tx); /** * Send Query to Iroha Peer, i.e. target_ip:port @@ -58,7 +58,7 @@ namespace iroha_cli { * @return */ CliClient::Response sendQuery( - std::shared_ptr query); + const shared_model::interface::Query &query); CliClient::Response getTxStatus( std::string tx_hash); diff --git a/iroha-cli/interactive/impl/interactive_query_cli.cpp b/iroha-cli/interactive/impl/interactive_query_cli.cpp index 3c1f6a362f..8a9b6047b7 100644 --- a/iroha-cli/interactive/impl/interactive_query_cli.cpp +++ b/iroha-cli/interactive/impl/interactive_query_cli.cpp @@ -18,6 +18,8 @@ #include #include +#include "backend/protobuf/queries/proto_query.hpp" + #include "client.hpp" #include "common/byteutils.hpp" #include "crypto/keys_manager_impl.hpp" @@ -26,6 +28,7 @@ #include "grpc_response_handler.hpp" #include "interactive/interactive_query_cli.hpp" #include "model/converters/json_query_factory.hpp" +#include "model/converters/pb_query_factory.hpp" #include "model/model_crypto_provider.hpp" // for ModelCryptoProvider #include "model/queries/get_asset_info.hpp" #include "model/queries/get_roles.hpp" @@ -194,9 +197,8 @@ namespace iroha_cli { GetTransactions::TxHashCollectionType tx_hashes; std::for_each( params.begin(), params.end(), [&tx_hashes](auto const &hex_hash) { - if (auto opt = iroha:: - hexstringToArray( - hex_hash)) { + if (auto opt = iroha::hexstringToArray< + GetTransactions::TxHashType::size()>(hex_hash)) { tx_hashes.push_back(*opt); } }); @@ -262,7 +264,9 @@ namespace iroha_cli { provider_->sign(*query_); CliClient client(address.value().first, address.value().second); - GrpcResponseHandler{}.handle(client.sendQuery(query_)); + auto query = shared_model::proto::Query( + *iroha::model::converters::PbQueryFactory().serialize(query_)); + GrpcResponseHandler{}.handle(client.sendQuery(query)); printEnd(); // Stop parsing return false; diff --git a/iroha-cli/interactive/impl/interactive_transaction_cli.cpp b/iroha-cli/interactive/impl/interactive_transaction_cli.cpp index d7849a029f..02b095a6e1 100644 --- a/iroha-cli/interactive/impl/interactive_transaction_cli.cpp +++ b/iroha-cli/interactive/impl/interactive_transaction_cli.cpp @@ -19,6 +19,8 @@ #include #include + +#include "backend/protobuf/transaction.hpp" #include "client.hpp" #include "grpc_response_handler.hpp" #include "model/commands/append_role.hpp" @@ -30,10 +32,11 @@ #include "model/converters/json_common.hpp" #include "model/converters/json_transaction_factory.hpp" #include "model/converters/pb_common.hpp" +#include "model/converters/pb_transaction_factory.hpp" #include "model/model_crypto_provider.hpp" // for ModelCryptoProvider -#include "validators/permissions.hpp" #include "model/sha3_hash.hpp" #include "parser/parser.hpp" // for parser::ParseValue +#include "validators/permissions.hpp" using namespace iroha::model; using namespace shared_model::permissions; @@ -251,9 +254,7 @@ namespace iroha_cli { auto create_account = parser::parseValue(params[8]); if (not(read_self and edit_self and read_all and transfer_receive - and asset_create - and create_domain - and roles + and asset_create and create_domain and roles and create_account)) { std::cout << "Wrong format for permission" << std::endl; return nullptr; @@ -471,17 +472,18 @@ namespace iroha_cli { // Forming a transaction - auto tx = - tx_generator_.generateTransaction(creator_, commands_); + auto tx = tx_generator_.generateTransaction(creator_, commands_); // clear commands so that we can start creating new tx commands_.clear(); provider_->sign(tx); GrpcResponseHandler response_handler; - + auto shared_tx = shared_model::proto::Transaction( + iroha::model::converters::PbTransactionFactory().serialize(tx)); response_handler.handle( - CliClient(address.value().first, address.value().second).sendTx(tx)); + CliClient(address.value().first, address.value().second) + .sendTx(shared_tx)); printTxHash(tx); printEnd(); @@ -500,8 +502,7 @@ namespace iroha_cli { } // Forming a transaction - auto tx = - tx_generator_.generateTransaction(creator_, commands_); + auto tx = tx_generator_.generateTransaction(creator_, commands_); // clear commands so that we can start creating new tx commands_.clear(); diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index bc203e02df..8b0c730fa8 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -22,7 +22,7 @@ #include #include -#include "backend/protobuf/from_old_model.hpp" +#include "backend/protobuf/queries/proto_query.hpp" #include "client.hpp" #include "common/assert_config.hpp" #include "converters/protobuf/json_proto_converter.hpp" @@ -31,6 +31,9 @@ #include "interactive/interactive_cli.hpp" #include "model/converters/json_block_factory.hpp" #include "model/converters/json_query_factory.hpp" +#include "model/converters/pb_block_factory.hpp" +#include "model/converters/pb_query_factory.hpp" +#include "model/converters/pb_transaction_factory.hpp" #include "model/generators/block_generator.hpp" #include "model/model_crypto_provider_impl.hpp" #include "validators.hpp" @@ -74,6 +77,14 @@ using namespace iroha::model::converters; using namespace iroha_cli::interactive; namespace fs = boost::filesystem; +iroha::keypair_t *makeOldModel(const shared_model::crypto::Keypair &keypair) { + return new iroha::keypair_t{ + shared_model::crypto::PublicKey::OldPublicKeyType::from_string( + toBinaryString(keypair.publicKey())), + shared_model::crypto::PrivateKey::OldPrivateKeyType::from_string( + toBinaryString(keypair.privateKey()))}; +} + int main(int argc, char *argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); gflags::ShutDownCommandLineFlags(); @@ -114,9 +125,9 @@ int main(int argc, char *argv[]) { auto block = generator.generateGenesisBlock(0, {transaction}); // Convert to json std::ofstream output_file("genesis.block"); - output_file << shared_model::converters::protobuf::modelToJson( - shared_model::proto::from_old(block) - ); + auto bl = shared_model::proto::Block( + iroha::model::converters::PbBlockFactory().serialize(block)); + output_file << shared_model::converters::protobuf::modelToJson(bl); logger->info("File saved to genesis.block"); } // Create new pub/priv key, register in Iroha Network @@ -151,7 +162,10 @@ int main(int argc, char *argv[]) { if (not tx_opt) { logger->error("Json transaction has wrong format."); } else { - response_handler.handle(client.sendTx(tx_opt.value())); + auto tx = shared_model::proto::Transaction( + iroha::model::converters::PbTransactionFactory().serialize( + *tx_opt)); + response_handler.handle(client.sendTx(tx)); } } if (not FLAGS_json_query.empty()) { @@ -164,7 +178,10 @@ int main(int argc, char *argv[]) { if (not query_opt) { logger->error("Json has wrong format."); } else { - response_handler.handle(client.sendQuery(query_opt.value())); + auto query = shared_model::proto::Query( + *iroha::model::converters::PbQueryFactory().serialize(*query_opt)); + auto response = client.sendQuery(query); + response_handler.handle(response); } } } @@ -201,7 +218,7 @@ int main(int argc, char *argv[]) { FLAGS_torii_port, 0, std::make_shared( - *std::unique_ptr(keypair->makeOldModel()))); + *std::unique_ptr(makeOldModel(*keypair)))); interactiveCli.run(); } else { logger->error("Invalid flags"); diff --git a/irohad/ametsuchi/impl/mutable_storage_impl.cpp b/irohad/ametsuchi/impl/mutable_storage_impl.cpp index f60b911be6..2baaf5e8e3 100644 --- a/irohad/ametsuchi/impl/mutable_storage_impl.cpp +++ b/irohad/ametsuchi/impl/mutable_storage_impl.cpp @@ -23,7 +23,6 @@ #include "ametsuchi/impl/postgres_wsv_command.hpp" #include "ametsuchi/impl/postgres_wsv_query.hpp" #include "ametsuchi/wsv_command.hpp" -#include "backend/protobuf/from_old_model.hpp" #include "model/sha3_hash.hpp" namespace iroha { diff --git a/irohad/model/generators/impl/transaction_generator.cpp b/irohad/model/generators/impl/transaction_generator.cpp index 1e570e3809..fe44cde0e1 100644 --- a/irohad/model/generators/impl/transaction_generator.cpp +++ b/irohad/model/generators/impl/transaction_generator.cpp @@ -25,6 +25,16 @@ namespace iroha { namespace model { namespace generators { + + iroha::keypair_t *makeOldModel( + const shared_model::crypto::Keypair &keypair) { + return new iroha::keypair_t{ + shared_model::crypto::PublicKey::OldPublicKeyType::from_string( + toBinaryString(keypair.publicKey())), + shared_model::crypto::PrivateKey::OldPrivateKeyType::from_string( + toBinaryString(keypair.privateKey()))}; + } + Transaction TransactionGenerator::generateGenesisTransaction( ts64_t timestamp, std::vector peers_address) { Transaction tx; @@ -35,7 +45,8 @@ namespace iroha { for (size_t i = 0; i < peers_address.size(); ++i) { KeysManagerImpl manager("node" + std::to_string(i)); manager.createKeys(); - auto keypair = *std::unique_ptr(manager.loadKeys()->makeOldModel()); + auto keypair = *std::unique_ptr( + makeOldModel(*manager.loadKeys())); tx.commands.push_back(command_generator.generateAddPeer( Peer(peers_address[i], keypair.pubkey))); } @@ -56,12 +67,14 @@ namespace iroha { // Create accounts KeysManagerImpl manager("admin@test"); manager.createKeys(); - auto keypair = *std::unique_ptr(manager.loadKeys()->makeOldModel()); + auto keypair = *std::unique_ptr( + makeOldModel(*manager.loadKeys())); tx.commands.push_back(command_generator.generateCreateAccount( "admin", "test", keypair.pubkey)); manager = KeysManagerImpl("test@test"); manager.createKeys(); - keypair = *std::unique_ptr(manager.loadKeys()->makeOldModel()); + keypair = *std::unique_ptr( + makeOldModel(*manager.loadKeys())); tx.commands.push_back(command_generator.generateCreateAccount( "test", "test", keypair.pubkey)); diff --git a/shared_model/backend/protobuf/from_old_model.hpp b/shared_model/backend/protobuf/from_old_model.hpp deleted file mode 100644 index 73730b8a91..0000000000 --- a/shared_model/backend/protobuf/from_old_model.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. 2018 All Rights Reserved. - * http://soramitsu.co.jp - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SHARED_MODEL_FROM_OLD_HPP -#define SHARED_MODEL_FROM_OLD_HPP -#ifndef DISABLE_BACKWARD - -#include - -#include "backend/protobuf/block.hpp" -#include "backend/protobuf/proposal.hpp" -#include "backend/protobuf/queries/proto_query.hpp" -#include "backend/protobuf/query_responses/proto_query_response.hpp" -#include "backend/protobuf/transaction.hpp" -#include "builders/protobuf/proposal.hpp" -#include "model/converters/pb_block_factory.hpp" -#include "model/converters/pb_command_factory.hpp" -#include "model/converters/pb_query_factory.hpp" -#include "model/converters/pb_query_response_factory.hpp" -#include "model/converters/pb_transaction_factory.hpp" - -#include "backend/protobuf/common_objects/account.hpp" -#include "backend/protobuf/common_objects/account_asset.hpp" -#include "backend/protobuf/common_objects/asset.hpp" -#include "backend/protobuf/common_objects/domain.hpp" -#include "backend/protobuf/common_objects/peer.hpp" -#include "model/converters/pb_common.hpp" - -namespace shared_model { - namespace proto { - - inline static shared_model::proto::Block from_old( - const iroha::model::Block &block) { - return shared_model::proto::Block( - iroha::model::converters::PbBlockFactory().serialize(block)); - } - - inline static shared_model::proto::Transaction from_old( - const iroha::model::Transaction &tx) { - return shared_model::proto::Transaction( - iroha::model::converters::PbTransactionFactory().serialize(tx)); - } - - inline static shared_model::proto::Query from_old( - std::shared_ptr qry) { - return shared_model::proto::Query( - *iroha::model::converters::PbQueryFactory().serialize(qry)); - } - - inline static shared_model::proto::Proposal from_old( - const iroha::model::Proposal &proposal) { - return shared_model::proto::ProposalBuilder() - .height(proposal.height) - .createdTime(proposal.created_time) - .transactions(proposal.transactions - | boost::adaptors::transformed( - [](auto &tx) { return from_old(tx); })) - .build(); - } - - inline static shared_model::proto::QueryResponse from_old( - std::shared_ptr queryResponse) { - auto proto_resp = - *iroha::model::converters::PbQueryResponseFactory().serialize( - queryResponse); - auto res = shared_model::proto::QueryResponse(std::move(proto_resp)); - auto hash = res.queryHash(); - return shared_model::proto::QueryResponse( - *iroha::model::converters::PbQueryResponseFactory().serialize( - queryResponse)); - } - - inline static shared_model::proto::Account from_old( - const iroha::model::Account &account) { - return shared_model::proto::Account( - iroha::model::converters::serializeAccount(account)); - } - - inline static shared_model::proto::Peer from_old( - const iroha::model::Peer &peer) { - return shared_model::proto::Peer( - iroha::model::converters::serializePeer(peer)); - } - - inline static shared_model::proto::Asset from_old( - const iroha::model::Asset &asset) { - return shared_model::proto::Asset( - iroha::model::converters::serializeAsset(asset)); - } - - inline static shared_model::proto::AccountAsset from_old( - const iroha::model::AccountAsset &account_asset) { - return shared_model::proto::AccountAsset( - iroha::model::converters::serializeAccountAsset(account_asset)); - } - - inline static shared_model::proto::Domain from_old( - const iroha::model::Domain &domain) { - return shared_model::proto::Domain( - iroha::model::converters::serializeDomain(domain)); - } - - inline static shared_model::proto::Amount from_old( - const iroha::Amount &amount) { - return shared_model::proto::Amount( - iroha::model::converters::serializeAmount(amount)); - } - - inline static shared_model::proto::Command from_old( - const iroha::model::Command &command) { - return shared_model::proto::Command( - iroha::model::converters::PbCommandFactory().serializeAbstractCommand( - command)); - } - - } // namespace proto -} // namespace shared_model - -#endif // DISABLE_BACKWARD -#endif // SHARED_MODEL_FROM_OLD_HPP diff --git a/test/module/iroha-cli/client_test.cpp b/test/module/iroha-cli/client_test.cpp index 8170c1c5ea..eab8f360ce 100644 --- a/test/module/iroha-cli/client_test.cpp +++ b/test/module/iroha-cli/client_test.cpp @@ -129,8 +129,7 @@ TEST_F(ClientServerTest, SendTxWhenValid) { shared_model::crypto::DefaultCryptoAlgorithmType:: generateKeypair()); - std::unique_ptr old_model(shm_tx.makeOldModel()); - auto status = client.sendTx(*old_model); + auto status = client.sendTx(shm_tx); ASSERT_EQ(status.answer, iroha_cli::CliClient::OK); } @@ -162,9 +161,8 @@ TEST_F(ClientServerTest, SendTxWhenStatelessInvalid) { .createdTime(iroha::time::now()) .setAccountQuorum("some@@account", 2) .build(); - std::unique_ptr old_tx(shm_tx.makeOldModel()); - ASSERT_EQ(iroha_cli::CliClient(Ip, Port).sendTx(*old_tx).answer, + ASSERT_EQ(iroha_cli::CliClient(Ip, Port).sendTx(shm_tx).answer, iroha_cli::CliClient::OK); auto tx_hash = shm_tx.hash(); auto res = iroha_cli::CliClient(Ip, Port).getTxStatus( @@ -205,8 +203,7 @@ TEST_F(ClientServerTest, SendQueryWhenStatelessInvalid) { .build(); auto proto_query = query.getTransport(); - auto res = client.sendQuery( - std::shared_ptr(query.makeOldModel())); + auto res = client.sendQuery(query); ASSERT_TRUE(res.status.ok()); ASSERT_TRUE(res.answer.has_error_response()); ASSERT_EQ(res.answer.error_response().reason(), @@ -243,8 +240,7 @@ TEST_F(ClientServerTest, SendQueryWhenValid) { .build() .signAndAddSignature(pair); - auto res = client.sendQuery( - std::shared_ptr(query.makeOldModel())); + auto res = client.sendQuery(query); ASSERT_EQ(res.answer.account_detail_response().detail(), "value"); } @@ -273,8 +269,7 @@ TEST_F(ClientServerTest, SendQueryWhenStatefulInvalid) { .build() .signAndAddSignature(pair); - auto res = client.sendQuery( - std::shared_ptr(query.makeOldModel())); + auto res = client.sendQuery(query); ASSERT_EQ(res.answer.error_response().reason(), iroha::protocol::ErrorResponse::STATEFUL_INVALID); } diff --git a/test/module/irohad/model/converters/pb_query_factory_test.cpp b/test/module/irohad/model/converters/pb_query_factory_test.cpp index 2560bc3185..60cb2a4f69 100644 --- a/test/module/irohad/model/converters/pb_query_factory_test.cpp +++ b/test/module/irohad/model/converters/pb_query_factory_test.cpp @@ -15,13 +15,14 @@ * limitations under the License. */ -#include "model/converters/pb_query_factory.hpp" #include -#include "model/generators/query_generator.hpp" -#include "model/sha3_hash.hpp" +#include "model/converters/pb_query_factory.hpp" +#include "model/converters/pb_transaction_factory.hpp" +#include "model/generators/query_generator.hpp" #include "model/queries/get_asset_info.hpp" #include "model/queries/get_roles.hpp" +#include "model/sha3_hash.hpp" using namespace iroha::model::converters; using namespace iroha::model::generators; From c87dec028a57fdf58ca481cc96323c8f5340d275 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bikbaev Date: Fri, 18 May 2018 10:09:00 +0300 Subject: [PATCH 106/110] fix: email in contributors (#1352) Signed-off-by: Vyacheslav Bikbaev --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a531fc7495..1885c6f9c2 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -23,7 +23,7 @@ This is the list of maintainers, including their email address for direct commun | Igor Egorov | @igor-egorov | igor@soramitsu.co.jp | Development, Android library | | Konstantin Munichev | @luckychess | konstantin@soramitsu.co.jp | Security | | Evgenii Mininbaev | @l4l | evgenii@soramitsu.co.jp | Security, Python library | -| Vyacheslav Bikbaev | @laSinteZ | bikbaev@soramitsu.co.jp | Documentation, NodeJS library | +| Vyacheslav Bikbaev | @laSinteZ | viacheslav@soramitsu.co.jp | Documentation, NodeJS library | | Arseniy Fokin | @stinger112 | stinger112@gmail.com | NodeJS library | | Alexey Chernyshov | @Alexey-N-Chernyshov | chernyshov@soramitsu.co.jp | Development | | Artyom Bakhtin | @bakhtin | a@bakhtin.net | Ansible, Jenkins, artifacts | From 5c0631aadc3c9d87a75b8357015064a2be046e30 Mon Sep 17 00:00:00 2001 From: Igor Egorov <36847043+igor-egorov@users.noreply.github.com> Date: Fri, 18 May 2018 10:54:49 +0300 Subject: [PATCH 107/110] Fix build issues related to changes in "amount utils" (#1349) Signed-off-by: Igor Egorov --- shared_model/utils/CMakeLists.txt | 4 ++++ shared_model/utils/amount_utils.cpp | 4 ++++ shared_model/utils/amount_utils.hpp | 6 ++++-- test/module/shared_model/amount_utils_test.cpp | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/shared_model/utils/CMakeLists.txt b/shared_model/utils/CMakeLists.txt index 9301746fc9..1b7146d58a 100644 --- a/shared_model/utils/CMakeLists.txt +++ b/shared_model/utils/CMakeLists.txt @@ -2,3 +2,7 @@ add_library(shared_model_amount_utils amount_utils.cpp ) + +target_link_libraries(shared_model_amount_utils + shared_model_proto_backend + ) diff --git a/shared_model/utils/amount_utils.cpp b/shared_model/utils/amount_utils.cpp index 44f98d8ea5..45a88d5a10 100644 --- a/shared_model/utils/amount_utils.cpp +++ b/shared_model/utils/amount_utils.cpp @@ -16,8 +16,12 @@ */ #include "utils/amount_utils.hpp" + #include +#include "builders/default_builders.hpp" +#include "builders/protobuf/common_objects/proto_amount_builder.hpp" + namespace shared_model { namespace detail { const boost::multiprecision::uint256_t ten = 10; diff --git a/shared_model/utils/amount_utils.hpp b/shared_model/utils/amount_utils.hpp index 781ae98a86..6d92c0c2d7 100644 --- a/shared_model/utils/amount_utils.hpp +++ b/shared_model/utils/amount_utils.hpp @@ -20,11 +20,13 @@ #include -#include "builders/default_builders.hpp" -#include "builders/protobuf/common_objects/proto_amount_builder.hpp" #include "common/result.hpp" namespace shared_model { + namespace interface { + class Amount; + } // namespace interface + namespace detail { boost::multiprecision::uint256_t increaseValuePrecision( boost::multiprecision::uint256_t value, int degree); diff --git a/test/module/shared_model/amount_utils_test.cpp b/test/module/shared_model/amount_utils_test.cpp index f21100f305..114eabd626 100644 --- a/test/module/shared_model/amount_utils_test.cpp +++ b/test/module/shared_model/amount_utils_test.cpp @@ -17,6 +17,7 @@ #include +#include "builders/default_builders.hpp" #include "utils/amount_utils.hpp" using namespace shared_model::detail; From f030fccfb519c0e4c3c5038a42f49a6229629b63 Mon Sep 17 00:00:00 2001 From: Igor Egorov <36847043+igor-egorov@users.noreply.github.com> Date: Fri, 18 May 2018 12:15:56 +0300 Subject: [PATCH 108/110] Fix segfault when non intialized ITF was destructed (#1353) Signed-off-by: Igor Egorov --- .../integration_test_framework.cpp | 4 +++- test/regression/regression_test.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/framework/integration_framework/integration_test_framework.cpp b/test/framework/integration_framework/integration_test_framework.cpp index 6ae70729dd..04979b6323 100644 --- a/test/framework/integration_framework/integration_test_framework.cpp +++ b/test/framework/integration_framework/integration_test_framework.cpp @@ -229,6 +229,8 @@ namespace integration_framework { void IntegrationTestFramework::done() { log_->info("done"); - iroha_instance_->instance_->storage->dropStorage(); + if (iroha_instance_->instance_ and iroha_instance_->instance_->storage) { + iroha_instance_->instance_->storage->dropStorage(); + } } } // namespace integration_framework diff --git a/test/regression/regression_test.cpp b/test/regression/regression_test.cpp index 566fb6d2ce..18fe37f882 100644 --- a/test/regression/regression_test.cpp +++ b/test/regression/regression_test.cpp @@ -80,3 +80,13 @@ TEST(RegressionTest, DoubleCallOfDone) { itf.setInitialState(kAdminKeypair).done(); itf.done(); } + +/** + * @given non initialized ITF instance + * @when done method is called inside destructor + * @then no exceptions are risen + */ +TEST(RegressionTest, DestructionOfNonInitializedItf) { + integration_framework::IntegrationTestFramework itf( + 1, [](auto &itf) { itf.done(); }); +} From 036cac895be5b4e93f4b8005744d7c97a7cb891b Mon Sep 17 00:00:00 2001 From: Artyom Bakhtin Date: Fri, 18 May 2018 17:43:19 +0300 Subject: [PATCH 109/110] fix findgrpc command (#1355) Signed-off-by: Artyom Bakhtin --- cmake/Modules/Findgrpc.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/Modules/Findgrpc.cmake b/cmake/Modules/Findgrpc.cmake index 5bf71b0f49..2dde985c0f 100644 --- a/cmake/Modules/Findgrpc.cmake +++ b/cmake/Modules/Findgrpc.cmake @@ -15,6 +15,9 @@ mark_as_advanced(grpc_grpc++_LIBRARY) find_library(gpr_LIBRARY gpr) mark_as_advanced(gpr_LIBRARY) +find_library(address_sorting_LIBRARY address_sorting) +mark_as_advanced(address_sorting_LIBRARY) + find_program(grpc_CPP_PLUGIN grpc_cpp_plugin) mark_as_advanced(grpc_CPP_PLUGIN) @@ -54,6 +57,7 @@ if (NOT grpc_FOUND) set(gpr_LIBRARY ${binary_dir}/${CMAKE_SHARED_LIBRARY_PREFIX}gpr${CMAKE_SHARED_LIBRARY_SUFFIX}) set(grpc_LIBRARY ${binary_dir}/${CMAKE_SHARED_LIBRARY_PREFIX}grpc${CMAKE_SHARED_LIBRARY_SUFFIX}) set(grpc_grpc++_LIBRARY ${binary_dir}/${CMAKE_SHARED_LIBRARY_PREFIX}grpc++${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(address_sorting_LIBRARY ${binary_dir}/${CMAKE_SHARED_LIBRARY_PREFIX}address_sorting${CMAKE_SHARED_LIBRARY_SUFFIX}) set(grpc_CPP_PLUGIN ${binary_dir}/grpc_cpp_plugin) file(MAKE_DIRECTORY ${grpc_INCLUDE_DIR}) link_directories(${binary_dir}) @@ -88,4 +92,5 @@ if(ENABLE_LIBS_PACKAGING) add_install_step_for_lib(${grpc_LIBRARY}) add_install_step_for_lib(${grpc_grpc++_LIBRARY}) add_install_step_for_lib(${gpr_LIBRARY}) + add_install_step_for_lib(${address_sorting_LIBRARY}) endif() From 21b0c8da20afccd66fc8a479706e61878457759b Mon Sep 17 00:00:00 2001 From: Dumitru Date: Fri, 18 May 2018 18:32:26 +0300 Subject: [PATCH 110/110] Refactor/disable compatibility (#1348) * Fix build errors Signed-off-by: Dumitru * Move linked library to the right place Signed-off-by: Dumitru * Fixed link error Signed-off-by: Dumitru --- iroha-cli/main.cpp | 3 --- irohad/consensus/yac/CMakeLists.txt | 1 + irohad/execution/CMakeLists.txt | 1 + irohad/network/CMakeLists.txt | 2 ++ irohad/torii/CMakeLists.txt | 1 + irohad/torii/processor/CMakeLists.txt | 1 + test/integration/transport/CMakeLists.txt | 1 + test/module/iroha-cli/client_test.cpp | 5 +---- test/module/irohad/ordering/CMakeLists.txt | 2 ++ test/module/irohad/synchronizer/CMakeLists.txt | 1 + test/module/irohad/validation/query_execution.cpp | 4 ---- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iroha-cli/main.cpp b/iroha-cli/main.cpp index 8b0c730fa8..364bbeca64 100644 --- a/iroha-cli/main.cpp +++ b/iroha-cli/main.cpp @@ -19,12 +19,10 @@ #include #include #include -#include #include #include "backend/protobuf/queries/proto_query.hpp" #include "client.hpp" -#include "common/assert_config.hpp" #include "converters/protobuf/json_proto_converter.hpp" #include "crypto/keys_manager_impl.hpp" #include "grpc_response_handler.hpp" @@ -36,7 +34,6 @@ #include "model/converters/pb_transaction_factory.hpp" #include "model/generators/block_generator.hpp" #include "model/model_crypto_provider_impl.hpp" -#include "validators.hpp" // Account information DEFINE_bool(new_account, diff --git a/irohad/consensus/yac/CMakeLists.txt b/irohad/consensus/yac/CMakeLists.txt index 14c42364e0..5bb0fa0b12 100644 --- a/irohad/consensus/yac/CMakeLists.txt +++ b/irohad/consensus/yac/CMakeLists.txt @@ -43,4 +43,5 @@ target_link_libraries(yac yac_grpc logger hash + shared_model_proto_backend ) diff --git a/irohad/execution/CMakeLists.txt b/irohad/execution/CMakeLists.txt index c473317a5e..c875c2b3d4 100644 --- a/irohad/execution/CMakeLists.txt +++ b/irohad/execution/CMakeLists.txt @@ -39,4 +39,5 @@ add_library(query_execution target_link_libraries(query_execution rxcpp shared_model_default_builders + common_execution ) diff --git a/irohad/network/CMakeLists.txt b/irohad/network/CMakeLists.txt index 21b66bd9f5..0e0bfadd68 100644 --- a/irohad/network/CMakeLists.txt +++ b/irohad/network/CMakeLists.txt @@ -18,6 +18,8 @@ target_link_libraries(block_loader loader_grpc rxcpp shared_model_interfaces + shared_model_proto_backend + logger ) add_library(block_loader_service diff --git a/irohad/torii/CMakeLists.txt b/irohad/torii/CMakeLists.txt index c2cb96c6aa..6f5ad86cd6 100644 --- a/irohad/torii/CMakeLists.txt +++ b/irohad/torii/CMakeLists.txt @@ -36,4 +36,5 @@ target_link_libraries(torii_service shared_model_proto_backend logger shared_model_stateless_validation + processors ) diff --git a/irohad/torii/processor/CMakeLists.txt b/irohad/torii/processor/CMakeLists.txt index f94dc05d3b..ff25230d08 100644 --- a/irohad/torii/processor/CMakeLists.txt +++ b/irohad/torii/processor/CMakeLists.txt @@ -8,4 +8,5 @@ target_link_libraries(processors PUBLIC logger endpoint shared_model_proto_builders + query_execution ) diff --git a/test/integration/transport/CMakeLists.txt b/test/integration/transport/CMakeLists.txt index 8d8617e791..ba36f9b9e6 100644 --- a/test/integration/transport/CMakeLists.txt +++ b/test/integration/transport/CMakeLists.txt @@ -6,4 +6,5 @@ target_link_libraries(ordering_gate_service_test ordering_service shared_model_stateless_validation shared_model_cryptography_model + iroha_amount ) diff --git a/test/module/iroha-cli/client_test.cpp b/test/module/iroha-cli/client_test.cpp index eab8f360ce..6e98634680 100644 --- a/test/module/iroha-cli/client_test.cpp +++ b/test/module/iroha-cli/client_test.cpp @@ -207,7 +207,7 @@ TEST_F(ClientServerTest, SendQueryWhenStatelessInvalid) { ASSERT_TRUE(res.status.ok()); ASSERT_TRUE(res.answer.has_error_response()); ASSERT_EQ(res.answer.error_response().reason(), - iroha::model::ErrorResponse::STATELESS_INVALID); + iroha::protocol::ErrorResponse::STATELESS_INVALID); ASSERT_NE(res.answer.error_response().message().size(), 0); } @@ -247,9 +247,6 @@ TEST_F(ClientServerTest, SendQueryWhenValid) { TEST_F(ClientServerTest, SendQueryWhenStatefulInvalid) { iroha_cli::CliClient client(Ip, Port); - auto account_test = iroha::model::Account(); - account_test.account_id = "test@test"; - EXPECT_CALL(*wsv_query, getSignatories("admin@test")) .WillRepeatedly(Return(signatories)); diff --git a/test/module/irohad/ordering/CMakeLists.txt b/test/module/irohad/ordering/CMakeLists.txt index 6193e3b988..5dc742dba8 100644 --- a/test/module/irohad/ordering/CMakeLists.txt +++ b/test/module/irohad/ordering/CMakeLists.txt @@ -16,6 +16,7 @@ addtest(ordering_service_test ordering_service_test.cpp) target_link_libraries(ordering_service_test ordering_service shared_model_stateless_validation + iroha_amount ) addtest(ordering_gate_test ordering_gate_test.cpp) @@ -23,4 +24,5 @@ target_link_libraries(ordering_gate_test ordering_service shared_model_cryptography_model shared_model_stateless_validation + iroha_amount ) diff --git a/test/module/irohad/synchronizer/CMakeLists.txt b/test/module/irohad/synchronizer/CMakeLists.txt index 92279a485d..2c2d7b48da 100644 --- a/test/module/irohad/synchronizer/CMakeLists.txt +++ b/test/module/irohad/synchronizer/CMakeLists.txt @@ -2,6 +2,7 @@ addtest(synchronizer_test synchronizer_test.cpp) target_link_libraries(synchronizer_test synchronizer shared_model_cryptography + shared_model_proto_backend ) diff --git a/test/module/irohad/validation/query_execution.cpp b/test/module/irohad/validation/query_execution.cpp index df10082124..ba9b12177f 100644 --- a/test/module/irohad/validation/query_execution.cpp +++ b/test/module/irohad/validation/query_execution.cpp @@ -38,7 +38,6 @@ using ::testing::_; using namespace iroha; using namespace iroha::ametsuchi; -using namespace iroha::model; using namespace framework::test_subscriber; using namespace shared_model::permissions; @@ -118,7 +117,6 @@ class QueryValidateExecuteTest : public ::testing::Test { std::shared_ptr block_query; std::shared_ptr factory; - std::shared_ptr query; }; class GetAccountTest : public QueryValidateExecuteTest { @@ -1277,7 +1275,6 @@ class GetRolesTest : public QueryValidateExecuteTest { roles = {admin_role, "some_role"}; } std::vector roles; - std::shared_ptr qry; }; /** @@ -1359,7 +1356,6 @@ class GetRolePermissionsTest : public QueryValidateExecuteTest { } std::string role_id = "user"; std::vector perms; - std::shared_ptr qry; }; /**

    #guE+ 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

    K6k;p`?~>l{ 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 azJ6+oMWeN_jGBXeEg1<#@mf(((EkCV=>kvy literal 0 HcmV?d00001 diff --git a/docs/image_assets/iroha_swift_guide/iroha_swift_guide_005.png b/docs/image_assets/iroha_swift_guide/iroha_swift_guide_005.png new file mode 100644 index 0000000000000000000000000000000000000000..fd8ea8bbd312f2e85973c369ab0e2af3471756e6 GIT binary patch literal 35190 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 CGq4!| literal 0 HcmV?d00001 diff --git a/docs/image_assets/iroha_swift_guide/iroha_swift_guide_007.png b/docs/image_assets/iroha_swift_guide/iroha_swift_guide_007.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e7d53101ed3795a3ec642a66620e01a1a03490 GIT binary patch literal 140251 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