Kagome
Polkadot Runtime Engine in C++17
babe_block_validator.cpp
Go to the documentation of this file.
1 
7 
8 #include <algorithm>
9 #include <boost/assert.hpp>
10 
11 #include "common/mp_utils.hpp"
16 #include "scale/scale.hpp"
17 
19  BabeBlockValidator::ValidationError,
20  e) {
22  switch (e) {
23  case E::NO_AUTHORITIES:
24  return "no authorities are provided for the validation";
25  case E::INVALID_SIGNATURE:
26  return "SR25519 signature, which is in BABE header, is invalid";
27  case E::INVALID_VRF:
28  return "VRF value and output are invalid";
29  case E::TWO_BLOCKS_IN_SLOT:
30  return "peer tried to distribute several blocks in one slot";
31  case E::SECONDARY_SLOT_ASSIGNMENTS_DISABLED:
32  return "Secondary slot assignments are disabled for the current epoch.";
33  }
34  return "unknown error";
35 }
36 
37 namespace kagome::consensus {
38  using common::Buffer;
40 
42  std::shared_ptr<blockchain::BlockTree> block_tree,
43  std::shared_ptr<runtime::TaggedTransactionQueue> tx_queue,
44  std::shared_ptr<crypto::Hasher> hasher,
45  std::shared_ptr<crypto::VRFProvider> vrf_provider,
46  std::shared_ptr<crypto::Sr25519Provider> sr25519_provider)
47  : block_tree_{std::move(block_tree)},
48  tx_queue_{std::move(tx_queue)},
49  hasher_{std::move(hasher)},
50  vrf_provider_{std::move(vrf_provider)},
51  sr25519_provider_{std::move(sr25519_provider)},
52  log_{log::createLogger("BlockValidator", "block_validator")} {
53  BOOST_ASSERT(block_tree_);
54  BOOST_ASSERT(tx_queue_);
55  BOOST_ASSERT(hasher_);
56  BOOST_ASSERT(vrf_provider_);
57  BOOST_ASSERT(sr25519_provider_);
58  }
59 
60  outcome::result<void> BabeBlockValidator::validateHeader(
61  const primitives::BlockHeader &header,
62  const EpochNumber epoch_number,
63  const primitives::AuthorityId &authority_id,
64  const Threshold &threshold,
65  const primitives::BabeConfiguration &babe_config) const {
66  SL_DEBUG(log_, "Validated block signed by authority: {}", authority_id.id);
67 
68  // get BABE-specific digests, which must be inside this block
69  OUTCOME_TRY(babe_digests, getBabeDigests(header));
70  const auto &[seal, babe_header] = babe_digests;
71 
72  // @see
73  // https://github.com/paritytech/substrate/blob/polkadot-v0.9.8/client/consensus/babe/src/verification.rs#L111
74 
75  if (babe_header.isProducedInSecondarySlot()) {
76  bool plainAndAllowed =
77  babe_config.allowed_slots == AllowedSlots::PrimaryAndSecondaryPlain
78  and babe_header.slotType() == SlotType::SecondaryPlain;
79  bool vrfAndAllowed =
80  babe_config.allowed_slots == AllowedSlots::PrimaryAndSecondaryVRF
81  and babe_header.slotType() == SlotType::SecondaryVRF;
82  if (not plainAndAllowed and not vrfAndAllowed) {
83  // SL_WARN unwraps to a lambda which cannot capture a local binding,
84  // thus this copy
85  auto slot_type = babe_header.slotType();
86  SL_WARN(
87  log_,
88  "Block {} produced in {} slot, but current "
89  "configuration allows only {}",
90  [&] {
91  auto encoded = scale::encode(header).value();
92  auto hash = hasher_->blake2b_256(encoded);
93  return primitives::BlockInfo(header.number, hash);
94  }(),
95  to_string(slot_type),
96  to_string(babe_config.allowed_slots));
98  }
99  }
100 
101  // signature in seal of the header must be valid
102  if (!verifySignature(header,
103  babe_header,
104  seal,
105  primitives::BabeSessionKey{authority_id.id})) {
107  }
108 
109  // VRF must prove that the peer is the leader of the slot
110  if (babe_header.needVRFCheck()
111  && !verifyVRF(babe_header,
112  epoch_number,
113  primitives::BabeSessionKey{authority_id.id},
114  threshold,
115  babe_config.randomness,
116  babe_header.needVRFWithThresholdCheck())) {
118  }
119 
120  return outcome::success();
121  }
122 
124  const primitives::BlockHeader &header,
125  const BabeBlockHeader &babe_header,
126  const Seal &seal,
127  const primitives::BabeSessionKey &public_key) const {
128  // firstly, take hash of the block's header without Seal, which is the last
129  // digest
130  auto unsealed_header = header;
131  unsealed_header.digest.pop_back();
132 
133  auto unsealed_header_encoded = scale::encode(unsealed_header).value();
134 
135  auto block_hash = hasher_->blake2b_256(unsealed_header_encoded);
136 
137  // secondly, use verify function to check the signature
138  auto res =
139  sr25519_provider_->verify(seal.signature, block_hash, public_key);
140  return res && res.value();
141  }
142 
144  const BabeBlockHeader &babe_header,
145  const EpochNumber epoch_number,
146  const primitives::BabeSessionKey &public_key,
147  const Threshold &threshold,
148  const Randomness &randomness,
149  const bool checkThreshold) const {
150  primitives::Transcript transcript;
152  transcript, randomness, babe_header.slot_number, epoch_number);
153  SL_DEBUG(log_,
154  "prepareTranscript (verifyVRF): randomness {}, slot {}, epoch {}",
155  randomness,
156  babe_header.slot_number,
157  epoch_number);
158 
159  auto verify_res = vrf_provider_->verifyTranscript(
160  transcript, babe_header.vrf_output, public_key, threshold);
161  if (not verify_res.is_valid) {
162  log_->error("VRF proof in block is not valid");
163  return false;
164  }
165 
166  // verify threshold
167  if (checkThreshold && not verify_res.is_less) {
168  log_->error("VRF value is not less than the threshold");
169  return false;
170  }
171 
172  return true;
173  }
174 } // namespace kagome::consensus
crypto::Sr25519PublicKey BabeSessionKey
Definition: session_key.hpp:17
Randomness randomness
The randomness for the genesis epoch.
outcome::result< std::pair< Seal, BabeBlockHeader > > getBabeDigests(const primitives::BlockHeader &block_header)
A secondary deterministic slot assignment.
std::shared_ptr< blockchain::BlockTree > block_tree_
std::string_view to_string(SlotType s)
Definition: slot.hpp:22
A secondary deterministic slot assignment with VRF outputs.
crypto::VRFOutput vrf_output
output of VRF function
std::shared_ptr< crypto::Sr25519Provider > sr25519_provider_
Configuration data used by the BABE consensus engine.
outcome::result< void > validateHeader(const primitives::BlockHeader &header, const EpochNumber epoch_number, const primitives::AuthorityId &authority_id, const Threshold &threshold, const primitives::BabeConfiguration &babe_config) const override
Digest digest
chain-specific auxiliary data
BabeSlotNumber slot_number
slot, in which the block was produced
std::shared_ptr< runtime::TaggedTransactionQueue > tx_queue_
crypto::Sr25519Signature signature
Sig_sr25519(Blake2s(block_header))
Definition: seal.hpp:20
SLBuffer< std::numeric_limits< size_t >::max()> Buffer
Definition: buffer.hpp:244
AllowedSlots allowed_slots
Type of allowed slots.
OUTCOME_CPP_DEFINE_CATEGORY(kagome::consensus, BabeBlockValidator::ValidationError, e)
BabeBlockValidator(std::shared_ptr< blockchain::BlockTree > block_tree, std::shared_ptr< runtime::TaggedTransactionQueue > tx_queue, std::shared_ptr< crypto::Hasher > hasher, std::shared_ptr< crypto::VRFProvider > vrf_provider, std::shared_ptr< crypto::Sr25519Provider > sr25519_provider)
bool verifySignature(const primitives::BlockHeader &header, const BabeBlockHeader &babe_header, const Seal &seal, const primitives::BabeSessionKey &public_key) const
BlockNumber number
index of the block in the chain
detail::BlockInfoT< struct BlockInfoTag > BlockInfo
Definition: common.hpp:63
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
bool verifyVRF(const BabeBlockHeader &babe_header, const EpochNumber epoch_number, const primitives::BabeSessionKey &public_key, const Threshold &threshold, const Randomness &randomness, const bool checkThreshold) const
uint64_t EpochNumber
number of the epoch in the Babe production
Definition: common.hpp:27
crypto::VRFThreshold Threshold
threshold, which must not be exceeded for the party to be a slot leader
Definition: common.hpp:33
std::shared_ptr< crypto::Hasher > hasher_
primitives::Transcript & prepareTranscript(primitives::Transcript &transcript, const Randomness &randomness, BabeSlotNumber slot_number, EpochNumber epoch)
std::shared_ptr< crypto::VRFProvider > vrf_provider_