From 5d3dce151440a6cd28fe068cf34c0780447581c1 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 3 Aug 2023 14:52:16 +0200 Subject: [PATCH 01/78] First definition for pair public keys --- substrate/primitives/core/src/lib.rs | 1 + .../primitives/core/src/paired_crypto.rs | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 substrate/primitives/core/src/paired_crypto.rs diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 3a0e1f33f16c..7174e8b34aad 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -59,6 +59,7 @@ pub use paste; pub mod bandersnatch; #[cfg(feature = "bls-experimental")] pub mod bls; +pub mod paired_crypto; pub mod defer; pub mod ecdsa; pub mod ed25519; diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs new file mode 100644 index 000000000000..e999860336e6 --- /dev/null +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -0,0 +1,81 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Licenseff is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! API for using a pair of crypto schemes together. + +#[cfg(feature = "std")] +use crate::crypto::Ss58Codec; +use crate::crypto::{ByteArray, CryptoType, Derive, Public as TraitPublic, UncheckedFrom}; +#[cfg(feature = "full_crypto")] +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; + +#[cfg(feature = "full_crypto")] +use sp_std::vec::Vec; + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +use sp_runtime_interface::pass_by::PassByInner; +use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; + +/// ECDSA and BLS-377 specialized types +pub mod ecdsa_n_bls377 { + use crate::crypto::{CryptoTypeId}; + use crate::{ecdsa, ed25519}; + + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); + + /// BLS12-377 key pair. + #[cfg(feature = "full_crypto")] + //pub type Pair = super::Pair; + /// BLS12-377 public key. + pub type Public = super::Public; + // /// BLS12-377 signature. + //pub type Signature = super::Signature; + + // impl super::HardJunctionId for TinyBLS377 { + // const ID: &'static str = "BLS12377HDKD"; + // } +} + +/// A secret seed. +/// +/// It's not called a "secret key" because ring doesn't expose the secret keys +/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we +/// will need it later (such as for HDKD). +#[cfg(feature = "full_crypto")] +//type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; + +/// A public key. +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] +#[scale_info(skip_type_params(T))] +pub struct Public { + left_public : LeftPublic, + right_public: RightPublic, +} + +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.left_public.hash(state); + self.right_public.hash(state); + } +} + From be890d4bdbdad43cd95aeda5a5223d28ac5438e4 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 3 Aug 2023 16:35:02 +0200 Subject: [PATCH 02/78] Two example of implementation of pair for demonestration --- .../primitives/core/src/paired_crypto.rs | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index e999860336e6..0dbab1cd960f 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -63,19 +63,47 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct Public { +pub struct PublicWithInner { + inner: [u8; LEFT_PLUS_RIGHT_SIZE], + _phantom: PhantomData (LeftPublic, RightPublic)>, +} + +pub struct Public { left_public : LeftPublic, right_public: RightPublic, } -#[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.left_public.hash(state); - self.right_public.hash(state); - } -} +// #[cfg(feature = "full_crypto")] +// impl sp_std::hash::Hash for Public { +// fn hash(&self, state: &mut H) { +// self.left_public.hash(state); +// self.right_public.hash(state); +// } +// } + +// impl ByteArray for Public { +// const LEN: usize = T1::LEN + T2::LEN; +// } + +// impl TryFrom<&[u8]> for Public { +// type Error = (); + +// fn try_from(data: &[u8]) -> Result { +// // if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { +// // return Err(()) +// // } +// // let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; +// // r.copy_from_slice(data); +// // Ok(Self::unchecked_from(r)) +// } +// } +// impl AsMut<[u8]> for Public { +// fn as_mut(&mut self) -> &mut [u8] { +// &mut self.inner[..] +// } +// } From fb6a0180a934fdbc5b350562f371732c146fe63d Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 14 Aug 2023 10:15:06 -0400 Subject: [PATCH 03/78] - implement paired crypto `Public` as tuple of two `Public`s - unsucessfuly try to implement ByteArray for paired crypto Public --- .../primitives/core/src/paired_crypto.rs | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 0dbab1cd960f..59fb3bbf0aa3 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -34,6 +34,7 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; + /// ECDSA and BLS-377 specialized types pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; @@ -46,7 +47,7 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; // /// BLS12-377 signature. //pub type Signature = super::Signature; @@ -63,47 +64,61 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct PublicWithInner { - inner: [u8; LEFT_PLUS_RIGHT_SIZE], - _phantom: PhantomData (LeftPublic, RightPublic)>, +pub struct Public (LeftPublic, RightPublic); + +#[cfg(feature = "full_crypto")] +impl, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.0.hash(state); + self.1.hash(state); + } } -pub struct Public { - left_public : LeftPublic, - right_public: RightPublic, +impl ByteArray for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> + AsRef<[u8]> + AsMut<[u8]> { + const LEN: usize = LeftPublic::LEN + RightPublic::LEN; } -// #[cfg(feature = "full_crypto")] -// impl sp_std::hash::Hash for Public { -// fn hash(&self, state: &mut H) { -// self.left_public.hash(state); -// self.right_public.hash(state); -// } -// } +impl<'a,LeftPublic: PublicKeyBound + UncheckedFrom<[u8; LEFT_LEN]>, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_LEN + RIGHT_LEN { + return Err(()) + } + + let mut r0 = [0u8; LEFT_LEN]; + let mut r1 = [0u8; RIGHT_LEN]; + r0.copy_from_slice(&data[0..LEFT_LEN]); + r1.copy_from_slice(&data[LEFT_LEN..RIGHT_LEN]); + Ok(Self(LeftPublic::unchecked_from(r0),RightPublic::unchecked_from(r1))) + } +} -// impl ByteArray for Public { -// const LEN: usize = T1::LEN + T2::LEN; +// impl AsMut<[u8]> for Public { +// fn as_mut(&mut self) -> &mut [u8] { +// &mut [self.0.as_mut(), self.1.as_mut()].concat() +// } // } -// impl TryFrom<&[u8]> for Public { -// type Error = (); - -// fn try_from(data: &[u8]) -> Result { -// // if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { -// // return Err(()) -// // } -// // let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; -// // r.copy_from_slice(data); -// // Ok(Self::unchecked_from(r)) -// } +// impl AsRef<[u8; RIGHT_PLUS_LEFT_LEN]> for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> { +// fn as_ref(&self) -> &[u8; RIGHT_PLUS_LEFT_LEN] { +// let mut r = [0u8; RIGHT_PLUS_LEFT_LEN]; +// r.copy_from_slice(self.0.as_ref()); +// r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref()); +// &r +// } // } -// impl AsMut<[u8]> for Public { -// fn as_mut(&mut self) -> &mut [u8] { -// &mut self.inner[..] -// } +// impl AsRef<[u8]> for Public { +// fn as_ref(&self) -> &[u8] { +// //let mut r : Vec = vec![0u8; LEFT_LEN + RIGHT_LEN]; +// //r.copy_from_slice(self.0.as_ref(), LeftPublic::LEN); +// //r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref(), RightPublic::LEN); +// let mut r :Vec = [self.0.as_ref(), self.1.as_ref()].concat(); +// &r[..] +// } // } From 62ef8b14ce394d7919a26abd0877705b826d1012 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 21 Aug 2023 09:12:50 -0400 Subject: [PATCH 04/78] keep both public key object and their continous serialization in paired crypto object in favor of avoiding copy --- .../primitives/core/src/paired_crypto.rs | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 59fb3bbf0aa3..3ae113d9f3a4 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -37,7 +37,7 @@ use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// ECDSA and BLS-377 specialized types pub mod ecdsa_n_bls377 { - use crate::crypto::{CryptoTypeId}; + use crate::crypto::{CryptoTypeId}; use crate::{ecdsa, ed25519}; /// An identifier used to match public keys against BLS12-377 keys @@ -47,7 +47,7 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; // /// BLS12-377 signature. //pub type Signature = super::Signature; @@ -64,61 +64,71 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct Public (LeftPublic, RightPublic); +pub struct Public { + left: LeftPublic, + right: RightPublic, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} + +// We essentially could implement this instead of storing left and right but we are going to end up copying left and right. +// impl Public { +// inline fn left<'a>(&self)-> &'a LeftPublic { +// &LeftPublic::try_from(&self.inner[0..LeftPublic::LEN]).unwrap() +// } + +// fn right<'a>(&self)-> &'a RightPublic { +// &RightPublic::try_from(&self.inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN]).unwrap() +// } + + +// } #[cfg(feature = "full_crypto")] -impl, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.0.hash(state); - self.1.hash(state); +impl sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl ByteArray for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> + AsRef<[u8]> + AsMut<[u8]> { - const LEN: usize = LeftPublic::LEN + RightPublic::LEN; +impl ByteArray for Public { + const LEN: usize = LEFT_PLUS_RIGHT_LEN; } -impl<'a,LeftPublic: PublicKeyBound + UncheckedFrom<[u8; LEFT_LEN]>, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { - type Error = (); +impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_LEN + RIGHT_LEN { - return Err(()) - } + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Ok(Public { left, right, inner }) + + } +} - let mut r0 = [0u8; LEFT_LEN]; - let mut r1 = [0u8; RIGHT_LEN]; - r0.copy_from_slice(&data[0..LEFT_LEN]); - r1.copy_from_slice(&data[LEFT_LEN..RIGHT_LEN]); - Ok(Self(LeftPublic::unchecked_from(r0),RightPublic::unchecked_from(r1))) +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] } } -// impl AsMut<[u8]> for Public { -// fn as_mut(&mut self) -> &mut [u8] { -// &mut [self.0.as_mut(), self.1.as_mut()].concat() -// } -// } - -// impl AsRef<[u8; RIGHT_PLUS_LEFT_LEN]> for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> { -// fn as_ref(&self) -> &[u8; RIGHT_PLUS_LEFT_LEN] { -// let mut r = [0u8; RIGHT_PLUS_LEFT_LEN]; -// r.copy_from_slice(self.0.as_ref()); -// r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref()); -// &r -// } -// } +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.inner + } +} -// impl AsRef<[u8]> for Public { -// fn as_ref(&self) -> &[u8] { -// //let mut r : Vec = vec![0u8; LEFT_LEN + RIGHT_LEN]; -// //r.copy_from_slice(self.0.as_ref(), LeftPublic::LEN); -// //r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref(), RightPublic::LEN); -// let mut r :Vec = [self.0.as_ref(), self.1.as_ref()].concat(); -// &r[..] -// } -// } +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} From 8d4e523787d05de385cf641e2da685d640faeb5c Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 21 Aug 2023 18:21:10 +0200 Subject: [PATCH 05/78] implement PassBy and From for paired_crypto --- .../primitives/core/src/paired_crypto.rs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 3ae113d9f3a4..e2f1081c8393 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -64,7 +64,8 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} +//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] @@ -132,3 +133,35 @@ impl PassByInner for Public { + type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; + + fn into_inner(self) -> Self::Inner { + self.inner + } + + fn inner(&self) -> &Self::Inner { + &self.inner + } + + fn from_inner(inner: Self::Inner) -> Self { + let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let mut right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + + Self { left, right, inner } + } +} + +#[cfg(feature = "full_crypto")] +impl From> for Public where Pair : TraitPair>, +{ + fn from(x: Pair) -> Self { + x.public() + } +} + +/// A key pair. +#[cfg(feature = "full_crypto")] +#[derive(Clone)] +pub struct Pair(LeftPair, RightPair); From eea74e27a40d3c74333676d2adeacd165772ae65 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 22 Aug 2023 16:58:16 -0400 Subject: [PATCH 06/78] implement rest of aux traits for `paired_crypto::Public` implement some of aux traits for `paired_crypto::Signature` --- .../primitives/core/src/paired_crypto.rs | 153 +++++++++++++++++- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index e2f1081c8393..5e384eb1155a 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -45,12 +45,17 @@ pub mod ecdsa_n_bls377 { /// BLS12-377 key pair. #[cfg(feature = "full_crypto")] - //pub type Pair = super::Pair; + pub type Pair = super::Pair; /// BLS12-377 public key. pub type Public = super::Public; // /// BLS12-377 signature. //pub type Signature = super::Signature; + // impl super::CryptoType for Public + // { + // #[cfg(feature = "full_crypto")] + // type Pair = Pair; + // } // impl super::HardJunctionId for TinyBLS377 { // const ID: &'static str = "BLS12377HDKD"; // } @@ -65,7 +70,10 @@ pub mod ecdsa_n_bls377 { //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} +pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} + +impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType> PublicKeyBound for PublicKeyTrait {} + /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] @@ -107,7 +115,7 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; @@ -155,13 +163,150 @@ impl From> for Public where Pair : TraitPair>, -{ + { fn from(x: Pair) -> Self { x.public() } } +impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { + fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Public { left, right, inner } + + } +} + +#[cfg(feature = "std")] +impl std::str::FromStr for Public where Public : CryptoType { + type Err = crate::crypto::PublicError; + + fn from_str(s: &str) -> Result { + ::from_ss58check(s) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for Public where Public : CryptoType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl sp_std::fmt::Debug for Public where Public : CryptoType, [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef { + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.inner), &s[0..8]) + } +} + +#[cfg(not(feature = "std"))] +impl_sp_std::fmt::Debug for Public { + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + + Ok(()) + } +} + +#[cfg(feature = "std")] +impl Serialize for Public where Public : CryptoType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_ss58check()) + + } +} + +#[cfg(feature = "std")] +impl<'de, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public where Public : CryptoType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + + } +} + +impl TraitPublic for Public where Public : CryptoType {} + +impl Derive for Public {} + +#[cfg(not(feature = "full_crypto"))] +impl CryptoType for Public +{} + +//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> {} + +/// A pair of signatures of different types +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[scale_info(skip_type_params(T))] +pub struct Signature { + left: LeftSignature, + right: RightSignature, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} + +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); + } +} + +impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let Ok(mut left) = data[0..LEFT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) = data[LEFT_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Ok(Signature { left, right, inner }) + + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } +} + +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.inner + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} + // serializer.serialize_str(&array_bytes::bytes2hex("", self)) + + // let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) + // .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + // Signature::try_from(signature_hex.as_ref()) + // .map_err(|e| de::Error::custom(format!("{:?}", e))) + /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair(LeftPair, RightPair); + + + From f407d87201373fb7e4dcc14a475b40be4dc51f01 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 29 Aug 2023 05:00:05 -0400 Subject: [PATCH 07/78] Attempt to implement trait `Pair` for `pair_cyrpto::Pair` --- .../primitives/core/src/paired_crypto.rs | 198 ++++++++++++++++-- 1 file changed, 180 insertions(+), 18 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 5e384eb1155a..2f6838db8694 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -34,7 +34,6 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; - /// ECDSA and BLS-377 specialized types pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; @@ -59,6 +58,12 @@ pub mod ecdsa_n_bls377 { // impl super::HardJunctionId for TinyBLS377 { // const ID: &'static str = "BLS12377HDKD"; // } + +// impl CryptoType for Signature { +// #[cfg(feature = "full_crypto")] +// type Pair = Pair; +// } + } /// A secret seed. @@ -67,7 +72,7 @@ pub mod ecdsa_n_bls377 { /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -//type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; +type Seed = [u8; {LEFT_PLUS_RIGHT_LEN}]; //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -176,8 +181,8 @@ impl_sp_std::fmt::Debug for Public { +impl sp_std::fmt::Debug for Public { fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { Ok(()) @@ -249,29 +254,35 @@ pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> {} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(T))] -pub struct Signature { +pub struct Signature { left: LeftSignature, right: RightSignature, inner: [u8; LEFT_PLUS_RIGHT_LEN], } +trait SignaturePair { + const LEFT_SIGNATURE_LEN: usize; + const RIGHT_SIGNATURE_LEN: usize; + const LEFT_PLUS_RIGHT_LEN: usize; +} + #[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { +impl sp_std::hash::Hash for Signature { fn hash(&self, state: &mut H) { self.left.hash(state); self.right.hash(state); } } -impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature { +impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature where Signature: SignaturePair { type Error = (); fn try_from(data: &[u8]) -> Result { if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let Ok(mut left) = data[0..LEFT_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) = data[LEFT_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Ok(Signature { left, right, inner }) @@ -279,34 +290,185 @@ impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEF } } -impl AsMut<[u8]> for Signature { +impl AsMut<[u8]> for Signature { fn as_mut(&mut self) -> &mut [u8] { &mut self.inner[..] } } -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner } } -impl AsRef<[u8]> for Signature { +impl AsRef<[u8]> for Signature { fn as_ref(&self) -> &[u8] { &self.inner[..] } } - // serializer.serialize_str(&array_bytes::bytes2hex("", self)) +#[cfg(feature = "std")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&array_bytes::bytes2hex("", self)) + } +} + +#[cfg(feature = "std")] +impl<'de, LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + Signature::try_from(signature_hex.as_ref()) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +impl From> for [u8; LEFT_PLUS_RIGHT_LEN] +{ + fn from(signature: Signature) -> [u8; LEFT_PLUS_RIGHT_LEN] { + signature.inner + } +} + +impl sp_std::fmt::Debug for Signature { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { + fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + let mut left : LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().unwrap(); + let mut right : RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); - // let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - // .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - // Signature::try_from(signature_hex.as_ref()) - // .map_err(|e| de::Error::custom(format!("{:?}", e))) + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Signature { left, right, inner } + } +} /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] -pub struct Pair(LeftPair, RightPair); +pub struct Pair { + left: LeftPair, + right: RightPair, + +} +trait DoublePair { + const PUBLIC_KEY_LEN: usize; + const LEFT_SIGNATURE_LEN: usize; + const RIGHT_SIGNATURE_LEN:usize; + const SIGNATURE_LEN: usize; + const LEFT_SEED_LEN: usize; + const RIGHT_SEED_LEN: usize; +} +trait HardJunctionId { + const ID: &'static str; +} + +#[cfg(feature = "full_crypto")] +impl Pair { +} + +#[cfg(feature = "full_crypto")] +impl TraitPair for Pair where + Pair: DoublePair + CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, +{ + type Seed = (LeftPair::Seed, RightPair::Seed); + type Public = Public::PUBLIC_KEY_LEN}>; + type Signature = Signature; + + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength) + } + let left = LeftPair::from_seed_slice(seed_slice[0..Self::LEFT_SEED_LEN])?; + let right = RightPair::from_seed_slice(seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + Ok(Pair { left, right }) + } + + // fn derive>( + // &self, + // path: Iter, + // _seed: Option, + // ) -> Result<(Self, Option), DeriveError> { + // let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = + // self.0.secret.to_bytes().try_into().expect( + // "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size", + // ); + // for j in path { + // match j { + // DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), + // DeriveJunction::Hard(cc) => acc = derive_hard_junction::(&acc, &cc), + // } + // } + // Ok((Self::from_seed(&acc), Some(acc))) + // } + + // fn public(&self) -> Self::Public { + // let mut raw = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; + // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); + // raw.copy_from_slice(pk.as_slice()); + // Self::Public::unchecked_from(raw) + // } + + // fn sign(&self, message: &[u8]) -> Self::Signature { + // let mut mutable_self = self.clone(); + // let r: [u8; SIGNATURE_SERIALIZED_SIZE] = + // DoublePublicKeyScheme::sign(&mut mutable_self.0, &Message::new(b"", message)) + // .to_bytes() + // .try_into() + // .expect("Signature serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size"); + // Self::Signature::unchecked_from(r) + // } + + // fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + // let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = + // match <[u8; PUBLIC_KEY_SERIALIZED_SIZE]>::try_from(pubkey.as_ref()) { + // Ok(pk) => pk, + // Err(_) => return false, + // }; + // let public_key = match w3f_bls::double::DoublePublicKey::::from_bytes(&pubkey_array) { + // Ok(pk) => pk, + // Err(_) => return false, + // }; + + // let sig_array = match sig.inner[..].try_into() { + // Ok(s) => s, + // Err(_) => return false, + // }; + // let sig = match w3f_bls::double::DoubleSignature::from_bytes(sig_array) { + // Ok(s) => s, + // Err(_) => return false, + // }; + + // sig.verify(&Message::new(b"", message.as_ref()), &public_key) + // } + + // /// Get the seed for this key. + // fn to_raw_vec(&self) -> Vec { + // self.0 + // .secret + // .to_bytes() + // .try_into() + // .expect("Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size") + // } +} From 2606cc4d12617a4123f029ad0653fcc144ac0a94 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 31 Aug 2023 10:11:56 -0400 Subject: [PATCH 08/78] - Implement trait `Pair` for `paired_crypto::Pair` - Implement a pair of seeds for paired crypto scheme. --- .../primitives/core/src/paired_crypto.rs | 172 +++++++++++------- 1 file changed, 105 insertions(+), 67 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 2f6838db8694..b76a7b42c0ff 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -44,7 +44,7 @@ pub mod ecdsa_n_bls377 { /// BLS12-377 key pair. #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair; + pub type Pair = super::Pair; /// BLS12-377 public key. pub type Public = super::Public; // /// BLS12-377 signature. @@ -66,14 +66,26 @@ pub mod ecdsa_n_bls377 { } +#[cfg(feature = "full_crypto")] +const SECURE_SEED_LEN: usize = 32; + +#[cfg(feature = "full_crypto")] +const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; + /// A secret seed. /// /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -type Seed = [u8; {LEFT_PLUS_RIGHT_LEN}]; +pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} +#[cfg(feature = "full_crypto")] +pub struct Seed { + left: LeftSeed, + right: RightSeed, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -120,8 +132,8 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); - let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; + let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Ok(Public { left, right, inner }) @@ -167,9 +179,9 @@ impl From> for Public where Pair : TraitPair>, +impl From> for Public where Pair : TraitPair>, { - fn from(x: Pair) -> Self { + fn from(x: Pair) -> Self { x.public() } } @@ -179,8 +191,7 @@ impl CryptoType for Public {} + //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> {} +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]> {} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] @@ -281,10 +293,13 @@ impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEF if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(left.as_ref()); + inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Ok(Signature { left, right, inner }) } @@ -318,15 +333,17 @@ impl Deserialize<'de> for Signature { +impl<'de,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature where +Signature: for<'a> TryFrom<&'a[u8]>{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("{:?}", e))) + let sighex_ref = signature_hex.as_ref(); + Signature::try_from(sighex_ref) + .map_err(|e| de::Error::custom(format!("Error in converting deserialized data into signature"))) } } @@ -337,7 +354,7 @@ impl sp_std::fmt::Debug for Signature { +impl sp_std::fmt::Debug for Signature where [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef{ #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) @@ -351,8 +368,8 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let mut left : LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().unwrap(); - let mut right : RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Signature { left, right, inner } @@ -362,7 +379,8 @@ impl { +pub struct Pair +{ left: LeftPair, right: RightPair, @@ -383,64 +401,87 @@ trait HardJunctionId { } #[cfg(feature = "full_crypto")] -impl Pair { +impl Pair { } #[cfg(feature = "full_crypto")] -impl TraitPair for Pair where - Pair: DoublePair + CryptoType, +impl TraitPair for Pair where + Pair: DoublePair + CryptoType, LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, +Public: CryptoType, +Signature: SignaturePair, + LeftPair::Seed: SeedBound, + RightPair::Seed: SeedBound, +Seed: SeedBound, { - type Seed = (LeftPair::Seed, RightPair::Seed); - type Public = Public::PUBLIC_KEY_LEN}>; - type Signature = Signature; + type Seed = Seed; + type Public = Public; + type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { return Err(SecretStringError::InvalidSeedLength) } - let left = LeftPair::from_seed_slice(seed_slice[0..Self::LEFT_SEED_LEN])?; - let right = RightPair::from_seed_slice(seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; + let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; Ok(Pair { left, right }) } - // fn derive>( - // &self, - // path: Iter, - // _seed: Option, - // ) -> Result<(Self, Option), DeriveError> { - // let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = - // self.0.secret.to_bytes().try_into().expect( - // "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size", - // ); - // for j in path { - // match j { - // DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), - // DeriveJunction::Hard(cc) => acc = derive_hard_junction::(&acc, &cc), - // } - // } - // Ok((Self::from_seed(&acc), Some(acc))) - // } - - // fn public(&self) -> Self::Public { - // let mut raw = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; - // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); - // raw.copy_from_slice(pk.as_slice()); - // Self::Public::unchecked_from(raw) - // } + fn derive>( + &self, + path: Iter, + seed: Option, + ) -> Result<(Self, Option), DeriveError> { + + let seed_left_right = match seed { + Some(seed) => (Some(seed.left), Some(seed.right)), + //(LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), + None => (None, None), + }; + + let left_path: Vec<_> = path.map(|p|p.clone()).collect(); + let right_path = left_path.clone(); + let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; + let derived_right = self.right.derive(right_path.into_iter(), seed_left_right.1)?; + + let optional_seed = match (derived_left.1, derived_right.1) { + (Some(seed_left), Some(seed_right)) => { + let mut inner = [0u8; DOUBLE_SEED_LEN]; + inner.copy_from_slice(seed_left.as_ref()); + inner[SECURE_SEED_LEN..].copy_from_slice(seed_right.as_ref()); + Some(Self::Seed{left: seed_left, right: seed_right, inner: inner})}, + _ => None, + + }; + // Some(seed) => (LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), + // None => (None, None), + // }; + + Ok((Self{left: derived_left.0, right: derived_right.0}, optional_seed)) + } + + fn public(&self) -> Self::Public { + let mut raw = [0u8; PUBLIC_KEY_LEN]; + let left_pub = self.left.public(); + let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); + raw.copy_from_slice(left_pub.as_ref()); + raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); + Self::Public::unchecked_from(raw) + //Public{left: left_pub, right: right_pub, inner: raw} + } - // fn sign(&self, message: &[u8]) -> Self::Signature { - // let mut mutable_self = self.clone(); - // let r: [u8; SIGNATURE_SERIALIZED_SIZE] = + fn sign(&self, message: &[u8]) -> Self::Signature { + let mut mutable_self = self.clone(); + let r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; // DoublePublicKeyScheme::sign(&mut mutable_self.0, &Message::new(b"", message)) // .to_bytes() // .try_into() // .expect("Signature serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size"); - // Self::Signature::unchecked_from(r) - // } + Self::Signature::unchecked_from(r) + } - // fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { // let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = // match <[u8; PUBLIC_KEY_SERIALIZED_SIZE]>::try_from(pubkey.as_ref()) { // Ok(pk) => pk, @@ -460,15 +501,12 @@ impl TraitPair for Pair return false, // }; - // sig.verify(&Message::new(b"", message.as_ref()), &public_key) - // } + // sig.verify(&Message::new(b"", message.as_ref()), &public_key) + return false; + } - // /// Get the seed for this key. - // fn to_raw_vec(&self) -> Vec { - // self.0 - // .secret - // .to_bytes() - // .try_into() - // .expect("Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size") - // } + /// Get the seed for this key. + fn to_raw_vec(&self) -> Vec { + [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() + } } From 00933da3589c5d6527e40b6b1e6fcf103824bae2 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 5 Sep 2023 16:58:31 -0400 Subject: [PATCH 09/78] implement sgin and verify for --- .../primitives/core/src/paired_crypto.rs | 36 +++++-------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index b76a7b42c0ff..6f9abbc18c39 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -473,36 +473,17 @@ Seed: SeedBound, fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); - let r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - // DoublePublicKeyScheme::sign(&mut mutable_self.0, &Message::new(b"", message)) - // .to_bytes() - // .try_into() - // .expect("Signature serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size"); + let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + r.copy_from_slice(self.left.sign(message).as_ref()); + r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - // let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = - // match <[u8; PUBLIC_KEY_SERIALIZED_SIZE]>::try_from(pubkey.as_ref()) { - // Ok(pk) => pk, - // Err(_) => return false, - // }; - // let public_key = match w3f_bls::double::DoublePublicKey::::from_bytes(&pubkey_array) { - // Ok(pk) => pk, - // Err(_) => return false, - // }; - - // let sig_array = match sig.inner[..].try_into() { - // Ok(s) => s, - // Err(_) => return false, - // }; - // let sig = match w3f_bls::double::DoubleSignature::from_bytes(sig_array) { - // Ok(s) => s, - // Err(_) => return false, - // }; - - // sig.verify(&Message::new(b"", message.as_ref()), &public_key) - return false; + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + let mut vec_message = vec![0u8; message.as_ref().len()]; + vec_message.clone_from_slice(message.as_ref()); + + LeftPair::verify(&sig.left, message, &pubkey.left) && RightPair::verify(&sig.right, vec_message, &pubkey.right) } /// Get the seed for this key. @@ -510,3 +491,4 @@ Seed: SeedBound, [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() } } + From e7719ab3aa1b14ce5fa34b3161f69e403a482c62 Mon Sep 17 00:00:00 2001 From: Skalman Date: Sun, 10 Sep 2023 14:02:12 -0400 Subject: [PATCH 10/78] Actually implementing `paired_crypto::{Pair, Public, Signatrue}` for paired (ECDSA, BLS377) crypto --- substrate/primitives/core/src/bls.rs | 4 +- .../primitives/core/src/paired_crypto.rs | 104 ++++++++++++++---- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 951aa1828ea5..40fc29ffa544 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -89,11 +89,11 @@ const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; // Public key serialized size -const PUBLIC_KEY_SERIALIZED_SIZE: usize = +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; // Signature serialized size -const SIGNATURE_SERIALIZED_SIZE: usize = +pub const SIGNATURE_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; /// A secret seed. diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 6f9abbc18c39..a43f030fdc0f 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -35,34 +35,61 @@ use sp_runtime_interface::pass_by::PassByInner; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// ECDSA and BLS-377 specialized types +#[cfg(feature = "bls-experimental")] pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; - use crate::{ecdsa, ed25519}; + use crate::{ecdsa, ed25519, bls377}; - /// An identifier used to match public keys against BLS12-377 keys - pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); - - /// BLS12-377 key pair. - #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair; + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); + + const PUBLIC_KEY_LEN :usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const LEFT_SIGNATURE_LEN :usize = 64; + const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; + const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; + const LEFT_SEED_LEN: usize = 32; + const RIGHT_SEED_LEN: usize = 32; + + /// BLS12-377 key pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; // /// BLS12-377 signature. - //pub type Signature = super::Signature; - - // impl super::CryptoType for Public - // { - // #[cfg(feature = "full_crypto")] - // type Pair = Pair; - // } - // impl super::HardJunctionId for TinyBLS377 { - // const ID: &'static str = "BLS12377HDKD"; - // } - -// impl CryptoType for Signature { -// #[cfg(feature = "full_crypto")] -// type Pair = Pair; -// } + pub type Signature = super::Signature; + + impl super::SignaturePair for Signature { + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; + const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; + } + + #[cfg(feature = "full_crypto")] + impl super::DoublePair for Pair{ + const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN:usize = RIGHT_SIGNATURE_LEN; + const SIGNATURE_LEN: usize = SIGNATURE_LEN; + const LEFT_SEED_LEN: usize = LEFT_SEED_LEN; + const RIGHT_SEED_LEN: usize = RIGHT_SEED_LEN; + } + + impl super::CryptoType for Public + { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + impl super::CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + #[cfg(feature = "full_crypto")] + impl super::CryptoType for Pair{ + type Pair = Pair; + } + } @@ -80,12 +107,40 @@ const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; #[cfg(feature = "full_crypto")] pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} +impl + AsMut<[u8]> + Clone> SeedBound for SeedTrait {} + #[cfg(feature = "full_crypto")] +#[derive(Clone)] pub struct Seed { left: LeftSeed, right: RightSeed, inner: [u8; LEFT_PLUS_RIGHT_LEN], } + +#[cfg(feature = "full_crypto")] +impl Default for Seed { + fn default() -> Self{ + Self { + left: LeftSeed::default(), right: RightSeed::default(), inner: [LeftSeed::default().as_ref(), RightSeed::default().as_ref()].concat().try_into().unwrap() + } + } +} + +#[cfg(feature = "full_crypto")] +impl AsRef<[u8]> for Seed { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} + +#[cfg(feature = "full_crypto")] +impl AsMut<[u8]> for Seed { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } +} + + //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -263,6 +318,8 @@ impl TryFrom<&'a[u8]> + AsRef<[u8]> {} +impl TryFrom<&'a[u8]> + AsRef<[u8]>> SignatureBound for SignatureTrait {} + /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(T))] @@ -492,3 +549,4 @@ Seed: SeedBound, } } + From 7a9b67777977248e49306a07b6235e69da598f49 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 11 Sep 2023 05:58:28 -0400 Subject: [PATCH 11/78] Implement and pass all test for `paired_crypto` --- substrate/primitives/core/src/crypto.rs | 2 +- substrate/primitives/core/src/hexdisplay.rs | 2 +- .../primitives/core/src/paired_crypto.rs | 242 ++++++++++++++++-- 3 files changed, 216 insertions(+), 30 deletions(-) diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 8c7d98f00cd8..946ebfaeb836 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1197,7 +1197,7 @@ macro_rules! impl_from_entropy_base { [$type; 17], [$type; 18], [$type; 19], [$type; 20], [$type; 21], [$type; 22], [$type; 23], [$type; 24], [$type; 25], [$type; 26], [$type; 27], [$type; 28], [$type; 29], [$type; 30], [$type; 31], [$type; 32], [$type; 36], [$type; 40], [$type; 44], [$type; 48], [$type; 56], [$type; 64], [$type; 72], [$type; 80], - [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 192], [$type; 224], [$type; 256] + [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 177], [$type; 192], [$type; 224], [$type; 256] ); } } diff --git a/substrate/primitives/core/src/hexdisplay.rs b/substrate/primitives/core/src/hexdisplay.rs index 30e045dfc52a..72bb24a186e5 100644 --- a/substrate/primitives/core/src/hexdisplay.rs +++ b/substrate/primitives/core/src/hexdisplay.rs @@ -96,7 +96,7 @@ macro_rules! impl_non_endians { impl_non_endians!( [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], [u8; 48], [u8; 56], - [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128], [u8; 144] + [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128], [u8; 144], [u8; 177] ); /// Format into ASCII + # + hex, suitable for storage key preimages. diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a43f030fdc0f..81d41a52394c 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -39,16 +39,17 @@ use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; use crate::{ecdsa, ed25519, bls377}; + use super::{SECURE_SEED_LEN, DOUBLE_SEED_LEN}; /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); const PUBLIC_KEY_LEN :usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; - const LEFT_SIGNATURE_LEN :usize = 64; + const LEFT_SIGNATURE_LEN :usize = 65; const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; - const LEFT_SEED_LEN: usize = 32; - const RIGHT_SEED_LEN: usize = 32; + const LEFT_SEED_LEN: usize = SECURE_SEED_LEN; + const RIGHT_SEED_LEN: usize = SECURE_SEED_LEN; /// BLS12-377 key pair. #[cfg(feature = "full_crypto")] @@ -58,6 +59,8 @@ pub mod ecdsa_n_bls377 { // /// BLS12-377 signature. pub type Signature = super::Signature; + pub type Seed = super::Seed<[u8; SECURE_SEED_LEN], [u8; SECURE_SEED_LEN], DOUBLE_SEED_LEN,>; + impl super::SignaturePair for Signature { const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; @@ -90,6 +93,22 @@ pub mod ecdsa_n_bls377 { type Pair = Pair; } + impl<'a> TryFrom<&'a[u8]> for Seed { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != DOUBLE_SEED_LEN { + return Err(()) + } + let mut left : [u8; 32] = data[0..SECURE_SEED_LEN].try_into().unwrap(); + let mut right : [u8; 32] = data[SECURE_SEED_LEN..DOUBLE_SEED_LEN].try_into().unwrap(); + + let mut inner = [0u8; DOUBLE_SEED_LEN]; + inner.copy_from_slice(data); + Ok(Seed { left, right, inner }) + + } + } } @@ -141,6 +160,8 @@ impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -184,13 +205,14 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); Ok(Public { left, right, inner }) } @@ -226,7 +248,7 @@ impl Self { - let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); let mut right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); Self { left, right, inner } @@ -354,7 +376,7 @@ impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEF let Ok(mut right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(left.as_ref()); + inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); Ok(Signature { left, right, inner }) @@ -428,8 +450,7 @@ impl: SeedBound, type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { - if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { - return Err(SecretStringError::InvalidSeedLength) - } - let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; - let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; - Ok(Pair { left, right }) + if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength) + } + let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; + let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + Ok(Pair { left, right }) } fn derive>( @@ -493,20 +514,19 @@ Seed: SeedBound, let seed_left_right = match seed { Some(seed) => (Some(seed.left), Some(seed.right)), - //(LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), - None => (None, None), + None => (None, None), }; let left_path: Vec<_> = path.map(|p|p.clone()).collect(); let right_path = left_path.clone(); - let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; + let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; let derived_right = self.right.derive(right_path.into_iter(), seed_left_right.1)?; let optional_seed = match (derived_left.1, derived_right.1) { (Some(seed_left), Some(seed_right)) => { let mut inner = [0u8; DOUBLE_SEED_LEN]; - inner.copy_from_slice(seed_left.as_ref()); - inner[SECURE_SEED_LEN..].copy_from_slice(seed_right.as_ref()); + inner[..Self::LEFT_SEED_LEN].copy_from_slice(seed_left.as_ref()); + inner[Self::LEFT_SEED_LEN..Self::LEFT_SEED_LEN + Self::RIGHT_SEED_LEN].copy_from_slice(seed_right.as_ref()); Some(Self::Seed{left: seed_left, right: seed_right, inner: inner})}, _ => None, @@ -520,9 +540,9 @@ Seed: SeedBound, fn public(&self) -> Self::Public { let mut raw = [0u8; PUBLIC_KEY_LEN]; - let left_pub = self.left.public(); - let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); - raw.copy_from_slice(left_pub.as_ref()); + let left_pub = self.left.public(); + let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); + raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); Self::Public::unchecked_from(raw) //Public{left: left_pub, right: right_pub, inner: raw} @@ -531,8 +551,8 @@ Seed: SeedBound, fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - r.copy_from_slice(self.left.sign(message).as_ref()); - r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); + r[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } @@ -545,8 +565,174 @@ Seed: SeedBound, /// Get the seed for this key. fn to_raw_vec(&self) -> Vec { - [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() + [self.left.to_raw_vec(), self.right.to_raw_vec()].concat() } } + +// Test set exercising the BLS12-377 implementation +#[cfg(test)] +mod test { + use super::*; + use crate::crypto::DEV_PHRASE; + use ecdsa_n_bls377::{Pair, Signature, Seed}; + use hex_literal::hex; + + + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) + .unwrap() + .public(), + ); + } + + #[test] + fn seed_and_derive_should_work() { + let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); + let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); + // we are using hash to field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + assert_eq!( + derived.to_raw_vec(), + [hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d")].concat() + ); + } + + + #[test] + fn test_vector_should_work() { + let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + ), + ), + ); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f609d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + ), + ), + ); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } + + + #[test] + fn seeded_pair_should_work() { + let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + ), + ); + let message = + hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn signature_serialization_works() { + let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + let serialized_signature = serde_json::to_string(&signature).unwrap(); + println!("{:?} -- {:}", signature.inner, serialized_signature); + // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy + assert_eq!(serialized_signature.len(), 356); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::verify(&signature, &message[..], &pair.public())); + } + + #[test] + fn signature_serialization_doesnt_panic() { + fn deserialize_signature(text: &str) -> Result { + serde_json::from_str(text) + } + assert!(deserialize_signature("Not valid json.").is_err()); + assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature("\"abc123\"").is_err()); + } +} From a01a814d6764a89a55c2ef7619f25e63f3b35c18 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 25 Sep 2023 15:53:15 -0400 Subject: [PATCH 12/78] - move to signle seed for both schemes in `primitives/core/src/paired_crypto.rs`. - put serialize and descerialze under `serde` feature instead of std. - in `primitives/core/src/bls.rs`. - fix documentation in `primitives/core/src/bls.rs`. - cargo fmt pair_crypto.rs --- substrate/primitives/core/src/bls.rs | 19 +- .../primitives/core/src/paired_crypto.rs | 828 ++++++++++-------- 2 files changed, 473 insertions(+), 374 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 40fc29ffa544..8e9f8ec356a9 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -83,16 +83,16 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {} impl BlsBound for T {} -// Secret key serialized size +/// Secret key serialized size #[cfg(feature = "full_crypto")] const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Public key serialized size +/// Public key serialized size pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Signature serialized size +/// Signature serialized size pub const SIGNATURE_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; @@ -258,7 +258,7 @@ impl sp_std::fmt::Debug for Public { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl Serialize for Public { fn serialize(&self, serializer: S) -> Result where @@ -268,7 +268,7 @@ impl Serialize for Public { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T: BlsBound> Deserialize<'de> for Public { fn deserialize(deserializer: D) -> Result where @@ -330,7 +330,7 @@ impl TryFrom<&[u8]> for Signature { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where @@ -340,7 +340,7 @@ impl Serialize for Signature { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result where @@ -529,11 +529,10 @@ mod test { ); } - // Only passes if the seed = (seed mod ScalarField) #[test] fn seed_and_derive_should_work() { let seed = array_bytes::hex2array_unchecked( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00", + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", ); let pair = Pair::from_seed(&seed); // we are using hash to field so this is not going to work @@ -543,7 +542,7 @@ mod test { assert_eq!( derived.to_raw_vec(), array_bytes::hex2array_unchecked::<_, 32>( - "a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d" + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" ) ); } diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 81d41a52394c..968930b73d51 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -10,7 +10,7 @@ // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the Licenseff is distributed on an "AS IS" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -32,151 +32,110 @@ use scale_info::TypeInfo; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; -use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; +use sp_std::convert::TryFrom; -/// ECDSA and BLS-377 specialized types +/// ECDSA and BLS-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_n_bls377 { - use crate::crypto::{CryptoTypeId}; - use crate::{ecdsa, ed25519, bls377}; - use super::{SECURE_SEED_LEN, DOUBLE_SEED_LEN}; - - /// An identifier used to match public keys against BLS12-377 keys - pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); - - const PUBLIC_KEY_LEN :usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; - const LEFT_SIGNATURE_LEN :usize = 65; - const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; - const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; - const LEFT_SEED_LEN: usize = SECURE_SEED_LEN; - const RIGHT_SEED_LEN: usize = SECURE_SEED_LEN; - - /// BLS12-377 key pair. - #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair; - /// BLS12-377 public key. - pub type Public = super::Public; - // /// BLS12-377 signature. - pub type Signature = super::Signature; - - pub type Seed = super::Seed<[u8; SECURE_SEED_LEN], [u8; SECURE_SEED_LEN], DOUBLE_SEED_LEN,>; - - impl super::SignaturePair for Signature { - const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; - const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; - const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; - } - - #[cfg(feature = "full_crypto")] - impl super::DoublePair for Pair{ - const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; - const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; - const RIGHT_SIGNATURE_LEN:usize = RIGHT_SIGNATURE_LEN; - const SIGNATURE_LEN: usize = SIGNATURE_LEN; - const LEFT_SEED_LEN: usize = LEFT_SEED_LEN; - const RIGHT_SEED_LEN: usize = RIGHT_SEED_LEN; - } - - impl super::CryptoType for Public - { - #[cfg(feature = "full_crypto")] - type Pair = Pair; - } - - impl super::CryptoType for Signature { - #[cfg(feature = "full_crypto")] - type Pair = Pair; - } - - #[cfg(feature = "full_crypto")] - impl super::CryptoType for Pair{ - type Pair = Pair; - } - - impl<'a> TryFrom<&'a[u8]> for Seed { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != DOUBLE_SEED_LEN { - return Err(()) - } - let mut left : [u8; 32] = data[0..SECURE_SEED_LEN].try_into().unwrap(); - let mut right : [u8; 32] = data[SECURE_SEED_LEN..DOUBLE_SEED_LEN].try_into().unwrap(); - - let mut inner = [0u8; DOUBLE_SEED_LEN]; - inner.copy_from_slice(data); - Ok(Seed { left, right, inner }) - - } - } + use crate::crypto::CryptoTypeId; + use crate::{bls377, ecdsa}; -} + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); -#[cfg(feature = "full_crypto")] -const SECURE_SEED_LEN: usize = 32; + const PUBLIC_KEY_LEN: usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const LEFT_SIGNATURE_LEN: usize = 65; + const RIGHT_SIGNATURE_LEN: usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; + const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; -#[cfg(feature = "full_crypto")] -const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; + /// (ECDSA, BLS12-377) key-pair pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; + /// (ECDSA, BLS12-377) public key pair. + pub type Public = super::Public; + /// (ECDSA, BLS12-377) signature pair. + pub type Signature = super::Signature; -/// A secret seed. -/// -/// It's not called a "secret key" because ring doesn't expose the secret keys -/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we -/// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] -pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} + impl super::SignaturePair for Signature { + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; + const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; + } -impl + AsMut<[u8]> + Clone> SeedBound for SeedTrait {} + #[cfg(feature = "full_crypto")] + impl super::DoublePair for Pair { + const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; + const SIGNATURE_LEN: usize = SIGNATURE_LEN; + } -#[cfg(feature = "full_crypto")] -#[derive(Clone)] -pub struct Seed { - left: LeftSeed, - right: RightSeed, - inner: [u8; LEFT_PLUS_RIGHT_LEN], -} + impl super::CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } -#[cfg(feature = "full_crypto")] -impl Default for Seed { - fn default() -> Self{ - Self { - left: LeftSeed::default(), right: RightSeed::default(), inner: [LeftSeed::default().as_ref(), RightSeed::default().as_ref()].concat().try_into().unwrap() + impl super::CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + #[cfg(feature = "full_crypto")] + impl super::CryptoType for Pair { + type Pair = Pair; } - } } +/// currently only supporting sub-schemes whose seed is a 32-bytes array. #[cfg(feature = "full_crypto")] -impl AsRef<[u8]> for Seed { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } -} +const SECURE_SEED_LEN: usize = 32; +/// A secret seed. +/// +/// It's not called a "secret key" because ring doesn't expose the secret keys +/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we +/// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -impl AsMut<[u8]> for Seed { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } +type Seed = [u8; SECURE_SEED_LEN]; + +/// trait characterizing Public key which could be used as individual component of an `paired_crypto:Public` pair. +pub trait PublicKeyBound: + TraitPublic + + Sized + + Derive + + sp_std::hash::Hash + + ByteArray + + for<'a> TryFrom<&'a [u8]> + + AsMut<[u8]> + + CryptoType +{ } - - - -//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} - -impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType> PublicKeyBound for PublicKeyTrait {} +impl< + PublicKeyTrait: TraitPublic + + Sized + + Derive + + sp_std::hash::Hash + + ByteArray + + for<'a> TryFrom<&'a [u8]> + + AsMut<[u8]> + + CryptoType, + > PublicKeyBound for PublicKeyTrait +{ +} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct Public { - left: LeftPublic, - right: RightPublic, - inner: [u8; LEFT_PLUS_RIGHT_LEN], +pub struct Public< + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_LEN: usize, +> { + left: LeftPublic, + right: RightPublic, + inner: [u8; LEFT_PLUS_RIGHT_LEN], } -// We essentially could implement this instead of storing left and right but we are going to end up copying left and right. +// We essentially could implement the following instead of storing left and right but we are going to end up copying and deserializing left and right, to perform any operation and that will take a hit on performance. // impl Public { // inline fn left<'a>(&self)-> &'a LeftPublic { // &LeftPublic::try_from(&self.inner[0..LeftPublic::LEN]).unwrap() @@ -186,57 +145,69 @@ pub struct Public sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); +impl + sp_std::hash::Hash for Public +{ + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl ByteArray for Public { - const LEN: usize = LEFT_PLUS_RIGHT_LEN; +impl + ByteArray for Public +{ + const LEN: usize = LEFT_PLUS_RIGHT_LEN; } -impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; - let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; +impl + TryFrom<&[u8]> for Public +{ + type Error = (); - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(data); - Ok(Public { left, right, inner }) + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()); + } + let left: LeftPublic = data[0..LeftPublic::LEN].try_into()?; + let right: RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; - } + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); + Ok(Public { left, right, inner }) + } } - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } + +impl + AsMut<[u8]> for Public +{ + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } } -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { +impl + AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner - } + } } -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } +impl + AsRef<[u8]> for Public +{ + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } } -impl PassByInner for Public { +impl + PassByInner for Public +{ type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; fn into_inner(self) -> Self::Inner { @@ -248,33 +219,49 @@ impl Self { - let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); - let mut right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let left: LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let right: RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); Self { left, right, inner } } } #[cfg(feature = "full_crypto")] -impl From> for Public where Pair : TraitPair>, - { +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + const SIGNATURE_LEN: usize, + > From> + for Public +where + Pair: + TraitPair>, +{ fn from(x: Pair) -> Self { x.public() } } -impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { +impl + UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public +{ fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); - let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let left: LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let right: RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); - Public { left: left, right: right, inner: data } + Public { left, right, inner: data } } - } #[cfg(feature = "std")] -impl std::str::FromStr for Public where Public : CryptoType { +impl + std::str::FromStr for Public +where + Public: CryptoType, +{ type Err = crate::crypto::PublicError; fn from_str(s: &str) -> Result { @@ -283,14 +270,23 @@ impl std::fmt::Display for Public where Public : CryptoType { +impl + std::fmt::Display for Public +where + Public: CryptoType, +{ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } #[cfg(feature = "std")] -impl sp_std::fmt::Debug for Public where Public : CryptoType, [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef { +impl + sp_std::fmt::Debug for Public +where + Public: CryptoType, + [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, +{ fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { let s = self.to_ss58check(); write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.inner), &s[0..8]) @@ -298,111 +294,173 @@ impl sp_std::fmt::Debug for Public { +impl + sp_std::fmt::Debug for Public +{ fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - - Ok(()) + Ok(()) } } #[cfg(feature = "std")] -impl Serialize for Public where Public : CryptoType { +impl + Serialize for Public +where + Public: CryptoType, +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, - { - serializer.serialize_str(&self.to_ss58check()) - + { + serializer.serialize_str(&self.to_ss58check()) } } #[cfg(feature = "std")] -impl<'de, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public where Public : CryptoType { +impl< + 'de, + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Deserialize<'de> for Public +where + Public: CryptoType, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, - { - Public::from_ss58check(&String::deserialize(deserializer)?) + { + Public::from_ss58check(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e))) - } } -impl TraitPublic for Public where Public : CryptoType {} +impl + TraitPublic for Public +where + Public: CryptoType, +{ +} -impl Derive for Public {} +impl + Derive for Public +{ +} #[cfg(not(feature = "full_crypto"))] -impl CryptoType for Public -{} - +impl< + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + > CryptoType for Public +{ +} -//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]> {} +/// trait characterizing a signature which could be used as individual component of an `paired_crypto:Signature` pair. +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> {} -impl TryFrom<&'a[u8]> + AsRef<[u8]>> SignatureBound for SignatureTrait {} +impl TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound + for SignatureTrait +{ +} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(T))] -pub struct Signature { - left: LeftSignature, - right: RightSignature, - inner: [u8; LEFT_PLUS_RIGHT_LEN], +pub struct Signature< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, +> { + left: LeftSignature, + right: RightSignature, + inner: [u8; LEFT_PLUS_RIGHT_LEN], } trait SignaturePair { - const LEFT_SIGNATURE_LEN: usize; - const RIGHT_SIGNATURE_LEN: usize; - const LEFT_PLUS_RIGHT_LEN: usize; + const LEFT_SIGNATURE_LEN: usize; + const RIGHT_SIGNATURE_LEN: usize; + const LEFT_PLUS_RIGHT_LEN: usize; } #[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > sp_std::hash::Hash for Signature +{ + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature where Signature: SignaturePair { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let Ok(mut left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > TryFrom<&[u8]> for Signature +where + Signature: SignaturePair, +{ + type Error = (); - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); - inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()); + } + let Ok(left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; - Ok(Signature { left, right, inner }) + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); + inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); - } + Ok(Signature { left, right, inner }) + } } - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } + +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsMut<[u8]> for Signature +{ + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } } -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner - } + } } -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsRef<[u8]> for Signature +{ + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } } #[cfg(feature = "std")] -impl Serialize for Signature { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Serialize for Signature +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -411,29 +469,56 @@ impl Deserialize<'de> for Signature where -Signature: for<'a> TryFrom<&'a[u8]>{ +#[cfg(feature = "serde")] +impl< + 'de, + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Deserialize<'de> for Signature +where + Signature: SignaturePair, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - let sighex_ref = signature_hex.as_ref(); - Signature::try_from(sighex_ref) - .map_err(|e| de::Error::custom(format!("Error in converting deserialized data into signature"))) + Signature::::try_from( + signature_hex.as_ref(), + ) + .map_err(|e| { + de::Error::custom(format!( + "Error in converting deserialized data into signature: {:?}", + e + )) + }) } } -impl From> for [u8; LEFT_PLUS_RIGHT_LEN] +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > From> + for [u8; LEFT_PLUS_RIGHT_LEN] { - fn from(signature: Signature) -> [u8; LEFT_PLUS_RIGHT_LEN] { + fn from( + signature: Signature, + ) -> [u8; LEFT_PLUS_RIGHT_LEN] { signature.inner } } -impl sp_std::fmt::Debug for Signature where [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef{ +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > sp_std::fmt::Debug for Signature +where + [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, +{ #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) @@ -445,141 +530,150 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature +where + Signature: SignaturePair, +{ fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; - Signature { left, right, inner: data } + Signature { left, right, inner: data } } } /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] -pub struct Pair -{ - left: LeftPair, - right: RightPair, - +pub struct Pair< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, +> { + left: LeftPair, + right: RightPair, } - trait DoublePair { - const PUBLIC_KEY_LEN: usize; - const LEFT_SIGNATURE_LEN: usize; - const RIGHT_SIGNATURE_LEN:usize; - const SIGNATURE_LEN: usize; - const LEFT_SEED_LEN: usize; - const RIGHT_SEED_LEN: usize; -} - -trait HardJunctionId { - const ID: &'static str; + const PUBLIC_KEY_LEN: usize; + const SIGNATURE_LEN: usize; } #[cfg(feature = "full_crypto")] -impl Pair { +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > Pair +{ } #[cfg(feature = "full_crypto")] -impl TraitPair for Pair where - Pair: DoublePair + CryptoType, - LeftPair::Signature: SignatureBound, - RightPair::Signature: SignatureBound, -Public: CryptoType, -Signature: SignaturePair, - LeftPair::Seed: SeedBound, - RightPair::Seed: SeedBound, -Seed: SeedBound, -{ - type Seed = Seed; +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > TraitPair for Pair +where + Pair: DoublePair + CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, + Public: CryptoType, + Signature: SignaturePair, + LeftPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, + RightPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, +{ + type Seed = Seed; type Public = Public; type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { - if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { - return Err(SecretStringError::InvalidSeedLength) - } - let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; - let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; - Ok(Pair { left, right }) + if seed_slice.len() != SECURE_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength); + } + let left = LeftPair::from_seed_slice(&seed_slice)?; + let right = RightPair::from_seed_slice(&seed_slice)?; + Ok(Pair { left, right }) } fn derive>( - &self, - path: Iter, - seed: Option, + &self, + path: Iter, + seed: Option, ) -> Result<(Self, Option), DeriveError> { - - let seed_left_right = match seed { - Some(seed) => (Some(seed.left), Some(seed.right)), - None => (None, None), - }; - - let left_path: Vec<_> = path.map(|p|p.clone()).collect(); - let right_path = left_path.clone(); - let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; - let derived_right = self.right.derive(right_path.into_iter(), seed_left_right.1)?; - - let optional_seed = match (derived_left.1, derived_right.1) { - (Some(seed_left), Some(seed_right)) => { - let mut inner = [0u8; DOUBLE_SEED_LEN]; - inner[..Self::LEFT_SEED_LEN].copy_from_slice(seed_left.as_ref()); - inner[Self::LEFT_SEED_LEN..Self::LEFT_SEED_LEN + Self::RIGHT_SEED_LEN].copy_from_slice(seed_right.as_ref()); - Some(Self::Seed{left: seed_left, right: seed_right, inner: inner})}, - _ => None, - - }; - // Some(seed) => (LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), - // None => (None, None), - // }; - - Ok((Self{left: derived_left.0, right: derived_right.0}, optional_seed)) - } + let (left_seed_option, right_seed_option) = match seed { + Some(seed) => { + let (left_seed, right_seed): (LeftPair::Seed, RightPair::Seed) = + (seed.clone().into(), seed.into()); + (Some(left_seed), Some(right_seed)) + }, + None => (None, None), + }; + + let left_path: Vec<_> = path.map(|p| p.clone()).collect(); + let right_path = left_path.clone(); + let derived_left = self.left.derive(left_path.into_iter(), left_seed_option)?; + let derived_right = self.right.derive(right_path.into_iter(), right_seed_option)?; + + let optional_seed: Option<[u8; SECURE_SEED_LEN]> = match (derived_left.1, derived_right.1) { + (Some(seed_left), Some(seed_right)) => { + if seed_left.as_ref() == seed_right.as_ref() { + Some(seed_left.into()) + } else { + None + } + }, + _ => None, + }; + Ok((Self { left: derived_left.0, right: derived_right.0 }, optional_seed)) + } fn public(&self) -> Self::Public { - let mut raw = [0u8; PUBLIC_KEY_LEN]; - let left_pub = self.left.public(); - let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); - raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); - raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); - Self::Public::unchecked_from(raw) - //Public{left: left_pub, right: right_pub, inner: raw} + let mut raw = [0u8; PUBLIC_KEY_LEN]; + let left_pub = self.left.public(); + let right_pub = self.right.public(); + raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); + raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); + Self::Public::unchecked_from(raw) } fn sign(&self, message: &[u8]) -> Self::Signature { - let mut mutable_self = self.clone(); - let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - r[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); - r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); - Self::Signature::unchecked_from(r) + let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + r[..Self::Signature::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[Self::Signature::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); + Self::Signature::unchecked_from(r) } - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - let mut vec_message = vec![0u8; message.as_ref().len()]; - vec_message.clone_from_slice(message.as_ref()); + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + let mut vec_message = vec![0u8; message.as_ref().len()]; + vec_message.clone_from_slice(message.as_ref()); - LeftPair::verify(&sig.left, message, &pubkey.left) && RightPair::verify(&sig.right, vec_message, &pubkey.right) + LeftPair::verify(&sig.left, message, &pubkey.left) + && RightPair::verify(&sig.right, vec_message, &pubkey.right) } - /// Get the seed for this key. + /// Get the seed/secret key for each key and then concatenate them. fn to_raw_vec(&self) -> Vec { [self.left.to_raw_vec(), self.right.to_raw_vec()].concat() } } - - -// Test set exercising the BLS12-377 implementation +// Test set exercising the (ECDSA, BLS12-377) implementation #[cfg(test)] mod test { use super::*; use crate::crypto::DEV_PHRASE; - use ecdsa_n_bls377::{Pair, Signature, Seed}; + use ecdsa_n_bls377::{Pair, Signature}; use hex_literal::hex; - #[test] fn default_phrase_should_be_used() { assert_eq!( @@ -590,35 +684,38 @@ mod test { ); } - #[test] - fn seed_and_derive_should_work() { - let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); - let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); + #[test] + fn seed_and_derive_should_work() { + let seed_for_right_and_left = + hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&seed_for_right_and_left); // we are using hash to field so this is not going to work // assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.to_raw_vec(), - [hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d")].concat() + [ + hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), + hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + ] + .concat() ); } - - #[test] + #[test] fn test_vector_should_work() { - let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + let seed_left_and_right = + hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" ), - ), - ); + ), + ); let message = b""; let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); let signature = Signature::unchecked_from(signature); @@ -628,18 +725,19 @@ mod test { #[test] fn test_vector_by_string_should_work() { - let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f609d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + let pair = Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", None, ) .unwrap(); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" ), - ), - ); + ), + ); let message = b""; let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); let signature = Signature::unchecked_from(signature); @@ -647,7 +745,7 @@ mod test { assert!(Pair::verify(&signature, &message[..], &public)); } - #[test] + #[test] fn generated_pair_should_work() { let (pair, _) = Pair::generate(); let public = pair.public(); @@ -657,20 +755,20 @@ mod test { assert!(!Pair::verify(&signature, b"Something else", &public)); } - - #[test] + #[test] fn seeded_pair_should_work() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let public = pair.public(); assert_eq!( - public, - Public::unchecked_from( - hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + public, + Public::unchecked_from( + hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ), - ); + ); let message = - hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" - ); + hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -702,8 +800,9 @@ mod test { } #[test] - fn ss58check_roundtrip_works() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + fn ss58check_roundtrip_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let public = pair.public(); let s = public.to_ss58check(); println!("Correct: {}", s); @@ -713,12 +812,13 @@ mod test { #[test] fn signature_serialization_works() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let message = b"Something important"; - let signature = pair.sign(&message[..]); + let signature = pair.sign(&message[..]); - let serialized_signature = serde_json::to_string(&signature).unwrap(); - println!("{:?} -- {:}", signature.inner, serialized_signature); + let serialized_signature = serde_json::to_string(&signature).unwrap(); + println!("{:?} -- {:}", signature.inner, serialized_signature); // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy assert_eq!(serialized_signature.len(), 356); let signature = serde_json::from_str(&serialized_signature).unwrap(); From 7c0265859e1160a7ef12bfb8542ff2c413838767 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 25 Sep 2023 16:33:30 -0400 Subject: [PATCH 13/78] =?UTF-8?q?replace=20`hex!`=20=E2=86=92=20`array=5Fb?= =?UTF-8?q?ytes::hex2xx`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../primitives/core/src/paired_crypto.rs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 968930b73d51..aa9df4d991a6 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -672,7 +672,6 @@ mod test { use super::*; use crate::crypto::DEV_PHRASE; use ecdsa_n_bls377::{Pair, Signature}; - use hex_literal::hex; #[test] fn default_phrase_should_be_used() { @@ -686,8 +685,8 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed_for_right_and_left = - hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = + array_bytes::hex2array_unchecked("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); let pair = Pair::from_seed(&seed_for_right_and_left); // we are using hash to field so this is not going to work // assert_eq!(pair.seed(), seed); @@ -696,8 +695,8 @@ mod test { assert_eq!( derived.to_raw_vec(), [ - hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), - hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") ] .concat() ); @@ -705,19 +704,19 @@ mod test { #[test] fn test_vector_should_work() { - let seed_left_and_right = - hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_left_and_right: [u8; SECURE_SEED_LEN] = + array_bytes::hex2array_unchecked("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); let public = pair.public(); assert_eq!( public, Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" ), ), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -734,12 +733,12 @@ mod test { assert_eq!( public, Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" ), ), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -763,11 +762,11 @@ mod test { assert_eq!( public, Public::unchecked_from( - hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + array_bytes::hex2array_unchecked("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ), ); let message = - hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" ); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); From 7f8d958e731cf6c7501309135530a49dae1b8c46 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:44:56 -0400 Subject: [PATCH 14/78] Apply suggestions from `paired_crypto` code review on type nam, hash and SCALE. Co-authored-by: Davide Galassi --- substrate/primitives/core/src/paired_crypto.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index aa9df4d991a6..313e56ae5388 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -110,7 +110,7 @@ pub trait PublicKeyBound: } impl< - PublicKeyTrait: TraitPublic + T: TraitPublic + Sized + Derive + sp_std::hash::Hash @@ -118,13 +118,13 @@ impl< + for<'a> TryFrom<&'a [u8]> + AsMut<[u8]> + CryptoType, - > PublicKeyBound for PublicKeyTrait + > PublicKeyBound for T { } /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] -#[scale_info(skip_type_params(T))] +#[scale_info(skip_type_params(LeftPublic, RightPublic))] pub struct Public< LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, @@ -152,8 +152,7 @@ impl { fn hash(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); + self.inner.hash(state); } } @@ -359,14 +358,11 @@ impl< /// trait characterizing a signature which could be used as individual component of an `paired_crypto:Signature` pair. pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> {} -impl TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound - for SignatureTrait -{ -} +impl TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound for T {} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] -#[scale_info(skip_type_params(T))] +#[scale_info(skip_type_params(LeftSignature, RightSignature))] pub struct Signature< LeftSignature: SignatureBound, RightSignature: SignatureBound, From eef2cec53dda1ec962498b6e3a349239e83e2881 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:59:14 -0400 Subject: [PATCH 15/78] Do not panic in `paired::Signature::try_from` Co-authored-by: Davide Galassi --- substrate/primitives/core/src/paired_crypto.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 313e56ae5388..da0ff179045e 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -406,8 +406,8 @@ where if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()); } - let Ok(left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let left: LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().map_err(|_| ())?; + let right: RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); From efb215f78ea95346e4f07fa4a2801d83e575d1fe Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:00:27 -0400 Subject: [PATCH 16/78] Remove `DoublePair` trait. Co-authored-by: Davide Galassi --- substrate/primitives/core/src/paired_crypto.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index da0ff179045e..93a052be100c 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -556,10 +556,6 @@ pub struct Pair< right: RightPair, } -trait DoublePair { - const PUBLIC_KEY_LEN: usize; - const SIGNATURE_LEN: usize; -} #[cfg(feature = "full_crypto")] impl< From 65584bd7c58229caaa390f2d9bfb7d242f82198b Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:01:53 -0400 Subject: [PATCH 17/78] Do not empty implement `paired::Pair` Co-authored-by: Davide Galassi --- substrate/primitives/core/src/paired_crypto.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 93a052be100c..e04ead798f72 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -557,15 +557,6 @@ pub struct Pair< } -#[cfg(feature = "full_crypto")] -impl< - LeftPair: TraitPair, - RightPair: TraitPair, - const PUBLIC_KEY_LEN: usize, - const SIGNATURE_LEN: usize, - > Pair -{ -} #[cfg(feature = "full_crypto")] impl< From e047f75a52fda8d9ebc10b4a06558e1cc1b1cf37 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:17:46 -0400 Subject: [PATCH 18/78] Use `paired_crypto::Seed` instead of `[u8; SECURE_SEED_LEN]` Co-authored-by: Davide Galassi --- substrate/primitives/core/src/paired_crypto.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index e04ead798f72..50983ec5eb59 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -571,8 +571,8 @@ where RightPair::Signature: SignatureBound, Public: CryptoType, Signature: SignaturePair, - LeftPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, - RightPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, + LeftPair::Seed: From + Into, + RightPair::Seed: From + Into, { type Seed = Seed; type Public = Public; From c12b82e24d16aa813314b4ec74bf0923eee63714 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 5 Oct 2023 15:08:34 -0400 Subject: [PATCH 19/78] use `ecdsa::PUBLIC_KEY_SERIALIZED_SIZE` and `ecdsa::SIGNATURE_SERIALIZED_SIZE` instead of magic numbers --- substrate/primitives/core/src/ecdsa.rs | 50 +++++++++++-------- .../primitives/core/src/paired_crypto.rs | 4 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 05bc679386c3..ee047e0410df 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -50,6 +50,12 @@ use sp_std::vec::Vec; /// An identifier used to match public keys against ecdsa keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); +/// The byte length of public key +pub const PUBLIC_KEY_SERIALIZED_SIZE :usize = 33; + +/// The byte length of public key +pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; + /// A secret seed (which is bytewise essentially equivalent to a SecretKey). /// /// We need it as a different type because `Seed` is expected to be AsRef<[u8]>. @@ -71,11 +77,11 @@ type Seed = [u8; 32]; PartialOrd, Ord, )] -pub struct Public(pub [u8; 33]); +pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); impl crate::crypto::FromEntropy for Public { fn from_entropy(input: &mut impl codec::Input) -> Result { - let mut result = Self([0u8; 33]); + let mut result = Self([0u8; PUBLIC_KEY_SERIALIZED_SIZE]); input.read(&mut result.0[..])?; Ok(result) } @@ -86,7 +92,7 @@ impl Public { /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; 33]) -> Self { + pub fn from_raw(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Self(data) } @@ -109,7 +115,7 @@ impl Public { } impl ByteArray for Public { - const LEN: usize = 33; + const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; } impl TraitPublic for Public {} @@ -148,8 +154,8 @@ impl From for Public { } } -impl UncheckedFrom<[u8; 33]> for Public { - fn unchecked_from(x: [u8; 33]) -> Self { +impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Public(x) } } @@ -198,14 +204,14 @@ impl<'de> Deserialize<'de> for Public { /// A signature (a 512-bit value, plus 8 bits for recovery ID). #[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] -pub struct Signature(pub [u8; 65]); +pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() == 65 { - let mut inner = [0u8; 65]; + if data.len() == SIGNATURE_SERIALIZED_SIZE { + let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); Ok(Signature(inner)) } else { @@ -239,7 +245,7 @@ impl<'de> Deserialize<'de> for Signature { impl Clone for Signature { fn clone(&self) -> Self { - let mut r = [0u8; 65]; + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(&self.0[..]); Signature(r) } @@ -247,18 +253,18 @@ impl Clone for Signature { impl Default for Signature { fn default() -> Self { - Signature([0u8; 65]) + Signature([0u8; SIGNATURE_SERIALIZED_SIZE]) } } -impl From for [u8; 65] { - fn from(v: Signature) -> [u8; 65] { +impl From for [u8; SIGNATURE_SERIALIZED_SIZE] { + fn from(v: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] { v.0 } } -impl AsRef<[u8; 65]> for Signature { - fn as_ref(&self) -> &[u8; 65] { +impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] { &self.0 } } @@ -287,8 +293,8 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; 65]> for Signature { - fn unchecked_from(data: [u8; 65]) -> Signature { +impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { Signature(data) } } @@ -298,7 +304,7 @@ impl Signature { /// /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! - pub fn from_raw(data: [u8; 65]) -> Signature { + pub fn from_raw(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { Signature(data) } @@ -307,10 +313,10 @@ impl Signature { /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! pub fn from_slice(data: &[u8]) -> Option { - if data.len() != 65 { + if data.len() != SIGNATURE_SERIALIZED_SIZE { return None } - let mut r = [0u8; 65]; + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(data); Some(Signature(r)) } @@ -473,7 +479,7 @@ impl Pair { pub fn verify_deprecated>(sig: &Signature, message: M, pubkey: &Public) -> bool { let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - let parse_signature_overflowing = |x: [u8; 65]| { + let parse_signature_overflowing = |x: [u8; SIGNATURE_SERIALIZED_SIZE]| { let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64]).ok()?; let rid = libsecp256k1::RecoveryId::parse(x[64]).ok()?; Some((sig, rid)) @@ -726,7 +732,7 @@ mod test { let signature = pair.sign(&message[..]); let serialized_signature = serde_json::to_string(&signature).unwrap(); // Signature is 65 bytes, so 130 chars + 2 quote chars - assert_eq!(serialized_signature.len(), 132); + assert_eq!(serialized_signature.len(), SIGNATURE_SERIALIZED_SIZE * 2 + 2); let signature = serde_json::from_str(&serialized_signature).unwrap(); assert!(Pair::verify(&signature, &message[..], &pair.public())); } diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 50983ec5eb59..4188cd848e19 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -43,8 +43,8 @@ pub mod ecdsa_n_bls377 { /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); - const PUBLIC_KEY_LEN: usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; - const LEFT_SIGNATURE_LEN: usize = 65; + const PUBLIC_KEY_LEN: usize = crate::ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const LEFT_SIGNATURE_LEN: usize = crate::ecdsa::SIGNATURE_SERIALIZED_SIZE; const RIGHT_SIGNATURE_LEN: usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; From dba854a7ef736341c051954edcb023628c553e33 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 5 Oct 2023 15:20:34 -0400 Subject: [PATCH 20/78] Remove `paired::DoublePair` impl as well --- substrate/primitives/core/src/paired_crypto.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 4188cd848e19..d9401be8a540 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -62,12 +62,6 @@ pub mod ecdsa_n_bls377 { const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; } - #[cfg(feature = "full_crypto")] - impl super::DoublePair for Pair { - const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; - const SIGNATURE_LEN: usize = SIGNATURE_LEN; - } - impl super::CryptoType for Public { #[cfg(feature = "full_crypto")] type Pair = Pair; @@ -566,7 +560,7 @@ impl< const SIGNATURE_LEN: usize, > TraitPair for Pair where - Pair: DoublePair + CryptoType, + Pair: CryptoType, LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, Public: CryptoType, From 5182c8616b3f68a56f647260370d336429910f94 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 5 Oct 2023 15:46:46 -0400 Subject: [PATCH 21/78] - Implement `BytesArray` for both ecdsa and bls Signatures - Remove `SignaturePair` trait. - Skip encoding redundant copy of paired::Public and Signature and implement Decode --- substrate/primitives/core/src/bls.rs | 4 ++ substrate/primitives/core/src/ecdsa.rs | 4 ++ .../primitives/core/src/paired_crypto.rs | 72 +++++++++++-------- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 8e9f8ec356a9..e3c21832a19b 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -317,6 +317,10 @@ impl sp_std::hash::Hash for Signature { } } +impl ByteArray for Signature { + const LEN: usize = SIGNATURE_SERIALIZED_SIZE; +} + impl TryFrom<&[u8]> for Signature { type Error = (); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index ee047e0410df..1cdf24ac828c 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -206,6 +206,10 @@ impl<'de> Deserialize<'de> for Public { #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); +impl ByteArray for Signature { + const LEN: usize = SIGNATURE_SERIALIZED_SIZE; +} + impl TryFrom<&[u8]> for Signature { type Error = (); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index d9401be8a540..2c098b604d80 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -56,12 +56,6 @@ pub mod ecdsa_n_bls377 { /// (ECDSA, BLS12-377) signature pair. pub type Signature = super::Signature; - impl super::SignaturePair for Signature { - const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; - const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; - const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; - } - impl super::CryptoType for Public { #[cfg(feature = "full_crypto")] type Pair = Pair; @@ -117,18 +111,32 @@ impl< } /// A public key. -#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(LeftPublic, RightPublic))] pub struct Public< LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize, > { + #[codec(skip)] left: LeftPublic, + #[codec(skip)] right: RightPublic, inner: [u8; LEFT_PLUS_RIGHT_LEN], } +impl< + LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize + > Decode for Public +{ + fn decode(i: &mut R) -> Result { + let buf = <[u8; LEFT_PLUS_RIGHT_LEN]>::decode(i)?; + buf.as_slice() + .try_into() + .map_err(|_| codec::Error::from("invalid public key data")) + } +} + // We essentially could implement the following instead of storing left and right but we are going to end up copying and deserializing left and right, to perform any operation and that will take a hit on performance. // impl Public { // inline fn left<'a>(&self)-> &'a LeftPublic { @@ -141,6 +149,7 @@ pub struct Public< // } + #[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Public @@ -350,27 +359,37 @@ impl< } /// trait characterizing a signature which could be used as individual component of an `paired_crypto:Signature` pair. -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> {} +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray {} -impl TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound for T {} +impl TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray> SignatureBound for T {} /// A pair of signatures of different types -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[derive(Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(LeftSignature, RightSignature))] pub struct Signature< LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize, > { + #[codec(skip)] left: LeftSignature, + #[codec(skip)] right: RightSignature, inner: [u8; LEFT_PLUS_RIGHT_LEN], } -trait SignaturePair { - const LEFT_SIGNATURE_LEN: usize; - const RIGHT_SIGNATURE_LEN: usize; - const LEFT_PLUS_RIGHT_LEN: usize; +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Decode for Signature +{ + fn decode(i: &mut R) -> Result { + let buf = <[u8; LEFT_PLUS_RIGHT_LEN]>::decode(i)?; + buf.as_slice() + .try_into() + .map_err(|_| codec::Error::from("invalid signature data")) + } } #[cfg(feature = "full_crypto")] @@ -391,8 +410,6 @@ impl< RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize, > TryFrom<&[u8]> for Signature -where - Signature: SignaturePair, { type Error = (); @@ -400,12 +417,12 @@ where if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()); } - let left: LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().map_err(|_| ())?; - let right: RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; + let left: LeftSignature = data[0..LeftSignature::LEN].try_into().map_err(|_| ())?; + let right: RightSignature = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); - inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); + inner[..LeftSignature::LEN].copy_from_slice(left.as_ref()); + inner[LeftSignature::LEN..].copy_from_slice(right.as_ref()); Ok(Signature { left, right, inner }) } @@ -466,8 +483,6 @@ impl< RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize, > Deserialize<'de> for Signature -where - Signature: SignaturePair, { fn deserialize(deserializer: D) -> Result where @@ -526,12 +541,10 @@ impl< const LEFT_PLUS_RIGHT_LEN: usize, > UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature -where - Signature: SignaturePair, { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let Ok(left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(left) = data[0..LeftSignature::LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; Signature { left, right, inner: data } } @@ -564,7 +577,6 @@ where LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, Public: CryptoType, - Signature: SignaturePair, LeftPair::Seed: From + Into, RightPair::Seed: From + Into, { @@ -624,8 +636,8 @@ where fn sign(&self, message: &[u8]) -> Self::Signature { let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - r[..Self::Signature::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); - r[Self::Signature::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); + r[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[LeftPair::Signature::LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } @@ -795,7 +807,7 @@ mod test { let serialized_signature = serde_json::to_string(&signature).unwrap(); println!("{:?} -- {:}", signature.inner, serialized_signature); - // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy + // Signature is 177 bytes, hexify * 2 + 2 quote charsy assert_eq!(serialized_signature.len(), 356); let signature = serde_json::from_str(&serialized_signature).unwrap(); assert!(Pair::verify(&signature, &message[..], &pair.public())); From 17d0077b5681c95a6d1a8c0d4d045e4a4acf15c9 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 5 Oct 2023 15:59:47 -0400 Subject: [PATCH 22/78] Implement encode_and_decode_(public_key/signature)_works test for paired_crypto::Pair --- .../primitives/core/src/paired_crypto.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 2c098b604d80..a2e7942f6b47 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -823,4 +823,25 @@ mod test { // Poorly-sized assert!(deserialize_signature("\"abc123\"").is_err()); } + + #[test] + fn encode_and_decode_public_key_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let encoded_public = public.encode(); + let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); + assert_eq!(public, decoded_public) + } + + #[test] + fn encode_and_decode_signature_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + let encoded_signature = signature.encode(); + let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); + assert_eq!(signature, decoded_signature) + } } From a7405895f25f8bcb98b3eac7978123f20285f987 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 5 Oct 2023 16:04:38 -0400 Subject: [PATCH 23/78] cargo fmt --- substrate/primitives/core/src/bls.rs | 6 +- substrate/primitives/core/src/ecdsa.rs | 6 +- .../primitives/core/src/paired_crypto.rs | 70 +++++++++++-------- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index e3c21832a19b..7cb788f14c07 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -200,7 +200,7 @@ impl TryFrom<&[u8]> for Public { fn try_from(data: &[u8]) -> Result { if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { - return Err(()) + return Err(()); } let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; r.copy_from_slice(data); @@ -326,7 +326,7 @@ impl TryFrom<&[u8]> for Signature { fn try_from(data: &[u8]) -> Result { if data.len() != SIGNATURE_SERIALIZED_SIZE { - return Err(()) + return Err(()); } let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); @@ -436,7 +436,7 @@ impl TraitPair for Pair { fn from_seed_slice(seed_slice: &[u8]) -> Result { if seed_slice.len() != SECRET_KEY_SERIALIZED_SIZE { - return Err(SecretStringError::InvalidSeedLength) + return Err(SecretStringError::InvalidSeedLength); } let secret = w3f_bls::SecretKey::from_seed(seed_slice); let public = secret.into_public(); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 1cdf24ac828c..3e27acf5b739 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -51,7 +51,7 @@ use sp_std::vec::Vec; pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); /// The byte length of public key -pub const PUBLIC_KEY_SERIALIZED_SIZE :usize = 33; +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33; /// The byte length of public key pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; @@ -139,7 +139,7 @@ impl TryFrom<&[u8]> for Public { fn try_from(data: &[u8]) -> Result { if data.len() != Self::LEN { - return Err(()) + return Err(()); } let mut r = [0u8; Self::LEN]; r.copy_from_slice(data); @@ -318,7 +318,7 @@ impl Signature { /// you are certain that the array actually is a signature. GIGO! pub fn from_slice(data: &[u8]) -> Option { if data.len() != SIGNATURE_SERIALIZED_SIZE { - return None + return None; } let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(data); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a2e7942f6b47..2ea3e4f0387d 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -43,7 +43,8 @@ pub mod ecdsa_n_bls377 { /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); - const PUBLIC_KEY_LEN: usize = crate::ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const PUBLIC_KEY_LEN: usize = + crate::ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; const LEFT_SIGNATURE_LEN: usize = crate::ecdsa::SIGNATURE_SERIALIZED_SIZE; const RIGHT_SIGNATURE_LEN: usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; @@ -125,9 +126,8 @@ pub struct Public< inner: [u8; LEFT_PLUS_RIGHT_LEN], } -impl< - LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize - > Decode for Public +impl + Decode for Public { fn decode(i: &mut R) -> Result { let buf = <[u8; LEFT_PLUS_RIGHT_LEN]>::decode(i)?; @@ -149,7 +149,6 @@ impl< // } - #[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Public @@ -359,9 +358,15 @@ impl< } /// trait characterizing a signature which could be used as individual component of an `paired_crypto:Signature` pair. -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray {} +pub trait SignatureBound: + sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray +{ +} -impl TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray> SignatureBound for T {} +impl TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray> SignatureBound + for T +{ +} /// A pair of signatures of different types #[derive(Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] @@ -418,7 +423,8 @@ impl< return Err(()); } let left: LeftSignature = data[0..LeftSignature::LEN].try_into().map_err(|_| ())?; - let right: RightSignature = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; + let right: RightSignature = + data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; inner[..LeftSignature::LEN].copy_from_slice(left.as_ref()); @@ -544,7 +550,9 @@ impl< { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { let Ok(left) = data[0..LeftSignature::LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { + panic!("invalid signature") + }; Signature { left, right, inner: data } } @@ -563,8 +571,6 @@ pub struct Pair< right: RightPair, } - - #[cfg(feature = "full_crypto")] impl< LeftPair: TraitPair, @@ -674,8 +680,9 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = - array_bytes::hex2array_unchecked("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&seed_for_right_and_left); // we are using hash to field so this is not going to work // assert_eq!(pair.seed(), seed); @@ -684,8 +691,12 @@ mod test { assert_eq!( derived.to_raw_vec(), [ - array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), - array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>( + "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61" + ), + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>( + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" + ) ] .concat() ); @@ -693,8 +704,9 @@ mod test { #[test] fn test_vector_should_work() { - let seed_left_and_right: [u8; SECURE_SEED_LEN] = - array_bytes::hex2array_unchecked("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_left_and_right: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); let public = pair.public(); assert_eq!( @@ -824,24 +836,24 @@ mod test { assert!(deserialize_signature("\"abc123\"").is_err()); } - #[test] - fn encode_and_decode_public_key_works() { + #[test] + fn encode_and_decode_public_key_works() { let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let public = pair.public(); - let encoded_public = public.encode(); - let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); - assert_eq!(public, decoded_public) - } + let encoded_public = public.encode(); + let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); + assert_eq!(public, decoded_public) + } - #[test] - fn encode_and_decode_signature_works() { + #[test] + fn encode_and_decode_signature_works() { let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let message = b"Something important"; let signature = pair.sign(&message[..]); - let encoded_signature = signature.encode(); - let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); - assert_eq!(signature, decoded_signature) - } + let encoded_signature = signature.encode(); + let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); + assert_eq!(signature, decoded_signature) + } } From 79f25e9e717999535963fbbd7444b1d5e25e7af9 Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 6 Oct 2023 12:13:20 -0400 Subject: [PATCH 24/78] - Implement RuntimeAppCrypto and necessery hostApi for ecdsa_bls377 crypto type - Implement ecdsa_bls37_crypto for BEEFY primitives. --- .../application-crypto/src/ecdsa_bls377.rs | 56 +++++++++++++++ .../primitives/application-crypto/src/lib.rs | 2 + .../primitives/consensus/beefy/src/lib.rs | 56 +++++++++++++++ substrate/primitives/core/src/lib.rs | 2 + .../primitives/core/src/paired_crypto.rs | 13 ++-- substrate/primitives/core/src/testing.rs | 2 + substrate/primitives/io/src/lib.rs | 20 +++++- substrate/primitives/keystore/src/lib.rs | 71 ++++++++++++++++++- substrate/primitives/keystore/src/testing.rs | 26 ++++++- 9 files changed, 238 insertions(+), 10 deletions(-) create mode 100644 substrate/primitives/application-crypto/src/ecdsa_bls377.rs diff --git a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs new file mode 100644 index 000000000000..ae4214c9803d --- /dev/null +++ b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs @@ -0,0 +1,56 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! BLS12-377 crypto applications. +use crate::{KeyTypeId, RuntimePublic}; + +pub use sp_core::paired_crypto::ecdsa_bls377::*; + +mod app { + crate::app_crypto!(super, sp_core::testing::ECDSA_BLS377); +} + +#[cfg(feature = "full_crypto")] +pub use app::Pair as AppPair; +pub use app::{Public as AppPublic, Signature as AppSignature}; + +impl RuntimePublic for Public { + type Signature = Signature; + + /// Dummy implementation. Returns an empty vector. + fn all(_key_type: KeyTypeId) -> Vec { + Vec::new() + } + + fn generate_pair(key_type: KeyTypeId, seed: Option>) -> Self { + sp_io::crypto::ecdsa_bls377_generate(key_type, seed) + } + + /// Dummy implementation. Returns `None`. + fn sign>(&self, _key_type: KeyTypeId, _msg: &M) -> Option { + None + } + + /// Dummy implementation. Returns `false`. + fn verify>(&self, _msg: &M, _signature: &Self::Signature) -> bool { + false + } + + fn to_raw_vec(&self) -> Vec { + sp_core::crypto::ByteArray::to_raw_vec(self) + } +} diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 5384220bc9ca..9fab4ccbdc09 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -49,6 +49,8 @@ pub mod bandersnatch; pub mod bls377; #[cfg(feature = "bls-experimental")] pub mod bls381; +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls377; pub mod ecdsa; pub mod ed25519; pub mod sr25519; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index c69e26bf574d..4a842fa42acd 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -140,6 +140,45 @@ pub mod bls_crypto { } } } + +/// BEEFY cryptographic types for (ECDSA,BLS) crypto pair +/// +/// This module basically introduces four crypto types: +/// - `bls_crypto::Pair` +/// - `bls_crypto::Public` +/// - `bls_crypto::Signature` +/// - `bls_crypto::AuthorityId` +/// +/// Your code should use the above types as concrete types for all crypto related +/// functionality. +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls_crypto { + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use sp_application_crypto::{app_crypto, ecdsa_bls377}; + use sp_core::{ecdsa_bls377::Pair as EcdsaBlsPair, crypto::Wraps, Pair as _}; + app_crypto!(ecdsa_bls377, BEEFY_KEY_TYPE); + + /// Identity of a BEEFY authority using BLS as its crypto. + pub type AuthorityId = Public; + + /// Signature for a BEEFY authority using BLS as its crypto. + pub type AuthoritySignature = Signature; + + impl BeefyAuthorityId for AuthorityId + where + ::Output: Into<[u8; 32]>, + { + fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { + // `w3f-bls` library uses IETF hashing standard and as such does not exposes + // a choice of hash to field function. + // We are directly calling into the library to avoid introducing new host call. + // and because BeefyAuthorityId::verify is being called in the runtime so we don't have + + EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) + } + } +} + /// The `ConsensusEngineId` of BEEFY. pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; @@ -458,4 +497,21 @@ mod tests { let (other_pair, _) = bls_crypto::Pair::generate(); assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); } + + #[test] + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls_beefy_verify_works() { + let msg = &b"test-message"[..]; + let (pair, _) = ecdsa_bls_crypto::Pair::generate(); + + let signature: ecdsa_bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); + + // Verification works if same hashing function is used when signing and verifying. + assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); + + // Other public key doesn't work + let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); + assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); + } + } diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 7174e8b34aad..131d4739a1b0 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -75,6 +75,8 @@ pub mod uint; #[cfg(feature = "bls-experimental")] pub use bls::{bls377, bls381}; +#[cfg(feature = "bls-experimental")] +pub use paired_crypto::ecdsa_bls377; pub use self::{ hash::{convert_hash, H160, H256, H512}, diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 2ea3e4f0387d..e25c283da732 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -31,12 +31,12 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use sp_runtime_interface::pass_by::PassByInner; +use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::convert::TryFrom; /// ECDSA and BLS-377 paired crypto scheme #[cfg(feature = "bls-experimental")] -pub mod ecdsa_n_bls377 { +pub mod ecdsa_bls377 { use crate::crypto::CryptoTypeId; use crate::{bls377, ecdsa}; @@ -227,6 +227,11 @@ impl PassBy for Public { + type PassBy = pass_by::Inner; +} + + #[cfg(feature = "full_crypto")] impl< LeftPair: TraitPair, @@ -369,7 +374,7 @@ impl TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray } /// A pair of signatures of different types -#[derive(Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[derive(Clone, Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(LeftSignature, RightSignature))] pub struct Signature< LeftSignature: SignatureBound, @@ -666,7 +671,7 @@ where mod test { use super::*; use crate::crypto::DEV_PHRASE; - use ecdsa_n_bls377::{Pair, Signature}; + use ecdsa_bls377::{Pair, Signature}; #[test] fn default_phrase_should_be_used() { diff --git a/substrate/primitives/core/src/testing.rs b/substrate/primitives/core/src/testing.rs index 25f5f9012c99..5a84beac7f7f 100644 --- a/substrate/primitives/core/src/testing.rs +++ b/substrate/primitives/core/src/testing.rs @@ -31,6 +31,8 @@ pub const BANDERSNATCH: KeyTypeId = KeyTypeId(*b"band"); pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); /// Key type for generic BLS12-381 key. pub const BLS381: KeyTypeId = KeyTypeId(*b"bls8"); +/// Key type for (ECDSA, BLS12-377) key pair +pub const ECDSA_BLS377: KeyTypeId = KeyTypeId(*b"ecb7"); /// Macro for exporting functions from wasm in with the expected signature for using it with the /// wasm executor. This is useful for tests where you need to call a function in wasm. diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index ec098a155c9c..2730c152c515 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -106,7 +106,7 @@ use sp_core::{ }; #[cfg(feature = "bls-experimental")] -use sp_core::bls377; +use sp_core::{bls377, ecdsa_bls377}; #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1192,7 +1192,8 @@ pub trait Crypto { Ok(pubkey.serialize()) } - /// Generate an `bls12-377` key for the given key type using an optional `seed` and + + /// Generate an `bls12-377` key for the given key type using an optional `seed` and /// store it in the keystore. /// /// The `seed` needs to be a valid utf8. @@ -1207,6 +1208,21 @@ pub trait Crypto { .expect("`bls377_generate` failed") } + // Generate an pair of `(ecdsa,bls12-377)` key for the given key type using an optional `seed` and + /// store it in the keystore. + /// + /// The `seed` needs to be a valid utf8. + /// + /// Returns the public key. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate(&mut self, id: KeyTypeId, seed: Option>) -> ecdsa_bls377::Public { + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + self.extension::() + .expect("No `keystore` associated for the current context!") + .ecdsa_bls377_generate_new(id, seed) + .expect("`ecdsa_bls377_generate` failed") + } + /// Generate a `bandersnatch` key pair for the given key type using an optional /// `seed` and store it in the keystore. /// diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 035af7099a6f..926abb225867 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -23,7 +23,7 @@ pub mod testing; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, @@ -270,6 +270,10 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn bls377_public_keys(&self, id: KeyTypeId) -> Vec; + /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec; + /// Generate a new bls381 key pair for the given key type and an optional seed. /// /// Returns an `bls381::Public` key of the generated key pair or an `Err` if @@ -292,6 +296,18 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result; + + /// Generate a new (ecdsa,bls377) key pair for the given key type and an optional seed. + /// + /// Returns an `ecdsa_bls377::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result; + /// Generate a bls381 signature for a given message. /// /// Receives [`KeyTypeId`] and a [`bls381::Public`] key to be able to map @@ -324,6 +340,22 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; + /// Generate a (ecdsa, bls377) signature pair for a given message. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error>; + /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; @@ -348,7 +380,8 @@ pub trait Keystore: Send + Sync { /// - ecdsa /// - bandersnatch /// - bls381 - /// - bls377 + /// - bls377 + /// - (ecdsa,bls377) paired keys /// /// To support more schemes you can overwrite this method. /// @@ -398,6 +431,13 @@ pub trait Keystore: Send + Sync { .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; self.bls377_sign(id, &public, msg)?.map(|s| s.encode()) }, + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => { + let public = ecdsa_bls377::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) + }, + _ => return Err(Error::KeyNotSupported(id)), }; Ok(signature) @@ -560,6 +600,11 @@ impl Keystore for Arc { (**self).bls377_public_keys(id) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec { + (**self).ecdsa_bls377_public_keys(id) + } + #[cfg(feature = "bls-experimental")] fn bls381_generate_new( &self, @@ -578,7 +623,17 @@ impl Keystore for Arc { (**self).bls377_generate_new(key_type, seed) } - #[cfg(feature = "bls-experimental")] + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + (**self).ecdsa_bls377_generate_new(key_type, seed) + } + + #[cfg(feature = "bls-experimental")] fn bls381_sign( &self, key_type: KeyTypeId, @@ -598,6 +653,16 @@ impl Keystore for Arc { (**self).bls377_sign(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + (**self).ecdsa_bls377_sign(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index efa35fd24bf4..feb755fe578b 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,7 +22,7 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, @@ -322,6 +322,30 @@ impl Keystore for MemoryKeystore { self.sign::(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + self.generate_new::(key_type, seed) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + self.sign::(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() From 489522f888e023ebdb72cd1f6b1f0bc8f379e0bd Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 6 Oct 2023 12:16:33 -0400 Subject: [PATCH 25/78] cargo fmt --- .../primitives/application-crypto/src/lib.rs | 2 +- .../primitives/consensus/beefy/src/lib.rs | 17 +++++++------- substrate/primitives/keystore/src/lib.rs | 22 +++++++++---------- substrate/primitives/keystore/src/testing.rs | 2 +- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 9fab4ccbdc09..686b486f3353 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -49,9 +49,9 @@ pub mod bandersnatch; pub mod bls377; #[cfg(feature = "bls-experimental")] pub mod bls381; +pub mod ecdsa; #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377; -pub mod ecdsa; pub mod ed25519; pub mod sr25519; mod traits; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 4a842fa42acd..f3e801aa4ccc 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -155,7 +155,7 @@ pub mod bls_crypto { pub mod ecdsa_bls_crypto { use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; - use sp_core::{ecdsa_bls377::Pair as EcdsaBlsPair, crypto::Wraps, Pair as _}; + use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair, Pair as _}; app_crypto!(ecdsa_bls377, BEEFY_KEY_TYPE); /// Identity of a BEEFY authority using BLS as its crypto. @@ -325,12 +325,12 @@ where // have different validator set ids, // or both votes have the same commitment, // --> the equivocation is invalid. - if first.id != second.id || - first.commitment.block_number != second.commitment.block_number || - first.commitment.validator_set_id != second.commitment.validator_set_id || - first.commitment.payload == second.commitment.payload + if first.id != second.id + || first.commitment.block_number != second.commitment.block_number + || first.commitment.validator_set_id != second.commitment.validator_set_id + || first.commitment.payload == second.commitment.payload { - return false + return false; } // check signatures on both votes are valid @@ -338,7 +338,7 @@ where let valid_second = check_commitment_signature(&second.commitment, &second.id, &second.signature); - return valid_first && valid_second + return valid_first && valid_second; } /// New BEEFY validator set notification hook. @@ -498,7 +498,7 @@ mod tests { assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); } - #[test] + #[test] #[cfg(feature = "bls-experimental")] fn ecdsa_bls_beefy_verify_works() { let msg = &b"test-message"[..]; @@ -513,5 +513,4 @@ mod tests { let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); } - } diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 926abb225867..9fbb336f195c 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -270,7 +270,7 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn bls377_public_keys(&self, id: KeyTypeId) -> Vec; - /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. + /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec; @@ -296,7 +296,6 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result; - /// Generate a new (ecdsa,bls377) key pair for the given key type and an optional seed. /// /// Returns an `ecdsa_bls377::Public` key of the generated key pair or an `Err` if @@ -340,7 +339,7 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; - /// Generate a (ecdsa, bls377) signature pair for a given message. + /// Generate a (ecdsa, bls377) signature pair for a given message. /// /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map /// them to a private key that exists in the keystore. @@ -348,7 +347,7 @@ pub trait Keystore: Send + Sync { /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` /// and `public` combination doesn't exist in the keystore. /// An `Err` will be returned if generating the signature itself failed. - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_sign( &self, key_type: KeyTypeId, @@ -380,8 +379,8 @@ pub trait Keystore: Send + Sync { /// - ecdsa /// - bandersnatch /// - bls381 - /// - bls377 - /// - (ecdsa,bls377) paired keys + /// - bls377 + /// - (ecdsa,bls377) paired keys /// /// To support more schemes you can overwrite this method. /// @@ -437,7 +436,7 @@ pub trait Keystore: Send + Sync { .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) }, - + _ => return Err(Error::KeyNotSupported(id)), }; Ok(signature) @@ -623,8 +622,7 @@ impl Keystore for Arc { (**self).bls377_generate_new(key_type, seed) } - - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_generate_new( &self, key_type: KeyTypeId, @@ -633,7 +631,7 @@ impl Keystore for Arc { (**self).ecdsa_bls377_generate_new(key_type, seed) } - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn bls381_sign( &self, key_type: KeyTypeId, @@ -653,7 +651,7 @@ impl Keystore for Arc { (**self).bls377_sign(key_type, public, msg) } - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_sign( &self, key_type: KeyTypeId, @@ -661,7 +659,7 @@ impl Keystore for Arc { msg: &[u8], ) -> Result, Error> { (**self).ecdsa_bls377_sign(key_type, public, msg) - } + } fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index feb755fe578b..7f5dfd9faa71 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -345,7 +345,7 @@ impl Keystore for MemoryKeystore { ) -> Result, Error> { self.sign::(key_type, public, msg) } - + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() From 05e08b3eabd54b06699a8ae5a53abec61eaf65db Mon Sep 17 00:00:00 2001 From: Skalman Date: Sat, 7 Oct 2023 20:39:36 -0400 Subject: [PATCH 26/78] make BEEFY Keystore and Worker generic over AuthorityId --- substrate/client/consensus/beefy/Cargo.toml | 2 + .../client/consensus/beefy/src/aux_schema.rs | 21 ++- .../beefy/src/communication/gossip.rs | 133 +++++++++------ .../beefy/src/communication/notification.rs | 13 +- .../outgoing_requests_engine.rs | 45 ++++-- .../client/consensus/beefy/src/import.rs | 38 +++-- .../consensus/beefy/src/justification.rs | 49 +++--- .../client/consensus/beefy/src/keystore.rs | 144 ++++++++++++----- substrate/client/consensus/beefy/src/lib.rs | 69 +++++--- substrate/client/consensus/beefy/src/round.rs | 63 +++++--- .../client/consensus/beefy/src/worker.rs | 151 ++++++++++++------ .../application-crypto/src/traits.rs | 2 +- .../consensus/beefy/src/commitment.rs | 2 +- .../primitives/consensus/beefy/src/lib.rs | 1 + 14 files changed, 493 insertions(+), 240 deletions(-) diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index aae5a44d7fa2..8538ff66ee9b 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -36,6 +36,8 @@ sp-core = { path = "../../../primitives/core" } sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } +sp-std = { path = "../../../primitives/std", default-features = false} +smart-default = "0.6.0" [dev-dependencies] serde = "1.0.188" diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 409eb30d09ab..f9b026039105 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -18,11 +18,13 @@ //! Schema for BEEFY state persisted in the aux-db. -use crate::{worker::PersistedState, LOG_TARGET}; +use crate::{keystore::AuthorityIdBound, worker::PersistedState, LOG_TARGET}; use codec::{Decode, Encode}; use log::{info, trace}; use sc_client_api::{backend::AuxStore, Backend}; +use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{Error as ClientError, Result as ClientResult}; +use sp_consensus_beefy::{BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID}; use sp_runtime::traits::Block as BlockT; const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; @@ -36,10 +38,13 @@ pub(crate) fn write_current_version(backend: &BE) -> ClientResult< } /// Write voter state. -pub(crate) fn write_voter_state( +pub(crate) fn write_voter_state( backend: &BE, - state: &PersistedState, -) -> ClientResult<()> { + state: &PersistedState, +) -> ClientResult<()> +where + ::Signature: Send + Sync, +{ trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); AuxStore::insert_aux(backend, &[(WORKER_STATE_KEY, state.encode().as_slice())], &[]) } @@ -54,17 +59,21 @@ fn load_decode(backend: &BE, key: &[u8]) -> ClientResul } /// Load or initialize persistent data from backend. -pub(crate) fn load_persistent(backend: &BE) -> ClientResult>> +pub(crate) fn load_persistent( + backend: &BE, +) -> ClientResult>> where B: BlockT, BE: Backend, + ::Signature: Send + Sync, { let version: Option = load_decode(backend, VERSION_KEY)?; match version { None => (), Some(1) | Some(2) | Some(3) => (), // versions 1, 2 & 3 are obsolete and should be ignored - Some(4) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), + Some(4) => + return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), other => return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), } diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 8c025ca06761..8cc004a3e606 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -23,7 +23,7 @@ use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorCon use sp_core::hashing::twox_64; use sp_runtime::traits::{Block, Hash, Header, NumberFor}; -use codec::{Decode, DecodeAll, Encode}; +use codec::{Decode, DecodeAll, Encode, WrapperTypeEncode}; use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -37,12 +37,15 @@ use crate::{ justification::{ proof_block_num_and_set_id, verify_with_validator_set, BeefyVersionedFinalityProof, }, - keystore::BeefyKeystore, + keystore::{AuthorityIdBound, BeefyKeystore}, LOG_TARGET, }; +use sp_application_crypto::RuntimeAppPublic; use sp_consensus_beefy::{ - ecdsa_crypto::{AuthorityId, Signature}, - ValidatorSet, ValidatorSetId, VoteMessage, + //ecdsa_crypto::{Public as EcdsaPublic}, + ValidatorSet, + ValidatorSetId, + VoteMessage, }; // Timeout for rebroadcasting messages. @@ -74,16 +77,25 @@ enum Consider { /// BEEFY gossip message type that gets encoded and sent on the network. #[derive(Debug, Encode, Decode)] -pub(crate) enum GossipMessage { +pub(crate) enum GossipMessage +where + ::Signature: Send + Sync, +{ /// BEEFY message with commitment and single signature. - Vote(VoteMessage, AuthorityId, Signature>), + Vote(VoteMessage, AuthorityId, ::Signature>), /// BEEFY justification with commitment and signatures. - FinalityProof(BeefyVersionedFinalityProof), + FinalityProof(BeefyVersionedFinalityProof), } -impl GossipMessage { +impl GossipMessage +where + ::Signature: Send + Sync, +{ /// Return inner vote if this message is a Vote. - pub fn unwrap_vote(self) -> Option, AuthorityId, Signature>> { + pub fn unwrap_vote( + self, + ) -> Option, AuthorityId, ::Signature>> + { match self { GossipMessage::Vote(vote) => Some(vote), GossipMessage::FinalityProof(_) => None, @@ -91,7 +103,7 @@ impl GossipMessage { } /// Return inner finality proof if this message is a FinalityProof. - pub fn unwrap_finality_proof(self) -> Option> { + pub fn unwrap_finality_proof(self) -> Option> { match self { GossipMessage::Vote(_) => None, GossipMessage::FinalityProof(proof) => Some(proof), @@ -119,31 +131,43 @@ where pub type MessageHash = [u8; 8]; #[derive(Clone, Debug)] -pub(crate) struct GossipFilterCfg<'a, B: Block> { +pub(crate) struct GossipFilterCfg<'a, B: Block, AuthorityId: AuthorityIdBound> +where + ::Signature: Send + Sync, +{ pub start: NumberFor, pub end: NumberFor, pub validator_set: &'a ValidatorSet, } #[derive(Clone, Debug)] -struct FilterInner { +struct FilterInner +where + ::Signature: Send + Sync, +{ pub start: NumberFor, pub end: NumberFor, pub validator_set: ValidatorSet, } -struct Filter { - inner: Option>, +struct Filter +where + ::Signature: Send + Sync, +{ + inner: Option>, live_votes: BTreeMap, fnv::FnvHashSet>, } -impl Filter { +impl Filter +where + ::Signature: Send + Sync, +{ pub fn new() -> Self { Self { inner: None, live_votes: BTreeMap::new() } } /// Update filter to new `start` and `set_id`. - fn update(&mut self, cfg: GossipFilterCfg) { + fn update(&mut self, cfg: GossipFilterCfg) { self.live_votes.retain(|&round, _| round >= cfg.start && round <= cfg.end); // only clone+overwrite big validator_set if set_id changed match self.inner.as_mut() { @@ -226,25 +250,28 @@ impl Filter { /// rejected/expired. /// ///All messaging is handled in a single BEEFY global topic. -pub(crate) struct GossipValidator +pub(crate) struct GossipValidator where B: Block, + ::Signature: Send + Sync, { votes_topic: B::Hash, justifs_topic: B::Hash, - gossip_filter: RwLock>, + gossip_filter: RwLock>, next_rebroadcast: Mutex, known_peers: Arc>>, report_sender: TracingUnboundedSender, } -impl GossipValidator +impl GossipValidator where B: Block, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { pub(crate) fn new( known_peers: Arc>>, - ) -> (GossipValidator, TracingUnboundedReceiver) { + ) -> (GossipValidator, TracingUnboundedReceiver) { let (tx, rx) = tracing_unbounded("mpsc_beefy_gossip_validator", 10_000); let val = GossipValidator { votes_topic: votes_topic::(), @@ -260,7 +287,7 @@ where /// Update gossip validator filter. /// /// Only votes for `set_id` and rounds `start <= round <= end` will be accepted. - pub(crate) fn update_filter(&self, filter: GossipFilterCfg) { + pub(crate) fn update_filter(&self, filter: GossipFilterCfg) { debug!(target: LOG_TARGET, "🥩 New gossip filter {:?}", filter); self.gossip_filter.write().update(filter); } @@ -271,7 +298,7 @@ where fn validate_vote( &self, - vote: VoteMessage, AuthorityId, Signature>, + vote: VoteMessage, AuthorityId, ::Signature>, sender: &PeerId, data: &[u8], ) -> Action { @@ -322,10 +349,10 @@ where fn validate_finality_proof( &self, - proof: BeefyVersionedFinalityProof, + proof: BeefyVersionedFinalityProof, sender: &PeerId, ) -> Action { - let (round, set_id) = proof_block_num_and_set_id::(&proof); + let (round, set_id) = proof_block_num_and_set_id::(&proof); self.known_peers.lock().note_vote_for(*sender, round); let guard = self.gossip_filter.read(); @@ -341,7 +368,7 @@ where .validator_set() .map(|validator_set| { if let Err((_, signatures_checked)) = - verify_with_validator_set::(round, validator_set, &proof) + verify_with_validator_set::(round, validator_set, &proof) { debug!( target: LOG_TARGET, @@ -359,9 +386,11 @@ where } } -impl Validator for GossipValidator +impl Validator for GossipValidator where B: Block, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { fn peer_disconnected(&self, _context: &mut dyn ValidatorContext, who: &PeerId) { self.known_peers.lock().remove(who); @@ -374,7 +403,7 @@ where mut data: &[u8], ) -> ValidationResult { let raw = data; - let action = match GossipMessage::::decode_all(&mut data) { + let action = match GossipMessage::::decode_all(&mut data) { Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender, raw), Ok(GossipMessage::FinalityProof(proof)) => self.validate_finality_proof(proof, sender), Err(e) => { @@ -402,26 +431,28 @@ where fn message_expired<'a>(&'a self) -> Box bool + 'a> { let filter = self.gossip_filter.read(); - Box::new(move |_topic, mut data| match GossipMessage::::decode_all(&mut data) { - Ok(GossipMessage::Vote(msg)) => { - let round = msg.commitment.block_number; - let set_id = msg.commitment.validator_set_id; - let expired = filter.consider_vote(round, set_id) != Consider::Accept; - trace!(target: LOG_TARGET, "🥩 Vote for round #{} expired: {}", round, expired); - expired - }, - Ok(GossipMessage::FinalityProof(proof)) => { - let (round, set_id) = proof_block_num_and_set_id::(&proof); - let expired = filter.consider_finality_proof(round, set_id) != Consider::Accept; - trace!( - target: LOG_TARGET, - "🥩 Finality proof for round #{} expired: {}", - round, + Box::new(move |_topic, mut data| { + match GossipMessage::::decode_all(&mut data) { + Ok(GossipMessage::Vote(msg)) => { + let round = msg.commitment.block_number; + let set_id = msg.commitment.validator_set_id; + let expired = filter.consider_vote(round, set_id) != Consider::Accept; + trace!(target: LOG_TARGET, "🥩 Vote for round #{} expired: {}", round, expired); expired - ); - expired - }, - Err(_) => true, + }, + Ok(GossipMessage::FinalityProof(proof)) => { + let (round, set_id) = proof_block_num_and_set_id::(&proof); + let expired = filter.consider_finality_proof(round, set_id) != Consider::Accept; + trace!( + target: LOG_TARGET, + "🥩 Finality proof for round #{} expired: {}", + round, + expired + ); + expired + }, + Err(_) => true, + } }) } @@ -446,7 +477,7 @@ where return do_rebroadcast } - match GossipMessage::::decode_all(&mut data) { + match GossipMessage::::decode_all(&mut data) { Ok(GossipMessage::Vote(msg)) => { let round = msg.commitment.block_number; let set_id = msg.commitment.validator_set_id; @@ -455,7 +486,7 @@ where allowed }, Ok(GossipMessage::FinalityProof(proof)) => { - let (round, set_id) = proof_block_num_and_set_id::(&proof); + let (round, set_id) = proof_block_num_and_set_id::(&proof); let allowed = filter.consider_finality_proof(round, set_id) == Consider::Accept; trace!( target: LOG_TARGET, @@ -478,8 +509,8 @@ pub(crate) mod tests { use sc_network_test::Block; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - ecdsa_crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, - SignedCommitment, VoteMessage, + ecdsa_crypto::{Public as EcdsaPublic, Signature}, + known_payloads, Commitment, Keyring, MmrRootHash, Payload, SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -538,7 +569,7 @@ pub(crate) mod tests { pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store = MemoryKeystore::new(); store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store.into()).into(); + let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } diff --git a/substrate/client/consensus/beefy/src/communication/notification.rs b/substrate/client/consensus/beefy/src/communication/notification.rs index a4486e523c30..c30dc2afaf78 100644 --- a/substrate/client/consensus/beefy/src/communication/notification.rs +++ b/substrate/client/consensus/beefy/src/communication/notification.rs @@ -19,7 +19,7 @@ use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; use sp_runtime::traits::Block as BlockT; -use crate::justification::BeefyVersionedFinalityProof; +use crate::{justification::BeefyVersionedFinalityProof, keystore::AuthorityIdBound}; /// The sending half of the notifications channel(s) used to send /// notifications about best BEEFY block from the gadget side. @@ -32,13 +32,16 @@ pub type BeefyBestBlockStream = /// The sending half of the notifications channel(s) used to send notifications /// about versioned finality proof generated at the end of a BEEFY round. -pub type BeefyVersionedFinalityProofSender = - NotificationSender>; +pub type BeefyVersionedFinalityProofSender = + NotificationSender>; /// The receiving half of a notifications channel used to receive notifications /// about versioned finality proof generated at the end of a BEEFY round. -pub type BeefyVersionedFinalityProofStream = - NotificationStream, BeefyVersionedFinalityProofTracingKey>; +pub type BeefyVersionedFinalityProofStream = + NotificationStream< + BeefyVersionedFinalityProof, + BeefyVersionedFinalityProofTracingKey, + >; /// Provides tracing key for BEEFY best block stream. #[derive(Clone)] diff --git a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index ef462a54fca5..1912c86ba88f 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -26,7 +26,8 @@ use sc_network::{ request_responses::{IfDisconnected, RequestFailure}, NetworkRequest, PeerId, ProtocolName, }; -use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, ValidatorSet}; +use sp_application_crypto::RuntimeAppPublic; +use sp_consensus_beefy::ValidatorSet; use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; @@ -37,6 +38,7 @@ use crate::{ request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, }, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + keystore::AuthorityIdBound, metric_inc, metrics::{register_metrics, OnDemandOutgoingRequestsMetrics}, KnownPeers, @@ -48,38 +50,53 @@ type Response = Result, RequestFailure>; type ResponseReceiver = oneshot::Receiver; #[derive(Clone, Debug)] -struct RequestInfo { +struct RequestInfo +where + ::Signature: Send + Sync, +{ block: NumberFor, active_set: ValidatorSet, } -enum State { +enum State +where + ::Signature: Send + Sync, +{ Idle, - AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), + AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), } /// Possible engine responses. -pub(crate) enum ResponseInfo { +pub(crate) enum ResponseInfo +where + ::Signature: Send + Sync, +{ /// No peer response available yet. Pending, /// Valid justification provided alongside peer reputation changes. - ValidProof(BeefyVersionedFinalityProof, PeerReport), + ValidProof(BeefyVersionedFinalityProof, PeerReport), /// No justification yet, only peer reputation changes. PeerReport(PeerReport), } -pub struct OnDemandJustificationsEngine { +pub struct OnDemandJustificationsEngine +where + ::Signature: Send + Sync, +{ network: Arc, protocol_name: ProtocolName, live_peers: Arc>>, peers_cache: VecDeque, - state: State, + state: State, metrics: Option, } -impl OnDemandJustificationsEngine { +impl OnDemandJustificationsEngine +where + ::Signature: Send + Sync, +{ pub fn new( network: Arc, protocol_name: ProtocolName, @@ -111,7 +128,7 @@ impl OnDemandJustificationsEngine { None } - fn request_from_peer(&mut self, peer: PeerId, req_info: RequestInfo) { + fn request_from_peer(&mut self, peer: PeerId, req_info: RequestInfo) { debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 requesting justif #{:?} from peer {:?}", req_info.block, peer, @@ -172,9 +189,9 @@ impl OnDemandJustificationsEngine { fn process_response( &mut self, peer: &PeerId, - req_info: &RequestInfo, + req_info: &RequestInfo, response: Result, - ) -> Result, Error> { + ) -> Result, Error> { response .map_err(|e| { debug!( @@ -205,7 +222,7 @@ impl OnDemandJustificationsEngine { } }) .and_then(|encoded| { - decode_and_verify_finality_proof::( + decode_and_verify_finality_proof::( &encoded[..], req_info.block, &req_info.active_set, @@ -225,7 +242,7 @@ impl OnDemandJustificationsEngine { }) } - pub(crate) async fn next(&mut self) -> ResponseInfo { + pub(crate) async fn next(&mut self) -> ResponseInfo { let (peer, req_info, resp) = match &mut self.state { State::Idle => { futures::future::pending::<()>().await; diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index 5b2abb20aced..b20fd94378ec 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -21,6 +21,7 @@ use std::sync::Arc; use log::debug; use sp_api::ProvideRuntimeApi; +use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, BeefyApi, BEEFY_ENGINE_ID}; use sp_runtime::{ @@ -34,6 +35,7 @@ use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResul use crate::{ communication::notification::BeefyVersionedFinalityProofSender, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + keystore::AuthorityIdBound, metric_inc, metrics::BlockImportMetrics, LOG_TARGET, @@ -45,15 +47,22 @@ use crate::{ /// Wraps a `inner: BlockImport` and ultimately defers to it. /// /// When using BEEFY, the block import worker should be using this block import object. -pub struct BeefyBlockImport { +pub struct BeefyBlockImport +where + ::Signature: Send + Sync, +{ backend: Arc, runtime: Arc, inner: I, - justification_sender: BeefyVersionedFinalityProofSender, + justification_sender: BeefyVersionedFinalityProofSender, metrics: Option, } -impl Clone for BeefyBlockImport { +impl Clone + for BeefyBlockImport +where + ::Signature: Send + Sync, +{ fn clone(&self) -> Self { BeefyBlockImport { backend: self.backend.clone(), @@ -65,32 +74,38 @@ impl Clone for BeefyBlockImport BeefyBlockImport { +impl + BeefyBlockImport +where + ::Signature: Send + Sync, +{ /// Create a new BeefyBlockImport. pub fn new( backend: Arc, runtime: Arc, inner: I, - justification_sender: BeefyVersionedFinalityProofSender, + justification_sender: BeefyVersionedFinalityProofSender, metrics: Option, - ) -> BeefyBlockImport { + ) -> BeefyBlockImport { BeefyBlockImport { backend, runtime, inner, justification_sender, metrics } } } -impl BeefyBlockImport +impl BeefyBlockImport where Block: BlockT, BE: Backend, Runtime: ProvideRuntimeApi, Runtime::Api: BeefyApi + Send, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { fn decode_and_verify( &self, encoded: &EncodedJustification, number: NumberFor, hash: ::Hash, - ) -> Result, ConsensusError> { + ) -> Result, ConsensusError> { use ConsensusError::ClientImport as ImportError; let beefy_genesis = self .runtime @@ -108,19 +123,22 @@ where .map_err(|e| ImportError(e.to_string()))? .ok_or_else(|| ImportError("Unknown validator set".to_string()))?; - decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) + decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) .map_err(|(err, _)| err) } } #[async_trait::async_trait] -impl BlockImport for BeefyBlockImport +impl BlockImport + for BeefyBlockImport where Block: BlockT, BE: Backend, I: BlockImport + Send + Sync, Runtime: ProvideRuntimeApi + Send + Sync, Runtime::Api: BeefyApi, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { type Error = ConsensusError; diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 483184e2374a..458925dc07e3 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -16,21 +16,25 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::keystore::BeefyKeystore; -use codec::{DecodeAll, Encode}; +use crate::keystore::{AuthorityIdBound, BeefyKeystore}; +use codec::{Decode, DecodeAll, Encode, WrapperTypeEncode}; +use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; -use sp_consensus_beefy::{ - ecdsa_crypto::{AuthorityId, Signature}, - ValidatorSet, ValidatorSetId, VersionedFinalityProof, -}; +use sp_consensus_beefy::{ValidatorSet, ValidatorSetId, VersionedFinalityProof}; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// A finality proof with matching BEEFY authorities' signatures. -pub type BeefyVersionedFinalityProof = VersionedFinalityProof, Signature>; - -pub(crate) fn proof_block_num_and_set_id( - proof: &BeefyVersionedFinalityProof, -) -> (NumberFor, ValidatorSetId) { +pub type BeefyVersionedFinalityProof +where + ::Signature: Encode + Decode, += VersionedFinalityProof, ::Signature>; + +pub(crate) fn proof_block_num_and_set_id( + proof: &BeefyVersionedFinalityProof, +) -> (NumberFor, ValidatorSetId) +where + ::Signature: Send + Sync, +{ match proof { VersionedFinalityProof::V1(sc) => (sc.commitment.block_number, sc.commitment.validator_set_id), @@ -38,22 +42,29 @@ pub(crate) fn proof_block_num_and_set_id( } /// Decode and verify a Beefy FinalityProof. -pub(crate) fn decode_and_verify_finality_proof( +pub(crate) fn decode_and_verify_finality_proof( encoded: &[u8], target_number: NumberFor, validator_set: &ValidatorSet, -) -> Result, (ConsensusError, u32)> { - let proof = >::decode_all(&mut &*encoded) +) -> Result, (ConsensusError, u32)> +where + ::Signature: Send + Sync, +{ + let proof = >::decode_all(&mut &*encoded) .map_err(|_| (ConsensusError::InvalidJustification, 0))?; - verify_with_validator_set::(target_number, validator_set, &proof).map(|_| proof) + verify_with_validator_set::(target_number, validator_set, &proof) + .map(|_| proof) } /// Verify the Beefy finality proof against the validator set at the block it was generated. -pub(crate) fn verify_with_validator_set( +pub(crate) fn verify_with_validator_set( target_number: NumberFor, validator_set: &ValidatorSet, - proof: &BeefyVersionedFinalityProof, -) -> Result<(), (ConsensusError, u32)> { + proof: &BeefyVersionedFinalityProof, +) -> Result<(), (ConsensusError, u32)> +where + ::Signature: Send + Sync, +{ let mut signatures_checked = 0u32; match proof { VersionedFinalityProof::V1(signed_commitment) => { @@ -76,7 +87,7 @@ pub(crate) fn verify_with_validator_set( .as_ref() .map(|sig| { signatures_checked += 1; - BeefyKeystore::verify(id, sig, &message[..]) + BeefyKeystore::verify(*id, sig, &message[..]) }) .unwrap_or(false) }) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 925bb0882822..1c0f14d7817c 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -16,15 +16,23 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, RuntimeAppPublic}; -use sp_core::keccak_256; +use codec::{Codec, Decode, Encode}; +use core::fmt::{Debug, Display}; + +use sp_application_crypto::{ + key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, AppPublic, RuntimeAppPublic, +}; +use sp_core::{crypto::Wraps, keccak_256}; use sp_keystore::KeystorePtr; +use sp_std::marker::PhantomData; use log::warn; +use sp_consensus_beefy::{ecdsa_crypto::Public as EcdsaPublic, BeefyAuthorityId}; + +#[cfg(feature = "bls-experimental")] use sp_consensus_beefy::{ - ecdsa_crypto::{Public, Signature}, - BeefyAuthorityId, + bls_crypto::Public as BlsPublic, ecdsa_bls_crypto::Public as EcdsaBlsPublic, }; use crate::{error, LOG_TARGET}; @@ -32,25 +40,58 @@ use crate::{error, LOG_TARGET}; /// Hasher used for BEEFY signatures. pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256; -/// A BEEFY specific keystore implemented as a `Newtype`. This is basically a -/// wrapper around [`sp_keystore::Keystore`] and allows to customize -/// common cryptographic functionality. -pub(crate) struct BeefyKeystore(Option); +pub trait AuthorityIdBound: + Codec + + Debug + + Clone + + Ord + + Sync + + Send + + AsRef<[u8]> + + AppPublic + + AppCrypto + + RuntimeAppPublic + + Display + + BeefyAuthorityId +where + ::Signature: Send + Sync, +{ +} -impl BeefyKeystore { +// impl + AppPublic + AppCrypto + +// RuntimeAppPublic + BeefyAuthorityId > AuthorityIdBound for T { type +// Signature = AppCrypto::Signature; } + +/// A BEEFY specific keystore i mplemented as a `Newtype`. This is basically a +/// wrapper around [`sp_keystore::Keystore`] and allows to customize +/// commoncryptographic functionality. +pub(crate) struct BeefyKeystore( + Option, + PhantomData AuthorityId>, +) +where + ::Signature: Send + Sync; + +impl BeefyKeystore +where + ::Signature: Send + Sync, +{ /// Check if the keystore contains a private key for one of the public keys /// contained in `keys`. A public key with a matching private key is known /// as a local authority id. /// /// Return the public key for which we also do have a private key. If no /// matching private key is found, `None` will be returned. - pub fn authority_id(&self, keys: &[Public]) -> Option { + pub fn authority_id(&self, keys: &[AuthorityId]) -> Option { let store = self.0.clone()?; // we do check for multiple private keys as a key store sanity check. - let public: Vec = keys + let public: Vec = keys .iter() - .filter(|k| store.has_keys(&[(k.to_raw_vec(), BEEFY_KEY_TYPE)])) + .filter(|k| { + store + .has_keys(&[(::to_raw_vec(k), BEEFY_KEY_TYPE)]) + }) .cloned() .collect(); @@ -71,32 +112,56 @@ impl BeefyKeystore { /// Note that `message` usually will be pre-hashed before being signed. /// /// Return the message signature or an error in case of failure. - pub fn sign(&self, public: &Public, message: &[u8]) -> Result { + pub fn sign( + &self, + public: &AuthorityId, + message: &[u8], + ) -> Result<::Signature, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let msg = keccak_256(message); - let public = public.as_ref(); + //TODO: ECDSA is different from other methods because it needs to be hashed by keccak_256 - let sig = store - .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, public, &msg) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?; + // let msg = keccak_256(message); + // let public = public.as_inner_ref(); - // check that `sig` has the expected result type - let sig = sig.clone().try_into().map_err(|_| { - error::Error::Signature(format!("invalid signature {:?} for key {:?}", sig, public)) - })?; + // let sig = store + // .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, public.as_slice(), &msg) + // .map_err(|e| error::Error::Keystore(e.to_string()))? + // .ok_or_else(|| error::Error::AuthorityId::Signature("ecdsa_sign_prehashed() + // failed".to_string()))?; + + let sig = store + .sign_with( + ::ID, + ::CRYPTO_ID, + public.as_slice(), + message, + ) + .map_err(|e| error::Error::Signature(format!("{}. Key: {:?}", e, public)))? + .ok_or_else(|| { + error::Error::Signature(format!( + "Could not find key in keystore. Key: {:?}", + public + )) + })?; + + //check that `sig` has the expected result type + let sig = ::Signature::decode(&mut sig.clone().as_slice()) + .map_err(|_| { + error::Error::Signature(format!("invalid signature {:?} for key {:?}", sig, public)) + })?; Ok(sig) } /// Returns a vector of [`sp_consensus_beefy::crypto::Public`] keys which are currently /// supported (i.e. found in the keystore). - pub fn public_keys(&self) -> Result, error::Error> { + pub fn public_keys(&self) -> Result, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let pk: Vec = - store.ecdsa_public_keys(BEEFY_KEY_TYPE).drain(..).map(Public::from).collect(); + let pk: Vec = vec![]; + // store.ecdsa_public_keys(BEEFY_KEY_TYPE).drain(..).map(as_ref).map(AuthorityId::from). + // collect(); Ok(pk) } @@ -104,14 +169,21 @@ impl BeefyKeystore { /// Use the `public` key to verify that `sig` is a valid signature for `message`. /// /// Return `true` if the signature is authentic, `false` otherwise. - pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { + pub fn verify( + public: &AuthorityId, + sig: &::Signature, + message: &[u8], + ) -> bool { BeefyAuthorityId::::verify(public, sig, message) } } -impl From> for BeefyKeystore { - fn from(store: Option) -> BeefyKeystore { - BeefyKeystore(store) +impl From> for BeefyKeystore +where + ::Signature: Send + Sync, +{ + fn from(store: Option) -> BeefyKeystore { + BeefyKeystore(store, PhantomData) } } @@ -218,7 +290,7 @@ pub mod tests { let bob = Keyring::Bob.public(); let charlie = Keyring::Charlie.public(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let mut keys = vec![bob, charlie]; @@ -241,7 +313,7 @@ pub mod tests { .unwrap() .into(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let msg = b"are you involved or commited?"; @@ -260,7 +332,7 @@ pub mod tests { .ok() .unwrap(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let alice = Keyring::Alice.public(); @@ -273,7 +345,7 @@ pub mod tests { #[test] fn sign_no_keystore() { - let store: BeefyKeystore = None.into(); + let store: BeefyKeystore = None.into(); let alice = Keyring::Alice.public(); let msg = b"are you involved or commited"; @@ -293,7 +365,7 @@ pub mod tests { .unwrap() .into(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); // `msg` and `sig` match let msg = b"are you involved or commited?"; @@ -330,7 +402,7 @@ pub mod tests { let key1: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); let key2: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let keys = store.public_keys().ok().unwrap(); diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 72df3cab8550..5b4ab0e0e67b 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -41,14 +41,12 @@ use sc_consensus::BlockImport; use sc_network::{NetworkRequest, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi}; +use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, }; use sp_consensus::{Error as ConsensusError, SyncOracle}; -use sp_consensus_beefy::{ - ecdsa_crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, - BEEFY_ENGINE_ID, -}; +use sp_consensus_beefy::{BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID}; use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Zero}; @@ -108,50 +106,62 @@ where /// Links between the block importer, the background voter and the RPC layer, /// to be used by the voter. #[derive(Clone)] -pub struct BeefyVoterLinks { +pub struct BeefyVoterLinks +where + ::Signature: Send + Sync, +{ // BlockImport -> Voter links /// Stream of BEEFY signed commitments from block import to voter. - pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, + pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, // Voter -> RPC links /// Sends BEEFY signed commitments from voter to RPC. - pub to_rpc_justif_sender: BeefyVersionedFinalityProofSender, + pub to_rpc_justif_sender: BeefyVersionedFinalityProofSender, /// Sends BEEFY best block hashes from voter to RPC. pub to_rpc_best_block_sender: BeefyBestBlockSender, } /// Links used by the BEEFY RPC layer, from the BEEFY background voter. #[derive(Clone)] -pub struct BeefyRPCLinks { +pub struct BeefyRPCLinks +where + ::Signature: Send + Sync, +{ /// Stream of signed commitments coming from the voter. - pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, + pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, /// Stream of BEEFY best block hashes coming from the voter. pub from_voter_best_beefy_stream: BeefyBestBlockStream, } /// Make block importer and link half necessary to tie the background voter to it. -pub fn beefy_block_import_and_links( +pub fn beefy_block_import_and_links( wrapped_block_import: I, backend: Arc, runtime: Arc, prometheus_registry: Option, -) -> (BeefyBlockImport, BeefyVoterLinks, BeefyRPCLinks) +) -> ( + BeefyBlockImport, + BeefyVoterLinks, + BeefyRPCLinks, +) where B: Block, BE: Backend, I: BlockImport + Send + Sync, RuntimeApi: ProvideRuntimeApi + Send + Sync, RuntimeApi::Api: BeefyApi, + AuthorityId: keystore::AuthorityIdBound, + ::Signature: Send + Sync, { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = BeefyBestBlockStream::::channel(); // BlockImport -> Voter links let (to_voter_justif_sender, from_block_import_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let metrics = register_metrics(prometheus_registry); // BlockImport @@ -189,7 +199,10 @@ pub struct BeefyNetworkParams { } /// BEEFY gadget initialization parameters. -pub struct BeefyParams { +pub struct BeefyParams +where + ::Signature: Send + Sync, +{ /// BEEFY client pub client: Arc, /// Client Backend @@ -207,7 +220,7 @@ pub struct BeefyParams { /// Prometheus metric registry pub prometheus_registry: Option, /// Links between the block importer, the background voter and the RPC layer. - pub links: BeefyVoterLinks, + pub links: BeefyVoterLinks, /// Handler for incoming BEEFY justifications requests from a remote peer. pub on_demand_justifications_handler: BeefyJustifsRequestHandler, } @@ -215,8 +228,8 @@ pub struct BeefyParams { /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. -pub async fn start_beefy_gadget( - beefy_params: BeefyParams, +pub async fn start_beefy_gadget( + beefy_params: BeefyParams, ) where B: Block, BE: Backend, @@ -226,6 +239,8 @@ pub async fn start_beefy_gadget( R::Api: BeefyApi + MmrApi>, N: GossipNetwork + NetworkRequest + Send + Sync + 'static, S: GossipSyncing + SyncOracle + 'static, + AuthorityId: keystore::AuthorityIdBound, + ::Signature: Send + Sync, { let BeefyParams { client, @@ -353,18 +368,19 @@ pub async fn start_beefy_gadget( } } -fn load_or_init_voter_state( +fn load_or_init_voter_state( backend: &BE, runtime: &R, beefy_genesis: NumberFor, best_grandpa: ::Header, min_block_delta: u32, -) -> ClientResult> +) -> ClientResult> where B: Block, BE: Backend, R: ProvideRuntimeApi, R::Api: BeefyApi, + ::Signature: Send + Sync, { // Initialize voter state from AUX DB if compatible. crate::aux_schema::load_persistent(backend)? @@ -388,18 +404,19 @@ where // - latest BEEFY finalized block, or if none found on the way, // - BEEFY pallet genesis; // Enqueue any BEEFY mandatory blocks (session boundaries) found on the way, for voter to finalize. -fn initialize_voter_state( +fn initialize_voter_state( backend: &BE, runtime: &R, beefy_genesis: NumberFor, best_grandpa: ::Header, min_block_delta: u32, -) -> ClientResult> +) -> ClientResult> where B: Block, BE: Backend, R: ProvideRuntimeApi, R::Api: BeefyApi, + ::Signature: Send + Sync, { let beefy_genesis = runtime .runtime_api() @@ -467,7 +484,7 @@ where .ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))? } - if let Some(active) = worker::find_authorities_change::(&header) { + if let Some(active) = worker::find_authorities_change::(&header) { info!( target: LOG_TARGET, "🥩 Marking block {:?} as BEEFY Mandatory.", @@ -487,7 +504,7 @@ where /// Wait for BEEFY runtime pallet to be available, return active validator set. /// Should be called only once during worker initialization. -async fn wait_for_runtime_pallet( +async fn wait_for_runtime_pallet( runtime: &R, mut gossip_engine: &mut GossipEngine, finality: &mut Fuse>, @@ -496,6 +513,7 @@ where B: Block, R: ProvideRuntimeApi, R::Api: BeefyApi, + ::Signature: Send + Sync, { info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); loop { @@ -528,7 +546,7 @@ where Err(ClientError::Backend(err_msg)) } -fn expect_validator_set( +fn expect_validator_set( runtime: &R, backend: &BE, at_header: &B::Header, @@ -539,6 +557,7 @@ where BE: Backend, R: ProvideRuntimeApi, R::Api: BeefyApi, + ::Signature: Send + Sync, { runtime .runtime_api() @@ -551,7 +570,7 @@ where let blockchain = backend.blockchain(); let mut header = at_header.clone(); while *header.number() >= beefy_genesis { - match worker::find_authorities_change::(&header) { + match worker::find_authorities_change::(&header) { Some(active) => return Some(active), // Move up the chain. None => header = blockchain.expect_header(*header.parent_hash()).ok()?, diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 6f400ce47843..8ce18a3240a0 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -5,7 +5,7 @@ // 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 +// the Free oSftware 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, @@ -16,28 +16,39 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::LOG_TARGET; +use crate::{keystore::AuthorityIdBound, LOG_TARGET}; use codec::{Decode, Encode}; use log::debug; +use sp_application_crypto::RuntimeAppPublic; use sp_consensus_beefy::{ - ecdsa_crypto::{AuthorityId, Signature}, Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; use sp_runtime::traits::{Block, NumberFor}; use std::collections::BTreeMap; +use smart_default::SmartDefault; + /// Tracks for each round which validators have voted/signed and /// whether the local `self` validator has voted/signed. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Debug, Decode, Default, Encode, PartialEq)] -pub(crate) struct RoundTracker { - votes: BTreeMap, +#[derive(Debug, Decode, Encode, PartialEq, SmartDefault)] +pub(crate) struct RoundTracker +where + ::Signature: Send + Sync, +{ + votes: BTreeMap::Signature>, } -impl RoundTracker { - fn add_vote(&mut self, vote: (AuthorityId, Signature)) -> bool { +impl RoundTracker +where + ::Signature: Send + Sync, +{ + fn add_vote( + &mut self, + vote: (AuthorityId, ::Signature), + ) -> bool { if self.votes.contains_key(&vote.0) { return false } @@ -58,10 +69,15 @@ pub fn threshold(authorities: usize) -> usize { } #[derive(Debug, PartialEq)] -pub enum VoteImportResult { +pub enum VoteImportResult +where + ::Signature: Send + Sync, +{ Ok, - RoundConcluded(SignedCommitment, Signature>), - Equivocation(EquivocationProof, AuthorityId, Signature>), + RoundConcluded(SignedCommitment, ::Signature>), + Equivocation( + EquivocationProof, AuthorityId, ::Signature>, + ), Invalid, Stale, } @@ -71,19 +87,26 @@ pub enum VoteImportResult { /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct Rounds { - rounds: BTreeMap>, RoundTracker>, - previous_votes: - BTreeMap<(AuthorityId, NumberFor), VoteMessage, AuthorityId, Signature>>, +pub(crate) struct Rounds +where + ::Signature: Send + Sync, +{ + rounds: BTreeMap>, RoundTracker>, + previous_votes: BTreeMap< + (AuthorityId, NumberFor), + VoteMessage, AuthorityId, ::Signature>, + >, session_start: NumberFor, validator_set: ValidatorSet, mandatory_done: bool, best_done: Option>, } -impl Rounds +impl Rounds where B: Block, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { pub(crate) fn new( session_start: NumberFor, @@ -121,8 +144,8 @@ where pub(crate) fn add_vote( &mut self, - vote: VoteMessage, AuthorityId, Signature>, - ) -> VoteImportResult { + vote: VoteMessage, AuthorityId, ::Signature>, + ) -> VoteImportResult { let num = vote.commitment.block_number; let vote_key = (vote.id.clone(), num); @@ -177,8 +200,8 @@ where fn signed_commitment( &mut self, - round: (Commitment>, RoundTracker), - ) -> SignedCommitment, Signature> { + round: (Commitment>, RoundTracker), + ) -> SignedCommitment, ::Signature> { let votes = round.1.votes; let signatures = self .validators() diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index a239e34030c2..ff0f3e0ae509 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -24,13 +24,15 @@ use crate::{ }, error::Error, justification::BeefyVersionedFinalityProof, - keystore::{BeefyKeystore, BeefySignatureHasher}, + keystore::{AuthorityIdBound, BeefyKeystore, BeefySignatureHasher}, metric_inc, metric_set, metrics::VoterMetrics, round::{Rounds, VoteImportResult}, BeefyVoterLinks, LOG_TARGET, }; -use codec::{Codec, Decode, DecodeAll, Encode}; +use sp_application_crypto::RuntimeAppPublic; + +use codec::{Codec, Decode, DecodeAll, Encode, WrapperTypeEncode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; @@ -40,10 +42,8 @@ use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ - check_equivocation_proof, - ecdsa_crypto::{AuthorityId, Signature}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + check_equivocation_proof, BeefyApi, Commitment, ConsensusLog, EquivocationProof, + PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::OpaqueDigestItemId, @@ -56,6 +56,8 @@ use std::{ sync::Arc, }; +use sp_std::marker::PhantomData; + /// Bound for the number of pending justifications - use 2400 - the max number /// of justifications possible in a single session. const MAX_BUFFERED_JUSTIFICATIONS: usize = 2400; @@ -73,7 +75,10 @@ pub(crate) enum RoundAction { /// Note: this is part of `PersistedState` so any changes here should also bump /// aux-db schema version. #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct VoterOracle { +pub(crate) struct VoterOracle +where + ::Signature: Send + Sync, +{ /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. /// /// There are three voter states coresponding to three queue states: @@ -83,19 +88,25 @@ pub(crate) struct VoterOracle { /// 3. lagging behind GRANDPA: queue has [1, N] elements, where all `mandatory_done == false`. /// In this state, everytime a session gets its mandatory block BEEFY finalized, it's popped /// off the queue, eventually getting to state `2. up-to-date`. - sessions: VecDeque>, + sessions: VecDeque>, /// Min delta in block numbers between two blocks, BEEFY should vote on. min_block_delta: u32, /// Best block we received a GRANDPA finality for. best_grandpa_block_header: ::Header, /// Best block a BEEFY voting round has been concluded for. best_beefy_block: NumberFor, + + _phantom: PhantomData AuthorityId>, } -impl VoterOracle { +impl VoterOracle +where + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, +{ /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. pub fn checked_new( - sessions: VecDeque>, + sessions: VecDeque>, min_block_delta: u32, grandpa_header: ::Header, best_beefy: NumberFor, @@ -137,6 +148,7 @@ impl VoterOracle { min_block_delta: min_block_delta.max(1), best_grandpa_block_header: grandpa_header, best_beefy_block: best_beefy, + _phantom: PhantomData, }) } else { error!( @@ -152,13 +164,13 @@ impl VoterOracle { // Return reference to rounds pertaining to first session in the queue. // Voting will always happen at the head of the queue. - fn active_rounds(&self) -> Result<&Rounds, Error> { + fn active_rounds(&self) -> Result<&Rounds, Error> { self.sessions.front().ok_or(Error::UninitSession) } // Return mutable reference to rounds pertaining to first session in the queue. // Voting will always happen at the head of the queue. - fn active_rounds_mut(&mut self) -> Result<&mut Rounds, Error> { + fn active_rounds_mut(&mut self) -> Result<&mut Rounds, Error> { self.sessions.front_mut().ok_or(Error::UninitSession) } @@ -177,7 +189,7 @@ impl VoterOracle { } /// Add new observed session to the Oracle. - pub fn add_session(&mut self, rounds: Rounds) { + pub fn add_session(&mut self, rounds: Rounds) { self.sessions.push_back(rounds); // Once we add a new session we can drop/prune previous session if it's been finalized. self.try_prune(); @@ -263,21 +275,27 @@ impl VoterOracle { /// /// Note: Any changes here should also bump aux-db schema version. #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct PersistedState { +pub(crate) struct PersistedState +where + ::Signature: Send + Sync, +{ /// Best block we voted on. best_voted: NumberFor, /// Chooses which incoming votes to accept and which votes to generate. /// Keeps track of voting seen for current and future rounds. - voting_oracle: VoterOracle, + voting_oracle: VoterOracle, /// Pallet-beefy genesis block - block number when BEEFY consensus started for this chain. pallet_genesis: NumberFor, } -impl PersistedState { +impl PersistedState +where + ::Signature: Send + Sync, +{ pub fn checked_new( grandpa_header: ::Header, best_beefy: NumberFor, - sessions: VecDeque>, + sessions: VecDeque>, min_block_delta: u32, pallet_genesis: NumberFor, ) -> Option { @@ -306,7 +324,7 @@ impl PersistedState { self.voting_oracle.best_grandpa_block_header = best_grandpa; } - pub(crate) fn gossip_filter_config(&self) -> Result, Error> { + pub(crate) fn gossip_filter_config(&self) -> Result, Error> { let (start, end) = self.voting_oracle.accepted_interval()?; let validator_set = self.voting_oracle.current_validator_set()?; Ok(GossipFilterCfg { start, end, validator_set }) @@ -316,39 +334,45 @@ impl PersistedState { /// Helper object holding BEEFY worker communication/gossip components. /// /// These are created once, but will be reused if worker is restarted/reinitialized. -pub(crate) struct BeefyComms { +pub(crate) struct BeefyComms +where + ::Signature: Send + Sync, +{ pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, + pub gossip_validator: Arc>, pub gossip_report_stream: TracingUnboundedReceiver, - pub on_demand_justifications: OnDemandJustificationsEngine, + pub on_demand_justifications: OnDemandJustificationsEngine, } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker +where + ::Signature: Send + Sync, +{ // utilities pub backend: Arc, pub payload_provider: P, pub runtime: Arc, pub sync: Arc, - pub key_store: BeefyKeystore, + pub key_store: BeefyKeystore, // communication (created once, but returned and reused if worker is restarted/reinitialized) - pub comms: BeefyComms, + pub comms: BeefyComms, // channels /// Links between the block importer, the background voter and the RPC layer. - pub links: BeefyVoterLinks, + pub links: BeefyVoterLinks, // voter state /// BEEFY client metrics. pub metrics: Option, /// Buffer holding justifications for future processing. - pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. - pub persisted_state: PersistedState, + pub persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, @@ -356,16 +380,18 @@ where S: SyncOracle, R: ProvideRuntimeApi, R::Api: BeefyApi, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { fn best_grandpa_block(&self) -> NumberFor { *self.persisted_state.voting_oracle.best_grandpa_block_header.number() } - fn voting_oracle(&self) -> &VoterOracle { + fn voting_oracle(&self) -> &VoterOracle { &self.persisted_state.voting_oracle } - fn active_rounds(&mut self) -> Result<&Rounds, Error> { + fn active_rounds(&mut self) -> Result<&Rounds, Error> { self.persisted_state.voting_oracle.active_rounds() } @@ -473,7 +499,8 @@ where }) .chain(std::iter::once(header.clone())) { - if let Some(new_validator_set) = find_authorities_change::(&header) { + if let Some(new_validator_set) = find_authorities_change::(&header) + { self.init_session_at(new_validator_set, *header.number()); } } @@ -494,13 +521,17 @@ where /// Based on [VoterOracle] this vote is either processed here or discarded. fn triage_incoming_vote( &mut self, - vote: VoteMessage, AuthorityId, Signature>, - ) -> Result<(), Error> { + vote: VoteMessage, AuthorityId, ::Signature>, + ) -> Result<(), Error> + where + ::Signature: Encode + Decode, + { let block_num = vote.commitment.block_number; match self.voting_oracle().triage_round(block_num)? { RoundAction::Process => if let Some(finality_proof) = self.handle_vote(vote)? { - let gossip_proof = GossipMessage::::FinalityProof(finality_proof); + let gossip_proof = + GossipMessage::::FinalityProof(finality_proof); let encoded_proof = gossip_proof.encode(); self.comms.gossip_engine.gossip_message( proofs_topic::(), @@ -519,7 +550,7 @@ where /// Expects `justification` to be valid. fn triage_incoming_justif( &mut self, - justification: BeefyVersionedFinalityProof, + justification: BeefyVersionedFinalityProof, ) -> Result<(), Error> { let signed_commitment = match justification { VersionedFinalityProof::V1(ref sc) => sc, @@ -551,8 +582,8 @@ where fn handle_vote( &mut self, - vote: VoteMessage, AuthorityId, Signature>, - ) -> Result>, Error> { + vote: VoteMessage, AuthorityId, ::Signature>, + ) -> Result>, Error> { let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; let block_number = vote.commitment.block_number; @@ -599,7 +630,10 @@ where /// 4. Send best block hash and `finality_proof` to RPC worker. /// /// Expects `finality proof` to be valid and for a block > current-best-beefy. - fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) -> Result<(), Error> { + fn finalize( + &mut self, + finality_proof: BeefyVersionedFinalityProof, + ) -> Result<(), Error> { let block_num = match finality_proof { VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, }; @@ -762,14 +796,15 @@ where error!(target: LOG_TARGET, "🥩 Error handling self vote: {}", err); err })? { - let encoded_proof = GossipMessage::::FinalityProof(finality_proof).encode(); + let encoded_proof = + GossipMessage::::FinalityProof(finality_proof).encode(); self.comms .gossip_engine .gossip_message(proofs_topic::(), encoded_proof, true); } else { metric_inc!(self, beefy_votes_sent); debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", vote); - let encoded_vote = GossipMessage::::Vote(vote).encode(); + let encoded_vote = GossipMessage::::Vote(vote).encode(); self.comms.gossip_engine.gossip_message(votes_topic::(), encoded_vote, false); } @@ -807,9 +842,11 @@ where /// Should never end, returns `Error` otherwise. pub(crate) async fn run( mut self, - block_import_justif: &mut Fuse>>, + block_import_justif: &mut Fuse< + NotificationReceiver>, + >, finality_notifications: &mut Fuse>, - ) -> (Error, BeefyComms) { + ) -> (Error, BeefyComms) { info!( target: LOG_TARGET, "🥩 run BEEFY worker, best grandpa: #{:?}.", @@ -821,9 +858,10 @@ where .gossip_engine .messages_for(votes_topic::()) .filter_map(|notification| async move { - let vote = GossipMessage::::decode_all(&mut ¬ification.message[..]) - .ok() - .and_then(|message| message.unwrap_vote()); + let vote = + GossipMessage::::decode_all(&mut ¬ification.message[..]) + .ok() + .and_then(|message| message.unwrap_vote()); trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", vote); vote }) @@ -834,9 +872,10 @@ where .gossip_engine .messages_for(proofs_topic::()) .filter_map(|notification| async move { - let proof = GossipMessage::::decode_all(&mut ¬ification.message[..]) - .ok() - .and_then(|message| message.unwrap_finality_proof()); + let proof = + GossipMessage::::decode_all(&mut ¬ification.message[..]) + .ok() + .and_then(|message| message.unwrap_finality_proof()); trace!(target: LOG_TARGET, "🥩 Got gossip proof message: {:?}", proof); proof }) @@ -938,7 +977,11 @@ where /// isn't necessarily the best block if there are pending authority set changes. pub(crate) fn report_equivocation( &self, - proof: EquivocationProof, AuthorityId, Signature>, + proof: EquivocationProof< + NumberFor, + AuthorityId, + ::Signature, + >, ) -> Result<(), Error> { let rounds = self.persisted_state.voting_oracle.active_rounds()?; let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); @@ -994,9 +1037,13 @@ where /// Scan the `header` digest log for a BEEFY validator set change. Return either the new /// validator set or `None` in case no validator set change has been signaled. -pub(crate) fn find_authorities_change(header: &B::Header) -> Option> +pub(crate) fn find_authorities_change( + header: &B::Header, +) -> Option> where B: Block, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); @@ -1076,7 +1123,7 @@ pub(crate) mod tests { &self.voting_oracle } - pub fn active_round(&self) -> Result<&Rounds, Error> { + pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() } @@ -1090,7 +1137,7 @@ pub(crate) mod tests { } impl VoterOracle { - pub fn sessions(&self) -> &VecDeque> { + pub fn sessions(&self) -> &VecDeque> { &self.sessions } } diff --git a/substrate/primitives/application-crypto/src/traits.rs b/substrate/primitives/application-crypto/src/traits.rs index e9b1080f63d9..68c47c86d78b 100644 --- a/substrate/primitives/application-crypto/src/traits.rs +++ b/substrate/primitives/application-crypto/src/traits.rs @@ -10,7 +10,7 @@ // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS,/ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 5b6ef9ae5ab3..2ece99e042e2 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -235,7 +235,7 @@ where /// Note that this enum is subject to change in the future with introduction /// of additional cryptographic primitives to BEEFY. #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] -pub enum VersionedFinalityProof { +pub enum VersionedFinalityProof{ #[codec(index = 1)] /// Current active version V1(SignedCommitment), diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index f3e801aa4ccc..30725c368b9f 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -254,6 +254,7 @@ pub enum ConsensusLog { /// /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. +/// TODO: Remwove Signature get it from Id. #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct VoteMessage { /// Commit to information extracted from a finalized block From 0541cb0083d4435efff1654902c55c49c7b9b054 Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 27 Oct 2023 12:21:49 -0400 Subject: [PATCH 27/78] Fix `BeefyAuthorityId::verify` for `ecdsa_bls_crypto` not to use `ecdsa_bls::verify` --- .../primitives/consensus/beefy/src/lib.rs | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 5bdf8ce010a1..802567369e7c 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -133,7 +133,7 @@ pub mod bls_crypto { ::Output: Into<[u8; 32]>, { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - // `w3f-bls` library uses IETF hashing standard and as such does not exposes + // `w3f-bls` library uses IETF hashing standard and as such does not expose // a choice of hash to field function. // We are directly calling into the library to avoid introducing new host call. // and because BeefyAuthorityId::verify is being called in the runtime so we don't have @@ -157,7 +157,7 @@ pub mod bls_crypto { pub mod ecdsa_bls_crypto { use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; - use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair, Pair as _}; + use sp_core::{bls377, crypto::Wraps, ecdsa, Pair as _}; app_crypto!(ecdsa_bls377, KEY_TYPE); @@ -172,12 +172,30 @@ pub mod ecdsa_bls_crypto { ::Output: Into<[u8; 32]>, { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - // `w3f-bls` library uses IETF hashing standard and as such does not exposes - // a choice of hash to field function. - // We are directly calling into the library to avoid introducing new host call. - // and because BeefyAuthorityId::verify is being called in the runtime so we don't have + // We can not call simply call + // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` + // because that invokes ecdsa default verification which perfoms blake2 hash + // which we don't want. As such we need to re-implement the verification + // of signatures part by part instead of relying on paired crypto + let public: &[u8] = self.as_inner_ref().as_ref(); + let signature: &[u8] = signature.as_inner_ref().as_ref(); + let msg_hash = ::hash(msg).into(); + + let ecdsa_public = + ecdsa::Public::try_from(&public[0..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE]); + let ecdsa_signature = + ecdsa::Signature::try_from(&signature[0..ecdsa::SIGNATURE_SERIALIZED_SIZE]); + + let bls_public = bls377::Public::try_from(&public[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..]); + let bls_signature = + bls377::Signature::try_from(&signature[ecdsa::SIGNATURE_SERIALIZED_SIZE..]); - EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) + return match (ecdsa_public, ecdsa_signature, bls_public, bls_signature) { + (Ok(ecdsa_public), Ok(ecdsa_signature), Ok(bls_public), Ok(bls_signature)) => + ecdsa::Pair::verify_prehashed(&ecdsa_signature, &msg_hash, &ecdsa_public) && + bls377::Pair::verify(&bls_signature, msg, &bls_public), + _ => false, + }; } } } @@ -257,6 +275,7 @@ pub enum ConsensusLog { /// /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. +/// TODO: Remove `Signature` generic type, instead get it from `Id::Signature`. #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct VoteMessage { /// Commit to information extracted from a finalized block @@ -505,15 +524,30 @@ mod tests { #[cfg(feature = "bls-experimental")] fn ecdsa_bls_beefy_verify_works() { let msg = &b"test-message"[..]; - let (pair, _) = ecdsa_bls_crypto::Pair::generate(); - - let signature: ecdsa_bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); + let (ecdsa_pair, _) = ecdsa_crypto::Pair::generate(); + let (bls_pair, _) = bls_crypto::Pair::generate(); + + let ecdsa_keccak_256_signature = ecdsa_pair.as_inner_ref().sign_prehashed(&keccak_256(msg)); + let bls_signature = bls_pair.sign(&msg); + + let public_vec: Vec = [ + ecdsa_pair.public().as_inner_ref().as_ref(), + bls_pair.public().as_inner_ref().as_ref(), + ] + .concat(); + + let public = ecdsa_bls_crypto::Public::try_from(&public_vec[..]).unwrap(); + let signature_slice: Vec = [ + >::as_ref(&ecdsa_keccak_256_signature), + >::as_ref(&bls_signature.as_inner_ref()), + ] + .concat(); + let signature = ecdsa_bls_crypto::Signature::try_from(&signature_slice[..]).unwrap(); // Verification works if same hashing function is used when signing and verifying. - assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); + assert!(BeefyAuthorityId::::verify(&public, &signature, msg)); - // Other public key doesn't work - let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); - assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); + // Verification doesn't works if we verify function provided by pair_crypto implementation + assert!(!ecdsa_bls_crypto::Pair::verify(&signature, msg, &public)); } } From 099b86d3c743d4d23b4150b94fbc23bb5a0c40b6 Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 27 Oct 2023 12:31:06 -0400 Subject: [PATCH 28/78] Fix comment in `primitives/consensus/beefy/src/lib.rs` --- substrate/primitives/consensus/beefy/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 802567369e7c..1af40b2c4442 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -172,11 +172,11 @@ pub mod ecdsa_bls_crypto { ::Output: Into<[u8; 32]>, { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - // We can not call simply call + // We can not simply call // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` // because that invokes ecdsa default verification which perfoms blake2 hash // which we don't want. As such we need to re-implement the verification - // of signatures part by part instead of relying on paired crypto + // of signatures part by part instead of relying on `paired_crypto` let public: &[u8] = self.as_inner_ref().as_ref(); let signature: &[u8] = signature.as_inner_ref().as_ref(); let msg_hash = ::hash(msg).into(); From 033ff5701780d7537ccfe14d66b181252db928b5 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 31 Oct 2023 10:10:36 -0400 Subject: [PATCH 29/78] - implement `sign/verify_with_hasher` for `ecdsa_bls377` `Pair` with test - update `substrate/primitives/consensus/beefy/src/lib.rs` accordingly --- .../primitives/consensus/beefy/src/lib.rs | 60 +++++---------- .../primitives/core/src/paired_crypto.rs | 74 ++++++++++++++++++- 2 files changed, 88 insertions(+), 46 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 1af40b2c4442..c78abdeb1ccc 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -157,7 +157,7 @@ pub mod bls_crypto { pub mod ecdsa_bls_crypto { use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; - use sp_core::{bls377, crypto::Wraps, ecdsa, Pair as _}; + use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair}; app_crypto!(ecdsa_bls377, KEY_TYPE); @@ -175,27 +175,12 @@ pub mod ecdsa_bls_crypto { // We can not simply call // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` // because that invokes ecdsa default verification which perfoms blake2 hash - // which we don't want. As such we need to re-implement the verification - // of signatures part by part instead of relying on `paired_crypto` - let public: &[u8] = self.as_inner_ref().as_ref(); - let signature: &[u8] = signature.as_inner_ref().as_ref(); - let msg_hash = ::hash(msg).into(); - - let ecdsa_public = - ecdsa::Public::try_from(&public[0..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE]); - let ecdsa_signature = - ecdsa::Signature::try_from(&signature[0..ecdsa::SIGNATURE_SERIALIZED_SIZE]); - - let bls_public = bls377::Public::try_from(&public[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..]); - let bls_signature = - bls377::Signature::try_from(&signature[ecdsa::SIGNATURE_SERIALIZED_SIZE..]); - - return match (ecdsa_public, ecdsa_signature, bls_public, bls_signature) { - (Ok(ecdsa_public), Ok(ecdsa_signature), Ok(bls_public), Ok(bls_signature)) => - ecdsa::Pair::verify_prehashed(&ecdsa_signature, &msg_hash, &ecdsa_public) && - bls377::Pair::verify(&bls_signature, msg, &bls_public), - _ => false, - }; + // which we don't want. + EcdsaBlsPair::verify_with_hasher::( + signature.as_inner_ref(), + msg, + self.as_inner_ref(), + ) } } } @@ -524,30 +509,19 @@ mod tests { #[cfg(feature = "bls-experimental")] fn ecdsa_bls_beefy_verify_works() { let msg = &b"test-message"[..]; - let (ecdsa_pair, _) = ecdsa_crypto::Pair::generate(); - let (bls_pair, _) = bls_crypto::Pair::generate(); - - let ecdsa_keccak_256_signature = ecdsa_pair.as_inner_ref().sign_prehashed(&keccak_256(msg)); - let bls_signature = bls_pair.sign(&msg); - - let public_vec: Vec = [ - ecdsa_pair.public().as_inner_ref().as_ref(), - bls_pair.public().as_inner_ref().as_ref(), - ] - .concat(); - - let public = ecdsa_bls_crypto::Public::try_from(&public_vec[..]).unwrap(); - let signature_slice: Vec = [ - >::as_ref(&ecdsa_keccak_256_signature), - >::as_ref(&bls_signature.as_inner_ref()), - ] - .concat(); - let signature = ecdsa_bls_crypto::Signature::try_from(&signature_slice[..]).unwrap(); + let (pair, _) = ecdsa_bls_crypto::Pair::generate(); + + let signature: ecdsa_bls_crypto::Signature = + pair.as_inner_ref().sign_with_hasher::(&msg).into(); // Verification works if same hashing function is used when signing and verifying. - assert!(BeefyAuthorityId::::verify(&public, &signature, msg)); + assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); // Verification doesn't works if we verify function provided by pair_crypto implementation - assert!(!ecdsa_bls_crypto::Pair::verify(&signature, msg, &public)); + assert!(!ecdsa_bls_crypto::Pair::verify(&signature, msg, &pair.public())); + + // Other public key doesn't work + let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); + assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); } } diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a97b657e7578..88167bb8a2fe 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -39,7 +39,11 @@ use sp_std::convert::TryFrom; /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377 { - use crate::{bls377, crypto::CryptoTypeId, ecdsa}; + use crate::{ + bls377, + crypto::{CryptoTypeId, Pair as PairT, UncheckedFrom}, + ecdsa, + }; /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); @@ -71,6 +75,60 @@ pub mod ecdsa_bls377 { impl super::CryptoType for Pair { type Pair = Pair; } + + #[cfg(feature = "full_crypto")] + impl Pair { + /// hashes the `message` with the specified `MsgHasher` and then signs it using ECDSA + /// algorithm. It does not affect the behavoir of BLS12-377 component. It generates + /// BLS12-377 Signature according to IETF standard and disregard the hasher for the + /// BLS12-377 component + pub fn sign_with_hasher(&self, message: &[u8]) -> Signature + where + ::Out: Into<[u8; 32]>, + { + let msg_hash = ::hash(message).into(); + + let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + raw[..ecdsa::SIGNATURE_SERIALIZED_SIZE] + .copy_from_slice(self.left.sign_prehashed(&msg_hash).as_ref()); + raw[ecdsa::SIGNATURE_SERIALIZED_SIZE..] + .copy_from_slice(self.right.sign(message).as_ref()); + ::Signature::unchecked_from(raw) + } + + /// hashes the `message` with the specified `MsgHasher` and then verifys if the resulting + /// hash was signed by the provided ECDSA public key.. It does not affect the behavoir of + /// BLS12-377 component. It Verify the BLS12-377 signature as it was hashed and signed + /// according to IETF standrad + pub fn verify_with_hasher( + sig: &Signature, + message: &[u8], + public: &Public, + ) -> bool + where + ::Out: Into<[u8; 32]>, + { + let msg_hash = ::hash(message).into(); + + let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else { + return false + }; + let Ok(left_sig) = sig.0[0..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else { + return false + }; + if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) { + return false + } + + let Ok(right_pub) = public.0[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].try_into() else { + return false + }; + let Ok(right_sig) = sig.0[ecdsa::SIGNATURE_SERIALIZED_SIZE..].try_into() else { + return false + }; + bls377::Pair::verify(&right_sig, message.as_ref(), &right_pub) + } + } } /// Secure seed length. @@ -455,12 +513,12 @@ where #[cfg(all(test, feature = "bls-experimental"))] mod test { use super::*; - use crate::crypto::DEV_PHRASE; + use crate::{crypto::DEV_PHRASE, KeccakHasher}; use ecdsa_bls377::{Pair, Signature}; use crate::{bls377, ecdsa}; - #[test] + #[test] fn test_length_of_paired_ecdsa_and_bls377_public_key_and_signature_is_correct() { assert_eq!( ::Public::LEN, @@ -617,6 +675,16 @@ mod test { assert_eq!(cmp, public); } + #[test] + fn sign_and_verify_with_haser_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign_with_hasher::(&message[..]); + + assert!(Pair::verify_with_hasher::(&signature, &message[..], &pair.public())); + } + #[test] fn signature_serialization_works() { let pair = From 76831b7b87250e3db10e66bc0e357d9b33b48d64 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:00:44 -0400 Subject: [PATCH 30/78] Fix typos and improve comment quality Co-authored-by: Davide Galassi --- substrate/primitives/consensus/beefy/src/lib.rs | 2 +- substrate/primitives/core/src/paired_crypto.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index c78abdeb1ccc..738a491f04fb 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -260,7 +260,7 @@ pub enum ConsensusLog { /// /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. -/// TODO: Remove `Signature` generic type, instead get it from `Id::Signature`. +// TODO: Remove `Signature` generic type, instead get it from `Id::Signature`. #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct VoteMessage { /// Commit to information extracted from a finalized block diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 88167bb8a2fe..03567a8b7317 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -676,7 +676,7 @@ mod test { } #[test] - fn sign_and_verify_with_haser_works() { + fn sign_and_verify_with_hasher_works() { let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let message = b"Something important"; From a0c6d83edcaa12cfcad14f14597499bda2de9b36 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 2 Nov 2023 17:34:03 -0400 Subject: [PATCH 31/78] Add ecdsa_bls377_sign_with_keccak256 to the keystore --- substrate/primitives/keystore/src/lib.rs | 28 ++++++++++++++++++++ substrate/primitives/keystore/src/testing.rs | 15 ++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index e415080779cf..8999bf2ec0bc 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -355,6 +355,24 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; + /// Hashes the `message` using keccak256 and then signs it using ECDSA + /// algorithm. It does not affect the behavoir of BLS12-377 component. It generates + /// BLS12-377 Signature according to IETF standard. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error>; + /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; @@ -661,6 +679,16 @@ impl Keystore for Arc { (**self).ecdsa_bls377_sign(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + (**self).ecdsa_bls377_sign_with_keccak256(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index 7f5dfd9faa71..df9e4bdf083c 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -25,7 +25,7 @@ use sp_core::bandersnatch; use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, - ecdsa, ed25519, sr25519, + ecdsa, ed25519, sr25519, KeccakHasher, }; use parking_lot::RwLock; @@ -346,6 +346,19 @@ impl Keystore for MemoryKeystore { self.sign::(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + let sig = self + .pair::(key_type, public) + .map(|pair| pair.sign_with_hasher::(msg)); + Ok(sig) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() From 102ad62db34c58e4aa73dfada2038d79e53f383d Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 3 Nov 2023 13:23:57 -0400 Subject: [PATCH 32/78] add and implement `ecdsa_bls377_sign_with_keccak256` make BEEFY keystore generic over `AuthorityId` and works with both (ECDSA) and (ECDSA, BLS377) key types. pass all the BEEFY tests for ECDSA --- substrate/client/consensus/beefy/Cargo.toml | 1 + .../beefy/src/communication/gossip.rs | 2 +- .../consensus/beefy/src/justification.rs | 2 +- .../client/consensus/beefy/src/keystore.rs | 212 ++++++++++++++---- .../client/consensus/beefy/src/worker.rs | 2 +- substrate/client/keystore/src/local.rs | 13 ++ substrate/primitives/keystore/src/testing.rs | 36 ++- 7 files changed, 221 insertions(+), 47 deletions(-) diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index aae5a44d7fa2..4b300b649c44 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -36,6 +36,7 @@ sp-core = { path = "../../../primitives/core" } sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } +sp-std = { path = "../../../primitives/std", default-features = false} [dev-dependencies] serde = "1.0.188" diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 342cd0511a51..5bbbac502bb7 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -506,7 +506,7 @@ pub(crate) mod tests { pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store = MemoryKeystore::new(); store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store.into()).into(); + let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 483184e2374a..83e11b5b6e97 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -76,7 +76,7 @@ pub(crate) fn verify_with_validator_set( .as_ref() .map(|sig| { signatures_checked += 1; - BeefyKeystore::verify(id, sig, &message[..]) + BeefyKeystore::verify(*id, sig, &message[..]) }) .unwrap_or(false) }) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 925bb0882822..c9151a25c088 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -15,42 +15,86 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use codec::{Codec, Decode}; +use core::fmt::{Debug, Display}; + +use sp_application_crypto::{ + key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, AppPublic, ByteArray, RuntimeAppPublic, +}; +#[cfg(feature = "bls-experimental")] +use sp_core::{bls377, ecdsa_bls377}; +use sp_core::{ecdsa, keccak_256}; -use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, RuntimeAppPublic}; -use sp_core::keccak_256; use sp_keystore::KeystorePtr; +use sp_std::marker::PhantomData; use log::warn; -use sp_consensus_beefy::{ - ecdsa_crypto::{Public, Signature}, - BeefyAuthorityId, -}; +use sp_consensus_beefy::{ecdsa_crypto, BeefyAuthorityId}; + +#[cfg(feature = "bls-experimental")] +use sp_consensus_beefy::bls_crypto; use crate::{error, LOG_TARGET}; /// Hasher used for BEEFY signatures. pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256; -/// A BEEFY specific keystore implemented as a `Newtype`. This is basically a -/// wrapper around [`sp_keystore::Keystore`] and allows to customize -/// common cryptographic functionality. -pub(crate) struct BeefyKeystore(Option); +pub trait AuthorityIdBound: + Codec + + Debug + + Clone + + Ord + + Sync + + Send + + AsRef<[u8]> + + ByteArray + + AppPublic + + AppCrypto + + RuntimeAppPublic + + Display + + BeefyAuthorityId +where + ::Signature: Send + Sync, +{ +} -impl BeefyKeystore { +impl AuthorityIdBound for ecdsa_crypto::AuthorityId {} + +// impl + AppPublic + AppCrypto + +// RuntimeAppPublic + BeefyAuthorityId > AuthorityIdBound for T { type +// Signature = AppCrypto::Signature; } + +/// A BEEFY specific keystore i mplemented as a `Newtype`. This is basically a +/// wrapper around [`sp_keystore::Keystore`] and allows to customize +/// commoncryptographic functionality. +pub(crate) struct BeefyKeystore( + Option, + PhantomData AuthorityId>, +) +where + ::Signature: Send + Sync; + +impl BeefyKeystore +where + ::Signature: Send + Sync, +{ /// Check if the keystore contains a private key for one of the public keys /// contained in `keys`. A public key with a matching private key is known /// as a local authority id. /// /// Return the public key for which we also do have a private key. If no /// matching private key is found, `None` will be returned. - pub fn authority_id(&self, keys: &[Public]) -> Option { + pub fn authority_id(&self, keys: &[AuthorityId]) -> Option { let store = self.0.clone()?; // we do check for multiple private keys as a key store sanity check. - let public: Vec = keys + let public: Vec = keys .iter() - .filter(|k| store.has_keys(&[(k.to_raw_vec(), BEEFY_KEY_TYPE)])) + .filter(|k| { + store + .has_keys(&[(::to_raw_vec(k), BEEFY_KEY_TYPE)]) + }) .cloned() .collect(); @@ -71,47 +115,131 @@ impl BeefyKeystore { /// Note that `message` usually will be pre-hashed before being signed. /// /// Return the message signature or an error in case of failure. - pub fn sign(&self, public: &Public, message: &[u8]) -> Result { + pub fn sign( + &self, + public: &AuthorityId, + message: &[u8], + ) -> Result<::Signature, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let msg = keccak_256(message); - let public = public.as_ref(); - - let sig = store - .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, public, &msg) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?; - - // check that `sig` has the expected result type - let sig = sig.clone().try_into().map_err(|_| { - error::Error::Signature(format!("invalid signature {:?} for key {:?}", sig, public)) + //ECDSA shoud do ecdsa_sign_prehashed because it needs to be hashed by keccak_256 + //as such we need to deal with signing case by case + + let signature_byte_array: Vec = match ::CRYPTO_ID { + ecdsa::CRYPTO_ID => { + let msg_hash = keccak_256(message); + let public: ecdsa::Public = ecdsa::Public::try_from(public.as_slice()).unwrap(); + + let sig = store + .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, &public, &msg_hash) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| { + error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()) + })?; + let sig_ref: &[u8] = sig.as_ref(); + sig_ref.to_vec() + }, + + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => store + .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, public, &msg) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| { + error::Error::AuthorityId::Signature( + "bls377_sign() + failed" + .to_string(), + ) + })? + .as_ref(), + + _ => { + let sig = store + .sign_with( + ::ID, + ::CRYPTO_ID, + public.as_slice(), + message, + ) + .map_err(|e| error::Error::Signature(format!("{}. Key: {:?}", e, public)))? + .ok_or_else(|| { + error::Error::Signature(format!( + "Could not find key in keystore. Key: {:?}", + public + )) + })?; + + sig + }, + }; + + //check that `sig` has the expected result type + let signature = ::Signature::decode( + &mut signature_byte_array.as_slice(), + ) + .map_err(|_| { + error::Error::Signature(format!( + "invalid signature {:?} for key {:?}", + signature_byte_array, public + )) })?; - Ok(sig) + Ok(signature) } /// Returns a vector of [`sp_consensus_beefy::crypto::Public`] keys which are currently /// supported (i.e. found in the keystore). - pub fn public_keys(&self) -> Result, error::Error> { + pub fn public_keys(&self) -> Result, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let pk: Vec = - store.ecdsa_public_keys(BEEFY_KEY_TYPE).drain(..).map(Public::from).collect(); - - Ok(pk) + let pk = match ::CRYPTO_ID { + ecdsa::CRYPTO_ID => store + .ecdsa_public_keys(BEEFY_KEY_TYPE) + .drain(..) + .map(|pk| AuthorityId::try_from(pk.as_ref())) + .collect::, _>>() + .or_else(|_| { + Err(error::Error::Keystore( + "unable to convert public key into authority id".into(), + )) + }), + + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => store + .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) + .drain(..) + .map(|pk| AuthorityId::try_from(pk.as_ref())) + .collect::, _>>() + .or_else(|_| { + Err(error::Error::Keystore( + "unable to convert public key into authority id".into(), + )) + }), + + _ => Err(error::Error::Keystore("key type is not supported by BEEFY Keystore".into())), + }; + + pk } /// Use the `public` key to verify that `sig` is a valid signature for `message`. /// /// Return `true` if the signature is authentic, `false` otherwise. - pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { + pub fn verify( + public: &AuthorityId, + sig: &::Signature, + message: &[u8], + ) -> bool { BeefyAuthorityId::::verify(public, sig, message) } } -impl From> for BeefyKeystore { - fn from(store: Option) -> BeefyKeystore { - BeefyKeystore(store) +impl From> for BeefyKeystore +where + ::Signature: Send + Sync, +{ + fn from(store: Option) -> BeefyKeystore { + BeefyKeystore(store, PhantomData) } } @@ -218,7 +346,7 @@ pub mod tests { let bob = Keyring::Bob.public(); let charlie = Keyring::Charlie.public(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let mut keys = vec![bob, charlie]; @@ -241,7 +369,7 @@ pub mod tests { .unwrap() .into(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let msg = b"are you involved or commited?"; @@ -260,7 +388,7 @@ pub mod tests { .ok() .unwrap(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let alice = Keyring::Alice.public(); @@ -273,7 +401,7 @@ pub mod tests { #[test] fn sign_no_keystore() { - let store: BeefyKeystore = None.into(); + let store: BeefyKeystore = None.into(); let alice = Keyring::Alice.public(); let msg = b"are you involved or commited"; @@ -293,7 +421,7 @@ pub mod tests { .unwrap() .into(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); // `msg` and `sig` match let msg = b"are you involved or commited?"; @@ -330,7 +458,7 @@ pub mod tests { let key1: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); let key2: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let keys = store.public_keys().ok().unwrap(); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 309d8c5135be..8b3b8e782393 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -330,7 +330,7 @@ pub(crate) struct BeefyWorker { pub payload_provider: P, pub runtime: Arc, pub sync: Arc, - pub key_store: BeefyKeystore, + pub key_store: BeefyKeystore, // communication (created once, but returned and reused if worker is restarted/reinitialized) pub comms: BeefyComms, diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 8089dbba0352..30fbaedce896 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -391,6 +391,19 @@ impl Keystore for LocalKeystore { self.sign::(key_type, public, msg) } + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + let sig = self + .pair::(key_type, public) + .map(|pair| pair.sign_with_hasher::(msg)); + Ok(sig) + } + + } } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index df9e4bdf083c..25653ac9a6b0 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,10 +22,10 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377}; +use sp_core::{bls377, bls381, ecdsa_bls377, KeccakHasher}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, - ecdsa, ed25519, sr25519, KeccakHasher, + ecdsa, ed25519, sr25519, }; use parking_lot::RwLock; @@ -504,6 +504,38 @@ mod tests { assert!(res.is_some()); } + #[test] + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak_works() { + use sp_core::testing::ECDSA_BLS377; + + let store = MemoryKeystore::new(); + + let suri = "//Alice"; + let pair = ecdsa_bls377::Pair::from_string(suri, None).unwrap(); + + let msg = b"this should be a normal unhashed message not "; + + // insert key, sign again + store.insert(ECDSA_BLS377, suri, pair.public().as_ref()).unwrap(); + + let res = store + .ecdsa_bls377_sign_with_keccak256(ECDSA_BLS377, &pair.public(), &msg[..]) + .unwrap(); + + assert!(res.is_some()); + + // does not verify with default out-of-the-box verification + assert!(!ecdsa_bls377::Pair::verify(&res.clone().unwrap(), &msg[..], &pair.public())); + + // should verify using keccak256 as hasher + assert!(ecdsa_bls377::Pair::verify_with_hasher::( + &res.unwrap(), + msg, + &pair.public() + )); + } + #[test] #[cfg(feature = "bandersnatch-experimental")] fn bandersnatch_vrf_sign() { From 25d1afc215abae1f072b33dddbae87bb959a83c8 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 9 Nov 2023 12:10:44 -0500 Subject: [PATCH 33/78] - Make BEEFY Keyring to be generic over `AuthorityId`. - Make BEEFY Keystore test generic over `AuthorityId`. - Implement keystore tests for `ecdsa_bls` crypto. - Fix `bls::Pair::derive` and write test for it. --- substrate/client/consensus/beefy/Cargo.toml | 9 + .../beefy/src/communication/gossip.rs | 16 +- .../consensus/beefy/src/justification.rs | 13 +- .../client/consensus/beefy/src/keystore.rs | 406 ++++++++++++------ substrate/client/consensus/beefy/src/round.rs | 135 ++++-- substrate/client/consensus/beefy/src/tests.rs | 13 +- .../client/consensus/beefy/src/worker.rs | 10 +- substrate/client/keystore/src/local.rs | 9 +- .../primitives/consensus/beefy/Cargo.toml | 3 +- .../consensus/beefy/src/commitment.rs | 2 +- .../primitives/consensus/beefy/src/lib.rs | 37 +- .../consensus/beefy/src/test_utils.rs | 314 +++++++++++++- substrate/primitives/core/src/bls.rs | 26 +- substrate/primitives/core/src/ecdsa.rs | 13 + .../primitives/core/src/paired_crypto.rs | 23 +- substrate/primitives/core/src/sr25519.rs | 13 + 16 files changed, 813 insertions(+), 229 deletions(-) diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 4b300b649c44..65b941638c30 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -48,3 +48,12 @@ sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa" } sp-keyring = { path = "../../../primitives/keyring" } sp-tracing = { path = "../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } + +[features] +# This feature adds BLS crypto primitives. It should not be used in production since +# the BLS implementation and interface may still be subject to significant change. +bls-experimental = [ + "sp-application-crypto/bls-experimental", + "sp-core/bls-experimental", + "sp-consensus-beefy/bls-experimental" +] diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 5bbbac502bb7..c70e5214a13f 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -481,8 +481,8 @@ pub(crate) mod tests { use sc_network_test::Block; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - ecdsa_crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, - SignedCommitment, VoteMessage, + ecdsa_crypto::Signature, known_payloads, Commitment, GenericKeyring, Keyring, MmrRootHash, + Payload, SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -505,7 +505,12 @@ pub(crate) mod tests { pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store = MemoryKeystore::new(); - store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); + store + .ecdsa_generate_new( + BEEFY_KEY_TYPE, + Some(&>::to_seed(*who)), + ) + .unwrap(); let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } @@ -534,7 +539,10 @@ pub(crate) mod tests { .validators() .iter() .map(|validator: &AuthorityId| { - Some(sign_commitment(&Keyring::from_public(validator).unwrap(), &commitment)) + Some(sign_commitment( + &>::from_public(validator).unwrap(), + &commitment, + )) }) .collect(); diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 83e11b5b6e97..6de9c5b3316f 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -93,7 +93,8 @@ pub(crate) fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use sp_consensus_beefy::{ - known_payloads, Commitment, Keyring, Payload, SignedCommitment, VersionedFinalityProof, + known_payloads, Commitment, GenericKeyring, Keyring, Payload, SignedCommitment, + VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; @@ -111,7 +112,10 @@ pub(crate) mod tests { validator_set_id: validator_set.id(), }; let message = commitment.encode(); - let signatures = keys.iter().map(|key| Some(key.sign(&message))).collect(); + let signatures = keys + .iter() + .map(|key| Some(>::sign(*key, &message))) + .collect(); VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }) } @@ -174,7 +178,10 @@ pub(crate) mod tests { }; // change a signature to a different key *bad_signed_commitment.signatures.first_mut().unwrap() = - Some(Keyring::Dave.sign(&bad_signed_commitment.commitment.encode())); + Some(>::sign( + Keyring::Dave, + &bad_signed_commitment.commitment.encode(), + )); match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { Err((ConsensusError::InvalidJustification, 3)) => (), e => assert!(false, "Got unexpected {:?}", e), diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index c9151a25c088..80e2f807c2b1 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -15,14 +15,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use codec::{Codec, Decode}; -use core::fmt::{Debug, Display}; +use codec::Decode; -use sp_application_crypto::{ - key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, AppPublic, ByteArray, RuntimeAppPublic, -}; +use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, ecdsa_bls377}; +use sp_core::ecdsa_bls377; use sp_core::{ecdsa, keccak_256}; use sp_keystore::KeystorePtr; @@ -30,37 +27,13 @@ use sp_std::marker::PhantomData; use log::warn; -use sp_consensus_beefy::{ecdsa_crypto, BeefyAuthorityId}; +use sp_consensus_beefy::{AuthorityIdBound, BeefyAuthorityId, BeefySignatureHasher}; #[cfg(feature = "bls-experimental")] -use sp_consensus_beefy::bls_crypto; +use sp_consensus_beefy::ecdsa_bls_crypto; use crate::{error, LOG_TARGET}; -/// Hasher used for BEEFY signatures. -pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256; - -pub trait AuthorityIdBound: - Codec - + Debug - + Clone - + Ord - + Sync - + Send - + AsRef<[u8]> - + ByteArray - + AppPublic - + AppCrypto - + RuntimeAppPublic - + Display - + BeefyAuthorityId -where - ::Signature: Send + Sync, -{ -} - -impl AuthorityIdBound for ecdsa_crypto::AuthorityId {} - // impl + AppPublic + AppCrypto + // RuntimeAppPublic + BeefyAuthorityId > AuthorityIdBound for T { type // Signature = AppCrypto::Signature; } @@ -141,17 +114,16 @@ where }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => store - .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, public, &msg) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| { - error::Error::AuthorityId::Signature( - "bls377_sign() - failed" - .to_string(), - ) - })? - .as_ref(), + ecdsa_bls377::CRYPTO_ID => { + let public: ecdsa_bls377::Public = + ecdsa_bls377::Public::try_from(public.as_slice()).unwrap(); + let sig = store + .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; + let sig_ref: &[u8] = sig.as_ref(); + sig_ref.to_vec() + }, _ => { let sig = store @@ -208,7 +180,9 @@ where ecdsa_bls377::CRYPTO_ID => store .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) .drain(..) - .map(|pk| AuthorityId::try_from(pk.as_ref())) + .map(|pk| + AuthorityId::try_from(pk.as_ref()) + ) .collect::, _>>() .or_else(|_| { Err(error::Error::Keystore( @@ -245,8 +219,8 @@ where #[cfg(test)] pub mod tests { - use sp_consensus_beefy::{ecdsa_crypto, Keyring}; - use sp_core::{ecdsa, Pair}; + use sp_consensus_beefy::{ecdsa_crypto, BeefySignerAuthority, GenericKeyring, Keyring}; + use sp_core::Pair as PairT; use sp_keystore::testing::MemoryKeystore; use super::*; @@ -256,149 +230,246 @@ pub mod tests { MemoryKeystore::new().into() } - #[test] - fn verify_should_work() { - let msg = keccak_256(b"I am Alice!"); - let sig = Keyring::Alice.sign(b"I am Alice!"); - - assert!(ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Alice.public().into(), + fn pair_verify_should_work< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { + let msg = b"I am Alice!"; + let sig = >::sign(Keyring::Alice, b"I am Alice!"); + + assert!(>::verify( + &>::public(Keyring::Alice), + &sig, + &msg.as_slice(), )); // different public key -> fail - assert!(!ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Bob.public().into(), + assert!(!>::verify( + &>::public(Keyring::Bob), + &sig, + &msg.as_slice(), )); - let msg = keccak_256(b"I am not Alice!"); + let msg = b"I am not Alice!"; // different msg -> fail - assert!( - !ecdsa::Pair::verify_prehashed(&sig.into(), &msg, &Keyring::Alice.public().into(),) - ); + assert!(!>::verify( + &>::public(Keyring::Alice), + &sig, + &msg.as_slice(), + )); } #[test] - fn pair_works() { - let want = ecdsa_crypto::Pair::from_string("//Alice", None) + fn pair_verify_should_work_ecdsa() { + pair_verify_should_work::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn pair_verify_should_work_ecdsa_n_bls() { + pair_verify_should_work::(); + } + + fn pair_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { + let want = >::KeyPair::from_string("//Alice", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Alice.pair().to_raw_vec(); + let got = >::pair(Keyring::Alice).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Bob", None) + let want = >::KeyPair::from_string("//Bob", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Bob.pair().to_raw_vec(); + let got = >::pair(Keyring::Bob).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Charlie", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::Charlie.pair().to_raw_vec(); + let want = + >::KeyPair::from_string("//Charlie", None) + .expect("Pair failed") + .to_raw_vec(); + let got = >::pair(Keyring::Charlie).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Dave", None) + let want = >::KeyPair::from_string("//Dave", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Dave.pair().to_raw_vec(); + let got = >::pair(Keyring::Dave).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Eve", None) + let want = >::KeyPair::from_string("//Eve", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Eve.pair().to_raw_vec(); + let got = >::pair(Keyring::Eve).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Ferdie", None) + let want = >::KeyPair::from_string("//Ferdie", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Ferdie.pair().to_raw_vec(); + let got = >::pair(Keyring::Ferdie).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//One", None) + let want = >::KeyPair::from_string("//One", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::One.pair().to_raw_vec(); + let got = >::pair(Keyring::One).to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Two", None) + let want = >::KeyPair::from_string("//Two", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Two.pair().to_raw_vec(); + let got = >::pair(Keyring::Two).to_raw_vec(); assert_eq!(want, got); } #[test] - fn authority_id_works() { + fn ecdsa_pair_works() { + pair_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn ecdsa_n_bls_pair_works() { + pair_works::(); + } + + fn authority_id_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - let alice: ecdsa_crypto::Public = store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + Some(Keyring::Alice), + ); - let bob = Keyring::Bob.public(); - let charlie = Keyring::Charlie.public(); + let alice = >::public(Keyring::Alice); - let store: BeefyKeystore = Some(store).into(); + let bob = >::public(Keyring::Bob); + let charlie = >::public(Keyring::Charlie); + + let beefy_store: BeefyKeystore = Some(store).into(); let mut keys = vec![bob, charlie]; - let id = store.authority_id(keys.as_slice()); + let id = beefy_store.authority_id(keys.as_slice()); assert!(id.is_none()); keys.push(alice.clone()); - let id = store.authority_id(keys.as_slice()).unwrap(); + let id = beefy_store.authority_id(keys.as_slice()).unwrap(); assert_eq!(id, alice); } + #[cfg(feature = "bls-experimental")] + #[test] + + fn authority_id_works_for_ecdsa() { + authority_id_works::(); + } + + #[cfg(feature = "bls-experimental")] #[test] - fn sign_works() { + + fn authority_id_works_for_ecdsa_n_bls() { + authority_id_works::(); + } + + fn sign_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - let alice: ecdsa_crypto::Public = store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + Some(Keyring::Alice), + ); + + let alice = >::public(Keyring::Alice); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let msg = b"are you involved or commited?"; let sig1 = store.sign(&alice, msg).unwrap(); - let sig2 = Keyring::Alice.sign(msg); + let sig2 = >::sign(Keyring::Alice, msg); assert_eq!(sig1, sig2); } #[test] - fn sign_error() { + fn sign_works_for_ecdsa() { + sign_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn sign_works_for_ecdsa_n_bls() { + sign_works::(); + } + + fn sign_error< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >( + expected_error_message: &str, + ) where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Bob.to_seed())) - .ok() - .unwrap(); + >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + Some(Keyring::Bob), + ); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); - let alice = Keyring::Alice.public(); + let alice = >::public(Keyring::Alice); let msg = b"are you involved or commited?"; let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Signature("ecdsa_sign_prehashed() failed".to_string()); + let err = Error::Signature(expected_error_message.to_string()); assert_eq!(sig, err); } + #[test] + fn sign_error_for_ecdsa() { + sign_error::("ecdsa_sign_prehashed() failed"); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn sign_error_for_ecdsa_n_bls() { + sign_error::("bls377_sign() failed"); + } + #[test] fn sign_no_keystore() { let store: BeefyKeystore = None.into(); @@ -411,17 +482,25 @@ pub mod tests { assert_eq!(sig, err); } - #[test] - fn verify_works() { + fn verify_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - let alice: ecdsa_crypto::Public = store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + Some(Keyring::Alice), + ); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); + + let alice = >::public(Keyring::Alice); // `msg` and `sig` match let msg = b"are you involved or commited?"; @@ -433,39 +512,98 @@ pub mod tests { assert!(!BeefyKeystore::verify(&alice, &sig, msg)); } - // Note that we use keys with and without a seed for this test. #[test] - fn public_keys_works() { + fn verify_works_for_ecdsa() { + verify_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + + fn verify_works_for_ecdsa_n_bls() { + verify_works::(); + } + + // Note that we use keys with and without a seed for this test. + fn public_keys_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { const TEST_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"test"); let store = keystore(); - let add_key = - |key_type, seed: Option<&str>| store.ecdsa_generate_new(key_type, seed).unwrap(); - // test keys - let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); - let _ = add_key(TEST_TYPE, Some(Keyring::Bob.to_seed().as_str())); - - let _ = add_key(TEST_TYPE, None); - let _ = add_key(TEST_TYPE, None); + let _ = >::generate_in_store( + store.clone(), + TEST_TYPE, + Some(Keyring::Alice), + ); + let _ = >::generate_in_store( + store.clone(), + TEST_TYPE, + Some(Keyring::Bob), + ); // BEEFY keys - let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); - let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); + let _ = >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + Some(Keyring::Dave), + ); + let _ = >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + Some(Keyring::Eve), + ); + + let _ = >::generate_in_store( + store.clone(), + TEST_TYPE, + None, + ); + let _ = >::generate_in_store( + store.clone(), + TEST_TYPE, + None, + ); - let key1: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); - let key2: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); + let key1 = >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + None, + ); + let key2 = >::generate_in_store( + store.clone(), + BEEFY_KEY_TYPE, + None, + ); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let keys = store.public_keys().ok().unwrap(); assert!(keys.len() == 4); - assert!(keys.contains(&Keyring::Dave.public())); - assert!(keys.contains(&Keyring::Eve.public())); + assert!(keys.contains(&>::public(Keyring::Dave))); + assert!(keys.contains(&>::public(Keyring::Eve))); assert!(keys.contains(&key1)); assert!(keys.contains(&key2)); } + + #[test] + fn public_keys_works_for_ecdsa_keystore() { + public_keys_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + + fn public_keys_works_for_ecdsa_n_bls() { + public_keys_works::(); + } } diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 6f400ce47843..a3f8c1baad5f 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -203,8 +203,8 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, Keyring, Payload, - SignedCommitment, ValidatorSet, VoteMessage, + known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, GenericKeyring, Keyring, + Payload, SignedCommitment, ValidatorSet, VoteMessage, }; use super::{threshold, AuthorityId, Block as BlockT, RoundTracker, Rounds}; @@ -222,7 +222,10 @@ mod tests { #[test] fn round_tracker() { let mut rt = RoundTracker::default(); - let bob_vote = (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")); + let bob_vote = ( + >::public(Keyring::Bob), + >::sign(Keyring::Bob, b"I am committed"), + ); let threshold = 2; // adding new vote allowed @@ -233,7 +236,10 @@ mod tests { // vote is not done assert!(!rt.is_done(threshold)); - let alice_vote = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + let alice_vote = ( + >::public(Keyring::Alice), + >::sign(Keyring::Alice, b"I am committed"), + ); // adding new vote (self vote this time) allowed assert!(rt.add_vote(alice_vote)); @@ -256,7 +262,11 @@ mod tests { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + ], 42, ) .unwrap(); @@ -267,7 +277,11 @@ mod tests { assert_eq!(42, rounds.validator_set_id()); assert_eq!(1, rounds.session_start()); assert_eq!( - &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + &vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie) + ], rounds.validators() ); } @@ -278,9 +292,9 @@ mod tests { let validators = ValidatorSet::::new( vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), Keyring::Eve.public(), ], Default::default(), @@ -295,9 +309,12 @@ mod tests { let block_number = 1; let commitment = Commitment { block_number, payload, validator_set_id }; let mut vote = VoteMessage { - id: Keyring::Alice.public(), + id: >::public(Keyring::Alice), commitment: commitment.clone(), - signature: Keyring::Alice.sign(b"I am committed"), + signature: >::sign( + Keyring::Alice, + b"I am committed", + ), }; // add 1st good vote assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); @@ -305,35 +322,48 @@ mod tests { // double voting (same vote), ok, no effect assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - vote.id = Keyring::Dave.public(); - vote.signature = Keyring::Dave.sign(b"I am committed"); + vote.id = >::public(Keyring::Dave); + vote.signature = + >::sign(Keyring::Dave, b"I am committed"); // invalid vote (Dave is not a validator) assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Invalid); - vote.id = Keyring::Bob.public(); - vote.signature = Keyring::Bob.sign(b"I am committed"); + vote.id = >::public(Keyring::Bob); + vote.signature = + >::sign(Keyring::Bob, b"I am committed"); // add 2nd good vote assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - vote.id = Keyring::Charlie.public(); - vote.signature = Keyring::Charlie.sign(b"I am committed"); + vote.id = >::public(Keyring::Charlie); + vote.signature = + >::sign(Keyring::Charlie, b"I am committed"); // add 3rd good vote -> round concluded -> signatures present assert_eq!( rounds.add_vote(vote.clone()), VoteImportResult::RoundConcluded(SignedCommitment { commitment, signatures: vec![ - Some(Keyring::Alice.sign(b"I am committed")), - Some(Keyring::Bob.sign(b"I am committed")), - Some(Keyring::Charlie.sign(b"I am committed")), + Some(>::sign( + Keyring::Alice, + b"I am committed" + )), + Some(>::sign( + Keyring::Bob, + b"I am committed" + )), + Some(>::sign( + Keyring::Charlie, + b"I am committed" + )), None, ] }) ); rounds.conclude(block_number); - vote.id = Keyring::Eve.public(); - vote.signature = Keyring::Eve.sign(b"I am committed"); + vote.id = >::public(Keyring::Eve); + vote.signature = + >::sign(Keyring::Eve, b"I am committed"); // Eve is a validator, but round was concluded, adding vote disallowed assert_eq!(rounds.add_vote(vote), VoteImportResult::Stale); } @@ -343,7 +373,11 @@ mod tests { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + ], 42, ) .unwrap(); @@ -358,9 +392,12 @@ mod tests { let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); let commitment = Commitment { block_number, payload, validator_set_id }; let mut vote = VoteMessage { - id: Keyring::Alice.public(), + id: >::public(Keyring::Alice), commitment, - signature: Keyring::Alice.sign(b"I am committed"), + signature: >::sign( + Keyring::Alice, + b"I am committed", + ), }; // add vote for previous session, should fail assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); @@ -389,7 +426,11 @@ mod tests { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + ], Default::default(), ) .unwrap(); @@ -401,24 +442,36 @@ mod tests { let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); let commitment = Commitment { block_number: 1, payload, validator_set_id }; let mut alice_vote = VoteMessage { - id: Keyring::Alice.public(), + id: >::public(Keyring::Alice), commitment: commitment.clone(), - signature: Keyring::Alice.sign(b"I am committed"), + signature: >::sign( + Keyring::Alice, + b"I am committed", + ), }; let mut bob_vote = VoteMessage { - id: Keyring::Bob.public(), + id: >::public(Keyring::Bob), commitment: commitment.clone(), - signature: Keyring::Bob.sign(b"I am committed"), + signature: >::sign( + Keyring::Bob, + b"I am committed", + ), }; let mut charlie_vote = VoteMessage { - id: Keyring::Charlie.public(), + id: >::public(Keyring::Charlie), commitment, - signature: Keyring::Charlie.sign(b"I am committed"), + signature: >::sign( + Keyring::Charlie, + b"I am committed", + ), }; let expected_signatures = vec![ - Some(Keyring::Alice.sign(b"I am committed")), - Some(Keyring::Bob.sign(b"I am committed")), - Some(Keyring::Charlie.sign(b"I am committed")), + Some(>::sign(Keyring::Alice, b"I am committed")), + Some(>::sign(Keyring::Bob, b"I am committed")), + Some(>::sign( + Keyring::Charlie, + b"I am committed", + )), ]; // round 1 - only 2 out of 3 vote @@ -464,7 +517,10 @@ mod tests { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public()], + vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + ], Default::default(), ) .unwrap(); @@ -478,9 +534,12 @@ mod tests { let commitment2 = Commitment { block_number: 1, payload: payload2, validator_set_id }; let alice_vote1 = VoteMessage { - id: Keyring::Alice.public(), + id: >::public(Keyring::Alice), commitment: commitment1, - signature: Keyring::Alice.sign(b"I am committed"), + signature: >::sign( + Keyring::Alice, + b"I am committed", + ), }; let mut alice_vote2 = alice_vote1.clone(); alice_vote2.commitment = commitment2; diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 902feca16398..e3e5441dac66 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -54,8 +54,8 @@ use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId, Signature}, known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, - OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, GenericKeyring, Keyring as BeefyKeyring, + MmrRootHash, OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_core::H256; @@ -347,13 +347,18 @@ fn add_auth_change_digest(builder: &mut impl BlockBuilderExt, new_auth_set: Beef } pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { - keys.iter().map(|&key| key.public().into()).collect() + keys.iter() + .map(|&key| >::public(key).into()) + .collect() } pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr { let keystore = MemoryKeystore::new(); keystore - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&authority.to_seed())) + .ecdsa_generate_new( + BEEFY_KEY_TYPE, + Some(&>::to_seed(authority)), + ) .expect("Creates authority key"); keystore.into() } diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 8b3b8e782393..888d1b072344 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -24,7 +24,7 @@ use crate::{ }, error::Error, justification::BeefyVersionedFinalityProof, - keystore::{BeefyKeystore, BeefySignatureHasher}, + keystore::BeefyKeystore, metric_inc, metric_set, metrics::VoterMetrics, round::{Rounds, VoteImportResult}, @@ -42,8 +42,8 @@ use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, ecdsa_crypto::{AuthorityId, Signature}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + BeefyApi, BeefySignatureHasher, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, + ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::OpaqueDigestItemId, @@ -1068,7 +1068,7 @@ pub(crate) mod tests { use sp_blockchain::Backend as BlockchainBackendT; use sp_consensus_beefy::{ generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, - mmr::MmrRootProvider, Keyring, Payload, SignedCommitment, + mmr::MmrRootProvider, GenericKeyring, Keyring, Payload, SignedCommitment, }; use sp_runtime::traits::One; use substrate_test_runtime_client::{ @@ -1646,7 +1646,7 @@ pub(crate) mod tests { // now let's try with a bad proof let mut bad_proof = good_proof.clone(); - bad_proof.first.id = Keyring::Charlie.public(); + bad_proof.first.id = >::public(Keyring::Charlie); // bad proofs are simply ignored assert_eq!(worker.report_equivocation(bad_proof), Ok(())); // verify nothing reported to runtime diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 30fbaedce896..c42867295964 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -37,7 +37,7 @@ use sp_core::bandersnatch; } sp_keystore::bls_experimental_enabled! { -use sp_core::{bls377, bls381, ecdsa_bls377}; +use sp_core::{bls377, bls381, ecdsa_bls377, KeccakHasher}; } use crate::{Error, Result}; @@ -396,9 +396,10 @@ impl Keystore for LocalKeystore { key_type: KeyTypeId, public: &ecdsa_bls377::Public, msg: &[u8], - ) -> Result, Error> { - let sig = self - .pair::(key_type, public) + ) -> std::result::Result, TraitError> { + let sig = self.0 + .read() + .key_pair_by_type::(public, key_type)? .map(|pair| pair.sign_with_hasher::(msg)); Ok(sig) } diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 5ff0a2ebc70f..9457be51db5e 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -21,13 +21,14 @@ sp-core = { path = "../../core", default-features = false} sp-io = { path = "../../io", default-features = false} sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false} sp-runtime = { path = "../../runtime", default-features = false} +sp-keystore = { path = "../../keystore", default-features = false} sp-std = { path = "../../std", default-features = false} strum = { version = "0.24.1", features = ["derive"], default-features = false } lazy_static = "1.4.0" [dev-dependencies] array-bytes = "6.1" -w3f-bls = { version = "0.1.3", features = ["std"]} +w3f-bls = { version = "0.1.3", features = ["std"]} [features] default = [ "std" ] diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 5b6ef9ae5ab3..f8be4dbd7916 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -397,7 +397,7 @@ mod tests { assert_eq!( encoded, array_bytes::hex2bytes_unchecked( - "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01667603fc041cf9d7147d22bf54b15e5778893d6986b71a929747befd3b4d233fbe668bc480e8865116b94db46ca25a01e03c71955f2582604e415da68f2c3c406b9d5f4ad416230ec5453f05ac16a50d8d0923dfb0413cc956ae3fa6334465bd1f2cacec8e9cd606438390fe2a29dc052d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00df61d3b2be0963eb6caa243cc505d327aec73e1bb7ffe9a14b1354b0c406792ac6d6f47c06987c15dec9993f43eefa001d866fe0850d986702c414840f0d9ec0fdc04832ef91ae37c8d49e2f573ca50cb37f152801d489a19395cb04e5fc8f2ab6954b58a3bcc40ef9b6409d2ff7ef07" + "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba015dd1c9b2237e54baa93d232cdf83a430b58a5efbc2f86ca1bab173a315ff6f15bef161425750c028055e9a23947b73002889a8b22168628438875a8ef25d76db998a80187b50719471286f054f3b3809b77a0cd87d7fe9c1a9d5d562683e25a70610f0804e92340549a43a7159b77b0c2d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a001074884b6998c82331bd57ffa0a02cbfd02483c765b9216eab6a1fc119206236bf7971be68acaebff7400edee943240006a6096c9cfa65e9eb4e67f025c27112d14b4574fb208c439500f45cf3a8060f6cf009044f3141cce0364a7c2710a19b1bdf4abf27f86e5e3db08bddd35a7d12" ) ); } diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 738a491f04fb..5af0e9b0800f 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -44,8 +44,9 @@ pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; pub use test_utils::*; use codec::{Codec, Decode, Encode}; +use core::fmt::{Debug, Display}; use scale_info::TypeInfo; -use sp_application_crypto::RuntimeAppPublic; +use sp_application_crypto::{AppCrypto, AppPublic, ByteArray, RuntimeAppPublic}; use sp_core::H256; use sp_runtime::traits::{Hash, Keccak256, NumberFor}; use sp_std::prelude::*; @@ -63,6 +64,30 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool; } +/// Hasher used for BEEFY signatures. +pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; + +/// A trait bound which lists all traits which are required to be implemented by +/// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore +pub trait AuthorityIdBound: + Codec + + Debug + + Clone + + Ord + + Sync + + Send + + AsRef<[u8]> + + ByteArray + + AppPublic + + AppCrypto + + RuntimeAppPublic + + Display + + BeefyAuthorityId +where + ::Signature: Send + Sync, +{ +} + /// BEEFY cryptographic types for ECDSA crypto /// /// This module basically introduces four crypto types: @@ -74,7 +99,7 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { /// Your code should use the above types as concrete types for all crypto related /// functionality. pub mod ecdsa_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; @@ -101,6 +126,7 @@ pub mod ecdsa_crypto { } } } + impl AuthorityIdBound for AuthorityId {} } /// BEEFY cryptographic types for BLS crypto @@ -116,7 +142,7 @@ pub mod ecdsa_crypto { #[cfg(feature = "bls-experimental")] pub mod bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, bls377}; use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; @@ -141,6 +167,7 @@ pub mod bls_crypto { BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) } } + impl AuthorityIdBound for AuthorityId {} } /// BEEFY cryptographic types for (ECDSA,BLS) crypto pair @@ -155,7 +182,7 @@ pub mod bls_crypto { /// functionality. #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair}; @@ -183,6 +210,8 @@ pub mod ecdsa_bls_crypto { ) } } + + impl AuthorityIdBound for AuthorityId {} } /// The `ConsensusEngineId` of BEEFY. diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index b83f657af38e..2f355d5feea8 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -17,9 +17,21 @@ #![cfg(feature = "std")] -use crate::{ecdsa_crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage}; +use core::fmt::Debug; +use sp_runtime::traits::Hash; + +#[cfg(feature = "bls-experimental")] +use crate::ecdsa_bls_crypto; +use crate::{ + ecdsa_crypto, AuthorityIdBound, BeefySignatureHasher, Commitment, EquivocationProof, Payload, + ValidatorSetId, VoteMessage, +}; use codec::Encode; -use sp_core::{ecdsa, keccak_256, Pair}; +use sp_application_crypto::{AppCrypto, AppPair, RuntimeAppPublic, Wraps}; +#[cfg(feature = "bls-experimental")] +use sp_core::ecdsa_bls377; +use sp_core::{ecdsa, Pair}; +use sp_keystore::{Keystore, KeystorePtr}; use std::collections::HashMap; use strum::IntoEnumIterator; @@ -36,52 +48,307 @@ pub enum Keyring { One, Two, } +/// Trait representing BEEFY specific generating and signing behavoir of authority id +/// +/// Accepts custom hashing fn for the message and custom convertor fn for the signer. +pub trait BeefySignerAuthority: AppPair { + /// generate a signature. + /// + /// Return `true` if signature over `msg` is valid for this id. + fn sign_with_hasher(&self, message: &[u8]) -> ::Signature; +} + +impl BeefySignerAuthority for ::Pair +where + MsgHash: Hash, + ::Output: Into<[u8; 32]>, +{ + fn sign_with_hasher(&self, message: &[u8]) -> ::Signature { + let hashed_message = ::hash(message).into(); + self.as_inner_ref().sign_prehashed(&hashed_message).into() + } +} + +#[cfg(feature = "bls-experimental")] +impl BeefySignerAuthority for ::Pair +where + MsgHash: Hash, + ::Output: Into<[u8; 32]>, +{ + fn sign_with_hasher(&self, message: &[u8]) -> ::Signature { + self.as_inner_ref().sign_with_hasher::(&message).into() + } +} + +/// Implement Keyring functionalities generically over AuthorityId +pub trait GenericKeyring +where + ::Signature: Send + Sync, +{ + ///The key pair type which is used to perform crypto functionalities for the Keyring + type KeyPair: AppPair; + /// Generate key pair in the given store using the provided seed + fn generate_in_store( + store: KeystorePtr, + key_type: sp_application_crypto::KeyTypeId, + owner: Option, + ) -> AuthorityId; -impl Keyring { /// Sign `msg`. - pub fn sign(self, msg: &[u8]) -> ecdsa_crypto::Signature { - // todo: use custom signature hashing type - let msg = keccak_256(msg); - ecdsa::Pair::from(self).sign_prehashed(&msg).into() + fn sign(self, msg: &[u8]) -> ::Signature; + + /// Return key pair. + fn pair(self) -> Self::KeyPair; + + /// Return public key. + fn public(self) -> AuthorityId; + + /// Return seed string. + fn to_seed(self) -> String; + + /// Get Keyring from public key. + fn from_public(who: &AuthorityId) -> Option; +} + +impl GenericKeyring for Keyring +where + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + ::Pair: BeefySignerAuthority, + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, +{ + type KeyPair = ::Pair; + fn generate_in_store( + store: KeystorePtr, + key_type: sp_application_crypto::KeyTypeId, + owner: Option, + ) -> AuthorityId { + let optional_seed: Option = owner + .map(|owner| >::to_seed(owner)); + + match ::CRYPTO_ID { + ecdsa::CRYPTO_ID => AuthorityId::decode( + &mut Keystore::ecdsa_generate_new(&*store, key_type, optional_seed.as_deref()) + .ok() + .unwrap() + .as_ref(), + ) + .unwrap(), + + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => { + let pk = Keystore::ecdsa_bls377_generate_new( + &*store, + key_type, + optional_seed.as_deref(), + ) + .ok() + .unwrap(); + let decoded_pk = AuthorityId::decode(&mut pk.as_ref()).unwrap(); + println!( + "Seed: {:?}, before decode: {:?}, after decode: {:?}", + optional_seed, pk, decoded_pk + ); + decoded_pk + }, + + _ => panic!("Requested CRYPTO_ID is not supported by the BEEFY Keyring"), + } + } + /// Sign `msg`. + fn sign(self, msg: &[u8]) -> ::Signature { + let key_pair: Self::KeyPair = >::pair(self); + key_pair.sign_with_hasher(&msg).into() } /// Return key pair. - pub fn pair(self) -> ecdsa_crypto::Pair { - ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() + fn pair(self) -> Self::KeyPair { + Self::KeyPair::from_string( + >::to_seed(self).as_str(), + None, + ) + .unwrap() + .into() } /// Return public key. - pub fn public(self) -> ecdsa_crypto::Public { - self.pair().public() + fn public(self) -> AuthorityId { + >::pair(self).public().into() } /// Return seed string. - pub fn to_seed(self) -> String { + fn to_seed(self) -> String { format!("//{}", self) } /// Get Keyring from public key. - pub fn from_public(who: &ecdsa_crypto::Public) -> Option { - Self::iter().find(|&k| &ecdsa_crypto::Public::from(k) == who) + fn from_public(who: &AuthorityId) -> Option { + Self::iter().find(|&k| >::public(k) == *who) } } +// pub(crate) trait SimpleKeyPair: Clone + Sized + Sync + Send { +// type Public: Clone + Codec + Debug + Ord + Sync + Send + Wraps; +// type Signature: Clone + Codec + Debug + Clone + Sync + Send + Wraps; + +// fn generate_in_store(store: KeystorePtr, owner: Keyring) -> Self::Public; + +// fn add_typed_key_to_store( +// store: KeystorePtr, +// key_type: sp_application_crypto::KeyTypeId, +// seed: Option<&str>, +// ) -> Self::Public; + +// fn sign(&self, hashed_message: &[u8]) -> Self::Signature; + +// fn public(&self) -> Self::Public; + +// fn verify(sig: &Self::Signature, hashed_message: &[u8], pubkey: Self::Public) -> bool; + +// fn from_string(s: &str, password_override: Option<&str>) +// -> Result; + +// /// Return a vec filled with raw data. +// fn to_raw_vec(&self) -> Vec; +// } +// Auxiliary traits for ECDSA +// impl SimpleKeyPair for ecdsa_crypto::Pair { +// type Public = ecdsa_crypto::Public; +// type Signature = ecdsa_crypto::Signature; + +// fn geonerate_in_store(store: KeystorePtr, owner: Keyring) -> Self::Public { +// Keystore::ecdsa_generate_new( +// &*store, +// KEY_TYPE, +// Some(&>::to_seed(owner)), +// ) +// .ok() +// o.unwrap() +// .into() +// } + +// fn add_typed_key_to_store( +// store: KeystorePtr, +// key_type: sp_application_crypto::KeyTypeId, +// seed: Option<&str>, +// ) -> Self::Public { +// Keystore::ecdsa_generate_new(&*store, key_type, seed) +// .ok() +// .unwrap() +// .into() +// } + +// fn sign(&self, message: &[u8]) -> Self::Signature { +// let hashed_message = keccak_256(message); +// self.as_inner_ref().sign_prehashed(&hashed_message).into() +// } + +// fn verify( +// sig: &::Signature, +// message: &[u8], +// pubkey: Self::Public, +// ) -> bool { +// let hashed_message = keccak_256(message); +// ecdsa::Pair::verify_prehashed( +// sig.as_inner_ref(), +// &hashed_message, +// pubkey.as_inner_ref(), +// ) +// } + +// fn public(&self) -> Self::Public { +// ::public(self) +// } + +// fn from_string( +// s: &str, +// password_override: Option<&str>, +// ) -> Result { +// ::from_string(s, password_override) +// } + +// /// Return a vec filled with raw data. +// fn to_raw_vec(&self) -> Vec { +// ::to_raw_vec(self) +// } +// } + +// /// Auxiliary traits for ECDSA_BLS377 +// #[cfg(feature = "bls-experimental")] +// impl SimpleKeyPair for ecdas_bls377_crypto::Pair { +// type Public = ecdas_bls377_crypto::Public; +// type Signature = ecdas_bls377_crypto::Signature; + +// fn generate_in_store(store: KeystorePtr, owner: Keyring) -> Self::Public { +// Keystore::ecdsa_bls377_generate_new( +// &*store, +// KEY_TYPE, +// Some(&>::to_seed(owner)), +// ) +// .ok() +// .unwrap() +// .into() +// } + +// fn add_typed_key_to_store( +// store: KeystorePtr, +// key_type: sp_application_crypto::KeyTypeId, +// seed: Option<&str>, +// ) -> Self::Public { +// Keystore::ecdsa_bls377_generate_new(&*store, key_type, seed) +// .ok() +// .unwrap() +// .into() +// } + +// fn sign(&self, message: &[u8]) -> Self::Signature { +// self.sign_with_hasher::(&message).into() + +// } + +// fn verify( +// sig: &::Signature, +// message: &[u8], +// pubkey: Self::Public, +// ) -> bool { +// ecdsa_bls377::Pair::verify_with_hasher::(sig.as_inner_ref(), &message, +// &pubkey.as_inner_ref()) + +// } + +// fn public(&self) -> Self::Public { +// ::public(self) +// } + +// fn from_string( +// s: &str, +// password_override: Option<&str>, +// ) -> Result { +// ::from_string(s, password_override) +// } + +// /// Return a vec filled with raw data. +// fn to_raw_vec(&self) -> Vec { +// ::to_raw_vec(self) +// } +// } + lazy_static::lazy_static! { static ref PRIVATE_KEYS: HashMap = - Keyring::iter().map(|i| (i, i.pair())).collect(); + Keyring::iter().map(|i| (i, >::pair(i))).collect(); static ref PUBLIC_KEYS: HashMap = - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); + PRIVATE_KEYS.iter().map(|(&name, pair)| (name, sp_application_crypto::Pair::public(pair))).collect(); } impl From for ecdsa_crypto::Pair { fn from(k: Keyring) -> Self { - k.pair() + >::pair(k) } } impl From for ecdsa::Pair { fn from(k: Keyring) -> Self { - k.pair().into() + >::pair(k).into() } } @@ -101,8 +368,15 @@ pub fn generate_equivocation_proof( validator_set_id: ValidatorSetId, keyring: &Keyring| { let commitment = Commitment { validator_set_id, block_number, payload }; - let signature = keyring.sign(&commitment.encode()); - VoteMessage { commitment, id: keyring.public(), signature } + let signature = >::sign( + *keyring, + &commitment.encode(), + ); + VoteMessage { + commitment, + id: >::public(*keyring), + signature, + } }; let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3); let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3); diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index e519ba1806c4..720520af6bfd 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -452,11 +452,12 @@ impl TraitPair for Pair { fn derive>( &self, path: Iter, - _seed: Option, + seed: Option, ) -> Result<(Self, Option), DeriveError> { - let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = self.0.secret.to_bytes().try_into().expect( - "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size; qed", - ); + let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = + seed.unwrap_or(self.0.secret.to_bytes().try_into().expect( + "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size; qed", + )); for j in path { match j { DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), @@ -588,12 +589,12 @@ mod test { assert_eq!( public, Public::unchecked_from(array_bytes::hex2array_unchecked( - "6dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" )) ); let message = b""; let signature = - array_bytes::hex2array_unchecked("bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" + array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" ); let expected_signature = Signature::unchecked_from(signature); println!("signature is {:?}", pair.sign(&message[..])); @@ -647,6 +648,19 @@ mod test { assert_eq!(pair1.public(), pair2.public()); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } + #[test] fn password_does_something() { let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 603fa515a30e..a457d6c93326 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -651,6 +651,19 @@ mod test { assert_eq!(pair1.public(), pair2.public()); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } + #[test] fn password_does_something() { let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 03567a8b7317..aaf5efe2b705 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -458,10 +458,11 @@ where path: Iter, seed: Option, ) -> Result<(Self, Option), DeriveError> { - let path: Vec<_> = path.collect(); + let left_path: Vec<_> = path.collect(); + let right_path: Vec<_> = left_path.clone(); - let left = self.left.derive(path.iter().cloned(), seed.map(|s| s.into()))?; - let right = self.right.derive(path.into_iter(), seed.map(|s| s.into()))?; + let left = self.left.derive(left_path.into_iter(), seed.map(|s| s.into()))?; + let right = self.right.derive(right_path.into_iter(), seed.map(|s| s.into()))?; let seed = match (left.1, right.1) { (Some(l), Some(r)) if l.as_ref() == r.as_ref() => Some(l.into()), @@ -540,6 +541,18 @@ mod test { ); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } #[test] fn seed_and_derive_should_work() { let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( @@ -597,13 +610,13 @@ mod test { assert_eq!( public, Public::unchecked_from( - array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" ), ), ); let message = b""; let signature = - array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" + array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" ); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index ffa52ef97d1f..dfeefe130f3c 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -967,6 +967,19 @@ mod tests { assert!(Pair::verify(&signature, &message[..], &public)); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } + #[test] fn generated_pair_should_work() { let (pair, _) = Pair::generate(); From c860dd0a1810a0bee3e54c77bc0971ef84119e3d Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:58:03 -0500 Subject: [PATCH 34/78] Improve documention and comments Co-authored-by: Robert Hambrock --- substrate/primitives/consensus/beefy/src/lib.rs | 2 +- substrate/primitives/core/src/paired_crypto.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 738a491f04fb..2684baac407b 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -517,7 +517,7 @@ mod tests { // Verification works if same hashing function is used when signing and verifying. assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); - // Verification doesn't works if we verify function provided by pair_crypto implementation + // Verification doesn't work if we verify function provided by pair_crypto implementation assert!(!ecdsa_bls_crypto::Pair::verify(&signature, msg, &pair.public())); // Other public key doesn't work diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 03567a8b7317..684b8dffa343 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -80,7 +80,7 @@ pub mod ecdsa_bls377 { impl Pair { /// hashes the `message` with the specified `MsgHasher` and then signs it using ECDSA /// algorithm. It does not affect the behavoir of BLS12-377 component. It generates - /// BLS12-377 Signature according to IETF standard and disregard the hasher for the + /// BLS12-377 Signature according to IETF standard and disregards the hasher for the /// BLS12-377 component pub fn sign_with_hasher(&self, message: &[u8]) -> Signature where @@ -96,10 +96,10 @@ pub mod ecdsa_bls377 { ::Signature::unchecked_from(raw) } - /// hashes the `message` with the specified `MsgHasher` and then verifys if the resulting - /// hash was signed by the provided ECDSA public key.. It does not affect the behavoir of - /// BLS12-377 component. It Verify the BLS12-377 signature as it was hashed and signed - /// according to IETF standrad + /// Hashes the `message` with the specified `MsgHasher` and then verifies whether the resulting + /// hash was signed by the provided ECDSA public key. It does not affect the behavior of the + /// BLS12-377 component. It verifies whether the BLS12-377 signature was hashed and signed + /// according to IETF standard pub fn verify_with_hasher( sig: &Signature, message: &[u8], From 8958fde0b96c401be5cd82e233f85ea2e513fd64 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 9 Nov 2023 14:54:21 -0500 Subject: [PATCH 35/78] Remove unused SimpleKeyPair Trait --- .../consensus/beefy/src/test_utils.rs | 146 ------------------ 1 file changed, 146 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index 2f355d5feea8..795efbd81012 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -187,152 +187,6 @@ where } } -// pub(crate) trait SimpleKeyPair: Clone + Sized + Sync + Send { -// type Public: Clone + Codec + Debug + Ord + Sync + Send + Wraps; -// type Signature: Clone + Codec + Debug + Clone + Sync + Send + Wraps; - -// fn generate_in_store(store: KeystorePtr, owner: Keyring) -> Self::Public; - -// fn add_typed_key_to_store( -// store: KeystorePtr, -// key_type: sp_application_crypto::KeyTypeId, -// seed: Option<&str>, -// ) -> Self::Public; - -// fn sign(&self, hashed_message: &[u8]) -> Self::Signature; - -// fn public(&self) -> Self::Public; - -// fn verify(sig: &Self::Signature, hashed_message: &[u8], pubkey: Self::Public) -> bool; - -// fn from_string(s: &str, password_override: Option<&str>) -// -> Result; - -// /// Return a vec filled with raw data. -// fn to_raw_vec(&self) -> Vec; -// } -// Auxiliary traits for ECDSA -// impl SimpleKeyPair for ecdsa_crypto::Pair { -// type Public = ecdsa_crypto::Public; -// type Signature = ecdsa_crypto::Signature; - -// fn geonerate_in_store(store: KeystorePtr, owner: Keyring) -> Self::Public { -// Keystore::ecdsa_generate_new( -// &*store, -// KEY_TYPE, -// Some(&>::to_seed(owner)), -// ) -// .ok() -// o.unwrap() -// .into() -// } - -// fn add_typed_key_to_store( -// store: KeystorePtr, -// key_type: sp_application_crypto::KeyTypeId, -// seed: Option<&str>, -// ) -> Self::Public { -// Keystore::ecdsa_generate_new(&*store, key_type, seed) -// .ok() -// .unwrap() -// .into() -// } - -// fn sign(&self, message: &[u8]) -> Self::Signature { -// let hashed_message = keccak_256(message); -// self.as_inner_ref().sign_prehashed(&hashed_message).into() -// } - -// fn verify( -// sig: &::Signature, -// message: &[u8], -// pubkey: Self::Public, -// ) -> bool { -// let hashed_message = keccak_256(message); -// ecdsa::Pair::verify_prehashed( -// sig.as_inner_ref(), -// &hashed_message, -// pubkey.as_inner_ref(), -// ) -// } - -// fn public(&self) -> Self::Public { -// ::public(self) -// } - -// fn from_string( -// s: &str, -// password_override: Option<&str>, -// ) -> Result { -// ::from_string(s, password_override) -// } - -// /// Return a vec filled with raw data. -// fn to_raw_vec(&self) -> Vec { -// ::to_raw_vec(self) -// } -// } - -// /// Auxiliary traits for ECDSA_BLS377 -// #[cfg(feature = "bls-experimental")] -// impl SimpleKeyPair for ecdas_bls377_crypto::Pair { -// type Public = ecdas_bls377_crypto::Public; -// type Signature = ecdas_bls377_crypto::Signature; - -// fn generate_in_store(store: KeystorePtr, owner: Keyring) -> Self::Public { -// Keystore::ecdsa_bls377_generate_new( -// &*store, -// KEY_TYPE, -// Some(&>::to_seed(owner)), -// ) -// .ok() -// .unwrap() -// .into() -// } - -// fn add_typed_key_to_store( -// store: KeystorePtr, -// key_type: sp_application_crypto::KeyTypeId, -// seed: Option<&str>, -// ) -> Self::Public { -// Keystore::ecdsa_bls377_generate_new(&*store, key_type, seed) -// .ok() -// .unwrap() -// .into() -// } - -// fn sign(&self, message: &[u8]) -> Self::Signature { -// self.sign_with_hasher::(&message).into() - -// } - -// fn verify( -// sig: &::Signature, -// message: &[u8], -// pubkey: Self::Public, -// ) -> bool { -// ecdsa_bls377::Pair::verify_with_hasher::(sig.as_inner_ref(), &message, -// &pubkey.as_inner_ref()) - -// } - -// fn public(&self) -> Self::Public { -// ::public(self) -// } - -// fn from_string( -// s: &str, -// password_override: Option<&str>, -// ) -> Result { -// ::from_string(s, password_override) -// } - -// /// Return a vec filled with raw data. -// fn to_raw_vec(&self) -> Vec { -// ::to_raw_vec(self) -// } -// } - lazy_static::lazy_static! { static ref PRIVATE_KEYS: HashMap = Keyring::iter().map(|i| (i, >::pair(i))).collect(); From 3b8ededc87fb5203904cf4725b16407163705d40 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 13 Nov 2023 11:09:31 -0500 Subject: [PATCH 36/78] add reasoning on why in BEEFY we want the ECDSA signature on Keccak hash of the message instead of Blake2 --- substrate/primitives/consensus/beefy/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 2684baac407b..3fd33e934c69 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -175,7 +175,14 @@ pub mod ecdsa_bls_crypto { // We can not simply call // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` // because that invokes ecdsa default verification which perfoms blake2 hash - // which we don't want. + // which we don't want. This is because ECDSA signatures are meant to be verified + // on Ethereum network where Keccak hasher is siginificantly cheaper than Blake2b. + // See Figure 3 of [OnSc21](https://www.scitepress.org/Papers/2021/106066/106066.pdf) + // for comparison. + // + // - [OnSc21] Onica, E., & SchifirneÅ£, C. (2021). Towards efficient hashing in + // ethereum smart contracts. Proceedings of the 16th International + // Conference on Software Technologies, () EcdsaBlsPair::verify_with_hasher::( signature.as_inner_ref(), msg, From 8cfccd8696f39a2727a5952d55d8491d0648d3ff Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 13 Nov 2023 11:45:32 -0500 Subject: [PATCH 37/78] fmt --- substrate/primitives/core/src/paired_crypto.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 684b8dffa343..aa9994695573 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -96,10 +96,10 @@ pub mod ecdsa_bls377 { ::Signature::unchecked_from(raw) } - /// Hashes the `message` with the specified `MsgHasher` and then verifies whether the resulting - /// hash was signed by the provided ECDSA public key. It does not affect the behavior of the - /// BLS12-377 component. It verifies whether the BLS12-377 signature was hashed and signed - /// according to IETF standard + /// Hashes the `message` with the specified `MsgHasher` and then verifies whether the + /// resulting hash was signed by the provided ECDSA public key. It does not affect the + /// behavior of the BLS12-377 component. It verifies whether the BLS12-377 signature was + /// hashed and signed according to IETF standard pub fn verify_with_hasher( sig: &Signature, message: &[u8], From a15a60da935a52317d8e9975de233a9b9b9a0629 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:08:43 -0500 Subject: [PATCH 38/78] Improve documentation Co-authored-by: Davide Galassi --- substrate/primitives/consensus/beefy/src/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 3fd33e934c69..f79ee3ba0c9d 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -174,15 +174,11 @@ pub mod ecdsa_bls_crypto { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { // We can not simply call // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` - // because that invokes ecdsa default verification which perfoms blake2 hash + // because that invokes ECDSA default verification which perfoms Blake2b hash // which we don't want. This is because ECDSA signatures are meant to be verified - // on Ethereum network where Keccak hasher is siginificantly cheaper than Blake2b. + // on Ethereum network where Keccak hasher is significantly cheaper than Blake2b. // See Figure 3 of [OnSc21](https://www.scitepress.org/Papers/2021/106066/106066.pdf) // for comparison. - // - // - [OnSc21] Onica, E., & SchifirneÅ£, C. (2021). Towards efficient hashing in - // ethereum smart contracts. Proceedings of the 16th International - // Conference on Software Technologies, () EcdsaBlsPair::verify_with_hasher::( signature.as_inner_ref(), msg, From 00b62effe599d36d0ca699438ba996a8bafab96e Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 13 Nov 2023 15:24:15 -0500 Subject: [PATCH 39/78] fmt --- substrate/client/consensus/beefy/src/keystore.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 80e2f807c2b1..e21364c4baa5 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -180,9 +180,7 @@ where ecdsa_bls377::CRYPTO_ID => store .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) .drain(..) - .map(|pk| - AuthorityId::try_from(pk.as_ref()) - ) + .map(|pk| AuthorityId::try_from(pk.as_ref())) .collect::, _>>() .or_else(|_| { Err(error::Error::Keystore( From 3ef0f652f199cafc794d4eee924503138cd6d7c9 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Mon, 27 Nov 2023 06:13:40 -0500 Subject: [PATCH 40/78] Improve comment quality Co-authored-by: Robert Hambrock --- substrate/client/consensus/beefy/src/keystore.rs | 8 ++++---- substrate/primitives/consensus/beefy/src/lib.rs | 2 +- substrate/primitives/consensus/beefy/src/test_utils.rs | 3 ++- substrate/primitives/core/src/paired_crypto.rs | 2 +- substrate/primitives/keystore/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index e21364c4baa5..0ea46a47eee3 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -38,9 +38,9 @@ use crate::{error, LOG_TARGET}; // RuntimeAppPublic + BeefyAuthorityId > AuthorityIdBound for T { type // Signature = AppCrypto::Signature; } -/// A BEEFY specific keystore i mplemented as a `Newtype`. This is basically a +/// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::Keystore`] and allows to customize -/// commoncryptographic functionality. +/// common cryptographic functionality. pub(crate) struct BeefyKeystore( Option, PhantomData AuthorityId>, @@ -95,9 +95,9 @@ where ) -> Result<::Signature, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - //ECDSA shoud do ecdsa_sign_prehashed because it needs to be hashed by keccak_256 - //as such we need to deal with signing case by case + // ECDSA should use ecdsa_sign_prehashed since it needs to be hashed by keccak_256 instead of blake2. + // As such we need to deal with producing the signatures case-by-case let signature_byte_array: Vec = match ::CRYPTO_ID { ecdsa::CRYPTO_ID => { let msg_hash = keccak_256(message); diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index bd412faa4f7f..4fd71b298fa5 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -160,7 +160,7 @@ pub mod bls_crypto { { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { // `w3f-bls` library uses IETF hashing standard and as such does not expose - // a choice of hash to field function. + // a choice of hash-to-field function. // We are directly calling into the library to avoid introducing new host call. // and because BeefyAuthorityId::verify is being called in the runtime so we don't have diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index 795efbd81012..6aefc52f1fa5 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -48,7 +48,8 @@ pub enum Keyring { One, Two, } -/// Trait representing BEEFY specific generating and signing behavoir of authority id + +/// Trait representing BEEFY specific generation and signing behavior of authority id /// /// Accepts custom hashing fn for the message and custom convertor fn for the signer. pub trait BeefySignerAuthority: AppPair { diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a26c536d257c..79c02f1a979f 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -78,7 +78,7 @@ pub mod ecdsa_bls377 { #[cfg(feature = "full_crypto")] impl Pair { - /// hashes the `message` with the specified `MsgHasher` and then signs it using ECDSA + /// Hashes the `message` with the specified `MsgHasher` and then signs it using ECDSA /// algorithm. It does not affect the behavoir of BLS12-377 component. It generates /// BLS12-377 Signature according to IETF standard and disregards the hasher for the /// BLS12-377 component diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 8999bf2ec0bc..f6132f5e10f4 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -356,7 +356,7 @@ pub trait Keystore: Send + Sync { ) -> Result, Error>; /// Hashes the `message` using keccak256 and then signs it using ECDSA - /// algorithm. It does not affect the behavoir of BLS12-377 component. It generates + /// algorithm. It does not affect the behavior of BLS12-377 component. It generates /// BLS12-377 Signature according to IETF standard. /// /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map From 3f8d533375f3f78ddf315672cff605d94d92ee1c Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 5 Dec 2023 12:43:18 -0500 Subject: [PATCH 41/78] drop 'perhaps' from generate_with_phrase_should_be_recoverable_with_from_string_perhaps test and add it to bandersnatch and ed25519 --- substrate/primitives/core/src/bandersnatch.rs | 13 +++++++++++++ substrate/primitives/core/src/bls.rs | 2 +- substrate/primitives/core/src/ecdsa.rs | 2 +- substrate/primitives/core/src/ed25519.rs | 13 +++++++++++++ substrate/primitives/core/src/paired_crypto.rs | 3 ++- substrate/primitives/core/src/sr25519.rs | 2 +- 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index b91c001a7de0..760cc0862b32 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -983,6 +983,19 @@ mod tests { assert!(res.is_err()); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } + #[test] fn sign_verify() { let pair = Pair::from_seed(DEV_SEED); diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 720520af6bfd..11b1deeae8df 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -649,7 +649,7 @@ mod test { } #[test] - fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + fn generate_with_phrase_should_be_recoverable_with_from_string() { let (pair, phrase, seed) = Pair::generate_with_phrase(None); let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); assert_eq!(pair.public(), repair_seed.public()); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 0e31cad15d8d..9568c1386bf9 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -647,7 +647,7 @@ mod test { } #[test] - fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + fn generate_with_phrase_should_be_recoverable_with_from_string() { let (pair, phrase, seed) = Pair::generate_with_phrase(None); let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); assert_eq!(pair.public(), repair_seed.public()); diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index 151a7229315e..8b99e38247da 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -501,6 +501,19 @@ mod test { ); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } + #[test] fn test_vector_should_work() { let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index dded976e965e..f48f7f0918c5 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -544,7 +544,7 @@ mod test { } #[test] - fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + fn generate_with_phrase_should_be_recoverable_with_from_string() { let (pair, phrase, seed) = Pair::generate_with_phrase(None); let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); assert_eq!(pair.public(), repair_seed.public()); @@ -555,6 +555,7 @@ mod test { let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); assert_eq!(pair.public(), repair_string.public()); } + #[test] fn seed_and_derive_should_work() { let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index dfeefe130f3c..4018cd5bb120 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -968,7 +968,7 @@ mod tests { } #[test] - fn generate_with_phrase_should_be_recoverable_with_from_string_perhaps() { + fn generate_with_phrase_should_be_recoverable_with_from_string() { let (pair, phrase, seed) = Pair::generate_with_phrase(None); let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); assert_eq!(pair.public(), repair_seed.public()); From 5f09d22404a2c3470e1ac3a9f6ad0ea426dff300 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 5 Dec 2023 21:44:46 +0100 Subject: [PATCH 42/78] fmt --- substrate/client/consensus/beefy/src/keystore.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 0ea46a47eee3..8b7c638f2d93 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -95,9 +95,8 @@ where ) -> Result<::Signature, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - - // ECDSA should use ecdsa_sign_prehashed since it needs to be hashed by keccak_256 instead of blake2. - // As such we need to deal with producing the signatures case-by-case + // ECDSA should use ecdsa_sign_prehashed since it needs to be hashed by keccak_256 instead + // of blake2. As such we need to deal with producing the signatures case-by-case let signature_byte_array: Vec = match ::CRYPTO_ID { ecdsa::CRYPTO_ID => { let msg_hash = keccak_256(message); From 6304d1e110d76730499ff38ca341d086c88ead76 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:53:41 +0100 Subject: [PATCH 43/78] Apply suggestions from code review Code and dependency clean-up Co-authored-by: Davide Galassi --- substrate/client/consensus/beefy/Cargo.toml | 1 - substrate/primitives/consensus/beefy/src/test_utils.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index e2f26b71f857..c79e8b919b38 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -36,7 +36,6 @@ sp-core = { path = "../../../primitives/core" } sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } -sp-std = { path = "../../../primitives/std", default-features = false} [dev-dependencies] serde = "1.0.193" diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index 6aefc52f1fa5..13f2eb0176b1 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -53,7 +53,7 @@ pub enum Keyring { /// /// Accepts custom hashing fn for the message and custom convertor fn for the signer. pub trait BeefySignerAuthority: AppPair { - /// generate a signature. + /// Generate a signature. /// /// Return `true` if signature over `msg` is valid for this id. fn sign_with_hasher(&self, message: &[u8]) -> ::Signature; @@ -88,6 +88,7 @@ where { ///The key pair type which is used to perform crypto functionalities for the Keyring type KeyPair: AppPair; + /// Generate key pair in the given store using the provided seed fn generate_in_store( store: KeystorePtr, From 7fc132605dcf34e45db9558cce63a5270928e471 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:25:21 +0100 Subject: [PATCH 44/78] Apply suggestions from code review Co-authored-by: Davide Galassi --- substrate/client/consensus/beefy/src/keystore.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 8b7c638f2d93..dab1efdd8e73 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -34,9 +34,6 @@ use sp_consensus_beefy::ecdsa_bls_crypto; use crate::{error, LOG_TARGET}; -// impl + AppPublic + AppCrypto + -// RuntimeAppPublic + BeefyAuthorityId > AuthorityIdBound for T { type -// Signature = AppCrypto::Signature; } /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::Keystore`] and allows to customize From 6401a97733c2353df89ba08151f30fbd018e2c5e Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 19 Jan 2024 13:17:56 -0500 Subject: [PATCH 45/78] use std instead of sp_std as we are not in the Runtime --- substrate/client/consensus/beefy/src/keystore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 8b7c638f2d93..724d5b3dcc66 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -23,7 +23,7 @@ use sp_core::ecdsa_bls377; use sp_core::{ecdsa, keccak_256}; use sp_keystore::KeystorePtr; -use sp_std::marker::PhantomData; +use std::marker::PhantomData; use log::warn; From 425c3d341c9cda99edde0a83cdb1f9b4dc82820f Mon Sep 17 00:00:00 2001 From: Skalman Date: Fri, 19 Jan 2024 13:19:06 -0500 Subject: [PATCH 46/78] remove sp-std fro Cargo.lock --- Cargo.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 27ce0b716022..958ef3b4c4d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15224,7 +15224,6 @@ dependencies = [ "sp-keystore", "sp-mmr-primitives", "sp-runtime", - "sp-std 8.0.0", "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", From 59a4b5f8328f9b542454672305e383ef61cee6f6 Mon Sep 17 00:00:00 2001 From: Skalman Date: Sat, 20 Jan 2024 14:36:46 -0500 Subject: [PATCH 47/78] Do not re-export internal of primitives/consensus/beefy/src/test_utils --- substrate/client/consensus/beefy/src/communication/gossip.rs | 2 +- substrate/client/consensus/beefy/src/justification.rs | 2 +- substrate/client/consensus/beefy/src/keystore.rs | 2 +- substrate/client/consensus/beefy/src/round.rs | 2 +- substrate/client/consensus/beefy/src/tests.rs | 2 +- substrate/client/consensus/beefy/src/worker.rs | 4 ++-- substrate/primitives/consensus/beefy/src/lib.rs | 4 +--- 7 files changed, 8 insertions(+), 10 deletions(-) diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index c70e5214a13f..eb18f1f4034b 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -481,7 +481,7 @@ pub(crate) mod tests { use sc_network_test::Block; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - ecdsa_crypto::Signature, known_payloads, Commitment, GenericKeyring, Keyring, MmrRootHash, + ecdsa_crypto::Signature, known_payloads, Commitment, test_utils::GenericKeyring, test_utils::Keyring, MmrRootHash, Payload, SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 6de9c5b3316f..00a0e20c1724 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -93,7 +93,7 @@ pub(crate) fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use sp_consensus_beefy::{ - known_payloads, Commitment, GenericKeyring, Keyring, Payload, SignedCommitment, + known_payloads, Commitment, test_utils::GenericKeyring, test_utils::Keyring, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index e67856c160dd..6066aa5c6451 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -213,7 +213,7 @@ where #[cfg(test)] pub mod tests { - use sp_consensus_beefy::{ecdsa_crypto, BeefySignerAuthority, GenericKeyring, Keyring}; + use sp_consensus_beefy::{ecdsa_crypto, test_utils::BeefySignerAuthority, test_utils::GenericKeyring, test_utils::Keyring}; use sp_core::Pair as PairT; use sp_keystore::testing::MemoryKeystore; diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index a3f8c1baad5f..29f5f10a4444 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -203,7 +203,7 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, GenericKeyring, Keyring, + known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, test_utils::GenericKeyring, test_utils::Keyring, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index e85f1abc083f..85b5de238de8 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -55,7 +55,7 @@ use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId, Signature}, known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, GenericKeyring, Keyring as BeefyKeyring, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, test_utils::GenericKeyring, test_utils::Keyring as BeefyKeyring, MmrRootHash, OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index cb2b3285176a..49f888cf011d 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -1076,8 +1076,8 @@ pub(crate) mod tests { use sc_network_test::TestNetFactory; use sp_blockchain::Backend as BlockchainBackendT; use sp_consensus_beefy::{ - generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, - mmr::MmrRootProvider, GenericKeyring, Keyring, Payload, SignedCommitment, + test_utils::generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, + mmr::MmrRootProvider, test_utils::GenericKeyring, test_utils::Keyring, Payload, SignedCommitment, }; use sp_runtime::traits::{Header as HeaderT, One}; use substrate_test_runtime_client::{ diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 9b4d2955cb9d..a5758b74afb1 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -35,13 +35,11 @@ mod commitment; pub mod mmr; mod payload; #[cfg(feature = "std")] -mod test_utils; +pub mod test_utils; pub mod witness; pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; -#[cfg(feature = "std")] -pub use test_utils::*; use codec::{Codec, Decode, Encode}; use core::fmt::{Debug, Display}; From f2956c02249f390bfa7f7b33804da985e234733d Mon Sep 17 00:00:00 2001 From: Skalman Date: Sat, 20 Jan 2024 15:01:34 -0500 Subject: [PATCH 48/78] fix wrong doc for `BeefySignerAuthority::sign_with_hasher` --- substrate/primitives/consensus/beefy/src/test_utils.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index 13f2eb0176b1..0d19d4835465 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -53,9 +53,7 @@ pub enum Keyring { /// /// Accepts custom hashing fn for the message and custom convertor fn for the signer. pub trait BeefySignerAuthority: AppPair { - /// Generate a signature. - /// - /// Return `true` if signature over `msg` is valid for this id. + /// Generate and return signature for `message` using custom hashing `MsgHash` fn sign_with_hasher(&self, message: &[u8]) -> ::Signature; } From 3422057065a19d00c0fcc3e2a0f62fedd4cfef59 Mon Sep 17 00:00:00 2001 From: Skalman Date: Wed, 24 Jan 2024 11:13:19 -0500 Subject: [PATCH 49/78] Make BEEFY Keyring itself generic over AuthId using PhantomData. --- .../consensus/beefy/src/test_utils.rs | 113 ++++++++---------- 1 file changed, 47 insertions(+), 66 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index 0d19d4835465..d70a4d1dbcab 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -34,11 +34,13 @@ use sp_core::{ecdsa, Pair}; use sp_keystore::{Keystore, KeystorePtr}; use std::collections::HashMap; use strum::IntoEnumIterator; +use std::marker::PhantomData; + /// Set of test accounts using [`crate::ecdsa_crypto`] types. #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] -pub enum Keyring { +pub enum Keyring { Alice, Bob, Charlie, @@ -46,7 +48,8 @@ pub enum Keyring { Eve, Ferdie, One, - Two, + Two, + _Marker(PhantomData) } /// Trait representing BEEFY specific generation and signing behavior of authority id @@ -79,52 +82,22 @@ where } } -/// Implement Keyring functionalities generically over AuthorityId -pub trait GenericKeyring -where - ::Signature: Send + Sync, -{ - ///The key pair type which is used to perform crypto functionalities for the Keyring - type KeyPair: AppPair; - /// Generate key pair in the given store using the provided seed - fn generate_in_store( + + +/// Generate key pair in the given store using the provided seed +fn generate_in_store( store: KeystorePtr, key_type: sp_application_crypto::KeyTypeId, - owner: Option, - ) -> AuthorityId; - - /// Sign `msg`. - fn sign(self, msg: &[u8]) -> ::Signature; - - /// Return key pair. - fn pair(self) -> Self::KeyPair; - - /// Return public key. - fn public(self) -> AuthorityId; - - /// Return seed string. - fn to_seed(self) -> String; - - /// Get Keyring from public key. - fn from_public(who: &AuthorityId) -> Option; -} - -impl GenericKeyring for Keyring -where + owner: Option>, + ) -> AuthorityId where AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, ::Pair: BeefySignerAuthority, ::Signature: Send + Sync + From<<::Pair as AppCrypto>::Signature>, { - type KeyPair = ::Pair; - fn generate_in_store( - store: KeystorePtr, - key_type: sp_application_crypto::KeyTypeId, - owner: Option, - ) -> AuthorityId { - let optional_seed: Option = owner - .map(|owner| >::to_seed(owner)); + let optional_seed: Option = owner + .map(|owner| owner.to_seed()); match ::CRYPTO_ID { ecdsa::CRYPTO_ID => AuthorityId::decode( @@ -154,17 +127,26 @@ where _ => panic!("Requested CRYPTO_ID is not supported by the BEEFY Keyring"), } - } +} + +/// Implement Keyring functionalities generically over AuthorityId +impl Keyring +where + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + ::Pair: BeefySignerAuthority, + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, +{ /// Sign `msg`. fn sign(self, msg: &[u8]) -> ::Signature { - let key_pair: Self::KeyPair = >::pair(self); + let key_pair: ::Pair = self.clone().pair(); key_pair.sign_with_hasher(&msg).into() } /// Return key pair. - fn pair(self) -> Self::KeyPair { - Self::KeyPair::from_string( - >::to_seed(self).as_str(), + fn pair(self) -> ::Pair { + ::Pair::from_string( + self.to_seed().as_str(), None, ) .unwrap() @@ -173,7 +155,7 @@ where /// Return public key. fn public(self) -> AuthorityId { - >::pair(self).public().into() + self.clone().pair().public().into() } /// Return seed string. @@ -182,53 +164,52 @@ where } /// Get Keyring from public key. - fn from_public(who: &AuthorityId) -> Option { - Self::iter().find(|&k| >::public(k) == *who) + fn from_public(who: &AuthorityId) -> Option> { + Self::iter().find(|k| k.clone().public() == *who) } } lazy_static::lazy_static! { - static ref PRIVATE_KEYS: HashMap = - Keyring::iter().map(|i| (i, >::pair(i))).collect(); - static ref PUBLIC_KEYS: HashMap = - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, sp_application_crypto::Pair::public(pair))).collect(); + static ref PRIVATE_KEYS: HashMap, ecdsa_crypto::Pair> = + Keyring::iter().map(|i| (i.clone(), i.clone().pair())).collect(); + static ref PUBLIC_KEYS: HashMap, ecdsa_crypto::Public> = + PRIVATE_KEYS.iter().map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))).collect(); } -impl From for ecdsa_crypto::Pair { - fn from(k: Keyring) -> Self { - >::pair(k) +impl From> for ecdsa_crypto::Pair { + fn from(k: Keyring) -> Self { + k.clone().pair() } } -impl From for ecdsa::Pair { - fn from(k: Keyring) -> Self { - >::pair(k).into() +impl From> for ecdsa::Pair { + fn from(k: Keyring) -> Self { + k.clone().pair().into() } } -impl From for ecdsa_crypto::Public { - fn from(k: Keyring) -> Self { +impl From> for ecdsa_crypto::Public { + fn from(k: Keyring) -> Self { (*PUBLIC_KEYS).get(&k).cloned().unwrap() } } /// Create a new `EquivocationProof` based on given arguments. pub fn generate_equivocation_proof( - vote1: (u64, Payload, ValidatorSetId, &Keyring), - vote2: (u64, Payload, ValidatorSetId, &Keyring), + vote1: (u64, Payload, ValidatorSetId, &Keyring), + vote2: (u64, Payload, ValidatorSetId, &Keyring), ) -> EquivocationProof { let signed_vote = |block_number: u64, payload: Payload, validator_set_id: ValidatorSetId, - keyring: &Keyring| { + keyring: &Keyring| { let commitment = Commitment { validator_set_id, block_number, payload }; - let signature = >::sign( - *keyring, + let signature = keyring.clone().sign( &commitment.encode(), ); VoteMessage { commitment, - id: >::public(*keyring), + id: keyring.clone().public(), signature, } }; From 7454b6d13e7f5c5615da4c97b4890f7ff298bed7 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 25 Jan 2024 09:19:23 -0500 Subject: [PATCH 50/78] Compatiblize all client/beefy tests to Keyring enum model --- .../beefy/src/communication/gossip.rs | 10 +- .../consensus/beefy/src/justification.rs | 9 +- .../client/consensus/beefy/src/keystore.rs | 84 +++++++------- substrate/client/consensus/beefy/src/round.rs | 106 ++++++++---------- substrate/client/consensus/beefy/src/tests.rs | 18 +-- .../client/consensus/beefy/src/worker.rs | 8 +- .../consensus/beefy/src/test_utils.rs | 28 ++--- 7 files changed, 126 insertions(+), 137 deletions(-) diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index eb18f1f4034b..03c490fef745 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -481,7 +481,7 @@ pub(crate) mod tests { use sc_network_test::Block; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - ecdsa_crypto::Signature, known_payloads, Commitment, test_utils::GenericKeyring, test_utils::Keyring, MmrRootHash, + ecdsa_crypto::Signature, known_payloads, Commitment, test_utils::Keyring, MmrRootHash, Payload, SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -503,12 +503,12 @@ pub(crate) mod tests { } } - pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { + pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store = MemoryKeystore::new(); store .ecdsa_generate_new( BEEFY_KEY_TYPE, - Some(&>::to_seed(*who)), + Some(&who.to_seed()), ) .unwrap(); let beefy_keystore: BeefyKeystore = Some(store.into()).into(); @@ -540,7 +540,7 @@ pub(crate) mod tests { .iter() .map(|validator: &AuthorityId| { Some(sign_commitment( - &>::from_public(validator).unwrap(), + &Keyring::::from_public(validator).unwrap(), &commitment, )) }) @@ -551,7 +551,7 @@ pub(crate) mod tests { #[test] fn should_validate_messages() { - let keys = vec![Keyring::Alice.public()]; + let keys = vec![Keyring::::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); let (gv, mut report_stream) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 00a0e20c1724..d49b8abf4cf8 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -93,7 +93,7 @@ pub(crate) fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use sp_consensus_beefy::{ - known_payloads, Commitment, test_utils::GenericKeyring, test_utils::Keyring, Payload, SignedCommitment, + known_payloads, Commitment, test_utils::Keyring, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; @@ -104,7 +104,7 @@ pub(crate) mod tests { pub(crate) fn new_finality_proof( block_num: NumberFor, validator_set: &ValidatorSet, - keys: &[Keyring], + keys: &[Keyring], ) -> BeefyVersionedFinalityProof { let commitment = Commitment { payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), @@ -114,7 +114,7 @@ pub(crate) mod tests { let message = commitment.encode(); let signatures = keys .iter() - .map(|key| Some(>::sign(*key, &message))) + .map(|key| Some(key.sign(&message))) .collect(); VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }) } @@ -178,8 +178,7 @@ pub(crate) mod tests { }; // change a signature to a different key *bad_signed_commitment.signatures.first_mut().unwrap() = - Some(>::sign( - Keyring::Dave, + Some(Keyring::::Dave.sign( &bad_signed_commitment.commitment.encode(), )); match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 6066aa5c6451..eb79a385bd59 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -213,7 +213,7 @@ where #[cfg(test)] pub mod tests { - use sp_consensus_beefy::{ecdsa_crypto, test_utils::BeefySignerAuthority, test_utils::GenericKeyring, test_utils::Keyring}; + use sp_consensus_beefy::{ecdsa_crypto, test_utils::{BeefySignerAuthority, Keyring, generate_in_store}}; use sp_core::Pair as PairT; use sp_keystore::testing::MemoryKeystore; @@ -233,17 +233,17 @@ pub mod tests { ::Pair: BeefySignerAuthority, { let msg = b"I am Alice!"; - let sig = >::sign(Keyring::Alice, b"I am Alice!"); + let sig = Keyring::::Alice.sign(b"I am Alice!"); assert!(>::verify( - &>::public(Keyring::Alice), + &Keyring::Alice.public(), &sig, &msg.as_slice(), )); // different public key -> fail assert!(!>::verify( - &>::public(Keyring::Bob), + &Keyring::Bob.public(), &sig, &msg.as_slice(), )); @@ -252,7 +252,7 @@ pub mod tests { // different msg -> fail assert!(!>::verify( - &>::public(Keyring::Alice), + &Keyring::Alice.public(), &sig, &msg.as_slice(), )); @@ -277,53 +277,53 @@ pub mod tests { Send + Sync + From<<::Pair as AppCrypto>::Signature>, ::Pair: BeefySignerAuthority, { - let want = >::KeyPair::from_string("//Alice", None) + let want = ::Pair::from_string("//Alice", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Alice).to_raw_vec(); + let got = Keyring::::Alice.pair().to_raw_vec(); assert_eq!(want, got); - let want = >::KeyPair::from_string("//Bob", None) + let want = ::Pair::from_string("//Bob", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Bob).to_raw_vec(); + let got = Keyring::::Bob.pair().to_raw_vec(); assert_eq!(want, got); let want = - >::KeyPair::from_string("//Charlie", None) + ::Pair::from_string("//Charlie", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Charlie).to_raw_vec(); + let got = Keyring::::Charlie.pair().to_raw_vec(); assert_eq!(want, got); - let want = >::KeyPair::from_string("//Dave", None) + let want = ::Pair::from_string("//Dave", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Dave).to_raw_vec(); + let got = Keyring::::Dave.pair().to_raw_vec(); assert_eq!(want, got); - let want = >::KeyPair::from_string("//Eve", None) + let want = ::Pair::from_string("//Eve", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Eve).to_raw_vec(); + let got = Keyring::::Eve.pair().to_raw_vec(); assert_eq!(want, got); - let want = >::KeyPair::from_string("//Ferdie", None) + let want = ::Pair::from_string("//Ferdie", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Ferdie).to_raw_vec(); + let got = Keyring::::Ferdie.pair().to_raw_vec(); assert_eq!(want, got); - let want = >::KeyPair::from_string("//One", None) + let want = ::Pair::from_string("//One", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::One).to_raw_vec(); + let got = Keyring::::One.pair().to_raw_vec(); assert_eq!(want, got); - let want = >::KeyPair::from_string("//Two", None) + let want = ::Pair::from_string("//Two", None) .expect("Pair failed") .to_raw_vec(); - let got = >::pair(Keyring::Two).to_raw_vec(); + let got = Keyring::::Two.pair().to_raw_vec(); assert_eq!(want, got); } @@ -348,16 +348,16 @@ pub mod tests { { let store = keystore(); - >::generate_in_store( + generate_in_store::( store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice), ); - let alice = >::public(Keyring::Alice); + let alice = Keyring::::Alice.public(); - let bob = >::public(Keyring::Bob); - let charlie = >::public(Keyring::Charlie); + let bob = Keyring::Bob.public(); + let charlie = Keyring::Charlie.public(); let beefy_store: BeefyKeystore = Some(store).into(); @@ -396,20 +396,20 @@ pub mod tests { { let store = keystore(); - >::generate_in_store( + generate_in_store::( store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice), ); - let alice = >::public(Keyring::Alice); + let alice = Keyring::Alice.public(); let store: BeefyKeystore = Some(store).into(); let msg = b"are you involved or commited?"; let sig1 = store.sign(&alice, msg).unwrap(); - let sig2 = >::sign(Keyring::Alice, msg); + let sig2 = Keyring::::Alice.sign( msg); assert_eq!(sig1, sig2); } @@ -436,7 +436,7 @@ pub mod tests { { let store = keystore(); - >::generate_in_store( + generate_in_store::( store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Bob), @@ -444,7 +444,7 @@ pub mod tests { let store: BeefyKeystore = Some(store).into(); - let alice = >::public(Keyring::Alice); + let alice = Keyring::Alice.public(); let msg = b"are you involved or commited?"; let sig = store.sign(&alice, msg).err().unwrap(); @@ -486,7 +486,7 @@ pub mod tests { { let store = keystore(); - >::generate_in_store( + generate_in_store::( store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice), @@ -494,7 +494,7 @@ pub mod tests { let store: BeefyKeystore = Some(store).into(); - let alice = >::public(Keyring::Alice); + let alice = Keyring::Alice.public(); // `msg` and `sig` match let msg = b"are you involved or commited?"; @@ -533,46 +533,46 @@ pub mod tests { let store = keystore(); // test keys - let _ = >::generate_in_store( + let _ = generate_in_store::( store.clone(), TEST_TYPE, Some(Keyring::Alice), ); - let _ = >::generate_in_store( + let _ = generate_in_store::( store.clone(), TEST_TYPE, Some(Keyring::Bob), ); // BEEFY keys - let _ = >::generate_in_store( + let _ = generate_in_store::( store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Dave), ); - let _ = >::generate_in_store( + let _ = generate_in_store::( store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Eve), ); - let _ = >::generate_in_store( + let _ = generate_in_store::( store.clone(), TEST_TYPE, None, ); - let _ = >::generate_in_store( + let _ = generate_in_store::( store.clone(), TEST_TYPE, None, ); - let key1 = >::generate_in_store( + let key1 = generate_in_store::( store.clone(), BEEFY_KEY_TYPE, None, ); - let key2 = >::generate_in_store( + let key2 = generate_in_store::( store.clone(), BEEFY_KEY_TYPE, None, @@ -583,8 +583,8 @@ pub mod tests { let keys = store.public_keys().ok().unwrap(); assert!(keys.len() == 4); - assert!(keys.contains(&>::public(Keyring::Dave))); - assert!(keys.contains(&>::public(Keyring::Eve))); + assert!(keys.contains(&Keyring::Dave.public())); + assert!(keys.contains(&Keyring::Eve.public())); assert!(keys.contains(&key1)); assert!(keys.contains(&key2)); } diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 29f5f10a4444..9ff9bff3cbb8 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -203,7 +203,7 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, test_utils::GenericKeyring, test_utils::Keyring, + known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, test_utils::Keyring, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; @@ -223,8 +223,8 @@ mod tests { fn round_tracker() { let mut rt = RoundTracker::default(); let bob_vote = ( - >::public(Keyring::Bob), - >::sign(Keyring::Bob, b"I am committed"), + Keyring::Bob.public(), + Keyring::::Bob.sign( b"I am committed"), ); let threshold = 2; @@ -237,8 +237,8 @@ mod tests { assert!(!rt.is_done(threshold)); let alice_vote = ( - >::public(Keyring::Alice), - >::sign(Keyring::Alice, b"I am committed"), + Keyring::Alice.public(), + Keyring::::Alice.sign( b"I am committed"), ); // adding new vote (self vote this time) allowed assert!(rt.add_vote(alice_vote)); @@ -263,9 +263,9 @@ mod tests { let validators = ValidatorSet::::new( vec![ - >::public(Keyring::Alice), - >::public(Keyring::Bob), - >::public(Keyring::Charlie), + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), ], 42, ) @@ -278,9 +278,9 @@ mod tests { assert_eq!(1, rounds.session_start()); assert_eq!( &vec![ - >::public(Keyring::Alice), - >::public(Keyring::Bob), - >::public(Keyring::Charlie) + Keyring::::Alice.public(), + Keyring::::Bob.public(), + Keyring::::Charlie.public() ], rounds.validators() ); @@ -292,9 +292,9 @@ mod tests { let validators = ValidatorSet::::new( vec![ - >::public(Keyring::Alice), - >::public(Keyring::Bob), - >::public(Keyring::Charlie), + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), Keyring::Eve.public(), ], Default::default(), @@ -309,10 +309,9 @@ mod tests { let block_number = 1; let commitment = Commitment { block_number, payload, validator_set_id }; let mut vote = VoteMessage { - id: >::public(Keyring::Alice), + id: Keyring::Alice.public(), commitment: commitment.clone(), - signature: >::sign( - Keyring::Alice, + signature: Keyring::::Alice.sign( b"I am committed", ), }; @@ -322,37 +321,34 @@ mod tests { // double voting (same vote), ok, no effect assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - vote.id = >::public(Keyring::Dave); + vote.id = Keyring::Dave.public(); vote.signature = - >::sign(Keyring::Dave, b"I am committed"); + Keyring::::Dave.sign( b"I am committed"); // invalid vote (Dave is not a validator) assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Invalid); - vote.id = >::public(Keyring::Bob); + vote.id = Keyring::Bob.public(); vote.signature = - >::sign(Keyring::Bob, b"I am committed"); + Keyring::::Bob.sign( b"I am committed"); // add 2nd good vote assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - vote.id = >::public(Keyring::Charlie); + vote.id = Keyring::Charlie.public(); vote.signature = - >::sign(Keyring::Charlie, b"I am committed"); + Keyring::::Charlie.sign(b"I am committed"); // add 3rd good vote -> round concluded -> signatures present assert_eq!( rounds.add_vote(vote.clone()), VoteImportResult::RoundConcluded(SignedCommitment { commitment, signatures: vec![ - Some(>::sign( - Keyring::Alice, + Some(Keyring::::Alice.sign( b"I am committed" )), - Some(>::sign( - Keyring::Bob, + Some(Keyring::::Bob.sign( b"I am committed" )), - Some(>::sign( - Keyring::Charlie, + Some(Keyring::::Charlie.sign( b"I am committed" )), None, @@ -361,9 +357,9 @@ mod tests { ); rounds.conclude(block_number); - vote.id = >::public(Keyring::Eve); + vote.id = Keyring::Eve.public(); vote.signature = - >::sign(Keyring::Eve, b"I am committed"); + Keyring::::Eve.sign(b"I am committed"); // Eve is a validator, but round was concluded, adding vote disallowed assert_eq!(rounds.add_vote(vote), VoteImportResult::Stale); } @@ -374,9 +370,9 @@ mod tests { let validators = ValidatorSet::::new( vec![ - >::public(Keyring::Alice), - >::public(Keyring::Bob), - >::public(Keyring::Charlie), + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), ], 42, ) @@ -392,10 +388,9 @@ mod tests { let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); let commitment = Commitment { block_number, payload, validator_set_id }; let mut vote = VoteMessage { - id: >::public(Keyring::Alice), + id: Keyring::Alice.public(), commitment, - signature: >::sign( - Keyring::Alice, + signature: Keyring::::Alice.sign( b"I am committed", ), }; @@ -427,9 +422,9 @@ mod tests { let validators = ValidatorSet::::new( vec![ - >::public(Keyring::Alice), - >::public(Keyring::Bob), - >::public(Keyring::Charlie), + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), ], Default::default(), ) @@ -442,34 +437,30 @@ mod tests { let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); let commitment = Commitment { block_number: 1, payload, validator_set_id }; let mut alice_vote = VoteMessage { - id: >::public(Keyring::Alice), + id: Keyring::Alice.public(), commitment: commitment.clone(), - signature: >::sign( - Keyring::Alice, + signature: Keyring::::Alice.sign( b"I am committed", ), }; let mut bob_vote = VoteMessage { - id: >::public(Keyring::Bob), + id: Keyring::Bob.public(), commitment: commitment.clone(), - signature: >::sign( - Keyring::Bob, + signature: Keyring::::Bob.sign( b"I am committed", ), }; let mut charlie_vote = VoteMessage { - id: >::public(Keyring::Charlie), + id: Keyring::Charlie.public(), commitment, - signature: >::sign( - Keyring::Charlie, + signature: Keyring::::Charlie.sign( b"I am committed", ), }; let expected_signatures = vec![ - Some(>::sign(Keyring::Alice, b"I am committed")), - Some(>::sign(Keyring::Bob, b"I am committed")), - Some(>::sign( - Keyring::Charlie, + Some(Keyring::::Alice.sign( b"I am committed")), + Some(Keyring::::Bob.sign( b"I am committed")), + Some(Keyring::::Charlie.sign( b"I am committed", )), ]; @@ -518,8 +509,8 @@ mod tests { let validators = ValidatorSet::::new( vec![ - >::public(Keyring::Alice), - >::public(Keyring::Bob), + Keyring::Alice.public(), + Keyring::Bob.public(), ], Default::default(), ) @@ -534,10 +525,9 @@ mod tests { let commitment2 = Commitment { block_number: 1, payload: payload2, validator_set_id }; let alice_vote1 = VoteMessage { - id: >::public(Keyring::Alice), + id: Keyring::Alice.public(), commitment: commitment1, - signature: >::sign( - Keyring::Alice, + signature: Keyring::::Alice.sign( b"I am committed", ), }; diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 85b5de238de8..735e261340a4 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -55,7 +55,7 @@ use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId, Signature}, known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, test_utils::GenericKeyring, test_utils::Keyring as BeefyKeyring, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, test_utils::Keyring as BeefyKeyring, MmrRootHash, OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; @@ -347,18 +347,18 @@ fn add_auth_change_digest(builder: &mut impl BlockBuilderExt, new_auth_set: Beef .unwrap(); } -pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { +pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { keys.iter() - .map(|&key| >::public(key).into()) + .map(|key| key.public().into()) .collect() } -pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr { +pub(crate) fn create_beefy_keystore(authority: &BeefyKeyring) -> KeystorePtr { let keystore = MemoryKeystore::new(); keystore .ecdsa_generate_new( BEEFY_KEY_TYPE, - Some(&>::to_seed(authority)), + Some(&authority.to_seed()), ) .expect("Creates authority key"); keystore.into() @@ -389,7 +389,7 @@ async fn voter_init_setup( // Spawns beefy voters. Returns a future to spawn on the runtime. fn initialize_beefy( net: &mut BeefyTestNet, - peers: Vec<(usize, &BeefyKeyring, Arc)>, + peers: Vec<(usize, &BeefyKeyring, Arc)>, min_block_delta: u32, ) -> impl Future where @@ -409,7 +409,7 @@ where for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; - let keystore = create_beefy_keystore(*key); + let keystore = create_beefy_keystore(key); let (_, _, peer_data) = net.make_block_import(peer.client().clone()); let PeerData { beefy_rpc_links, beefy_voter_links, .. } = peer_data; @@ -467,7 +467,7 @@ async fn run_for(duration: Duration, net: &Arc>) { pub(crate) fn get_beefy_streams( net: &mut BeefyTestNet, // peer index and key - peers: impl Iterator, + peers: impl Iterator)>, ) -> (Vec>, Vec>>) { let mut best_block_streams = Vec::new(); @@ -565,7 +565,7 @@ async fn streams_empty_after_timeout( async fn finalize_block_and_wait_for_beefy( net: &Arc>, // peer index and key - peers: impl Iterator + Clone, + peers: impl Iterator)> + Clone, finalize_target: &H256, expected_beefy: &[u64], ) { diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 49f888cf011d..c6cc51f9914f 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -1077,7 +1077,7 @@ pub(crate) mod tests { use sp_blockchain::Backend as BlockchainBackendT; use sp_consensus_beefy::{ test_utils::generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, - mmr::MmrRootProvider, test_utils::GenericKeyring, test_utils::Keyring, Payload, SignedCommitment, + mmr::MmrRootProvider, test_utils::Keyring, Payload, SignedCommitment, }; use sp_runtime::traits::{Header as HeaderT, One}; use substrate_test_runtime_client::{ @@ -1111,7 +1111,7 @@ pub(crate) mod tests { fn create_beefy_worker( peer: &mut BeefyPeer, - key: &Keyring, + key: &Keyring, min_block_delta: u32, genesis_validator_set: ValidatorSet, ) -> BeefyWorker< @@ -1121,7 +1121,7 @@ pub(crate) mod tests { TestApi, Arc>, > { - let keystore = create_beefy_keystore(*key); + let keystore = create_beefy_keystore(key); let (to_rpc_justif_sender, from_voter_justif_stream) = BeefyVersionedFinalityProofStream::::channel(); @@ -1659,7 +1659,7 @@ pub(crate) mod tests { // now let's try with a bad proof let mut bad_proof = good_proof.clone(); - bad_proof.first.id = >::public(Keyring::Charlie); + bad_proof.first.id = Keyring::Charlie.public(); // bad proofs are simply ignored assert_eq!(worker.report_equivocation(bad_proof), Ok(())); // verify nothing reported to runtime diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index d70a4d1dbcab..802390b4d685 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -86,7 +86,7 @@ where /// Generate key pair in the given store using the provided seed -fn generate_in_store( +pub fn generate_in_store( store: KeystorePtr, key_type: sp_application_crypto::KeyTypeId, owner: Option>, @@ -138,13 +138,13 @@ where Send + Sync + From<<::Pair as AppCrypto>::Signature>, { /// Sign `msg`. - fn sign(self, msg: &[u8]) -> ::Signature { - let key_pair: ::Pair = self.clone().pair(); + pub fn sign(&self, msg: &[u8]) -> ::Signature { + let key_pair: ::Pair = self.pair(); key_pair.sign_with_hasher(&msg).into() } /// Return key pair. - fn pair(self) -> ::Pair { + pub fn pair(&self) -> ::Pair { ::Pair::from_string( self.to_seed().as_str(), None, @@ -154,37 +154,37 @@ where } /// Return public key. - fn public(self) -> AuthorityId { - self.clone().pair().public().into() + pub fn public(&self) -> AuthorityId { + self.pair().public().into() } /// Return seed string. - fn to_seed(self) -> String { + pub fn to_seed(&self) -> String { format!("//{}", self) } /// Get Keyring from public key. - fn from_public(who: &AuthorityId) -> Option> { - Self::iter().find(|k| k.clone().public() == *who) + pub fn from_public(who: &AuthorityId) -> Option> { + Self::iter().find(|k| k.public() == *who) } } lazy_static::lazy_static! { static ref PRIVATE_KEYS: HashMap, ecdsa_crypto::Pair> = - Keyring::iter().map(|i| (i.clone(), i.clone().pair())).collect(); + Keyring::iter().map(|i| (i.clone(), i.pair())).collect(); static ref PUBLIC_KEYS: HashMap, ecdsa_crypto::Public> = PRIVATE_KEYS.iter().map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))).collect(); } impl From> for ecdsa_crypto::Pair { fn from(k: Keyring) -> Self { - k.clone().pair() + k.pair() } } impl From> for ecdsa::Pair { fn from(k: Keyring) -> Self { - k.clone().pair().into() + k.pair().into() } } @@ -204,12 +204,12 @@ pub fn generate_equivocation_proof( validator_set_id: ValidatorSetId, keyring: &Keyring| { let commitment = Commitment { validator_set_id, block_number, payload }; - let signature = keyring.clone().sign( + let signature = keyring.sign( &commitment.encode(), ); VoteMessage { commitment, - id: keyring.clone().public(), + id: keyring.public(), signature, } }; From ce9ec4918a7f0f4eeb2560e30142a9545a54ba9a Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 13 Feb 2024 16:57:50 -0500 Subject: [PATCH 51/78] Fix compile errors after merge with master --- Cargo.lock | 12 ++++++ substrate/client/consensus/beefy/Cargo.toml | 2 +- .../client/consensus/beefy/src/aux_schema.rs | 7 ++-- substrate/client/consensus/beefy/src/error.rs | 7 ++++ .../client/consensus/beefy/src/keystore.rs | 5 +-- substrate/client/consensus/beefy/src/lib.rs | 2 +- .../client/consensus/beefy/src/worker.rs | 37 ++++++++++--------- .../primitives/consensus/beefy/src/lib.rs | 2 +- 8 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5b272d11756..8ec144c65eaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15705,6 +15705,7 @@ dependencies = [ "sc-network-test", "sc-utils", "serde", + "smart-default", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -17443,6 +17444,17 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +[[package]] +name = "smart-default" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "smol" version = "1.3.0" diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index e76d9ec826e3..3b2f3afeb693 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -41,7 +41,7 @@ sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } tokio = "1.22.0" - +smart-default = "0.6.0" [dev-dependencies] serde = "1.0.195" diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 1958494cf249..021f8cc6620c 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -50,14 +50,13 @@ where { trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); AuxStore::insert_aux(backend, &[(WORKER_STATE_KEY, state.encode().as_slice())], &[]) - .map_err(|e| Error::Backend(e.to_string())) } -fn load_decode(backend: &BE, key: &[u8]) -> Result, Error> { - match backend.get_aux(key).map_err(|e| Error::Backend(e.to_string()))? { +fn load_decode(backend: &BE, key: &[u8]) -> ClientResult> { + match backend.get_aux(key)? { None => Ok(None), Some(t) => T::decode(&mut &t[..]) - .map_err(|e| Error::Backend(format!("BEEFY DB is corrupted: {}", e))) + .map_err(|e| ClientError::Backend(format!("BEEFY DB is corrupted: {}", e))) .map(Some), } } diff --git a/substrate/client/consensus/beefy/src/error.rs b/substrate/client/consensus/beefy/src/error.rs index b4773f940193..9cd09cb99332 100644 --- a/substrate/client/consensus/beefy/src/error.rs +++ b/substrate/client/consensus/beefy/src/error.rs @@ -20,6 +20,7 @@ //! //! Used for BEEFY gadget internal error handling only +use sp_blockchain::Error as ClientError; use std::fmt::Debug; #[derive(Debug, thiserror::Error)] @@ -48,6 +49,12 @@ pub enum Error { VotesGossipStreamTerminated, } +impl From for Error { + fn from(e: ClientError) -> Self { + Self::Backend(e.to_string()) + } +} + #[cfg(test)] impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 62040b9912ed..a1997aa38cad 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . use codec::Decode; +use log::warn; use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; #[cfg(feature = "bls-experimental")] @@ -25,14 +26,10 @@ use sp_core::{ecdsa, keccak_256}; use sp_keystore::KeystorePtr; use std::marker::PhantomData; -use codec::Decode; -use log::warn; - use sp_consensus_beefy::{AuthorityIdBound, BeefyAuthorityId, BeefySignatureHasher}; #[cfg(feature = "bls-experimental")] use sp_consensus_beefy::ecdsa_bls_crypto; -use std::marker::PhantomData; use crate::{error, LOG_TARGET}; diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index e5836bcc095a..0d218500ee83 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -490,7 +490,7 @@ where if let Ok(Some(active)) = runtime.runtime_api().validator_set(header.hash()) { return Ok(active) } else { - match worker::find_authorities_change::(&header) { + match worker::find_authorities_change::(&header) { Some(active) => return Ok(active), // Move up the chain. Ultimately we'll get it from chain genesis state, or error out // there. diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index c302b272e022..682b05d529b4 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -42,7 +42,7 @@ use sc_network_gossip::GossipEngine; use sc_utils::{mpsc::TracingUnboundedReceiver, notification::NotificationReceiver}; use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; -use sp_blockchain::Backend as BlockchainBackend; +use sp_blockchain::{Backend as BlockchainBackend, Error as ClientError, Result as ClientResult}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, @@ -62,8 +62,6 @@ use std::{ sync::Arc, }; -use sp_std::marker::PhantomData; - /// Bound for the number of pending justifications - use 2400 - the max number /// of justifications possible in a single session. const MAX_BUFFERED_JUSTIFICATIONS: usize = 2400; @@ -394,7 +392,7 @@ where beefy_genesis: NumberFor, best_grandpa: ::Header, min_block_delta: u32, - ) -> Result, Error> { + ) -> Result, Error> { let blockchain = self.backend.blockchain(); let beefy_genesis = self @@ -467,7 +465,7 @@ where .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))? } - if let Some(active) = find_authorities_change::(&header) { + if let Some(active) = find_authorities_change::(&header) { info!( target: LOG_TARGET, "🥩 Marking block {:?} as BEEFY Mandatory.", @@ -490,7 +488,7 @@ where beefy_genesis: NumberFor, best_grandpa: ::Header, min_block_delta: u32, - ) -> Result, Error> { + ) -> Result, Error> { // Initialize voter state from AUX DB if compatible. if let Some(mut state) = crate::aux_schema::load_persistent(self.backend.as_ref())? // Verify state pallet genesis matches runtime. @@ -507,7 +505,7 @@ where let mut header = best_grandpa.clone(); while *header.number() > state.best_beefy() { if state.voting_oracle.can_add_session(*header.number()) { - if let Some(active) = find_authorities_change::(&header) { + if let Some(active) = find_authorities_change::(&header) { new_sessions.push((active, *header.number())); } } @@ -563,7 +561,7 @@ where /// Handle session changes by starting new voting round for mandatory blocks. fn init_session_at( &mut self, - persisted_state: &mut PersistedState, + persisted_state: &mut PersistedState, validator_set: ValidatorSet, new_session_start: NumberFor, ) { @@ -602,28 +600,31 @@ where } /// A BEEFY worker/voter that follows the BEEFY protocol -pub(crate) struct BeefyWorker { - pub base: BeefyWorkerBase, +pub(crate) struct BeefyWorker +where + ::Signature: Send + Sync, +{ + pub base: BeefyWorkerBase, // utils pub payload_provider: P, pub sync: Arc, // communication (created once, but returned and reused if worker is restarted/reinitialized) - pub comms: BeefyComms, + pub comms: BeefyComms, // channels /// Links between the block importer, the background voter and the RPC layer. - pub links: BeefyVoterLinks, + pub links: BeefyVoterLinks, // voter state /// Buffer holding justifications for future processing. - pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. - pub persisted_state: PersistedState, + pub persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, @@ -631,12 +632,14 @@ where S: SyncOracle, R: ProvideRuntimeApi, R::Api: BeefyApi, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { fn best_grandpa_block(&self) -> NumberFor { *self.persisted_state.voting_oracle.best_grandpa_block_header.number() } - fn voting_oracle(&self) -> &VoterOracle { + fn voting_oracle(&self) -> &VoterOracle { &self.persisted_state.voting_oracle } @@ -1340,7 +1343,7 @@ pub(crate) mod tests { Backend, }; - impl PersistedState { + impl PersistedState { pub fn voting_oracle(&self) -> &VoterOracle { &self.voting_oracle } diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 277fb04db527..39cb2c23a815 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -74,7 +74,7 @@ pub trait AuthorityIdBound: Codec + Debug + Clone - //+ Ord + + Ord //+ Sync //+ Send + AsRef<[u8]> From db4ee57a7139c770100749e943dac725bf8b3264 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 19 Feb 2024 12:44:23 -0500 Subject: [PATCH 52/78] Resolve all errors in BEEFY client test and pass them. --- .../client/consensus/beefy/src/aux_schema.rs | 5 +- .../beefy/src/communication/gossip.rs | 73 +++++++++++++------ .../consensus/beefy/src/justification.rs | 50 ++++++++++--- .../client/consensus/beefy/src/keystore.rs | 7 -- substrate/client/consensus/beefy/src/round.rs | 18 ++--- substrate/client/consensus/beefy/src/tests.rs | 44 ++++++----- .../client/consensus/beefy/src/worker.rs | 38 +++++----- 7 files changed, 148 insertions(+), 87 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 021f8cc6620c..531eacf98cc5 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -90,6 +90,7 @@ pub(crate) mod tests { use super::*; use crate::tests::BeefyTestNet; use sc_network_test::TestNetFactory; + use sp_consensus_beefy::ecdsa_crypto; // also used in tests.rs pub fn verify_persisted_version>(backend: &BE) -> bool { @@ -103,7 +104,7 @@ pub(crate) mod tests { let backend = net.peer(0).client().as_backend(); // version not available in db -> None - assert_eq!(load_persistent(&*backend).unwrap(), None); + assert_eq!(load_persistent::<_, _, ecdsa_crypto::AuthorityId>(&*backend).unwrap(), None); // populate version in db write_current_version(&*backend).unwrap(); @@ -111,7 +112,7 @@ pub(crate) mod tests { assert_eq!(load_decode(&*backend, VERSION_KEY).unwrap(), Some(CURRENT_VERSION)); // version is available in db but state isn't -> None - assert_eq!(load_persistent(&*backend).unwrap(), None); + assert_eq!(load_persistent::<_, _, ecdsa_crypto::AuthorityId>(&*backend).unwrap(), None); // full `PersistedState` load is tested in `tests.rs`. } diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 641467f47ccc..42fd0dc514f6 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -560,7 +560,7 @@ pub(crate) mod tests { pub fn dummy_proof( block_number: u64, validator_set: &ValidatorSet, - ) -> BeefyVersionedFinalityProof { + ) -> BeefyVersionedFinalityProof { let payload = Payload::from_single_entry( known_payloads::MMR_ROOT_ID, MmrRootHash::default().encode(), @@ -577,7 +577,10 @@ pub(crate) mod tests { }) .collect(); - BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment, signatures }) + BeefyVersionedFinalityProof::::V1(SignedCommitment { + commitment, + signatures, + }) } #[test] @@ -585,8 +588,9 @@ pub(crate) mod tests { let keys = vec![Keyring::::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let (gv, mut report_stream) = - GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let (gv, mut report_stream) = GossipValidator::::new( + Arc::new(Mutex::new(KnownPeers::new())), + ); let sender = PeerId::random(); let mut context = TestContext; @@ -604,7 +608,8 @@ pub(crate) mod tests { // verify votes validation let vote = dummy_vote(3); - let encoded = GossipMessage::::Vote(vote.clone()).encode(); + let encoded = + GossipMessage::::Vote(vote.clone()).encode(); // filter not initialized let res = gv.validate(&mut context, &sender, &encoded); @@ -622,7 +627,7 @@ pub(crate) mod tests { // reject vote, voter not in validator set let mut bad_vote = vote.clone(); bad_vote.id = Keyring::Bob.public(); - let bad_vote = GossipMessage::::Vote(bad_vote).encode(); + let bad_vote = GossipMessage::::Vote(bad_vote).encode(); let res = gv.validate(&mut context, &sender, &bad_vote); assert!(matches!(res, ValidationResult::Discard)); expected_report.cost_benefit = cost::UNKNOWN_VOTER; @@ -652,7 +657,8 @@ pub(crate) mod tests { // reject old proof let proof = dummy_proof(5, &validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); expected_report.cost_benefit = cost::OUTDATED_MESSAGE; @@ -660,7 +666,8 @@ pub(crate) mod tests { // accept next proof with good set_id let proof = dummy_proof(7, &validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); expected_report.cost_benefit = benefit::VALIDATED_PROOF; @@ -668,7 +675,8 @@ pub(crate) mod tests { // accept future proof with good set_id let proof = dummy_proof(20, &validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); expected_report.cost_benefit = benefit::VALIDATED_PROOF; @@ -677,7 +685,8 @@ pub(crate) mod tests { // reject proof, future set_id let bad_validator_set = ValidatorSet::::new(keys, 1).unwrap(); let proof = dummy_proof(20, &bad_validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); expected_report.cost_benefit = cost::FUTURE_MESSAGE; @@ -687,7 +696,8 @@ pub(crate) mod tests { let bad_validator_set = ValidatorSet::::new(vec![Keyring::Bob.public()], 0).unwrap(); let proof = dummy_proof(21, &bad_validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); expected_report.cost_benefit = cost::INVALID_PROOF; @@ -700,7 +710,9 @@ pub(crate) mod tests { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let (gv, _) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let (gv, _) = GossipValidator::::new(Arc::new( + Mutex::new(KnownPeers::new()), + )); gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let topic = Default::default(); @@ -717,59 +729,70 @@ pub(crate) mod tests { // inactive round 1 -> expired let vote = dummy_vote(1); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); + let mut encoded_vote = + GossipMessage::::Vote(vote).encode(); assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(expired(topic, &mut encoded_vote)); let proof = dummy_proof(1, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let mut encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); assert!(!allowed(&sender, intent, &topic, &mut encoded_proof)); assert!(expired(topic, &mut encoded_proof)); // active round 2 -> !expired - concluded but still gossiped let vote = dummy_vote(2); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); + let mut encoded_vote = + GossipMessage::::Vote(vote).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(!expired(topic, &mut encoded_vote)); let proof = dummy_proof(2, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let mut encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); assert!(!expired(topic, &mut encoded_proof)); // using wrong set_id -> !allowed, expired let bad_validator_set = ValidatorSet::::new(keys.clone(), 1).unwrap(); let proof = dummy_proof(2, &bad_validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let mut encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); assert!(!allowed(&sender, intent, &topic, &mut encoded_proof)); assert!(expired(topic, &mut encoded_proof)); // in progress round 3 -> !expired let vote = dummy_vote(3); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); + let mut encoded_vote = + GossipMessage::::Vote(vote).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(!expired(topic, &mut encoded_vote)); let proof = dummy_proof(3, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let mut encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); assert!(!expired(topic, &mut encoded_proof)); // unseen round 4 -> !expired let vote = dummy_vote(4); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); + let mut encoded_vote = + GossipMessage::::Vote(vote).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(!expired(topic, &mut encoded_vote)); let proof = dummy_proof(4, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let mut encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); assert!(!expired(topic, &mut encoded_proof)); // future round 11 -> expired let vote = dummy_vote(11); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); + let mut encoded_vote = + GossipMessage::::Vote(vote).encode(); assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(expired(topic, &mut encoded_vote)); // future proofs allowed while same set_id -> allowed let proof = dummy_proof(11, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let mut encoded_proof = + GossipMessage::::FinalityProof(proof).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); assert!(!expired(topic, &mut encoded_proof)); } @@ -779,7 +802,9 @@ pub(crate) mod tests { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let (gv, _) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let (gv, _) = GossipValidator::::new(Arc::new( + Mutex::new(KnownPeers::new()), + )); gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 1f819962fba1..29ede7a0cd25 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -114,7 +114,7 @@ pub(crate) mod tests { block_num: NumberFor, validator_set: &ValidatorSet, keys: &[Keyring], - ) -> BeefyVersionedFinalityProof { + ) -> BeefyVersionedFinalityProof { let commitment = Commitment { payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: block_num, @@ -136,11 +136,20 @@ pub(crate) mod tests { let good_proof = proof.clone().into(); // should verify successfully - verify_with_validator_set::(block_num, &validator_set, &good_proof).unwrap(); + verify_with_validator_set::( + block_num, + &validator_set, + &good_proof, + ) + .unwrap(); // wrong block number -> should fail verification let good_proof = proof.clone().into(); - match verify_with_validator_set::(block_num + 1, &validator_set, &good_proof) { + match verify_with_validator_set::( + block_num + 1, + &validator_set, + &good_proof, + ) { Err((ConsensusError::InvalidJustification, 0)) => (), e => assert!(false, "Got unexpected {:?}", e), }; @@ -148,7 +157,11 @@ pub(crate) mod tests { // wrong validator set id -> should fail verification let good_proof = proof.clone().into(); let other = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - match verify_with_validator_set::(block_num, &other, &good_proof) { + match verify_with_validator_set::( + block_num, + &other, + &good_proof, + ) { Err((ConsensusError::InvalidJustification, 0)) => (), e => assert!(false, "Got unexpected {:?}", e), }; @@ -160,7 +173,11 @@ pub(crate) mod tests { VersionedFinalityProof::V1(ref mut sc) => sc, }; bad_signed_commitment.signatures.pop().flatten().unwrap(); - match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + match verify_with_validator_set::( + block_num + 1, + &validator_set, + &bad_proof.into(), + ) { Err((ConsensusError::InvalidJustification, 0)) => (), e => assert!(false, "Got unexpected {:?}", e), }; @@ -172,7 +189,11 @@ pub(crate) mod tests { }; // remove a signature (but same length) *bad_signed_commitment.signatures.first_mut().unwrap() = None; - match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { + match verify_with_validator_set::( + block_num, + &validator_set, + &bad_proof.into(), + ) { Err((ConsensusError::InvalidJustification, 2)) => (), e => assert!(false, "Got unexpected {:?}", e), }; @@ -187,7 +208,11 @@ pub(crate) mod tests { Keyring::::Dave .sign(&bad_signed_commitment.commitment.encode()), ); - match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { + match verify_with_validator_set::( + block_num, + &validator_set, + &bad_proof.into(), + ) { Err((ConsensusError::InvalidJustification, 3)) => (), e => assert!(false, "Got unexpected {:?}", e), }; @@ -201,12 +226,17 @@ pub(crate) mod tests { // build valid justification let proof = new_finality_proof(block_num, &validator_set, keys); - let versioned_proof: BeefyVersionedFinalityProof = proof.into(); + let versioned_proof: BeefyVersionedFinalityProof = + proof.into(); let encoded = versioned_proof.encode(); // should successfully decode and verify - let verified = - decode_and_verify_finality_proof::(&encoded, block_num, &validator_set).unwrap(); + let verified = decode_and_verify_finality_proof::( + &encoded, + block_num, + &validator_set, + ) + .unwrap(); assert_eq!(verified, versioned_proof); } } diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index a1997aa38cad..fbfa0d67d2e3 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -380,13 +380,6 @@ pub mod tests { assert_eq!(id, alice); } - #[cfg(feature = "bls-experimental")] - #[test] - - fn authority_id_works_for_ecdsa() { - authority_id_works::(); - } - #[cfg(feature = "bls-experimental")] #[test] fn authority_id_works_for_ecdsa() { diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index ab0af8ee6276..f8f78a665b32 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -238,7 +238,7 @@ mod tests { use super::{threshold, Block as BlockT, RoundTracker, Rounds}; use crate::round::VoteImportResult; - impl Rounds + impl Rounds where B: BlockT, { @@ -249,9 +249,9 @@ mod tests { #[test] fn round_tracker() { - let mut rt = RoundTracker::default(); + let mut rt = RoundTracker::::default(); let bob_vote = ( - Keyring::Bob.public(), + Keyring::::Bob.public(), Keyring::::Bob.sign(b"I am committed"), ); let threshold = 2; @@ -265,7 +265,7 @@ mod tests { assert!(!rt.is_done(threshold)); let alice_vote = ( - Keyring::Alice.public(), + Keyring::::Alice.public(), Keyring::::Alice.sign(b"I am committed"), ); // adding new vote (self vote this time) allowed @@ -296,7 +296,7 @@ mod tests { .unwrap(); let session_start = 1u64.into(); - let rounds = Rounds::::new(session_start, validators); + let rounds = Rounds::::new(session_start, validators); assert_eq!(42, rounds.validator_set_id()); assert_eq!(1, rounds.session_start()); @@ -327,7 +327,7 @@ mod tests { let validator_set_id = validators.id(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); let block_number = 1; @@ -389,7 +389,7 @@ mod tests { // active rounds starts at block 10 let session_start = 10u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); // vote on round 9 let block_number = 9; @@ -434,7 +434,7 @@ mod tests { let validator_set_id = validators.id(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); let commitment = Commitment { block_number: 1, payload, validator_set_id }; @@ -508,7 +508,7 @@ mod tests { .unwrap(); let validator_set_id = validators.id(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![1, 1, 1, 1]); let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![2, 2, 2, 2]); diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 706628686b57..9b21cb2571ac 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -54,6 +54,7 @@ use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus::BlockOrigin; use sp_consensus_beefy::{ + ecdsa_crypto, ecdsa_crypto::{AuthorityId, Signature}, known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, @@ -107,7 +108,7 @@ impl BuildStorage for Genesis { #[derive(Default)] pub(crate) struct PeerData { - pub(crate) beefy_rpc_links: Mutex>>, + pub(crate) beefy_rpc_links: Mutex>>, pub(crate) beefy_voter_links: Mutex>>, pub(crate) beefy_justif_req_handler: Mutex>>, @@ -367,10 +368,11 @@ async fn voter_init_setup( net: &mut BeefyTestNet, finality: &mut futures::stream::Fuse>, api: &TestApi, -) -> Result, Error> { +) -> Result, Error> { let backend = net.peer(0).client().as_backend(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, _) = GossipValidator::new(known_peers); + let (gossip_validator, _) = + GossipValidator::::new(known_peers); let gossip_validator = Arc::new(gossip_validator); let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), @@ -448,7 +450,7 @@ where prometheus_registry: None, on_demand_justifications_handler: on_demand_justif_handler, }; - let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); + let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _, _>(beefy_params); fn assert_send(_: &T) {} assert_send(&task); @@ -474,8 +476,10 @@ pub(crate) fn get_beefy_streams( net: &mut BeefyTestNet, // peer index and key peers: impl Iterator)>, -) -> (Vec>, Vec>>) -{ +) -> ( + Vec>, + Vec>>, +) { let mut best_block_streams = Vec::new(); let mut versioned_finality_proof_streams = Vec::new(); peers.for_each(|(index, _)| { @@ -513,7 +517,7 @@ async fn wait_for_best_beefy_blocks( } async fn wait_for_beefy_signed_commitments( - streams: Vec>>, + streams: Vec>>, net: &Arc>, expected_commitment_block_nums: &[u64], ) { @@ -1071,7 +1075,7 @@ async fn should_initialize_voter_at_custom_genesis() { // doesn't allow creating a new `GossipEngine` as the notification handle is consumed by the // first `GossipEngine` let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, _) = GossipValidator::new(known_peers); + let (gossip_validator, _) = GossipValidator::<_, ecdsa_crypto::AuthorityId>::new(known_peers); let gossip_validator = Arc::new(gossip_validator); let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), @@ -1328,7 +1332,7 @@ async fn should_catch_up_when_loading_saved_voter_state() { // doesn't allow creating a new `GossipEngine` as the notification handle is consumed by the // first `GossipEngine` let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, _) = GossipValidator::new(known_peers); + let (gossip_validator, _) = GossipValidator::<_, ecdsa_crypto::AuthorityId>::new(known_peers); let gossip_validator = Arc::new(gossip_validator); let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), @@ -1531,7 +1535,7 @@ async fn gossipped_finality_proofs() { // Charlie will run just the gossip engine and not the full voter. let (gossip_validator, _) = GossipValidator::new(known_peers); let charlie_gossip_validator = Arc::new(gossip_validator); - charlie_gossip_validator.update_filter(GossipFilterCfg:: { + charlie_gossip_validator.update_filter(GossipFilterCfg:: { start: 1, end: 10, validator_set: &validator_set, @@ -1575,7 +1579,7 @@ async fn gossipped_finality_proofs() { let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); // Charlie gossips finality proof for #1 -> Alice and Bob also finalize. let proof = crate::communication::gossip::tests::dummy_proof(1, &validator_set); - let gossip_proof = GossipMessage::::FinalityProof(proof); + let gossip_proof = GossipMessage::::FinalityProof(proof); let encoded_proof = gossip_proof.encode(); charlie_gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); // Expect #1 is finalized. @@ -1600,7 +1604,8 @@ async fn gossipped_finality_proofs() { let commitment = Commitment { payload, block_number, validator_set_id: validator_set.id() }; let signature = sign_commitment(&BeefyKeyring::Charlie, &commitment); let vote_message = VoteMessage { commitment, id: BeefyKeyring::Charlie.public(), signature }; - let encoded_vote = GossipMessage::::Vote(vote_message).encode(); + let encoded_vote = + GossipMessage::::Vote(vote_message).encode(); charlie_gossip_engine.gossip_message(votes_topic::(), encoded_vote, true); // Expect #2 is finalized. @@ -1612,12 +1617,15 @@ async fn gossipped_finality_proofs() { charlie_gossip_engine .messages_for(proofs_topic::()) .filter_map(|notification| async move { - GossipMessage::::decode(&mut ¬ification.message[..]).ok().and_then( - |message| match message { - GossipMessage::::Vote(_) => unreachable!(), - GossipMessage::::FinalityProof(proof) => Some(proof), - }, + GossipMessage::::decode( + &mut ¬ification.message[..], ) + .ok() + .and_then(|message| match message { + GossipMessage::::Vote(_) => unreachable!(), + GossipMessage::::FinalityProof(proof) => + Some(proof), + }) }) .fuse(), ); @@ -1635,7 +1643,7 @@ async fn gossipped_finality_proofs() { // verify finality proof has been gossipped proof = charlie_gossip_proofs.next() => { let proof = proof.unwrap(); - let (round, _) = proof_block_num_and_set_id::(&proof); + let (round, _) = proof_block_num_and_set_id::(&proof); match round { 1 => continue, // finality proof generated by Charlie in the previous round 2 => break, // finality proof generated by Alice or Bob and gossiped to Charlie diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 682b05d529b4..6262e50a7f91 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -644,7 +644,7 @@ where } #[cfg(test)] - fn active_rounds(&mut self) -> Result<&Rounds, Error> { + fn active_rounds(&mut self) -> Result<&Rounds, Error> { self.persisted_state.voting_oracle.active_rounds() } @@ -1331,7 +1331,7 @@ pub(crate) mod tests { use sc_network_test::TestNetFactory; use sp_blockchain::Backend as BlockchainBackendT; use sp_consensus_beefy::{ - known_payloads, + ecdsa_crypto, known_payloads, known_payloads::MMR_ROOT_ID, mmr::MmrRootProvider, test_utils::{generate_equivocation_proof, Keyring}, @@ -1344,7 +1344,7 @@ pub(crate) mod tests { }; impl PersistedState { - pub fn voting_oracle(&self) -> &VoterOracle { + pub fn voting_oracle(&self) -> &VoterOracle { &self.voting_oracle } @@ -1357,7 +1357,7 @@ pub(crate) mod tests { } } - impl VoterOracle { + impl VoterOracle { pub fn sessions(&self) -> &VecDeque> { &self.sessions } @@ -1374,15 +1374,16 @@ pub(crate) mod tests { MmrRootProvider, TestApi, Arc>, + AuthorityId, > { let keystore = create_beefy_keystore(key); let (to_rpc_justif_sender, from_voter_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = BeefyBestBlockStream::::channel(); let (_, from_block_import_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let beefy_rpc_links = BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream }; @@ -1560,13 +1561,14 @@ pub(crate) mod tests { Default::default(), Digest::default(), ); - let mut oracle = VoterOracle:: { + let mut oracle = VoterOracle:: { best_beefy_block: 0, best_grandpa_block_header: header, min_block_delta: 1, sessions: VecDeque::new(), + _phantom: PhantomData, }; - let voting_target_with = |oracle: &mut VoterOracle, + let voting_target_with = |oracle: &mut VoterOracle, best_beefy: NumberFor, best_grandpa: NumberFor| -> Option> { @@ -1622,18 +1624,20 @@ pub(crate) mod tests { Default::default(), Digest::default(), ); - let mut oracle = VoterOracle:: { + let mut oracle = VoterOracle:: { best_beefy_block: 0, best_grandpa_block_header: header, min_block_delta: 1, sessions: VecDeque::new(), + _phantom: PhantomData, }; - let accepted_interval_with = |oracle: &mut VoterOracle, - best_grandpa: NumberFor| - -> Result<(NumberFor, NumberFor), Error> { - oracle.best_grandpa_block_header.number = best_grandpa; - oracle.accepted_interval() - }; + let accepted_interval_with = + |oracle: &mut VoterOracle, + best_grandpa: NumberFor| + -> Result<(NumberFor, NumberFor), Error> { + oracle.best_grandpa_block_header.number = best_grandpa; + oracle.accepted_interval() + }; // rounds not initialized -> should accept votes: `None` assert!(accepted_interval_with(&mut oracle, 1).is_err()); @@ -1704,7 +1708,7 @@ pub(crate) mod tests { ); // verify empty digest shows nothing - assert!(find_authorities_change::(&header).is_none()); + assert!(find_authorities_change::(&header).is_none()); let peers = &[Keyring::One, Keyring::Two]; let id = 42; @@ -1715,7 +1719,7 @@ pub(crate) mod tests { )); // verify validator set is correctly extracted from digest - let extracted = find_authorities_change::(&header); + let extracted = find_authorities_change::(&header); assert_eq!(extracted, Some(validator_set)); } From d230d74a0de1000f76835bda4fe9ebb7c40d9060 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 27 Feb 2024 04:59:21 -0500 Subject: [PATCH 53/78] Resolve warning in BEEFY client --- .../client/consensus/beefy/src/aux_schema.rs | 4 +-- .../beefy/src/communication/gossip.rs | 15 +++++----- .../beefy/src/communication/notification.rs | 1 - .../client/consensus/beefy/src/import.rs | 2 +- .../consensus/beefy/src/justification.rs | 2 +- .../client/consensus/beefy/src/keystore.rs | 3 -- substrate/client/consensus/beefy/src/lib.rs | 4 +-- .../client/consensus/beefy/src/worker.rs | 28 +++++++++---------- 8 files changed, 25 insertions(+), 34 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 531eacf98cc5..cac2f6a9e3fd 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -24,9 +24,7 @@ use log::{info, trace}; use sc_client_api::{backend::AuxStore, Backend}; use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_consensus_beefy::{ - AuthorityIdBound, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, -}; +use sp_consensus_beefy::AuthorityIdBound; use sp_runtime::traits::Block as BlockT; const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 42fd0dc514f6..1a297af53f97 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -22,7 +22,7 @@ use sc_network::{PeerId, ReputationChange}; use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; use sp_runtime::traits::{Block, Hash, Header, NumberFor}; -use codec::{Decode, DecodeAll, Encode, WrapperTypeEncode}; +use codec::{Decode, DecodeAll, Encode}; use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -511,11 +511,8 @@ pub(crate) mod tests { use sc_network_test::Block; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - ecdsa_crypto, - ecdsa_crypto::{Public as EcdsaPublic, Signature}, - known_payloads, - test_utils::Keyring, - Commitment, MmrRootHash, Payload, SignedCommitment, VoteMessage, + ecdsa_crypto, known_payloads, test_utils::Keyring, Commitment, MmrRootHash, Payload, + SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -539,14 +536,16 @@ pub(crate) mod tests { pub fn sign_commitment( who: &Keyring, commitment: &Commitment, - ) -> Signature { + ) -> ecdsa_crypto::Signature { let store = MemoryKeystore::new(); store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } - fn dummy_vote(block_number: u64) -> VoteMessage { + fn dummy_vote( + block_number: u64, + ) -> VoteMessage { let payload = Payload::from_single_entry( known_payloads::MMR_ROOT_ID, MmrRootHash::default().encode(), diff --git a/substrate/client/consensus/beefy/src/communication/notification.rs b/substrate/client/consensus/beefy/src/communication/notification.rs index ae80a8fd07f9..8bb5d848b4fa 100644 --- a/substrate/client/consensus/beefy/src/communication/notification.rs +++ b/substrate/client/consensus/beefy/src/communication/notification.rs @@ -17,7 +17,6 @@ // along with this program. If not, see . use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; -use sp_consensus_beefy::AuthorityIdBound; use sp_runtime::traits::Block as BlockT; use crate::justification::BeefyVersionedFinalityProof; diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index ed387b374a32..e67f0e6b8e54 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -23,7 +23,7 @@ use log::debug; use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; -use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, AuthorityIdBound, BeefyApi, BEEFY_ENGINE_ID}; +use sp_consensus_beefy::{AuthorityIdBound, BeefyApi, BEEFY_ENGINE_ID}; use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT, NumberFor}, EncodedJustification, diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 29ede7a0cd25..60327050636e 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::keystore::BeefyKeystore; -use codec::{Decode, DecodeAll, Encode, WrapperTypeEncode}; +use codec::{DecodeAll, Encode}; use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{AuthorityIdBound, ValidatorSet, ValidatorSetId, VersionedFinalityProof}; diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index fbfa0d67d2e3..d98816c80248 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -28,9 +28,6 @@ use std::marker::PhantomData; use sp_consensus_beefy::{AuthorityIdBound, BeefyAuthorityId, BeefySignatureHasher}; -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy::ecdsa_bls_crypto; - use crate::{error, LOG_TARGET}; /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 0d218500ee83..7d9735ead6f8 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -45,9 +45,7 @@ use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, }; use sp_consensus::{Error as ConsensusError, SyncOracle}; -use sp_consensus_beefy::{ - AuthorityIdBound, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, -}; +use sp_consensus_beefy::{AuthorityIdBound, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet}; use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 6262e50a7f91..751b4faded7e 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -34,7 +34,7 @@ use crate::{ }; use sp_application_crypto::RuntimeAppPublic; -use codec::{Codec, Decode, DecodeAll, Encode, WrapperTypeEncode}; +use codec::{Codec, Decode, DecodeAll, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; @@ -45,10 +45,9 @@ use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_blockchain::{Backend as BlockchainBackend, Error as ClientError, Result as ClientResult}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ - check_equivocation_proof, - ecdsa_crypto::{AuthorityId, Signature}, - AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, ConsensusLog, EquivocationProof, - PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + check_equivocation_proof, AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, + ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, + VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, @@ -1343,12 +1342,12 @@ pub(crate) mod tests { Backend, }; - impl PersistedState { - pub fn voting_oracle(&self) -> &VoterOracle { + impl PersistedState { + pub fn voting_oracle(&self) -> &VoterOracle { &self.voting_oracle } - pub fn active_round(&self) -> Result<&Rounds, Error> { + pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() } @@ -1357,24 +1356,24 @@ pub(crate) mod tests { } } - impl VoterOracle { - pub fn sessions(&self) -> &VecDeque> { + impl VoterOracle { + pub fn sessions(&self) -> &VecDeque> { &self.sessions } } fn create_beefy_worker( peer: &mut BeefyPeer, - key: &Keyring, + key: &Keyring, min_block_delta: u32, - genesis_validator_set: ValidatorSet, + genesis_validator_set: ValidatorSet, ) -> BeefyWorker< Block, Backend, MmrRootProvider, TestApi, Arc>, - AuthorityId, + ecdsa_crypto::AuthorityId, > { let keystore = create_beefy_keystore(key); @@ -1715,7 +1714,8 @@ pub(crate) mod tests { let validator_set = ValidatorSet::new(make_beefy_ids(peers), id).unwrap(); header.digest_mut().push(DigestItem::Consensus( BEEFY_ENGINE_ID, - ConsensusLog::::AuthoritiesChange(validator_set.clone()).encode(), + ConsensusLog::::AuthoritiesChange(validator_set.clone()) + .encode(), )); // verify validator set is correctly extracted from digest From 4464c384031fa3c4428291153b620dd40cfc4c2d Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 27 Feb 2024 05:27:38 -0500 Subject: [PATCH 54/78] Remove redundant imports --- substrate/client/consensus/beefy/src/worker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 751b4faded7e..37c8acbb7d45 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -42,7 +42,7 @@ use sc_network_gossip::GossipEngine; use sc_utils::{mpsc::TracingUnboundedReceiver, notification::NotificationReceiver}; use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; -use sp_blockchain::{Backend as BlockchainBackend, Error as ClientError, Result as ClientResult}; +use sp_blockchain::Backend as BlockchainBackend; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, From b82aaa14280b76559c4939540582639d23caf693 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 11 Mar 2024 12:17:23 -0400 Subject: [PATCH 55/78] fix error in beefy generic client after merge --- substrate/client/consensus/beefy/src/lib.rs | 48 +++++++++++------- .../client/consensus/beefy/src/worker.rs | 49 ++++++++++++++----- 2 files changed, 69 insertions(+), 28 deletions(-) diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 573f254b850b..8e41a29aa55c 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -45,7 +45,10 @@ use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, }; use sp_consensus::{Error as ConsensusError, SyncOracle}; -use sp_consensus_beefy::{AuthorityIdBound, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet}; +use sp_consensus_beefy::{ + AuthorityIdBound, BeefyApi, ConsensusLog, MmrRootHash, PayloadProvider, ValidatorSet, + BEEFY_ENGINE_ID, +}; use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; @@ -241,11 +244,14 @@ where /// Helper object holding BEEFY worker communication/gossip components. /// /// These are created once, but will be reused if worker is restarted/reinitialized. -pub(crate) struct BeefyComms { +pub(crate) struct BeefyComms +where + ::Signature: Send + Sync, +{ pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, + pub gossip_validator: Arc>, pub gossip_report_stream: TracingUnboundedReceiver, - pub on_demand_justifications: OnDemandJustificationsEngine, + pub on_demand_justifications: OnDemandJustificationsEngine, } /// Helper builder object for building [worker::BeefyWorker]. @@ -254,22 +260,27 @@ pub(crate) struct BeefyComms { /// for certain chain and backend conditions, and while sleeping we still need to pump the /// GossipEngine. Once initialization is done, the GossipEngine (and other pieces) are added to get /// the complete [worker::BeefyWorker] object. -pub(crate) struct BeefyWorkerBuilder { +pub(crate) struct BeefyWorkerBuilder +where + ::Signature: Send + Sync, +{ // utilities backend: Arc, runtime: Arc, key_store: BeefyKeystore, // voter metrics metrics: Option, - persisted_state: PersistedState, + persisted_state: PersistedState, } -impl BeefyWorkerBuilder +impl BeefyWorkerBuilder where B: Block + codec::Codec, BE: Backend, R: ProvideRuntimeApi, R::Api: BeefyApi, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { /// This will wait for the chain to enable BEEFY (if not yet enabled) and also wait for the /// backend to sync all headers required by the voter to build a contiguous chain of mandatory @@ -283,7 +294,7 @@ where key_store: BeefyKeystore, metrics: Option, min_block_delta: u32, - gossip_validator: Arc>, + gossip_validator: Arc>, finality_notifications: &mut Fuse>, ) -> Result { // Wait for BEEFY pallet to be active before starting voter. @@ -313,10 +324,10 @@ where self, payload_provider: P, sync: Arc, - comms: BeefyComms, - links: BeefyVoterLinks, - pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, - ) -> BeefyWorker { + comms: BeefyComms, + links: BeefyVoterLinks, + pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + ) -> BeefyWorker { BeefyWorker { backend: self.backend, runtime: self.runtime, @@ -342,7 +353,7 @@ where min_block_delta: u32, backend: Arc, runtime: Arc, - ) -> Result, Error> { + ) -> Result, Error> { let blockchain = backend.blockchain(); let beefy_genesis = runtime @@ -412,7 +423,7 @@ where .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))? } - if let Some(active) = find_authorities_change::(&header) { + if let Some(active) = find_authorities_change::(&header) { debug!( target: LOG_TARGET, "🥩 Marking block {:?} as BEEFY Mandatory.", @@ -438,7 +449,7 @@ where runtime: Arc, key_store: &BeefyKeystore, metrics: &Option, - ) -> Result, Error> { + ) -> Result, Error> { // Initialize voter state from AUX DB if compatible. if let Some(mut state) = crate::aux_schema::load_persistent(backend.as_ref())? // Verify state pallet genesis matches runtime. @@ -455,7 +466,7 @@ where let mut header = best_grandpa.clone(); while *header.number() > state.best_beefy() { if state.voting_oracle().can_add_session(*header.number()) { - if let Some(active) = find_authorities_change::(&header) { + if let Some(active) = find_authorities_change::(&header) { new_sessions.push((active, *header.number())); } } @@ -741,9 +752,12 @@ where /// Scan the `header` digest log for a BEEFY validator set change. Return either the new /// validator set or `None` in case no validator set change has been signaled. -pub(crate) fn find_authorities_change(header: &B::Header) -> Option> +pub(crate) fn find_authorities_change( + header: &B::Header, +) -> Option> where B: Block, + AuthorityId: AuthorityIdBound, { let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 05bef22fd166..2c66bf02d2bf 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -54,6 +54,7 @@ use sp_runtime::{ use std::{ collections::{BTreeMap, BTreeSet, VecDeque}, fmt::Debug, + marker::PhantomData, sync::Arc, }; @@ -332,11 +333,11 @@ where self.voting_oracle.best_grandpa_block_header = best_grandpa; } - pub fn voting_oracle(&self) -> &VoterOracle { + pub fn voting_oracle(&self) -> &VoterOracle { &self.voting_oracle } - pub(crate) fn gossip_filter_config(&self) -> Result, Error> { + pub(crate) fn gossip_filter_config(&self) -> Result, Error> { let (start, end) = self.voting_oracle.accepted_interval()?; let validator_set = self.voting_oracle.current_validator_set()?; Ok(GossipFilterCfg { start, end, validator_set }) @@ -367,7 +368,9 @@ where if log_enabled!(target: LOG_TARGET, log::Level::Debug) { // verify the new validator set - only do it if we're also logging the warning - if verify_validator_set::(&new_session_start, &validator_set, key_store).is_err() { + if verify_validator_set::(&new_session_start, &validator_set, key_store) + .is_err() + { metric_inc!(metrics, beefy_no_authority_found_in_store); } } @@ -385,7 +388,10 @@ where } /// A BEEFY worker/voter that follows the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker +where + ::Signature: Send + Sync, +{ // utilities pub backend: Arc, pub runtime: Arc, @@ -404,7 +410,7 @@ pub(crate) struct BeefyWorker { /// Buffer holding justifications for future processing. pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. - pub persisted_state: PersistedState, + pub persisted_state: PersistedState, /// BEEFY voter metrics pub metrics: Option, } @@ -1084,7 +1090,7 @@ where /// /// Note that for a non-authority node there will be no keystore, and we will /// return an error and don't check. The error can usually be ignored. -fn verify_validator_set( +fn verify_validator_set( block: &NumberFor, active: &ValidatorSet, key_store: &BeefyKeystore, @@ -1138,8 +1144,11 @@ pub(crate) mod tests { Backend, }; - impl PersistedState { - pub fn active_round(&self) -> Result<&Rounds, Error> { + impl PersistedState + where + ::Signature: Send + Sync, + { + pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() } @@ -1520,20 +1529,38 @@ pub(crate) mod tests { let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); // keystore doesn't contain other keys than validators' - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), Ok(())); + assert_eq!( + verify_validator_set::( + &1, + &validator_set, + &worker.key_store + ), + Ok(()) + ); // unknown `Bob` key let keys = &[Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let err_msg = "no authority public key found in store".to_string(); let expected = Err(Error::Keystore(err_msg)); - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), expected); + assert_eq!( + verify_validator_set::( + &1, + &validator_set, + &worker.key_store + ), + expected + ); // worker has no keystore worker.key_store = None.into(); let expected_err = Err(Error::Keystore("no Keystore".into())); assert_eq!( - verify_validator_set::(&1, &validator_set, &worker.key_store), + verify_validator_set::( + &1, + &validator_set, + &worker.key_store + ), expected_err ); } From 906b43646c32afacb7fd57edc17854d066339297 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 11 Mar 2024 12:22:33 -0400 Subject: [PATCH 56/78] Remove unused uses --- substrate/client/consensus/beefy/src/lib.rs | 2 +- substrate/client/consensus/beefy/src/worker.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 8e41a29aa55c..1fd4cfc92ed7 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -42,7 +42,7 @@ use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as Gossi use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{ - Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, + Backend as BlockchainBackend, HeaderBackend, }; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_consensus_beefy::{ diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 2c66bf02d2bf..1b7abbb080f1 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -43,7 +43,7 @@ use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, - ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, + EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ From 30673515fe46938ea57b0908d4323959b5c5198e Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 11 Mar 2024 12:41:42 -0400 Subject: [PATCH 57/78] fmt --- substrate/client/consensus/beefy/src/lib.rs | 4 +--- substrate/client/consensus/beefy/src/worker.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 1fd4cfc92ed7..f679efff11b8 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -41,9 +41,7 @@ use sc_network::{NetworkRequest, NotificationService, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; -use sp_blockchain::{ - Backend as BlockchainBackend, HeaderBackend, -}; +use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_consensus_beefy::{ AuthorityIdBound, BeefyApi, ConsensusLog, MmrRootHash, PayloadProvider, ValidatorSet, diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 1b7abbb080f1..3561f86f78c6 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -43,8 +43,8 @@ use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, - EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, - VoteMessage, BEEFY_ENGINE_ID, + EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, + BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::BlockId, From b2f7c9564ff3d7c2487a82d6df02fbafb0180ac7 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 14 Mar 2024 04:26:35 -0400 Subject: [PATCH 58/78] Make BEEFY RPC generic over AuthorityId Make Polkadot and template node specify BEEFY AuthorityId type --- Cargo.lock | 5 +++ polkadot/node/service/src/lib.rs | 18 ++++++--- polkadot/rpc/Cargo.toml | 2 + polkadot/rpc/src/lib.rs | 18 +++++---- substrate/bin/node/cli/src/service.rs | 15 ++++--- substrate/bin/node/rpc/Cargo.toml | 2 + substrate/bin/node/rpc/src/lib.rs | 18 +++++---- .../client/consensus/beefy/rpc/Cargo.toml | 1 + .../client/consensus/beefy/rpc/src/lib.rs | 39 ++++++++++++------- .../consensus/beefy/rpc/src/notification.rs | 9 ++++- 10 files changed, 86 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b402551c77ec..b48b926c990e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8630,10 +8630,12 @@ dependencies = [ "sc-sync-state-rpc", "sc-transaction-pool-api", "sp-api", + "sp-application-crypto", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-beefy", "sp-keystore", "sp-runtime", "sp-statement-store", @@ -13185,10 +13187,12 @@ dependencies = [ "sc-sync-state-rpc", "sc-transaction-pool-api", "sp-api", + "sp-application-crypto", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-beefy", "sp-keystore", "sp-runtime", "substrate-frame-rpc-system", @@ -15921,6 +15925,7 @@ dependencies = [ "sc-rpc", "serde", "serde_json", + "sp-application-crypto", "sp-consensus-beefy", "sp-core", "sp-runtime", diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 83a0afc077e7..d1f995885cb1 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -88,6 +88,7 @@ use telemetry::TelemetryWorker; #[cfg(feature = "full-node")] use telemetry::{Telemetry, TelemetryWorkerHandle}; +use beefy_primitives::ecdsa_crypto; pub use chain_spec::{GenericChainSpec, RococoChainSpec, WestendChainSpec}; pub use consensus_common::{Proposal, SelectChain}; use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; @@ -394,8 +395,8 @@ type FullSelectChain = relay_chain_selection::SelectRelayChain; type FullGrandpaBlockImport = grandpa::GrandpaBlockImport; #[cfg(feature = "full-node")] -type FullBeefyBlockImport = - beefy::import::BeefyBlockImport; +type FullBeefyBlockImport = + beefy::import::BeefyBlockImport; #[cfg(feature = "full-node")] struct Basics { @@ -486,11 +487,14 @@ fn new_partial( babe::BabeBlockImport< Block, FullClient, - FullBeefyBlockImport>, + FullBeefyBlockImport< + FullGrandpaBlockImport, + ecdsa_crypto::AuthorityId, + >, >, grandpa::LinkHalf, babe::BabeLink, - beefy::BeefyVoterLinks, + beefy::BeefyVoterLinks, ), grandpa::SharedVoterState, sp_consensus_babe::SlotDuration, @@ -601,7 +605,7 @@ where subscription_executor: subscription_executor.clone(), finality_provider: finality_proof_provider.clone(), }, - beefy: polkadot_rpc::BeefyDeps { + beefy: polkadot_rpc::BeefyDeps:: { beefy_finality_proof_stream: beefy_rpc_links.from_voter_justif_stream.clone(), beefy_best_block_stream: beefy_rpc_links.from_voter_best_beefy_stream.clone(), subscription_executor, @@ -1233,7 +1237,9 @@ pub fn new_full( on_demand_justifications_handler: beefy_on_demand_justifications_handler, }; - let gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); + let gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _, ecdsa_crypto::AuthorityId>( + beefy_params, + ); // BEEFY is part of consensus, if it fails we'll bring the node down with it to make sure it // is noticed. diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index 5af5e63b1753..1900b595d671 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -17,8 +17,10 @@ sp-blockchain = { path = "../../substrate/primitives/blockchain" } sp-keystore = { path = "../../substrate/primitives/keystore" } sp-runtime = { path = "../../substrate/primitives/runtime" } sp-api = { path = "../../substrate/primitives/api" } +sp-application-crypto = { path = "../../substrate/primitives/application-crypto" } sp-consensus = { path = "../../substrate/primitives/consensus/common" } sp-consensus-babe = { path = "../../substrate/primitives/consensus/babe" } +sp-consensus-beefy = { path = "../../substrate/primitives/consensus/beefy" } sc-chain-spec = { path = "../../substrate/client/chain-spec" } sc-rpc = { path = "../../substrate/client/rpc" } sc-rpc-spec-v2 = { path = "../../substrate/client/rpc-spec-v2" } diff --git a/polkadot/rpc/src/lib.rs b/polkadot/rpc/src/lib.rs index 4455efd3b533..2daa246102fc 100644 --- a/polkadot/rpc/src/lib.rs +++ b/polkadot/rpc/src/lib.rs @@ -29,10 +29,12 @@ use sc_consensus_beefy::communication::notification::{ use sc_consensus_grandpa::FinalityProofProvider; pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; use sp_api::ProvideRuntimeApi; +use sp_application_crypto::RuntimeAppPublic; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::SelectChain; use sp_consensus_babe::BabeApi; +use sp_consensus_beefy::AuthorityIdBound; use sp_keystore::KeystorePtr; use txpool_api::TransactionPool; @@ -62,9 +64,9 @@ pub struct GrandpaDeps { } /// Dependencies for BEEFY -pub struct BeefyDeps { +pub struct BeefyDeps { /// Receives notifications about finality proof events from BEEFY. - pub beefy_finality_proof_stream: BeefyVersionedFinalityProofStream, + pub beefy_finality_proof_stream: BeefyVersionedFinalityProofStream, /// Receives notifications about best block events from BEEFY. pub beefy_best_block_stream: BeefyBestBlockStream, /// Executor to drive the subscription manager in the BEEFY RPC handler. @@ -72,7 +74,7 @@ pub struct BeefyDeps { } /// Full client dependencies -pub struct FullDeps { +pub struct FullDeps { /// The client instance to use. pub client: Arc, /// Transaction pool instance. @@ -88,14 +90,14 @@ pub struct FullDeps { /// GRANDPA specific dependencies. pub grandpa: GrandpaDeps, /// BEEFY specific dependencies. - pub beefy: BeefyDeps, + pub beefy: BeefyDeps, /// Backend used by the node. pub backend: Arc, } /// Instantiate all RPC extensions. -pub fn create_full( - FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa, beefy, backend } : FullDeps, +pub fn create_full( + FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa, beefy, backend } : FullDeps, ) -> Result> where C: ProvideRuntimeApi @@ -114,6 +116,8 @@ where SC: SelectChain + 'static, B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::StateBackend>, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { use frame_rpc_system::{System, SystemApiServer}; use mmr_rpc::{Mmr, MmrApiServer}; @@ -171,7 +175,7 @@ where )?; io.merge( - Beefy::::new( + Beefy::::new( beefy.beefy_finality_proof_stream, beefy.beefy_best_block_stream, beefy.subscription_executor, diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 157f278fb534..71178b62d047 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -63,8 +63,13 @@ type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; type FullGrandpaBlockImport = grandpa::GrandpaBlockImport; -type FullBeefyBlockImport = - beefy::import::BeefyBlockImport; +type FullBeefyBlockImport = beefy::import::BeefyBlockImport< + Block, + FullBackend, + FullClient, + InnerBlockImport, + beefy_primitives::ecdsa_crypto::AuthorityId, +>; /// The transaction pool type definition. pub type TransactionPool = sc_transaction_pool::FullPool; @@ -179,7 +184,7 @@ pub fn new_partial( >, grandpa::LinkHalf, sc_consensus_babe::BabeLink, - beefy::BeefyVoterLinks, + beefy::BeefyVoterLinks, ), grandpa::SharedVoterState, Option, @@ -327,7 +332,7 @@ pub fn new_partial( subscription_executor: subscription_executor.clone(), finality_provider: finality_proof_provider.clone(), }, - beefy: node_rpc::BeefyDeps { + beefy: node_rpc::BeefyDeps:: { beefy_finality_proof_stream: beefy_rpc_links .from_voter_justif_stream .clone(), @@ -657,7 +662,7 @@ pub fn new_full_base( on_demand_justifications_handler: beefy_on_demand_justifications_handler, }; - let beefy_gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); + let beefy_gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _, _>(beefy_params); // BEEFY is part of consensus, if it fails we'll bring the node down with it to make sure it // is noticed. task_manager diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index 894dbf0da85c..6ae80eb57859 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -26,6 +26,7 @@ sc-consensus-babe = { path = "../../../client/consensus/babe" } sc-consensus-babe-rpc = { path = "../../../client/consensus/babe/rpc" } sc-consensus-beefy = { path = "../../../client/consensus/beefy" } sc-consensus-beefy-rpc = { path = "../../../client/consensus/beefy/rpc" } +sp-consensus-beefy = { path = "../../../primitives/consensus/beefy" } sc-consensus-grandpa = { path = "../../../client/consensus/grandpa" } sc-consensus-grandpa-rpc = { path = "../../../client/consensus/grandpa/rpc" } sc-mixnet = { path = "../../../client/mixnet" } @@ -41,6 +42,7 @@ sp-consensus = { path = "../../../primitives/consensus/common" } sp-consensus-babe = { path = "../../../primitives/consensus/babe" } sp-keystore = { path = "../../../primitives/keystore" } sp-runtime = { path = "../../../primitives/runtime" } +sp-application-crypto = { path = "../../../primitives/application-crypto" } sp-statement-store = { path = "../../../primitives/statement-store" } substrate-frame-rpc-system = { path = "../../../utils/frame/rpc/system" } substrate-state-trie-migration-rpc = { path = "../../../utils/frame/rpc/state-trie-migration-rpc" } diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index 4646524a25ba..52cd7f9561d2 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -47,10 +47,12 @@ pub use sc_rpc::SubscriptionTaskExecutor; pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; +use sp_application_crypto::RuntimeAppPublic; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::SelectChain; use sp_consensus_babe::BabeApi; +use sp_consensus_beefy::AuthorityIdBound; use sp_keystore::KeystorePtr; /// Extra dependencies for BABE. @@ -76,9 +78,9 @@ pub struct GrandpaDeps { } /// Dependencies for BEEFY -pub struct BeefyDeps { +pub struct BeefyDeps { /// Receives notifications about finality proof events from BEEFY. - pub beefy_finality_proof_stream: BeefyVersionedFinalityProofStream, + pub beefy_finality_proof_stream: BeefyVersionedFinalityProofStream, /// Receives notifications about best block events from BEEFY. pub beefy_best_block_stream: BeefyBestBlockStream, /// Executor to drive the subscription manager in the BEEFY RPC handler. @@ -86,7 +88,7 @@ pub struct BeefyDeps { } /// Full client dependencies. -pub struct FullDeps { +pub struct FullDeps { /// The client instance to use. pub client: Arc, /// Transaction pool instance. @@ -102,7 +104,7 @@ pub struct FullDeps { /// GRANDPA specific dependencies. pub grandpa: GrandpaDeps, /// BEEFY specific dependencies. - pub beefy: BeefyDeps, + pub beefy: BeefyDeps, /// Shared statement store reference. pub statement_store: Arc, /// The backend used by the node. @@ -112,7 +114,7 @@ pub struct FullDeps { } /// Instantiate all Full RPC extensions. -pub fn create_full( +pub fn create_full( FullDeps { client, pool, @@ -125,7 +127,7 @@ pub fn create_full( statement_store, backend, mixnet_api, - }: FullDeps, + }: FullDeps, ) -> Result, Box> where C: ProvideRuntimeApi @@ -145,6 +147,8 @@ where SC: SelectChain + 'static, B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { use mmr_rpc::{Mmr, MmrApiServer}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; @@ -223,7 +227,7 @@ where } io.merge( - Beefy::::new( + Beefy::::new( beefy.beefy_finality_proof_stream, beefy.beefy_best_block_stream, beefy.subscription_executor, diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index bb2ae4a08966..db1cb498e0bd 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -24,6 +24,7 @@ sp-consensus-beefy = { path = "../../../../primitives/consensus/beefy" } sc-rpc = { path = "../../../rpc" } sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } +sp-application-crypto = { path = "../../../../primitives/application-crypto" } [dev-dependencies] serde_json = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/beefy/rpc/src/lib.rs b/substrate/client/consensus/beefy/rpc/src/lib.rs index f01baee2d6ec..66102eeb35c8 100644 --- a/substrate/client/consensus/beefy/rpc/src/lib.rs +++ b/substrate/client/consensus/beefy/rpc/src/lib.rs @@ -21,9 +21,11 @@ #![warn(missing_docs)] use parking_lot::RwLock; +use sp_consensus_beefy::AuthorityIdBound; use std::sync::Arc; use sc_rpc::{utils::pipe_from_stream, SubscriptionTaskExecutor}; +use sp_application_crypto::RuntimeAppPublic; use sp_runtime::traits::Block as BlockT; use futures::{task::SpawnError, FutureExt, StreamExt}; @@ -98,19 +100,20 @@ pub trait BeefyApi { } /// Implements the BeefyApi RPC trait for interacting with BEEFY. -pub struct Beefy { - finality_proof_stream: BeefyVersionedFinalityProofStream, +pub struct Beefy { + finality_proof_stream: BeefyVersionedFinalityProofStream, beefy_best_block: Arc>>, executor: SubscriptionTaskExecutor, } -impl Beefy +impl Beefy where Block: BlockT, + AuthorityId: AuthorityIdBound, { /// Creates a new Beefy Rpc handler instance. pub fn new( - finality_proof_stream: BeefyVersionedFinalityProofStream, + finality_proof_stream: BeefyVersionedFinalityProofStream, best_block_stream: BeefyBestBlockStream, executor: SubscriptionTaskExecutor, ) -> Result { @@ -129,16 +132,18 @@ where } #[async_trait] -impl BeefyApiServer - for Beefy +impl BeefyApiServer + for Beefy where Block: BlockT, + AuthorityId: AuthorityIdBound, + ::Signature: Send + Sync, { fn subscribe_justifications(&self, pending: PendingSubscriptionSink) { let stream = self .finality_proof_stream .subscribe(100_000) - .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); + .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); sc_rpc::utils::spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); } @@ -158,20 +163,26 @@ mod tests { communication::notification::BeefyVersionedFinalityProofSender, justification::BeefyVersionedFinalityProof, }; - use sp_consensus_beefy::{known_payloads, Payload, SignedCommitment}; + use sp_consensus_beefy::{ecdsa_crypto, known_payloads, Payload, SignedCommitment}; use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; - fn setup_io_handler() -> (RpcModule>, BeefyVersionedFinalityProofSender) { + fn setup_io_handler() -> ( + RpcModule>, + BeefyVersionedFinalityProofSender, + ) { let (_, stream) = BeefyBestBlockStream::::channel(); setup_io_handler_with_best_block_stream(stream) } fn setup_io_handler_with_best_block_stream( best_block_stream: BeefyBestBlockStream, - ) -> (RpcModule>, BeefyVersionedFinalityProofSender) { + ) -> ( + RpcModule>, + BeefyVersionedFinalityProofSender, + ) { let (finality_proof_sender, finality_proof_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let handler = Beefy::new(finality_proof_stream, best_block_stream, sc_rpc::testing::test_executor()) @@ -250,10 +261,10 @@ mod tests { assert_eq!(response, expected); } - fn create_finality_proof() -> BeefyVersionedFinalityProof { + fn create_finality_proof() -> BeefyVersionedFinalityProof { let payload = Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - BeefyVersionedFinalityProof::::V1(SignedCommitment { + BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment: sp_consensus_beefy::Commitment { payload, block_number: 5, @@ -280,7 +291,7 @@ mod tests { // Inspect what we received let (bytes, recv_sub_id) = sub.next::().await.unwrap().unwrap(); - let recv_finality_proof: BeefyVersionedFinalityProof = + let recv_finality_proof: BeefyVersionedFinalityProof = Decode::decode(&mut &bytes[..]).unwrap(); assert_eq!(&recv_sub_id, sub.subscription_id()); assert_eq!(recv_finality_proof, finality_proof); diff --git a/substrate/client/consensus/beefy/rpc/src/notification.rs b/substrate/client/consensus/beefy/rpc/src/notification.rs index 690c511b999a..d4339058a694 100644 --- a/substrate/client/consensus/beefy/rpc/src/notification.rs +++ b/substrate/client/consensus/beefy/rpc/src/notification.rs @@ -19,6 +19,7 @@ use codec::Encode; use serde::{Deserialize, Serialize}; +use sp_consensus_beefy::AuthorityIdBound; use sp_runtime::traits::Block as BlockT; /// An encoded finality proof proving that the given header has been finalized. @@ -28,11 +29,15 @@ use sp_runtime::traits::Block as BlockT; pub struct EncodedVersionedFinalityProof(sp_core::Bytes); impl EncodedVersionedFinalityProof { - pub fn new( - finality_proof: sc_consensus_beefy::justification::BeefyVersionedFinalityProof, + pub fn new( + finality_proof: sc_consensus_beefy::justification::BeefyVersionedFinalityProof< + Block, + AuthorityId, + >, ) -> Self where Block: BlockT, + AuthorityId: AuthorityIdBound, { EncodedVersionedFinalityProof(finality_proof.encode().into()) } From 90cb62e9fe43c89c8c91f699e3af8694957ffe8d Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 14 Mar 2024 05:15:30 -0400 Subject: [PATCH 59/78] Don't put `authority_id_works_for_ecdsa` behind bls feature. --- substrate/client/consensus/beefy/src/keystore.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index d98816c80248..682a44472d83 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -377,7 +377,6 @@ pub mod tests { assert_eq!(id, alice); } - #[cfg(feature = "bls-experimental")] #[test] fn authority_id_works_for_ecdsa() { authority_id_works::(); From b91af5bd4c7048ed17788f45ee607cc02bf150ff Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 14 Mar 2024 08:21:42 -0400 Subject: [PATCH 60/78] Remove extrac copy of `ecdsa_bls377_sign_with_keccak_works` --- substrate/primitives/keystore/src/testing.rs | 34 +------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index b53af1679f5f..8315062334b2 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -516,39 +516,7 @@ mod tests { let suri = "//Alice"; let pair = ecdsa_bls377::Pair::from_string(suri, None).unwrap(); - let msg = b"this should be a normal unhashed message not "; - - // insert key, sign again - store.insert(ECDSA_BLS377, suri, pair.public().as_ref()).unwrap(); - - let res = store - .ecdsa_bls377_sign_with_keccak256(ECDSA_BLS377, &pair.public(), &msg[..]) - .unwrap(); - - assert!(res.is_some()); - - // does not verify with default out-of-the-box verification - assert!(!ecdsa_bls377::Pair::verify(&res.clone().unwrap(), &msg[..], &pair.public())); - - // should verify using keccak256 as hasher - assert!(ecdsa_bls377::Pair::verify_with_hasher::( - &res.unwrap(), - msg, - &pair.public() - )); - } - - #[test] - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign_with_keccak_works() { - use sp_core::testing::ECDSA_BLS377; - - let store = MemoryKeystore::new(); - - let suri = "//Alice"; - let pair = ecdsa_bls377::Pair::from_string(suri, None).unwrap(); - - let msg = b"this should be a normal unhashed message not "; + let msg = b"this should be a normal unhashed message not a hash of a message because bls scheme comes with its own hashing"; // insert key, sign again store.insert(ECDSA_BLS377, suri, pair.public().as_ref()).unwrap(); From c0fb32a8bf0826aaadb2747e2d7518dd43e60719 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:20:19 -0400 Subject: [PATCH 61/78] Adrian really doesn't like semi-colon at the end of a return statement. Co-authored-by: Adrian Catangiu --- substrate/primitives/consensus/beefy/src/lib.rs | 4 ++-- substrate/primitives/core/src/bls.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 39cb2c23a815..c06fa5c02e73 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -370,7 +370,7 @@ where first.commitment.validator_set_id != second.commitment.validator_set_id || first.commitment.payload == second.commitment.payload { - return false; + return false } // check signatures on both votes are valid @@ -378,7 +378,7 @@ where let valid_second = check_commitment_signature(&second.commitment, &second.id, &second.signature); - return valid_first && valid_second; + return valid_first && valid_second } /// New BEEFY validator set notification hook. diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 75119ec1892e..0c84d0ba8e6c 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -212,7 +212,7 @@ impl TryFrom<&[u8]> for Public { fn try_from(data: &[u8]) -> Result { if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { - return Err(()); + return Err(()) } let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; r.copy_from_slice(data); @@ -338,7 +338,7 @@ impl TryFrom<&[u8]> for Signature { fn try_from(data: &[u8]) -> Result { if data.len() != SIGNATURE_SERIALIZED_SIZE { - return Err(()); + return Err(()) } let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); @@ -448,7 +448,7 @@ impl TraitPair for Pair { fn from_seed_slice(seed_slice: &[u8]) -> Result { if seed_slice.len() != SECRET_KEY_SERIALIZED_SIZE { - return Err(SecretStringError::InvalidSeedLength); + return Err(SecretStringError::InvalidSeedLength) } let secret = w3f_bls::SecretKey::from_seed(seed_slice); let public = secret.into_public(); From a1d50ecab308ef722cbe2411a5c02460ac77d570 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:22:21 -0400 Subject: [PATCH 62/78] Remove redundant dead stuff Co-authored-by: Adrian Catangiu --- substrate/primitives/application-crypto/src/traits.rs | 2 +- substrate/primitives/consensus/beefy/src/lib.rs | 2 -- substrate/primitives/core/src/ecdsa.rs | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/application-crypto/src/traits.rs b/substrate/primitives/application-crypto/src/traits.rs index 68c47c86d78b..e9b1080f63d9 100644 --- a/substrate/primitives/application-crypto/src/traits.rs +++ b/substrate/primitives/application-crypto/src/traits.rs @@ -10,7 +10,7 @@ // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS,/ +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index c06fa5c02e73..74f1cff4e66f 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -75,8 +75,6 @@ pub trait AuthorityIdBound: + Debug + Clone + Ord - //+ Sync - //+ Send + AsRef<[u8]> + ByteArray + AppPublic diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 0e9cf8648d8b..e6bd2c7eb57d 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -158,7 +158,7 @@ impl TryFrom<&[u8]> for Public { fn try_from(data: &[u8]) -> Result { if data.len() != Self::LEN { - return Err(()); + return Err(()) } let mut r = [0u8; Self::LEN]; r.copy_from_slice(data); From 45f9c394f82df2c48a79e5e310552fab490e280d Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 18 Mar 2024 10:43:24 -0400 Subject: [PATCH 63/78] delete the a accidental file --- .../client/consensus/beefy/src/communication/gossip.rs:808:3 | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 substrate/client/consensus/beefy/src/communication/gossip.rs:808:3 diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs:808:3 b/substrate/client/consensus/beefy/src/communication/gossip.rs:808:3 deleted file mode 100644 index e69de29bb2d1..000000000000 From f7c8b611b54bd551211cfa10c3317f68743831fc Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:29:44 -0400 Subject: [PATCH 64/78] Remove SmartDefault Co-authored-by: Davide Galassi --- substrate/client/consensus/beefy/Cargo.toml | 1 - substrate/client/consensus/beefy/src/round.rs | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 62f9a121fb6e..d5bfff133f9a 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -41,7 +41,6 @@ sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } tokio = "1.22.0" -smart-default = "0.6.0" [dev-dependencies] serde = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index f8f78a665b32..9757f12068d0 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -28,13 +28,11 @@ use sp_consensus_beefy::{ use sp_runtime::traits::{Block, NumberFor}; use std::collections::BTreeMap; -use smart_default::SmartDefault; - /// Tracks for each round which validators have voted/signed and /// whether the local `self` validator has voted/signed. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Debug, Decode, Encode, PartialEq, SmartDefault)] +#[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct RoundTracker where ::Signature: Send + Sync, From adfb1bdb8ec9f56f658137060bce7d3c2d94ae96 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:35:04 -0400 Subject: [PATCH 65/78] Typos and Redudnacies Co-authored-by: Davide Galassi --- substrate/client/consensus/beefy/src/communication/gossip.rs | 2 +- substrate/client/consensus/beefy/src/round.rs | 2 +- substrate/client/consensus/beefy/src/worker.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index cb736ca1077c..3f7989f116e6 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -73,7 +73,7 @@ enum Consider { /// BEEFY gossip message type that gets encoded and sent on the network. #[derive(Debug, Encode, Decode)] -pub(crate) enum GossipMessage +pub(crate) enum GossipMessage where ::Signature: Send + Sync, { diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 9757f12068d0..5bbd68a88229 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -5,7 +5,7 @@ // 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 oSftware Foundation, either version 3 of the License, or +// 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, diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 3561f86f78c6..f1d21b06b789 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -95,7 +95,6 @@ where best_grandpa_block_header: ::Header, /// Best block a BEEFY voting round has been concluded for. best_beefy_block: NumberFor, - _phantom: PhantomData AuthorityId>, } From 56e75eb9650694c1019f1ba34926e18cfe96cd26 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 18 Mar 2024 13:11:39 -0400 Subject: [PATCH 66/78] Remove redundant bound from AuthorityIdBound. --- Cargo.lock | 12 -------- substrate/client/consensus/beefy/src/round.rs | 9 ++++++ .../primitives/consensus/beefy/src/lib.rs | 30 ++++++++++--------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b48b926c990e..4c2e8275d442 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15889,7 +15889,6 @@ dependencies = [ "sc-network-test", "sc-utils", "serde", - "smart-default", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -17620,17 +17619,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "smol" version = "1.3.0" diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 5bbd68a88229..97210875b898 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -40,6 +40,15 @@ where votes: BTreeMap::Signature>, } +impl Default for RoundTracker +where + ::Signature: Send + Sync, +{ + fn default() -> Self { + Self { votes: Default::default() } + } +} + impl RoundTracker where ::Signature: Send + Sync, diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 74f1cff4e66f..7652fc8dc6b5 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -47,7 +47,7 @@ pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; use codec::{Codec, Decode, Encode}; use core::fmt::{Debug, Display}; use scale_info::TypeInfo; -use sp_application_crypto::{AppCrypto, AppPublic, ByteArray, RuntimeAppPublic}; +use sp_application_crypto::{AppPublic, RuntimeAppPublic}; use sp_core::H256; use sp_runtime::traits::{Hash, Keccak256, NumberFor}; use sp_std::prelude::*; @@ -71,19 +71,21 @@ pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; /// A trait bound which lists all traits which are required to be implemented by /// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore pub trait AuthorityIdBound: - Codec - + Debug - + Clone - + Ord - + AsRef<[u8]> - + ByteArray - + AppPublic - + AppCrypto - + RuntimeAppPublic - + Display - + BeefyAuthorityId -{ -} + Ord + AppPublic + Display + BeefyAuthorityId { } +// pub trait AuthorityIdBound: +// Codec +// + Debug +// + Clone +// + Ord +// + AsRef<[u8]> +// + ByteArray +// + AppPublic +// + AppCrypto +// + RuntimeAppPublic +// + Display +// + BeefyAuthorityId +// { +// } /// BEEFY cryptographic types for ECDSA crypto /// From 39695283ba52f5ae2ed3c1bd4f6fc35ea8ed4484 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 18 Mar 2024 13:23:46 -0400 Subject: [PATCH 67/78] fmt --- substrate/primitives/consensus/beefy/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 7652fc8dc6b5..68059a40bbe3 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -71,7 +71,9 @@ pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; /// A trait bound which lists all traits which are required to be implemented by /// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore pub trait AuthorityIdBound: - Ord + AppPublic + Display + BeefyAuthorityId { } + Ord + AppPublic + Display + BeefyAuthorityId +{ +} // pub trait AuthorityIdBound: // Codec // + Debug From f75e3a21ce9d85f889410886522f06eedd27dad3 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 19 Mar 2024 10:10:14 -0400 Subject: [PATCH 68/78] warn if backend contains a BEEFY state of an obsolete version --- substrate/client/consensus/beefy/src/aux_schema.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index ec096a72f309..90ec47af1ef7 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -20,7 +20,7 @@ use crate::{error::Error, worker::PersistedState, LOG_TARGET}; use codec::{Decode, Encode}; -use log::{debug, trace}; +use log::{debug, trace, warn}; use sc_client_api::{backend::AuxStore, Backend}; use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{Error as ClientError, Result as ClientResult}; @@ -72,7 +72,12 @@ where match version { None => (), - Some(1) | Some(2) | Some(3) => (), // versions 1, 2 & 3 are obsolete and should be ignored + Some(1) | Some(2) | Some(3) => + // versions 1, 2 & 3 are obsolete and should be ignored + warn!( + target: LOG_TARGET, + "🥩 backend contains a BEEFY state of an obselete version {}. ignoring...", + version.expect("we already checked that it is some obselete version")), Some(4) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), other => From 5d2f33a12e862c06fd15c88c68c854a44ebca8dc Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 27 May 2024 00:50:28 -0400 Subject: [PATCH 69/78] Removing constrain on `::Signature` --- .../client/consensus/beefy/src/worker.rs | 14 +--------- .../primitives/consensus/beefy/src/lib.rs | 28 +++++++------------ 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index f1d21b06b789..a44deeae6798 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -75,10 +75,7 @@ pub(crate) enum RoundAction { /// Note: this is part of `PersistedState` so any changes here should also bump /// aux-db schema version. #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct VoterOracle -where - ::Signature: Send + Sync, -{ +pub(crate) struct VoterOracle{ /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. /// /// There are three voter states coresponding to three queue states: @@ -101,7 +98,6 @@ where impl VoterOracle where AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. pub fn checked_new( @@ -280,8 +276,6 @@ where /// Note: Any changes here should also bump aux-db schema version. #[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct PersistedState -where - ::Signature: Send + Sync, { /// Best block we voted on. best_voted: NumberFor, @@ -293,8 +287,6 @@ where } impl PersistedState -where - ::Signature: Send + Sync, { pub fn checked_new( grandpa_header: ::Header, @@ -388,8 +380,6 @@ where /// A BEEFY worker/voter that follows the BEEFY protocol pub(crate) struct BeefyWorker -where - ::Signature: Send + Sync, { // utilities pub backend: Arc, @@ -423,7 +413,6 @@ where R: ProvideRuntimeApi, R::Api: BeefyApi, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { fn best_grandpa_block(&self) -> NumberFor { *self.persisted_state.voting_oracle.best_grandpa_block_header.number() @@ -1145,7 +1134,6 @@ pub(crate) mod tests { impl PersistedState where - ::Signature: Send + Sync, { pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 68059a40bbe3..e90c047cbb88 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -71,23 +71,11 @@ pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; /// A trait bound which lists all traits which are required to be implemented by /// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore pub trait AuthorityIdBound: - Ord + AppPublic + Display + BeefyAuthorityId +Ord + AppPublic + Display + + BeefyAuthorityId { + type BoundedSignature: Debug + Eq + PartialEq + Clone + TypeInfo + Codec + Send + Sync; } -// pub trait AuthorityIdBound: -// Codec -// + Debug -// + Clone -// + Ord -// + AsRef<[u8]> -// + ByteArray -// + AppPublic -// + AppCrypto -// + RuntimeAppPublic -// + Display -// + BeefyAuthorityId -// { -// } /// BEEFY cryptographic types for ECDSA crypto /// @@ -127,7 +115,9 @@ pub mod ecdsa_crypto { } } } - impl AuthorityIdBound for AuthorityId {} + impl AuthorityIdBound for AuthorityId { + type BoundedSignature = Signature; + } } /// BEEFY cryptographic types for BLS crypto @@ -168,7 +158,8 @@ pub mod bls_crypto { BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) } } - impl AuthorityIdBound for AuthorityId {} + impl AuthorityIdBound for AuthorityId { type BoundedSignature = Signature; +} } /// BEEFY cryptographic types for (ECDSA,BLS) crypto pair @@ -216,7 +207,8 @@ pub mod ecdsa_bls_crypto { } } - impl AuthorityIdBound for AuthorityId {} + impl AuthorityIdBound for AuthorityId { type BoundedSignature = Signature; +} } /// The `ConsensusEngineId` of BEEFY. From f55e92f8146e7ad66060a740f326fcd02fd2d3f3 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 28 May 2024 01:51:12 -0400 Subject: [PATCH 70/78] fix beefy tests after merging --- .../beefy/src/communication/gossip.rs | 6 +-- substrate/client/consensus/beefy/src/round.rs | 2 +- .../client/consensus/beefy/src/worker.rs | 46 +------------------ 3 files changed, 5 insertions(+), 49 deletions(-) diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index d5005752d038..b5d4d68abda1 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -688,7 +688,7 @@ pub(crate) mod tests { let (network, mut report_stream) = TestNetwork::new(); - let gv = GossipValidator::::new( + let gv = GossipValidator::::new( Arc::new(Mutex::new(KnownPeers::new())), Arc::new(network), ); @@ -810,7 +810,7 @@ pub(crate) mod tests { fn messages_allowed_and_expired() { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let gv = GossipValidator::::new( + let gv = GossipValidator::::new( Arc::new(Mutex::new(KnownPeers::new())), Arc::new(TestNetwork::new().0), ); @@ -902,7 +902,7 @@ pub(crate) mod tests { fn messages_rebroadcast() { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let gv = GossipValidator::::new( + let gv = GossipValidator::::new( Arc::new(Mutex::new(KnownPeers::new())), Arc::new(TestNetwork::new().0), ); diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index f2ebf11e3459..fa2f8a9ba5dc 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -237,7 +237,7 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - ecdsa_cryptop, known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, DoubleVotingProof, Payload, + ecdsa_crypto, known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, DoubleVotingProof, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 83fc15e2993d..6031faffc3b9 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -1143,7 +1143,7 @@ pub(crate) mod tests { .unwrap(); let payload_provider = MmrRootProvider::new(api.clone()); let comms = BeefyComms { gossip_engine, gossip_validator, on_demand_justifications }; - let key_store: Arc> = Arc::new(Some(keystore).into()); + let key_store: Arc> = Arc::new(Some(keystore).into()); BeefyWorker { backend: backend.clone(), runtime: api.clone(), @@ -1424,50 +1424,6 @@ pub(crate) mod tests { assert_eq!(extracted, Some(validator_set)); } - #[tokio::test] - async fn keystore_vs_validator_set() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); - - // keystore doesn't contain other keys than validators' - assert_eq!( - verify_validator_set::( - &1, - &validator_set, - &worker.key_store - ), - Ok(()) - ); - - // unknown `Bob` key - let keys = &[Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let err_msg = "no authority public key found in store".to_string(); - let expected = Err(Error::Keystore(err_msg)); - assert_eq!( - verify_validator_set::( - &1, - &validator_set, - &worker.key_store - ), - expected - ); - - // worker has no keystore - worker.key_store = None.into(); - let expected_err = Err(Error::Keystore("no Keystore".into())); - assert_eq!( - verify_validator_set::( - &1, - &validator_set, - &worker.key_store - ), - expected_err - ); - } - #[tokio::test] async fn should_finalize_correctly() { let keys = [Keyring::Alice]; From 99ab160339760d4e4e0f89f9743607aff5639a37 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 28 May 2024 16:21:45 -0400 Subject: [PATCH 71/78] unwrap beefy justification to pass test --- substrate/client/consensus/beefy/src/justification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 2d8496764ace..349e26de53f9 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -50,7 +50,7 @@ where { let proof = >::decode_all(&mut &*encoded) .map_err(|_| (ConsensusError::InvalidJustification, 0))?; - verify_with_validator_set::(target_number, validator_set, &proof); + verify_with_validator_set::(target_number, validator_set, &proof)?; Ok(proof) } From 8bf7a40c6d1c12cb7712e0e33ce660de516ea9f8 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 28 May 2024 21:51:43 -0400 Subject: [PATCH 72/78] Remove all remaining `::Signature: Send + Sync,` constraints --- .../client/consensus/beefy/src/aux_schema.rs | 3 --- .../consensus/beefy/src/communication/gossip.rs | 16 +--------------- .../request_response/outgoing_requests_engine.rs | 10 ---------- substrate/client/consensus/beefy/src/import.rs | 8 -------- .../client/consensus/beefy/src/justification.rs | 4 ---- substrate/client/consensus/beefy/src/keystore.rs | 2 -- substrate/client/consensus/beefy/src/lib.rs | 15 --------------- substrate/client/consensus/beefy/src/round.rs | 11 ----------- 8 files changed, 1 insertion(+), 68 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 90ec47af1ef7..dd06f9905d3b 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -43,8 +43,6 @@ pub(crate) fn write_voter_state, ) -> ClientResult<()> -where - ::Signature: Send + Sync, { trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); AuxStore::insert_aux(backend, &[(WORKER_STATE_KEY, state.encode().as_slice())], &[]) @@ -66,7 +64,6 @@ pub(crate) fn load_persistent( where B: BlockT, BE: Backend, - ::Signature: Send + Sync, { let version: Option = load_decode(backend, VERSION_KEY)?; diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index b5d4d68abda1..91ad2c040409 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -71,8 +71,6 @@ enum Consider { /// BEEFY gossip message type that gets encoded and sent on the network. #[derive(Debug, Encode, Decode)] pub(crate) enum GossipMessage -where - ::Signature: Send + Sync, { /// BEEFY message with commitment and single signature. Vote(VoteMessage, AuthorityId, ::Signature>), @@ -81,8 +79,6 @@ where } impl GossipMessage -where - ::Signature: Send + Sync, { /// Return inner vote if this message is a Vote. pub fn unwrap_vote( @@ -122,8 +118,6 @@ where #[derive(Clone, Debug)] pub(crate) struct GossipFilterCfg<'a, B: Block, AuthorityId: AuthorityIdBound> -where - ::Signature: Send + Sync, { pub start: NumberFor, pub end: NumberFor, @@ -132,8 +126,6 @@ where #[derive(Clone, Debug)] struct FilterInner -where - ::Signature: Send + Sync, { pub start: NumberFor, pub end: NumberFor, @@ -141,8 +133,6 @@ where } struct Filter -where - ::Signature: Send + Sync, { // specifies live rounds inner: Option>, @@ -151,8 +141,6 @@ where } impl Filter -where - ::Signature: Send + Sync, { pub fn new() -> Self { Self { inner: None, rounds_with_valid_proofs: BTreeSet::new() } @@ -242,7 +230,6 @@ where pub(crate) struct GossipValidator where B: Block, - ::Signature: Send + Sync, { votes_topic: B::Hash, justifs_topic: B::Hash, @@ -256,11 +243,10 @@ impl GossipValidator where B: Block, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { pub(crate) fn new(known_peers: Arc>>, network: Arc) -> Self { Self { - votes_topic: votes_topic::(), + votes_topic: votes_topic::(), justifs_topic: proofs_topic::(), gossip_filter: RwLock::new(Filter::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), diff --git a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index a46c9245722f..cacae5e6a503 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -51,16 +51,12 @@ type ResponseReceiver = oneshot::Receiver; #[derive(Clone, Debug)] struct RequestInfo -where - ::Signature: Send + Sync, { block: NumberFor, active_set: ValidatorSet, } enum State -where - ::Signature: Send + Sync, { Idle, AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), @@ -68,8 +64,6 @@ where /// Possible engine responses. pub(crate) enum ResponseInfo -where - ::Signature: Send + Sync, { /// No peer response available yet. Pending, @@ -80,8 +74,6 @@ where } pub struct OnDemandJustificationsEngine -where - ::Signature: Send + Sync, { network: Arc, protocol_name: ProtocolName, @@ -94,8 +86,6 @@ where } impl OnDemandJustificationsEngine -where - ::Signature: Send + Sync, { pub fn new( network: Arc, diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index 362103ec8e06..3f5cfc924a13 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -47,8 +47,6 @@ use crate::{ /// /// When using BEEFY, the block import worker should be using this block import object. pub struct BeefyBlockImport -where - ::Signature: Send + Sync, { backend: Arc, runtime: Arc, @@ -59,8 +57,6 @@ where impl Clone for BeefyBlockImport -where - ::Signature: Send + Sync, { fn clone(&self) -> Self { BeefyBlockImport { @@ -75,8 +71,6 @@ where impl BeefyBlockImport -where - ::Signature: Send + Sync, { /// Create a new BeefyBlockImport. pub fn new( @@ -97,7 +91,6 @@ where Runtime: ProvideRuntimeApi, Runtime::Api: BeefyApi + Send, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { fn decode_and_verify( &self, @@ -137,7 +130,6 @@ where Runtime: ProvideRuntimeApi + Send + Sync, Runtime::Api: BeefyApi, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { type Error = ConsensusError; diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 349e26de53f9..f9a2145b1929 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -30,8 +30,6 @@ pub type BeefyVersionedFinalityProof = pub(crate) fn proof_block_num_and_set_id( proof: &BeefyVersionedFinalityProof, ) -> (NumberFor, ValidatorSetId) -where - ::Signature: Send + Sync, { match proof { VersionedFinalityProof::V1(sc) => @@ -45,8 +43,6 @@ pub(crate) fn decode_and_verify_finality_proof, validator_set: &ValidatorSet, ) -> Result, (ConsensusError, u32)> -where - ::Signature: Send + Sync, { let proof = >::decode_all(&mut &*encoded) .map_err(|_| (ConsensusError::InvalidJustification, 0))?; diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 81895a08204f..bf025d029e5b 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -176,8 +176,6 @@ impl BeefyKeystore { } impl From> for BeefyKeystore -where - ::Signature: Send + Sync, { fn from(store: Option) -> BeefyKeystore { BeefyKeystore(store, PhantomData) diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 38f266bd5420..9d12fd996904 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -120,8 +120,6 @@ where /// to be used by the voter. #[derive(Clone)] pub struct BeefyVoterLinks -where - ::Signature: Send + Sync, { // BlockImport -> Voter links /// Stream of BEEFY signed commitments from block import to voter. @@ -137,8 +135,6 @@ where /// Links used by the BEEFY RPC layer, from the BEEFY background voter. #[derive(Clone)] pub struct BeefyRPCLinks -where - ::Signature: Send + Sync, { /// Stream of signed commitments coming from the voter. pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, @@ -164,7 +160,6 @@ where RuntimeApi: ProvideRuntimeApi + Send + Sync, RuntimeApi::Api: BeefyApi, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = @@ -215,8 +210,6 @@ pub struct BeefyNetworkParams { /// BEEFY gadget initialization parameters. pub struct BeefyParams -where - ::Signature: Send + Sync, { /// BEEFY client pub client: Arc, @@ -245,8 +238,6 @@ where /// /// These are created once, but will be reused if worker is restarted/reinitialized. pub(crate) struct BeefyComms -where - ::Signature: Send + Sync, { pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, @@ -260,8 +251,6 @@ where /// GossipEngine. Once initialization is done, the GossipEngine (and other pieces) are added to get /// the complete [worker::BeefyWorker] object. pub(crate) struct BeefyWorkerBuilder -where - ::Signature: Send + Sync, { // utilities backend: Arc, @@ -279,7 +268,6 @@ where R: ProvideRuntimeApi, R::Api: BeefyApi, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { /// This will wait for the chain to enable BEEFY (if not yet enabled) and also wait for the /// backend to sync all headers required by the voter to build a contiguous chain of mandatory @@ -518,7 +506,6 @@ pub async fn start_beefy_gadget( N: GossipNetwork + NetworkRequest + Send + Sync + 'static, S: GossipSyncing + SyncOracle + 'static, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { let BeefyParams { client, @@ -685,7 +672,6 @@ where B: Block, R: ProvideRuntimeApi, R::Api: BeefyApi, - ::Signature: Send + Sync, { info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); loop { @@ -724,7 +710,6 @@ where BE: Backend, R: ProvideRuntimeApi, R::Api: BeefyApi, - ::Signature: Send + Sync, { let blockchain = backend.blockchain(); // Walk up the chain looking for the validator set active at 'at_header'. Process both state and diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index fa2f8a9ba5dc..486ea19d000e 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -34,15 +34,11 @@ use std::collections::BTreeMap; /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct RoundTracker -where - ::Signature: Send + Sync, { votes: BTreeMap::Signature>, } impl Default for RoundTracker -where - ::Signature: Send + Sync, { fn default() -> Self { Self { votes: Default::default() } @@ -50,8 +46,6 @@ where } impl RoundTracker -where - ::Signature: Send + Sync, { fn add_vote( &mut self, @@ -78,8 +72,6 @@ pub fn threshold(authorities: usize) -> usize { #[derive(Debug, PartialEq)] pub enum VoteImportResult -where - ::Signature: Send + Sync, { Ok, RoundConcluded(SignedCommitment, ::Signature>), @@ -95,8 +87,6 @@ where /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct Rounds -where - ::Signature: Send + Sync, { rounds: BTreeMap>, RoundTracker>, previous_votes: BTreeMap< @@ -113,7 +103,6 @@ impl Rounds where B: Block, AuthorityId: AuthorityIdBound, - ::Signature: Send + Sync, { pub(crate) fn new( session_start: NumberFor, From 7c42d8bfcdfd85538a05d852aa501bb3191f7947 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 28 May 2024 21:55:24 -0400 Subject: [PATCH 73/78] Do `cargo +nightly fmt` --- .../client/consensus/beefy/src/aux_schema.rs | 7 +-- .../beefy/src/communication/gossip.rs | 45 ++++++++-------- .../incoming_requests_handler.rs | 4 +- .../outgoing_requests_engine.rs | 21 +++----- .../client/consensus/beefy/src/fisherman.rs | 24 +++++---- .../client/consensus/beefy/src/import.rs | 7 ++- .../consensus/beefy/src/justification.rs | 21 ++++---- .../client/consensus/beefy/src/keystore.rs | 3 +- substrate/client/consensus/beefy/src/lib.rs | 39 +++++++------- substrate/client/consensus/beefy/src/round.rs | 34 ++++++------ substrate/client/consensus/beefy/src/tests.rs | 2 +- .../client/consensus/beefy/src/worker.rs | 53 +++++++++---------- .../primitives/consensus/beefy/src/lib.rs | 24 +++++---- 13 files changed, 140 insertions(+), 144 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index dd06f9905d3b..11557eeb8f2a 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -42,8 +42,7 @@ pub(crate) fn write_current_version(backend: &BE) -> Result<(), Er pub(crate) fn write_voter_state( backend: &BE, state: &PersistedState, -) -> ClientResult<()> -{ +) -> ClientResult<()> { trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); AuxStore::insert_aux(backend, &[(WORKER_STATE_KEY, state.encode().as_slice())], &[]) } @@ -71,10 +70,12 @@ where None => (), Some(1) | Some(2) | Some(3) => // versions 1, 2 & 3 are obsolete and should be ignored + { warn!( target: LOG_TARGET, "🥩 backend contains a BEEFY state of an obselete version {}. ignoring...", - version.expect("we already checked that it is some obselete version")), + version.expect("we already checked that it is some obselete version")) + }, Some(4) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), other => diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 91ad2c040409..6a1439c98043 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -37,7 +37,9 @@ use crate::{ LOG_TARGET, }; use sp_application_crypto::RuntimeAppPublic; -use sp_consensus_beefy::{AuthorityIdBound, ValidatorSet, ValidatorSetId, VoteMessage, ecdsa_crypto::AuthorityId}; +use sp_consensus_beefy::{ + ecdsa_crypto::AuthorityId, AuthorityIdBound, ValidatorSet, ValidatorSetId, VoteMessage, +}; // Timeout for rebroadcasting messages. #[cfg(not(test))] @@ -70,16 +72,14 @@ enum Consider { /// BEEFY gossip message type that gets encoded and sent on the network. #[derive(Debug, Encode, Decode)] -pub(crate) enum GossipMessage -{ +pub(crate) enum GossipMessage { /// BEEFY message with commitment and single signature. Vote(VoteMessage, AuthorityId, ::Signature>), /// BEEFY justification with commitment and signatures. FinalityProof(BeefyVersionedFinalityProof), } -impl GossipMessage -{ +impl GossipMessage { /// Return inner vote if this message is a Vote. pub fn unwrap_vote( self, @@ -117,31 +117,27 @@ where } #[derive(Clone, Debug)] -pub(crate) struct GossipFilterCfg<'a, B: Block, AuthorityId: AuthorityIdBound> -{ +pub(crate) struct GossipFilterCfg<'a, B: Block, AuthorityId: AuthorityIdBound> { pub start: NumberFor, pub end: NumberFor, pub validator_set: &'a ValidatorSet, } #[derive(Clone, Debug)] -struct FilterInner -{ +struct FilterInner { pub start: NumberFor, pub end: NumberFor, pub validator_set: ValidatorSet, } -struct Filter -{ +struct Filter { // specifies live rounds inner: Option>, // cache of seen valid justifications in active rounds rounds_with_valid_proofs: BTreeSet>, } -impl Filter -{ +impl Filter { pub fn new() -> Self { Self { inner: None, rounds_with_valid_proofs: BTreeSet::new() } } @@ -239,14 +235,14 @@ where network: Arc, } -impl GossipValidator +impl GossipValidator where B: Block, AuthorityId: AuthorityIdBound, { pub(crate) fn new(known_peers: Arc>>, network: Arc) -> Self { Self { - votes_topic: votes_topic::(), + votes_topic: votes_topic::(), justifs_topic: proofs_topic::(), gossip_filter: RwLock::new(Filter::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), @@ -271,8 +267,8 @@ where impl GossipValidator where B: Block, - N: NetworkPeers, -AuthorityId: AuthorityIdBound, + N: NetworkPeers, + AuthorityId: AuthorityIdBound, { fn report(&self, who: PeerId, cost_benefit: ReputationChange) { self.network.report_peer(who, cost_benefit); @@ -308,7 +304,7 @@ AuthorityId: AuthorityIdBound, .unwrap_or(false) { debug!(target: LOG_TARGET, "Message from voter not in validator set: {}", vote.id); - return Action::Discard(cost::UNKNOWN_VOTER) + return Action::Discard(cost::UNKNOWN_VOTER); } } @@ -345,7 +341,7 @@ AuthorityId: AuthorityIdBound, } if guard.is_already_proven(round) { - return Action::Discard(benefit::NOT_INTERESTED) + return Action::Discard(benefit::NOT_INTERESTED); } // Verify justification signatures. @@ -467,7 +463,7 @@ where let filter = self.gossip_filter.read(); Box::new(move |_who, intent, _topic, mut data| { if let MessageIntent::PeriodicRebroadcast = intent { - return do_rebroadcast + return do_rebroadcast; } match GossipMessage::::decode_all(&mut data) { @@ -670,7 +666,8 @@ pub(crate) mod tests { #[test] fn should_validate_messages() { let keys = vec![Keyring::::Alice.public()]; - let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); + let validator_set = + ValidatorSet::::new(keys.clone(), 0).unwrap(); let (network, mut report_stream) = TestNetwork::new(); @@ -795,7 +792,8 @@ pub(crate) mod tests { #[test] fn messages_allowed_and_expired() { let keys = vec![Keyring::Alice.public()]; - let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); + let validator_set = + ValidatorSet::::new(keys.clone(), 0).unwrap(); let gv = GossipValidator::::new( Arc::new(Mutex::new(KnownPeers::new())), Arc::new(TestNetwork::new().0), @@ -887,7 +885,8 @@ pub(crate) mod tests { #[test] fn messages_rebroadcast() { let keys = vec![Keyring::Alice.public()]; - let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); + let validator_set = + ValidatorSet::::new(keys.clone(), 0).unwrap(); let gv = GossipValidator::::new( Arc::new(Mutex::new(KnownPeers::new())), Arc::new(TestNetwork::new().0), diff --git a/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs b/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs index 7893066a01e0..350e7a271bc3 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -87,9 +87,9 @@ impl IncomingRequest { sent_feedback: None, }; if let Err(_) = pending_response.send(response) { - return Err(Error::DecodingErrorNoReputationChange(peer, err)) + return Err(Error::DecodingErrorNoReputationChange(peer, err)); } - return Err(Error::DecodingError(peer, err)) + return Err(Error::DecodingError(peer, err)); }, }; Ok(Self::new(peer, payload, pending_response)) diff --git a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index cacae5e6a503..8bfadb70c8d6 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -50,21 +50,18 @@ type Response = Result<(Vec, ProtocolName), RequestFailure>; type ResponseReceiver = oneshot::Receiver; #[derive(Clone, Debug)] -struct RequestInfo -{ +struct RequestInfo { block: NumberFor, active_set: ValidatorSet, } -enum State -{ +enum State { Idle, AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), } /// Possible engine responses. -pub(crate) enum ResponseInfo -{ +pub(crate) enum ResponseInfo { /// No peer response available yet. Pending, /// Valid justification provided alongside peer reputation changes. @@ -73,8 +70,7 @@ pub(crate) enum ResponseInfo PeerReport(PeerReport), } -pub struct OnDemandJustificationsEngine -{ +pub struct OnDemandJustificationsEngine { network: Arc, protocol_name: ProtocolName, @@ -85,8 +81,7 @@ pub struct OnDemandJustificationsEngine metrics: Option, } -impl OnDemandJustificationsEngine -{ +impl OnDemandJustificationsEngine { pub fn new( network: Arc, protocol_name: ProtocolName, @@ -112,7 +107,7 @@ impl OnDemandJustificationsEngine OnDemandJustificationsEngine, active_set: ValidatorSet) { // ignore new requests while there's already one pending if matches!(self.state, State::AwaitingResponse(_, _, _)) { - return + return; } self.reset_peers_cache_for_block(block); @@ -237,7 +232,7 @@ impl OnDemandJustificationsEngine { futures::future::pending::<()>().await; - return ResponseInfo::Pending + return ResponseInfo::Pending; }, State::AwaitingResponse(peer, req_info, receiver) => { let resp = receiver.await; diff --git a/substrate/client/consensus/beefy/src/fisherman.rs b/substrate/client/consensus/beefy/src/fisherman.rs index 999cfc181f23..073fee0bdbdb 100644 --- a/substrate/client/consensus/beefy/src/fisherman.rs +++ b/substrate/client/consensus/beefy/src/fisherman.rs @@ -17,15 +17,14 @@ // along with this program. If not, see . use crate::{error::Error, keystore::BeefyKeystore, round::Rounds, LOG_TARGET}; -use sp_application_crypto::RuntimeAppPublic; use log::{debug, error, warn}; use sc_client_api::Backend; use sp_api::ProvideRuntimeApi; +use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::HeaderBackend; use sp_consensus_beefy::{ - check_equivocation_proof, - AuthorityIdBound, - BeefyApi, BeefySignatureHasher, DoubleVotingProof, OpaqueKeyOwnershipProof, ValidatorSetId, + check_equivocation_proof, AuthorityIdBound, BeefyApi, BeefySignatureHasher, DoubleVotingProof, + OpaqueKeyOwnershipProof, ValidatorSetId, }; use sp_runtime::{ generic::BlockId, @@ -48,10 +47,11 @@ pub struct Fisherman { _phantom: PhantomData, } -impl, RuntimeApi: ProvideRuntimeApi, AuthorityId> Fisherman +impl, RuntimeApi: ProvideRuntimeApi, AuthorityId> + Fisherman where - RuntimeApi::Api: BeefyApi, - AuthorityId: AuthorityIdBound, + RuntimeApi::Api: BeefyApi, + AuthorityId: AuthorityIdBound, { pub fn new( backend: Arc, @@ -121,7 +121,11 @@ where /// isn't necessarily the best block if there are pending authority set changes. pub fn report_double_voting( &self, - proof: DoubleVotingProof, AuthorityId, ::Signature>, + proof: DoubleVotingProof< + NumberFor, + AuthorityId, + ::Signature, + >, active_rounds: &Rounds, ) -> Result<(), Error> { let (validators, validator_set_id) = @@ -130,13 +134,13 @@ where if !check_equivocation_proof::<_, _, BeefySignatureHasher>(&proof) { debug!(target: LOG_TARGET, "🥩 Skipping report for bad equivocation {:?}", proof); - return Ok(()) + return Ok(()); } if let Some(local_id) = self.key_store.authority_id(validators) { if offender_id == &local_id { warn!(target: LOG_TARGET, "🥩 Skipping report for own equivocation"); - return Ok(()) + return Ok(()); } } diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index 3f5cfc924a13..f1148c6dcf32 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -46,8 +46,7 @@ use crate::{ /// Wraps a `inner: BlockImport` and ultimately defers to it. /// /// When using BEEFY, the block import worker should be using this block import object. -pub struct BeefyBlockImport -{ +pub struct BeefyBlockImport { backend: Arc, runtime: Arc, inner: I, @@ -106,7 +105,7 @@ where .map_err(|e| ImportError(e.to_string()))? .ok_or_else(|| ImportError("Unknown BEEFY genesis".to_string()))?; if number < beefy_genesis { - return Err(ImportError("BEEFY genesis is set for future block".to_string())) + return Err(ImportError("BEEFY genesis is set for future block".to_string())); } let validator_set = self .runtime @@ -157,7 +156,7 @@ where // The block is imported as part of some chain sync. // The voter doesn't need to process it now. // It will be detected and processed as part of the voter state init. - return Ok(inner_import_result) + return Ok(inner_import_result); }, } diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index f9a2145b1929..a977a0a513bb 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -20,7 +20,10 @@ use crate::keystore::BeefyKeystore; use codec::{DecodeAll, Encode}; use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; -use sp_consensus_beefy::{AuthorityIdBound, ValidatorSet, ValidatorSetId, VersionedFinalityProof, BeefySignatureHasher, KnownSignature,}; +use sp_consensus_beefy::{ + AuthorityIdBound, BeefySignatureHasher, KnownSignature, ValidatorSet, ValidatorSetId, + VersionedFinalityProof, +}; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// A finality proof with matching BEEFY authorities' signatures. @@ -29,8 +32,7 @@ pub type BeefyVersionedFinalityProof = pub(crate) fn proof_block_num_and_set_id( proof: &BeefyVersionedFinalityProof, -) -> (NumberFor, ValidatorSetId) -{ +) -> (NumberFor, ValidatorSetId) { match proof { VersionedFinalityProof::V1(sc) => (sc.commitment.block_number, sc.commitment.validator_set_id), @@ -42,12 +44,11 @@ pub(crate) fn decode_and_verify_finality_proof, validator_set: &ValidatorSet, -) -> Result, (ConsensusError, u32)> -{ +) -> Result, (ConsensusError, u32)> { let proof = >::decode_all(&mut &*encoded) .map_err(|_| (ConsensusError::InvalidJustification, 0))?; - verify_with_validator_set::(target_number, validator_set, &proof)?; - Ok(proof) + verify_with_validator_set::(target_number, validator_set, &proof)?; + Ok(proof) } /// Verify the Beefy finality proof against the validator set at the block it was generated. @@ -55,8 +56,10 @@ pub(crate) fn verify_with_validator_set<'a, Block: BlockT, AuthorityId: Authorit target_number: NumberFor, validator_set: &'a ValidatorSet, proof: &'a BeefyVersionedFinalityProof, -) -> Result::Signature>>, (ConsensusError, u32)> -{ +) -> Result< + Vec::Signature>>, + (ConsensusError, u32), +> { let mut signatures_checked = 0u32; match proof { VersionedFinalityProof::V1(signed_commitment) => { diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index bf025d029e5b..8daf3440c7d2 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -175,8 +175,7 @@ impl BeefyKeystore { } } -impl From> for BeefyKeystore -{ +impl From> for BeefyKeystore { fn from(store: Option) -> BeefyKeystore { BeefyKeystore(store, PhantomData) } diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 9d12fd996904..0a954857a299 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -119,8 +119,7 @@ where /// Links between the block importer, the background voter and the RPC layer, /// to be used by the voter. #[derive(Clone)] -pub struct BeefyVoterLinks -{ +pub struct BeefyVoterLinks { // BlockImport -> Voter links /// Stream of BEEFY signed commitments from block import to voter. pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, @@ -134,8 +133,7 @@ pub struct BeefyVoterLinks /// Links used by the BEEFY RPC layer, from the BEEFY background voter. #[derive(Clone)] -pub struct BeefyRPCLinks -{ +pub struct BeefyRPCLinks { /// Stream of signed commitments coming from the voter. pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, /// Stream of BEEFY best block hashes coming from the voter. @@ -209,8 +207,7 @@ pub struct BeefyNetworkParams { } /// BEEFY gadget initialization parameters. -pub struct BeefyParams -{ +pub struct BeefyParams { /// BEEFY client pub client: Arc, /// Client Backend @@ -237,8 +234,7 @@ pub struct BeefyParams -{ +pub(crate) struct BeefyComms { pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, pub on_demand_justifications: OnDemandJustificationsEngine, @@ -250,8 +246,7 @@ pub(crate) struct BeefyComms /// for certain chain and backend conditions, and while sleeping we still need to pump the /// GossipEngine. Once initialization is done, the GossipEngine (and other pieces) are added to get /// the complete [worker::BeefyWorker] object. -pub(crate) struct BeefyWorkerBuilder -{ +pub(crate) struct BeefyWorkerBuilder { // utilities backend: Arc, runtime: Arc, @@ -390,7 +385,7 @@ where beefy_genesis, ) .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))?; - break state + break state; } if *header.number() == beefy_genesis { @@ -413,7 +408,7 @@ where min_block_delta, beefy_genesis, ) - .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))? + .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))?; } if let Some(active) = find_authorities_change::(&header) { @@ -483,7 +478,7 @@ where is_authority, ); } - return Ok(state) + return Ok(state); } // No valid voter-state persisted, re-initialize from pallet genesis. @@ -611,15 +606,17 @@ pub async fn start_beefy_gadget( futures::future::Either::Left(((error::Error::ConsensusReset, reuse_comms), _)) => { error!(target: LOG_TARGET, "🥩 Error: {:?}. Restarting voter.", error::Error::ConsensusReset); beefy_comms = reuse_comms; - continue + continue; }, // On other errors, bring down / finish the task. - futures::future::Either::Left(((worker_err, _), _)) => - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", worker_err), - futures::future::Either::Right((odj_handler_err, _)) => - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", odj_handler_err), + futures::future::Either::Left(((worker_err, _), _)) => { + error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", worker_err) + }, + futures::future::Either::Right((odj_handler_err, _)) => { + error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", odj_handler_err) + }, }; - return + return; } } @@ -689,7 +686,7 @@ where "🥩 BEEFY pallet available: block {:?} beefy genesis {:?}", notif.header.number(), start ); - return Ok((start, notif.header)) + return Ok((start, notif.header)); } } } @@ -724,7 +721,7 @@ where loop { debug!(target: LOG_TARGET, "🥩 Looking for auth set change at block number: {:?}", *header.number()); if let Ok(Some(active)) = runtime.runtime_api().validator_set(header.hash()) { - return Ok(active) + return Ok(active); } else { match find_authorities_change::(&header) { Some(active) => return Ok(active), diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 486ea19d000e..31cfe4c10c2e 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -33,26 +33,23 @@ use std::collections::BTreeMap; /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct RoundTracker -{ +pub(crate) struct RoundTracker { votes: BTreeMap::Signature>, } -impl Default for RoundTracker -{ +impl Default for RoundTracker { fn default() -> Self { Self { votes: Default::default() } } } -impl RoundTracker -{ +impl RoundTracker { fn add_vote( &mut self, vote: (AuthorityId, ::Signature), ) -> bool { if self.votes.contains_key(&vote.0) { - return false + return false; } self.votes.insert(vote.0, vote.1); @@ -71,11 +68,11 @@ pub fn threshold(authorities: usize) -> usize { } #[derive(Debug, PartialEq)] -pub enum VoteImportResult -{ +pub enum VoteImportResult { Ok, RoundConcluded(SignedCommitment, ::Signature>), - DoubleVoting(DoubleVotingProof, AuthorityId, ::Signature>, + DoubleVoting( + DoubleVotingProof, AuthorityId, ::Signature>, ), Invalid, Stale, @@ -86,8 +83,7 @@ pub enum VoteImportResult /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct Rounds -{ +pub(crate) struct Rounds { rounds: BTreeMap>, RoundTracker>, previous_votes: BTreeMap< (AuthorityId, NumberFor), @@ -147,7 +143,7 @@ where if num < self.session_start || Some(num) <= self.best_done { debug!(target: LOG_TARGET, "🥩 received vote for old stale round {:?}, ignoring", num); - return VoteImportResult::Stale + return VoteImportResult::Stale; } else if vote.commitment.validator_set_id != self.validator_set_id() { debug!( target: LOG_TARGET, @@ -155,14 +151,14 @@ where self.validator_set_id(), vote, ); - return VoteImportResult::Invalid + return VoteImportResult::Invalid; } else if !self.validators().iter().any(|id| &vote.id == id) { debug!( target: LOG_TARGET, "🥩 received vote {:?} from validator that is not in the validator set, ignoring", vote ); - return VoteImportResult::Invalid + return VoteImportResult::Invalid; } if let Some(previous_vote) = self.previous_votes.get(&vote_key) { @@ -175,7 +171,7 @@ where return VoteImportResult::DoubleVoting(DoubleVotingProof { first: previous_vote.clone(), second: vote, - }) + }); } } else { // this is the first vote sent by `id` for `num`, all good @@ -188,7 +184,7 @@ where round.is_done(threshold(self.validator_set.len())) { if let Some(round) = self.rounds.remove_entry(&vote.commitment) { - return VoteImportResult::RoundConcluded(self.signed_commitment(round)) + return VoteImportResult::RoundConcluded(self.signed_commitment(round)); } } VoteImportResult::Ok @@ -226,8 +222,8 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - ecdsa_crypto, known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, DoubleVotingProof, Payload, - SignedCommitment, ValidatorSet, VoteMessage, + ecdsa_crypto, known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, + DoubleVotingProof, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; use super::{threshold, Block as BlockT, RoundTracker, Rounds}; diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index e04f5a9b4419..681e11a0c531 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -1421,7 +1421,7 @@ async fn beefy_reports_equivocations() { for wait_ms in [250, 500, 1250, 3000] { run_for(Duration::from_millis(wait_ms), &net).await; if !api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty() { - break + break; } } diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 6031faffc3b9..638e42b3a158 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -42,9 +42,8 @@ use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ - AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, - DoubleVotingProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, - BEEFY_ENGINE_ID, + AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, DoubleVotingProof, + PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::BlockId, @@ -75,7 +74,7 @@ pub(crate) enum RoundAction { /// Note: this is part of `PersistedState` so any changes here should also bump /// aux-db schema version. #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct VoterOracle{ +pub(crate) struct VoterOracle { /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. /// /// There are three voter states corresponding to three queue states: @@ -112,24 +111,24 @@ where let mut validate = || -> bool { let best_grandpa = *grandpa_header.number(); if sessions.is_empty() || best_beefy > best_grandpa { - return false + return false; } for (idx, session) in sessions.iter().enumerate() { let start = session.session_start(); if session.validators().is_empty() { - return false + return false; } if start > best_grandpa || start <= prev_start { - return false + return false; } #[cfg(not(test))] if let Some(prev_id) = prev_validator_id { if session.validator_set_id() <= prev_id { - return false + return false; } } if idx != 0 && session.mandatory_done() { - return false + return false; } prev_start = session.session_start(); prev_validator_id = Some(session.validator_set_id()); @@ -275,8 +274,7 @@ where /// /// Note: Any changes here should also bump aux-db schema version. #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct PersistedState -{ +pub(crate) struct PersistedState { /// Best block we voted on. best_voted: NumberFor, /// Chooses which incoming votes to accept and which votes to generate. @@ -286,8 +284,7 @@ pub(crate) struct PersistedState pallet_genesis: NumberFor, } -impl PersistedState -{ +impl PersistedState { pub fn checked_new( grandpa_header: ::Header, best_beefy: NumberFor, @@ -383,8 +380,7 @@ impl PersistedState } /// A BEEFY worker/voter that follows the BEEFY protocol -pub(crate) struct BeefyWorker -{ +pub(crate) struct BeefyWorker { // utilities pub backend: Arc, pub runtime: Arc, @@ -593,7 +589,7 @@ where // New state is persisted after finalization. self.finalize(finality_proof.clone())?; metric_inc!(self.metrics, beefy_good_votes_processed); - return Ok(Some(finality_proof)) + return Ok(Some(finality_proof)); }, VoteImportResult::Ok => { // Persist state after handling mandatory block vote. @@ -635,7 +631,7 @@ where if block_num <= self.persisted_state.voting_oracle.best_beefy_block { // we've already finalized this round before, short-circuit. - return Ok(()) + return Ok(()); } // Finalize inner round and update voting_oracle state. @@ -760,7 +756,7 @@ where hash } else { warn!(target: LOG_TARGET, "🥩 No MMR root digest found for: {:?}", target_hash); - return Ok(()) + return Ok(()); }; let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; @@ -774,7 +770,7 @@ where target: LOG_TARGET, "🥩 Missing validator id - can't vote for: {:?}", target_hash ); - return Ok(()) + return Ok(()); }; let commitment = Commitment { payload, block_number: target_number, validator_set_id }; @@ -784,7 +780,7 @@ where Ok(sig) => sig, Err(err) => { warn!(target: LOG_TARGET, "🥩 Error signing commitment: {:?}", err); - return Ok(()) + return Ok(()); }, }; @@ -970,7 +966,11 @@ where /// Report the given equivocation to the BEEFY runtime module. fn report_double_voting( &self, - proof: DoubleVotingProof, AuthorityId, ::Signature>, + proof: DoubleVotingProof< + NumberFor, + AuthorityId, + ::Signature, + >, ) -> Result<(), Error> { let rounds = self.persisted_state.voting_oracle.active_rounds()?; self.fisherman.report_double_voting(proof, rounds) @@ -1048,9 +1048,7 @@ pub(crate) mod tests { Backend, }; - impl PersistedState - where - { + impl PersistedState { pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() } @@ -1077,8 +1075,8 @@ pub(crate) mod tests { MmrRootProvider, TestApi, Arc>, - TestNetwork, - ecdsa_crypto::AuthorityId, + TestNetwork, + ecdsa_crypto::AuthorityId, > { let keystore = create_beefy_keystore(key); @@ -1143,7 +1141,8 @@ pub(crate) mod tests { .unwrap(); let payload_provider = MmrRootProvider::new(api.clone()); let comms = BeefyComms { gossip_engine, gossip_validator, on_demand_justifications }; - let key_store: Arc> = Arc::new(Some(keystore).into()); + let key_store: Arc> = + Arc::new(Some(keystore).into()); BeefyWorker { backend: backend.clone(), runtime: api.clone(), diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 85103a8297f6..7a951d267712 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -76,10 +76,12 @@ pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; /// A trait bound which lists all traits which are required to be implemented by /// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore pub trait AuthorityIdBound: -Ord + AppPublic + Display - + BeefyAuthorityId + Ord + + AppPublic + + Display + + BeefyAuthorityId { - type BoundedSignature: Debug + Eq + PartialEq + Clone + TypeInfo + Codec + Send + Sync; + type BoundedSignature: Debug + Eq + PartialEq + Clone + TypeInfo + Codec + Send + Sync; } /// BEEFY cryptographic types for ECDSA crypto @@ -120,9 +122,9 @@ pub mod ecdsa_crypto { } } } - impl AuthorityIdBound for AuthorityId { - type BoundedSignature = Signature; - } + impl AuthorityIdBound for AuthorityId { + type BoundedSignature = Signature; + } } /// BEEFY cryptographic types for BLS crypto @@ -163,8 +165,9 @@ pub mod bls_crypto { BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) } } - impl AuthorityIdBound for AuthorityId { type BoundedSignature = Signature; -} + impl AuthorityIdBound for AuthorityId { + type BoundedSignature = Signature; + } } /// BEEFY cryptographic types for (ECDSA,BLS) crypto pair @@ -212,8 +215,9 @@ pub mod ecdsa_bls_crypto { } } - impl AuthorityIdBound for AuthorityId { type BoundedSignature = Signature; -} + impl AuthorityIdBound for AuthorityId { + type BoundedSignature = Signature; + } } /// The `ConsensusEngineId` of BEEFY. From a326523ad4259fec7eed00148a2685982cd888ea Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 28 May 2024 22:08:34 -0400 Subject: [PATCH 74/78] Remove redundant imports resolve all warnings --- substrate/client/consensus/beefy/src/aux_schema.rs | 1 - substrate/client/consensus/beefy/src/communication/gossip.rs | 4 +--- .../request_response/outgoing_requests_engine.rs | 1 - substrate/client/consensus/beefy/src/import.rs | 1 - substrate/client/consensus/beefy/src/justification.rs | 4 +--- substrate/client/consensus/beefy/src/lib.rs | 4 +--- substrate/client/consensus/beefy/src/worker.rs | 4 ++-- substrate/primitives/consensus/beefy/src/lib.rs | 1 + 8 files changed, 6 insertions(+), 14 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 11557eeb8f2a..b0f4b8480c9c 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -22,7 +22,6 @@ use crate::{error::Error, worker::PersistedState, LOG_TARGET}; use codec::{Decode, Encode}; use log::{debug, trace, warn}; use sc_client_api::{backend::AuxStore, Backend}; -use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sp_consensus_beefy::AuthorityIdBound; use sp_runtime::traits::Block as BlockT; diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 6a1439c98043..95cac250b7c5 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -37,9 +37,7 @@ use crate::{ LOG_TARGET, }; use sp_application_crypto::RuntimeAppPublic; -use sp_consensus_beefy::{ - ecdsa_crypto::AuthorityId, AuthorityIdBound, ValidatorSet, ValidatorSetId, VoteMessage, -}; +use sp_consensus_beefy::{AuthorityIdBound, ValidatorSet, ValidatorSetId, VoteMessage}; // Timeout for rebroadcasting messages. #[cfg(not(test))] diff --git a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index 8bfadb70c8d6..4d40656375ec 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -27,7 +27,6 @@ use sc_network::{ NetworkRequest, ProtocolName, }; use sc_network_types::PeerId; -use sp_application_crypto::RuntimeAppPublic; use sp_consensus_beefy::{AuthorityIdBound, ValidatorSet}; use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index f1148c6dcf32..c01fb3db4845 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -21,7 +21,6 @@ use std::sync::Arc; use log::debug; use sp_api::ProvideRuntimeApi; -use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{AuthorityIdBound, BeefyApi, BEEFY_ENGINE_ID}; use sp_runtime::{ diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index a977a0a513bb..9ff7c3cf54f6 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -16,8 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::keystore::BeefyKeystore; -use codec::{DecodeAll, Encode}; +use codec::DecodeAll; use sp_application_crypto::RuntimeAppPublic; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{ @@ -60,7 +59,6 @@ pub(crate) fn verify_with_validator_set<'a, Block: BlockT, AuthorityId: Authorit Vec::Signature>>, (ConsensusError, u32), > { - let mut signatures_checked = 0u32; match proof { VersionedFinalityProof::V1(signed_commitment) => { let signatories = signed_commitment diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 0a954857a299..4cb014b00d5b 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -40,12 +40,10 @@ use sc_consensus::BlockImport; use sc_network::{NetworkRequest, NotificationService, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::ProvideRuntimeApi; -use sp_application_crypto::RuntimeAppPublic; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_consensus_beefy::{ - AuthorityIdBound, BeefyApi, ConsensusLog, MmrRootHash, PayloadProvider, ValidatorSet, - BEEFY_ENGINE_ID, + AuthorityIdBound, BeefyApi, ConsensusLog, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, }; use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 638e42b3a158..3ce4da7ecd56 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -42,8 +42,8 @@ use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ - AuthorityIdBound, BeefyApi, BeefySignatureHasher, Commitment, DoubleVotingProof, - PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + AuthorityIdBound, BeefyApi, Commitment, DoubleVotingProof, PayloadProvider, ValidatorSet, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::BlockId, diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 7a951d267712..3d6e43217f5f 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -81,6 +81,7 @@ pub trait AuthorityIdBound: + Display + BeefyAuthorityId { + /// Necessary bounds on the Signature associated with the AuthorityId type BoundedSignature: Debug + Eq + PartialEq + Clone + TypeInfo + Codec + Send + Sync; } From 725fc2c8823c8364adabd488c87dfb53daefe65f Mon Sep 17 00:00:00 2001 From: Skalman Date: Wed, 29 May 2024 03:27:36 -0400 Subject: [PATCH 75/78] make @davxy happy --- substrate/client/consensus/beefy/src/aux_schema.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index b0f4b8480c9c..1922494ad112 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -67,14 +67,10 @@ where match version { None => (), - Some(1) | Some(2) | Some(3) => + + Some(v) if 1 <= v && v <= 3 => // versions 1, 2 & 3 are obsolete and should be ignored - { - warn!( - target: LOG_TARGET, - "🥩 backend contains a BEEFY state of an obselete version {}. ignoring...", - version.expect("we already checked that it is some obselete version")) - }, + warn!(target: LOG_TARGET, "🥩 backend contains a BEEFY state of an obsolete version {v}. ignoring..."), Some(4) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), other => From d834a1dcf0c38bd33df1064dc8a87f073685c11e Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Wed, 29 May 2024 07:31:28 -0400 Subject: [PATCH 76/78] Remove empty line from substrate/primitives/consensus/beefy/src/lib.rs Co-authored-by: Davide Galassi --- substrate/primitives/consensus/beefy/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 3d6e43217f5f..913184402aef 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -296,7 +296,6 @@ pub enum ConsensusLog { /// /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. - // TODO: Remove `Signature` generic type, instead get it from `Id::Signature`. #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct VoteMessage { From f65096e0cf866de8e2032399448181db2045c018 Mon Sep 17 00:00:00 2001 From: Skalman Date: Wed, 29 May 2024 12:20:01 -0400 Subject: [PATCH 77/78] add beefy_primitisto cli/service --- substrate/bin/node/cli/src/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index a040b221d471..3243db15d3ed 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -20,7 +20,7 @@ //! Service implementation. Specialized wrapper over substrate service. -use polkadot_sdk::{sc_consensus_beefy as beefy, sc_consensus_grandpa as grandpa, *}; +use polkadot_sdk::{sc_consensus_beefy as beefy, sp_consensus_beefy as beefy_primitives, sc_consensus_grandpa as grandpa, *}; use crate::Cli; use codec::Encode; From cfc59ed5a11162b52621c1329cc5d72d058100ff Mon Sep 17 00:00:00 2001 From: Skalman Date: Wed, 29 May 2024 12:34:14 -0400 Subject: [PATCH 78/78] fmt --- substrate/bin/node/cli/src/service.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 3243db15d3ed..e57ca04f3b74 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -20,7 +20,10 @@ //! Service implementation. Specialized wrapper over substrate service. -use polkadot_sdk::{sc_consensus_beefy as beefy, sp_consensus_beefy as beefy_primitives, sc_consensus_grandpa as grandpa, *}; +use polkadot_sdk::{ + sc_consensus_beefy as beefy, sc_consensus_grandpa as grandpa, + sp_consensus_beefy as beefy_primitives, *, +}; use crate::Cli; use codec::Encode;