grandpa: report equivocations (#3868)

* session: runtime api for generating session membership proofs

* grandpa: add runtime api for creating equivocation report txs

* grandpa: submit signed equivocation report transactions

* grandpa: use proper equivocation report type

* grandpa: report equivocations

* grandpa: validate equivocation proof

* grandpa: update to finality-grandpa 0.9.1

* grandpa: fix encoding of session membership proof

* grandpa: initialize set id session mapping for genesis session

* grandpa: fix bug in set_id session validation

* fix compilation

* cleanup from merge conflicts

* cleanup crate tomls

* grandpa: refactor equivocation handling to separate trait

* node-template: fix compilation

* fix test compilation

* bump finality-grandpa to v0.10.2

* rpc: fix runtime version test

* CHERRY-PICK #4200: Add documentation to SubmitSignedTransaction and actually make it work

Squashed commit of the following:

commit 4f2cb0b1c588a06f2f3b478bb4b28b5cb29d54b9
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Tue Dec 3 16:29:33 2019 +0100

    Split the method to avoid confusing type error message.

commit c5bf24eeaaf902add89ed1b046b22c4a4aaeb2cd
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Tue Dec 3 16:19:55 2019 +0100

    Make accounts optional, fix logic.

commit 97db1ef556e023cf6847e5ffdb036c0e3ea6fb0a
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Tue Dec 3 10:06:20 2019 +0100

    Remove warning.

commit 535f5c116d1a2e826eaf90c3f7e6798e443d61d8
Merge: 516257217 0f1a5f651
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Tue Dec 3 07:08:05 2019 +0100

    Merge branch 'master' into td-signed-transactions

commit 516257217bac89fcebd083712f4ea68b7b23b55a
Merge: ac98248c6 2e68c80c2
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Mon Dec 2 13:57:25 2019 +0100

    Merge branch 'master' into td-signed-transactions

commit ac98248c6c56cff381130645a82a13d29933cf83
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Mon Nov 25 17:34:52 2019 +0100

    Forgotten import.

commit 67a3c19031506c28e31c6bc4a90fff62d467dd58
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Mon Nov 25 17:32:10 2019 +0100

    Fix naming and bounds.

commit 93e768ea9df97a4629fca1f9bc4b108fdb33f876
Author: Tomasz Drwięga <tomasz@parity.io>
Date:   Mon Nov 25 17:01:05 2019 +0100

    Add documentation to signed transactions and actually make them work.

* grandpa: skip block initialization on report submission method

* primitives: allow transaction pool access by default for offchain calls

* grandpa: unused parameters

* grandpa: remove unused method

* grandpa: enable equivocation reporting

* grandpa: add workaround for parameter encoding

* grandpa: fix localized_payload calls in tests

* fix submit_report_equivocation_extrinsic in runtimes

* node: fix submit transaction test compilation

* node: bump spec_version

* rpc: fix api version test

* grandpa: allow custom equivocation offence type

* grandpa: add test for authorities::next_change_height

* grandpa: cleanup report_equivocation function

* node: move reporting app crypto to node-primitives

* grandpa: move equivocation traits to own module

* grandpa: rename app-crypto crate import

* grandpa: export equivocation types

* node: bump spec_version

* grandpa: rename EquivocationReport to EquivocationProof

* grandpa: add missing docs to primitives

* grandpa: add missing docs to equivocation

* node: fix compilation

* grandpa: add missing docs to pallet

* node: bump spec_version

* fix whitespace

* grandpa: return error on offence reporting

* grandpa: expose session and validator count in proofs through traits

* grandpa: use strong key in module KeyOwnerProofSystem

* grandpa: move key ownership proof to grandpa runtime api

* grandpa: remove unnecessary cloning when checking equivocation proof

* grandpa: make report_equivocation a method in Environment

* support: implement KeyOwnerProofSystem for ()

* grandpa: move KeyOwnerProofSystem to module trait

* test-utils: fix runtime compilation

* grandpa: fix test compilation

* grandpa: fix test compilation after merge

* grandpa: simplify transaction submission types

* grandpa: validate equivocation report in signed extension

* client: fix test

* node: use ValidateEquivocationReport signed extension

* grandpa: expose key ownership proof under opaque type

* grandpa: better docs on key ownership proofs

* grandpa: add note about signed extension

* grandpa: add ValidateEquivocationReport::new

* grandpa: remove skip_initialize_block from runtime api

* grandpa: use new offchain transaction submission API

* grandpa: take set_id in generate_key_ownership_proof

* grandpa: update to finality-grandpa v0.12.2

* grandpa: cleanup usages of AuthoritySet::current

* grandpa: fix test

* grandpa: add mocking utilities for equivocation reporting

* grandpa: add test for equivocation reporting

* grandpa: move SetIdSession initialization

* grandpa: add more tests

* node: enable historical session manager

* node: bump spec_version

* node: use strong key types in KeyOwnerProofSystem definitions

* grandpa: export GrandpaEquivocationOffence type
This commit is contained in:
André Silva
2020-05-06 17:25:51 +01:00
committed by GitHub
parent a1127f8f9d
commit fbd2ac8f3b
38 changed files with 2249 additions and 296 deletions
+3 -2
View File
@@ -85,8 +85,9 @@ pallet-balances = { version = "2.0.0-dev", path = "../../../frame/balances" }
pallet-transaction-payment = { version = "2.0.0-dev", path = "../../../frame/transaction-payment" }
frame-support = { version = "2.0.0-dev", default-features = false, path = "../../../frame/support" }
pallet-im-online = { version = "2.0.0-dev", default-features = false, path = "../../../frame/im-online" }
pallet-authority-discovery = { version = "2.0.0-dev", path = "../../../frame/authority-discovery" }
pallet-staking = { version = "2.0.0-dev", path = "../../../frame/staking" }
pallet-authority-discovery = { version = "2.0.0-dev", path = "../../../frame/authority-discovery" }
pallet-staking = { version = "2.0.0-dev", path = "../../../frame/staking" }
pallet-grandpa = { version = "2.0.0-dev", path = "../../../frame/grandpa" }
# node-specific dependencies
node-runtime = { version = "2.0.0-dev", path = "../runtime" }
+3 -1
View File
@@ -613,6 +613,7 @@ mod tests {
let check_nonce = frame_system::CheckNonce::from(index);
let check_weight = frame_system::CheckWeight::new();
let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0);
let validate_grandpa_equivocation = pallet_grandpa::ValidateEquivocationReport::new();
let extra = (
check_version,
check_genesis,
@@ -620,11 +621,12 @@ mod tests {
check_nonce,
check_weight,
payment,
validate_grandpa_equivocation,
);
let raw_payload = SignedPayload::from_raw(
function,
extra,
(version, genesis_hash, genesis_hash, (), (), ())
(version, genesis_hash, genesis_hash, (), (), (), ())
);
let signature = raw_payload.using_encoded(|payload| {
signer.sign(payload)
+6
View File
@@ -11,6 +11,9 @@ repository = "https://github.com/paritytech/substrate/"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = ["derive"] }
frame-system = { version = "2.0.0-dev", default-features = false, path = "../../../frame/system" }
sp-application-crypto = { version = "2.0.0-dev", default-features = false, path = "../../../primitives/application-crypto" }
sp-core = { version = "2.0.0-dev", default-features = false, path = "../../../primitives/core" }
sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../../../primitives/runtime" }
@@ -21,6 +24,9 @@ pretty_assertions = "0.6.1"
[features]
default = ["std"]
std = [
"codec/std",
"frame-system/std",
"sp-application-crypto/std",
"sp-core/std",
"sp-runtime/std",
]
+31
View File
@@ -62,3 +62,34 @@ pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, OpaqueExtrinsic>;
/// Block ID.
pub type BlockId = generic::BlockId<Block>;
/// App-specific crypto used for reporting equivocation/misbehavior in BABE and
/// GRANDPA. Any rewards for misbehavior reporting will be paid out to this
/// account.
pub mod report {
use super::{Signature, Verify};
use frame_system::offchain::AppCrypto;
use sp_core::crypto::KeyTypeId;
/// Key type for the reporting module. Used for reporting BABE and GRANDPA
/// equivocations.
pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"fish");
mod app {
use sp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::KEY_TYPE);
}
/// Identity of the equivocation/misbehavior reporter.
pub type ReporterId = app::Public;
/// An `AppCrypto` type to allow submitting signed transactions using the reporting
/// application key as signer.
pub struct ReporterAppCrypto;
impl AppCrypto<<Signature as Verify>::Signer, Signature> for ReporterAppCrypto {
type RuntimeAppPublic = ReporterId;
type GenericSignature = sp_core::sr25519::Signature;
type GenericPublic = sp_core::sr25519::Public;
}
}
+59 -8
View File
@@ -27,9 +27,13 @@ use frame_support::{
Weight,
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
},
traits::{Currency, Randomness, OnUnbalanced, Imbalance, LockIdentifier},
traits::{Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier},
};
use sp_core::{
crypto::KeyTypeId,
u32_trait::{_1, _2, _3, _4},
OpaqueMetadata,
};
use sp_core::u32_trait::{_1, _2, _3, _4};
pub use node_primitives::{AccountId, Signature};
use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
use sp_api::impl_runtime_apis;
@@ -41,18 +45,18 @@ use sp_runtime::curve::PiecewiseLinear;
use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority};
use sp_runtime::traits::{
self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion,
ConvertInto, OpaqueKeys,
ConvertInto, OpaqueKeys, NumberFor,
};
use sp_version::RuntimeVersion;
#[cfg(any(feature = "std", test))]
use sp_version::NativeVersion;
use sp_core::OpaqueMetadata;
use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
use pallet_grandpa::fg_primitives;
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
use pallet_contracts_rpc_runtime_api::ContractExecResult;
use pallet_session::{historical as pallet_session_historical};
use sp_inherents::{InherentData, CheckInherentsResult};
#[cfg(any(feature = "std", test))]
@@ -86,7 +90,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// and set impl_version to 0. If only runtime
// implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version.
spec_version: 246,
spec_version: 247,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
@@ -271,7 +275,7 @@ impl pallet_session::Trait for Runtime {
type ValidatorId = <Self as frame_system::Trait>::AccountId;
type ValidatorIdOf = pallet_staking::StashOf<Self>;
type ShouldEndSession = Babe;
type SessionManager = Staking;
type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
@@ -529,6 +533,7 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
frame_system::CheckNonce::<Runtime>::from(nonce),
frame_system::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
pallet_grandpa::ValidateEquivocationReport::<Runtime>::new(),
);
let raw_payload = SignedPayload::new(call, extra).map_err(|e| {
debug::warn!("Unable to create signed payload: {:?}", e);
@@ -572,6 +577,24 @@ impl pallet_authority_discovery::Trait for Runtime {}
impl pallet_grandpa::Trait for Runtime {
type Event = Event;
type Call = Call;
type KeyOwnerProofSystem = Historical;
type KeyOwnerProof =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
GrandpaId,
)>>::IdentificationTuple;
type HandleEquivocation = pallet_grandpa::EquivocationHandler<
Self::KeyOwnerIdentification,
node_primitives::report::ReporterAppCrypto,
Runtime,
Offences,
>;
}
parameter_types! {
@@ -693,6 +716,7 @@ construct_runtime!(
ImOnline: pallet_im_online::{Module, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
AuthorityDiscovery: pallet_authority_discovery::{Module, Call, Config},
Offences: pallet_offences::{Module, Call, Storage, Event},
Historical: pallet_session_historical::{Module},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
Identity: pallet_identity::{Module, Call, Storage, Event<T>},
Society: pallet_society::{Module, Call, Storage, Event<T>, Config<T>},
@@ -720,6 +744,7 @@ pub type SignedExtra = (
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_grandpa::ValidateEquivocationReport<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
@@ -792,6 +817,32 @@ impl_runtime_apis! {
fn grandpa_authorities() -> GrandpaAuthorityList {
Grandpa::grandpa_authorities()
}
fn submit_report_equivocation_extrinsic(
equivocation_proof: fg_primitives::EquivocationProof<
<Block as BlockT>::Hash,
NumberFor<Block>,
>,
key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof,
) -> Option<()> {
let key_owner_proof = key_owner_proof.decode()?;
Grandpa::submit_report_equivocation_extrinsic(
equivocation_proof,
key_owner_proof,
)
}
fn generate_key_ownership_proof(
_set_id: fg_primitives::SetId,
authority_id: GrandpaId,
) -> Option<fg_primitives::OpaqueKeyOwnershipProof> {
use codec::Encode;
Historical::prove((fg_primitives::KEY_TYPE, authority_id))
.map(|p| p.encode())
.map(fg_primitives::OpaqueKeyOwnershipProof::new)
}
}
impl sp_consensus_babe::BabeApi<Block> for Runtime {
@@ -880,7 +931,7 @@ impl_runtime_apis! {
fn decode_session_keys(
encoded: Vec<u8>,
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
SessionKeys::decode_into_raw_public_keys(&encoded)
}
}
@@ -74,6 +74,7 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
frame_system::CheckNonce::from(nonce),
frame_system::CheckWeight::new(),
pallet_transaction_payment::ChargeTransactionPayment::from(extra_fee),
pallet_grandpa::ValidateEquivocationReport::new(),
)
}