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

Commit

Permalink
Add beefy pallet (#25)
Browse files Browse the repository at this point in the history
* move beefy application crypto to primitives

* make primitives compile under no_std

* add beefy pallet that maintains authority set

* add beefy pallet to node example runtime

* tabify node-example cargo.toml files

* use double quotes in Cargo.toml files

* add missing hex-literal dependency

* add runtime api to fetch BEEFY authorities

* fix clippy warnings

* rename beefy-pallet to pallet-beefy

* sort dependencies in node-example/runtime/Cargo.toml
  • Loading branch information
andresilva authored Nov 20, 2020
1 parent ea541f9 commit cbda281
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 56 deletions.
3 changes: 3 additions & 0 deletions client/beefy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ futures = "0.3"
log = "0.4"
parking_lot = "0.11"

beefy-primitives = { path = "../primitives" }

sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
Expand Down
80 changes: 24 additions & 56 deletions client/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,43 +24,25 @@ use futures::{future, FutureExt, Stream, StreamExt};
use log::{debug, error, info, trace, warn};
use parking_lot::Mutex;

use beefy_primitives::{
ecdsa::{AuthorityId, AuthoritySignature},
BeefyApi, BEEFY_ENGINE_ID, KEY_TYPE,
};

use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotification, Finalizer};
use sc_network_gossip::{
GossipEngine, Network as GossipNetwork, ValidationResult as GossipValidationResult, Validator as GossipValidator,
ValidatorContext as GossipValidatorContext,
};
use sp_application_crypto::Ss58Codec;
use sp_api::{BlockId, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_consensus::SyncOracle as SyncOracleT;
use sp_core::Public;
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::{
traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor, Zero},
ConsensusEngineId, KeyTypeId,
};
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor, Zero};

pub const BEEFY_ENGINE_ID: ConsensusEngineId = *b"BEEF";
pub const BEEFY_PROTOCOL_NAME: &str = "/paritytech/beefy/1";

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

mod app {
use sp_application_crypto::{app_crypto, ecdsa};
app_crypto!(ecdsa, super::KEY_TYPE);
}

sp_application_crypto::with_pair! {
/// The BEEFY crypto scheme defined via the keypair type.
pub type AuthorityPair = app::Pair;
}

/// Identity of a BEEFY authority.
pub type AuthorityId = app::Public;

/// Signature for a BEEFY authority.
pub type AuthoritySignature = app::Signature;

/// Allows all gossip messages to get through.
struct AllowAll<Hash> {
topic: Hash,
Expand Down Expand Up @@ -231,7 +213,7 @@ where
}

