astar_collator/parachain/
shell_upgrade.rs

1// This file is part of Astar.
2
3// Copyright (C) Stake Technologies Pte.Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later
5
6// Astar is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// Astar is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18
19//! Utility for the upgrade from shell to a parachain runtime that implements Aura.
20use astar_primitives::*;
21use cumulus_primitives_core::relay_chain::PersistedValidationData;
22use cumulus_primitives_core::RelayParentOffsetApi;
23use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
24use fc_rpc::pending::ConsensusDataProvider;
25use sc_client_api::{AuxStore, UsageProvider};
26use sc_consensus::{import_queue::Verifier as VerifierT, BlockImportParams};
27use sp_api::{ApiExt, ProvideRuntimeApi};
28use sp_consensus_aura::{
29    digests::CompatibleDigestItem,
30    sr25519::{AuthorityId as AuraId, AuthoritySignature},
31    AuraApi,
32};
33use sp_inherents::{CreateInherentDataProviders, Error, InherentData};
34use sp_runtime::{
35    traits::{Block as BlockT, Header as HeaderT},
36    Digest, DigestItem,
37};
38use sp_timestamp::TimestampInherentData;
39use std::{marker::PhantomData, sync::Arc};
40
41pub struct Verifier<Client> {
42    pub client: Arc<Client>,
43    pub aura_verifier: Box<dyn VerifierT<Block>>,
44    pub relay_chain_verifier: Box<dyn VerifierT<Block>>,
45}
46
47#[async_trait::async_trait]
48impl<Client> VerifierT<Block> for Verifier<Client>
49where
50    Client: ProvideRuntimeApi<Block> + Send + Sync,
51    Client::Api: AuraApi<Block, AuraId>,
52{
53    async fn verify(
54        &self,
55        block_import: BlockImportParams<Block>,
56    ) -> Result<BlockImportParams<Block>, String> {
57        if self
58            .client
59            .runtime_api()
60            .has_api::<dyn AuraApi<Block, AuraId>>(*block_import.header.parent_hash())
61            .unwrap_or(false)
62        {
63            self.aura_verifier.verify(block_import).await
64        } else {
65            self.relay_chain_verifier.verify(block_import).await
66        }
67    }
68}
69
70/// AuraConsensusDataProvider custom implementation which awaits for AuraApi to become available,
71/// until then it will return error. Shiden genesis did not start with AuraApi, therefore this
72/// implementation makes sure to return digest after AuraApi becomes available.
73/// This is currently required by EVM RPC.
74pub struct AuraConsensusDataProviderFallback<B, C> {
75    client: Arc<C>,
76    phantom_data: PhantomData<B>,
77}
78
79impl<B, C> AuraConsensusDataProviderFallback<B, C>
80where
81    B: BlockT,
82    C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
83    C::Api: AuraApi<B, AuraId>,
84{
85    pub fn new(client: Arc<C>) -> Self {
86        Self {
87            client,
88            phantom_data: Default::default(),
89        }
90    }
91}
92
93impl<B, C> ConsensusDataProvider<B> for AuraConsensusDataProviderFallback<B, C>
94where
95    B: BlockT,
96    C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
97    C::Api: AuraApi<B, AuraId>,
98{
99    fn create_digest(&self, parent: &B::Header, data: &InherentData) -> Result<Digest, Error> {
100        if self
101            .client
102            .runtime_api()
103            .has_api::<dyn AuraApi<Block, AuraId>>(parent.hash())
104            .unwrap_or_default()
105        {
106            let slot_duration = sc_consensus_aura::slot_duration(&*self.client)
107                .expect("slot_duration should be present at this point; qed.");
108            let timestamp = data
109                .timestamp_inherent_data()?
110                .expect("Timestamp is always present; qed");
111
112            let digest_item =
113                <DigestItem as CompatibleDigestItem<AuthoritySignature>>::aura_pre_digest(
114                    sp_consensus_aura::Slot::from_timestamp(timestamp, slot_duration),
115                );
116
117            return Ok(Digest {
118                logs: vec![digest_item],
119            });
120        }
121        Err(Error::Application("AuraApi is not present".into()))
122    }
123}
124
125/// Shiden genesis did not start with AuraApi, therefore this implementation makes sure to return
126/// inherent data after AuraApi becomes available.
127/// This is currently required by EVM RPC.
128pub struct PendingCrateInherentDataProvider<B, C> {
129    client: Arc<C>,
130    phantom_data: PhantomData<B>,
131}
132
133impl<B, C> PendingCrateInherentDataProvider<B, C>
134where
135    B: BlockT,
136    C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
137    C::Api: AuraApi<B, AuraId>,
138{
139    pub fn new(client: Arc<C>) -> Self {
140        Self {
141            client,
142            phantom_data: Default::default(),
143        }
144    }
145}
146
147#[async_trait::async_trait]
148impl<B, C> CreateInherentDataProviders<B, ()> for PendingCrateInherentDataProvider<B, C>
149where
150    B: BlockT,
151    C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
152    C::Api: AuraApi<B, AuraId> + RelayParentOffsetApi<B>,
153{
154    type InherentDataProviders = (
155        sp_consensus_aura::inherents::InherentDataProvider,
156        sp_timestamp::InherentDataProvider,
157        cumulus_primitives_parachain_inherent::ParachainInherentData,
158    );
159
160    async fn create_inherent_data_providers(
161        &self,
162        parent: B::Hash,
163        _extra_args: (),
164    ) -> Result<Self::InherentDataProviders, Box<dyn std::error::Error + Send + Sync>> {
165        if !self
166            .client
167            .runtime_api()
168            .has_api::<dyn AuraApi<Block, AuraId>>(parent)
169            .unwrap_or_default()
170        {
171            return Err("AuraApi is not present".into());
172        }
173
174        let slot_duration = sc_consensus_aura::slot_duration(&*self.client)
175            .expect("slot_duration should be present at this point; qed.");
176        let current = sp_timestamp::InherentDataProvider::from_system_time();
177        let next_slot = current.timestamp().as_millis() + slot_duration.as_millis();
178        let timestamp = sp_timestamp::InherentDataProvider::new(next_slot.into());
179        let slot =
180            sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
181                *timestamp,
182                slot_duration,
183            );
184        // Create a dummy parachain inherent data provider which is required to pass
185        // the checks by the para chain system. We use dummy values because in the 'pending context'
186        // neither do we have access to the real values nor do we need them.
187        let (relay_parent_storage_root, relay_chain_state, relay_parent_descendants) = if self
188            .client
189            .runtime_api()
190            .has_api::<dyn RelayParentOffsetApi<B>>(parent)
191            .unwrap_or(false)
192        {
193            let offset = self
194                .client
195                .runtime_api()
196                .relay_parent_offset(parent)
197                .expect("API present, call should succeed; qed");
198            RelayStateSproofBuilder::default().into_state_root_proof_and_descendants(offset.into())
199        } else {
200            let (root, proof) = RelayStateSproofBuilder::default().into_state_root_and_proof();
201            (root, proof, Default::default())
202        };
203        let vfp = PersistedValidationData {
204            // This is a hack to make `cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases`
205            // happy. Relay parent number can't be bigger than u32::MAX.
206            relay_parent_number: u32::MAX,
207            relay_parent_storage_root,
208            ..Default::default()
209        };
210        let parachain_inherent_data =
211            cumulus_primitives_parachain_inherent::ParachainInherentData {
212                validation_data: vfp,
213                relay_chain_state,
214                downward_messages: Default::default(),
215                horizontal_messages: Default::default(),
216                relay_parent_descendants,
217                collator_peer_id: Default::default(),
218            };
219        Ok((slot, timestamp, parachain_inherent_data))
220    }
221}