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

Implement OutOfRangeTx variant of Invalid bundle fraud proof #2039

Closed
wants to merge 9 commits into from
6 changes: 6 additions & 0 deletions 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 crates/pallet-domains/src/domain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::block_tree::import_genesis_receipt;
use crate::pallet::DomainStakingSummary;
use crate::staking::StakingSummary;
use crate::{
Config, DomainRegistry, ExecutionReceiptOf, HoldIdentifier, NextDomainId, RuntimeRegistry,
Config, DomainRegistry, DomainRuntimeMap, ExecutionReceiptOf, HoldIdentifier, NextDomainId,
RuntimeRegistry,
};
use codec::{Decode, Encode};
use frame_support::traits::fungible::{Inspect, MutateHold};
Expand Down Expand Up @@ -125,9 +126,10 @@ pub(crate) fn do_instantiate_domain<T: Config>(
can_instantiate_domain::<T>(&owner_account_id, &domain_config)?;

let domain_id = NextDomainId::<T>::get();
let runtime_id = domain_config.runtime_id;

let genesis_receipt = {
let runtime_obj = RuntimeRegistry::<T>::get(domain_config.runtime_id)
let runtime_obj = RuntimeRegistry::<T>::get(runtime_id)
.expect("Runtime object must exist as checked in `can_instantiate_domain`; qed");
initialize_genesis_receipt::<T>(
domain_id,
Expand All @@ -146,6 +148,7 @@ pub(crate) fn do_instantiate_domain<T: Config>(
raw_genesis_config,
};
DomainRegistry::<T>::insert(domain_id, domain_obj);
DomainRuntimeMap::<T>::insert(domain_id, runtime_id);

let next_domain_id = domain_id.checked_add(&1.into()).ok_or(Error::MaxDomainId)?;
NextDomainId::<T>::set(next_domain_id);
Expand Down Expand Up @@ -208,10 +211,9 @@ fn initialize_genesis_receipt<T: Config>(
mod tests {
use super::*;
use crate::pallet::{DomainRegistry, NextDomainId, RuntimeRegistry};
use crate::runtime_registry::RuntimeObject;
use crate::tests::{new_test_ext, GenesisStateRootGenerater, Test};
use frame_support::traits::Currency;
use sp_domains::GenesisReceiptExtension;
use sp_domains::{GenesisReceiptExtension, RuntimeObject};
use sp_std::vec;
use sp_version::RuntimeVersion;
use std::sync::Arc;
Expand Down
41 changes: 27 additions & 14 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ use sp_domains::verification::{
};
use sp_domains::{
DomainBlockLimit, DomainId, DomainInstanceData, ExecutionReceipt, OpaqueBundle, OperatorId,
OperatorPublicKey, ProofOfElection, RuntimeId, DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT,
EMPTY_EXTRINSIC_ROOT,
OperatorPublicKey, ProofOfElection, ReceiptHash, RuntimeId,
DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT, EMPTY_EXTRINSIC_ROOT,
};
use sp_runtime::traits::{BlakeTwo256, CheckedSub, Hash, One, Zero};
use sp_runtime::{RuntimeAppPublic, SaturatedConversion, Saturating};
Expand Down Expand Up @@ -90,6 +90,13 @@ pub type OpaqueBundleOf<T> = OpaqueBundle<
BalanceOf<T>,
>;

pub type FraudProofOf<T> = FraudProof<
BlockNumberFor<T>,
<T as frame_system::Config>::Hash,
<T as Config>::DomainNumber,
<T as Config>::DomainHash,
>;

/// Parameters used to verify proof of election.
#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub(crate) struct ElectionVerificationParams<Balance> {
Expand All @@ -110,8 +117,7 @@ mod pallet {
};
use crate::runtime_registry::{
do_register_runtime, do_schedule_runtime_upgrade, do_upgrade_runtimes,
register_runtime_at_genesis, Error as RuntimeRegistryError, RuntimeObject,
ScheduledRuntimeUpgrade,
register_runtime_at_genesis, Error as RuntimeRegistryError, ScheduledRuntimeUpgrade,
};
#[cfg(not(feature = "runtime-benchmarks"))]
use crate::staking::do_reward_operators;
Expand All @@ -128,7 +134,8 @@ mod pallet {
};
use crate::weights::WeightInfo;
use crate::{
BalanceOf, ElectionVerificationParams, HoldIdentifier, NominatorId, OpaqueBundleOf,
BalanceOf, ElectionVerificationParams, FraudProofOf, HoldIdentifier, NominatorId,
OpaqueBundleOf,
};
use codec::FullCodec;
use frame_support::pallet_prelude::*;
Expand All @@ -138,12 +145,12 @@ mod pallet {
use frame_support::{Identity, PalletError};
use frame_system::pallet_prelude::*;
use sp_core::H256;
use sp_domains::fraud_proof::{DeriveExtrinsics, FraudProof, StorageKeys};
use sp_domains::fraud_proof::{DeriveExtrinsics, StorageKeys};
use sp_domains::inherents::{InherentError, InherentType, INHERENT_IDENTIFIER};
use sp_domains::transaction::InvalidTransactionCode;
use sp_domains::{
BundleDigest, DomainId, EpochIndex, GenesisDomain, OperatorId, ReceiptHash, RuntimeId,
RuntimeType,
RuntimeObject, RuntimeType,
};
use sp_runtime::traits::{
AtLeast32BitUnsigned, BlockNumberProvider, Bounded, CheckEqual, CheckedAdd, MaybeDisplay,
Expand Down Expand Up @@ -446,6 +453,11 @@ mod pallet {
OptionQuery,
>;

/// A handy mapping of `domain_id` -> `runtime_id`, used in fraud proof to generate storage
/// proof of the domain runtime code.
#[pallet::storage]
pub(super) type DomainRuntimeMap<T> = StorageMap<_, Identity, DomainId, RuntimeId, OptionQuery>;

/// The domain block tree, map (`domain_id`, `domain_block_number`) to the hash of a domain blocks,
/// which can be used get the domain block in `DomainBlocks`
#[pallet::storage]
Expand Down Expand Up @@ -863,7 +875,7 @@ mod pallet {
#[pallet::weight((Weight::from_all(10_000), Pays::No))]
pub fn submit_fraud_proof(
origin: OriginFor<T>,
fraud_proof: Box<FraudProof<BlockNumberFor<T>, T::Hash>>,
fraud_proof: Box<FraudProofOf<T>>,
) -> DispatchResult {
ensure_none(origin)?;

Expand Down Expand Up @@ -1395,8 +1407,7 @@ impl<T: Config> Pallet<T> {
}

pub fn runtime_id(domain_id: DomainId) -> Option<RuntimeId> {
DomainRegistry::<T>::get(domain_id)
.map(|domain_object| domain_object.domain_config.runtime_id)
DomainRuntimeMap::<T>::get(domain_id)
}

pub fn domain_instance_data(
Expand Down Expand Up @@ -1569,9 +1580,7 @@ impl<T: Config> Pallet<T> {
Ok(())
}

fn validate_fraud_proof(
fraud_proof: &FraudProof<BlockNumberFor<T>, T::Hash>,
) -> Result<(), FraudProofError> {
fn validate_fraud_proof(fraud_proof: &FraudProofOf<T>) -> Result<(), FraudProofError> {
let bad_receipt = DomainBlocks::<T>::get(fraud_proof.bad_receipt_hash())
.ok_or(FraudProofError::BadReceiptNotFound)?
.execution_receipt;
Expand Down Expand Up @@ -1762,6 +1771,10 @@ impl<T: Config> Pallet<T> {
});
}

pub fn execution_receipt_by_hash(hash: ReceiptHash) -> Option<ExecutionReceiptOf<T>> {
DomainBlocks::<T>::get(hash).map(|domain_block| domain_block.execution_receipt)
}

/// Returns if there are any ERs in the challenge period that have non empty extrinsics.
/// Note that Genesis ER is also considered special and hence non empty
pub fn non_empty_er_exists(domain_id: DomainId) -> bool {
Expand Down Expand Up @@ -1821,7 +1834,7 @@ where
}

/// Submits an unsigned extrinsic [`Call::submit_fraud_proof`].
pub fn submit_fraud_proof_unsigned(fraud_proof: FraudProof<BlockNumberFor<T>, T::Hash>) {
pub fn submit_fraud_proof_unsigned(fraud_proof: FraudProofOf<T>) {
let call = Call::submit_fraud_proof {
fraud_proof: Box::new(fraud_proof),
};
Expand Down
14 changes: 1 addition & 13 deletions crates/pallet-domains/src/runtime_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use frame_support::PalletError;
use frame_system::pallet_prelude::*;
use scale_info::TypeInfo;
use sp_core::Hasher;
use sp_domains::{DomainsDigestItem, RuntimeId, RuntimeType};
use sp_domains::{DomainsDigestItem, RuntimeId, RuntimeObject, RuntimeType};
use sp_runtime::traits::{CheckedAdd, Get};
use sp_runtime::DigestItem;
use sp_std::vec::Vec;
Expand All @@ -25,18 +25,6 @@ pub enum Error {
MaxScheduledBlockNumber,
}

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct RuntimeObject<Number, Hash> {
pub runtime_name: Vec<u8>,
pub runtime_type: RuntimeType,
pub runtime_upgrades: u32,
pub hash: Hash,
pub code: Vec<u8>,
pub version: RuntimeVersion,
pub created_at: Number,
pub updated_at: Number,
}

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct ScheduledRuntimeUpgrade {
pub code: Vec<u8>,
Expand Down
7 changes: 4 additions & 3 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use crate::domain_registry::{DomainConfig, DomainObject};
use crate::{
self as pallet_domains, BalanceOf, BlockTree, BundleError, Config, ConsensusBlockInfo,
DomainBlocks, DomainRegistry, ExecutionInbox, ExecutionReceiptOf, FraudProofError,
FungibleHoldId, HeadReceiptNumber, NextDomainId, Operator, OperatorStatus, Operators,
FraudProofOf, FungibleHoldId, HeadReceiptNumber, NextDomainId, Operator, OperatorStatus,
Operators,
};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::dispatch::RawOrigin;
Expand Down Expand Up @@ -827,7 +828,7 @@ fn generate_invalid_total_rewards_fraud_proof<T: Config>(
domain_id: DomainId,
bad_receipt_hash: ReceiptHash,
rewards: BalanceOf<T>,
) -> (FraudProof<BlockNumberFor<T>, T::Hash>, T::Hash) {
) -> (FraudProofOf<T>, T::Hash) {
let storage_key = sp_domains::fraud_proof::operator_block_rewards_final_key();
let mut root = T::Hash::default();
let mut mdb = PrefixedMemoryDB::<T::Hashing>::default();
Expand Down Expand Up @@ -901,7 +902,7 @@ fn generate_invalid_domain_extrinsic_root_fraud_proof<T: Config + pallet_timesta
bad_receipt_hash: ReceiptHash,
randomness: Randomness,
moment: Moment,
) -> (FraudProof<BlockNumberFor<T>, T::Hash>, T::Hash) {
) -> (FraudProofOf<T>, T::Hash) {
let randomness_storage_key =
frame_support::storage::storage_prefix("Subspace".as_ref(), "BlockRandomness".as_ref())
.to_vec();
Expand Down
28 changes: 13 additions & 15 deletions crates/sc-consensus-fraud-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@

//! Subspace fraud proof verification in the consensus level.

use codec::{Decode, Encode};
use sc_consensus::block_import::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult};
use sp_api::ProvideRuntimeApi;
use sp_consensus::Error as ConsensusError;
use sp_domains::DomainsApi;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use std::marker::PhantomData;
use std::sync::Arc;
use subspace_fraud_proof::VerifyFraudProof;
Expand All @@ -33,15 +32,15 @@ use subspace_fraud_proof::VerifyFraudProof;
///
/// This block import object should be used with the subspace consensus block import together until
/// the fraud proof verification can be done in the runtime properly.
pub struct FraudProofBlockImport<Block, Client, I, Verifier, DomainNumber, DomainHash> {
pub struct FraudProofBlockImport<Block, DomainBlock, Client, I, Verifier> {
inner: I,
client: Arc<Client>,
fraud_proof_verifier: Verifier,
_phantom: PhantomData<(Block, DomainNumber, DomainHash)>,
_phantom: PhantomData<(Block, DomainBlock)>,
}

impl<Block, Client, I, Verifier, DomainNumber, DomainHash> Clone
for FraudProofBlockImport<Block, Client, I, Verifier, DomainNumber, DomainHash>
impl<Block, DomainBlock, Client, I, Verifier> Clone
for FraudProofBlockImport<Block, DomainBlock, Client, I, Verifier>
where
I: Clone,
Verifier: Clone,
Expand All @@ -57,16 +56,15 @@ where
}

#[async_trait::async_trait]
impl<Block, Client, Inner, Verifier, DomainNumber, DomainHash> BlockImport<Block>
for FraudProofBlockImport<Block, Client, Inner, Verifier, DomainNumber, DomainHash>
impl<Block, DomainBlock, Client, Inner, Verifier> BlockImport<Block>
for FraudProofBlockImport<Block, DomainBlock, Client, Inner, Verifier>
where
Block: BlockT,
DomainBlock: BlockT,
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static,
Client::Api: DomainsApi<Block, DomainNumber, DomainHash>,
Client::Api: DomainsApi<Block, NumberFor<DomainBlock>, DomainBlock::Hash>,
Inner: BlockImport<Block, Error = ConsensusError> + Send + Sync,
Verifier: VerifyFraudProof<Block> + Send + Sync,
DomainNumber: Encode + Decode + Send + Sync,
DomainHash: Encode + Decode + Send + Sync,
Verifier: VerifyFraudProof<Block, DomainBlock> + Send + Sync,
{
type Error = ConsensusError;

Expand Down Expand Up @@ -110,15 +108,15 @@ where
}
}

pub fn block_import<Block, Client, I, Verifier, DomainNumber, DomainHash>(
pub fn block_import<Block, DomainBlock, Client, I, Verifier>(
client: Arc<Client>,
wrapped_block_import: I,
fraud_proof_verifier: Verifier,
) -> FraudProofBlockImport<Block, Client, I, Verifier, DomainNumber, DomainHash> {
) -> FraudProofBlockImport<Block, DomainBlock, Client, I, Verifier> {
FraudProofBlockImport {
inner: wrapped_block_import,
client,
fraud_proof_verifier,
_phantom: PhantomData::<(Block, DomainNumber, DomainHash)>,
_phantom: PhantomData::<(Block, DomainBlock)>,
}
}
2 changes: 2 additions & 0 deletions crates/sp-domains/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rand = { version = "0.8.5", default-features = false }
rand_chacha = { version = "0.3.1", default-features = false }
rs_merkle = { version = "1.4.1", default-features = false }
scale-info = { version = "2.7.0", default-features = false, features = ["derive"] }
sc-client-api = { version = "4.0.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7", optional = true }
serde = { version = "1.0.183", default-features = false, features = ["alloc", "derive"] }
sp-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-application-crypto = { version = "23.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
Expand Down Expand Up @@ -60,6 +61,7 @@ std = [
"rand_chacha/std",
"rs_merkle/std",
"scale-info/std",
"sc-client-api",
"serde/std",
"sp-api/std",
"sp-blockchain",
Expand Down
Loading
Loading