fn handle_finality_notification(&mut self, notification: FinalityNotification<Block>) {
info!(target: "beefy", "Finality notification: {:?}", notification);
info!(target: "beefy", "🥩 Finality notification: {:?}", notification);

if self.should_vote_on(*notification.header.number()) {
let signature = match SyncCryptoStore::sign_with(
Expand Down Expand Up @@ -261,6 +243,7 @@ where
self.gossip_engine
.lock()
.gossip_message(topic::<Block>(), message.encode(), false);

debug!(target: "beefy", "Sent vote message: {:?}", message);

self.handle_vote(message.block, (message.id, message.signature));
Expand All @@ -273,7 +256,7 @@ where
// TODO: validate signature
let vote_added = self.rounds.add_vote(round, vote);
if vote_added && self.rounds.is_done(&round) {
info!(target: "beefy", "Round {:?} concluded.", round);
info!(target: "beefy", "🥩 Round {:?} concluded.", round);
self.rounds.drop(&round);
}
}
Expand Down Expand Up @@ -323,7 +306,13 @@ pub async fn start_beefy_gadget<Block, Backend, Client, Network, SyncOracle>(
) where
Block: BlockT,
Backend: BackendT<Block>,
Client: BlockchainEvents<Block> + HeaderBackend<Block> + Finalizer<Block, Backend> + Send + Sync,
Client: BlockchainEvents<Block>
+ HeaderBackend<Block>
+ Finalizer<Block, Backend>
+ ProvideRuntimeApi<Block>
+ Send
+ Sync,
Client::Api: BeefyApi<Block, AuthorityId>,
Network: GossipNetwork<Block> + Clone + Send + 'static,
SyncOracle: SyncOracleT + Send + 'static,
{
Expand All @@ -336,43 +325,22 @@ pub async fn start_beefy_gadget<Block, Backend, Client, Network, SyncOracle>(
}),
);

// ECDSA KEYS
// Secret phrase `history unique love spell mixed scrub expose retreat lawn jungle envelope spoon` is account:
// Secret seed: 0x996ed8439b50c50a94e5ca2254cde3d6d310f2babe39697fa51eb1bc65649fdb
// Public key (hex): 0x026a47a82cd7f0655a3bc9108fcf87c7ec444c5e2e7d44b826d9467635fe9b147e
// Account ID: 0xcba579b19a7e89087144c98b259d74465016f064ec2be5f45f2a632c2ffc1b14
// SS58 Address: 5GfijY8EJs724J7uujqqpNtJ4R4sUZxHTSGn4zMczaLt95eY
//
// curl -H 'Content-Type: application/json' --data '{"id":1,"jsonrpc":"2.0","method":"author_insertKey","params":["beef","0x996ed8439b50c50a94e5ca2254cde3d6d310f2babe39697fa51eb1bc65649fdb","0x026a47a82cd7f0655a3bc9108fcf87c7ec444c5e2e7d44b826d9467635fe9b147e"]}' http://localhost:9933
//
// Secret phrase `cage olympic bone detect control alert side off proud lucky rotate turkey` is account:
// Secret seed: 0x99eac69a6545d4c454c54232d8afe47dc16a8483b9d155663f52b7ccabe0d284
// Public key (hex): 0x03df6630e91b0309fa0986fcf52f83fcf437091c58534bd2f398d6e9aeb475de82
// Account ID: 0xa9b4c177c0d11d97a7123553d90f4ba265461c1217f544c2e787400c4a7478d6
// SS58 Address: 5FuDePC3XmirUqSvjxziwZzop4vVN8pBkzszdabQ8Pj7oRCW
//
// curl -H 'Content-Type: application/json' --data '{"id":1,"jsonrpc":"2.0","method":"author_insertKey","params":["beef","0x99eac69a6545d4c454c54232d8afe47dc16a8483b9d155663f52b7ccabe0d284","0x03df6630e91b0309fa0986fcf52f83fcf437091c58534bd2f398d6e9aeb475de82"]}' http://localhost:9933

let voters = vec![
"0x026a47a82cd7f0655a3bc9108fcf87c7ec444c5e2e7d44b826d9467635fe9b147e",
"0x03df6630e91b0309fa0986fcf52f83fcf437091c58534bd2f398d6e9aeb475de82",
];

let voters = voters
.into_iter()
.map(|address| AuthorityId::from_string(address).unwrap())
.collect::<Vec<_>>();
let at = BlockId::hash(client.info().best_hash);
let voters = client
.runtime_api()
.authorities(&at)
.expect("Failed to get BEEFY authorities");

let local_id = match voters
.iter()
.find(|id| SyncCryptoStore::has_keys(&*key_store, &[(id.to_raw_vec(), KEY_TYPE)]))
{
Some(id) => {
info!(target: "beefy", "Starting BEEFY worker with local id: {:?}", id);
info!(target: "beefy", "🥩 Starting BEEFY worker with local id: {:?}", id);
id.clone()
}
None => {
info!(target: "beefy", "No local id found, not starting BEEFY worker.");
info!(target: "beefy", "🥩 No local id found, not starting BEEFY worker.");
return futures::future::pending().await;
}
};
Expand Down

0 comments on commit cbda281

Please sign in to comment.