Skip to content

Commit 95bb765

Browse files
committed
Merge remote-tracking branch 'origin/main' into ab/epoch-integration-test
2 parents 9de78ea + a31db38 commit 95bb765

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2179
-880
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hotshot-example-types/src/block_types.rs

+16
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,22 @@ impl TestBlockHeader {
298298
}
299299
}
300300

301+
impl Default for TestBlockHeader {
302+
fn default() -> Self {
303+
let metadata = TestMetadata {
304+
num_transactions: 0,
305+
};
306+
Self {
307+
block_number: 0,
308+
payload_commitment: Default::default(),
309+
builder_commitment: Default::default(),
310+
metadata,
311+
timestamp: 0,
312+
random: 0,
313+
}
314+
}
315+
}
316+
301317
impl<
302318
TYPES: NodeType<
303319
BlockHeader = Self,

hotshot-example-types/src/node_types.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ pub use hotshot::traits::election::helpers::{
1111
};
1212
use hotshot::traits::{
1313
election::{
14-
helpers::QuorumFilterConfig, randomized_committee::Committee,
15-
randomized_committee_members::RandomizedCommitteeMembers,
14+
dummy_catchup_membership::DummyCatchupCommittee, helpers::QuorumFilterConfig,
15+
randomized_committee::Committee, randomized_committee_members::RandomizedCommitteeMembers,
1616
static_committee::StaticCommittee,
1717
static_committee_leader_two_views::StaticCommitteeLeaderForTwoViews,
1818
two_static_committees::TwoStaticCommittees,
@@ -101,6 +101,36 @@ impl NodeType for TestTypesRandomizedLeader {
101101
type BuilderSignatureKey = BuilderKey;
102102
}
103103

104+
#[derive(
105+
Copy,
106+
Clone,
107+
Debug,
108+
Default,
109+
Hash,
110+
PartialEq,
111+
Eq,
112+
PartialOrd,
113+
Ord,
114+
serde::Serialize,
115+
serde::Deserialize,
116+
)]
117+
pub struct TestTypesEpochCatchupTypes;
118+
impl NodeType for TestTypesEpochCatchupTypes {
119+
const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
120+
121+
type AuctionResult = TestAuctionResult;
122+
type View = ViewNumber;
123+
type Epoch = EpochNumber;
124+
type BlockHeader = TestBlockHeader;
125+
type BlockPayload = TestBlockPayload;
126+
type SignatureKey = BLSPubKey;
127+
type Transaction = TestTransaction;
128+
type ValidatedState = TestValidatedState;
129+
type InstanceState = TestInstanceState;
130+
type Membership = DummyCatchupCommittee<TestTypesEpochCatchupTypes>;
131+
type BuilderSignatureKey = BuilderKey;
132+
}
133+
104134
#[derive(
105135
Copy,
106136
Clone,

hotshot-examples/infra/mod.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use hotshot_testing::block_builder::{
5454
use hotshot_types::{
5555
consensus::ConsensusMetricsValue,
5656
data::{Leaf, TestableLeaf},
57+
epoch_membership::EpochMembershipCoordinator,
5758
event::{Event, EventType},
5859
network::{BuilderType, NetworkConfig, NetworkConfigFile, NetworkConfigSource},
5960
traits::{
@@ -388,13 +389,14 @@ pub trait RunDa<
388389
// TODO: we need to pass a valid fallback builder url here somehow
389390
fallback_builder_url: config.config.builder_urls.first().clone(),
390391
};
392+
let epoch_height = config.config.epoch_height;
391393

392394
SystemContext::init(
393395
pk,
394396
sk,
395397
config.node_index,
396398
config.config,
397-
membership,
399+
EpochMembershipCoordinator::new(membership, epoch_height),
398400
Arc::from(network),
399401
initializer,
400402
ConsensusMetricsValue::default(),
@@ -524,15 +526,15 @@ pub trait RunDa<
524526
}
525527
}
526528
}
529+
// Panic if we don't have the genesis epoch, there is no recovery from that
527530
let num_eligible_leaders = context
528531
.hotshot
529-
.memberships
530-
.read()
532+
.membership_coordinator
533+
.membership_for_epoch(genesis_epoch_from_version::<V, TYPES>())
534+
.await
535+
.unwrap()
536+
.committee_leaders(TYPES::View::genesis())
531537
.await
532-
.committee_leaders(
533-
TYPES::View::genesis(),
534-
genesis_epoch_from_version::<V, TYPES>(),
535-
)
536538
.len();
537539
let consensus_lock = context.hotshot.consensus();
538540
let consensus_reader = consensus_lock.read().await;

