Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #include "consensus/yac/storage/yac_proposal_storage.hpp"
7 :
8 : #include <boost/range/adaptor/transformed.hpp>
9 : #include "logger/logger.hpp"
10 : #include "logger/logger_manager.hpp"
11 :
12 : using namespace logger;
13 :
14 : namespace iroha {
15 : namespace consensus {
16 : namespace yac {
17 :
18 : // --------| private api |--------
19 :
20 : auto YacProposalStorage::findStore(const YacHash &store_hash) {
21 : // find exist
22 3625 : auto iter = std::find_if(block_storages_.begin(),
23 3625 : block_storages_.end(),
24 : [&store_hash](auto block_storage) {
25 : auto storage_key =
26 481 : block_storage.getStorageKey();
27 481 : return storage_key == store_hash;
28 481 : });
29 3625 : if (iter != block_storages_.end()) {
30 473 : return iter;
31 : }
32 : // insert and return new
33 3152 : return block_storages_.emplace(
34 3152 : block_storages_.end(),
35 3152 : YacHash(store_hash.vote_round,
36 3152 : store_hash.vote_hashes.proposal_hash,
37 3152 : store_hash.vote_hashes.block_hash),
38 3152 : peers_in_round_,
39 3152 : supermajority_checker_,
40 3152 : log_manager_->getChild("BlockStorage")->getLogger());
41 3625 : }
42 :
43 : // --------| public api |--------
44 :
45 : YacProposalStorage::YacProposalStorage(
46 : Round store_round,
47 : PeersNumberType peers_in_round,
48 : std::shared_ptr<SupermajorityChecker> supermajority_checker,
49 : logger::LoggerManagerTreePtr log_manager)
50 3148 : : current_state_(boost::none),
51 3148 : storage_key_(store_round),
52 3148 : peers_in_round_(peers_in_round),
53 3148 : supermajority_checker_(supermajority_checker),
54 3148 : log_manager_(std::move(log_manager)),
55 3148 : log_(log_manager_->getLogger()) {}
56 :
57 : boost::optional<Answer> YacProposalStorage::insert(VoteMessage msg) {
58 7213 : if (shouldInsert(msg)) {
59 : // insert to block store
60 :
61 3625 : log_->info("Vote with {} and hashes [{}, {}] looks valid",
62 3625 : msg.hash.vote_round,
63 3625 : msg.hash.vote_hashes.proposal_hash,
64 3625 : msg.hash.vote_hashes.block_hash);
65 :
66 3625 : auto iter = findStore(msg.hash);
67 3625 : auto block_state = iter->insert(msg);
68 :
69 : // Single BlockStorage always returns CommitMessage because it
70 : // aggregates votes for a single hash.
71 3625 : if (block_state) {
72 : // supermajority on block achieved
73 3150 : current_state_ = std::move(block_state);
74 3150 : } else {
75 : // try to find reject case
76 475 : auto reject_state = findRejectProof();
77 475 : if (reject_state) {
78 6 : log_->info("Found reject proof");
79 6 : current_state_ = std::move(reject_state);
80 6 : }
81 475 : }
82 3625 : }
83 7213 : return getState();
84 0 : }
85 :
86 : boost::optional<Answer> YacProposalStorage::insert(
87 : std::vector<VoteMessage> messages) {
88 : std::for_each(messages.begin(), messages.end(), [this](auto vote) {
89 7192 : this->insert(std::move(vote));
90 7192 : });
91 6735 : return getState();
92 : }
93 :
94 : const Round &YacProposalStorage::getStorageKey() const {
95 19835 : return storage_key_;
96 : }
97 :
98 : boost::optional<Answer> YacProposalStorage::getState() const {
99 13949 : return current_state_;
100 : }
101 :
102 : // --------| private api |--------
103 :
104 : bool YacProposalStorage::shouldInsert(const VoteMessage &msg) {
105 7213 : return checkProposalRound(msg.hash.vote_round)
106 7213 : and checkPeerUniqueness(msg);
107 : }
108 :
109 : bool YacProposalStorage::checkProposalRound(const Round &vote_round) {
110 7213 : return vote_round == storage_key_;
111 : }
112 :
113 : bool YacProposalStorage::checkPeerUniqueness(const VoteMessage &msg) {
114 7212 : return std::all_of(block_storages_.begin(),
115 7212 : block_storages_.end(),
116 : [&msg](YacBlockStorage &storage) {
117 4071 : if (storage.getStorageKey() != msg.hash) {
118 11 : return true;
119 : }
120 4060 : return not storage.isContains(msg);
121 4071 : });
122 : }
123 :
124 : boost::optional<Answer> YacProposalStorage::findRejectProof() {
125 475 : auto is_reject = not supermajority_checker_->canHaveSupermajority(
126 475 : block_storages_
127 : | boost::adaptors::transformed([](const auto &storage) {
128 950 : return storage.getNumberOfVotes();
129 : }),
130 475 : peers_in_round_);
131 :
132 475 : if (is_reject) {
133 6 : std::vector<VoteMessage> result;
134 6 : std::for_each(block_storages_.begin(),
135 6 : block_storages_.end(),
136 : [&result](auto &storage) {
137 12 : auto votes_from_block_storage = storage.getVotes();
138 12 : std::move(votes_from_block_storage.begin(),
139 12 : votes_from_block_storage.end(),
140 12 : std::back_inserter(result));
141 12 : });
142 :
143 6 : return Answer(RejectMessage(std::move(result)));
144 6 : }
145 :
146 469 : return boost::none;
147 475 : }
148 :
149 : } // namespace yac
150 : } // namespace consensus
151 : } // namespace iroha
|