Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
tag = 'monthly-2021-07'
version = "0.9.0"

[dependencies.prometheus]
version = "0.12.0"

[dependencies.frame-benchmarking]
git = 'https://github.com/paritytech/substrate.git'
Expand Down
115 changes: 109 additions & 6 deletions node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand All @@ -25,6 +26,106 @@ type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;

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<B, Block: BlockT, C, A: TransactionPool, PR> {
proposer: sc_basic_authorship::Proposer<B, Block, C, A, PR>,
value: Vec<u8>,
}

impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for
Proposer<B, Block, C, A, PR>
where
A: TransactionPool<Block = Block> + 'static,
B: backend::Backend<Block> + Send + Sync + 'static,
Block: BlockT,
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
+ Send + Sync + 'static,
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
+ BlockBuilderApi<Block>,
PR: ProofRecording,
{
type Transaction = backend::TransactionFor<B, Block>;
type Proposal = Pin<Box<dyn Future<
Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>
> + Send>>;
type Error = sp_blockchain::Error;
type Proof = PR::Proof;
type ProofRecording = PR;

fn propose(
self,
inherent_data: InherentData,
inherent_digests: DigestFor<Block>,
max_duration: time::Duration,
block_size_limit: Option<usize>,
) -> 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<A, B, C, PR>,
value: Cycle<Lines<'a>>
}

impl<A, B, C, PR> MyProposerFactory<'_, A, B, C, PR> {
pub fn new(
proposer_factory: sc_basic_authorship::ProposerFactory<A, B, C, PR>,
) -> Self {
MyProposerFactory {
proposer_factory,
value:
"qwertyuiop
asdfghjkl
zxcvbnm".lines().cycle(),
}
}
}

impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for
MyProposerFactory<'_, A, B, C, PR>
where
A: TransactionPool<Block = Block> + 'static,
B: backend::Backend<Block> + Send + Sync + 'static,
Block: BlockT,
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
+ Send + Sync + 'static,
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
+ BlockBuilderApi<Block>,
PR: ProofRecording,
{

type Error = sp_blockchain::Error;
type Proposer = Proposer<B, Block, C, A, PR>;
type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>;

fn init(&mut self, parent_header: &<Block as BlockT>::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<sc_service::PartialComponents<
FullClient, FullBackend, FullSelectChain,
sp_consensus::DefaultImportQueue<Block, FullClient>,
Expand Down Expand Up @@ -206,12 +307,14 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
)?;

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 =
Expand Down
3 changes: 3 additions & 0 deletions pallets/template/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
111 changes: 52 additions & 59 deletions pallets/template/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}

#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);

// 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<T> = 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<T: Config> {
/// Event documentation should end with an array that provides descriptive names for event
/// parameters. [something, who]
SomethingStored(u32, T::AccountId),
NextLine(Vec<u8>),
}

// Errors inform users that something went wrong.
#[pallet::error]
pub enum Error<T> {
/// 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<T:Config> Pallet<T> {
/// 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<T>, 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.
<Something<T>>::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<Self> {
if id == &INHERENT_IDENTIFIER {
<InherentError as codec::Decode>::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<T:Config> ProvideInherent for Pallet<T> {
type Call = Call<T>;
type Error = InherentError;

const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;

fn create_inherent(data: &InherentData) -> Option<Self::Call> {
let inherent_data =
data.get_data::<Vec<u8>>(&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<T>) -> DispatchResult {
let _who = ensure_signed(origin)?;

// Read a value from storage.
match <Something<T>>::get() {
// Return an error if the value has not been set.
None => Err(Error::<T>::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::<T>::StorageOverflow)?;
// Update the value in storage with the incremented result.
<Something<T>>::put(new);
Ok(())
},
}
fn is_inherent(call: &Self::Call) -> bool {
matches!(call, Call::show_next_line(_))
}
}

#[pallet::call]
impl<T:Config> Pallet<T> {
#[pallet::weight(10_000)]
pub fn show_next_line(_origin: OriginFor<T>, value: Vec<u8>) -> DispatchResult {
Self::deposit_event(Event::NextLine(value));
Ok(())
}
}
}
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ construct_runtime!(
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
// Include the custom logic from the pallet-template in the runtime.
TemplateModule: pallet_template::{Pallet, Call, Storage, Event<T>},
TemplateModule: pallet_template::{Pallet, Call, Storage, Event<T>, Inherent},
}
);

Expand Down