-
Notifications
You must be signed in to change notification settings - Fork 220
Expand file tree
/
Copy pathcore.rs
More file actions
129 lines (119 loc) · 3.74 KB
/
core.rs
File metadata and controls
129 lines (119 loc) · 3.74 KB
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
//! Core reshare [Application] implementation.
use crate::{
application::{genesis_block, Block},
dkg,
};
use commonware_consensus::{
simplex::types::Context,
types::{Epoch, Round, View},
Heightable,
};
use commonware_cryptography::{
bls12381::primitives::variant::Variant, certificate::Scheme, Committable, Digest, Hasher,
Signer,
};
use commonware_runtime::{Clock, Metrics, Spawner};
use futures::{Stream, StreamExt};
use rand::Rng;
use std::marker::PhantomData;
pub struct Application<E, S, H, C, V>
where
E: Rng + Spawner + Metrics + Clock,
S: Scheme,
H: Hasher,
C: Signer,
V: Variant,
{
dkg: dkg::Mailbox<H, C, V>,
_marker: PhantomData<(E, S)>,
}
impl<E, S, H, C, V> Clone for Application<E, S, H, C, V>
where
E: Rng + Spawner + Metrics + Clock,
S: Scheme,
H: Hasher,
C: Signer,
V: Variant,
{
fn clone(&self) -> Self {
Self {
dkg: self.dkg.clone(),
_marker: PhantomData,
}
}
}
impl<E, S, H, C, V> Application<E, S, H, C, V>
where
E: Rng + Spawner + Metrics + Clock,
S: Scheme,
H: Hasher,
C: Signer,
V: Variant,
{
pub const fn new(dkg: dkg::Mailbox<H, C, V>) -> Self {
Self {
dkg,
_marker: PhantomData,
}
}
}
impl<E, S, H, C, V> commonware_consensus::Application<E> for Application<E, S, H, C, V>
where
E: Rng + Spawner + Metrics + Clock,
S: Scheme,
H: Hasher,
C: Signer,
V: Variant,
{
type Context = Context<H::Digest, C::PublicKey>;
type SigningScheme = S;
type Block = Block<H, C, V>;
async fn genesis(&mut self) -> Self::Block {
// Create a genesis context with epoch 0, view 0, and empty parent.
// Use a deterministic leader from seed 0 so all validators agree on genesis.
let genesis_context = Context {
round: Round::new(Epoch::zero(), View::zero()),
leader: C::from_seed(0).public_key(),
parent: (View::zero(), <H::Digest as Digest>::EMPTY),
};
genesis_block::<H, C, V>(genesis_context)
}
async fn propose(
&mut self,
(_, context): (E, Self::Context),
mut ancestry: impl Stream<Item = Self::Block> + Send + Unpin + 'static,
) -> Option<Self::Block> {
// Fetch the parent block from the ancestry stream.
let parent_block = ancestry.next().await?;
let parent_commitment = parent_block.commitment();
// Ask the DKG actor for a result to include
//
// This approach does allow duplicate commitments to be proposed, but
// the arbiter handles this by choosing the first commitment it sees
// from any given dealer.
let reshare = self.dkg.act().await;
// Create a new block with the consensus context
Some(Block::new(
context,
parent_commitment,
parent_block.height().next(),
reshare,
))
}
async fn verify(
&mut self,
_: (E, Self::Context),
_: impl Stream<Item = Self::Block> + Send + Unpin + 'static,
) -> bool {
// We wrap this application with `Marshaled`, which handles ancestry
// verification (parent commitment and height contiguity).
//
// You could opt to verify the deal_outcome in the block here (both that it is valid
// and that the dealer is the proposer) but we opt to only process deal data after the
// block has been finalized to keep verification as fast as possible. The downside
// of this approach is that invalid data can be included in the canonical chain (which
// makes certificates over finalized blocks less useful because the verifier must still
// check the block contents).
true
}
}