mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 01:38:04 +00:00
1e01162505
* Remove unneeded script * Rename Substrate Demo -> Substrate * Rename demo -> node * Build wasm from last rename. * Merge ed25519 into substrate-primitives * Minor tweak * Rename substrate -> core * Move substrate-runtime-support to core/runtime/support * Rename/move substrate-runtime-version * Move codec up a level * Rename substrate-codec -> parity-codec * Move environmental up a level * Move pwasm-* up to top, ready for removal * Remove requirement of s-r-support from s-r-primitives * Move core/runtime/primitives into core/runtime-primitives * Remove s-r-support dep from s-r-version * Remove dep of s-r-support from bft * Remove dep of s-r-support from node/consensus * Sever all other core deps from s-r-support * Forgot the no_std directive * Rename non-SRML modules to sr-* to avoid match clashes * Move runtime/* to srml/* * Rename substrate-runtime-* -> srml-* * Move srml to top-level
207 lines
5.7 KiB
Rust
207 lines
5.7 KiB
Rust
// Copyright 2017 Parity Technologies (UK) Ltd.
|
|
// This file is part of Substrate.
|
|
|
|
// Substrate is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Substrate is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// tag::description[]
|
|
//! Utility for substrate-based runtimes that want to check misbehavior reports.
|
|
// end::description[]
|
|
|
|
#![cfg_attr(not(feature = "std"), no_std)]
|
|
|
|
extern crate parity_codec as codec;
|
|
extern crate substrate_primitives as primitives;
|
|
extern crate sr_io as runtime_io;
|
|
extern crate sr_primitives as runtime_primitives;
|
|
|
|
#[cfg(test)]
|
|
extern crate substrate_bft;
|
|
#[cfg(test)]
|
|
extern crate substrate_keyring as keyring;
|
|
#[cfg(test)]
|
|
extern crate rhododendron;
|
|
|
|
use codec::{Codec, Encode};
|
|
use primitives::{AuthorityId, Signature};
|
|
|
|
use runtime_primitives::bft::{Action, Message, MisbehaviorKind};
|
|
|
|
// check a message signature. returns true if signed by that authority.
|
|
fn check_message_sig<B: Codec, H: Codec>(
|
|
message: Message<B, H>,
|
|
signature: &Signature,
|
|
from: &AuthorityId
|
|
) -> bool {
|
|
let msg: Vec<u8> = message.encode();
|
|
runtime_io::ed25519_verify(&signature.0, &msg, from)
|
|
}
|
|
|
|
fn prepare<B, H>(parent: H, round_number: u32, hash: H) -> Message<B, H> {
|
|
Message {
|
|
parent,
|
|
action: Action::Prepare(round_number, hash),
|
|
}
|
|
}
|
|
|
|
fn commit<B, H>(parent: H, round_number: u32, hash: H) -> Message<B, H> {
|
|
Message {
|
|
parent,
|
|
action: Action::Commit(round_number, hash),
|
|
}
|
|
}
|
|
|
|
/// Evaluate misbehavior.
|
|
///
|
|
/// Doesn't check that the header hash in question is
|
|
/// valid or whether the misbehaving authority was part of
|
|
/// the set at that block.
|
|
pub fn evaluate_misbehavior<B: Codec, H: Codec + Copy>(
|
|
misbehaved: &AuthorityId,
|
|
parent_hash: H,
|
|
kind: &MisbehaviorKind<H>,
|
|
) -> bool {
|
|
match *kind {
|
|
MisbehaviorKind::BftDoublePrepare(round, (h_1, ref s_1), (h_2, ref s_2)) => {
|
|
s_1 != s_2 &&
|
|
check_message_sig::<B, H>(prepare::<B, H>(parent_hash, round, h_1), s_1, misbehaved) &&
|
|
check_message_sig::<B, H>(prepare::<B, H>(parent_hash, round, h_2), s_2, misbehaved)
|
|
}
|
|
MisbehaviorKind::BftDoubleCommit(round, (h_1, ref s_1), (h_2, ref s_2)) => {
|
|
s_1 != s_2 &&
|
|
check_message_sig::<B, H>(commit::<B, H>(parent_hash, round, h_1), s_1, misbehaved) &&
|
|
check_message_sig::<B, H>(commit::<B, H>(parent_hash, round, h_2), s_2, misbehaved)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
use keyring::ed25519;
|
|
use keyring::Keyring;
|
|
|
|
use runtime_primitives::testing::{H256, Block as RawBlock};
|
|
|
|
type Block = RawBlock<u64>;
|
|
|
|
fn sign_prepare(key: &ed25519::Pair, round: u32, hash: H256, parent_hash: H256) -> (H256, Signature) {
|
|
let msg = substrate_bft::sign_message::<Block>(
|
|
rhododendron::Message::Vote(rhododendron::Vote::Prepare(round as _, hash)),
|
|
key,
|
|
parent_hash
|
|
);
|
|
|
|
match msg {
|
|
rhododendron::LocalizedMessage::Vote(vote) => (hash, vote.signature.signature),
|
|
_ => panic!("signing vote leads to signed vote"),
|
|
}
|
|
}
|
|
|
|
fn sign_commit(key: &ed25519::Pair, round: u32, hash: H256, parent_hash: H256) -> (H256, Signature) {
|
|
let msg = substrate_bft::sign_message::<Block>(
|
|
rhododendron::Message::Vote(rhododendron::Vote::Commit(round as _, hash)),
|
|
key,
|
|
parent_hash
|
|
);
|
|
|
|
match msg {
|
|
rhododendron::LocalizedMessage::Vote(vote) => (hash, vote.signature.signature),
|
|
_ => panic!("signing vote leads to signed vote"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn evaluates_double_prepare() {
|
|
let key: ed25519::Pair = Keyring::One.into();
|
|
let parent_hash = [0xff; 32].into();
|
|
let hash_1 = [0; 32].into();
|
|
let hash_2 = [1; 32].into();
|
|
|
|
assert!(evaluate_misbehavior::<Block, H256>(
|
|
&key.public().into(),
|
|
parent_hash,
|
|
&MisbehaviorKind::BftDoublePrepare(
|
|
1,
|
|
sign_prepare(&key, 1, hash_1, parent_hash),
|
|
sign_prepare(&key, 1, hash_2, parent_hash)
|
|
)
|
|
));
|
|
|
|
// same signature twice is not misbehavior.
|
|
let signed = sign_prepare(&key, 1, hash_1, parent_hash);
|
|
assert!(evaluate_misbehavior::<Block, H256>(
|
|
&key.public().into(),
|
|
parent_hash,
|
|
&MisbehaviorKind::BftDoublePrepare(
|
|
1,
|
|
signed,
|
|
signed,
|
|
)
|
|
) == false);
|
|
|
|
// misbehavior has wrong target.
|
|
assert!(evaluate_misbehavior::<Block, H256>(
|
|
&Keyring::Two.to_raw_public().into(),
|
|
parent_hash,
|
|
&MisbehaviorKind::BftDoublePrepare(
|
|
1,
|
|
sign_prepare(&key, 1, hash_1, parent_hash),
|
|
sign_prepare(&key, 1, hash_2, parent_hash),
|
|
)
|
|
) == false);
|
|
}
|
|
|
|
#[test]
|
|
fn evaluates_double_commit() {
|
|
let key: ed25519::Pair = Keyring::One.into();
|
|
let parent_hash = [0xff; 32].into();
|
|
let hash_1 = [0; 32].into();
|
|
let hash_2 = [1; 32].into();
|
|
|
|
assert!(evaluate_misbehavior::<Block, H256>(
|
|
&key.public().into(),
|
|
parent_hash,
|
|
&MisbehaviorKind::BftDoubleCommit(
|
|
1,
|
|
sign_commit(&key, 1, hash_1, parent_hash),
|
|
sign_commit(&key, 1, hash_2, parent_hash)
|
|
)
|
|
));
|
|
|
|
// same signature twice is not misbehavior.
|
|
let signed = sign_commit(&key, 1, hash_1, parent_hash);
|
|
assert!(evaluate_misbehavior::<Block, H256>(
|
|
&key.public().into(),
|
|
parent_hash,
|
|
&MisbehaviorKind::BftDoubleCommit(
|
|
1,
|
|
signed,
|
|
signed,
|
|
)
|
|
) == false);
|
|
|
|
// misbehavior has wrong target.
|
|
assert!(evaluate_misbehavior::<Block, H256>(
|
|
&Keyring::Two.to_raw_public().into(),
|
|
parent_hash,
|
|
&MisbehaviorKind::BftDoubleCommit(
|
|
1,
|
|
sign_commit(&key, 1, hash_1, parent_hash),
|
|
sign_commit(&key, 1, hash_2, parent_hash),
|
|
)
|
|
) == false);
|
|
}
|
|
}
|