Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Adds an offchain call to submit double vote reports (#966)
Browse files Browse the repository at this point in the history
* Adds an offchain call to submit double vote reports

* Some tweaks

* Remove unnecessary IdentifyAccount impls

* Adds ValidateDoubleVoteReports to test runtime

* sp-application-crypto is only a dev dependency
  • Loading branch information
montekki authored Apr 16, 2020
1 parent be1e2b3 commit dd59eb3
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 13 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

11 changes: 11 additions & 0 deletions primitives/src/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ application_crypto::with_pair! {
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
pub type ValidatorSignature = validator_app::Signature;

/// The key type ID for a fisherman key.
pub const FISHERMAN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"fish");

mod fisherman_app {
use application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::FISHERMAN_KEY_TYPE_ID);
}

/// Identity that fishermen use when generating reports.
pub type FishermanId = fisherman_app::Public;

/// Retriability for a given active para.
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
Expand Down
1 change: 1 addition & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ hex-literal = "0.2.1"
keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
babe = { package = "pallet-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
randomness-collective-flip = { package = "pallet-randomness-collective-flip", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate", branch = "master" }
treasury = { package = "pallet-treasury", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
Expand Down
80 changes: 77 additions & 3 deletions runtime/common/src/parachains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ use sp_runtime::transaction_validity::InvalidTransaction;

use inherents::{ProvideInherent, InherentData, MakeFatalError, InherentIdentifier};

use system::{ensure_none, ensure_signed};
use system::{
ensure_none, ensure_signed,
offchain::SubmitSignedTransaction,
};
use crate::attestations::{self, IncludedBlocks};
use crate::registrar::Registrar;

Expand Down Expand Up @@ -222,7 +225,7 @@ pub trait Trait: attestations::Trait + session::historical::Trait {
type Origin: From<Origin> + From<system::RawOrigin<Self::AccountId>>;

/// The outer call dispatch type.
type Call: Parameter + Dispatchable<Origin=<Self as Trait>::Origin>;
type Call: Parameter + Dispatchable<Origin=<Self as Trait>::Origin> + From<Call<Self>>;

/// Some way of interacting with balances for fees.
type ParachainCurrency: ParachainCurrency<Self::AccountId>;
Expand Down Expand Up @@ -290,6 +293,9 @@ pub trait Trait: attestations::Trait + session::historical::Trait {

/// A type that converts the opaque hash type to exact one.
type BlockHashConversion: Convert<Self::Hash, primitives::Hash>;

/// Submit a signed transaction.
type SubmitSignedTransaction: SubmitSignedTransaction<Self, <Self as Trait>::Call>;
}

/// Origin for the parachains module.
Expand Down Expand Up @@ -784,6 +790,21 @@ impl<T: Trait> Module<T> {
}
}

/// Submit a double vote report.
pub fn submit_double_vote_report(
report: DoubleVoteReport<T::Proof>,
) -> Option<()> {
let call = Call::report_double_vote(report);

let res = T::SubmitSignedTransaction::submit_signed(call);

if res.iter().any(|(_, r)| r.is_ok()) {
Some(())
} else {
None
}
}

/// Dispatch some messages from a parachain.
fn dispatch_message(
id: ParaId,
Expand Down Expand Up @@ -1426,6 +1447,13 @@ impl<T> sp_std::fmt::Debug for ValidateDoubleVoteReports<T> where
}
}

impl<T> ValidateDoubleVoteReports<T> {
/// Create a new `ValidateDoubleVoteReports` struct.
pub fn new() -> Self {
ValidateDoubleVoteReports(sp_std::marker::PhantomData)
}
}

/// Custom validity error used while validating double vote reports.
#[derive(RuntimeDebug)]
#[repr(u8)]
Expand Down Expand Up @@ -1522,7 +1550,7 @@ mod tests {
Perbill, curve::PiecewiseLinear,
traits::{
BlakeTwo256, IdentityLookup, SaturatedConversion,
OpaqueKeys,
OpaqueKeys, Extrinsic as ExtrinsicT,
},
testing::TestXt,
};
Expand Down Expand Up @@ -1787,6 +1815,31 @@ mod tests {
pub const SlashPeriod: BlockNumber = 50;
}

// This is needed for a custom `AccountId` type which is `u64` in testing here.
pub mod test_keys {
use sp_core::crypto::KeyTypeId;

pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");

mod app {
use sp_application_crypto::{app_crypto, sr25519};
use super::super::Parachains;

app_crypto!(sr25519, super::KEY_TYPE);

impl sp_runtime::traits::IdentifyAccount for Public {
type AccountId = u64;

fn into_account(self) -> Self::AccountId {
Parachains::authorities().iter().position(|b| *b == self.0.clone().into()).unwrap() as u64
}
}
}

pub type ReporterId = app::Public;
pub type ReporterSignature = app::Signature;
}

impl Trait for Test {
type Origin = Origin;
type Call = Call;
Expand All @@ -1807,6 +1860,27 @@ mod tests {
type ReportOffence = Offences;
type BlockHashConversion = sp_runtime::traits::Identity;
type KeyOwnerProofSystem = Historical;
type SubmitSignedTransaction = system::offchain::TransactionSubmitter<
test_keys::ReporterId,
Test,
Extrinsic,
>;
}

type Extrinsic = TestXt<Call, ()>;

impl system::offchain::CreateTransaction<Test, Extrinsic> for Test {
type Public = test_keys::ReporterId;
type Signature = test_keys::ReporterSignature;

fn create_transaction<F: system::offchain::Signer<Self::Public, Self::Signature>>(
call: <Extrinsic as ExtrinsicT>::Call,
_public: Self::Public,
_account: <Test as system::Trait>::AccountId,
nonce: <Test as system::Trait>::Index,
) -> Option<(<Extrinsic as ExtrinsicT>::Call, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
Some((call, (nonce, ())))
}
}

type Parachains = Module<Test>;
Expand Down
58 changes: 57 additions & 1 deletion runtime/common/src/registrar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,15 @@ impl<T: Trait> ActiveParas for Module<T> {
pub struct LimitParathreadCommits<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>) where
<T as system::Trait>::Call: IsSubType<Module<T>, T>;

impl<T: Trait + Send + Sync> LimitParathreadCommits<T> where
<T as system::Trait>::Call: IsSubType<Module<T>, T>
{
/// Create a new `LimitParathreadCommits` struct.
pub fn new() -> Self {
LimitParathreadCommits(sp_std::marker::PhantomData)
}
}

impl<T: Trait + Send + Sync> sp_std::fmt::Debug for LimitParathreadCommits<T> where
<T as system::Trait>::Call: IsSubType<Module<T>, T>
{
Expand Down Expand Up @@ -658,7 +667,7 @@ mod tests {
use sp_runtime::{
traits::{
BlakeTwo256, IdentityLookup, Dispatchable,
AccountIdConversion,
AccountIdConversion, Extrinsic as ExtrinsicT,
}, testing::{UintAuthorityId, TestXt}, KeyTypeId, Perbill, curve::PiecewiseLinear,
};
use primitives::{
Expand Down Expand Up @@ -840,6 +849,32 @@ mod tests {
type FullIdentificationOf = staking::ExposureOf<Self>;
}

// This is needed for a custom `AccountId` type which is `u64` in testing here.
pub mod test_keys {
use sp_core::crypto::KeyTypeId;

pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");

mod app {
use super::super::Parachains;
use sp_application_crypto::{app_crypto, sr25519};

app_crypto!(sr25519, super::KEY_TYPE);

impl sp_runtime::traits::IdentifyAccount for Public {
type AccountId = u64;

fn into_account(self) -> Self::AccountId {
let id = self.0.clone().into();
Parachains::authorities().iter().position(|b| *b == id).unwrap() as u64
}
}
}

pub type ReporterId = app::Public;
pub type ReporterSignature = app::Signature;
}

impl parachains::Trait for Test {
type Origin = Origin;
type Call = Call;
Expand All @@ -858,6 +893,27 @@ mod tests {
type IdentificationTuple = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, Vec<u8>)>>::IdentificationTuple;
type ReportOffence = ();
type BlockHashConversion = sp_runtime::traits::Identity;
type SubmitSignedTransaction = system::offchain::TransactionSubmitter<
test_keys::ReporterId,
Test,
Extrinsic,
>;
}

type Extrinsic = TestXt<Call, ()>;

impl system::offchain::CreateTransaction<Test, Extrinsic> for Test {
type Public = test_keys::ReporterId;
type Signature = test_keys::ReporterSignature;

fn create_transaction<F: system::offchain::Signer<Self::Public, Self::Signature>>(
call: <Extrinsic as ExtrinsicT>::Call,
_public: Self::Public,
_account: <Test as system::Trait>::AccountId,
nonce: <Test as system::Trait>::Index,
) -> Option<(<Extrinsic as ExtrinsicT>::Call, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
Some((call, (nonce, ())))
}
}

parameter_types! {
Expand Down
47 changes: 45 additions & 2 deletions runtime/kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use sp_runtime::{
curve::PiecewiseLinear,
traits::{
BlakeTwo256, Block as BlockT, SignedExtension, OpaqueKeys, ConvertInto, IdentityLookup,
DispatchInfoOf,
DispatchInfoOf, Extrinsic as ExtrinsicT, SaturatedConversion,
},
};
#[cfg(feature = "runtime-benchmarks")]
Expand All @@ -53,7 +53,8 @@ use version::NativeVersion;
use sp_core::OpaqueMetadata;
use sp_staking::SessionIndex;
use frame_support::{
parameter_types, construct_runtime, traits::{KeyOwnerProofSystem, SplitTwoWays, Randomness},
parameter_types, construct_runtime, debug,
traits::{KeyOwnerProofSystem, SplitTwoWays, Randomness},
};
use im_online::sr25519::AuthorityId as ImOnlineId;
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
Expand Down Expand Up @@ -539,6 +540,46 @@ impl parachains::Trait for Runtime {
type IdentificationTuple = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, Vec<u8>)>>::IdentificationTuple;
type ReportOffence = Offences;
type BlockHashConversion = sp_runtime::traits::Identity;
type SubmitSignedTransaction = TransactionSubmitter<parachain::FishermanId, Runtime, UncheckedExtrinsic>;
}

impl system::offchain::CreateTransaction<Runtime, UncheckedExtrinsic> for Runtime {
type Public = <primitives::Signature as sp_runtime::traits::Verify>::Signer;
type Signature = primitives::Signature;

fn create_transaction<TSigner: system::offchain::Signer<Self::Public, Self::Signature>>(
call: <UncheckedExtrinsic as ExtrinsicT>::Call,
public: Self::Public,
account: <Runtime as system::Trait>::AccountId,
nonce: <Runtime as system::Trait>::Index,
) -> Option<(Call, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
let period = BlockHashCount::get()
.checked_next_power_of_two()
.map(|c| c / 2)
.unwrap_or(2) as u64;

let current_block = System::block_number()
.saturated_into::<u64>()
.saturating_sub(1);
let tip = 0;
let extra: SignedExtra = (
RestrictFunctionality,
system::CheckVersion::<Runtime>::new(),
system::CheckGenesis::<Runtime>::new(),
system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
system::CheckNonce::<Runtime>::from(nonce),
system::CheckWeight::<Runtime>::new(),
transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
registrar::LimitParathreadCommits::<Runtime>::new(),
parachains::ValidateDoubleVoteReports::<Runtime>::new(),
);
let raw_payload = SignedPayload::new(call, extra).map_err(|e| {
debug::warn!("Unable to create signed payload: {:?}", e)
}).ok()?;
let signature = TSigner::sign(public, &raw_payload)?;
let (call, extra, _) = raw_payload.deconstruct();
Some((call, (account, signature, extra)))
}
}

parameter_types! {
Expand Down Expand Up @@ -769,6 +810,8 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signatu
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Nonce, Call>;
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;
/// The payload being signed in the transactions.
pub type SignedPayload = generic::SignedPayload<Call, SignedExtra>;

sp_api::impl_runtime_apis! {
impl sp_api::Core<Block> for Runtime {
Expand Down
Loading

0 comments on commit dd59eb3

Please sign in to comment.