mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 20:21:03 +00:00
Beefy: use VersionedFinalityProof instead of SignedCommitment (#11962)
* beefy: use VersionedFinalityProof instead of SignedCommitment. * Change the exposed RPC API to support versioned proofs. Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
@@ -35,7 +35,7 @@ use jsonrpsee::{
|
|||||||
};
|
};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use beefy_gadget::notification::{BeefyBestBlockStream, BeefySignedCommitmentStream};
|
use beefy_gadget::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream};
|
||||||
|
|
||||||
mod notification;
|
mod notification;
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ pub trait BeefyApi<Notification, Hash> {
|
|||||||
|
|
||||||
/// Implements the BeefyApi RPC trait for interacting with BEEFY.
|
/// Implements the BeefyApi RPC trait for interacting with BEEFY.
|
||||||
pub struct Beefy<Block: BlockT> {
|
pub struct Beefy<Block: BlockT> {
|
||||||
signed_commitment_stream: BeefySignedCommitmentStream<Block>,
|
finality_proof_stream: BeefyVersionedFinalityProofStream<Block>,
|
||||||
beefy_best_block: Arc<RwLock<Option<Block::Hash>>>,
|
beefy_best_block: Arc<RwLock<Option<Block::Hash>>>,
|
||||||
executor: SubscriptionTaskExecutor,
|
executor: SubscriptionTaskExecutor,
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Creates a new Beefy Rpc handler instance.
|
/// Creates a new Beefy Rpc handler instance.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
signed_commitment_stream: BeefySignedCommitmentStream<Block>,
|
finality_proof_stream: BeefyVersionedFinalityProofStream<Block>,
|
||||||
best_block_stream: BeefyBestBlockStream<Block>,
|
best_block_stream: BeefyBestBlockStream<Block>,
|
||||||
executor: SubscriptionTaskExecutor,
|
executor: SubscriptionTaskExecutor,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
@@ -126,20 +126,21 @@ where
|
|||||||
});
|
});
|
||||||
|
|
||||||
executor.spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed());
|
executor.spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed());
|
||||||
Ok(Self { signed_commitment_stream, beefy_best_block, executor })
|
Ok(Self { finality_proof_stream, beefy_best_block, executor })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<Block> BeefyApiServer<notification::EncodedSignedCommitment, Block::Hash> for Beefy<Block>
|
impl<Block> BeefyApiServer<notification::EncodedVersionedFinalityProof, Block::Hash>
|
||||||
|
for Beefy<Block>
|
||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
{
|
{
|
||||||
fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult {
|
fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult {
|
||||||
let stream = self
|
let stream = self
|
||||||
.signed_commitment_stream
|
.finality_proof_stream
|
||||||
.subscribe()
|
.subscribe()
|
||||||
.map(|sc| notification::EncodedSignedCommitment::new::<Block>(sc));
|
.map(|vfp| notification::EncodedVersionedFinalityProof::new::<Block>(vfp));
|
||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
sink.pipe_from_stream(stream).await;
|
sink.pipe_from_stream(stream).await;
|
||||||
@@ -164,31 +165,31 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use beefy_gadget::{
|
use beefy_gadget::{
|
||||||
justification::BeefySignedCommitment,
|
justification::BeefyVersionedFinalityProof,
|
||||||
notification::{BeefyBestBlockStream, BeefySignedCommitmentSender},
|
notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofSender},
|
||||||
};
|
};
|
||||||
use beefy_primitives::{known_payload_ids, Payload};
|
use beefy_primitives::{known_payload_ids, Payload, SignedCommitment};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use jsonrpsee::{types::EmptyParams, RpcModule};
|
use jsonrpsee::{types::EmptyParams, RpcModule};
|
||||||
use sp_runtime::traits::{BlakeTwo256, Hash};
|
use sp_runtime::traits::{BlakeTwo256, Hash};
|
||||||
use substrate_test_runtime_client::runtime::Block;
|
use substrate_test_runtime_client::runtime::Block;
|
||||||
|
|
||||||
fn setup_io_handler() -> (RpcModule<Beefy<Block>>, BeefySignedCommitmentSender<Block>) {
|
fn setup_io_handler() -> (RpcModule<Beefy<Block>>, BeefyVersionedFinalityProofSender<Block>) {
|
||||||
let (_, stream) = BeefyBestBlockStream::<Block>::channel();
|
let (_, stream) = BeefyBestBlockStream::<Block>::channel();
|
||||||
setup_io_handler_with_best_block_stream(stream)
|
setup_io_handler_with_best_block_stream(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_io_handler_with_best_block_stream(
|
fn setup_io_handler_with_best_block_stream(
|
||||||
best_block_stream: BeefyBestBlockStream<Block>,
|
best_block_stream: BeefyBestBlockStream<Block>,
|
||||||
) -> (RpcModule<Beefy<Block>>, BeefySignedCommitmentSender<Block>) {
|
) -> (RpcModule<Beefy<Block>>, BeefyVersionedFinalityProofSender<Block>) {
|
||||||
let (commitment_sender, commitment_stream) =
|
let (finality_proof_sender, finality_proof_stream) =
|
||||||
BeefySignedCommitmentStream::<Block>::channel();
|
BeefyVersionedFinalityProofStream::<Block>::channel();
|
||||||
|
|
||||||
let handler =
|
let handler =
|
||||||
Beefy::new(commitment_stream, best_block_stream, sc_rpc::testing::test_executor())
|
Beefy::new(finality_proof_stream, best_block_stream, sc_rpc::testing::test_executor())
|
||||||
.expect("Setting up the BEEFY RPC handler works");
|
.expect("Setting up the BEEFY RPC handler works");
|
||||||
|
|
||||||
(handler.into_rpc(), commitment_sender)
|
(handler.into_rpc(), finality_proof_sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -262,21 +263,21 @@ mod tests {
|
|||||||
assert_eq!(response.result, expected);
|
assert_eq!(response.result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_commitment() -> BeefySignedCommitment<Block> {
|
fn create_finality_proof() -> BeefyVersionedFinalityProof<Block> {
|
||||||
let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode());
|
let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode());
|
||||||
BeefySignedCommitment::<Block> {
|
BeefyVersionedFinalityProof::<Block>::V1(SignedCommitment {
|
||||||
commitment: beefy_primitives::Commitment {
|
commitment: beefy_primitives::Commitment {
|
||||||
payload,
|
payload,
|
||||||
block_number: 5,
|
block_number: 5,
|
||||||
validator_set_id: 0,
|
validator_set_id: 0,
|
||||||
},
|
},
|
||||||
signatures: vec![],
|
signatures: vec![],
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn subscribe_and_listen_to_one_justification() {
|
async fn subscribe_and_listen_to_one_justification() {
|
||||||
let (rpc, commitment_sender) = setup_io_handler();
|
let (rpc, finality_proof_sender) = setup_io_handler();
|
||||||
|
|
||||||
// Subscribe
|
// Subscribe
|
||||||
let mut sub = rpc
|
let mut sub = rpc
|
||||||
@@ -284,16 +285,16 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Notify with commitment
|
// Notify with finality_proof
|
||||||
let commitment = create_commitment();
|
let finality_proof = create_finality_proof();
|
||||||
let r: Result<(), ()> = commitment_sender.notify(|| Ok(commitment.clone()));
|
let r: Result<(), ()> = finality_proof_sender.notify(|| Ok(finality_proof.clone()));
|
||||||
r.unwrap();
|
r.unwrap();
|
||||||
|
|
||||||
// Inspect what we received
|
// Inspect what we received
|
||||||
let (bytes, recv_sub_id) = sub.next::<sp_core::Bytes>().await.unwrap().unwrap();
|
let (bytes, recv_sub_id) = sub.next::<sp_core::Bytes>().await.unwrap().unwrap();
|
||||||
let recv_commitment: BeefySignedCommitment<Block> =
|
let recv_finality_proof: BeefyVersionedFinalityProof<Block> =
|
||||||
Decode::decode(&mut &bytes[..]).unwrap();
|
Decode::decode(&mut &bytes[..]).unwrap();
|
||||||
assert_eq!(&recv_sub_id, sub.subscription_id());
|
assert_eq!(&recv_sub_id, sub.subscription_id());
|
||||||
assert_eq!(recv_commitment, commitment);
|
assert_eq!(recv_finality_proof, finality_proof);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,19 +21,19 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
|
|
||||||
/// An encoded signed commitment proving that the given header has been finalized.
|
/// An encoded finality proof proving that the given header has been finalized.
|
||||||
/// The given bytes should be the SCALE-encoded representation of a
|
/// The given bytes should be the SCALE-encoded representation of a
|
||||||
/// `beefy_primitives::SignedCommitment`.
|
/// `beefy_primitives::VersionedFinalityProof`.
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct EncodedSignedCommitment(sp_core::Bytes);
|
pub struct EncodedVersionedFinalityProof(sp_core::Bytes);
|
||||||
|
|
||||||
impl EncodedSignedCommitment {
|
impl EncodedVersionedFinalityProof {
|
||||||
pub fn new<Block>(
|
pub fn new<Block>(
|
||||||
signed_commitment: beefy_gadget::justification::BeefySignedCommitment<Block>,
|
finality_proof: beefy_gadget::justification::BeefyVersionedFinalityProof<Block>,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
{
|
{
|
||||||
EncodedSignedCommitment(signed_commitment.encode().into())
|
EncodedVersionedFinalityProof(finality_proof.encode().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use beefy_primitives::{crypto::Signature, BeefyApi, VersionedFinalityProof, BEEFY_ENGINE_ID};
|
use beefy_primitives::{BeefyApi, BEEFY_ENGINE_ID};
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
@@ -34,7 +34,8 @@ use sc_client_api::backend::Backend;
|
|||||||
use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult};
|
use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
justification::decode_and_verify_commitment, notification::BeefySignedCommitmentSender,
|
justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof},
|
||||||
|
notification::BeefyVersionedFinalityProofSender,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A block-import handler for BEEFY.
|
/// A block-import handler for BEEFY.
|
||||||
@@ -47,7 +48,7 @@ pub struct BeefyBlockImport<Block: BlockT, Backend, RuntimeApi, I> {
|
|||||||
backend: Arc<Backend>,
|
backend: Arc<Backend>,
|
||||||
runtime: Arc<RuntimeApi>,
|
runtime: Arc<RuntimeApi>,
|
||||||
inner: I,
|
inner: I,
|
||||||
justification_sender: BeefySignedCommitmentSender<Block>,
|
justification_sender: BeefyVersionedFinalityProofSender<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT, BE, Runtime, I: Clone> Clone for BeefyBlockImport<Block, BE, Runtime, I> {
|
impl<Block: BlockT, BE, Runtime, I: Clone> Clone for BeefyBlockImport<Block, BE, Runtime, I> {
|
||||||
@@ -67,7 +68,7 @@ impl<Block: BlockT, BE, Runtime, I> BeefyBlockImport<Block, BE, Runtime, I> {
|
|||||||
backend: Arc<BE>,
|
backend: Arc<BE>,
|
||||||
runtime: Arc<Runtime>,
|
runtime: Arc<Runtime>,
|
||||||
inner: I,
|
inner: I,
|
||||||
justification_sender: BeefySignedCommitmentSender<Block>,
|
justification_sender: BeefyVersionedFinalityProofSender<Block>,
|
||||||
) -> BeefyBlockImport<Block, BE, Runtime, I> {
|
) -> BeefyBlockImport<Block, BE, Runtime, I> {
|
||||||
BeefyBlockImport { backend, runtime, inner, justification_sender }
|
BeefyBlockImport { backend, runtime, inner, justification_sender }
|
||||||
}
|
}
|
||||||
@@ -85,7 +86,7 @@ where
|
|||||||
encoded: &EncodedJustification,
|
encoded: &EncodedJustification,
|
||||||
number: NumberFor<Block>,
|
number: NumberFor<Block>,
|
||||||
hash: <Block as BlockT>::Hash,
|
hash: <Block as BlockT>::Hash,
|
||||||
) -> Result<VersionedFinalityProof<NumberFor<Block>, Signature>, ConsensusError> {
|
) -> Result<BeefyVersionedFinalityProof<Block>, ConsensusError> {
|
||||||
let block_id = BlockId::hash(hash);
|
let block_id = BlockId::hash(hash);
|
||||||
let validator_set = self
|
let validator_set = self
|
||||||
.runtime
|
.runtime
|
||||||
@@ -94,7 +95,7 @@ where
|
|||||||
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?
|
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?
|
||||||
.ok_or_else(|| ConsensusError::ClientImport("Unknown validator set".to_string()))?;
|
.ok_or_else(|| ConsensusError::ClientImport("Unknown validator set".to_string()))?;
|
||||||
|
|
||||||
decode_and_verify_commitment::<Block>(&encoded[..], number, &validator_set)
|
decode_and_verify_finality_proof::<Block>(&encoded[..], number, &validator_set)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import BEEFY justification: Send it to worker for processing and also append it to backend.
|
/// Import BEEFY justification: Send it to worker for processing and also append it to backend.
|
||||||
@@ -105,7 +106,7 @@ where
|
|||||||
fn import_beefy_justification_unchecked(
|
fn import_beefy_justification_unchecked(
|
||||||
&self,
|
&self,
|
||||||
number: NumberFor<Block>,
|
number: NumberFor<Block>,
|
||||||
justification: VersionedFinalityProof<NumberFor<Block>, Signature>,
|
justification: BeefyVersionedFinalityProof<Block>,
|
||||||
) {
|
) {
|
||||||
// Append the justification to the block in the backend.
|
// Append the justification to the block in the backend.
|
||||||
if let Err(e) = self.backend.append_justification(
|
if let Err(e) = self.backend.append_justification(
|
||||||
@@ -115,14 +116,9 @@ where
|
|||||||
error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, justification);
|
error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, justification);
|
||||||
}
|
}
|
||||||
// Send the justification to the BEEFY voter for processing.
|
// Send the justification to the BEEFY voter for processing.
|
||||||
match justification {
|
self.justification_sender
|
||||||
// TODO #11838: Should not unpack, these channels should also use
|
.notify(|| Ok::<_, ()>(justification))
|
||||||
// `VersionedFinalityProof`.
|
.expect("forwards closure result; the closure always returns Ok; qed.");
|
||||||
VersionedFinalityProof::V1(signed_commitment) => self
|
|
||||||
.justification_sender
|
|
||||||
.notify(|| Ok::<_, ()>(signed_commitment))
|
|
||||||
.expect("forwards closure result; the closure always returns Ok; qed."),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,17 +25,17 @@ use codec::{Decode, Encode};
|
|||||||
use sp_consensus::Error as ConsensusError;
|
use sp_consensus::Error as ConsensusError;
|
||||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||||
|
|
||||||
/// A commitment with matching BEEFY authorities' signatures.
|
/// A finality proof with matching BEEFY authorities' signatures.
|
||||||
pub type BeefySignedCommitment<Block> =
|
pub type BeefyVersionedFinalityProof<Block> =
|
||||||
beefy_primitives::SignedCommitment<NumberFor<Block>, beefy_primitives::crypto::Signature>;
|
beefy_primitives::VersionedFinalityProof<NumberFor<Block>, Signature>;
|
||||||
|
|
||||||
/// Decode and verify a Beefy SignedCommitment.
|
/// Decode and verify a Beefy FinalityProof.
|
||||||
pub(crate) fn decode_and_verify_commitment<Block: BlockT>(
|
pub(crate) fn decode_and_verify_finality_proof<Block: BlockT>(
|
||||||
encoded: &[u8],
|
encoded: &[u8],
|
||||||
target_number: NumberFor<Block>,
|
target_number: NumberFor<Block>,
|
||||||
validator_set: &ValidatorSet<AuthorityId>,
|
validator_set: &ValidatorSet<AuthorityId>,
|
||||||
) -> Result<VersionedFinalityProof<NumberFor<Block>, Signature>, ConsensusError> {
|
) -> Result<BeefyVersionedFinalityProof<Block>, ConsensusError> {
|
||||||
let proof = <VersionedFinalityProof<NumberFor<Block>, Signature>>::decode(&mut &*encoded)
|
let proof = <BeefyVersionedFinalityProof<Block>>::decode(&mut &*encoded)
|
||||||
.map_err(|_| ConsensusError::InvalidJustification)?;
|
.map_err(|_| ConsensusError::InvalidJustification)?;
|
||||||
verify_with_validator_set::<Block>(target_number, validator_set, &proof).map(|_| proof)
|
verify_with_validator_set::<Block>(target_number, validator_set, &proof).map(|_| proof)
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ pub(crate) fn decode_and_verify_commitment<Block: BlockT>(
|
|||||||
fn verify_with_validator_set<Block: BlockT>(
|
fn verify_with_validator_set<Block: BlockT>(
|
||||||
target_number: NumberFor<Block>,
|
target_number: NumberFor<Block>,
|
||||||
validator_set: &ValidatorSet<AuthorityId>,
|
validator_set: &ValidatorSet<AuthorityId>,
|
||||||
proof: &VersionedFinalityProof<NumberFor<Block>, Signature>,
|
proof: &BeefyVersionedFinalityProof<Block>,
|
||||||
) -> Result<(), ConsensusError> {
|
) -> Result<(), ConsensusError> {
|
||||||
match proof {
|
match proof {
|
||||||
VersionedFinalityProof::V1(signed_commitment) => {
|
VersionedFinalityProof::V1(signed_commitment) => {
|
||||||
@@ -80,17 +80,19 @@ fn verify_with_validator_set<Block: BlockT>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use beefy_primitives::{known_payload_ids, Commitment, Payload, SignedCommitment};
|
use beefy_primitives::{
|
||||||
|
known_payload_ids, Commitment, Payload, SignedCommitment, VersionedFinalityProof,
|
||||||
|
};
|
||||||
use substrate_test_runtime_client::runtime::Block;
|
use substrate_test_runtime_client::runtime::Block;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{keystore::tests::Keyring, tests::make_beefy_ids};
|
use crate::{keystore::tests::Keyring, tests::make_beefy_ids};
|
||||||
|
|
||||||
pub(crate) fn new_signed_commitment(
|
pub(crate) fn new_finality_proof(
|
||||||
block_num: NumberFor<Block>,
|
block_num: NumberFor<Block>,
|
||||||
validator_set: &ValidatorSet<AuthorityId>,
|
validator_set: &ValidatorSet<AuthorityId>,
|
||||||
keys: &[Keyring],
|
keys: &[Keyring],
|
||||||
) -> BeefySignedCommitment<Block> {
|
) -> BeefyVersionedFinalityProof<Block> {
|
||||||
let commitment = Commitment {
|
let commitment = Commitment {
|
||||||
payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]),
|
payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]),
|
||||||
block_number: block_num,
|
block_number: block_num,
|
||||||
@@ -98,7 +100,7 @@ pub(crate) mod tests {
|
|||||||
};
|
};
|
||||||
let message = commitment.encode();
|
let message = commitment.encode();
|
||||||
let signatures = keys.iter().map(|key| Some(key.sign(&message))).collect();
|
let signatures = keys.iter().map(|key| Some(key.sign(&message))).collect();
|
||||||
SignedCommitment { commitment, signatures }
|
VersionedFinalityProof::V1(SignedCommitment { commitment, signatures })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -108,7 +110,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
// build valid justification
|
// build valid justification
|
||||||
let block_num = 42;
|
let block_num = 42;
|
||||||
let proof = new_signed_commitment(block_num, &validator_set, keys);
|
let proof = new_finality_proof(block_num, &validator_set, keys);
|
||||||
|
|
||||||
let good_proof = proof.clone().into();
|
let good_proof = proof.clone().into();
|
||||||
// should verify successfully
|
// should verify successfully
|
||||||
@@ -132,7 +134,10 @@ pub(crate) mod tests {
|
|||||||
// wrong signatures length -> should fail verification
|
// wrong signatures length -> should fail verification
|
||||||
let mut bad_proof = proof.clone();
|
let mut bad_proof = proof.clone();
|
||||||
// change length of signatures
|
// change length of signatures
|
||||||
bad_proof.signatures.pop().flatten().unwrap();
|
let bad_signed_commitment = match bad_proof {
|
||||||
|
VersionedFinalityProof::V1(ref mut sc) => sc,
|
||||||
|
};
|
||||||
|
bad_signed_commitment.signatures.pop().flatten().unwrap();
|
||||||
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
|
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
|
||||||
Err(ConsensusError::InvalidJustification) => (),
|
Err(ConsensusError::InvalidJustification) => (),
|
||||||
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
|
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
|
||||||
@@ -140,8 +145,11 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
// not enough signatures -> should fail verification
|
// not enough signatures -> should fail verification
|
||||||
let mut bad_proof = proof.clone();
|
let mut bad_proof = proof.clone();
|
||||||
|
let bad_signed_commitment = match bad_proof {
|
||||||
|
VersionedFinalityProof::V1(ref mut sc) => sc,
|
||||||
|
};
|
||||||
// remove a signature (but same length)
|
// remove a signature (but same length)
|
||||||
*bad_proof.signatures.first_mut().unwrap() = None;
|
*bad_signed_commitment.signatures.first_mut().unwrap() = None;
|
||||||
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
|
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
|
||||||
Err(ConsensusError::InvalidJustification) => (),
|
Err(ConsensusError::InvalidJustification) => (),
|
||||||
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
|
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
|
||||||
@@ -149,9 +157,12 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
// not enough _correct_ signatures -> should fail verification
|
// not enough _correct_ signatures -> should fail verification
|
||||||
let mut bad_proof = proof.clone();
|
let mut bad_proof = proof.clone();
|
||||||
|
let bad_signed_commitment = match bad_proof {
|
||||||
|
VersionedFinalityProof::V1(ref mut sc) => sc,
|
||||||
|
};
|
||||||
// change a signature to a different key
|
// change a signature to a different key
|
||||||
*bad_proof.signatures.first_mut().unwrap() =
|
*bad_signed_commitment.signatures.first_mut().unwrap() =
|
||||||
Some(Keyring::Dave.sign(&proof.commitment.encode()));
|
Some(Keyring::Dave.sign(&bad_signed_commitment.commitment.encode()));
|
||||||
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
|
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
|
||||||
Err(ConsensusError::InvalidJustification) => (),
|
Err(ConsensusError::InvalidJustification) => (),
|
||||||
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
|
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
|
||||||
@@ -159,19 +170,19 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_decode_and_verify_commitment() {
|
fn should_decode_and_verify_finality_proof() {
|
||||||
let keys = &[Keyring::Alice, Keyring::Bob];
|
let keys = &[Keyring::Alice, Keyring::Bob];
|
||||||
let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap();
|
let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap();
|
||||||
let block_num = 1;
|
let block_num = 1;
|
||||||
|
|
||||||
// build valid justification
|
// build valid justification
|
||||||
let proof = new_signed_commitment(block_num, &validator_set, keys);
|
let proof = new_finality_proof(block_num, &validator_set, keys);
|
||||||
let versioned_proof: VersionedFinalityProof<NumberFor<Block>, Signature> = proof.into();
|
let versioned_proof: BeefyVersionedFinalityProof<Block> = proof.into();
|
||||||
let encoded = versioned_proof.encode();
|
let encoded = versioned_proof.encode();
|
||||||
|
|
||||||
// should successfully decode and verify
|
// should successfully decode and verify
|
||||||
let verified =
|
let verified =
|
||||||
decode_and_verify_commitment::<Block>(&encoded, block_num, &validator_set).unwrap();
|
decode_and_verify_finality_proof::<Block>(&encoded, block_num, &validator_set).unwrap();
|
||||||
assert_eq!(verified, versioned_proof);
|
assert_eq!(verified, versioned_proof);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ mod tests;
|
|||||||
use crate::{
|
use crate::{
|
||||||
import::BeefyBlockImport,
|
import::BeefyBlockImport,
|
||||||
notification::{
|
notification::{
|
||||||
BeefyBestBlockSender, BeefyBestBlockStream, BeefySignedCommitmentSender,
|
BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender,
|
||||||
BeefySignedCommitmentStream,
|
BeefyVersionedFinalityProofStream,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -121,11 +121,11 @@ where
|
|||||||
pub struct BeefyVoterLinks<B: Block> {
|
pub struct BeefyVoterLinks<B: Block> {
|
||||||
// BlockImport -> Voter links
|
// BlockImport -> Voter links
|
||||||
/// Stream of BEEFY signed commitments from block import to voter.
|
/// Stream of BEEFY signed commitments from block import to voter.
|
||||||
pub from_block_import_justif_stream: BeefySignedCommitmentStream<B>,
|
pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream<B>,
|
||||||
|
|
||||||
// Voter -> RPC links
|
// Voter -> RPC links
|
||||||
/// Sends BEEFY signed commitments from voter to RPC.
|
/// Sends BEEFY signed commitments from voter to RPC.
|
||||||
pub to_rpc_justif_sender: BeefySignedCommitmentSender<B>,
|
pub to_rpc_justif_sender: BeefyVersionedFinalityProofSender<B>,
|
||||||
/// Sends BEEFY best block hashes from voter to RPC.
|
/// Sends BEEFY best block hashes from voter to RPC.
|
||||||
pub to_rpc_best_block_sender: BeefyBestBlockSender<B>,
|
pub to_rpc_best_block_sender: BeefyBestBlockSender<B>,
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ pub struct BeefyVoterLinks<B: Block> {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BeefyRPCLinks<B: Block> {
|
pub struct BeefyRPCLinks<B: Block> {
|
||||||
/// Stream of signed commitments coming from the voter.
|
/// Stream of signed commitments coming from the voter.
|
||||||
pub from_voter_justif_stream: BeefySignedCommitmentStream<B>,
|
pub from_voter_justif_stream: BeefyVersionedFinalityProofStream<B>,
|
||||||
/// Stream of BEEFY best block hashes coming from the voter.
|
/// Stream of BEEFY best block hashes coming from the voter.
|
||||||
pub from_voter_best_beefy_stream: BeefyBestBlockStream<B>,
|
pub from_voter_best_beefy_stream: BeefyBestBlockStream<B>,
|
||||||
}
|
}
|
||||||
@@ -156,13 +156,13 @@ where
|
|||||||
{
|
{
|
||||||
// Voter -> RPC links
|
// Voter -> RPC links
|
||||||
let (to_rpc_justif_sender, from_voter_justif_stream) =
|
let (to_rpc_justif_sender, from_voter_justif_stream) =
|
||||||
notification::BeefySignedCommitmentStream::<B>::channel();
|
notification::BeefyVersionedFinalityProofStream::<B>::channel();
|
||||||
let (to_rpc_best_block_sender, from_voter_best_beefy_stream) =
|
let (to_rpc_best_block_sender, from_voter_best_beefy_stream) =
|
||||||
notification::BeefyBestBlockStream::<B>::channel();
|
notification::BeefyBestBlockStream::<B>::channel();
|
||||||
|
|
||||||
// BlockImport -> Voter links
|
// BlockImport -> Voter links
|
||||||
let (to_voter_justif_sender, from_block_import_justif_stream) =
|
let (to_voter_justif_sender, from_block_import_justif_stream) =
|
||||||
notification::BeefySignedCommitmentStream::<B>::channel();
|
notification::BeefyVersionedFinalityProofStream::<B>::channel();
|
||||||
|
|
||||||
// BlockImport
|
// BlockImport
|
||||||
let import =
|
let import =
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr};
|
use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
|
|
||||||
use crate::justification::BeefySignedCommitment;
|
use crate::justification::BeefyVersionedFinalityProof;
|
||||||
|
|
||||||
/// The sending half of the notifications channel(s) used to send
|
/// The sending half of the notifications channel(s) used to send
|
||||||
/// notifications about best BEEFY block from the gadget side.
|
/// notifications about best BEEFY block from the gadget side.
|
||||||
@@ -31,13 +31,14 @@ pub type BeefyBestBlockStream<Block> =
|
|||||||
NotificationStream<<Block as BlockT>::Hash, BeefyBestBlockTracingKey>;
|
NotificationStream<<Block as BlockT>::Hash, BeefyBestBlockTracingKey>;
|
||||||
|
|
||||||
/// The sending half of the notifications channel(s) used to send notifications
|
/// The sending half of the notifications channel(s) used to send notifications
|
||||||
/// about signed commitments generated at the end of a BEEFY round.
|
/// about versioned finality proof generated at the end of a BEEFY round.
|
||||||
pub type BeefySignedCommitmentSender<Block> = NotificationSender<BeefySignedCommitment<Block>>;
|
pub type BeefyVersionedFinalityProofSender<Block> =
|
||||||
|
NotificationSender<BeefyVersionedFinalityProof<Block>>;
|
||||||
|
|
||||||
/// The receiving half of a notifications channel used to receive notifications
|
/// The receiving half of a notifications channel used to receive notifications
|
||||||
/// about signed commitments generated at the end of a BEEFY round.
|
/// about versioned finality proof generated at the end of a BEEFY round.
|
||||||
pub type BeefySignedCommitmentStream<Block> =
|
pub type BeefyVersionedFinalityProofStream<Block> =
|
||||||
NotificationStream<BeefySignedCommitment<Block>, BeefySignedCommitmentTracingKey>;
|
NotificationStream<BeefyVersionedFinalityProof<Block>, BeefyVersionedFinalityProofTracingKey>;
|
||||||
|
|
||||||
/// Provides tracing key for BEEFY best block stream.
|
/// Provides tracing key for BEEFY best block stream.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -46,9 +47,9 @@ impl TracingKeyStr for BeefyBestBlockTracingKey {
|
|||||||
const TRACING_KEY: &'static str = "mpsc_beefy_best_block_notification_stream";
|
const TRACING_KEY: &'static str = "mpsc_beefy_best_block_notification_stream";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides tracing key for BEEFY signed commitments stream.
|
/// Provides tracing key for BEEFY versioned finality proof stream.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BeefySignedCommitmentTracingKey;
|
pub struct BeefyVersionedFinalityProofTracingKey;
|
||||||
impl TracingKeyStr for BeefySignedCommitmentTracingKey {
|
impl TracingKeyStr for BeefyVersionedFinalityProofTracingKey {
|
||||||
const TRACING_KEY: &'static str = "mpsc_beefy_signed_commitments_notification_stream";
|
const TRACING_KEY: &'static str = "mpsc_beefy_versioned_finality_proof_notification_stream";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,17 +397,18 @@ fn run_for(duration: Duration, net: &Arc<Mutex<BeefyTestNet>>, runtime: &mut Run
|
|||||||
pub(crate) fn get_beefy_streams(
|
pub(crate) fn get_beefy_streams(
|
||||||
net: &mut BeefyTestNet,
|
net: &mut BeefyTestNet,
|
||||||
peers: &[BeefyKeyring],
|
peers: &[BeefyKeyring],
|
||||||
) -> (Vec<NotificationReceiver<H256>>, Vec<NotificationReceiver<BeefySignedCommitment<Block>>>) {
|
) -> (Vec<NotificationReceiver<H256>>, Vec<NotificationReceiver<BeefyVersionedFinalityProof<Block>>>)
|
||||||
|
{
|
||||||
let mut best_block_streams = Vec::new();
|
let mut best_block_streams = Vec::new();
|
||||||
let mut signed_commitment_streams = Vec::new();
|
let mut versioned_finality_proof_streams = Vec::new();
|
||||||
for peer_id in 0..peers.len() {
|
for peer_id in 0..peers.len() {
|
||||||
let beefy_rpc_links = net.peer(peer_id).data.beefy_rpc_links.lock().clone().unwrap();
|
let beefy_rpc_links = net.peer(peer_id).data.beefy_rpc_links.lock().clone().unwrap();
|
||||||
let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } =
|
let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } =
|
||||||
beefy_rpc_links;
|
beefy_rpc_links;
|
||||||
best_block_streams.push(from_voter_best_beefy_stream.subscribe());
|
best_block_streams.push(from_voter_best_beefy_stream.subscribe());
|
||||||
signed_commitment_streams.push(from_voter_justif_stream.subscribe());
|
versioned_finality_proof_streams.push(from_voter_justif_stream.subscribe());
|
||||||
}
|
}
|
||||||
(best_block_streams, signed_commitment_streams)
|
(best_block_streams, versioned_finality_proof_streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_best_beefy_blocks(
|
fn wait_for_best_beefy_blocks(
|
||||||
@@ -437,7 +438,7 @@ fn wait_for_best_beefy_blocks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_beefy_signed_commitments(
|
fn wait_for_beefy_signed_commitments(
|
||||||
streams: Vec<NotificationReceiver<BeefySignedCommitment<Block>>>,
|
streams: Vec<NotificationReceiver<BeefyVersionedFinalityProof<Block>>>,
|
||||||
net: &Arc<Mutex<BeefyTestNet>>,
|
net: &Arc<Mutex<BeefyTestNet>>,
|
||||||
runtime: &mut Runtime,
|
runtime: &mut Runtime,
|
||||||
expected_commitment_block_nums: &[u64],
|
expected_commitment_block_nums: &[u64],
|
||||||
@@ -446,9 +447,12 @@ fn wait_for_beefy_signed_commitments(
|
|||||||
let len = expected_commitment_block_nums.len();
|
let len = expected_commitment_block_nums.len();
|
||||||
streams.into_iter().for_each(|stream| {
|
streams.into_iter().for_each(|stream| {
|
||||||
let mut expected = expected_commitment_block_nums.iter();
|
let mut expected = expected_commitment_block_nums.iter();
|
||||||
wait_for.push(Box::pin(stream.take(len).for_each(move |signed_commitment| {
|
wait_for.push(Box::pin(stream.take(len).for_each(move |versioned_finality_proof| {
|
||||||
let expected = expected.next();
|
let expected = expected.next();
|
||||||
async move {
|
async move {
|
||||||
|
let signed_commitment = match versioned_finality_proof {
|
||||||
|
beefy_primitives::VersionedFinalityProof::V1(sc) => sc,
|
||||||
|
};
|
||||||
let commitment_block_num = signed_commitment.commitment.block_number;
|
let commitment_block_num = signed_commitment.commitment.block_number;
|
||||||
assert_eq!(expected, Some(commitment_block_num).as_ref());
|
assert_eq!(expected, Some(commitment_block_num).as_ref());
|
||||||
// TODO: also verify commitment payload, validator set id, and signatures.
|
// TODO: also verify commitment payload, validator set id, and signatures.
|
||||||
@@ -486,7 +490,7 @@ fn finalize_block_and_wait_for_beefy(
|
|||||||
finalize_targets: &[u64],
|
finalize_targets: &[u64],
|
||||||
expected_beefy: &[u64],
|
expected_beefy: &[u64],
|
||||||
) {
|
) {
|
||||||
let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers);
|
let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers);
|
||||||
|
|
||||||
for block in finalize_targets {
|
for block in finalize_targets {
|
||||||
let finalize = BlockId::number(*block);
|
let finalize = BlockId::number(*block);
|
||||||
@@ -499,11 +503,11 @@ fn finalize_block_and_wait_for_beefy(
|
|||||||
// run for quarter second then verify no new best beefy block available
|
// run for quarter second then verify no new best beefy block available
|
||||||
let timeout = Some(Duration::from_millis(250));
|
let timeout = Some(Duration::from_millis(250));
|
||||||
streams_empty_after_timeout(best_blocks, &net, runtime, timeout);
|
streams_empty_after_timeout(best_blocks, &net, runtime, timeout);
|
||||||
streams_empty_after_timeout(signed_commitments, &net, runtime, None);
|
streams_empty_after_timeout(versioned_finality_proof, &net, runtime, None);
|
||||||
} else {
|
} else {
|
||||||
// run until expected beefy blocks are received
|
// run until expected beefy blocks are received
|
||||||
wait_for_best_beefy_blocks(best_blocks, &net, runtime, expected_beefy);
|
wait_for_best_beefy_blocks(best_blocks, &net, runtime, expected_beefy);
|
||||||
wait_for_beefy_signed_commitments(signed_commitments, &net, runtime, expected_beefy);
|
wait_for_beefy_signed_commitments(versioned_finality_proof, &net, runtime, expected_beefy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,19 +578,19 @@ fn lagging_validators() {
|
|||||||
|
|
||||||
// Alice finalizes #25, Bob lags behind
|
// Alice finalizes #25, Bob lags behind
|
||||||
let finalize = BlockId::number(25);
|
let finalize = BlockId::number(25);
|
||||||
let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers);
|
let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers);
|
||||||
net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap();
|
net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap();
|
||||||
// verify nothing gets finalized by BEEFY
|
// verify nothing gets finalized by BEEFY
|
||||||
let timeout = Some(Duration::from_millis(250));
|
let timeout = Some(Duration::from_millis(250));
|
||||||
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
|
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
|
||||||
streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None);
|
streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None);
|
||||||
|
|
||||||
// Bob catches up and also finalizes #25
|
// Bob catches up and also finalizes #25
|
||||||
let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers);
|
let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers);
|
||||||
net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap();
|
net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap();
|
||||||
// expected beefy finalizes block #17 from diff-power-of-two
|
// expected beefy finalizes block #17 from diff-power-of-two
|
||||||
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]);
|
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]);
|
||||||
wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[23, 24, 25]);
|
wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[23, 24, 25]);
|
||||||
|
|
||||||
// Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32
|
// Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32
|
||||||
finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]);
|
finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]);
|
||||||
@@ -596,20 +600,20 @@ fn lagging_validators() {
|
|||||||
// validator set).
|
// validator set).
|
||||||
|
|
||||||
// Alice finalizes session-boundary mandatory block #60, Bob lags behind
|
// Alice finalizes session-boundary mandatory block #60, Bob lags behind
|
||||||
let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers);
|
let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers);
|
||||||
let finalize = BlockId::number(60);
|
let finalize = BlockId::number(60);
|
||||||
net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap();
|
net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap();
|
||||||
// verify nothing gets finalized by BEEFY
|
// verify nothing gets finalized by BEEFY
|
||||||
let timeout = Some(Duration::from_millis(250));
|
let timeout = Some(Duration::from_millis(250));
|
||||||
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
|
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
|
||||||
streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None);
|
streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None);
|
||||||
|
|
||||||
// Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60)
|
// Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60)
|
||||||
let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers);
|
let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers);
|
||||||
net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap();
|
net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap();
|
||||||
// verify beefy skips intermediary votes, and successfully finalizes mandatory block #40
|
// verify beefy skips intermediary votes, and successfully finalizes mandatory block #40
|
||||||
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]);
|
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]);
|
||||||
wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[60]);
|
wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -647,7 +651,7 @@ fn correct_beefy_payload() {
|
|||||||
// with 3 good voters and 1 bad one, consensus should happen and best blocks produced.
|
// with 3 good voters and 1 bad one, consensus should happen and best blocks produced.
|
||||||
finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]);
|
finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]);
|
||||||
|
|
||||||
let (best_blocks, signed_commitments) =
|
let (best_blocks, versioned_finality_proof) =
|
||||||
get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]);
|
get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]);
|
||||||
|
|
||||||
// now 2 good validators and 1 bad one are voting
|
// now 2 good validators and 1 bad one are voting
|
||||||
@@ -673,10 +677,10 @@ fn correct_beefy_payload() {
|
|||||||
// verify consensus is _not_ reached
|
// verify consensus is _not_ reached
|
||||||
let timeout = Some(Duration::from_millis(250));
|
let timeout = Some(Duration::from_millis(250));
|
||||||
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
|
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
|
||||||
streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None);
|
streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None);
|
||||||
|
|
||||||
// 3rd good validator catches up and votes as well
|
// 3rd good validator catches up and votes as well
|
||||||
let (best_blocks, signed_commitments) =
|
let (best_blocks, versioned_finality_proof) =
|
||||||
get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]);
|
get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]);
|
||||||
net.lock()
|
net.lock()
|
||||||
.peer(2)
|
.peer(2)
|
||||||
@@ -687,7 +691,7 @@ fn correct_beefy_payload() {
|
|||||||
|
|
||||||
// verify consensus is reached
|
// verify consensus is reached
|
||||||
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]);
|
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]);
|
||||||
wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[11]);
|
wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[11]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -746,7 +750,7 @@ fn beefy_importing_blocks() {
|
|||||||
let block_num = 2;
|
let block_num = 2;
|
||||||
let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob];
|
let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob];
|
||||||
let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap();
|
let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap();
|
||||||
let proof = crate::justification::tests::new_signed_commitment(block_num, &validator_set, keys);
|
let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys);
|
||||||
let versioned_proof: VersionedFinalityProof<NumberFor<Block>, Signature> = proof.into();
|
let versioned_proof: VersionedFinalityProof<NumberFor<Block>, Signature> = proof.into();
|
||||||
let encoded = versioned_proof.encode();
|
let encoded = versioned_proof.encode();
|
||||||
let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded)));
|
let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded)));
|
||||||
@@ -781,7 +785,7 @@ fn beefy_importing_blocks() {
|
|||||||
let block_num = 3;
|
let block_num = 3;
|
||||||
let keys = &[BeefyKeyring::Alice];
|
let keys = &[BeefyKeyring::Alice];
|
||||||
let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap();
|
let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap();
|
||||||
let proof = crate::justification::tests::new_signed_commitment(block_num, &validator_set, keys);
|
let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys);
|
||||||
let versioned_proof: VersionedFinalityProof<NumberFor<Block>, Signature> = proof.into();
|
let versioned_proof: VersionedFinalityProof<NumberFor<Block>, Signature> = proof.into();
|
||||||
let encoded = versioned_proof.encode();
|
let encoded = versioned_proof.encode();
|
||||||
let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded)));
|
let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded)));
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ use beefy_primitives::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
gossip::{topic, GossipValidator},
|
gossip::{topic, GossipValidator},
|
||||||
justification::BeefySignedCommitment,
|
justification::BeefyVersionedFinalityProof,
|
||||||
keystore::BeefyKeystore,
|
keystore::BeefyKeystore,
|
||||||
metric_inc, metric_set,
|
metric_inc, metric_set,
|
||||||
metrics::Metrics,
|
metrics::Metrics,
|
||||||
@@ -212,7 +212,7 @@ pub(crate) struct BeefyWorker<B: Block, BE, C, R, SO> {
|
|||||||
/// Buffer holding votes for future processing.
|
/// Buffer holding votes for future processing.
|
||||||
pending_votes: BTreeMap<NumberFor<B>, Vec<VoteMessage<NumberFor<B>, AuthorityId, Signature>>>,
|
pending_votes: BTreeMap<NumberFor<B>, Vec<VoteMessage<NumberFor<B>, AuthorityId, Signature>>>,
|
||||||
/// Buffer holding justifications for future processing.
|
/// Buffer holding justifications for future processing.
|
||||||
pending_justifications: BTreeMap<NumberFor<B>, Vec<BeefySignedCommitment<B>>>,
|
pending_justifications: BTreeMap<NumberFor<B>, Vec<BeefyVersionedFinalityProof<B>>>,
|
||||||
/// Chooses which incoming votes to accept and which votes to generate.
|
/// Chooses which incoming votes to accept and which votes to generate.
|
||||||
voting_oracle: VoterOracle<B>,
|
voting_oracle: VoterOracle<B>,
|
||||||
}
|
}
|
||||||
@@ -381,9 +381,12 @@ where
|
|||||||
/// Expects `justification` to be valid.
|
/// Expects `justification` to be valid.
|
||||||
fn triage_incoming_justif(
|
fn triage_incoming_justif(
|
||||||
&mut self,
|
&mut self,
|
||||||
justification: BeefySignedCommitment<B>,
|
justification: BeefyVersionedFinalityProof<B>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let block_num = justification.commitment.block_number;
|
let signed_commitment = match justification {
|
||||||
|
VersionedFinalityProof::V1(ref sc) => sc,
|
||||||
|
};
|
||||||
|
let block_num = signed_commitment.commitment.block_number;
|
||||||
let best_grandpa = *self.best_grandpa_block_header.number();
|
let best_grandpa = *self.best_grandpa_block_header.number();
|
||||||
match self.voting_oracle.triage_round(block_num, best_grandpa)? {
|
match self.voting_oracle.triage_round(block_num, best_grandpa)? {
|
||||||
RoundAction::Process => self.finalize(justification),
|
RoundAction::Process => self.finalize(justification),
|
||||||
@@ -417,39 +420,39 @@ where
|
|||||||
validator_set_id: rounds.validator_set_id(),
|
validator_set_id: rounds.validator_set_id(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let signed_commitment = SignedCommitment { commitment, signatures };
|
let finality_proof =
|
||||||
|
VersionedFinalityProof::V1(SignedCommitment { commitment, signatures });
|
||||||
|
|
||||||
metric_set!(self, beefy_round_concluded, block_num);
|
metric_set!(self, beefy_round_concluded, block_num);
|
||||||
|
|
||||||
info!(target: "beefy", "🥩 Round #{} concluded, committed: {:?}.", round.1, signed_commitment);
|
info!(target: "beefy", "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof);
|
||||||
|
|
||||||
if let Err(e) = self.backend.append_justification(
|
if let Err(e) = self.backend.append_justification(
|
||||||
BlockId::Number(block_num),
|
BlockId::Number(block_num),
|
||||||
(
|
(BEEFY_ENGINE_ID, finality_proof.clone().encode()),
|
||||||
BEEFY_ENGINE_ID,
|
|
||||||
VersionedFinalityProof::V1(signed_commitment.clone()).encode(),
|
|
||||||
),
|
|
||||||
) {
|
) {
|
||||||
debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, signed_commitment);
|
debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We created the `signed_commitment` and know to be valid.
|
// We created the `finality_proof` and know to be valid.
|
||||||
self.finalize(signed_commitment);
|
self.finalize(finality_proof);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide BEEFY finality for block based on `signed_commitment`:
|
/// Provide BEEFY finality for block based on `finality_proof`:
|
||||||
/// 1. Prune irrelevant past sessions from the oracle,
|
/// 1. Prune irrelevant past sessions from the oracle,
|
||||||
/// 2. Set BEEFY best block,
|
/// 2. Set BEEFY best block,
|
||||||
/// 3. Send best block hash and `signed_commitment` to RPC worker.
|
/// 3. Send best block hash and `finality_proof` to RPC worker.
|
||||||
///
|
///
|
||||||
/// Expects `signed commitment` to be valid.
|
/// Expects `finality proof` to be valid.
|
||||||
fn finalize(&mut self, signed_commitment: BeefySignedCommitment<B>) {
|
fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof<B>) {
|
||||||
// Prune any now "finalized" sessions from queue.
|
// Prune any now "finalized" sessions from queue.
|
||||||
self.voting_oracle.try_prune();
|
self.voting_oracle.try_prune();
|
||||||
|
let signed_commitment = match finality_proof {
|
||||||
|
VersionedFinalityProof::V1(ref sc) => sc,
|
||||||
|
};
|
||||||
let block_num = signed_commitment.commitment.block_number;
|
let block_num = signed_commitment.commitment.block_number;
|
||||||
if Some(block_num) > self.best_beefy_block {
|
if Some(block_num) > self.best_beefy_block {
|
||||||
// Set new best BEEFY block number.
|
// Set new best BEEFY block number.
|
||||||
@@ -465,7 +468,7 @@ where
|
|||||||
|
|
||||||
self.links
|
self.links
|
||||||
.to_rpc_justif_sender
|
.to_rpc_justif_sender
|
||||||
.notify(|| Ok::<_, ()>(signed_commitment))
|
.notify(|| Ok::<_, ()>(finality_proof))
|
||||||
.expect("forwards closure result; the closure always returns Ok; qed.");
|
.expect("forwards closure result; the closure always returns Ok; qed.");
|
||||||
} else {
|
} else {
|
||||||
debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num);
|
debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num);
|
||||||
@@ -832,7 +835,7 @@ pub(crate) mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
keystore::tests::Keyring,
|
keystore::tests::Keyring,
|
||||||
notification::{BeefyBestBlockStream, BeefySignedCommitmentStream},
|
notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream},
|
||||||
tests::{
|
tests::{
|
||||||
create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi,
|
create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi,
|
||||||
BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME,
|
BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME,
|
||||||
@@ -859,10 +862,11 @@ pub(crate) mod tests {
|
|||||||
let keystore = create_beefy_keystore(*key);
|
let keystore = create_beefy_keystore(*key);
|
||||||
|
|
||||||
let (to_rpc_justif_sender, from_voter_justif_stream) =
|
let (to_rpc_justif_sender, from_voter_justif_stream) =
|
||||||
BeefySignedCommitmentStream::<Block>::channel();
|
BeefyVersionedFinalityProofStream::<Block>::channel();
|
||||||
let (to_rpc_best_block_sender, from_voter_best_beefy_stream) =
|
let (to_rpc_best_block_sender, from_voter_best_beefy_stream) =
|
||||||
BeefyBestBlockStream::<Block>::channel();
|
BeefyBestBlockStream::<Block>::channel();
|
||||||
let (_, from_block_import_justif_stream) = BeefySignedCommitmentStream::<Block>::channel();
|
let (_, from_block_import_justif_stream) =
|
||||||
|
BeefyVersionedFinalityProofStream::<Block>::channel();
|
||||||
|
|
||||||
let beefy_rpc_links =
|
let beefy_rpc_links =
|
||||||
BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream };
|
BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream };
|
||||||
@@ -1168,37 +1172,37 @@ pub(crate) mod tests {
|
|||||||
let mut net = BeefyTestNet::new(1, 0);
|
let mut net = BeefyTestNet::new(1, 0);
|
||||||
let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1);
|
let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1);
|
||||||
|
|
||||||
let (mut best_block_streams, mut signed_commitments) = get_beefy_streams(&mut net, keys);
|
let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys);
|
||||||
let mut best_block_stream = best_block_streams.drain(..).next().unwrap();
|
let mut best_block_stream = best_block_streams.drain(..).next().unwrap();
|
||||||
let mut signed_commitments = signed_commitments.drain(..).next().unwrap();
|
let mut finality_proof = finality_proofs.drain(..).next().unwrap();
|
||||||
|
|
||||||
let create_signed_commitment = |block_num: NumberFor<Block>| {
|
let create_finality_proof = |block_num: NumberFor<Block>| {
|
||||||
let commitment = Commitment {
|
let commitment = Commitment {
|
||||||
payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]),
|
payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]),
|
||||||
block_number: block_num,
|
block_number: block_num,
|
||||||
validator_set_id: validator_set.id(),
|
validator_set_id: validator_set.id(),
|
||||||
};
|
};
|
||||||
SignedCommitment { commitment, signatures: vec![None] }
|
VersionedFinalityProof::V1(SignedCommitment { commitment, signatures: vec![None] })
|
||||||
};
|
};
|
||||||
|
|
||||||
// no 'best beefy block' or signed commitments
|
// no 'best beefy block' or finality proofs
|
||||||
assert_eq!(worker.best_beefy_block, None);
|
assert_eq!(worker.best_beefy_block, None);
|
||||||
block_on(poll_fn(move |cx| {
|
block_on(poll_fn(move |cx| {
|
||||||
assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending);
|
assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending);
|
||||||
assert_eq!(signed_commitments.poll_next_unpin(cx), Poll::Pending);
|
assert_eq!(finality_proof.poll_next_unpin(cx), Poll::Pending);
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// unknown hash for block #1
|
// unknown hash for block #1
|
||||||
let (mut best_block_streams, mut signed_commitments) = get_beefy_streams(&mut net, keys);
|
let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys);
|
||||||
let mut best_block_stream = best_block_streams.drain(..).next().unwrap();
|
let mut best_block_stream = best_block_streams.drain(..).next().unwrap();
|
||||||
let mut signed_commitments = signed_commitments.drain(..).next().unwrap();
|
let mut finality_proof = finality_proofs.drain(..).next().unwrap();
|
||||||
let justif = create_signed_commitment(1);
|
let justif = create_finality_proof(1);
|
||||||
worker.finalize(justif.clone());
|
worker.finalize(justif.clone());
|
||||||
assert_eq!(worker.best_beefy_block, Some(1));
|
assert_eq!(worker.best_beefy_block, Some(1));
|
||||||
block_on(poll_fn(move |cx| {
|
block_on(poll_fn(move |cx| {
|
||||||
assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending);
|
assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending);
|
||||||
match signed_commitments.poll_next_unpin(cx) {
|
match finality_proof.poll_next_unpin(cx) {
|
||||||
// expect justification
|
// expect justification
|
||||||
Poll::Ready(Some(received)) => assert_eq!(received, justif),
|
Poll::Ready(Some(received)) => assert_eq!(received, justif),
|
||||||
v => panic!("unexpected value: {:?}", v),
|
v => panic!("unexpected value: {:?}", v),
|
||||||
@@ -1211,7 +1215,7 @@ pub(crate) mod tests {
|
|||||||
let mut best_block_stream = best_block_streams.drain(..).next().unwrap();
|
let mut best_block_stream = best_block_streams.drain(..).next().unwrap();
|
||||||
net.generate_blocks(2, 10, &validator_set, false);
|
net.generate_blocks(2, 10, &validator_set, false);
|
||||||
|
|
||||||
let justif = create_signed_commitment(2);
|
let justif = create_finality_proof(2);
|
||||||
worker.finalize(justif);
|
worker.finalize(justif);
|
||||||
assert_eq!(worker.best_beefy_block, Some(2));
|
assert_eq!(worker.best_beefy_block, Some(2));
|
||||||
block_on(poll_fn(move |cx| {
|
block_on(poll_fn(move |cx| {
|
||||||
|
|||||||
Reference in New Issue
Block a user