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

Beefy equivocation: add runtime API methods #4993

Merged
merged 7 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 25 additions & 0 deletions polkadot/node/service/src/fake_runtime_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,37 @@ sp_api::impl_runtime_apis! {
unimplemented!()
}

fn submit_report_fork_voting_unsigned_extrinsic(
_: sp_consensus_beefy::ForkVotingProof<
<Block as BlockT>::Header,
BeefyId,
sp_runtime::OpaqueValue
>,
_: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
unimplemented!()
}

fn submit_report_future_block_voting_unsigned_extrinsic(
_: sp_consensus_beefy::FutureBlockVotingProof<BlockNumber, BeefyId>,
_: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
unimplemented!()
}

fn generate_key_ownership_proof(
_: sp_consensus_beefy::ValidatorSetId,
_: BeefyId,
) -> Option<sp_consensus_beefy::OpaqueKeyOwnershipProof> {
unimplemented!()
}

fn generate_ancestry_proof(
_: BlockNumber,
_: Option<BlockNumber>,
) -> Option<sp_runtime::OpaqueValue> {
unimplemented!()
}
}

impl sp_mmr_primitives::MmrApi<Block, Hash, BlockNumber> for Runtime {
Expand Down
38 changes: 37 additions & 1 deletion polkadot/runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2054,7 +2054,7 @@ sp_api::impl_runtime_apis! {
}
}

#[api_version(4)]
#[api_version(5)]
impl sp_consensus_beefy::BeefyApi<Block, BeefyId> for Runtime {
fn beefy_genesis() -> Option<BlockNumber> {
pallet_beefy::GenesisBlock::<Runtime>::get()
Expand All @@ -2080,6 +2080,31 @@ sp_api::impl_runtime_apis! {
)
}

fn submit_report_fork_voting_unsigned_extrinsic(
equivocation_proof:
sp_consensus_beefy::ForkVotingProof<
<Block as BlockT>::Header,
BeefyId,
sp_runtime::OpaqueValue
>,
key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
Beefy::submit_unsigned_fork_voting_report(
equivocation_proof.try_into()?,
key_owner_proof.decode()?,
)
}

fn submit_report_future_block_voting_unsigned_extrinsic(
equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof<BlockNumber, BeefyId>,
key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
Beefy::submit_unsigned_future_block_voting_report(
equivocation_proof,
key_owner_proof.decode()?,
)
}

fn generate_key_ownership_proof(
_set_id: sp_consensus_beefy::ValidatorSetId,
authority_id: BeefyId,
Expand All @@ -2090,6 +2115,17 @@ sp_api::impl_runtime_apis! {
.map(|p| p.encode())
.map(sp_consensus_beefy::OpaqueKeyOwnershipProof::new)
}

fn generate_ancestry_proof(
prev_block_number: BlockNumber,
best_known_block_number: Option<BlockNumber>,
) -> Option<sp_runtime::OpaqueValue> {
use sp_consensus_beefy::AncestryHelper;

MmrLeaf::generate_proof(prev_block_number, best_known_block_number)
.map(|p| p.encode())
.map(sp_runtime::OpaqueValue::new)
}
}

#[api_version(2)]
Expand Down
26 changes: 26 additions & 0 deletions polkadot/runtime/test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,12 +1029,38 @@ sp_api::impl_runtime_apis! {
None
}

fn submit_report_fork_voting_unsigned_extrinsic(
_equivocation_proof:
sp_consensus_beefy::ForkVotingProof<
<Block as BlockT>::Header,
BeefyId,
sp_runtime::OpaqueValue
>,
_key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
}

fn submit_report_future_block_voting_unsigned_extrinsic(
_equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof<BlockNumber, BeefyId>,
_key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
}

fn generate_key_ownership_proof(
_set_id: sp_consensus_beefy::ValidatorSetId,
_authority_id: BeefyId,
) -> Option<sp_consensus_beefy::OpaqueKeyOwnershipProof> {
None
}

fn generate_ancestry_proof(
_prev_block_number: BlockNumber,
_best_known_block_number: Option<BlockNumber>,
) -> Option<sp_runtime::OpaqueValue> {
None
}
}

