Skip to content

Commit

Permalink
Merge pull request hyperledger-iroha#739 from hyperledger/feature/sha…
Browse files Browse the repository at this point in the history
…red-model-tx-stateless-validation

Transaction stateless validation in shared model
  • Loading branch information
kamilsa authored and lebdron committed Dec 19, 2017
2 parents f21b505 + 5452832 commit 077613b
Show file tree
Hide file tree
Showing 10 changed files with 556 additions and 22 deletions.
19 changes: 15 additions & 4 deletions shared_model/builders/protobuf/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
#include "builders/protobuf/helpers.hpp"
#include "builders/protobuf/unsigned_proto.hpp"
#include "interfaces/common_objects/types.hpp"
#include "validators/default_validator.hpp"

namespace shared_model {
namespace proto {
template <int S = 0>
template <int S = 0, typename SV = validation::DefaultValidator>
class TemplateTransactionBuilder {
private:
template <int>
template <int, typename>
friend class TemplateTransactionBuilder;

enum RequiredFields {
Expand All @@ -50,8 +51,12 @@ namespace shared_model {
iroha::protocol::Transaction transaction_;

template <int Sp>
TemplateTransactionBuilder(const TemplateTransactionBuilder<Sp> &o)
: transaction_(o.transaction_) {}
TemplateTransactionBuilder(const TemplateTransactionBuilder<Sp> &o,
SV&& stateless_validator = SV())
: transaction_(o.transaction_),
stateless_validator_(std::forward<SV>(stateless_validator)) {}

SV stateless_validator_;

public:
TemplateTransactionBuilder() = default;
Expand Down Expand Up @@ -167,6 +172,12 @@ namespace shared_model {

UnsignedWrapper<Transaction> build() {
static_assert(S == (1 << TOTAL) - 1, "Required fields are not set");

auto answer = stateless_validator_.validate(
detail::make_polymorphic<Transaction>(transaction_));
if (answer.hasErrors()) {
throw std::invalid_argument(answer.reason());
}
return UnsignedWrapper<Transaction>(
Transaction(iroha::protocol::Transaction(transaction_)));
}
Expand Down
18 changes: 13 additions & 5 deletions shared_model/interfaces/polymorphic_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define IROHA_POLYMORPHIC_WRAPPER_HPP

#include <memory>
#include <utility>

namespace shared_model {
namespace detail {
Expand All @@ -38,6 +39,8 @@ namespace shared_model {

PolymorphicWrapper() = delete;

PolymorphicWrapper(std::shared_ptr<T> shp) : ptr_(shp) {}

/**
* Copy constructor that performs deep copy
* @param rhs - another wrapped value
Expand All @@ -58,17 +61,16 @@ namespace shared_model {
* @param value - pointer for wrapping
*/
template <typename Y,
typename = std::enable_if_t<std::is_base_of<T, Y>::value>>
explicit PolymorphicWrapper(Y *value)
: ptr_(value) {}
typename = std::enable_if_t<std::is_base_of<T, Y>::value>>
explicit PolymorphicWrapper(Y *value) : ptr_(value) {}

template <typename Y,
typename = std::enable_if_t<std::is_base_of<T, Y>::value>>
typename = std::enable_if_t<std::is_base_of<T, Y>::value>>
PolymorphicWrapper(const PolymorphicWrapper<Y> &rhs)
: ptr_(rhs.ptr_->copy()) {}

template <typename Y,
typename = std::enable_if_t<std::is_base_of<T, Y>::value>>
typename = std::enable_if_t<std::is_base_of<T, Y>::value>>
PolymorphicWrapper(PolymorphicWrapper<Y> &&rhs) noexcept
: ptr_(std::move(rhs.ptr_)) {
rhs.ptr_ = nullptr;
Expand Down Expand Up @@ -120,6 +122,12 @@ namespace shared_model {
std::shared_ptr<WrappedType> ptr_;
};

template <class T, class... Args>
PolymorphicWrapper<T> make_polymorphic(Args &&... args) {
return PolymorphicWrapper<T>(
std::make_shared<T>(std::forward<Args>(args)...));
}

} // namespace detail
} // namespace shared_model

Expand Down
2 changes: 1 addition & 1 deletion shared_model/interfaces/queries/get_roles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* 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 copyof the License at
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
Expand Down
8 changes: 8 additions & 0 deletions shared_model/validators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.

add_library(shared_model_stateless_validation
default_validator.cpp
)

target_link_libraries(shared_model_stateless_validation
schema
model_interfaces
)
79 changes: 79 additions & 0 deletions shared_model/validators/answer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* 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_ANSWER_HPP
#define IROHA_ANSWER_HPP

#include <boost/range/numeric.hpp>
#include <unordered_map>
#include "utils/string_builder.hpp"

namespace shared_model {
namespace validation {

using ConcreteReasonType = std::string;
using GroupedReasons = std::vector<ConcreteReasonType>;
using ReasonsGroupName = std::string;
using ReasonsGroupType = std::pair<ReasonsGroupName, GroupedReasons>;

/**
* Class which represents the answer to stateless validation: whether
* validation is done right and if not it explains the reason
*/
class Answer {
public:
operator bool() const { return not reasons_map_.empty(); }

/**
* @return string representation of errors
*/
std::string reason() const {
return boost::accumulate(
reasons_map_,
std::string{},
[](auto &&acc, const auto &command_reasons) {
acc += detail::PrettyStringBuilder()
.init(command_reasons.first)
.appendAll(command_reasons.second,
[](auto &element) { return element; })
.finalize();
return std::forward<decltype(acc)>(acc);
});
}

/**
* Check if any error has been recorded to the answer
* @return true if there are any errors, false otherwise
*/
bool hasErrors() { return not reasons_map_.empty(); }

/**
* Adds error to map
* @param reasons
*/
void addReason(ReasonsGroupType &&reasons) {
reasons_map_.insert(std::move(reasons));
}

private:
std::unordered_map<ReasonsGroupName, GroupedReasons> reasons_map_;
};

} // namespace validation
} // namespace shared_model

#endif // IROHA_ANSWER_HPP
Loading

0 comments on commit 077613b

Please sign in to comment.