Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Beefy node cleanup (#75)
Browse files Browse the repository at this point in the history
* bump serde

* bump substrate, scale-codec 2.0.0

* we need a proper beefy node

* rename primitives as well

* Sort members.

Co-authored-by: Tomasz Drwięga <[email protected]>
  • Loading branch information
adoerr and tomusdrw authored Feb 3, 2021
0 parents commit 2d531f8
Show file tree
Hide file tree
Showing 9 changed files with 1,283 additions and 0 deletions.
29 changes: 29 additions & 0 deletions primitives/beefy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "beefy-primitives"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"

[dependencies]
codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] }

sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-application-crypto = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

[dev-dependencies]
hex-literal = "0.3"

[features]
default = ["std"]
std = [
"codec/std",
"sp-api/std",
"sp-application-crypto/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
]
198 changes: 198 additions & 0 deletions primitives/beefy/src/commitment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

use sp_std::{cmp, prelude::*};

use crate::ValidatorSetId;

/// A commitment signed by GRANDPA validators as part of BEEFY protocol.
///
/// The commitment contains a [payload] extracted from the finalized block at height [block_number].
/// GRANDPA validators collect signatures on commitments and a stream of such signed commitments
/// (see [SignedCommitment]) forms the BEEFY protocol.
#[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)]
pub struct Commitment<TBlockNumber, TPayload> {
/// The payload being signed.
///
/// This should be some form of cumulative representation of the chain (think MMR root hash).
/// The payload should also contain some details that allow the light client to verify next
/// validator set. The protocol does not enforce any particular format of this data,
/// nor how often it should be present in commitments, however the light client has to be
/// provided with full validator set whenever it performs the transition (i.e. importing first
/// block with [validator_set_id] incremented).
pub payload: TPayload,

/// Finalized block number this commitment is for.
///
/// GRANDPA validators agree on a block they create a commitment for and start collecting
/// signatures. This process is called a round.
/// There might be multiple rounds in progress (depending on the block choice rule), however
/// since the payload is supposed to be cumulative, it is not required to import all
/// commitments.
/// BEEFY light client is expected to import at least one commitment per epoch,
/// but is free to import as many as it requires.
pub block_number: TBlockNumber,

/// BEEFY validator set supposed to sign this commitment.
///
/// Validator set is changing once per epoch. The Light Client must be provided by details about
/// the validator set whenever it's importing first commitment with a new `validator_set_id`.
/// Validator set data MUST be verifiable, for instance using [payload] information.
pub validator_set_id: ValidatorSetId,
}

impl<TBlockNumber, TPayload> cmp::PartialOrd for Commitment<TBlockNumber, TPayload>
where
TBlockNumber: cmp::Ord,
TPayload: cmp::Eq,
{
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}

impl<TBlockNumber, TPayload> cmp::Ord for Commitment<TBlockNumber, TPayload>
where
TBlockNumber: cmp::Ord,
TPayload: cmp::Eq,
{
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.validator_set_id
.cmp(&other.validator_set_id)
.then_with(|| self.block_number.cmp(&other.block_number))
}
}

/// A commitment with matching GRANDPA validators' signatures.
#[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)]
pub struct SignedCommitment<TBlockNumber, TPayload, TSignature> {
/// The commitment signatures are collected for.
pub commitment: Commitment<TBlockNumber, TPayload>,
/// GRANDPA validators' signatures for the commitment.
///
/// The length of this `Vec` must match number of validators in the current set (see
/// [Commitment::validator_set_id]).
pub signatures: Vec<Option<TSignature>>,
}

impl<TBlockNumber, TPayload, TSignature> SignedCommitment<TBlockNumber, TPayload, TSignature> {
/// Return the number of collected signatures.
pub fn no_of_signatures(&self) -> usize {
self.signatures.iter().filter(|x| x.is_some()).count()
}
}

