Rust区块链插件库pallet-offences的使用:Substrate框架中的节点违规检测与惩罚机制
Offences Module
Tracks reported offences
License: Apache-2.0
使用示例
下面是一个使用pallet-offences的完整示例代码,展示了如何在Substrate框架中实现节点违规检测与惩罚机制:
// 在runtime/src/lib.rs中引入pallet-offences
pub use pallet_offences;
// 配置trait实现
impl pallet_offences::Config for Runtime {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler =
Staking;
}
// 在construct_runtime!宏中添加pallet
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// ...其他pallet
Offences: pallet_offences::{Pallet, Call, Storage, Event<T>},
}
);
// 报告违规的示例代码
pub fn report_offence(
offenders: Vec<(T::ValidatorId, T::FullIdentification)>,
offence: Box<dyn Offence<T::ValidatorId, T::FullIdentification>>,
) -> Result<(), OffenceError> {
// 获取当前session索引
let session_index = Session::current_index();
// 调用pallet-offences的报告函数
pallet_offences::Pallet::<T>::report_offence(
offenders,
offence,
session_index,
)
}
// 自定义违规类型示例
pub struct MyCustomOffence;
impl<T: pallet_offences::Config> Offence<T::ValidatorId, T::FullIdentification> for MyCustomOffence {
const ID: Kind = *b"my_custom_offence";
const MAX_REPORTERS: u32 = 10;
fn offenders(&self) -> Vec<(T::ValidatorId, T::FullIdentification)> {
// 返回违规者列表
vec![]
}
fn session_index(&self) -> SessionIndex {
// 返回违规发生的session索引
0
}
fn validator_set_count(&self) -> u32 {
// 返回验证者集合大小
0
}
fn time_slot(&self) -> Self::TimeSlot {
// 返回时间槽
Default::default()
}
}
主要功能
- 违规跟踪:记录网络中报告的节点违规行为
- 惩罚机制:与staking模块配合实施惩罚
- 自定义违规类型:允许定义新的违规类型
集成说明
- 在Cargo.toml中添加依赖:
pallet-offences = { version = "41.0.0", default-features = false }
- 实现必要的trait配置
- 在runtime构建中集成该pallet
该模块通常与staking和session模块配合使用,以识别违规验证者并实施惩罚措施。
完整示例Demo
下面是一个更完整的pallet-offences使用示例,包含runtime集成和自定义违规处理:
// runtime/src/lib.rs
// 1. 引入必要的依赖
pub use pallet_offences;
pub use pallet_session;
pub use pallet_staking;
// 2. 配置trait实现
impl pallet_offences::Config for Runtime {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;
}
// 3. 在construct_runtime!宏中添加pallet
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// ...其他pallet
Offences: pallet_offences::{Pallet, Call, Storage, Event<T>},
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Staking: pallet_staking::{Pallet, Call, Storage, Event<T>, Config<T>},
}
);
// 4. 自定义违规类型实现
pub struct DoubleVotingOffence;
impl<T: pallet_offences::Config> Offence<T::ValidatorId, T::FullIdentification> for DoubleVotingOffence {
const ID: Kind = *b"double_voting";
const MAX_REPORTERS: u32 = 5;
fn offenders(&self) -> Vec<(T::ValidatorId, T::FullIdentification)> {
// 实际应用中这里应该返回真正的违规者列表
vec![]
}
fn session_index(&self) -> SessionIndex {
Session::current_index()
}
fn validator_set_count(&self) -> u32 {
// 返回当前验证者集合大小
Staking::validator_count()
}
fn time_slot(&self) -> Self::TimeSlot {
// 使用区块号作为时间槽
System::block_number()
}
}
// 5. 报告违规的实用函数
pub fn report_double_voting_offence(
offender: <T as pallet_session::Config>::ValidatorId,
identification: <T as pallet_staking::Config>::FullIdentification,
) -> DispatchResult {
// 创建违规实例
let offence = Box::new(DoubleVotingOffence);
// 准备违规者列表
let offenders = vec![(offender, identification)];
// 报告违规
pallet_offences::Pallet::<T>::report_offence(
offenders,
offence,
Session::current_index(),
)?;
Ok(())
}
详细说明
- 依赖配置:需在runtime中同时引入offences、session和staking模块
- trait实现:必须实现Config trait,指定事件类型、验证者识别元组和违规处理器
- 自定义违规:通过实现Offence trait可以定义新的违规类型
- 报告流程:违规报告需要提供违规者列表、违规实例和session索引
- 惩罚执行:违规处理由配置的OnOffenceHandler(通常是staking模块)负责执行
Cargo.toml配置示例
[dependencies]
pallet-offences = { version = "41.0.0", default-features = false }
pallet-session = { version = "41.0.0", default-features = false }
pallet-staking = { version = "41.0.0", default-features = false }
这个完整示例展示了如何从零开始集成pallet-offences,包括自定义违规类型和实际报告违规的流程。
1 回复
以下是基于您提供的内容整理的完整示例demo,首先展示内容中已有的示例,然后提供更完整的实现:
内容中原有的示例代码
报告违规行为
use frame_support::dispatch::DispatchResult;
use sp_runtime::Perbill;
use pallet_offences::{Kind, OffenceDetails};
fn report_offence(
offenders: Vec<(ValidatorId, Perbill)>,
kind: Kind,
) -> DispatchResult {
let offence = OffenceDetails {
offender: offenders,
reporters: vec![],
};
Offences::report_offence(offence, kind)
}
自定义违规类型
pub const CUSTOM_OFFENCE: Kind = *b"custom";
pub struct CustomOffence<ValidatorId>(pub Vec<ValidatorId>);
impl<ValidatorId: Clone> Offence<ValidatorId> for CustomOffence<ValidatorId> {
const ID: Kind = CUSTOM_OFFENCE;
fn offenders(&self) -> Vec<ValidatorId> {
self.0.clone()
}
fn slash_fraction(&self, offenders_count: u32) -> Perbill {
Perbill::from_percent(10 * offenders_count)
}
}
完整示例demo
//! 完整示例:使用pallet-offences实现节点违规检测与惩罚
use frame_support::{dispatch::DispatchResult, traits::ValidatorSet};
use sp_runtime::Perbill;
use pallet_offences::{Kind, Offence, OffenceDetails, OnOffenceHandler};
use pallet_session::historical::IdentificationTuple;
use pallet_staking::Staking;
// 1. 定义自定义违规类型
pub const DOUBLE_SIGNING: Kind = *b"dblsign"; // 双重签名
pub const OFFLINE: Kind = *b"offline"; // 离线违规
/// 双重签名违规实现
pub struct DoubleSigningOffence<ValidatorId>(pub Vec<ValidatorId>);
impl<ValidatorId: Clone> Offence<ValidatorId> for DoubleSigningOffence<ValidatorId> {
const ID: Kind = DOUBLE_SIGNING;
fn offenders(&self) -> Vec<ValidatorId> {
self.0.clone()
}
fn slash_fraction(&self, _offenders_count: u32) -> Perbill {
// 双重签名是非常严重的违规,惩罚100%
Perbill::from_percent(100)
}
}
/// 离线违规实现
pub struct OfflineOffence<ValidatorId>(pub Vec<ValidatorId>);
impl<ValidatorId: Clone> Offence<ValidatorId> for OfflineOffence<ValidatorId> {
const ID: Kind = OFFLINE;
fn offenders(&self) -> Vec<ValidatorId> {
self.0.clone()
}
fn slash_fraction(&self, offenders_count: u32) -> Perbill {
// 离线违规根据次数递增惩罚
Perbill::from_percent(5 * offenders_count)
}
}
// 2. 实现违规报告逻辑
pub struct OffenceReporter;
impl OffenceReporter {
/// 报告双重签名违规
pub fn report_double_signing(
validator: ValidatorId,
) -> DispatchResult {
let offence = OffenceDetails {
offender: vec![(validator, Perbill::from_percent(100))],
reporters: vec![],
};
Offences::report_offence(offence, DOUBLE_SIGNING)
}
/// 报告离线违规
pub fn report_offline(
validators: Vec<ValidatorId>,
slash_percent: u8,
) -> DispatchResult {
let offence = OffenceDetails {
offender: validators.iter()
.map(|v| (v.clone(), Perbill::from_percent(slash_percent)))
.collect(),
reporters: vec![],
};
Offences::report_offence(offence, OFFLINE)
}
}
// 3. 运行时配置实现
impl pallet_offences::Config for Runtime {
type Event = Event;
type IdentificationTuple = IdentificationTuple<Self>;
type OnOffenceHandler = Staking;
// 配置参数
#[cfg(feature = "runtime-benchmarks")]
const REPORT_LONGEVITY: u64 = 100;
const SLASH_REWARD_FRACTION: Perbill = Perbill::from_percent(10);
}
// 4. 在construct_runtime!宏中添加pallet
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// ... 其他pallet
Offences: pallet_offences::{Pallet, Call, Storage, Event<T>},
}
);
// 5. 使用示例
mod tests {
use super::*;
#[test]
fn test_report_offences() {
// 模拟测试环境
let validator = // 获取测试验证者;
// 报告双重签名
OffenceReporter::report_double_signing(validator.clone())
.expect("Failed to report double signing");
// 报告离线违规
OffenceReporter::report_offline(vec![validator], 10)
.expect("Failed to report offline offence");
}
}
关键点说明
-
违规类型定义:
- 实现了两种常见违规类型:
DoubleSigningOffence
和OfflineOffence
- 每种违规类型定义了不同的惩罚力度
- 实现了两种常见违规类型:
-
违规报告:
- 封装了
OffenceReporter
工具类提供便捷的报告方法 - 支持单节点和多节点违规报告
- 封装了
-
运行时配置:
- 实现了
pallet_offences::Config
trait - 配置了违规报告有效期和举报奖励比例
- 实现了
-
测试示例:
- 展示了如何在实际代码中报告违规行为
- 可以在测试环境中验证惩罚逻辑
这个完整示例展示了如何从定义违规类型到实际报告违规的完整流程,并包含了必要的运行时配置。您可以根据实际网络需求调整惩罚力度和违规类型。