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

change: Feed block production log from session validator management pallet #513

Merged
merged 5 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 2 additions & 1 deletion Cargo.lock

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

10 changes: 6 additions & 4 deletions node/node/src/inherent_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ use sidechain_domain::{McBlockHash, ScEpochNumber};
use sidechain_mc_hash::McHashDataSource;
use sidechain_mc_hash::McHashInherentDataProvider as McHashIDP;
use sidechain_runtime::opaque::SessionKeys;
use sidechain_runtime::CrossChainPublic;
use sidechain_runtime::{opaque::Block, BeneficiaryId};
use sidechain_runtime::{BlockAuthor, CrossChainPublic};
use sidechain_slots::ScSlotConfig;
use sp_api::ProvideRuntimeApi;
use sp_block_production_log::BlockProducerIdInherentProvider;
use sp_block_production_log::BlockAuthorInherentProvider;
use sp_block_production_log::BlockProductionLogApi;
use sp_block_rewards::BlockBeneficiaryInherentProvider;
use sp_blockchain::HeaderBackend;
use sp_consensus_aura::{
Expand Down Expand Up @@ -56,13 +57,14 @@ where
ScEpochNumber,
>,
T::Api: NativeTokenManagementApi<Block>,
T::Api: BlockProductionLogApi<Block, CommitteeMember<CrossChainPublic, SessionKeys>>,
{
type InherentDataProviders = (
AuraIDP,
TimestampIDP,
McHashIDP,
AriadneIDP,
BlockProducerIdInherentProvider<BeneficiaryId>,
BlockAuthorInherentProvider<BlockAuthor>,
BlockBeneficiaryInherentProvider<BeneficiaryId>,
NativeTokenIDP,
);
Expand Down Expand Up @@ -101,7 +103,7 @@ where
)
.await?;
let block_producer_id_provider =
BlockProducerIdInherentProvider::from_env("SIDECHAIN_BLOCK_BENEFICIARY")?;
BlockAuthorInherentProvider::new(client.as_ref(), parent_hash)?;
let block_beneficiary_provider =
BlockBeneficiaryInherentProvider::<BeneficiaryId>::from_env(
"SIDECHAIN_BLOCK_BENEFICIARY",
Expand Down
15 changes: 9 additions & 6 deletions node/node/src/tests/inherent_data_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use authority_selection_inherents::{
authority_selection_inputs::AuthoritySelectionInputs, mock::MockAuthoritySelectionDataSource,
};
use hex_literal::hex;
use sidechain_domain::byte_string::SizedByteString;
use sidechain_domain::{
MainchainBlock, McBlockHash, McBlockNumber, McEpochNumber, McSlotNumber, NativeTokenAmount,
ScEpochNumber,
};
use sidechain_mc_hash::mock::MockMcHashDataSource;
use sidechain_runtime::BlockAuthor;
use sp_consensus_aura::Slot;
use sp_core::H256;
use sp_core::{ecdsa, H256};
use sp_inherents::CreateInherentDataProviders;
use sp_inherents::{InherentData, InherentDataProvider};
use sp_native_token_management::mock::MockNativeTokenDataSource;
Expand Down Expand Up @@ -97,11 +97,14 @@ async fn block_proposal_cidp_should_be_created_correctly() {
.is_some());
assert_eq!(
inherent_data
.get_data::<SizedByteString::<32>>(&sp_block_production_log::INHERENT_IDENTIFIER)
.get_data::<BlockAuthor>(&sp_block_production_log::INHERENT_IDENTIFIER)
.unwrap(),
Some(SizedByteString::<32>(hex!(
"0000000000000000000000000000000000000000000000000000000000000001"
)))
Some(BlockAuthor::ProBono(
ecdsa::Public::from_raw(hex!(
"000000000000000000000000000000000000000000000000000000000000000001"
))
.into()
))
);
}

Expand Down
14 changes: 14 additions & 0 deletions node/node/src/tests/runtime_api_mock.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use super::mock::mock_genesis_utxo;
use authority_selection_inherents::authority_selection_inputs::AuthoritySelectionInputs;
use authority_selection_inherents::CommitteeMember;
use hex_literal::hex;
use sidechain_domain::*;
use sidechain_mc_hash::McHashInherentDigest;
use sidechain_runtime::opaque::SessionKeys;
use sidechain_runtime::CrossChainPublic;
use sp_api::{ApiRef, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_core::ecdsa;
use sp_core::{ed25519, sr25519};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero};
use sp_runtime::Digest;
use sp_sidechain::GetGenesisUtxo;
Expand Down Expand Up @@ -107,6 +109,18 @@ sp_api::mock_impl_runtime_apis! {
true
}
}

impl sp_block_production_log::BlockProductionLogApi<Block, CommitteeMember<CrossChainPublic, SessionKeys>> for TestApi {
fn get_current_author() -> CommitteeMember<CrossChainPublic, SessionKeys> {
CommitteeMember::permissioned(
ecdsa::Public::from_raw(hex!("000000000000000000000000000000000000000000000000000000000000000001")).into(),
SessionKeys {
aura: sr25519::Public::default().into(),
grandpa: ed25519::Public::default().into()
}
)
}
}
}

