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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use std::{any::Any, collections::BTreeMap, fmt::Debug};
use anyhow::Error;
use datasize::DataSize;
use serde::{Deserialize, Serialize};
use crate::{
components::consensus::traits::Context,
types::{CryptoRngCore, Timestamp},
};
/// Information about the context in which a new block is created.
#[derive(Clone, DataSize, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub struct BlockContext {
timestamp: Timestamp,
height: u64,
}
impl BlockContext {
/// Constructs a new `BlockContext`.
pub(crate) fn new(timestamp: Timestamp, height: u64) -> Self {
BlockContext { timestamp, height }
}
/// The block's timestamp.
pub(crate) fn timestamp(&self) -> Timestamp {
self.timestamp
}
}
/// Equivocation and reward information to be included in the terminal finalized block.
#[derive(Clone, DataSize, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(bound(
serialize = "VID: Ord + Serialize",
deserialize = "VID: Ord + Deserialize<'de>",
))]
pub struct EraEnd<VID> {
/// The set of equivocators.
pub(crate) equivocators: Vec<VID>,
/// Rewards for finalization of earlier blocks.
///
/// This is a measure of the value of each validator's contribution to consensus, in
/// fractions of the configured maximum block reward.
pub(crate) rewards: BTreeMap<VID, u64>,
}
/// A finalized block. All nodes are guaranteed to see the same sequence of blocks, and to agree
/// about all the information contained in this type, as long as the total weight of faulty
/// validators remains below the threshold.
#[derive(Debug, Eq, PartialEq)]
pub(crate) struct FinalizedBlock<C: Context> {
/// The finalized value.
pub(crate) value: C::ConsensusValue,
/// The timestamp at which this value was proposed.
pub(crate) timestamp: Timestamp,
/// The relative height in this instance of the protocol.
pub(crate) height: u64,
/// If this is a terminal block, i.e. the last one to be finalized, this includes rewards.
pub(crate) rewards: Option<BTreeMap<C::ValidatorId, u64>>,
/// The validators known to be faulty as seen by this block.
pub(crate) equivocators: Vec<C::ValidatorId>,
/// Proposer of this value
pub(crate) proposer: C::ValidatorId,
}
#[derive(Debug)]
pub(crate) enum ConsensusProtocolResult<I, C: Context> {
CreatedGossipMessage(Vec<u8>),
CreatedTargetedMessage(Vec<u8>, I),
InvalidIncomingMessage(Vec<u8>, I, Error),
ScheduleTimer(Timestamp),
/// Request deploys for a new block, whose timestamp will be the given `u64`.
/// TODO: Add more details that are necessary for block creation.
CreateNewBlock {
block_context: BlockContext,
},
/// A block was finalized.
FinalizedBlock(FinalizedBlock<C>),
/// Request validation of the consensus value, contained in a message received from the given
/// node.
///
/// The domain logic should verify any intrinsic validity conditions of consensus values, e.g.
/// that it has the expected structure, or that deploys that are mentioned by hash actually
/// exist, and then call `ConsensusProtocol::resolve_validity`.
ValidateConsensusValue(I, C::ConsensusValue, Timestamp),
/// New direct evidence was added against the given validator.
NewEvidence(C::ValidatorId),
/// Send evidence about the validator from an earlier era to the peer.
SendEvidence(I, C::ValidatorId),
}
/// An API for a single instance of the consensus.
pub(crate) trait ConsensusProtocol<I, C: Context> {
/// Upcasts consensus protocol into `dyn Any`.
///
/// Typically called on a boxed trait object for downcasting afterwards.
fn as_any(&self) -> &dyn Any;
/// Handles an incoming message (like NewVote, RequestDependency).
fn handle_message(
&mut self,
sender: I,
msg: Vec<u8>,
evidence_only: bool,
rng: &mut dyn CryptoRngCore,
) -> Vec<ConsensusProtocolResult<I, C>>;
/// Triggers consensus' timer.
fn handle_timer(
&mut self,
timestamp: Timestamp,
rng: &mut dyn CryptoRngCore,
) -> Vec<ConsensusProtocolResult<I, C>>;
/// Proposes a new value for consensus.
fn propose(
&mut self,
value: C::ConsensusValue,
block_context: BlockContext,
rng: &mut dyn CryptoRngCore,
) -> Vec<ConsensusProtocolResult<I, C>>;
/// Marks the `value` as valid or invalid, based on validation requested via
/// `ConsensusProtocolResult::ValidateConsensusvalue`.
fn resolve_validity(
&mut self,
value: &C::ConsensusValue,
valid: bool,
rng: &mut dyn CryptoRngCore,
) -> Vec<ConsensusProtocolResult<I, C>>;
/// Turns this instance into an active validator, that participates in the consensus protocol.
fn activate_validator(
&mut self,
our_id: C::ValidatorId,
secret: C::ValidatorSecret,
timestamp: Timestamp,
) -> Vec<ConsensusProtocolResult<I, C>>;
/// Turns this instance into a passive observer, that does not create any new vertices.
fn deactivate_validator(&mut self);
/// Returns whether the validator `vid` is known to be faulty.
fn has_evidence(&self, vid: &C::ValidatorId) -> bool;
/// Marks the validator `vid` as faulty, based on evidence from a different instance.
fn mark_faulty(&mut self, vid: &C::ValidatorId);
/// Sends evidence for a faulty of validator `vid` to the `sender` of the request.
fn request_evidence(
&self,
sender: I,
vid: &C::ValidatorId,
) -> Vec<ConsensusProtocolResult<I, C>>;
/// Returns the list of all validators that were observed as faulty in this consensus instance.
fn validators_with_evidence(&self) -> Vec<&C::ValidatorId>;
/// Returns true if the protocol has received some messages since initialization.
fn has_received_messages(&self) -> bool;
}