impl mmr::MmrApi<Block, Hash, BlockNumber> for Runtime {
Expand Down
38 changes: 37 additions & 1 deletion polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2109,7 +2109,7 @@ sp_api::impl_runtime_apis! {
}
}

#[api_version(4)]
#[api_version(5)]
impl sp_consensus_beefy::BeefyApi<Block, BeefyId> for Runtime {
fn beefy_genesis() -> Option<BlockNumber> {
pallet_beefy::GenesisBlock::<Runtime>::get()
Expand All @@ -2135,6 +2135,31 @@ sp_api::impl_runtime_apis! {
)
}

fn submit_report_fork_voting_unsigned_extrinsic(
equivocation_proof:
sp_consensus_beefy::ForkVotingProof<
<Block as BlockT>::Header,
BeefyId,
sp_runtime::OpaqueValue
>,
key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
Beefy::submit_unsigned_fork_voting_report(
equivocation_proof.try_into()?,
key_owner_proof.decode()?,
)
}

fn submit_report_future_block_voting_unsigned_extrinsic(
equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof<BlockNumber, BeefyId>,
key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
Beefy::submit_unsigned_future_block_voting_report(
equivocation_proof,
key_owner_proof.decode()?,
)
}

fn generate_key_ownership_proof(
_set_id: sp_consensus_beefy::ValidatorSetId,
authority_id: BeefyId,
Expand All @@ -2145,6 +2170,17 @@ sp_api::impl_runtime_apis! {
.map(|p| p.encode())
.map(sp_consensus_beefy::OpaqueKeyOwnershipProof::new)
}

fn generate_ancestry_proof(
prev_block_number: BlockNumber,
best_known_block_number: Option<BlockNumber>,
) -> Option<sp_runtime::OpaqueValue> {
use sp_consensus_beefy::AncestryHelper;

BeefyMmrLeaf::generate_proof(prev_block_number, best_known_block_number)
.map(|p| p.encode())
.map(sp_runtime::OpaqueValue::new)
}
}

impl mmr::MmrApi<Block, Hash, BlockNumber> for Runtime {
Expand Down
27 changes: 27 additions & 0 deletions prdoc/pr_4993.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Added BEEFY equivocation-related methods to BeefyApi

doc:
- audience: Node Dev
description: |
This PR adds the `generate_ancestry_proof`, `submit_report_fork_voting_unsigned_extrinsic` and
`submit_report_future_block_voting_unsigned_extrinsic` to `BeefyApi` and bumps the `BeefyApi` version
from 4 to 5.

crates:
- name: pallet-beefy
bump: minor
- name: pallet-beefy-mmr
bump: minor
- name: kitchensink-runtime
bump: major
- name: rococo-runtime
bump: major
- name: westend-runtime
bump: major
- name: sp-consensus-beefy
bump: minor
- name: polkadot-service
bump: patch
38 changes: 37 additions & 1 deletion substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3038,7 +3038,7 @@ impl_runtime_apis! {
}
}

#[api_version(4)]
#[api_version(5)]
impl sp_consensus_beefy::BeefyApi<Block, BeefyId> for Runtime {
fn beefy_genesis() -> Option<BlockNumber> {
pallet_beefy::GenesisBlock::<Runtime>::get()
Expand All @@ -3064,6 +3064,31 @@ impl_runtime_apis! {
)
}

fn submit_report_fork_voting_unsigned_extrinsic(
equivocation_proof:
sp_consensus_beefy::ForkVotingProof<
<Block as BlockT>::Header,
BeefyId,
sp_runtime::OpaqueValue
>,
key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
Beefy::submit_unsigned_fork_voting_report(
equivocation_proof.try_into()?,
key_owner_proof.decode()?,
)
}

fn submit_report_future_block_voting_unsigned_extrinsic(
equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof<BlockNumber, BeefyId>,
key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof,
) -> Option<()> {
Beefy::submit_unsigned_future_block_voting_report(
equivocation_proof,
key_owner_proof.decode()?,
)
}

fn generate_key_ownership_proof(
_set_id: sp_consensus_beefy::ValidatorSetId,
authority_id: BeefyId,
Expand All @@ -3072,6 +3097,17 @@ impl_runtime_apis! {
.map(|p| p.encode())
.map(sp_consensus_beefy::OpaqueKeyOwnershipProof::new)
}

fn generate_ancestry_proof(
prev_block_number: BlockNumber,
best_known_block_number: Option<BlockNumber>,
) -> Option<sp_runtime::OpaqueValue> {
use sp_consensus_beefy::AncestryHelper;

MmrLeaf::generate_proof(prev_block_number, best_known_block_number)
.map(|p| p.encode())
.map(sp_runtime::OpaqueValue::new)
}
}

impl pallet_mmr::primitives::MmrApi<
Expand Down
18 changes: 18 additions & 0 deletions substrate/frame/beefy-mmr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,24 @@ where
type Proof = AncestryProof<MerkleRootOf<T>>;
type ValidationContext = MerkleRootOf<T>;

fn generate_proof(
prev_block_number: BlockNumberFor<T>,
best_known_block_number: Option<BlockNumberFor<T>>,
) -> Option<Self::Proof> {
pallet_mmr::Pallet::<T>::generate_ancestry_proof(prev_block_number, best_known_block_number)
.map_err(|e| {
log::error!(
target: "runtime::beefy",
"Failed to generate ancestry proof for block {:?} at {:?}: {:?}",
prev_block_number,
best_known_block_number,
e
);
e
})
.ok()
}

fn extract_validation_context(header: HeaderFor<T>) -> Option<Self::ValidationContext> {
// Check if the provided header is canonical.
let expected_hash = frame_system::Pallet::<T>::block_hash(header.number());
Expand Down
35 changes: 33 additions & 2 deletions substrate/frame/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,8 @@ impl<T: Config> Pallet<T> {
ValidatorSet::<T::BeefyId>::new(validators, id)
}

/// Submits an extrinsic to report an equivocation. This method will create
/// an unsigned extrinsic with a call to `report_equivocation_unsigned` and
/// Submits an extrinsic to report a double voting equivocation. This method will create
/// an unsigned extrinsic with a call to `report_double_voting_unsigned` and
/// will push the transaction to the pool. Only useful in an offchain context.
pub fn submit_unsigned_double_voting_report(
equivocation_proof: DoubleVotingProof<
Expand All @@ -556,6 +556,37 @@ impl<T: Config> Pallet<T> {
.ok()
}

/// Submits an extrinsic to report a fork voting equivocation. This method will create
/// an unsigned extrinsic with a call to `report_fork_voting_unsigned` and
/// will push the transaction to the pool. Only useful in an offchain context.
pub fn submit_unsigned_fork_voting_report(
equivocation_proof: ForkVotingProof<
HeaderFor<T>,
T::BeefyId,
<T::AncestryHelper as AncestryHelper<HeaderFor<T>>>::Proof,
>,
key_owner_proof: T::KeyOwnerProof,
) -> Option<()> {
T::EquivocationReportSystem::publish_evidence(EquivocationEvidenceFor::ForkVotingProof(
equivocation_proof,
key_owner_proof,
))
.ok()
}

/// Submits an extrinsic to report a future block voting equivocation. This method will create
/// an unsigned extrinsic with a call to `report_future_block_voting_unsigned` and
/// will push the transaction to the pool. Only useful in an offchain context.
pub fn submit_unsigned_future_block_voting_report(
equivocation_proof: FutureBlockVotingProof<BlockNumberFor<T>, T::BeefyId>,
key_owner_proof: T::KeyOwnerProof,
) -> Option<()> {
T::EquivocationReportSystem::publish_evidence(
EquivocationEvidenceFor::FutureBlockVotingProof(equivocation_proof, key_owner_proof),
)
.ok()
}

fn change_authorities(
new: BoundedVec<T::BeefyId, T::MaxAuthorities>,
queued: BoundedVec<T::BeefyId, T::MaxAuthorities>,
Expand Down
7 changes: 7 additions & 0 deletions substrate/frame/beefy/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ impl<Header: HeaderT> AncestryHelper<Header> for MockAncestryHelper {
type Proof = MockAncestryProof;
type ValidationContext = MockAncestryProofContext;

fn generate_proof(
_prev_block_number: Header::Number,
_best_known_block_number: Option<Header::Number>,
) -> Option<Self::Proof> {
unimplemented!()
}

fn extract_validation_context(_header: Header) -> Option<Self::ValidationContext> {
AncestryProofContext::get()
}
Expand Down
Loading
Loading