Developers Home»How-to Guide»Configure a Chain to POW Consensus

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.

Examples

Resources

Rust docs

Docs

Last edit: on

Run into problems?
Let us Know