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