use serde::{Deserialize, Serialize};
use crate::module::traits::{
BlockServeDenylistSnapshot, ChainInfo, EventType, LightningInfo, MempoolSize, NetworkStats,
PaymentState, PeerInfo, SyncStatus, TxServeDenylistSnapshot,
};
use crate::{Block, BlockHeader, Hash, OutPoint, Transaction, UTXO};
pub type CorrelationId = u64;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ModuleMessage {
Request(RequestMessage),
Response(ResponseMessage),
Event(EventMessage),
Log(LogMessage),
Invocation(InvocationMessage),
InvocationResult(InvocationResultMessage),
}
impl ModuleMessage {
pub fn correlation_id(&self) -> Option<CorrelationId> {
match self {
ModuleMessage::Request(req) => Some(req.correlation_id),
ModuleMessage::Response(resp) => Some(resp.correlation_id),
ModuleMessage::Event(_) => None,
ModuleMessage::Log(_) => None,
ModuleMessage::Invocation(inv) => Some(inv.correlation_id),
ModuleMessage::InvocationResult(res) => Some(res.correlation_id),
}
}
pub fn message_type(&self) -> MessageType {
match self {
ModuleMessage::Request(req) => req.request_type.clone(),
ModuleMessage::Response(_resp) => MessageType::Response,
ModuleMessage::Event(_) => MessageType::Event,
ModuleMessage::Log(_) => MessageType::Log,
ModuleMessage::Invocation(_) => MessageType::Invocation,
ModuleMessage::InvocationResult(_) => MessageType::InvocationResult,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum MessageType {
GetBlock,
GetBlockHeader,
GetTransaction,
HasTransaction,
GetChainTip,
GetBlockHeight,
GetUtxo,
SubscribeEvents,
Handshake,
GetMempoolTransactions,
GetMempoolTransaction,
GetMempoolSize,
GetNetworkStats,
GetNetworkPeers,
GetChainInfo,
GetBlockByHeight,
GetLightningNodeUrl,
GetLightningInfo,
GetPaymentState,
CheckTransactionInMempool,
GetFeeEstimate,
ReadFile,
WriteFile,
DeleteFile,
ListDirectory,
CreateDirectory,
GetFileMetadata,
RegisterRpcEndpoint,
UnregisterRpcEndpoint,
RegisterTimer,
CancelTimer,
ScheduleTask,
ReportMetric,
GetModuleMetrics,
GetAllMetrics,
DiscoverModules,
GetModuleInfo,
IsModuleAvailable,
PublishEvent,
CallModule,
RegisterModuleApi,
UnregisterModuleApi,
GetModuleHealth,
GetAllModuleHealth,
ReportModuleHealth,
SendMeshPacketToPeer,
SendStratumV2MessageToPeer,
GetBlockTemplate,
SubmitBlock,
MergeBlockServeDenylist,
GetBlockServeDenylistSnapshot,
ClearBlockServeDenylist,
ReplaceBlockServeDenylist,
MergeTxServeDenylist,
GetTxServeDenylistSnapshot,
ClearTxServeDenylist,
ReplaceTxServeDenylist,
GetSyncStatus,
BanPeer,
SetBlockServeMaintenanceMode,
RegisterCliSpec,
Invocation,
InvocationResult,
Log,
Response,
Event,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestMessage {
pub correlation_id: CorrelationId,
pub request_type: MessageType,
pub payload: RequestPayload,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RequestPayload {
Handshake {
module_id: String,
module_name: String,
version: String,
},
GetBlock {
hash: Hash,
},
GetBlockHeader {
hash: Hash,
},
GetTransaction {
hash: Hash,
},
HasTransaction {
hash: Hash,
},
GetChainTip,
GetBlockHeight,
GetUtxo {
outpoint: OutPoint,
},
SubscribeEvents {
event_types: Vec<EventType>,
},
GetMempoolTransactions,
GetMempoolTransaction {
tx_hash: Hash,
},
GetMempoolSize,
GetNetworkStats,
GetNetworkPeers,
GetChainInfo,
GetBlockByHeight {
height: u64,
},
GetLightningNodeUrl,
GetLightningInfo,
GetPaymentState {
payment_id: String,
},
CheckTransactionInMempool {
tx_hash: Hash,
},
GetFeeEstimate {
target_blocks: u32,
},
ReadFile {
path: String,
},
WriteFile {
path: String,
data: Vec<u8>,
},
DeleteFile {
path: String,
},
ListDirectory {
path: String,
},
CreateDirectory {
path: String,
},
GetFileMetadata {
path: String,
},
RegisterRpcEndpoint {
method: String,
description: String,
},
UnregisterRpcEndpoint {
method: String,
},
RegisterTimer {
interval_seconds: u64,
},
CancelTimer {
timer_id: u64,
},
ScheduleTask {
delay_seconds: u64,
},
ReportMetric {
metric: crate::module::metrics::manager::Metric,
},
GetModuleMetrics {
module_id: String,
},
GetAllMetrics,
DiscoverModules,
GetModuleInfo {
module_id: String,
},
IsModuleAvailable {
module_id: String,
},
PublishEvent {
event_type: EventType,
payload: EventPayload,
},
CallModule {
target_module_id: Option<String>,
method: String,
params: Vec<u8>,
},
RegisterModuleApi {
methods: Vec<String>,
api_version: u32,
},
UnregisterModuleApi,
GetModuleHealth {
module_id: String,
},
GetAllModuleHealth,
ReportModuleHealth {
health: crate::module::process::monitor::ModuleHealth,
},
SendMeshPacketToPeer {
peer_addr: String,
packet_data: Vec<u8>,
},
SendStratumV2MessageToPeer {
peer_addr: String,
message_data: Vec<u8>,
},
GetBlockTemplate {
rules: Vec<String>,
coinbase_script: Option<Vec<u8>>,
coinbase_address: Option<String>,
},
SubmitBlock {
block: Block,
},
MergeBlockServeDenylist {
block_hashes: Vec<Hash>,
},
GetBlockServeDenylistSnapshot,
ClearBlockServeDenylist,
ReplaceBlockServeDenylist {
block_hashes: Vec<Hash>,
},
MergeTxServeDenylist {
tx_hashes: Vec<Hash>,
},
GetTxServeDenylistSnapshot,
ClearTxServeDenylist,
ReplaceTxServeDenylist {
tx_hashes: Vec<Hash>,
},
GetSyncStatus,
BanPeer {
peer_addr: String,
ban_duration_seconds: Option<u64>,
},
SetBlockServeMaintenanceMode {
enabled: bool,
},
RegisterCliSpec {
spec: CliSpec,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CliSpec {
pub version: u32,
pub name: String,
pub about: Option<String>,
pub subcommands: Vec<CliSubcommandSpec>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CliSubcommandSpec {
pub name: String,
pub about: Option<String>,
pub args: Vec<CliArgSpec>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CliArgSpec {
pub name: String,
#[serde(default)]
pub long_name: Option<String>,
#[serde(default)]
pub short_name: Option<String>,
pub required: Option<bool>,
pub takes_value: Option<bool>,
pub default: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InvocationMessage {
pub correlation_id: CorrelationId,
pub invocation_type: InvocationType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InvocationType {
Cli {
subcommand: String,
args: Vec<String>,
},
Rpc {
method: String,
params: serde_json::Value,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InvocationResultMessage {
pub correlation_id: CorrelationId,
pub success: bool,
pub payload: Option<InvocationResultPayload>,
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InvocationResultPayload {
Cli {
stdout: String,
stderr: String,
exit_code: i32,
},
Rpc(serde_json::Value),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseMessage {
pub correlation_id: CorrelationId,
pub success: bool,
pub payload: Option<ResponsePayload>,
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ResponsePayload {
HandshakeAck {
node_version: String,
},
Block(Option<Block>),
BlockHeader(Option<BlockHeader>),
Transaction(Option<Transaction>),
Bool(bool),
Hash(Hash),
U64(u64),
Utxo(Option<UTXO>),
SubscribeAck,
MempoolTransactions(Vec<Hash>),
MempoolTransaction(Option<Transaction>),
MempoolSize(MempoolSize),
NetworkStats(NetworkStats),
NetworkPeers(Vec<PeerInfo>),
ChainInfo(ChainInfo),
BlockByHeight(Option<Block>),
LightningNodeUrl(Option<String>),
LightningInfo(Option<LightningInfo>),
PaymentState(Option<PaymentState>),
CheckTransactionInMempool(bool),
FeeEstimate(u64),
FileData(Vec<u8>),
DirectoryListing(Vec<String>),
FileMetadata(FileMetadata),
RpcEndpointRegistered,
RpcEndpointUnregistered,
TimerId(u64),
TaskId(u64),
TimerCancelled,
TaskScheduled,
MetricReported,
ModuleMetrics(Vec<crate::module::metrics::manager::Metric>),
AllMetrics(std::collections::HashMap<String, Vec<crate::module::metrics::manager::Metric>>),
ModuleList(Vec<crate::module::traits::ModuleInfo>),
ModuleInfo(Option<crate::module::traits::ModuleInfo>),
ModuleAvailable(bool),
EventPublished,
ModuleApiResponse(Vec<u8>),
ModuleApiRegistered,
ModuleApiUnregistered,
ModuleHealth(Option<crate::module::process::monitor::ModuleHealth>),
AllModuleHealth(Vec<(String, crate::module::process::monitor::ModuleHealth)>),
HealthReported,
BlockTemplate(blvm_protocol::mining::BlockTemplate),
SubmitBlockResult(crate::module::traits::SubmitBlockResult),
BlockServeDenylistMerged,
TxServeDenylistMerged,
BlockServeDenylistSnapshot(BlockServeDenylistSnapshot),
TxServeDenylistSnapshot(TxServeDenylistSnapshot),
NodeSyncStatus(SyncStatus),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventMessage {
pub event_type: EventType,
pub payload: EventPayload,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogMessage {
pub level: LogLevel,
pub module_id: String,
pub message: String,
pub target: String, pub timestamp: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EventPayload {
NewBlock {
block_hash: Hash,
height: u64,
},
NewTransaction {
tx_hash: Hash,
},
BlockDisconnected {
hash: Hash,
height: u64,
},
ChainReorg {
old_tip: Hash,
new_tip: Hash,
},
PaymentRequestCreated {
payment_id: String,
amount_sats: u64,
invoice: Option<String>,
},
PaymentSettled {
payment_id: String,
tx_hash: Hash,
confirmations: u32,
},
PaymentFailed {
payment_id: String,
reason: String,
},
PaymentVerified {
payment_id: String,
amount_msats: u64,
invoice: String,
},
PaymentRouteFound {
payment_id: String,
route_hops: usize,
route_cost_msats: u64,
},
PaymentRouteFailed {
payment_id: String,
reason: String,
},
ChannelOpened {
channel_id: String,
peer_pubkey: Vec<u8>,
capacity_sats: u64,
},
ChannelClosed {
channel_id: String,
reason: String,
},
BlockMined {
block_hash: Hash,
height: u64,
miner_id: Option<String>,
},
BlockTemplateUpdated {
prev_hash: Hash,
height: u64,
tx_count: usize,
},
MiningDifficultyChanged {
old_difficulty: u32,
new_difficulty: u32,
height: u64,
},
MiningJobCreated {
job_id: String,
prev_hash: Hash,
height: u64,
},
ShareSubmitted {
job_id: String,
share_hash: Hash,
miner_id: Option<String>,
},
MergeMiningReward {
secondary_chain: String,
reward_amount: u64,
block_hash: Hash,
},
MiningPoolConnected {
pool_url: String,
pool_id: Option<String>,
},
MiningPoolDisconnected {
pool_url: String,
reason: String,
},
GovernanceProposalCreated {
proposal_id: String,
repository: String,
pr_number: u64,
tier: String,
},
GovernanceProposalVoted {
proposal_id: String,
voter: String,
vote: String, },
GovernanceProposalMerged {
proposal_id: String,
repository: String,
pr_number: u64,
},
WebhookSent {
webhook_url: String,
event_type: String,
success: bool,
},
WebhookFailed {
webhook_url: String,
event_type: String,
error: String,
},
GovernanceForkDetected {
fork_id: String,
ruleset_version: String,
adoption_count: usize,
},
PeerConnected {
peer_addr: String, transport_type: String, services: u64,
version: u32,
},
PeerDisconnected {
peer_addr: String,
reason: String, },
PeerBanned {
peer_addr: String,
reason: String,
ban_duration_seconds: u64,
},
PeerUnbanned {
peer_addr: String,
},
MessageReceived {
peer_addr: String,
message_type: String, message_size: usize,
protocol_version: u32,
},
MessageSent {
peer_addr: String,
message_type: String,
message_size: usize,
},
BroadcastStarted {
message_type: String,
target_peers: usize,
},
BroadcastCompleted {
message_type: String,
successful: usize,
failed: usize,
},
RouteDiscovered {
destination: Vec<u8>, route_path: Vec<String>, route_cost: u64,
},
RouteFailed {
destination: Vec<u8>,
reason: String,
},
ConnectionAttempt {
peer_addr: String,
success: bool,
error: Option<String>,
},
AddressDiscovered {
peer_addr: String,
source: String, },
AddressExpired {
peer_addr: String,
},
NetworkPartition {
partition_id: Vec<u8>,
disconnected_peers: Vec<String>,
partition_size: usize,
},
NetworkReconnected {
partition_id: Vec<u8>,
reconnected_peers: Vec<String>,
},
DoSAttackDetected {
peer_addr: String,
attack_type: String, severity: String, },
RateLimitExceeded {
peer_addr: String,
limit_type: String, current_rate: f64,
limit: f64,
},
BlockValidationStarted {
block_hash: Hash,
height: u64,
},
BlockValidationCompleted {
block_hash: Hash,
height: u64,
success: bool,
validation_time_ms: u64,
error: Option<String>,
},
ScriptVerificationStarted {
tx_hash: Hash,
input_index: usize,
},
ScriptVerificationCompleted {
tx_hash: Hash,
input_index: usize,
success: bool,
verification_time_ms: u64,
},
UTXOValidationStarted {
block_hash: Hash,
height: u64,
},
UTXOValidationCompleted {
block_hash: Hash,
height: u64,
success: bool,
},
DifficultyAdjusted {
old_difficulty: u32,
new_difficulty: u32,
height: u64,
},
SoftForkActivated {
fork_name: String, height: u64,
},
SoftForkLockedIn {
fork_name: String,
height: u64,
},
ConsensusRuleViolation {
rule_name: String,
block_hash: Option<Hash>,
tx_hash: Option<Hash>,
error: String,
},
HeadersSyncStarted {
start_height: u64,
},
HeadersSyncProgress {
current_height: u64,
target_height: u64,
progress_percent: f64,
},
HeadersSyncCompleted {
final_height: u64,
duration_seconds: u64,
},
BlockSyncStarted {
start_height: u64,
target_height: u64,
},
BlockSyncProgress {
current_height: u64,
target_height: u64,
progress_percent: f64,
blocks_per_second: f64,
},
BlockSyncCompleted {
final_height: u64,
duration_seconds: u64,
},
SyncStateChanged {
old_state: String, new_state: String,
},
MempoolTransactionAdded {
tx_hash: Hash,
fee_rate: f64,
mempool_size: usize,
},
MempoolTransactionRemoved {
tx_hash: Hash,
reason: String, mempool_size: usize,
},
MempoolThresholdExceeded {
current_size: usize,
threshold: usize,
},
FeeRateChanged {
old_fee_rate: f64,
new_fee_rate: f64,
mempool_size: usize,
},
MempoolCleared {
cleared_count: usize,
},
StorageRead {
operation: String,
duration_ms: u64,
},
StorageWrite {
operation: String,
duration_ms: u64,
bytes_written: usize,
},
StorageQuery {
query_type: String,
duration_ms: u64,
},
DatabaseBackupStarted {
backup_path: String,
},
DatabaseBackupCompleted {
backup_path: String,
success: bool,
size_bytes: u64,
duration_seconds: u64,
},
ModuleLoaded {
module_name: String,
version: String,
},
ModuleUnloaded {
module_name: String,
version: String,
},
ModuleReloaded {
module_name: String,
old_version: String,
new_version: String,
},
ModuleStarted {
module_name: String,
},
ModuleStopped {
module_name: String,
},
MeshPacketReceived {
packet_data: Vec<u8>,
peer_addr: String, },
StratumV2MessageReceived {
message_data: Vec<u8>,
peer_addr: String, },
ModuleCrashed {
module_name: String,
error: String,
},
ModuleHealthChanged {
module_name: String,
old_health: String, new_health: String,
},
ModuleStateChanged {
module_name: String,
old_state: String,
new_state: String,
},
ConfigLoaded {
changed_sections: Vec<String>,
config_json: Option<String>,
},
NodeShutdown {
reason: String,
timeout_seconds: u64,
},
NodeShutdownCompleted {
duration_ms: u64,
},
NodeStartupCompleted {
duration_ms: u64,
components: Vec<String>,
},
MaintenanceStarted {
maintenance_type: String,
estimated_duration_seconds: Option<u64>,
},
MaintenanceCompleted {
maintenance_type: String,
success: bool,
duration_ms: u64,
results: Option<String>,
},
DataMaintenance {
operation: String,
urgency: String,
reason: String,
target_age_days: Option<u64>,
timeout_seconds: Option<u64>,
},
HealthCheck {
check_type: String,
node_healthy: bool,
health_report: Option<String>,
},
DiskSpaceLow {
available_bytes: u64,
total_bytes: u64,
percent_free: f64,
disk_path: String,
},
ResourceLimitWarning {
resource_type: String,
usage_percent: f64,
current_usage: u64,
limit: u64,
threshold_percent: f64,
},
DandelionStemStarted {
tx_hash: Hash,
current_peer: String,
next_peer: String,
},
DandelionStemAdvanced {
tx_hash: Hash,
hop_count: u8,
next_peer: String,
},
DandelionFluffed {
tx_hash: Hash,
stem_hops: u8,
},
DandelionStemPathExpired {
peer_addr: String,
},
CompactBlockReceived {
block_hash: Hash,
height: u64,
short_ids_count: usize,
},
BlockReconstructionStarted {
block_hash: Hash,
height: u64,
},
BlockReconstructionCompleted {
block_hash: Hash,
height: u64,
success: bool,
missing_txs: usize,
},
FibreBlockEncoded {
block_hash: Hash,
height: u64,
chunks: usize,
encoding_time_ms: u64,
},
FibreBlockSent {
block_hash: Hash,
height: u64,
peer_addr: String,
},
FibrePeerRegistered {
peer_addr: String,
},
PackageReceived {
package_id: Vec<u8>,
transaction_count: usize,
peer_addr: String,
},
PackageRejected {
package_id: Vec<u8>,
reason: String,
peer_addr: String,
},
UtxoCommitmentReceived {
block_hash: Hash,
height: u64,
commitment_hash: Hash,
peer_addr: String,
},
UtxoCommitmentVerified {
block_hash: Hash,
height: u64,
commitment_hash: Hash,
valid: bool,
},
BanListShared {
peer_addr: String,
ban_count: usize,
},
BanListReceived {
peer_addr: String,
ban_count: usize,
},
SelectiveSyncPolicyApplied {
policy_source: String, registry_count: usize,
},
ActionExecuted {
action_id: String,
action_type: String,
target: String, success: bool,
},
ModulePurchaseCompleted {
module_id: String,
payment_id: String,
amount_sats: u64,
},
StratumClientConnected {
endpoint: String,
protocol_version: u32,
},
StratumClientDisconnected {
endpoint: String,
reason: String,
},
IBDBlockFiltered {
block_hash: Hash,
height: u64,
reason: String, },
ModuleDiscovered {
module_name: String,
version: String,
source: String, },
ModuleInstalled {
module_name: String,
version: String,
},
ModuleUpdated {
module_name: String,
old_version: String,
new_version: String,
},
ModuleRemoved {
module_name: String,
version: String,
},
}
impl EventPayload {
pub fn as_new_block(&self) -> Option<(&Hash, u64)> {
match self {
Self::NewBlock { block_hash, height } => Some((block_hash, *height)),
_ => None,
}
}
pub fn as_new_transaction(&self) -> Option<&Hash> {
match self {
Self::NewTransaction { tx_hash } => Some(tx_hash),
_ => None,
}
}
pub fn as_module_loaded(&self) -> Option<(&str, &str)> {
match self {
Self::ModuleLoaded {
module_name,
version,
} => Some((module_name.as_str(), version.as_str())),
_ => None,
}
}
pub fn as_block_disconnected(&self) -> Option<(&Hash, u64)> {
match self {
Self::BlockDisconnected { hash, height } => Some((hash, *height)),
_ => None,
}
}
pub fn as_chain_reorg(&self) -> Option<(&Hash, &Hash)> {
match self {
Self::ChainReorg { old_tip, new_tip } => Some((old_tip, new_tip)),
_ => None,
}
}
}
impl RequestMessage {
pub fn get_block(correlation_id: CorrelationId, hash: Hash) -> Self {
Self {
correlation_id,
request_type: MessageType::GetBlock,
payload: RequestPayload::GetBlock { hash },
}
}
pub fn get_block_header(correlation_id: CorrelationId, hash: Hash) -> Self {
Self {
correlation_id,
request_type: MessageType::GetBlockHeader,
payload: RequestPayload::GetBlockHeader { hash },
}
}
pub fn get_transaction(correlation_id: CorrelationId, hash: Hash) -> Self {
Self {
correlation_id,
request_type: MessageType::GetTransaction,
payload: RequestPayload::GetTransaction { hash },
}
}
pub fn has_transaction(correlation_id: CorrelationId, hash: Hash) -> Self {
Self {
correlation_id,
request_type: MessageType::HasTransaction,
payload: RequestPayload::HasTransaction { hash },
}
}
pub fn get_chain_tip(correlation_id: CorrelationId) -> Self {
Self {
correlation_id,
request_type: MessageType::GetChainTip,
payload: RequestPayload::GetChainTip,
}
}
pub fn get_block_height(correlation_id: CorrelationId) -> Self {
Self {
correlation_id,
request_type: MessageType::GetBlockHeight,
payload: RequestPayload::GetBlockHeight,
}
}
pub fn get_utxo(correlation_id: CorrelationId, outpoint: OutPoint) -> Self {
Self {
correlation_id,
request_type: MessageType::GetUtxo,
payload: RequestPayload::GetUtxo { outpoint },
}
}
pub fn subscribe_events(correlation_id: CorrelationId, event_types: Vec<EventType>) -> Self {
Self {
correlation_id,
request_type: MessageType::SubscribeEvents,
payload: RequestPayload::SubscribeEvents { event_types },
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileMetadata {
pub path: String,
pub size: u64,
pub is_file: bool,
pub is_directory: bool,
pub modified: Option<u64>, pub created: Option<u64>, }
impl ResponseMessage {
pub fn success(correlation_id: CorrelationId, payload: ResponsePayload) -> Self {
Self {
correlation_id,
success: true,
payload: Some(payload),
error: None,
}
}
pub fn error(correlation_id: CorrelationId, error: String) -> Self {
Self {
correlation_id,
success: false,
payload: None,
error: Some(error),
}
}
}