Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #include "multi_sig_transactions/state/mst_state.hpp"
7 :
8 : #include <utility>
9 :
10 : #include <boost/range/algorithm/find.hpp>
11 : #include <boost/range/combine.hpp>
12 : #include "common/set.hpp"
13 : #include "interfaces/iroha_internal/transaction_batch.hpp"
14 : #include "interfaces/transaction.hpp"
15 : #include "logger/logger.hpp"
16 :
17 : namespace iroha {
18 :
19 : bool BatchHashEquality::operator()(const DataType &left_tx,
20 : const DataType &right_tx) const {
21 135 : return left_tx->reducedHash() == right_tx->reducedHash();
22 : }
23 :
24 : DefaultCompleter::DefaultCompleter(std::chrono::minutes expiration_time)
25 278 : : expiration_time_(expiration_time) {}
26 :
27 : bool DefaultCompleter::operator()(const DataType &batch) const {
28 9 : return std::all_of(batch->transactions().begin(),
29 9 : batch->transactions().end(),
30 : [](const auto &tx) {
31 12 : return boost::size(tx->signatures()) >= tx->quorum();
32 0 : });
33 : }
34 :
35 : bool DefaultCompleter::operator()(const DataType &batch,
36 : const TimeType &time) const {
37 16 : return std::any_of(batch->transactions().begin(),
38 16 : batch->transactions().end(),
39 : [&](const auto &tx) {
40 18 : return tx->createdTime()
41 18 : + expiration_time_ / std::chrono::milliseconds(1)
42 18 : < time;
43 : });
44 : }
45 :
46 : // ------------------------------| public api |-------------------------------
47 :
48 : MstState MstState::empty(logger::LoggerPtr log,
49 : const CompleterType &completer) {
50 615 : return MstState(completer, std::move(log));
51 0 : }
52 :
53 : StateUpdateResult MstState::operator+=(const DataType &rhs) {
54 112 : auto state_update = StateUpdateResult{
55 112 : std::make_shared<MstState>(MstState::empty(log_, completer_)),
56 112 : std::make_shared<MstState>(MstState::empty(log_, completer_))};
57 112 : insertOne(state_update, rhs);
58 112 : return state_update;
59 112 : }
60 :
61 : StateUpdateResult MstState::operator+=(const MstState &rhs) {
62 11 : auto state_update = StateUpdateResult{
63 11 : std::make_shared<MstState>(MstState::empty(log_, completer_)),
64 11 : std::make_shared<MstState>(MstState::empty(log_, completer_))};
65 29 : for (auto &&rhs_tx : rhs.internal_state_) {
66 18 : insertOne(state_update, rhs_tx);
67 : }
68 11 : return state_update;
69 11 : }
70 :
71 : MstState MstState::operator-(const MstState &rhs) const {
72 27 : return MstState(this->completer_,
73 27 : set_difference(this->internal_state_, rhs.internal_state_),
74 27 : log_);
75 0 : }
76 :
77 : bool MstState::operator==(const MstState &rhs) const {
78 1 : return std::all_of(
79 : internal_state_.begin(), internal_state_.end(), [&rhs](auto &i) {
80 3 : return rhs.internal_state_.find(i) != rhs.internal_state_.end();
81 : });
82 : }
83 :
84 : bool MstState::isEmpty() const {
85 97 : return internal_state_.empty();
86 : }
87 :
88 : std::unordered_set<DataType,
89 : iroha::model::PointerBatchHasher,
90 : BatchHashEquality>
91 : MstState::getBatches() const {
92 87 : return {internal_state_.begin(), internal_state_.end()};
93 : }
94 :
95 : MstState MstState::eraseByTime(const TimeType &time) {
96 50 : MstState out = MstState::empty(log_, completer_);
97 58 : while (not index_.empty() and (*completer_)(index_.top(), time)) {
98 8 : auto iter = internal_state_.find(index_.top());
99 :
100 8 : out += *iter;
101 8 : internal_state_.erase(iter);
102 8 : index_.pop();
103 : }
104 50 : return out;
105 50 : }
106 :
107 : // ------------------------------| private api |------------------------------
108 :
109 : bool MstState::Less::operator()(const DataType &left,
110 : const DataType &right) const {
111 64 : return left->transactions().at(0)->createdTime()
112 64 : < right->transactions().at(0)->createdTime();
113 : }
114 :
115 : /**
116 : * Merge signatures in batches
117 : * @param target - batch for inserting
118 : * @param donor - batch with transactions to copy signatures from
119 : * @return return if at least one new signature was inserted
120 : */
121 : bool mergeSignaturesInBatch(DataType &target, const DataType &donor) {
122 24 : auto inserted_new_signatures = false;
123 48 : for (auto zip :
124 24 : boost::combine(target->transactions(), donor->transactions())) {
125 24 : const auto &target_tx = zip.get<0>();
126 24 : const auto &donor_tx = zip.get<1>();
127 24 : inserted_new_signatures = std::accumulate(
128 24 : std::begin(donor_tx->signatures()),
129 24 : std::end(donor_tx->signatures()),
130 24 : inserted_new_signatures,
131 : [&target_tx](bool accumulator, const auto &signature) {
132 31 : return target_tx->addSignature(signature.signedData(),
133 31 : signature.publicKey())
134 31 : or accumulator;
135 : });
136 : }
137 24 : return inserted_new_signatures;
138 0 : }
139 :
140 : MstState::MstState(const CompleterType &completer, logger::LoggerPtr log)
141 615 : : MstState(completer, InternalStateType{}, std::move(log)) {}
142 :
143 : MstState::MstState(const CompleterType &completer,
144 : const InternalStateType &transactions,
145 : logger::LoggerPtr log)
146 642 : : completer_(completer),
147 642 : internal_state_(transactions.begin(), transactions.end()),
148 642 : index_(transactions.begin(), transactions.end()),
149 642 : log_(std::move(log)) {}
150 :
151 : void MstState::insertOne(StateUpdateResult &state_update,
152 : const DataType &rhs_batch) {
153 130 : log_->info("batch: {}", *rhs_batch);
154 130 : auto corresponding = internal_state_.find(rhs_batch);
155 130 : if (corresponding == internal_state_.end()) {
156 : // when state does not contain transaction
157 106 : rawInsert(rhs_batch);
158 106 : state_update.updated_state_->rawInsert(rhs_batch);
159 106 : return;
160 : }
161 :
162 24 : DataType found = *corresponding;
163 : // Append new signatures to the existing state
164 24 : auto inserted_new_signatures = mergeSignaturesInBatch(found, rhs_batch);
165 :
166 24 : if ((*completer_)(found)) {
167 : // state already has completed transaction,
168 : // remove from state and return it
169 8 : internal_state_.erase(internal_state_.find(found));
170 8 : state_update.completed_state_->rawInsert(found);
171 8 : return;
172 : }
173 :
174 : // if batch still isn't completed, return it, if new signatures were
175 : // inserted
176 16 : if (inserted_new_signatures) {
177 11 : state_update.updated_state_->rawInsert(found);
178 11 : }
179 130 : }
180 :
181 : void MstState::rawInsert(const DataType &rhs_batch) {
182 231 : internal_state_.insert(rhs_batch);
183 231 : index_.push(rhs_batch);
184 231 : }
185 :
186 : bool MstState::contains(const DataType &element) const {
187 728 : return internal_state_.find(element) != internal_state_.end();
188 : }
189 :
190 : } // namespace iroha
|