1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (C) 2021 Subspace Labs, Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! `sc-consensus-subspace` is the core of Subspace consensus implementation.
//!
//! You should familiarize yourself with [Subnomicon](https://subnomicon.subspace.network/) and, ideally, protocol
//! specifications. Documentation here assumes decent prior knowledge of the protocol on conceptual level and will not
//! explain how the protocol works, it will instead explain how the protocol is implemented.
//!
//! All of the modules here are crucial for consensus, open each module for specific details.

#![feature(const_option, let_chains, try_blocks)]
#![feature(duration_constructors)]
#![forbid(unsafe_code)]
#![warn(missing_docs)]

pub mod archiver;
pub mod aux_schema;
pub mod block_import;
pub mod notification;
pub mod slot_worker;
#[cfg(test)]
mod tests;
pub mod verifier;

use crate::archiver::ArchivedSegmentNotification;
use crate::block_import::BlockImportingNotification;
use crate::notification::{SubspaceNotificationSender, SubspaceNotificationStream};
use crate::slot_worker::{NewSlotNotification, RewardSigningNotification};
use sp_consensus_subspace::ChainConstants;
use sp_runtime::traits::Block as BlockT;
use subspace_core_primitives::crypto::kzg::Kzg;
use subspace_erasure_coding::ErasureCoding;

/// State that must be shared between various consensus components.
#[derive(Clone)]
pub struct SubspaceLink<Block: BlockT> {
    new_slot_notification_sender: SubspaceNotificationSender<NewSlotNotification>,
    new_slot_notification_stream: SubspaceNotificationStream<NewSlotNotification>,
    reward_signing_notification_sender: SubspaceNotificationSender<RewardSigningNotification>,
    reward_signing_notification_stream: SubspaceNotificationStream<RewardSigningNotification>,
    archived_segment_notification_sender: SubspaceNotificationSender<ArchivedSegmentNotification>,
    archived_segment_notification_stream: SubspaceNotificationStream<ArchivedSegmentNotification>,
    block_importing_notification_sender:
        SubspaceNotificationSender<BlockImportingNotification<Block>>,
    block_importing_notification_stream:
        SubspaceNotificationStream<BlockImportingNotification<Block>>,
    chain_constants: ChainConstants,
    kzg: Kzg,
    erasure_coding: ErasureCoding,
}

impl<Block: BlockT> SubspaceLink<Block> {
    /// Create new instance.
    pub fn new(chain_constants: ChainConstants, kzg: Kzg, erasure_coding: ErasureCoding) -> Self {
        let (new_slot_notification_sender, new_slot_notification_stream) =
            notification::channel("subspace_new_slot_notification_stream");
        let (reward_signing_notification_sender, reward_signing_notification_stream) =
            notification::channel("subspace_reward_signing_notification_stream");
        let (archived_segment_notification_sender, archived_segment_notification_stream) =
            notification::channel("subspace_archived_segment_notification_stream");
        let (block_importing_notification_sender, block_importing_notification_stream) =
            notification::channel("subspace_block_importing_notification_stream");

        Self {
            new_slot_notification_sender,
            new_slot_notification_stream,
            reward_signing_notification_sender,
            reward_signing_notification_stream,
            archived_segment_notification_sender,
            archived_segment_notification_stream,
            block_importing_notification_sender,
            block_importing_notification_stream,
            chain_constants,
            kzg,
            erasure_coding,
        }
    }

    /// Get stream with notifications about new slot arrival with ability to send solution back.
    pub fn new_slot_notification_stream(&self) -> SubspaceNotificationStream<NewSlotNotification> {
        self.new_slot_notification_stream.clone()
    }

    /// A stream with notifications about headers that need to be signed with ability to send
    /// signature back.
    pub fn reward_signing_notification_stream(
        &self,
    ) -> SubspaceNotificationStream<RewardSigningNotification> {
        self.reward_signing_notification_stream.clone()
    }

    /// Get stream with notifications about archived segment creation
    pub fn archived_segment_notification_stream(
        &self,
    ) -> SubspaceNotificationStream<ArchivedSegmentNotification> {
        self.archived_segment_notification_stream.clone()
    }

    /// Get stream with notifications about each imported block right BEFORE import actually
    /// happens.
    ///
    /// NOTE: all Subspace checks have already happened for this block, but block can still
    /// potentially fail to import in Substrate's internals.
    pub fn block_importing_notification_stream(
        &self,
    ) -> SubspaceNotificationStream<BlockImportingNotification<Block>> {
        self.block_importing_notification_stream.clone()
    }

    /// Subspace chain constants.
    pub fn chain_constants(&self) -> &ChainConstants {
        &self.chain_constants
    }

    /// Access KZG instance
    pub fn kzg(&self) -> &Kzg {
        &self.kzg
    }

    /// Access erasure coding instance
    pub fn erasure_coding(&self) -> &ErasureCoding {
        &self.erasure_coding
    }
}