Configure a Chain to POW Consensus
Goal
To understand how link a POW consensus engine to a service client.
Use Cases
- Launching a POW chain.
- Upgrading a chain from Authority based to POW based.
Overview
The basic-pow node demonstrates how to wire up a custom consensus engine into the Substrate Service. It uses a minimal proof of work consensus engine to reach agreement over the blockchain. This guide will teach us many useful aspects of dealing with consensus and prepare us to understand more advanced consensus engines in the future.
Steps
1. Make a function that defines a full node using sc_consensus_pow
and sc_service
In src/service.rs
, make a function called new_full1
that defines PartialComponents
and
PowBlockImport
:
let pow_block_import = sc_consensus_pow::PowBlockImport::new(
client.clone(),
client.clone(),
sha3pow::MinimalSha3Algorithm,
0, // check inherents starting at block 0
select_chain.clone(),
inherent_data_providers.clone(),
can_author_with,
);
let import_queue = sc_consensus_pow::import_queue(
Box::new(pow_block_import.clone()),
None,
sha3pow::MinimalSha3Algorithm, // provide it with references to our client
inherent_data_providers.clone(),
&task_manager.spawn_handle(),
config.prometheus_registry(),
)?;
See the Rust docs on to configure the pow_block_import
function.
2. Create import queue
Define your node's inherents by using InherentDataProviders
in a function that defines the providers of your POW system:
pub fn build_inherent_data_providers() -> Result<InherentDataProviders, ServiceError> {
let providers = InherentDataProviders::new();
providers
.register_provider(sp_timestamp::InherentDataProvider)
.map_err(Into::into)
.map_err(sp_consensus::error::Error::InherentData)?;
Ok(providers)
}
3. Define the proposer
and worker
In the new_full
function, define proposer
:
let proposer = sc_basic_authorship::ProposerFactory::new(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry.as_ref(),
);
let (_worker, worker_task) = sc_consensus_pow::start_mining_worker(
Box::new(pow_block_import),
client,
select_chain,
MinimalSha3Algorithm,
proposer,
network.clone(),
None,
inherent_data_providers,
// time to wait for a new block before starting to mine a new one
Duration::from_secs(10),
// how long to take to actually build the block (i.e. executing extrinsics)
Duration::from_secs(10),
can_author_with,
);
Let the task manager spawn it:
task_manager
.spawn_essential_handle()
.spawn_blocking("pow", worker_task);
4. Construct the light client's service
The construction of the light client service is quite similar to the construction of the new_full
function.
Follow the pattern from the previous step to create new_light
.