Rust链上活动监控插件pallet-im-online的使用,实现Substrate区块链节点在线状态检测与报告

Rust链上活动监控插件pallet-im-online的使用,实现Substrate区块链节点在线状态检测与报告

I’m online模块

如果本地节点是验证器(即包含权威密钥),该模块会在每个新会话中广播心跳交易。心跳作为一种简单机制,表明该节点在当前时代(era)是在线的。

收到的心跳会跟踪一个时代,并在每个新时代重置。该模块公开了两个公共函数来查询在当前时代或会话中是否收到了心跳。

心跳是一个签名交易,使用会话密钥签名,包含本地验证器链最近的最佳区块号以及NetworkState。它通过链下工作者作为未签名交易提交。

接口

公共函数

  • is_online - 如果验证器在当前会话中发送了心跳则为真

使用示例

以下是内容中提供的示例代码:

use pallet_im_online::{self as im_online};

#[frame_support::pallet]
pub mod pallet {
    use super::*;
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    #[pallet::pallet]
    pub struct Pallet<T>(_);

    #[pallet::config]
    pub trait Config: frame_system::Config + im_online::Config {}

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        #[pallet::weight(0)]
        pub fn is_online(origin: OriginFor<T>, authority_index: u32) -> DispatchResult {
            let _sender = ensure_signed(origin)?;
            let _is_online = <im_online::Pallet<T>>::is_online(authority_index);
            Ok(())
        }
    }
}

完整实现示例

以下是一个更完整的实现示例,展示如何配置和使用pallet-im-online:

// 在runtime/src/lib.rs中

// 1. 引入必要的依赖
use frame_support::traits::KeyOwnerProofSystem;
use sp_runtime::traits::{Convert, Verify};

// 2. 配置runtime
impl pallet_im_online::Config for Runtime {
    type AuthorityId = ImOnlineId;  // 通常使用专门的心跳ID类型
    type Event = Event;
    type ValidatorSet = Session;
    type NextSessionRotation = Babe;
    type ReportUnresponsiveness = Offences;
    type UnsignedPriority = TransactionPriority;
    type WeightInfo = ();
    
    // 配置心跳超时
    type HeartbeatTimeout = HeartbeatTimeout;
}

// 3. 在construct_runtime!宏中包含该pallet
construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        // ...其他pallet...
        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, Config<T>},
        // ...其他pallet...
    }
);

// 4. 使用示例 - 查询验证器在线状态
pub fn check_validator_online_status(authority_index: u32) -> bool {
    // 获取当前验证器是否在线
    pallet_im_online::Pallet::<Runtime>::is_online(authority_index)
}

// 5. 监控节点状态示例
pub fn monitor_node_status() {
    // 获取当前会话的所有验证器
    let validators = Session::validators();
    
    for (index, validator) in validators.iter().enumerate() {
        let is_online = pallet_im_online::Pallet::<Runtime>::is_online(index as u32);
        println!("Validator {} ({}) is {}",
            index,
            validator,
            if is_online { "online" } else { "offline" }
        );
    }
}

依赖

该模块依赖于Session模块。

安装

要将pallet-im-online添加到您的项目中,请运行以下Cargo命令:

cargo add pallet-im-online

或在您的Cargo.toml中添加以下行:

pallet-im-online = "41.0.0"

License: Apache-2.0


1 回复

Rust链上活动监控插件pallet-im-online的使用指南

概述

pallet-im-online是Substrate框架中的一个重要插件,用于监控区块链节点的在线状态。它允许验证人和普通节点向网络报告其在线状态,是维护区块链网络健康运行的关键组件。

主要功能

  1. 节点在线状态检测
  2. 自动心跳信号发送
  3. 离线节点报告
  4. 验证人活动监控

使用方法

1. 引入pallet-im-online到runtime

首先需要在项目的runtime/src/lib.rs中添加依赖和配置:

// 在runtime的Cargo.toml中添加依赖
[dependencies.pallet-im-online]
default-features = false
git = 'https://github.com/paritytech/substrate.git'
branch = 'master'

// 在runtime/src/lib.rs中配置
impl pallet_im_online::Config for Runtime {
    type AuthorityId = ImOnlineId;
    type Event = Event;
    type NextSessionRotation = Babe;
    type ReportUnresponsiveness = Offences;
    type UnsignedPriority = TransactionPriority;
    type WeightInfo = ();
}

2. 实现签名验证

impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
where
    Call: From<LocalCall>,
{
    fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
        call: Call,
        public: <Signature as Verify>::Signer,
        account: AccountId,
        nonce: Index,
    ) -> Option<(Call, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
        // 实现签名逻辑
    }
}

3. 心跳发送示例

节点会自动发送心跳,但也可以手动触发:

use frame_system::offchain::SubmitTransaction;
use pallet_im_online::Call as ImOnlineCall;

fn send_heartbeat(block_number: u64) -> Result<(), &'static str> {
    let heartbeat = ImOnlineCall::heartbeat(heartbeat, signature);
    SubmitTransaction::<Runtime, ImOnlineCall>::submit_unsigned_transaction(heartbeat.into())
        .map_err(|_| "Failed to submit heartbeat")
}

4. 查询节点状态

use pallet_im_online::Heartbeat;

// 获取最近的心跳
let recent_heartbeats = ImOnline::received_heartbeats();
for (validator_index, heartbeat) in recent_heartbeats.iter().enumerate() {
    println!("Validator {} last heartbeat at block {}", validator_index, heartbeat.block_number);
}

配置参数

runtime/src/lib.rs中可以配置以下参数:

parameter_types! {
    pub const ImOnlineUnsignedPriority: u64 = 1 << 20;
    pub const MaxKeys: u32 = 10_000;
    pub const MaxPeerInHeartbeats: u32 = 1_000;
}

监控离线节点

// 监听事件
frame_system::Pallet::<T>::deposit_event(
    Event::HeartbeatReceived(validator, is_online)
);

// 处理离线节点
if !is_online {
    // 触发惩罚机制或报警
}

最佳实践

  1. 确保节点时钟同步,避免因时间不同步导致心跳失效
  2. 合理设置心跳间隔,默认是每5个区块一次
  3. 监控HeartbeatReceived事件来跟踪节点状态变化
  4. 对于验证人节点,确保有足够的余额支付交易费用

注意事项

  1. 心跳消息需要签名,确保私钥安全存储
  2. 频繁的心跳会增加网络负载
  3. 离线检测有一定延迟,不要仅依赖此机制判断节点状态

完整示例代码

下面是一个完整的runtime集成示例:

// runtime/src/lib.rs

// 1. 添加依赖
pub use pallet_im_online;

// 2. 配置实现
parameter_types! {
    pub const ImOnlineUnsignedPriority: u64 = 1 << 20;
    pub const MaxKeys: u32 = 10_000;
    pub const MaxPeerInHeartbeats: u32 = 1_000;
}

impl pallet_im_online::Config for Runtime {
    type AuthorityId = ImOnlineId;
    type Event = Event;
    type NextSessionRotation = Babe;
    type ReportUnresponsiveness = Offences;
    type UnsignedPriority = ImOnlineUnsignedPriority;
    type WeightInfo = ();
}

// 3. 实现签名验证
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
where
    Call: From<LocalCall>,
{
    fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
        call: Call,
        public: <Signature as Verify>::Signer,
        account: AccountId,
        nonce: Index,
    ) -> Option<(Call, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
        let tip = 0; // 无小费
        let spec_version = RuntimeVersion::get().spec_version;
        let genesis_hash = <frame_system::Module<Runtime>>::block_hash(0);
        let transaction = TransactionPayload::new(call, nonce)
            .with_spec_version(spec_version)
            .with_genesis_hash(genesis_hash)
            .with_tip(tip);
        
        let signature = transaction.using_encoded(|payload| C::sign(payload, public))?;
        let (call, extra, _) = transaction.deconstruct();
        
        Some((call, (account, signature, extra)))
    }
}

// 4. 心跳监控服务示例
pub struct HeartbeatMonitor;
impl HeartbeatMonitor {
    pub fn check_validators() {
        let current_block = <frame_system::Module<Runtime>>::block_number();
        let heartbeats = <pallet_im_online::Module<Runtime>>::received_heartbeats();
        
        for (index, heartbeat) in heartbeats.iter().enumerate() {
            let last_seen = current_block.saturating_sub(heartbeat.block_number);
            if last_seen > 30 {
                log::warn!("Validator {} offline for {} blocks", index, last_seen);
                // 触发惩罚逻辑
                <pallet_offences::Module<Runtime>>::report_offence(
                    vec![index as u32],
                    pallet_im_online::UnresponsivenessOffence {})
                    .unwrap_or_else(|e| log::error!("Failed to report offence: {:?}", e));
            }
        }
    }
}

通过pallet-im-online,Substrate网络可以有效地监控节点健康状况,及时发现并处理问题节点,保障区块链网络的稳定运行。

回到顶部