hotshot-query-service/examples/simple-server.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use hotshot_query_service::{
4242
use hotshot_testing::block_builder::{SimpleBuilderImplementation, TestBuilderImplementation};
4343
use hotshot_types::{
4444
consensus::ConsensusMetricsValue,
45+
epoch_membership::EpochMembershipCoordinator,
4546
light_client::StateKeyPair,
4647
signature_key::BLSPubKey,
4748
traits::{election::Membership, network::Topic},
@@ -236,13 +237,17 @@ async fn init_consensus(
236237
));
237238

238239
let storage: TestStorage<MockTypes> = TestStorage::default();
240+
let coordinator = EpochMembershipCoordinator::new(
241+
Arc::new(RwLock::new(membership)),
242+
config.epoch_height,
243+
);
239244

240245
SystemContext::init(
241246
pub_keys[node_id],
242247
priv_key,
243248
node_id as u64,
244249
config,
245-
Arc::new(RwLock::new(membership)),
250+
coordinator,
246251
network,
247252
HotShotInitializer::from_genesis::<MockVersions>(
248253
TestInstanceState::default(),

hotshot-query-service/src/testing/consensus.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use hotshot_example_types::{
3838
use hotshot_testing::block_builder::{SimpleBuilderImplementation, TestBuilderImplementation};
3939
use hotshot_types::{
4040
consensus::ConsensusMetricsValue,
41+
epoch_membership::EpochMembershipCoordinator,
4142
light_client::StateKeyPair,
4243
signature_key::BLSPubKey,
4344
traits::{election::Membership, network::Topic, signature_key::SignatureKey as _},
@@ -181,13 +182,15 @@ impl<D: DataSourceLifeCycle + UpdateStatusData> MockNetwork<D> {
181182
));
182183

183184
let hs_storage: TestStorage<MockTypes> = TestStorage::default();
185+
let memberships =
186+
EpochMembershipCoordinator::new(membership, config.epoch_height);
184187

185188
let hotshot = SystemContext::init(
186189
pub_keys[node_id],
187190
priv_key,
188191
node_id as u64,
189192
config,
190-
membership,
193+
memberships,
191194
network,
192195
HotShotInitializer::from_genesis::<MockVersions>(
193196
TestInstanceState::default(),

hotshot-task-impls/src/consensus/handlers.rs

+46-40
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ use chrono::Utc;
1111
use hotshot_types::{
1212
event::{Event, EventType},
1313
simple_vote::{HasEpoch, QuorumVote2, TimeoutData2, TimeoutVote2},
14-
traits::{
15-
election::Membership,
16-
node_implementation::{ConsensusTime, NodeImplementation, NodeType},
17-
},
14+
traits::node_implementation::{ConsensusTime, NodeImplementation, NodeType},
1815
utils::EpochTransitionIndicator,
1916
vote::{HasViewNumber, Vote},
2017
};
@@ -47,12 +44,14 @@ pub(crate) async fn handle_quorum_vote_recv<
4744
.read()
4845
.await
4946
.is_high_qc_for_last_block();
50-
let we_are_leader = task_state
51-
.membership
52-
.read()
47+
let epoch_membership = task_state
48+
.membership_coordinator
49+
.membership_for_epoch(vote.data.epoch)
5350
.await
54-
.leader(vote.view_number() + 1, vote.data.epoch)?
55-
== task_state.public_key;
51+
.context(warn!("No stake table for epoch"))?;
52+
53+
let we_are_leader =
54+
epoch_membership.leader(vote.view_number() + 1).await? == task_state.public_key;
5655
ensure!(
5756
in_transition || we_are_leader,
5857
info!(
@@ -70,8 +69,7 @@ pub(crate) async fn handle_quorum_vote_recv<
7069
&mut task_state.vote_collectors,
7170
vote,
7271
task_state.public_key.clone(),
73-
&task_state.membership,
74-
vote.data.epoch,
72+
&epoch_membership,
7573
task_state.id,
7674
&event,
7775
sender,
@@ -80,20 +78,19 @@ pub(crate) async fn handle_quorum_vote_recv<
8078
)
8179
.await?;
8280

83-
if let Some(vote_epoch) = vote.epoch() {
81+
if vote.epoch().is_some() {
8482
// If the vote sender belongs to the next epoch, collect it separately to form the second QC
85-
let has_stake = task_state
86-
.membership
87-
.read()
88-
.await
89-
.has_stake(&vote.signing_key(), Some(vote_epoch + 1));
83+
let has_stake = epoch_membership
84+
.next_epoch()
85+
.await?
86+
.has_stake(&vote.signing_key())
87+
.await;
9088
if has_stake {
9189
handle_vote(
9290
&mut task_state.next_epoch_vote_collectors,
9391
&vote.clone().into(),
9492
task_state.public_key.clone(),
95-
&task_state.membership,
96-
vote.data.epoch,
93+
&epoch_membership.next_epoch().await?.clone(),
9794
task_state.id,
9895
&event,
9996
sender,
@@ -118,14 +115,14 @@ pub(crate) async fn handle_timeout_vote_recv<
118115
sender: &Sender<Arc<HotShotEvent<TYPES>>>,
119116
task_state: &mut ConsensusTaskState<TYPES, I, V>,
120117
) -> Result<()> {
118+
let epoch_membership = task_state
119+
.membership_coordinator
120+
.membership_for_epoch(task_state.cur_epoch)
121+
.await
122+
.context(warn!("No stake table for epoch"))?;
121123
// Are we the leader for this view?
122124
ensure!(
123-
task_state
124-
.membership
125-
.read()
126-
.await
127-
.leader(vote.view_number() + 1, task_state.cur_epoch)?
128-
== task_state.public_key,
125+
epoch_membership.leader(vote.view_number() + 1).await? == task_state.public_key,
129126
info!(
130127
"We are not the leader for view {:?}",
131128
vote.view_number() + 1
@@ -136,8 +133,10 @@ pub(crate) async fn handle_timeout_vote_recv<
136133
&mut task_state.timeout_vote_collectors,
137134
vote,
138135
task_state.public_key.clone(),
139-
&task_state.membership,
140-
vote.data.epoch,
136+
&task_state
137+
.membership_coordinator
138+
.membership_for_epoch(vote.data.epoch)
139+
.await?,
141140
task_state.id,
142141
&event,
143142
sender,
@@ -201,10 +200,11 @@ pub async fn send_high_qc<TYPES: NodeType, V: Versions, I: NodeImplementation<TY
201200
.await;
202201
} else {
203202
let leader = task_state
204-
.membership
205-
.read()
206-
.await
207-
.leader(new_view_number, task_state.cur_epoch)?;
203+
.membership_coordinator
204+
.membership_for_epoch(task_state.cur_epoch)
205+
.await?
206+
.leader(new_view_number)
207+
.await?;
208208
broadcast_event(
209209
Arc::new(HotShotEvent::HighQcSend(
210210
high_qc,
@@ -305,10 +305,12 @@ pub(crate) async fn handle_view_change<
305305
std::mem::replace(&mut task_state.timeout_task, new_timeout_task).abort();
306306

307307
let old_view_leader_key = task_state
308-
.membership
309-
.read()
308+
.membership_coordinator
309+
.membership_for_epoch(task_state.cur_epoch)
310310
.await
311-
.leader(old_view_number, task_state.cur_epoch)?;
311+
.context(warn!("No stake table for epoch"))?
312+
.leader(old_view_number)
313+
.await?;
312314

313315
let consensus_reader = task_state.consensus.read().await;
314316
consensus_reader
@@ -367,10 +369,12 @@ pub(crate) async fn handle_timeout<TYPES: NodeType, I: NodeImplementation<TYPES>
367369

368370
ensure!(
369371
task_state
370-
.membership
371-
.read()
372+
.membership_coordinator
373+
.membership_for_epoch(epoch)
372374
.await
373-
.has_stake(&task_state.public_key, epoch),
375+
.context(warn!("No stake table for epoch"))?
376+
.has_stake(&task_state.public_key)
377+
.await,
374378
debug!(
375379
"We were not chosen for the consensus committee for view {:?}",
376380
view_number
@@ -416,10 +420,12 @@ pub(crate) async fn handle_timeout<TYPES: NodeType, I: NodeImplementation<TYPES>
416420
.await;
417421

418422
let leader = task_state
419-
.membership
420-
.read()
423+
.membership_coordinator
424+
.membership_for_epoch(task_state.cur_epoch)
421425
.await
422-
.leader(view_number, task_state.cur_epoch);
426+
.context(warn!("No stake table for epoch"))?
427+
.leader(view_number)
428+
.await;
423429

424430
let consensus_reader = task_state.consensus.read().await;
425431
consensus_reader.metrics.number_of_timeouts.add(1);

hotshot-task-impls/src/consensus/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
// along with the HotShot repository. If not, see <https://mit-license.org/>.
66

77
use async_broadcast::{Receiver, Sender};
8-
use async_lock::RwLock;
98
use async_trait::async_trait;
109
use hotshot_task::task::TaskState;
1110
use hotshot_types::{
1211
consensus::OuterConsensus,
12+
epoch_membership::EpochMembershipCoordinator,
1313
event::Event,
1414
message::UpgradeLock,
1515
simple_certificate::{NextEpochQuorumCertificate2, QuorumCertificate2, TimeoutCertificate2},
@@ -53,7 +53,7 @@ pub struct ConsensusTaskState<TYPES: NodeType, I: NodeImplementation<TYPES>, V:
5353
pub network: Arc<I::Network>,
5454

5555
/// Membership for Quorum Certs/votes
56-
pub membership: Arc<RwLock<TYPES::Membership>>,
56+
pub membership_coordinator: EpochMembershipCoordinator<TYPES>,
5757

5858
/// A map of `QuorumVote` collector tasks.
5959
pub vote_collectors: VoteCollectorsMap<TYPES, QuorumVote2<TYPES>, QuorumCertificate2<TYPES>, V>,
@@ -183,7 +183,7 @@ impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> ConsensusTaskSt
183183
high_qc,
184184
Some(next_epoch_high_qc),
185185
&self.consensus,
186-
&self.membership,
186+
&self.membership_coordinator,
187187
&self.upgrade_lock,
188188
)
189189
.await

0 commit comments

Comments
 (0)