From 29b5e0b947b780aa17578b340258b12852600a7f Mon Sep 17 00:00:00 2001 From: Nikolaos Dymitriadis Date: Wed, 21 Aug 2024 10:50:52 +0200 Subject: [PATCH] Native token inherent data provider Signed-off-by: Nikolaos Dymitriadis --- Cargo.lock | 22 +++ Cargo.toml | 5 +- node/Cargo.toml | 1 + node/src/inherent_data.rs | 31 +++- node/src/tests/inherent_data_tests.rs | 27 +++- node/src/tests/runtime_api_mock.rs | 22 ++- primitives/native-token-management/Cargo.toml | 45 ++++++ primitives/native-token-management/src/lib.rs | 117 ++++++++++++++ .../native-token-management/src/tests/mod.rs | 148 ++++++++++++++++++ .../src/tests/runtime_api_mock.rs | 69 ++++++++ primitives/sidechain-mc-hash/Cargo.toml | 3 +- primitives/sidechain-mc-hash/src/lib.rs | 44 +++++- runtime/Cargo.toml | 2 + runtime/src/lib.rs | 10 ++ 14 files changed, 529 insertions(+), 17 deletions(-) create mode 100644 primitives/native-token-management/Cargo.toml create mode 100644 primitives/native-token-management/src/lib.rs create mode 100644 primitives/native-token-management/src/tests/mod.rs create mode 100644 primitives/native-token-management/src/tests/runtime_api_mock.rs diff --git a/Cargo.lock b/Cargo.lock index 536b0d6f4..14b2c7a53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6098,6 +6098,7 @@ dependencies = [ "sp-inherents", "sp-io", "sp-keyring", + "sp-native-token-management", "sp-runtime", "sp-session-validator-management", "sp-session-validator-management-query", @@ -8984,6 +8985,7 @@ dependencies = [ "async-trait", "main-chain-follower-api", "sidechain-domain", + "sp-blockchain", "sp-consensus", "sp-consensus-slots", "sp-inherents", @@ -9043,6 +9045,7 @@ dependencies = [ "sp-inherents", "sp-io", "sp-keyring", + "sp-native-token-management", "sp-offchain", "sp-partner-chains-session", "sp-runtime", @@ -9591,6 +9594,25 @@ dependencies = [ "sp-application-crypto", ] +[[package]] +name = "sp-native-token-management" +version = "0.1.0" +dependencies = [ + "async-trait", + "main-chain-follower-api", + "parity-scale-codec", + "scale-info", + "serde", + "sidechain-domain", + "sidechain-mc-hash", + "sp-api", + "sp-blockchain", + "sp-inherents", + "sp-runtime", + "thiserror", + "tokio", +] + [[package]] name = "sp-offchain" version = "34.0.0" diff --git a/Cargo.toml b/Cargo.toml index b4b6fa6ce..3514a6cf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,8 @@ members = [ "primitives/session-validator-management/query", "primitives/session-manager", "primitives/sidechain", - "partner-chains-cli" -] + "partner-chains-cli", + "primitives/native-token-management"] resolver = "2" [profile.release] @@ -188,3 +188,4 @@ authority-selection-inherents = { path = "primitives/authority-selection-inheren session-manager = { path = "primitives/session-manager", default-features = false } sp-sidechain = { path = "primitives/sidechain", default-features = false } chain-params = { path = "primitives/chain-params", default-features = false } +sp-native-token-management = { path = "primitives/native-token-management", default-features = false } diff --git a/node/Cargo.toml b/node/Cargo.toml index 965a62c0f..e50638a7c 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -87,6 +87,7 @@ frame-benchmarking-cli = { workspace = true } # Local Dependencies sidechain-runtime = { workspace = true } sidechain-mc-hash = { workspace = true, features = ["mock"] } +sp-native-token-management = { workspace = true } main-chain-follower-api = { workspace = true } db-sync-follower = { workspace = true, features = ["block-source", "candidate-source", "native-token"] } main-chain-follower-mock = { workspace = true, features = ["block-source", "candidate-source", "native-token"] } diff --git a/node/src/inherent_data.rs b/node/src/inherent_data.rs index d450b8617..79e823d39 100644 --- a/node/src/inherent_data.rs +++ b/node/src/inherent_data.rs @@ -17,6 +17,8 @@ use sp_consensus_aura::inherents::InherentDataProvider as AuraIDP; use sp_consensus_aura::{sr25519::AuthorityPair as AuraPair, Slot}; use sp_core::Pair; use sp_inherents::CreateInherentDataProviders; +use sp_native_token_management::NativeTokenManagementApi; +use sp_native_token_management::NativeTokenManagementInherentDataProvider as NativeTokenIDP; use sp_runtime::traits::{Block as BlockT, Header, Zero}; use sp_session_validator_management::SessionValidatorManagementApi; use sp_timestamp::InherentDataProvider as TimestampIDP; @@ -38,6 +40,7 @@ pub struct ProposalCIDP { impl CreateInherentDataProviders for ProposalCIDP where T: ProvideRuntimeApi + Send + Sync + 'static, + T: HeaderBackend, T::Api: SessionValidatorManagementApi< Block, SessionKeys, @@ -45,6 +48,7 @@ where AuthoritySelectionInputs, ScEpochNumber, >, + T::Api: NativeTokenManagementApi, { #[cfg(feature = "block-beneficiary")] type InherentDataProviders = ( @@ -53,9 +57,10 @@ where McHashIDP, AriadneIDP, BlockBeneficiaryInherentProvider, + NativeTokenIDP, ); #[cfg(not(feature = "block-beneficiary"))] - type InherentDataProviders = (AuraIDP, TimestampIDP, McHashIDP, AriadneIDP); + type InherentDataProviders = (AuraIDP, TimestampIDP, McHashIDP, AriadneIDP, NativeTokenIDP); async fn create_inherent_data_providers( &self, @@ -89,6 +94,14 @@ where "SIDECHAIN_BLOCK_BENEFICIARY", )?; + let native_token = NativeTokenIDP::new( + client.clone(), + data_sources.native_token.as_ref(), + mc_hash.mc_hash(), + parent_hash.clone(), + ) + .await?; + Ok(( slot, timestamp, @@ -96,6 +109,7 @@ where ariadne_data_provider, #[cfg(feature = "block-beneficiary")] block_beneficiary_provider, + native_token, )) } } @@ -124,8 +138,9 @@ where AuthoritySelectionInputs, ScEpochNumber, >, + T::Api: NativeTokenManagementApi, { - type InherentDataProviders = (TimestampIDP, AriadneIDP); + type InherentDataProviders = (TimestampIDP, AriadneIDP, NativeTokenIDP); async fn create_inherent_data_providers( &self, @@ -142,7 +157,7 @@ where parent_header, parent_slot, verified_block_slot, - mc_hash, + mc_hash.clone(), config.slot_duration(), data_sources.block.as_ref(), ) @@ -159,7 +174,15 @@ where ) .await?; - Ok((timestamp, ariadne_data_provider)) + let native_token = NativeTokenIDP::new( + client.clone(), + data_sources.native_token.as_ref(), + mc_hash, + parent_hash.clone(), + ) + .await?; + + Ok((timestamp, ariadne_data_provider, native_token)) } } diff --git a/node/src/tests/inherent_data_tests.rs b/node/src/tests/inherent_data_tests.rs index 78ff3c6d6..30f08ecb3 100644 --- a/node/src/tests/inherent_data_tests.rs +++ b/node/src/tests/inherent_data_tests.rs @@ -1,9 +1,11 @@ use crate::inherent_data::{ProposalCIDP, VerifierCIDP}; use crate::tests::mock::{test_client, test_create_inherent_data_config}; -use crate::tests::runtime_api_mock::mock_header; +use crate::tests::runtime_api_mock::{mock_header, TestApi}; use authority_selection_inherents::authority_selection_inputs::AuthoritySelectionInputs; use main_chain_follower_api::{block::MainchainBlock, mock_services::*}; -use sidechain_domain::{McBlockHash, McBlockNumber, McEpochNumber, McSlotNumber}; +use sidechain_domain::{ + McBlockHash, McBlockNumber, McEpochNumber, McSlotNumber, NativeTokenAmount, ScEpochNumber, +}; use sp_consensus_aura::Slot; use sp_core::H256; use sp_inherents::CreateInherentDataProviders; @@ -20,7 +22,9 @@ async fn block_proposal_cidp_should_be_created_correctly() { let inherent_data_providers = ProposalCIDP::new( test_create_inherent_data_config(), - test_client(), + TestApi::new(ScEpochNumber(2)) + .with_headers([(H256::zero(), mock_header())]) + .into(), TestDataSources::new().into(), ) .create_inherent_data_providers(H256::zero(), ()) @@ -28,9 +32,10 @@ async fn block_proposal_cidp_should_be_created_correctly() { .unwrap(); #[cfg(not(feature = "block-beneficiary"))] - let (slot, timestamp, mc_hash, ariadne_data) = inherent_data_providers; + let (slot, timestamp, mc_hash, ariadne_data, native_token) = inherent_data_providers; #[cfg(feature = "block-beneficiary")] - let (slot, timestamp, mc_hash, ariadne_data, block_beneficiary) = inherent_data_providers; + let (slot, timestamp, mc_hash, ariadne_data, block_beneficiary, native_token) = + inherent_data_providers; let mut inherent_data = InherentData::new(); slot.provide_inherent_data(&mut inherent_data).await.unwrap(); timestamp.provide_inherent_data(&mut inherent_data).await.unwrap(); @@ -38,6 +43,7 @@ async fn block_proposal_cidp_should_be_created_correctly() { ariadne_data.provide_inherent_data(&mut inherent_data).await.unwrap(); #[cfg(feature = "block-beneficiary")] block_beneficiary.provide_inherent_data(&mut inherent_data).await.unwrap(); + native_token.provide_inherent_data(&mut inherent_data).await.unwrap(); assert_eq!( inherent_data .get_data::(&sp_consensus_aura::inherents::INHERENT_IDENTIFIER) @@ -63,6 +69,10 @@ async fn block_proposal_cidp_should_be_created_correctly() { .get_data::(&sp_session_validator_management::INHERENT_IDENTIFIER) .unwrap() .is_some()); + assert!(inherent_data + .get_data::(&sp_native_token_management::INHERENT_IDENTIFIER) + .unwrap() + .is_some()) } #[tokio::test] @@ -88,10 +98,11 @@ async fn block_verification_cidp_should_be_created_correctly() { .create_inherent_data_providers(mock_header().hash(), (30.into(), mc_block_hash)) .await .unwrap(); - let (timestamp, ariadne_data_provider) = inherent_data_providers; + let (timestamp, ariadne_data_provider, native_token_provider) = inherent_data_providers; let mut inherent_data = InherentData::new(); timestamp.provide_inherent_data(&mut inherent_data).await.unwrap(); ariadne_data_provider.provide_inherent_data(&mut inherent_data).await.unwrap(); + native_token_provider.provide_inherent_data(&mut inherent_data).await.unwrap(); assert_eq!( inherent_data.get_data::(&sp_timestamp::INHERENT_IDENTIFIER).unwrap(), @@ -101,4 +112,8 @@ async fn block_verification_cidp_should_be_created_correctly() { .get_data::(&sp_session_validator_management::INHERENT_IDENTIFIER) .unwrap() .is_some()); + assert!(inherent_data + .get_data::(&sp_native_token_management::INHERENT_IDENTIFIER) + .unwrap() + .is_some()) } diff --git a/node/src/tests/runtime_api_mock.rs b/node/src/tests/runtime_api_mock.rs index 543b21138..484b8fe24 100644 --- a/node/src/tests/runtime_api_mock.rs +++ b/node/src/tests/runtime_api_mock.rs @@ -7,15 +7,18 @@ use sidechain_runtime::opaque::SessionKeys; use sidechain_runtime::CrossChainPublic; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}; use sp_runtime::Digest; use sp_sidechain::GetSidechainParams; use std::collections::HashMap; +type Hash = ::Hash; +type Header = ::Header; + #[derive(Clone)] pub struct TestApi { pub next_unset_epoch_number: ScEpochNumber, - pub headers: HashMap<::Hash, ::Header>, + pub headers: HashMap, } impl TestApi { @@ -25,6 +28,10 @@ impl TestApi { headers.insert(header.hash(), header); Self { next_unset_epoch_number, headers } } + + pub fn with_headers>>(self, headers: Hs) -> Self { + Self { headers: headers.into(), ..self } + } } impl Default for TestApi { @@ -82,6 +89,17 @@ sp_api::mock_impl_runtime_apis! { } } } + + impl sp_native_token_management::NativeTokenManagementApi for TestApi { + fn get_main_chain_scripts() -> sp_native_token_management::MainChainScripts { + sp_native_token_management::MainChainScripts { + native_token_policy: Default::default(), + native_token_asset_name: Default::default(), + illiquid_supply_address: Default::default(), + + } + } + } } impl HeaderBackend for TestApi { diff --git a/primitives/native-token-management/Cargo.toml b/primitives/native-token-management/Cargo.toml new file mode 100644 index 000000000..e1d35f2c4 --- /dev/null +++ b/primitives/native-token-management/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "sp-native-token-management" +version = "0.1.0" +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +async-trait = { workspace = true, optional = true } +main-chain-follower-api = { workspace = true, optional = true, features = ["native-token"] } +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } +sidechain-domain = { workspace = true } +sidechain-mc-hash = { workspace = true, optional = true } +sp-api = { workspace = true } +sp-blockchain = { workspace = true, optional = true } +sp-inherents = { workspace = true } +sp-runtime = { workspace = true } +thiserror = { workspace = true, optional = true } +serde = { workspace = true, optional = true } + +[dev-dependencies] +tokio = { workspace = true } + +[features] +default = ["std"] +std = [ + "async-trait", + "main-chain-follower-api/std", + "parity-scale-codec/std", + "scale-info/std", + "sidechain-domain/std", + "sidechain-mc-hash", + "sp-api/std", + "sp-blockchain", + "sp-inherents/std", + "sp-runtime/std", + "thiserror" +] +serde = [ + "dep:serde", + "scale-info/serde", + "sidechain-domain/serde", +] diff --git a/primitives/native-token-management/src/lib.rs b/primitives/native-token-management/src/lib.rs new file mode 100644 index 000000000..5197078cf --- /dev/null +++ b/primitives/native-token-management/src/lib.rs @@ -0,0 +1,117 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +pub use inherent_provider::*; + +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sidechain_domain::*; +use sp_inherents::*; +use sp_runtime::{scale_info::TypeInfo, traits::Block as BlockT}; + +#[cfg(test)] +mod tests; + +pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"nattoken"; + +#[derive(Default, Debug, Clone, PartialEq, Eq, TypeInfo, Encode, Decode, MaxEncodedLen)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MainChainScripts { + pub native_token_policy: PolicyId, + pub native_token_asset_name: AssetName, + pub illiquid_supply_address: MainchainAddress, +} + +sp_api::decl_runtime_apis! { + pub trait NativeTokenManagementApi { + fn get_main_chain_scripts() -> MainChainScripts; + } +} + +#[derive(Decode, Encode)] +pub struct TokenTransferData { + pub token_amount: NativeTokenAmount, +} + +#[cfg(feature = "std")] +mod inherent_provider { + use super::*; + use main_chain_follower_api::{DataSourceError, NativeTokenManagementDataSource}; + use sidechain_mc_hash::get_mc_hash_for_block; + use sp_api::{ApiError, ProvideRuntimeApi}; + use sp_blockchain::HeaderBackend; + use std::error::Error; + use std::sync::Arc; + + pub struct NativeTokenManagementInherentDataProvider { + pub token_amount: NativeTokenAmount, + } + + #[derive(thiserror::Error, sp_runtime::RuntimeDebug)] + pub enum IDPCreationError { + #[error("Failed to read native token data from data source: {0:?}")] + DataSourceError(#[from] DataSourceError), + #[error("Failed to retrieve main chain scripts from the runtime: {0:?}")] + GetMainChainScriptsError(ApiError), + #[error("Failed to retrieve previous MC hash: {0:?}")] + McHashError(Box), + } + + impl NativeTokenManagementInherentDataProvider { + pub async fn new( + client: Arc, + data_source: &(dyn NativeTokenManagementDataSource + Send + Sync), + mc_hash: McBlockHash, + parent_hash: ::Hash, + ) -> Result + where + Block: BlockT, + C: HeaderBackend, + C: ProvideRuntimeApi + Send + Sync, + C::Api: NativeTokenManagementApi, + { + let api = client.runtime_api(); + let scripts = api + .get_main_chain_scripts(parent_hash) + .map_err(IDPCreationError::GetMainChainScriptsError)?; + let parent_mc_hash: Option = + get_mc_hash_for_block(client.as_ref(), parent_hash) + .map_err(IDPCreationError::McHashError)?; + let token_amount = data_source + .get_total_native_token_transfer( + parent_mc_hash, + mc_hash, + scripts.native_token_policy, + scripts.native_token_asset_name, + scripts.illiquid_supply_address, + ) + .await?; + + Ok(Self { token_amount }) + } + } + + #[async_trait::async_trait] + impl InherentDataProvider for NativeTokenManagementInherentDataProvider { + async fn provide_inherent_data( + &self, + inherent_data: &mut InherentData, + ) -> Result<(), sp_inherents::Error> { + inherent_data.put_data( + INHERENT_IDENTIFIER, + &TokenTransferData { token_amount: self.token_amount.clone() }, + ) + } + + async fn try_handle_error( + &self, + identifier: &InherentIdentifier, + _error: &[u8], + ) -> Option> { + if *identifier == INHERENT_IDENTIFIER { + panic!("BUG: {:?} inherent shouldn't return any errors", INHERENT_IDENTIFIER) + } else { + None + } + } + } +} diff --git a/primitives/native-token-management/src/tests/mod.rs b/primitives/native-token-management/src/tests/mod.rs new file mode 100644 index 000000000..ebf1db36f --- /dev/null +++ b/primitives/native-token-management/src/tests/mod.rs @@ -0,0 +1,148 @@ +pub(crate) mod runtime_api_mock; + +#[cfg(feature = "std")] +mod inherent_provider { + use super::runtime_api_mock::*; + use crate::inherent_provider::*; + use crate::INHERENT_IDENTIFIER; + use main_chain_follower_api::mock_services::MockNativeTokenDataSource; + use sidechain_domain::*; + use sidechain_mc_hash::MC_HASH_DIGEST_ID; + use sp_inherents::InherentData; + use sp_inherents::InherentDataProvider; + use sp_runtime::testing::Digest; + use sp_runtime::testing::DigestItem; + use std::sync::Arc; + + #[tokio::test] + async fn correctly_fetches_total_transfer_between_two_hashes() { + let parent_number = 1; // not genesis + + let mc_hash = McBlockHash([1; 32]); + let parent_hash = Hash::from([2; 32]); + let parent_mc_hash = Some(McBlockHash([3; 32])); + let total_transfered = 103; + + let data_source = + create_data_source(parent_mc_hash.clone(), mc_hash.clone(), total_transfered); + let client = create_client(parent_hash, parent_mc_hash, parent_number); + + let inherent_provider = NativeTokenManagementInherentDataProvider::new( + client, + &data_source, + mc_hash, + parent_hash, + ) + .await + .expect("Should not fail"); + + assert_eq!(inherent_provider.token_amount.0, total_transfered) + } + + #[tokio::test] + async fn fetches_with_no_lower_bound_when_parent_is_genesis() { + let parent_number = 0; // genesis + + let mc_hash = McBlockHash([1; 32]); + let parent_hash = Hash::from([2; 32]); + let parent_mc_hash = None; // genesis doesn't refer to any mc hash + let total_transfered = 103; + + let data_source = + create_data_source(parent_mc_hash.clone(), mc_hash.clone(), total_transfered); + let client = create_client(parent_hash, parent_mc_hash, parent_number); + + let inherent_provider = NativeTokenManagementInherentDataProvider::new( + client, + &data_source, + mc_hash, + parent_hash, + ) + .await + .expect("Should not fail"); + + assert_eq!(inherent_provider.token_amount.0, total_transfered) + } + + #[tokio::test] + async fn defaults_to_zero_when_no_data() { + let parent_number = 1; + + let mc_hash = McBlockHash([1; 32]); + let parent_hash = Hash::from([2; 32]); + let parent_mc_hash = Some(McBlockHash([3; 32])); + + let data_source = MockNativeTokenDataSource::new([].into()); + let client = create_client(parent_hash, parent_mc_hash, parent_number); + + let inherent_provider = NativeTokenManagementInherentDataProvider::new( + client, + &data_source, + mc_hash, + parent_hash, + ) + .await + .expect("Should not fail"); + + assert_eq!(inherent_provider.token_amount.0, 0) + } + + #[tokio::test] + async fn correctly_puts_data_into_inherent_data_structure() { + let token_amount = 1234; + + let mut inherent_data = InherentData::new(); + + let inherent_provider = NativeTokenManagementInherentDataProvider { + token_amount: NativeTokenAmount(token_amount), + }; + + inherent_provider.provide_inherent_data(&mut inherent_data).await.unwrap(); + + assert_eq!( + inherent_data + .get_data::(&INHERENT_IDENTIFIER) + .unwrap() + .unwrap() + .0, + token_amount + ) + } + + fn create_data_source( + parent_mc_hash: Option, + mc_hash: McBlockHash, + total_transfered: u128, + ) -> MockNativeTokenDataSource { + let total_transfered = NativeTokenAmount(total_transfered); + MockNativeTokenDataSource::new([((parent_mc_hash, mc_hash), total_transfered)].into()) + } + + fn create_client( + parent_hash: Hash, + parent_mc_hash: Option, + parent_number: u32, + ) -> Arc { + Arc::new(TestApi { + headers: [( + parent_hash.clone(), + Header { + digest: Digest { + logs: match parent_mc_hash { + None => vec![], + Some(parent_mc_hash) => vec![DigestItem::PreRuntime( + MC_HASH_DIGEST_ID, + parent_mc_hash.0.to_vec(), + )], + }, + }, + extrinsics_root: Default::default(), + number: parent_number, + parent_hash: parent_hash.clone(), + state_root: Default::default(), + }, + )] + .into(), + }) + } +} diff --git a/primitives/native-token-management/src/tests/runtime_api_mock.rs b/primitives/native-token-management/src/tests/runtime_api_mock.rs new file mode 100644 index 000000000..6d20917d6 --- /dev/null +++ b/primitives/native-token-management/src/tests/runtime_api_mock.rs @@ -0,0 +1,69 @@ +use sp_blockchain::HeaderBackend; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::collections::HashMap; + +use crate::MainChainScripts; + +pub type Block = sp_runtime::generic::Block< + sp_runtime::generic::Header, + sp_runtime::OpaqueExtrinsic, +>; + +pub type Hash = ::Hash; +pub type Header = ::Header; + +#[derive(Clone)] +pub struct TestApi { + pub headers: HashMap<::Hash, ::Header>, +} + +impl sp_api::ProvideRuntimeApi for TestApi { + type Api = TestApi; + + fn runtime_api(&self) -> sp_api::ApiRef { + self.clone().into() + } +} + +sp_api::mock_impl_runtime_apis! { + impl crate::NativeTokenManagementApi for TestApi { + fn get_main_chain_scripts() -> MainChainScripts { + MainChainScripts::default() + } + + } +} + +impl HeaderBackend for TestApi { + fn header( + &self, + id: ::Hash, + ) -> Result::Header>, sp_blockchain::Error> { + Ok(self.headers.get(&id).cloned()) + } + + fn info(&self) -> sp_blockchain::Info { + unimplemented!() + } + + fn status( + &self, + _id: ::Hash, + ) -> Result { + unimplemented!() + } + + fn number( + &self, + _hash: ::Hash, + ) -> Result>, sp_blockchain::Error> { + unimplemented!() + } + + fn hash( + &self, + _number: NumberFor, + ) -> Result::Hash>, sp_blockchain::Error> { + unimplemented!() + } +} diff --git a/primitives/sidechain-mc-hash/Cargo.toml b/primitives/sidechain-mc-hash/Cargo.toml index 163ff4c0e..fd6879525 100644 --- a/primitives/sidechain-mc-hash/Cargo.toml +++ b/primitives/sidechain-mc-hash/Cargo.toml @@ -7,9 +7,10 @@ description = "Logic for putting a main chain block reference in digest and inhe [dependencies] async-trait = { workspace = true } main-chain-follower-api = { workspace = true, features = ["block-source"] } -sp-consensus-slots = { workspace = true } +sp-consensus-slots = { workspace = true, features = ["std"] } sidechain-domain = { workspace = true, features = ["std"] } sp-consensus = { workspace = true } +sp-blockchain = { workspace = true } sp-inherents = { workspace = true, features = ["std"] } sp-runtime = { workspace = true, features = ["std"] } sp-timestamp = { workspace = true } diff --git a/primitives/sidechain-mc-hash/src/lib.rs b/primitives/sidechain-mc-hash/src/lib.rs index 56cdb3c97..971f24d93 100644 --- a/primitives/sidechain-mc-hash/src/lib.rs +++ b/primitives/sidechain-mc-hash/src/lib.rs @@ -3,9 +3,13 @@ use main_chain_follower_api::{ block::MainchainBlock, common::Timestamp as McTimestamp, BlockDataSource, DataSourceError, }; use sidechain_domain::{byte_string::ByteString, McBlockHash, McBlockNumber, McEpochNumber}; +use sp_blockchain::HeaderBackend; use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::{InherentData, InherentDataProvider, InherentDigest, InherentIdentifier}; -use sp_runtime::{traits::Header as HeaderT, DigestItem}; +use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT, Zero}, + DigestItem, +}; use sp_timestamp::Timestamp; use std::{error::Error, ops::Deref}; @@ -13,7 +17,7 @@ use std::{error::Error, ops::Deref}; mod test; pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"scmchash"; -const MC_HASH_DIGEST_ID: [u8; 4] = *b"mcsh"; +pub const MC_HASH_DIGEST_ID: [u8; 4] = *b"mcsh"; #[derive(Debug)] pub struct McHashInherentDataProvider { @@ -119,6 +123,10 @@ impl McHashInherentDataProvider { pub fn mc_block(&self) -> McBlockNumber { self.mc_block.number } + + pub fn mc_hash(&self) -> McBlockHash { + self.mc_block.hash.clone() + } } async fn get_mc_state_reference( @@ -201,6 +209,38 @@ impl InherentDigest for McHashInherentDigest { } } +pub fn get_inherent_digest_value_for_block( + client: &C, + block_hash: Block::Hash, +) -> Result, Box> +where + C: HeaderBackend, + Block::Hash: std::fmt::Debug, +{ + let header = (client.header(block_hash)) + .map_err(|err| format!("Failed to retrieve header for hash {block_hash:?}: {err:?}"))? + .ok_or(format!("Header for hash {block_hash:?} does not exist"))?; + + if header.number().is_zero() { + Ok(None) + } else { + let value = ID::value_from_digest(&header.digest().logs) + .map_err(|err| format!("Failed to retrieve inherent digest from header: {err:?}"))?; + Ok(Some(value)) + } +} + +pub fn get_mc_hash_for_block( + client: &C, + block_hash: Block::Hash, +) -> Result, Box> +where + C: HeaderBackend, + Block::Hash: std::fmt::Debug, +{ + get_inherent_digest_value_for_block::(client, block_hash) +} + #[cfg(any(feature = "mock", test))] pub mod mock { use super::*; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index dcd8d5271..4ca22842a 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -70,6 +70,7 @@ sidechain-domain = { workspace = true, features = ["serde"] } chain-params = { workspace = true, features = ["serde"] } sidechain-slots = { workspace = true } session-manager = { workspace = true } +sp-native-token-management = { workspace = true, features = ["serde"] } [dev-dependencies] sp-io = { workspace = true } @@ -140,6 +141,7 @@ std = [ "sidechain-domain/std", "sp-inherents/std", "chain-params/std", + "sp-native-token-management/std" ] runtime-benchmarks = [ diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index e94d05b33..39c7c7fef 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -838,6 +838,16 @@ impl_runtime_apis! { validate_permissioned_candidate_data::(candidate).err() } } + + impl sp_native_token_management::NativeTokenManagementApi for Runtime { + fn get_main_chain_scripts() -> sp_native_token_management::MainChainScripts { + sp_native_token_management::MainChainScripts { + native_token_policy: Default::default(), + native_token_asset_name: Default::default(), + illiquid_supply_address: Default::default(), + } + } + } } #[cfg(test)]