#[cfg(test)]
mod tests {
use super::*;
use codec::Decode;

type TestCommitment = Commitment<u128, String>;
type TestSignedCommitment = SignedCommitment<u128, String, Vec<u8>>;

#[test]
fn commitment_encode_decode() {
// given
let commitment: TestCommitment = Commitment {
payload: "Hello World!".into(),
block_number: 5,
validator_set_id: 0,
};

// when
let encoded = codec::Encode::encode(&commitment);
let decoded = TestCommitment::decode(&mut &*encoded);

// then
assert_eq!(decoded, Ok(commitment));
assert_eq!(
encoded,
hex_literal::hex!("3048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000")
);
}

#[test]
fn signed_commitment_encode_decode() {
// given
let commitment: TestCommitment = Commitment {
payload: "Hello World!".into(),
block_number: 5,
validator_set_id: 0,
};
let signed = SignedCommitment {
commitment,
signatures: vec![None, None, Some(vec![1, 2, 3, 4]), Some(vec![5, 6, 7, 8])],
};

// when
let encoded = codec::Encode::encode(&signed);
let decoded = TestSignedCommitment::decode(&mut &*encoded);

// then
assert_eq!(decoded, Ok(signed));
assert_eq!(
encoded,
hex_literal::hex!(
"3048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000100000011001020304011005060708"
)
);
}

#[test]
fn signed_commitment_count_signatures() {
// given
let commitment: TestCommitment = Commitment {
payload: "Hello World!".into(),
block_number: 5,
validator_set_id: 0,
};
let mut signed = SignedCommitment {
commitment,
signatures: vec![None, None, Some(vec![1, 2, 3, 4]), Some(vec![5, 6, 7, 8])],
};
assert_eq!(signed.no_of_signatures(), 2);

// when
signed.signatures[2] = None;

// then
assert_eq!(signed.no_of_signatures(), 1);
}

#[test]
fn commitment_ordering() {
fn commitment(block_number: u128, validator_set_id: crate::ValidatorSetId) -> TestCommitment {
Commitment {
payload: "Hello World!".into(),
block_number,
validator_set_id,
}
}

// given
let a = commitment(1, 0);
let b = commitment(2, 1);
let c = commitment(10, 0);
let d = commitment(10, 1);

// then
assert!(a < b);
assert!(a < c);
assert!(c < b);
assert!(c < d);
assert!(b < d);
}
}
98 changes: 98 additions & 0 deletions primitives/beefy/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
// NOTE: needed to silence warnings about generated code in `decl_runtime_apis`
#![allow(clippy::too_many_arguments, clippy::unnecessary_mut_passed)]

//! Primitives for BEEFY protocol.
//!
//! The crate contains shared data types used by BEEFY protocol and documentation (in a form of
//! code) for building a BEEFY light client.
//!
//! BEEFY is a gadget that runs alongside another finality gadget (for instance GRANDPA).
//! For simplicity (and the initially intended use case) the documentation says GRANDPA in places
//! where a more abstract "Finality Gadget" term could be used, but there is no reason why BEEFY
//! wouldn't run with some other finality scheme.
//! BEEFY validator set is supposed to be tracking the Finality Gadget validator set, but note that
//! it will use a different set of keys. For Polkadot use case we plan to use `secp256k1` for BEEFY,
//! while GRANDPA uses `ed25519`.
mod commitment;
pub mod witness;

pub use commitment::{Commitment, SignedCommitment};

use codec::{Codec, Decode, Encode};
use sp_core::H256;
use sp_std::prelude::*;

/// Key type for BEEFY module.
pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef");

/// BEEFY application-specific crypto types using ECDSA.
pub mod ecdsa {
mod app_ecdsa {
use sp_application_crypto::{app_crypto, ecdsa};
app_crypto!(ecdsa, crate::KEY_TYPE);
}

sp_application_crypto::with_pair! {
/// A BEEFY authority keypair using ECDSA as its crypto.
pub type AuthorityPair = app_ecdsa::Pair;
}

/// Identity of a BEEFY authority using ECDSA as its crypto.
pub type AuthorityId = app_ecdsa::Public;

/// Signature for a BEEFY authority using ECDSA as its crypto.
pub type AuthoritySignature = app_ecdsa::Signature;
}

/// The `ConsensusEngineId` of BEEFY.
pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF";

/// A typedef for validator set id.
pub type ValidatorSetId = u64;

/// The index of an authority.
pub type AuthorityIndex = u32;

/// The type used to represent an MMR root hash.
pub type MmrRootHash = H256;

/// A consensus log item for BEEFY.
#[derive(Decode, Encode)]
pub enum ConsensusLog<AuthorityId: Codec> {
/// The authorities have changed.
#[codec(index = 1)]
AuthoritiesChange(Vec<AuthorityId>),
/// Disable the authority with given index.
#[codec(index = 2)]
OnDisabled(AuthorityIndex),
/// MMR root hash.
#[codec(index = 3)]
MmrRoot(MmrRootHash),
}

sp_api::decl_runtime_apis! {
/// API necessary for BEEFY voters.
pub trait BeefyApi<AuthorityId: Codec> {
/// Return the current set of authorities.
fn authorities() -> Vec<AuthorityId>;
}
}
Loading

0 comments on commit 2d531f8

Please sign in to comment.