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

Add genesis config to the genesis domain #1704

Merged
merged 11 commits into from
Aug 1, 2023
Merged
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 31 additions & 32 deletions crates/pallet-domains/src/domain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ use scale_info::TypeInfo;
use sp_core::Get;
use sp_domains::domain::generate_genesis_state_root;
use sp_domains::{
DomainId, DomainInstanceData, DomainsDigestItem, GenesisDomain, ReceiptHash, RuntimeId,
RuntimeType,
DomainId, DomainInstanceData, DomainsDigestItem, ReceiptHash, RuntimeId, RuntimeType,
};
use sp_runtime::traits::{CheckedAdd, Zero};
use sp_runtime::DigestItem;
Expand Down Expand Up @@ -56,22 +55,6 @@ pub struct DomainConfig {
pub target_bundles_per_block: u32,
}

impl DomainConfig {
pub(crate) fn from_genesis<T: Config>(
genesis_domain: &GenesisDomain<T::AccountId>,
runtime_id: RuntimeId,
) -> Self {
DomainConfig {
domain_name: genesis_domain.domain_name.clone(),
runtime_id,
max_block_size: genesis_domain.max_block_size,
max_block_weight: genesis_domain.max_block_weight,
bundle_slot_probability: genesis_domain.bundle_slot_probability,
target_bundles_per_block: genesis_domain.target_bundles_per_block,
}
}
}

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct DomainObject<Number, AccountId> {
/// The address of the domain creator, used to validate updating the domain config.
Expand All @@ -82,6 +65,12 @@ pub struct DomainObject<Number, AccountId> {
pub genesis_receipt_hash: ReceiptHash,
/// The domain config.
pub domain_config: DomainConfig,
/// The genesis config of the domain, encoded in json format.
//
/// NOTE: the WASM code in the `system-pallet` genesis config should be empty to avoid
/// redundancy with the `RuntimeRegistry`. Currently, this value only set to `Some` for
/// the genesis domain instance.
pub raw_genesis_config: Option<Vec<u8>>,
vedhavyas marked this conversation as resolved.
Show resolved Hide resolved
}

pub(crate) fn can_instantiate_domain<T: Config>(
Expand Down Expand Up @@ -130,6 +119,7 @@ pub(crate) fn do_instantiate_domain<T: Config>(
domain_config: DomainConfig,
owner_account_id: T::AccountId,
created_at: T::BlockNumber,
raw_genesis_config: Option<Vec<u8>>,
) -> Result<DomainId, Error> {
can_instantiate_domain::<T>(&owner_account_id, &domain_config)?;

Expand All @@ -138,7 +128,12 @@ pub(crate) fn do_instantiate_domain<T: Config>(
let genesis_receipt = {
let runtime_obj = RuntimeRegistry::<T>::get(domain_config.runtime_id)
.expect("Runtime object must exist as checked in `can_instantiate_domain`; qed");
initialize_genesis_receipt::<T>(domain_id, runtime_obj.runtime_type, runtime_obj.code)?
initialize_genesis_receipt::<T>(
domain_id,
runtime_obj.runtime_type,
runtime_obj.code,
raw_genesis_config.clone(),
)?
};
let genesis_receipt_hash = genesis_receipt.hash();

Expand All @@ -147,6 +142,7 @@ pub(crate) fn do_instantiate_domain<T: Config>(
created_at,
genesis_receipt_hash,
domain_config,
raw_genesis_config,
vedhavyas marked this conversation as resolved.
Show resolved Hide resolved
};
DomainRegistry::<T>::insert(domain_id, domain_obj);

Expand Down Expand Up @@ -183,13 +179,15 @@ fn initialize_genesis_receipt<T: Config>(
domain_id: DomainId,
runtime_type: RuntimeType,
runtime_code: Vec<u8>,
raw_genesis_config: Option<Vec<u8>>,
) -> Result<ExecutionReceiptOf<T>, Error> {
let consensus_genesis_hash = frame_system::Pallet::<T>::block_hash(T::BlockNumber::zero());
let genesis_state_root = generate_genesis_state_root(
domain_id,
DomainInstanceData {
runtime_type,
runtime_code,
raw_genesis_config,
},
)
.ok_or(Error::FailedToGenerateGenesisStateRoot)?;
Expand Down Expand Up @@ -237,15 +235,15 @@ mod tests {

// Failed to instantiate domain due to `domain_name` too long
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::DomainNameTooLong)
);
// Recorrect `domain_name`
domain_config.domain_name = b"evm-domain".to_vec();

// Failed to instantiate domain due to using unregistered runtime id
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::RuntimeNotFound)
);
// Register runtime id
Expand All @@ -271,59 +269,59 @@ mod tests {

// Failed to instantiate domain due to exceed max domain block size limit
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::ExceedMaxDomainBlockSize)
);
// Recorrect `max_block_size`
domain_config.max_block_size = 1;

// Failed to instantiate domain due to exceed max domain block weight limit
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::ExceedMaxDomainBlockWeight)
);
// Recorrect `max_block_weight`
domain_config.max_block_weight = Weight::from_parts(1, 0);

