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
4 changes: 4 additions & 0 deletions demo/node/src/tests/runtime_api_mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ sp_api::mock_impl_runtime_apis! {
permissioned_candidates_policy_id: PolicyId::default(),
}
}

fn get_pallet_version() -> u32 {
1
}
}

impl sp_block_participation::BlockParticipationApi<Block, BlockAuthor, Slot> for TestApi {
Expand Down
5 changes: 4 additions & 1 deletion demo/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,7 @@ impl_runtime_apis! {
}
}

#[api_version(3)]
#[api_version(4)]
impl sp_session_validator_management::SessionValidatorManagementApi<
Block,
CrossChainPublic,
Expand All @@ -1094,6 +1094,9 @@ impl_runtime_apis! {
fn get_main_chain_scripts() -> sp_session_validator_management::MainChainScripts {
SessionCommitteeManagement::get_main_chain_scripts()
}
fn get_pallet_version() -> u32 {
SessionCommitteeManagement::get_version()
}
}

impl authority_selection_inherents::CandidateValidationApi<Block> for Runtime {
Expand Down
21 changes: 10 additions & 11 deletions demo/runtime/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,16 @@ pub fn create_inherent_data_struct(
})
.collect();

AriadneInherentDataProvider {
data: Some(AuthoritySelectionInputs {
d_parameter: DParameter {
num_permissioned_candidates: 0,
num_registered_candidates: max(candidates.len() as u16, 1),
},
permissioned_candidates: vec![],
registered_candidates: candidates,
epoch_nonce: EpochNonce(DUMMY_EPOCH_NONCE.to_vec()),
}),
}
AriadneInherentDataProvider::V1(Some(AuthoritySelectionInputs {
d_parameter: DParameter {
num_permissioned_candidates: 0,
num_registered_candidates: max(candidates.len() as u16, 1),
num_native_stake_candidates: 0,
},
permissioned_candidates: vec![],
registered_candidates: candidates,
epoch_nonce: EpochNonce(DUMMY_EPOCH_NONCE.to_vec()),
}))
}

pub type CrossChainPair = <CrossChainPublic as CryptoType>::Pair;
Expand Down
12 changes: 8 additions & 4 deletions demo/runtime/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::mock::*;
use crate::*;
use authority_selection_inherents::AriadneInherentDataProvider;
use frame_support::{
dispatch::PostDispatchInfo,
inherent::ProvideInherent,
Expand Down Expand Up @@ -160,12 +161,15 @@ fn set_committee_through_inherent_data(expected_authorities: &[TestKeys]) -> Pos
expected_authorities.len()
);
let inherent_data_struct = create_inherent_data_struct(expected_authorities);
let ariadne_selection_inputs = match inherent_data_struct {
AriadneInherentDataProvider::Inert => panic!("Inert inherent data provider"),
AriadneInherentDataProvider::Legacy(inputs) => inputs.unwrap().into(),
AriadneInherentDataProvider::V1(inputs) => inputs.unwrap(),
};

let mut inherent_data = InherentData::new();
inherent_data
.put_data(
SessionCommitteeManagement::INHERENT_IDENTIFIER,
&inherent_data_struct.data.unwrap(),
)
.put_data(SessionCommitteeManagement::INHERENT_IDENTIFIER, &ariadne_selection_inputs)
.expect("Setting inherent data should not fail");
let call = <SessionCommitteeManagement as ProvideInherent>::create_inherent(&inherent_data)
.expect("Creating test inherent should not fail");
Expand Down
2 changes: 1 addition & 1 deletion toolkit/block-participation/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ extern crate alloc;
use alloc::vec::Vec;
use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
use scale_info::TypeInfo;
use sidechain_domain::{DelegatorKey, MainchainKeyHash, McEpochNumber};
use sidechain_domain::{DelegatorKey, MainchainKeyHash};
use sp_inherents::{InherentIdentifier, IsFatalError};