impl HeaderBackend<Block> for TestApi {
Expand Down
2 changes: 2 additions & 0 deletions node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ frame-system-benchmarking = { workspace = true, optional = true }

# Local Dependencies
sp-block-rewards = { workspace = true }
sp-block-production-log = { workspace = true }
pallet-block-production-log = { workspace = true }
pallet-block-rewards = { workspace = true }
sp-sidechain = { workspace = true }
Expand Down Expand Up @@ -153,6 +154,7 @@ std = [
"pallet-native-token-management/std",
"sp-native-token-management/std",
"pallet-session-runtime-stub/std",
"sp-block-production-log/std",
]

runtime-benchmarks = [
Expand Down
61 changes: 57 additions & 4 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,19 @@ use opaque::SessionKeys;
use pallet_grandpa::AuthorityId as GrandpaId;
use pallet_session_validator_management;
use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
use parity_scale_codec::MaxEncodedLen;
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
use session_manager::ValidatorManagementSessionManager;
use sidechain_domain::{
NativeTokenAmount, PermissionedCandidateData, RegistrationData, ScEpochNumber, ScSlotNumber,
StakeDelegation, StakePoolPublicKey, UtxoId,
};
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{crypto::KeyTypeId, hexdisplay::HexDisplay, OpaqueMetadata};
use sp_core::hexdisplay::HexDisplay;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_core::{ByteArray, Pair};
use sp_runtime::{
generic, impl_opaque_keys,
traits::{
Expand Down Expand Up @@ -431,10 +436,18 @@ impl sp_sidechain::OnNewEpoch for LogBeneficiaries {
let slot = pallet_aura::CurrentSlot::<Runtime>::get();
let block_production_log = BlockProductionLog::take_prefix(&slot);
if let Some((s, b)) = block_production_log.first() {
log::info!("Block production log head: {} -> {}", **s, HexDisplay::from(&b.0))
log::info!(
"Block production log head: {} -> {:?}",
**s,
HexDisplay::from(&b.id().as_slice())
)
};
if let Some((s, b)) = block_production_log.last() {
log::info!("Block production log tail: {} -> {}", **s, HexDisplay::from(&b.0))
log::info!(
"Block production log tail: {} -> {:?}",
**s,
HexDisplay::from(&b.id().as_slice())
)
};
RuntimeDbWeight::get().reads_writes(1, 1)
}
Expand All @@ -455,8 +468,39 @@ impl pallet_block_rewards::Config for Runtime {
type GetBlockRewardPoints = sp_block_rewards::SimpleBlockCount;
}

#[derive(MaxEncodedLen, Encode, Decode, Clone, TypeInfo, PartialEq, Eq, Debug)]
pub enum BlockAuthor {
Incentivized(CrossChainPublic, StakePoolPublicKey),
ProBono(CrossChainPublic),
}
impl BlockAuthor {
pub fn id(&self) -> &CrossChainPublic {
match self {
Self::Incentivized(id, _) => id,
Self::ProBono(id) => id,
}
}
}
impl From<CommitteeMember<CrossChainPublic, SessionKeys>> for BlockAuthor {
fn from(value: CommitteeMember<CrossChainPublic, SessionKeys>) -> Self {
match value {
CommitteeMember::Permissioned { id, .. } => BlockAuthor::ProBono(id),
CommitteeMember::Registered { id, stake_pool_pub_key, .. } => {
BlockAuthor::Incentivized(id, stake_pool_pub_key)
},
}
}
}
#[cfg(feature = "runtime-benchmarks")]
impl From<[u8; 32]> for BlockAuthor {
fn from(arr: [u8; 32]) -> Self {
let id = sp_core::ecdsa::Pair::from_seed(&arr).public().into();
Self::ProBono(id)
}
}

impl pallet_block_production_log::Config for Runtime {
type BlockProducerId = BeneficiaryId;
type BlockProducerId = BlockAuthor;
type WeightInfo = pallet_block_production_log::weights::SubstrateWeight<Runtime>;

fn current_slot() -> sp_consensus_slots::Slot {
Expand Down Expand Up @@ -871,6 +915,15 @@ impl_runtime_apis! {
NativeTokenManagement::initialized()
}
}

impl sp_block_production_log::BlockProductionLogApi<Block, CommitteeMember<CrossChainPublic, SessionKeys>> for Runtime {
fn get_current_author() -> CommitteeMember<CrossChainPublic, SessionKeys> {
let mut committee = SessionCommitteeManagement::get_current_committee().1;
let slot = pallet_aura::CurrentSlot::<Runtime>::get();
// this implementation is compatible with round-robin employed by Aura
committee.remove(*slot as usize % committee.len())
}
}
}

#[cfg(test)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use crate::authority_selection_inputs::AuthoritySelectionDataSource;
use crate::authority_selection_inputs::AuthoritySelectionInputs;
use parity_scale_codec::{Decode, Encode};
use sp_session_validator_management::CommitteeMember as CommitteeMemberT;
#[cfg(feature = "std")]
use {
crate::authority_selection_inputs::AuthoritySelectionInputsCreationError,
Expand All @@ -13,6 +12,7 @@ use {
sp_consensus_slots::Slot,
sp_inherents::{InherentData, InherentIdentifier},
sp_runtime::traits::Block as BlockT,
sp_session_validator_management::CommitteeMember as CommitteeMemberT,
sp_session_validator_management::{
InherentError, MainChainScripts, SessionValidatorManagementApi, INHERENT_IDENTIFIER,
},
Expand Down
3 changes: 2 additions & 1 deletion toolkit/primitives/block-production-log/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ license = "Apache-2.0"
[dependencies]
async-trait = { workspace = true }
parity-scale-codec = { workspace = true }
sp-api = { workspace = true }
sp-core = { workspace = true, optional = true }
sp-inherents = { workspace = true }
sp-runtime = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
hex = { workspace = true }
sealed_test = { workspace = true }

[features]
default = ["std"]
Expand All @@ -26,4 +26,5 @@ std = [
"sp-core/std",
"sp-inherents/std",
"sp-runtime/std",
"sp-api/std",
]
58 changes: 35 additions & 23 deletions toolkit/primitives/block-production-log/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

#[cfg(test)]
mod test;

use parity_scale_codec::Encode;
use core::error::Error;
use parity_scale_codec::{Decode, Encode};
use sp_inherents::{InherentIdentifier, IsFatalError};
use sp_runtime::traits::Block as BlockT;
#[cfg(feature = "std")]
use {parity_scale_codec::Decode, sp_inherents::InherentData};
use {sp_api::ProvideRuntimeApi, sp_inherents::InherentData};

pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"blprdlog";

#[derive(Encode, PartialEq)]
#[cfg_attr(not(feature = "std"), derive(Debug))]
#[cfg_attr(feature = "std", derive(Decode, thiserror::Error, sp_runtime::RuntimeDebug))]
pub enum InherentError {
#[cfg_attr(feature = "std", error("Block Producer Id inherent must be provided every block"))]
#[cfg_attr(feature = "std", error("Block Author inherent must be provided every block"))]
InherentRequired,
}
impl IsFatalError for InherentError {
Expand All @@ -25,41 +29,40 @@ impl IsFatalError for InherentError {

#[cfg(feature = "std")]
#[derive(Debug)]
pub struct BlockProducerIdInherentProvider<T> {
pub id: T,
pub struct BlockAuthorInherentProvider<Author> {
pub author: Author,
}

#[cfg(feature = "std")]
impl<T> BlockProducerIdInherentProvider<T>
where
T: TryFrom<Vec<u8>> + Send + Sync + Encode,
<T as TryFrom<Vec<u8>>>::Error: std::fmt::Debug,
{
pub fn from_env(env_var: &str) -> Result<Self, String> {
let env_var_value = std::env::var(env_var).map_err(|_| {
format!("Block Producer Id environment variable '{env_var}' is not set")
})?;
let bytes = sp_core::bytes::from_hex(&env_var_value)
.map_err(|_| format!("Block Producer Id environment variable '{env_var}' value '{env_var_value}' is not a valid hex string"))?;
let id = T::try_from(bytes.clone()).map_err(|e| {
format!("Could not convert '{env_var_value}' into Block Producer Id. Cause: {e:#?}")
})?;
impl<Author> BlockAuthorInherentProvider<Author> {
pub fn new<C, Member, Block>(
client: &C,
parent_hash: Block::Hash,
) -> Result<Self, Box<dyn Error + Send + Sync>>
where
Member: Decode,
Block: BlockT,
C: ProvideRuntimeApi<Block>,
C::Api: BlockProductionLogApi<Block, Member>,
Author: From<Member>,
{
let author: Author = client.runtime_api().get_current_author(parent_hash)?.into();

Ok(BlockProducerIdInherentProvider { id })
Ok(BlockAuthorInherentProvider { author })
}
}

#[cfg(feature = "std")]
#[async_trait::async_trait]
impl<T> sp_inherents::InherentDataProvider for BlockProducerIdInherentProvider<T>
impl<T> sp_inherents::InherentDataProvider for BlockAuthorInherentProvider<T>
where
T: TryFrom<Vec<u8>> + Send + Sync + Encode,
T: Send + Sync + Encode + Decode,
{
async fn provide_inherent_data(
&self,
inherent_data: &mut InherentData,
) -> Result<(), sp_inherents::Error> {
inherent_data.put_data(INHERENT_IDENTIFIER, &self.id)
inherent_data.put_data(INHERENT_IDENTIFIER, &self.author)
}

async fn try_handle_error(
Expand All @@ -75,3 +78,12 @@ where
}
}
}

sp_api::decl_runtime_apis! {
pub trait BlockProductionLogApi<Member>
where
Member: Decode
{
fn get_current_author() -> Member;
}
}
Loading