// Failed to instantiate domain due to invalid `target_bundles_per_block`
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InvalidBundlesPerBlock)
);
domain_config.target_bundles_per_block = u32::MAX;
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InvalidBundlesPerBlock)
);
// Recorrect `target_bundles_per_block`
domain_config.target_bundles_per_block = 1;

// Failed to instantiate domain due to invalid `bundle_slot_probability`
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InvalidSlotProbability)
);
domain_config.bundle_slot_probability = (1, 0);
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InvalidSlotProbability)
);
domain_config.bundle_slot_probability = (0, 1);
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InvalidSlotProbability)
);
domain_config.bundle_slot_probability = (2, 1);
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InvalidSlotProbability)
);
// Recorrect `bundle_slot_probability`
domain_config.bundle_slot_probability = (1, 1);

// Failed to instantiate domain due to creator don't have enough fund
assert_eq!(
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at),
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None),
Err(Error::InsufficientFund)
);
// Set enough fund to creator
Expand All @@ -335,7 +333,8 @@ mod tests {

// `instantiate_domain` must success now
let domain_id =
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at).unwrap();
do_instantiate_domain::<Test>(domain_config.clone(), creator, created_at, None)
.unwrap();
let domain_obj = DomainRegistry::<Test>::get(domain_id).unwrap();