#[cfg(test)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
#[cfg(feature = "std")]
use crate::authority_selection_inputs::AuthoritySelectionDataSource;
use crate::authority_selection_inputs::AuthoritySelectionInputs;
use crate::authority_selection_inputs::AuthoritySelectionInputsLegacy;
use parity_scale_codec::{Decode, Encode};
#[cfg(feature = "std")]
use {
crate::authority_selection_inputs::AuthoritySelectionInputsCreationError,
sidechain_domain::mainchain_epoch::MainchainEpochDerivation,
sidechain_domain::*,
sp_api::ProvideRuntimeApi,
sp_api::{ApiExt, ProvideRuntimeApi},
sp_inherents::{InherentData, InherentIdentifier},
sp_runtime::traits::Block as BlockT,
sp_session_validator_management::{
Expand All @@ -21,9 +22,13 @@ pub use sidechain_domain::mainchain_epoch::MainchainEpochConfig;

#[derive(Clone, Debug, Encode, Decode)]
/// Inherent data provider providing inputs for authority selection.
pub struct AriadneInherentDataProvider {
/// Authority selection inputs.
pub data: Option<AuthoritySelectionInputs>,
pub enum AriadneInherentDataProvider {
/// No data available.
Inert,
/// Legacy authority selection inputs.
Legacy(Option<AuthoritySelectionInputsLegacy>),
/// Authority selection inputs with native stake support.
V1(Option<AuthoritySelectionInputs>),
}

#[cfg(feature = "std")]
Expand Down Expand Up @@ -66,27 +71,71 @@ impl AriadneInherentDataProvider {
// We could accept mc_reference at last slot of data_epoch, but calculations are much easier like that.
// Additionally, in current implementation, the inequality below is always true, thus there is no need to make it more accurate.
let scripts = client.runtime_api().get_main_chain_scripts(parent_hash)?;
if data_epoch < mc_reference_epoch {
Ok(AriadneInherentDataProvider::from_mc_data(data_source, for_mc_epoch, scripts)
.await?)
} else {
Ok(AriadneInherentDataProvider { data: None })

let api = client.runtime_api();

if !api
.has_api::<dyn SessionValidatorManagementApi<Block, AuthorityId, AuthorityKeys, ScEpochNumber>>(
parent_hash,
)? {
log::info!("💤 Legacy DParam observation. Pallet not detected in the runtime.");
return Ok(AriadneInherentDataProvider::from_mc_data_legacy(
data_source,
for_mc_epoch,
scripts,
)
.await?);
}

if data_epoch >= mc_reference_epoch {
return Ok(AriadneInherentDataProvider::Legacy(None));
}

match api.get_pallet_version(parent_hash).ok() {
None => Ok(AriadneInherentDataProvider::from_mc_data_legacy(
data_source,
for_mc_epoch,
scripts,
)
.await?),
Some(1) => {
Ok(AriadneInherentDataProvider::from_mc_data_v1(data_source, for_mc_epoch, scripts)
.await?)
},
unsupported_version => {
Err(InherentProviderCreationError::UnsupportedPalletVersion(unsupported_version, 1))
},
}
}

async fn from_mc_data_legacy(
candidate_data_source: &(dyn AuthoritySelectionDataSource + Send + Sync),
for_epoch: McEpochNumber,
scripts: MainChainScripts,
) -> Result<Self, InherentProviderCreationError> {
use crate::authority_selection_inputs::authority_selection_inputs_from_mc_data_legacy;

Ok(Self::Legacy(Some(
authority_selection_inputs_from_mc_data_legacy(
candidate_data_source,
for_epoch,
scripts,
)
.await?,
)))
}

async fn from_mc_data(
async fn from_mc_data_v1(
candidate_data_source: &(dyn AuthoritySelectionDataSource + Send + Sync),
for_epoch: McEpochNumber,
scripts: MainChainScripts,
) -> Result<Self, InherentProviderCreationError> {
use crate::authority_selection_inputs::authority_selection_inputs_from_mc_data;

Ok(Self {
data: Some(
authority_selection_inputs_from_mc_data(candidate_data_source, for_epoch, scripts)
.await?,
),
})
use crate::authority_selection_inputs::authority_selection_inputs_from_mc_data_v1;

Ok(Self::V1(Some(
authority_selection_inputs_from_mc_data_v1(candidate_data_source, for_epoch, scripts)
.await?,
)))
}
}

Expand All @@ -106,6 +155,9 @@ pub enum InherentProviderCreationError {
/// Data source call failed.
#[error("Data source call failed: {0}")]
DataSourceError(#[from] Box<dyn std::error::Error + Send + Sync>),
/// Unsupported pallet version.
#[error("Unsupported pallet version: got {0:?}, expected {1}")]
UnsupportedPalletVersion(Option<u32>, u32),
}

#[cfg(feature = "std")]
Expand Down Expand Up @@ -154,9 +206,16 @@ impl sp_inherents::InherentDataProvider for AriadneInherentDataProvider {
&self,
inherent_data: &mut InherentData,
) -> Result<(), sp_inherents::Error> {
match &self.data {
None => Ok(()),
Some(data) => inherent_data.put_data(INHERENT_IDENTIFIER, data),
match &self {
AriadneInherentDataProvider::Inert => Ok(()),
AriadneInherentDataProvider::Legacy(data) => match data {
None => Ok(()),
Some(data) => inherent_data.put_data(INHERENT_IDENTIFIER, data),
},
AriadneInherentDataProvider::V1(data) => match data {
None => Ok(()),
Some(data) => inherent_data.put_data(INHERENT_IDENTIFIER, data),
},
}
}

Expand Down Expand Up @@ -189,6 +248,14 @@ mod tests {

const TIMESTAMP: u64 = 400_000;

fn has_data(provider: &AriadneInherentDataProvider) -> bool {
match provider {
AriadneInherentDataProvider::Inert => false,
AriadneInherentDataProvider::Legacy(data) => data.is_some(),
AriadneInherentDataProvider::V1(data) => data.is_some(),
}
}

#[tokio::test]
async fn return_empty_ariadne_cidp_if_runtime_requests_too_new_epoch() {
// This is the epoch number that is too new
Expand All @@ -207,7 +274,7 @@ mod tests {
.await;

assert!(empty_ariadne_idp.is_ok());
assert!(empty_ariadne_idp.unwrap().data.is_none());
assert!(!has_data(&empty_ariadne_idp.unwrap()));
}

#[tokio::test]
Expand Down Expand Up @@ -257,7 +324,7 @@ mod tests {
.await;

assert!(ariadne_idp.is_ok());
assert!(ariadne_idp.unwrap().data.is_some());
assert!(has_data(&ariadne_idp.unwrap()));
}

fn sc_epoch_duration_millis() -> u64 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use plutus::*;
use sidechain_domain::*;

/// Inherent data type provided by [crate::AriadneInherentDataProvider].
pub use sp_session_validator_management::AuthoritySelectionInputs;
pub use sp_session_validator_management::{
AuthoritySelectionInputs, AuthoritySelectionInputsLegacy,
};

#[cfg(feature = "std")]
#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -88,7 +90,7 @@ pub trait AuthoritySelectionDataSource {
}

#[cfg(feature = "std")]
pub(crate) async fn authority_selection_inputs_from_mc_data(
pub(crate) async fn authority_selection_inputs_from_mc_data_v1(
candidate_data_source: &(dyn AuthoritySelectionDataSource + Send + Sync),
for_epoch: McEpochNumber,
scripts: sp_session_validator_management::MainChainScripts,
Expand Down Expand Up @@ -147,3 +149,67 @@ pub(crate) async fn authority_selection_inputs_from_mc_data(
epoch_nonce,
})
}

#[cfg(feature = "std")]
pub(crate) async fn authority_selection_inputs_from_mc_data_legacy(
candidate_data_source: &(dyn AuthoritySelectionDataSource + Send + Sync),
for_epoch: McEpochNumber,
scripts: sp_session_validator_management::MainChainScripts,
) -> Result<AuthoritySelectionInputsLegacy, AuthoritySelectionInputsCreationError> {
let ariadne_parameters_response = candidate_data_source
.get_ariadne_parameters(
for_epoch,
scripts.d_parameter_policy_id.clone(),
scripts.permissioned_candidates_policy_id.clone(),
)
.await
.map_err(|err| {
AuthoritySelectionInputsCreationError::AriadneParametersQuery(
for_epoch,
scripts.d_parameter_policy_id.clone(),
scripts.permissioned_candidates_policy_id.clone(),
err,
)
})?;

let d_parameter = ariadne_parameters_response.d_parameter;
let no_permissioned_candidates_expected = d_parameter.num_permissioned_candidates == 0;
let permissioned_candidates = match ariadne_parameters_response.permissioned_candidates {
None if no_permissioned_candidates_expected => Vec::new(),
None => {
return Err(AuthoritySelectionInputsCreationError::AriadneParametersQuery(
for_epoch,
scripts.d_parameter_policy_id,
scripts.permissioned_candidates_policy_id,
("Expected Data Not Found: Permissioned Candidates List".to_string()).into(),
));
},
Some(permissioned_candidates) => permissioned_candidates,
};

let registered_candidates: Vec<CandidateRegistrations> = candidate_data_source
.get_candidates(for_epoch, scripts.committee_candidate_address.clone())
.await
.map_err(|err| {
AuthoritySelectionInputsCreationError::GetCandidatesQuery(
for_epoch,
scripts.committee_candidate_address.to_string(),
err,
)
})?;
let epoch_nonce_response = candidate_data_source
.get_epoch_nonce(for_epoch)
.await
.map_err(|err| AuthoritySelectionInputsCreationError::GetEpochNonceQuery(for_epoch, err))?;
let epoch_nonce = epoch_nonce_response.unwrap_or(EpochNonce(vec![]));

Ok(AuthoritySelectionInputsLegacy {
d_parameter: DParameterLegacy {
num_permissioned_candidates: d_parameter.num_permissioned_candidates,
num_registered_candidates: d_parameter.num_registered_candidates,
},
permissioned_candidates,
registered_candidates,
epoch_nonce,
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl AuthoritySelectionDataSource for MockAuthoritySelectionDataSource {
d_parameter: DParameter {
num_permissioned_candidates: self.num_permissioned_candidates,
num_registered_candidates: 2,
num_native_stake_candidates: 0,
},
permissioned_candidates: candidates.clone(),
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@ sp_api::mock_impl_runtime_apis! {
permissioned_candidates_policy_id: PolicyId::default(),
}
}
fn get_pallet_version() -> u32 {
1
}
}
}
Loading
Loading