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

Adds an offchain call to submit double vote reports #966

Merged
merged 7 commits into from
Apr 16, 2020
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to have this key type, as the one in the Grandpa equivocations PR is in substrate-node, not a common library.

@andresilva does this conflict with #1000 ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will use this key in polkadot for all equivocation reporting across BABE, GRANDPA and Parachains. It conflicts with #1000 since I added the same key, but I'll change it after this one is merged.


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 @@ -19,6 +19,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", de
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { 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 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add sp-application-crypto/std below in the std feature list.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's only needed as dev-dependency.


authorship = { package = "pallet-authorship", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
balances = { package = "pallet-balances", 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 {
andresilva marked this conversation as resolved.
Show resolved Hide resolved
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)
andresilva marked this conversation as resolved.
Show resolved Hide resolved
}
}

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
1 change: 1 addition & 0 deletions runtime/polkadot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/par
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
offchain-primitives = { package = "sp-offchain", 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 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, needs sp-application-crypto/std below.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if needed actually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, it's not needed here, and in common it is only needed as a dev dep, thanks

sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
Expand Down
Loading