From 4232fc4fdb2d91fffd183f1e5589b63b183c6120 Mon Sep 17 00:00:00 2001 From: Jedrzej Kula Date: Mon, 5 Jul 2021 16:10:42 +0200 Subject: [PATCH 1/3] Add solution to Karaoke --- node/Cargo.toml | 15 +++++ node/src/service.rs | 115 ++++++++++++++++++++++++++++++++++-- pallets/template/Cargo.toml | 3 + pallets/template/src/lib.rs | 111 ++++++++++++++++------------------ runtime/src/lib.rs | 2 +- 5 files changed, 180 insertions(+), 66 deletions(-) diff --git a/node/Cargo.toml b/node/Cargo.toml index cb1898a66c..77f2ba3653 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -23,6 +23,21 @@ targets = ['x86_64-unknown-linux-gnu'] [dependencies] jsonrpc-core = '15.1.0' structopt = '0.3.8' +futures = "0.3.9" +sp-std = { version = "3.0.0", default-features = false } + +[dependencies.pallet-template] +default-features = false +path = '../pallets/template' +version = '3.0.0' + +[dependencies.sc-block-builder] +git = 'https://github.com/paritytech/substrate.git' +rev = 'd6c33e7ec313f9bd5e319dc0a5a3ace5543f9617' +version = "0.9.0" + +[dependencies.prometheus] +version = "0.12.0" [dependencies.frame-benchmarking] git = 'https://github.com/paritytech/substrate.git' diff --git a/node/src/service.rs b/node/src/service.rs index c19824e9ea..1060c0dca3 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -12,6 +12,7 @@ use sc_finality_grandpa::SharedVoterState; use sc_keystore::LocalKeystore; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_consensus::SlotData; +use node_template_runtime::pallet_template::INHERENT_IDENTIFIER; // Our native executor instance. native_executor_instance!( @@ -25,6 +26,106 @@ type FullClient = sc_service::TFullClient; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; +use std::{pin::Pin, time}; + +use futures::{future, future::Future}; +use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_client_api::backend; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_blockchain::HeaderBackend; +use sp_consensus::Proposal; +use sp_inherents::InherentData; +use sp_runtime::{ + traits::{Block as BlockT, DigestFor}, +}; +use sp_transaction_pool::TransactionPool; +use sp_consensus::ProofRecording; +use sp_std::iter::Cycle; +use sp_std::str::Lines; + +struct Proposer { + proposer: sc_basic_authorship::Proposer, + value: Vec, +} + +impl sp_consensus::Proposer for + Proposer + where + A: TransactionPool + 'static, + B: backend::Backend + Send + Sync + 'static, + Block: BlockT, + C: BlockBuilderProvider + HeaderBackend + ProvideRuntimeApi + + Send + Sync + 'static, + C::Api: ApiExt> + + BlockBuilderApi, + PR: ProofRecording, +{ + type Transaction = backend::TransactionFor; + type Proposal = Pin, Self::Error> + > + Send>>; + type Error = sp_blockchain::Error; + type Proof = PR::Proof; + type ProofRecording = PR; + + fn propose( + self, + inherent_data: InherentData, + inherent_digests: DigestFor, + max_duration: time::Duration, + block_size_limit: Option, + ) -> Self::Proposal { + let mut inherent_data = inherent_data; + inherent_data.put_data(INHERENT_IDENTIFIER, &self.value).unwrap(); + self.proposer.propose(inherent_data, inherent_digests, max_duration, block_size_limit) + } +} + +struct MyProposerFactory<'a, A, B, C, PR> { + proposer_factory: sc_basic_authorship::ProposerFactory, + value: Cycle> +} + +impl MyProposerFactory<'_, A, B, C, PR> { + pub fn new( + proposer_factory: sc_basic_authorship::ProposerFactory, + ) -> Self { + MyProposerFactory { + proposer_factory, + value: + "qwertyuiop + asdfghjkl + zxcvbnm".lines().cycle(), + } + } +} + +impl sp_consensus::Environment for + MyProposerFactory<'_, A, B, C, PR> + where + A: TransactionPool + 'static, + B: backend::Backend + Send + Sync + 'static, + Block: BlockT, + C: BlockBuilderProvider + HeaderBackend + ProvideRuntimeApi + + Send + Sync + 'static, + C::Api: ApiExt> + + BlockBuilderApi, + PR: ProofRecording, +{ + + type Error = sp_blockchain::Error; + type Proposer = Proposer; + type CreateProposer = future::Ready>; + + fn init(&mut self, parent_header: &::Header) -> Self::CreateProposer { + let proposer = self.proposer_factory.init(parent_header).into_inner().unwrap(); + future::ready(Ok(Proposer{ + proposer, + value: self.value.next().unwrap().as_bytes().to_vec(), + })) + } +} + pub fn new_partial(config: &Configuration) -> Result, @@ -206,12 +307,14 @@ pub fn new_full(mut config: Configuration) -> Result )?; if role.is_authority() { - let proposer_factory = sc_basic_authorship::ProposerFactory::new( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|x| x.handle()), + let proposer_factory = MyProposerFactory::new( + sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|x| x.handle()), + ), ); let can_author_with = diff --git a/pallets/template/Cargo.toml b/pallets/template/Cargo.toml index 184d67fc63..0d9fe0460f 100644 --- a/pallets/template/Cargo.toml +++ b/pallets/template/Cargo.toml @@ -13,6 +13,9 @@ targets = ['x86_64-unknown-linux-gnu'] [dev-dependencies.serde] version = '1.0.119' +[dependencies] +sp-std = { version = "3.0.0", default-features = false } + [dev-dependencies.sp-core] default-features = false git = 'https://github.com/paritytech/substrate.git' diff --git a/pallets/template/src/lib.rs b/pallets/template/src/lib.rs index 373a56f444..244d246c25 100644 --- a/pallets/template/src/lib.rs +++ b/pallets/template/src/lib.rs @@ -17,88 +17,81 @@ mod benchmarking; #[frame_support::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use frame_support::inherent::IsFatalError; + use frame_support::sp_std::result; + use sp_std::vec::Vec; - /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] pub trait Config: frame_system::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. type Event: From> + IsType<::Event>; } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); - // The pallet's runtime storage items. - // https://substrate.dev/docs/en/knowledgebase/runtime/storage - #[pallet::storage] - #[pallet::getter(fn something)] - // Learn more about declaring storage items: - // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items - pub type Something = StorageValue<_, u32>; - - // Pallets use events to inform users when important changes are made. - // https://substrate.dev/docs/en/knowledgebase/runtime/events #[pallet::event] #[pallet::metadata(T::AccountId = "AccountId")] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Event documentation should end with an array that provides descriptive names for event - /// parameters. [something, who] - SomethingStored(u32, T::AccountId), + NextLine(Vec), } - // Errors inform users that something went wrong. #[pallet::error] pub enum Error { - /// Error names should be descriptive. - NoneValue, - /// Errors should have helpful documentation associated with them. - StorageOverflow, + Error, } - // Dispatchable functions allows users to interact with the pallet and invoke state changes. - // These functions materialize as "extrinsics", which are often compared to transactions. - // Dispatchable functions must be annotated with a weight and must return a DispatchResult. - #[pallet::call] - impl Pallet { - /// An example dispatchable that takes a singles value as a parameter, writes the value to - /// storage and emits an event. This function must be dispatched by a signed extrinsic. - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { - // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://substrate.dev/docs/en/knowledgebase/runtime/origin - let who = ensure_signed(origin)?; - - // Update storage. - >::put(something); - - // Emit an event. - Self::deposit_event(Event::SomethingStored(something, who)); - // Return a successful DispatchResultWithPostInfo + #[derive(Encode, Decode)] + pub struct InherentError; + + impl InherentError { + pub fn try_from(id: &InherentIdentifier, data: &[u8]) -> Option { + if id == &INHERENT_IDENTIFIER { + ::decode(&mut &data[..]).ok() + } else { + None + } + } + } + + impl IsFatalError for InherentError { + fn is_fatal_error(&self) -> bool { + false + } + } + + pub const INHERENT_IDENTIFIER: [u8; 8] = *b"jedrzejs"; + + #[pallet::inherent] + impl ProvideInherent for Pallet { + type Call = Call; + type Error = InherentError; + + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(data: &InherentData) -> Option { + let inherent_data = + data.get_data::>(&INHERENT_IDENTIFIER).unwrap().unwrap(); + Some(Call::show_next_line(inherent_data)) + } + + fn check_inherent(_call: &Self::Call, _data: &InherentData) -> result::Result<(), Self::Error> { Ok(()) } - /// An example dispatchable that may throw a custom error. - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))] - pub fn cause_error(origin: OriginFor) -> DispatchResult { - let _who = ensure_signed(origin)?; - - // Read a value from storage. - match >::get() { - // Return an error if the value has not been set. - None => Err(Error::::NoneValue)?, - Some(old) => { - // Increment the value read from storage; will error in the event of overflow. - let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; - // Update the value in storage with the incremented result. - >::put(new); - Ok(()) - }, - } + fn is_inherent(call: &Self::Call) -> bool { + matches!(call, Call::show_next_line(_)) + } + } + + #[pallet::call] + impl Pallet { + #[pallet::weight(10_000)] + pub fn show_next_line(_origin: OriginFor, value: Vec) -> DispatchResult { + Self::deposit_event(Event::NextLine(value)); + Ok(()) } } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index e89d7f28be..f5e2acfc81 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -288,7 +288,7 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template::{Pallet, Call, Storage, Event}, + TemplateModule: pallet_template::{Pallet, Call, Storage, Event, Inherent}, } ); From 756666c930206c030f5640e79b42b36331f3879e Mon Sep 17 00:00:00 2001 From: Jedrzej Kula Date: Mon, 5 Jul 2021 19:56:13 +0200 Subject: [PATCH 2/3] Fix cargo.toml --- node/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Cargo.toml b/node/Cargo.toml index 77f2ba3653..4927abdeb1 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -33,7 +33,7 @@ version = '3.0.0' [dependencies.sc-block-builder] git = 'https://github.com/paritytech/substrate.git' -rev = 'd6c33e7ec313f9bd5e319dc0a5a3ace5543f9617' +rev = 'monthly-2021-07' version = "0.9.0" [dependencies.prometheus] From 36df818259c32ddf54c3597ea657cdc206904bdd Mon Sep 17 00:00:00 2001 From: Jedrzej Kula Date: Tue, 6 Jul 2021 12:22:08 +0200 Subject: [PATCH 3/3] Fix cargo.toml --- node/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Cargo.toml b/node/Cargo.toml index 4927abdeb1..860196b149 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -33,7 +33,7 @@ version = '3.0.0' [dependencies.sc-block-builder] git = 'https://github.com/paritytech/substrate.git' -rev = 'monthly-2021-07' +tag = 'monthly-2021-07' version = "0.9.0" [dependencies.prometheus]