assert_eq!(domain_obj.owner_account_id, creator);
Expand All @@ -347,7 +346,7 @@ mod tests {

// cannot use the locked funds to create a new domain instance
assert!(
do_instantiate_domain::<Test>(domain_config, creator, created_at)
do_instantiate_domain::<Test>(domain_config, creator, created_at, None)
== Err(Error::InsufficientFund)
)
});
Expand Down
34 changes: 21 additions & 13 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ mod pallet {
let who = ensure_signed(origin)?;
let created_at = frame_system::Pallet::<T>::current_block_number();

let domain_id = do_instantiate_domain::<T>(domain_config, who, created_at)
let domain_id = do_instantiate_domain::<T>(domain_config, who, created_at, None)
.map_err(Error::<T>::from)?;

Self::deposit_event(Event::DomainInstantiated { domain_id });
Expand Down Expand Up @@ -899,24 +899,32 @@ mod pallet {
impl<T: Config> Hooks<T::BlockNumber> for Pallet<T> {
fn on_initialize(block_number: T::BlockNumber) -> Weight {
if block_number.is_one() {
if let Some(ref genesis_domain) = PendingGenesisDomain::<T>::take() {
if let Some(genesis_domain) = PendingGenesisDomain::<T>::take() {
// Register the genesis domain runtime
let runtime_id = register_runtime_at_genesis::<T>(
genesis_domain.runtime_name.clone(),
genesis_domain.runtime_type.clone(),
genesis_domain.runtime_version.clone(),
genesis_domain.code.clone(),
genesis_domain.runtime_name,
genesis_domain.runtime_type,
genesis_domain.runtime_version,
genesis_domain.code,
Zero::zero(),
)
.expect("Genesis runtime registration must always succeed");

// Instantiate the genesis domain
let domain_config = DomainConfig::from_genesis::<T>(genesis_domain, runtime_id);
let domain_owner = genesis_domain.owner_account_id.clone();
let domain_config = DomainConfig {
domain_name: genesis_domain.domain_name,
runtime_id,
max_block_size: genesis_domain.max_block_size,
max_block_weight: genesis_domain.max_block_weight,
bundle_slot_probability: genesis_domain.bundle_slot_probability,
target_bundles_per_block: genesis_domain.target_bundles_per_block,
};
let domain_owner = genesis_domain.owner_account_id;
let domain_id = do_instantiate_domain::<T>(
domain_config,
domain_owner.clone(),
Zero::zero(),
Some(genesis_domain.raw_genesis_config),
)
.expect("Genesis domain instantiation must always succeed");

Expand Down Expand Up @@ -1042,14 +1050,14 @@ impl<T: Config> Pallet<T> {
}

pub fn domain_instance_data(domain_id: DomainId) -> Option<DomainInstanceData> {
let runtime_id = DomainRegistry::<T>::get(domain_id)?
.domain_config
.runtime_id;
let (runtime_type, runtime_code) = RuntimeRegistry::<T>::get(runtime_id)
.map(|runtime_object| (runtime_object.runtime_type, runtime_object.code))?;
let domain_obj = DomainRegistry::<T>::get(domain_id)?;
let (runtime_type, runtime_code) =
RuntimeRegistry::<T>::get(domain_obj.domain_config.runtime_id)
.map(|runtime_object| (runtime_object.runtime_type, runtime_object.code))?;
Some(DomainInstanceData {
runtime_type,
runtime_code,
raw_genesis_config: domain_obj.raw_genesis_config,
})
}

Expand Down
1 change: 1 addition & 0 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ fn test_bundle_fromat_verification() {
created_at: Default::default(),
genesis_receipt_hash: Default::default(),
domain_config,
raw_genesis_config: None,
};
DomainRegistry::<Test>::insert(domain_id, domain_obj);

Expand Down
6 changes: 6 additions & 0 deletions crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ pub struct GenesisDomain<AccountId> {
pub max_block_weight: Weight,
pub bundle_slot_probability: (u64, u64),
pub target_bundles_per_block: u32,
pub raw_genesis_config: Vec<u8>,

// Genesis operator
pub signing_key: OperatorPublicKey,
Expand Down Expand Up @@ -515,6 +516,11 @@ impl DomainsDigestItem for DigestItem {
pub struct DomainInstanceData {
pub runtime_type: RuntimeType,
pub runtime_code: Vec<u8>,
// The genesis config of the domain, encoded in json format.
//
// NOTE: the WASM code in the `system-pallet` genesis config should be empty to avoid
// redundancy with the `runtime_code` field.
pub raw_genesis_config: Option<Vec<u8>>,
vedhavyas marked this conversation as resolved.
Show resolved Hide resolved
}

impl PassBy for DomainInstanceData {
Expand Down
15 changes: 15 additions & 0 deletions crates/subspace-node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use crate::chain_spec_utils::{
chain_spec_properties, get_account_id_from_seed, get_public_key_from_seed,
};
use crate::domain::evm_chain_spec::{self, SpecId};
use sc_service::{ChainType, NoExtension};
use sc_subspace_chain_specs::ConsensusChainSpec;
use sc_telemetry::TelemetryEndpoints;
Expand Down Expand Up @@ -137,6 +138,7 @@ pub fn gemini_3e_compiled() -> Result<ConsensusChainSpec<GenesisConfig>, String>
})
.collect::<Vec<_>>();
subspace_genesis_config(
SpecId::Gemini,
WASM_BINARY.expect("Wasm binary must be built for Gemini"),
sudo_account,
balances,
Expand Down Expand Up @@ -230,6 +232,7 @@ pub fn devnet_config_compiled() -> Result<ConsensusChainSpec<GenesisConfig>, Str
})
.collect::<Vec<_>>();
subspace_genesis_config(
SpecId::DevNet,
WASM_BINARY.expect("Wasm binary must be built for Gemini"),
sudo_account,
balances,
Expand Down Expand Up @@ -272,6 +275,7 @@ pub fn dev_config() -> Result<ConsensusChainSpec<GenesisConfig>, String> {
ChainType::Development,
|| {
subspace_genesis_config(
SpecId::Dev,
wasm_binary,
// Sudo account
get_account_id_from_seed("Alice"),
Expand Down Expand Up @@ -318,6 +322,7 @@ pub fn local_config() -> Result<ConsensusChainSpec<GenesisConfig>, String> {
ChainType::Local,
|| {
subspace_genesis_config(
SpecId::Local,
wasm_binary,
// Sudo account
get_account_id_from_seed("Alice"),
Expand Down Expand Up @@ -363,6 +368,7 @@ pub fn local_config() -> Result<ConsensusChainSpec<GenesisConfig>, String> {

/// Configure initial storage state for FRAME modules.
fn subspace_genesis_config(
spec_id: SpecId,
wasm_binary: &[u8],
sudo_account: AccountId,
balances: Vec<(AccountId, Balance)>,
Expand All @@ -379,6 +385,14 @@ fn subspace_genesis_config(
confirmation_depth_k,
} = genesis_params;

let raw_domain_genesis_config = {
let mut domain_genesis_config = evm_chain_spec::get_testnet_genesis_by_spec_id(spec_id);
// Clear the WASM code of the genesis config since it is duplicated with `GenesisDomain::code`
domain_genesis_config.system = Default::default();
NingLin-P marked this conversation as resolved.
Show resolved Hide resolved
serde_json::to_vec(&domain_genesis_config)
.expect("Genesis config serialization never fails; qed")
};

GenesisConfig {
system: SystemConfig {
// Add Wasm runtime to storage.
Expand Down Expand Up @@ -417,6 +431,7 @@ fn subspace_genesis_config(
max_block_weight: MaxDomainBlockWeight::get(),
bundle_slot_probability: (1, 1),
target_bundles_per_block: 10,
raw_genesis_config: raw_domain_genesis_config,

// TODO: Configurable genesis operator signing key.
signing_key: get_public_key_from_seed::<OperatorPublicKey>("Alice"),
Expand Down
Loading