mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
9a0074ff06
Using the stl functions here (which signal intend more clearly) results in: fatal error: error in backend: Cannot emit physreg copy instruction clang: error: clang frontend command failed with exit code 70 (use -v to see invocation) Manually unroll things into for loops works around the compiler bug.
158 lines
6.4 KiB
C++
158 lines
6.4 KiB
C++
// Copyright (c) 2019, The Loki Project
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
// permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
// conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
// of conditions and the following disclaimer in the documentation and/or other
|
|
// materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
// used to endorse or promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include "tx_blink.h"
|
|
#include "common/util.h"
|
|
#include "service_node_list.h"
|
|
#include <algorithm>
|
|
#include "../cryptonote_basic/cryptonote_format_utils.h"
|
|
|
|
namespace cryptonote {
|
|
|
|
using namespace service_nodes;
|
|
|
|
static void check_args(blink_tx::subquorum q, int position, const char *func_name) {
|
|
if (q < blink_tx::subquorum::base || q >= blink_tx::subquorum::_count)
|
|
throw std::invalid_argument("Invalid sub-quorum value passed to " + std::string(func_name));
|
|
if (position < 0 || position >= BLINK_SUBQUORUM_SIZE)
|
|
throw std::invalid_argument("Invalid voter position passed to " + std::string(func_name));
|
|
}
|
|
|
|
crypto::public_key blink_tx::get_sn_pubkey(subquorum q, int position, const service_node_list &snl) const {
|
|
check_args(q, position, __func__);
|
|
uint64_t qheight = quorum_height(q);
|
|
auto blink_quorum = snl.get_quorum(quorum_type::blink, qheight);
|
|
if (!blink_quorum) {
|
|
// TODO FIXME XXX - we don't want a failure here; if this happens we need to go back into state
|
|
// history to retrieve the state info. (Or maybe this can't happen?)
|
|
MERROR("FIXME: could not get blink quorum for blink_tx");
|
|
return crypto::null_pkey;
|
|
}
|
|
|
|
if (position < (int) blink_quorum->validators.size())
|
|
return blink_quorum->validators[position];
|
|
|
|
return crypto::null_pkey;
|
|
};
|
|
|
|
crypto::hash blink_tx::hash(bool approved) const {
|
|
auto buf = tools::memcpy_le(height, get_txhash().data, uint8_t{approved});
|
|
crypto::hash blink_hash;
|
|
crypto::cn_fast_hash(buf.data(), buf.size(), blink_hash);
|
|
return blink_hash;
|
|
}
|
|
|
|
|
|
void blink_tx::limit_signatures(subquorum q, size_t max_size) {
|
|
if (max_size > BLINK_SUBQUORUM_SIZE)
|
|
throw std::domain_error("Internal error: too many potential blink signers!");
|
|
else if (max_size < BLINK_SUBQUORUM_SIZE)
|
|
for (size_t i = max_size; i < BLINK_SUBQUORUM_SIZE; i++)
|
|
signatures_[static_cast<uint8_t>(q)][i].status = signature_status::rejected;
|
|
}
|
|
|
|
bool blink_tx::add_signature(subquorum q, int position, bool approved, const crypto::signature &sig, const crypto::public_key &pubkey) {
|
|
check_args(q, position, __func__);
|
|
|
|
if (!crypto::check_signature(hash(approved), pubkey, sig))
|
|
throw signature_verification_error("Given blink quorum signature verification failed!");
|
|
|
|
return add_prechecked_signature(q, position, approved, sig);
|
|
}
|
|
|
|
|
|
bool blink_tx::add_signature(subquorum q, int position, bool approved, const crypto::signature &sig, const service_node_list &snl) {
|
|
return add_signature(q, position, approved, sig, get_sn_pubkey(q, position, snl));
|
|
}
|
|
|
|
bool blink_tx::add_prechecked_signature(subquorum q, int position, bool approved, const crypto::signature &sig) {
|
|
check_args(q, position, __func__);
|
|
|
|
auto &sig_slot = signatures_[static_cast<uint8_t>(q)][position];
|
|
if (sig_slot.status != signature_status::none)
|
|
return false;
|
|
|
|
sig_slot.status = approved ? signature_status::approved : signature_status::rejected;
|
|
sig_slot.sig = sig;
|
|
return true;
|
|
}
|
|
|
|
blink_tx::signature_status blink_tx::get_signature_status(subquorum q, int position) const {
|
|
check_args(q, position, __func__);
|
|
return signatures_[static_cast<uint8_t>(q)][position].status;
|
|
}
|
|
|
|
static int sig_count(const std::array<blink_tx::quorum_signature, BLINK_SUBQUORUM_SIZE>& sigs, blink_tx::signature_status status) {
|
|
int count = 0;
|
|
for (auto& s : sigs)
|
|
if (s.status == status)
|
|
count++;
|
|
return count;
|
|
}
|
|
|
|
bool blink_tx::approved() const {
|
|
for (auto& sigs : signatures_)
|
|
if (sig_count(sigs, signature_status::approved) < BLINK_MIN_VOTES)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool blink_tx::rejected() const {
|
|
for (auto& sigs : signatures_)
|
|
if (sig_count(sigs, signature_status::rejected) > BLINK_SUBQUORUM_SIZE - BLINK_MIN_VOTES)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void blink_tx::fill_serialization_data(crypto::hash &tx_hash, uint64_t &height, std::vector<uint8_t> &quorum, std::vector<uint8_t> &position, std::vector<crypto::signature> &signature) const {
|
|
tx_hash = get_txhash();
|
|
height = this->height;
|
|
constexpr size_t res_size = tools::enum_count<subquorum> * service_nodes::BLINK_SUBQUORUM_SIZE;
|
|
quorum.reserve(res_size);
|
|
position.reserve(res_size);
|
|
signature.reserve(res_size);
|
|
for (uint8_t qi = 0; qi < signatures_.size(); qi++) {
|
|
for (uint8_t p = 0; p < signatures_[qi].size(); p++) {
|
|
auto &sig = signatures_[qi][p];
|
|
if (sig.status == signature_status::approved) {
|
|
quorum.push_back(qi);
|
|
position.push_back(p);
|
|
signature.push_back(sig.sig);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
crypto::hash blink_tx::tx_hash_visitor::operator()(const transaction &tx) const {
|
|
crypto::hash h;
|
|
if (!cryptonote::get_transaction_hash(tx, h))
|
|
throw std::runtime_error("Failed to calculate transaction hash");
|
|
return h;
|
|
}
|
|
|
|
}
|