Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parachain bitfield signer #1336

Merged
merged 12 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmake/Hunter/hunter-gate-url.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

HunterGate(
URL "https://github.com/soramitsu/soramitsu-hunter/archive/52069249f8ed86f30d3f473c32de44c64270d186.zip"
SHA1 "4edea9f8976988f8f34ca59c5341a2297315a941"
URL "https://github.com/soramitsu/soramitsu-hunter/archive/refs/tags/v0.23.257-soramitsu31.zip"
SHA1 "a13dcf6dae9e926441715e67c409838630f6f3e0"
LOCAL
)
37 changes: 5 additions & 32 deletions core/consensus/babe/impl/parachains_inherent_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/

#include <scale/bitvec.hpp>

#include "common/stub.hpp"
#include "common/tagged.hpp"
#include "common/unused.hpp"
#include "network/types/collator_messages.hpp"
#include "primitives/common.hpp"

namespace kagome::consensus::babe {
Expand Down Expand Up @@ -189,7 +192,7 @@ namespace kagome::consensus::babe {
std::vector<Attestation> validity_votes;

/// A bitfield of indices of the validators within the validator group
std::vector<bool> indices;
scale::BitVec indices;
};

scale::ScaleEncoderStream &operator<<(scale::ScaleEncoderStream &s,
Expand Down Expand Up @@ -284,42 +287,12 @@ namespace kagome::consensus::babe {
// clang-format on
}

/// Bitfields signed by validators claiming the candidate is available or not
struct SignedBitfields {
/// The availability bitfield
std::vector<bool> bitfield;

/// The signature of the validator
Signature signature;

/// The validator index in the authority set
uint32_t validator_index;
};

scale::ScaleEncoderStream &operator<<(scale::ScaleEncoderStream &s,
const SignedBitfields &data) {
// clang-format off
return s << data.bitfield
<< data.signature
<< data.validator_index;
// clang-format on
}

scale::ScaleDecoderStream &operator>>(scale::ScaleDecoderStream &s,
SignedBitfields &data) {
// clang-format off
return s >> data.bitfield
>> data.signature
>> data.validator_index;
// clang-format on
}

struct ParachainInherentData {
/// The array of signed bitfields by validators claiming the candidate is
/// available (or not).
/// @note The array must be sorted by validator index corresponding to the
/// authority set
std::vector<SignedBitfields> bitfields;
std::vector<network::SignedBitfield> bitfields;

/// The array of backed candidates for inclusion in the current block
std::vector<Empty> backed_candidates;
Expand Down
10 changes: 10 additions & 0 deletions core/crypto/crypto_store/session_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,14 @@ namespace kagome::crypto {
return gran_key_pair_;
}

const std::shared_ptr<Sr25519Keypair> &SessionKeys::getParaKeyPair() {
if (not para_key_pair_ && roles_.flags.authority) {
auto keys = store_->getSr25519PublicKeys(KEY_TYPE_PARA);
if (keys and not keys.value().empty()) {
auto kp = store_->findSr25519Keypair(KEY_TYPE_PARA, keys.value().at(0));
para_key_pair_ = std::make_shared<Sr25519Keypair>(kp.value());
}
}
return para_key_pair_;
}
} // namespace kagome::crypto
6 changes: 6 additions & 0 deletions core/crypto/crypto_store/session_keys.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace kagome::crypto {
class SessionKeys {
std::shared_ptr<Sr25519Keypair> babe_key_pair_;
std::shared_ptr<Ed25519Keypair> gran_key_pair_;
std::shared_ptr<Sr25519Keypair> para_key_pair_;
network::Roles roles_;
std::shared_ptr<CryptoStore> store_;

Expand All @@ -46,6 +47,11 @@ namespace kagome::crypto {
* @return current GRANDPA session key pair
*/
const std::shared_ptr<Ed25519Keypair> &getGranKeyPair();

/**
* @return current parachain validator session key pair
*/
const std::shared_ptr<Sr25519Keypair> &getParaKeyPair();
};
} // namespace kagome::crypto

Expand Down
1 change: 1 addition & 0 deletions core/injector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ target_link_libraries(application_injector
p2p::p2p_identify
p2p::p2p_kademlia
p2p::p2p_ping
parachain_host_api
payment_api_service
pbkdf2_provider
peer_manager
Expand Down
2 changes: 2 additions & 0 deletions core/injector/application_injector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
#include "offchain/impl/offchain_worker_impl.hpp"
#include "offchain/impl/offchain_worker_pool_impl.hpp"
#include "outcome/outcome.hpp"
#include "parachain/availability/bitfield/store_impl.hpp"
#include "parachain/availability/store/store_impl.hpp"
#include "parachain/validator/parachain_observer.hpp"
#include "parachain/validator/parachain_processor.hpp"
Expand Down Expand Up @@ -1246,6 +1247,7 @@ namespace {
bind_by_lambda<network::StateProtocolObserver>(get_state_observer_impl),
bind_by_lambda<network::SyncProtocolObserver>(get_sync_observer_impl),
di::bind<parachain::AvailabilityStore>.template to<parachain::AvailabilityStoreImpl>(),
di::bind<parachain::BitfieldStore>.template to<parachain::BitfieldStoreImpl>(),
di::bind<parachain::ParachainObserverImpl>.to([](auto const &injector) {
return get_parachain_observer_impl(injector);
}),
Expand Down
19 changes: 19 additions & 0 deletions core/network/types/collator_messages.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define KAGOME_COLLATOR_DECLARE_HPP

#include <boost/variant.hpp>
#include <scale/bitvec.hpp>
#include <tuple>
#include <type_traits>
#include <vector>
Expand All @@ -30,6 +31,21 @@ namespace kagome::network {
using CandidateHash = primitives::BlockHash;
using ChunkProof = std::vector<common::Buffer>;

/// Payload signed by validator.
template <typename Payload>
struct Signed {
SCALE_TIE(3);

static_assert(std::is_same_v<std::decay_t<Payload>, Payload>);

/// Payload.
Payload payload;
/// Index of validator in validator list.
ValidatorIndex validator_index;
/// Signature of `SigningContext::signable(payload)`.
Signature signature;
};

/// NU element.
using Dummy = std::tuple<>;

Expand Down Expand Up @@ -199,6 +215,9 @@ namespace kagome::network {
Statement statement; /// statement of seconded candidate
};

/// Signed availability bitfield.
using SignedBitfield = Signed<scale::BitVec>;

/**
* Collator -> Validator and Validator -> Collator if statement message.
* Type of the appropriate message.
Expand Down
4 changes: 4 additions & 0 deletions core/parachain/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@

add_library(validator_parachain
availability/bitfield/signer.cpp
availability/bitfield/store_impl.cpp
availability/store/store_impl.cpp
validator/impl/parachain_observer.cpp
validator/impl/parachain_processor.cpp
validator/signer.cpp
)

target_link_libraries(validator_parachain
crypto_store
req_collation_protocol
collation_protocol
protocol_error
Expand Down
94 changes: 94 additions & 0 deletions core/parachain/availability/bitfield/signer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "parachain/availability/bitfield/signer.hpp"

#include "log/logger.hpp"
#include "primitives/block_header.hpp"

namespace kagome::parachain {
constexpr std::chrono::milliseconds kDelay{1500};

namespace {
inline auto log() {
return log::createLogger("BitfieldSigner");
}
} // namespace

BitfieldSigner::BitfieldSigner(
std::shared_ptr<crypto::Hasher> hasher,
std::shared_ptr<ValidatorSignerFactory> signer_factory,
std::shared_ptr<libp2p::basic::Scheduler> scheduler,
std::shared_ptr<runtime::ParachainHost> parachain_api,
std::shared_ptr<AvailabilityStore> store,
std::shared_ptr<BitfieldStore> bitfield_store)
: hasher_{std::move(hasher)},
signer_factory_{std::move(signer_factory)},
scheduler_{std::move(scheduler)},
parachain_api_{std::move(parachain_api)},
store_{std::move(store)},
bitfield_store_{std::move(bitfield_store)} {}

void BitfieldSigner::start(
std::shared_ptr<primitives::events::ChainSubscriptionEngine>
chain_sub_engine) {
chain_sub_ = std::make_shared<primitives::events::ChainEventSubscriber>(
chain_sub_engine);
chain_sub_->subscribe(chain_sub_->generateSubscriptionSetId(),
primitives::events::ChainEventType::kNewHeads);
chain_sub_->setCallback(
[weak = weak_from_this()](
subscription::SubscriptionSetId,
auto &&,
primitives::events::ChainEventType,
const primitives::events::ChainEventParams &event) {
if (auto self = weak.lock()) {
auto r = self->onBlock(self->hasher_->blake2b_256(
scale::encode(
boost::get<primitives::events::HeadsEventParams>(event))
.value()));
if (r.has_error()) {
SL_WARN(log(), "onBlock error {}", r.error());
}
}
});
}

outcome::result<void> BitfieldSigner::sign(const ValidatorSigner &signer) {
auto &relay_parent = signer.context().relay_parent;
scale::BitVec bitfield;
OUTCOME_TRY(cores, parachain_api_->availability_cores(relay_parent));
bitfield.bits.reserve(cores.size());
for (auto &core : cores) {
auto occupied = boost::get<runtime::OccupiedCore>(&core);
bitfield.bits.push_back(occupied != nullptr
&& store_->hasChunk(occupied->candidate_hash,
signer.validatorIndex()));
}

OUTCOME_TRY(signed_bitfield, signer.sign(bitfield));
bitfield_store_->putBitfield(relay_parent, signed_bitfield);
// TODO(turuslan): broadcast
return outcome::success();
}

outcome::result<void> BitfieldSigner::onBlock(const BlockHash &relay_parent) {
OUTCOME_TRY(signer, signer_factory_->at(relay_parent));
if (not signer.has_value()) {
return outcome::success();
}
scheduler_->schedule(
[weak = weak_from_this(), relay_parent, signer{std::move(*signer)}]() {
if (auto self = weak.lock()) {
auto r = self->sign(signer);
if (r.has_error()) {
SL_WARN(log(), "sign error {}", r.error());
}
}
},
kDelay);
return outcome::success();
}
} // namespace kagome::parachain
51 changes: 51 additions & 0 deletions core/parachain/availability/bitfield/signer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef KAGOME_PARACHAIN_AVAILABILITY_BITFIELD_SIGNER_HPP
#define KAGOME_PARACHAIN_AVAILABILITY_BITFIELD_SIGNER_HPP

#include <libp2p/basic/scheduler.hpp>

#include "crypto/hasher.hpp"
#include "parachain/availability/bitfield/store.hpp"
#include "parachain/availability/store/store.hpp"
#include "parachain/validator/signer.hpp"
#include "primitives/event_types.hpp"
#include "runtime/runtime_api/parachain_host.hpp"

namespace kagome::parachain {
/// Signs, stores and broadcasts bitfield for every new head.
class BitfieldSigner : public std::enable_shared_from_this<BitfieldSigner> {
public:
BitfieldSigner(std::shared_ptr<crypto::Hasher> hasher,
std::shared_ptr<ValidatorSignerFactory> signer_factory,
std::shared_ptr<libp2p::basic::Scheduler> scheduler,
std::shared_ptr<runtime::ParachainHost> parachain_api,
std::shared_ptr<AvailabilityStore> store,
std::shared_ptr<BitfieldStore> bitfield_store);

/// Subscribes to new heads.
void start(std::shared_ptr<primitives::events::ChainSubscriptionEngine>
chain_sub_engine);

/// Sign bitfield for given block.
outcome::result<void> sign(const ValidatorSigner &signer);

private:
using BlockHash = primitives::BlockHash;
turuslan marked this conversation as resolved.
Show resolved Hide resolved

outcome::result<void> onBlock(const BlockHash &relay_parent);

std::shared_ptr<crypto::Hasher> hasher_;
std::shared_ptr<ValidatorSignerFactory> signer_factory_;
std::shared_ptr<libp2p::basic::Scheduler> scheduler_;
std::shared_ptr<runtime::ParachainHost> parachain_api_;
std::shared_ptr<AvailabilityStore> store_;
std::shared_ptr<BitfieldStore> bitfield_store_;
std::shared_ptr<primitives::events::ChainEventSubscriber> chain_sub_;
};
} // namespace kagome::parachain

#endif // KAGOME_PARACHAIN_AVAILABILITY_BITFIELD_SIGNER_HPP
30 changes: 30 additions & 0 deletions core/parachain/availability/bitfield/store.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef KAGOME_PARACHAIN_AVAILABILITY_BITFIELD_STORE_HPP
#define KAGOME_PARACHAIN_AVAILABILITY_BITFIELD_STORE_HPP

#include "network/types/collator_messages.hpp"

namespace kagome::parachain {
/// Stores bitfields signed by validators.
class BitfieldStore {
public:
using BlockHash = primitives::BlockHash;
using SignedBitfield = network::SignedBitfield;

virtual ~BitfieldStore() = default;

/// Store bitfield at given block.
virtual void putBitfield(const BlockHash &relay_parent,
const SignedBitfield &bitfield) = 0;

/// Get bitfields for given block.
virtual std::vector<SignedBitfield> getBitfields(
const BlockHash &relay_parent) const = 0;
};
} // namespace kagome::parachain

#endif // KAGOME_PARACHAIN_AVAILABILITY_BITFIELD_STORE_HPP
23 changes: 23 additions & 0 deletions core/parachain/availability/bitfield/store_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "parachain/availability/bitfield/store_impl.hpp"

namespace kagome::parachain {
void BitfieldStoreImpl::putBitfield(const BlockHash &relay_parent,
const SignedBitfield &bitfield) {
bitfields_[relay_parent].push_back(bitfield);
}

std::vector<BitfieldStore::SignedBitfield> BitfieldStoreImpl::getBitfields(
const BlockHash &relay_parent) const {
std::vector<SignedBitfield> bitfields;
auto it = bitfields_.find(relay_parent);
if (it != bitfields_.end()) {
bitfields = it->second;
}
return bitfields;
}
} // namespace kagome::parachain
Loading