Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChainSpec is not constructible in some cases #3750

Closed
bddap opened this issue Oct 3, 2019 · 1 comment

Comments

@bddap
Copy link
Contributor

@bddap bddap commented Oct 3, 2019

ChainSpec::from_genesis() takes a bare function (fn() -> G) as input.

Bare functions (fn() -> G) implement function traits (Fn() -> G) but not all objects that implement function traits (Fn() -> G) can be converted to bare functions (fn() -> G).

Problem

Closures with captures cannot be passed to ChainSpec::from_genesis(). This prevents the caller from doing dynamic setup of the genesis config.

Example

use serde::{Deserialize, Serialize};
use sr_primitives::{BuildStorage, ChildrenStorageOverlay, StorageOverlay};
use std::collections::HashMap;
use substrate_chain_spec::ChainSpec;
use substrate_finality_grandpa_primitives::AuthorityId;

#[derive(Debug, Serialize, Deserialize, Clone)]
struct Genesis(HashMap<String, String>);

impl BuildStorage for Genesis {
    fn assimilate_storage(
        self,
        storage: &mut (StorageOverlay, ChildrenStorageOverlay),
    ) -> Result<(), String> {
        storage.0.extend(
            self.0
                .into_iter()
                .map(|(a, b)| (a.into_bytes(), b.into_bytes())),
        );
        Ok(())
    }
}

fn this_compiles() -> ChainSpec<Genesis> {
    ChainSpec::<Genesis>::from_genesis(
        "",
        "",
        || Genesis(Default::default()),
        vec![],
        None,
        None,
        None,
        None,
    )
}

fn this_does_not_compile(authority: AuthorityId) -> ChainSpec<Genesis> {
    ChainSpec::<Genesis>::from_genesis(
        "",
        "",
        move || {
            let mut kvs: HashMap<String, String> = HashMap::new();
            kvs.insert("0xsomekey".to_string(), format!("{}", authority));
            Genesis(kvs)
        },
        vec![],
        None,
        None,
        None,
        None,
    )
}

fn main() {
    let json_chainspec = this_compiles().to_json(false).unwrap();
    println!("{}", json_chainspec);
    let json_chainspec = this_does_not_compile(unimplemented!())
        .to_json(false)
        .unwrap();
    println!("{}", json_chainspec);
}

Why is this an issue?

It makes it impossible to dynamically generate a chainspec. The limitation will likely block projects like substrate-developer-hub/hacktoberfest#26.

Sugested fixes

Option 1

The genesis config does not need to be lazily evaluated. Replace the fn() -> G field with a simple G field. Where G: Clone

Option 2

Store an Fn() -> G instead.

@bddap

This comment has been minimized.

Copy link
Contributor Author

@bddap bddap commented Nov 15, 2019

Fixed by 9b8bfd7

@bddap bddap closed this Nov 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.