Skip to content

Commit affdfce

Browse files
authored
refactor(contract): factor out shared gen_authenticated_participants helper (#3654)
1 parent 8d9da60 commit affdfce

4 files changed

Lines changed: 41 additions & 76 deletions

File tree

crates/contract/src/foreign_chain_rpc.rs

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,12 @@ impl ForeignChainRpcWhitelist {
246246
#[expect(non_snake_case)]
247247
mod tests {
248248
use super::*;
249-
use crate::primitives::{key_state::AuthenticatedParticipantId, test_utils::gen_participants};
249+
use crate::primitives::{
250+
key_state::AuthenticatedParticipantId, test_utils::gen_authenticated_participants,
251+
};
250252
use assert_matches::assert_matches;
251253
use mpc_primitives::Threshold;
252254
use near_mpc_contract_interface::types::AuthScheme;
253-
use near_sdk::test_utils::VMContextBuilder;
254-
use near_sdk::testing_env;
255255

256256
/// Build a `ThresholdParameters` for tests, bypassing the relative-threshold
257257
/// validation so tests can express edge-case combinations (e.g. the stale-votes
@@ -300,22 +300,6 @@ mod tests {
300300
NonEmptyBTreeMap::try_from(map).expect("test setup: batch must be non-empty")
301301
}
302302

303-
/// Build `n` participants and pre-authenticate each one. The pattern intentionally
304-
/// runs all `testing_env!` resets *before* any storage-backed state is touched —
305-
/// later vote ops can then write to the mocked storage without an env reset
306-
/// wiping prior writes.
307-
fn setup(n: usize) -> (Participants, Vec<AuthenticatedParticipantId>) {
308-
let participants = gen_participants(n);
309-
let mut auth_ids = Vec::with_capacity(n);
310-
for (account_id, _, _) in participants.participants() {
311-
let mut ctx = VMContextBuilder::new();
312-
ctx.signer_account_id(account_id.clone());
313-
testing_env!(ctx.build());
314-
auth_ids.push(AuthenticatedParticipantId::new(&participants).unwrap());
315-
}
316-
(participants, auth_ids)
317-
}
318-
319303
fn assert_malformed(err: Error, reason_substring: &str) {
320304
match err {
321305
Error::InvalidParameters(InvalidParameters::MalformedPayload { reason }) => {
@@ -363,7 +347,7 @@ mod tests {
363347
#[test]
364348
fn vote__should_apply_chain_when_all_participants_match() {
365349
// Given
366-
let (participants, auth_ids) = setup(2);
350+
let (participants, auth_ids) = gen_authenticated_participants(2);
367351
let mut wl = ForeignChainRpcWhitelist::default();
368352

369353
// When
@@ -406,7 +390,7 @@ mod tests {
406390
fn vote__should_canonicalize_provider_order_for_threshold_comparison() {
407391
// Two participants submit the same logical set in different orders.
408392
// Given
409-
let (participants, auth_ids) = setup(2);
393+
let (participants, auth_ids) = gen_authenticated_participants(2);
410394
let mut wl = ForeignChainRpcWhitelist::default();
411395

412396
// When
@@ -431,7 +415,7 @@ mod tests {
431415
#[test]
432416
fn vote__should_apply_chains_independently() {
433417
// Given
434-
let (participants, auth_ids) = setup(2);
418+
let (participants, auth_ids) = gen_authenticated_participants(2);
435419
let mut wl = ForeignChainRpcWhitelist::default();
436420

437421
// When: both participants agree on Ethereum, disagree on Polygon.
@@ -475,7 +459,7 @@ mod tests {
475459
#[test]
476460
fn vote__should_overwrite_only_mentioned_chain_slots_on_recast() {
477461
// Given
478-
let (participants, auth_ids) = setup(2);
462+
let (participants, auth_ids) = gen_authenticated_participants(2);
479463
let mut wl = ForeignChainRpcWhitelist::default();
480464
let p0 = auth_ids[0].clone();
481465
wl.vote(
@@ -501,7 +485,7 @@ mod tests {
501485
#[test]
502486
fn vote__should_overwrite_same_chain_slot_with_latest_proposal() {
503487
// Given: p0 has voted Polygon with providers=[alchemy], response quorum=1.
504-
let (participants, auth_ids) = setup(2);
488+
let (participants, auth_ids) = gen_authenticated_participants(2);
505489
let mut wl = ForeignChainRpcWhitelist::default();
506490
let p0 = auth_ids[0].clone();
507491
wl.vote(
@@ -542,7 +526,7 @@ mod tests {
542526
#[test]
543527
fn vote__should_replace_full_chain_state_on_apply() {
544528
// Given: chain currently holds [alchemy, ankr].
545-
let (participants, auth_ids) = setup(2);
529+
let (participants, auth_ids) = gen_authenticated_participants(2);
546530
let mut wl = ForeignChainRpcWhitelist::default();
547531
wl.vote(
548532
auth_ids[0].clone(),
@@ -583,7 +567,7 @@ mod tests {
583567

584568
#[test]
585569
fn vote__should_return_err_on_zero_quorum() {
586-
let (participants, auth_ids) = setup(2);
570+
let (participants, auth_ids) = gen_authenticated_participants(2);
587571
let mut wl = ForeignChainRpcWhitelist::default();
588572
let err = wl
589573
.vote(
@@ -597,7 +581,7 @@ mod tests {
597581

598582
#[test]
599583
fn vote__should_return_err_on_quorum_exceeding_providers_len() {
600-
let (participants, auth_ids) = setup(2);
584+
let (participants, auth_ids) = gen_authenticated_participants(2);
601585
let mut wl = ForeignChainRpcWhitelist::default();
602586
let err = wl
603587
.vote(
@@ -611,7 +595,7 @@ mod tests {
611595

612596
#[test]
613597
fn vote__should_return_err_on_path_segment_with_slash() {
614-
let (participants, auth_ids) = setup(2);
598+
let (participants, auth_ids) = gen_authenticated_participants(2);
615599
let mut wl = ForeignChainRpcWhitelist::default();
616600
let bad = (
617601
ProviderId("ankr".to_string()),
@@ -641,7 +625,7 @@ mod tests {
641625

642626
#[test]
643627
fn vote__should_return_err_on_query_param_name_colliding_with_auth_query() {
644-
let (participants, auth_ids) = setup(2);
628+
let (participants, auth_ids) = gen_authenticated_participants(2);
645629
let mut wl = ForeignChainRpcWhitelist::default();
646630
let bad = (
647631
ProviderId("drpc".to_string()),
@@ -675,7 +659,7 @@ mod tests {
675659
#[test]
676660
fn vote__should_accept_non_colliding_query_param_and_auth_query() {
677661
// Given
678-
let (participants, auth_ids) = setup(2);
662+
let (participants, auth_ids) = gen_authenticated_participants(2);
679663
let mut wl = ForeignChainRpcWhitelist::default();
680664
let drpc = || {
681665
(
@@ -727,7 +711,7 @@ mod tests {
727711
fn vote__should_not_count_stale_non_participant_votes() {
728712
// Given: 3 participants; p0 and p1 each vote the same proposal — chain
729713
// hasn't applied yet (count = 2, threshold = 3).
730-
let (participants, auth_ids) = setup(3);
714+
let (participants, auth_ids) = gen_authenticated_participants(3);
731715
let mut wl = ForeignChainRpcWhitelist::default();
732716
wl.vote(
733717
auth_ids[0].clone(),
@@ -765,7 +749,7 @@ mod tests {
765749
#[test]
766750
fn clean_non_participant_votes__should_drop_stale_votes() {
767751
// Given
768-
let (participants, auth_ids) = setup(3);
752+
let (participants, auth_ids) = gen_authenticated_participants(3);
769753
let mut wl = ForeignChainRpcWhitelist::default();
770754
let p0 = auth_ids[0].clone();
771755
let p1 = auth_ids[1].clone();

crates/contract/src/primitives/domain.rs

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -285,16 +285,13 @@ impl AddDomainsVotes {
285285
#[expect(non_snake_case)]
286286
pub mod tests {
287287
use super::{
288-
AddDomainsVotes, Curve, DomainConfig, DomainId, DomainPurpose, DomainRegistry,
289-
Participants, Protocol, is_valid_protocol_for_purpose, validate_domain_purpose,
288+
AddDomainsVotes, Curve, DomainConfig, DomainId, DomainPurpose, DomainRegistry, Protocol,
289+
is_valid_protocol_for_purpose, validate_domain_purpose,
290290
};
291-
use crate::primitives::key_state::AuthenticatedParticipantId;
292291
use crate::primitives::test_utils::{
293-
gen_participant, gen_participants, infer_purpose_from_protocol,
292+
gen_authenticated_participants, gen_participants, infer_purpose_from_protocol,
294293
};
295294
use near_mpc_contract_interface::types::ReconstructionThreshold;
296-
use near_sdk::test_utils::VMContextBuilder;
297-
use near_sdk::testing_env;
298295
use rstest::rstest;
299296
use std::collections::BTreeMap;
300297

@@ -498,24 +495,6 @@ pub mod tests {
498495
assert_eq!(validate_domain_purpose(&domain).is_ok(), expected_ok);
499496
}
500497

501-
fn setup_participants(n: usize) -> (Participants, Vec<AuthenticatedParticipantId>) {
502-
let mut participants = Participants::new();
503-
let mut accounts = Vec::new();
504-
for i in 0..n {
505-
let (account_id, info) = gen_participant(i);
506-
accounts.push(account_id.clone());
507-
participants.insert(account_id, info).unwrap();
508-
}
509-
let mut auth_ids = Vec::new();
510-
for account_id in &accounts {
511-
let mut ctx = VMContextBuilder::new();
512-
ctx.signer_account_id(account_id.clone());
513-
testing_env!(ctx.build());
514-
auth_ids.push(AuthenticatedParticipantId::new(&participants).unwrap());
515-
}
516-
(participants, auth_ids)
517-
}
518-
519498
fn sample_proposal() -> Vec<DomainConfig> {
520499
vec![DomainConfig {
521500
id: DomainId(0),
@@ -541,7 +520,7 @@ pub mod tests {
541520
#[test]
542521
fn test_get_remaining_votes_all_voters_still_participants() {
543522
// Given
544-
let (participants, auth_ids) = setup_participants(3);
523+
let (participants, auth_ids) = gen_authenticated_participants(3);
545524
let proposal = sample_proposal();
546525
let mut votes = AddDomainsVotes::default();
547526
for auth_id in &auth_ids {
@@ -558,7 +537,7 @@ pub mod tests {
558537
#[test]
559538
fn test_get_remaining_votes_some_voters_removed() {
560539
// Given
561-
let (participants, auth_ids) = setup_participants(3);
540+
let (participants, auth_ids) = gen_authenticated_participants(3);
562541
let proposal = sample_proposal();
563542
let mut votes = AddDomainsVotes::default();
564543
for auth_id in &auth_ids {
@@ -577,7 +556,7 @@ pub mod tests {
577556
#[test]
578557
fn test_get_remaining_votes_all_voters_removed() {
579558
// Given
580-
let (_, auth_ids) = setup_participants(3);
559+
let (_, auth_ids) = gen_authenticated_participants(3);
581560
let proposal = sample_proposal();
582561
let mut votes = AddDomainsVotes::default();
583562
for auth_id in &auth_ids {
@@ -595,7 +574,7 @@ pub mod tests {
595574
#[test]
596575
fn test_get_remaining_votes_preserves_different_proposals() {
597576
// Given
598-
let (participants, auth_ids) = setup_participants(3);
577+
let (participants, auth_ids) = gen_authenticated_participants(3);
599578
let proposal_a = vec![DomainConfig {
600579
id: DomainId(0),
601580
protocol: Protocol::CaitSith,

crates/contract/src/primitives/test_utils.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::domain::DomainRegistry;
22
use crate::{
33
crypto_shared::types::{PublicKeyExtended, serializable::SerializableEdwardsPoint},
44
primitives::{
5+
key_state::AuthenticatedParticipantId,
56
participants::{ParticipantInfo, Participants},
67
thresholds::{
78
ProposedThresholdParameters, Threshold, ThresholdParameters,
@@ -14,6 +15,7 @@ use near_account_id::AccountId;
1415
use near_mpc_contract_interface::types::{
1516
DomainConfig, DomainId, DomainPurpose, Protocol, ReconstructionThreshold,
1617
};
18+
use near_sdk::{test_utils::VMContextBuilder, testing_env};
1719
use rand::{Rng, SeedableRng, distributions::Uniform, rngs::StdRng};
1820
use std::collections::BTreeMap;
1921
// Re-export for convenience
@@ -145,6 +147,20 @@ pub fn gen_participants(n: usize) -> Participants {
145147
participants
146148
}
147149

150+
/// Build `n` participants and pre-authenticate each, returning the set alongside
151+
/// each participant's [`AuthenticatedParticipantId`].
152+
pub fn gen_authenticated_participants(n: usize) -> (Participants, Vec<AuthenticatedParticipantId>) {
153+
let participants = gen_participants(n);
154+
let mut auth_ids = Vec::with_capacity(n);
155+
for (account_id, _, _) in participants.participants() {
156+
let mut ctx = VMContextBuilder::new();
157+
ctx.signer_account_id(account_id.clone());
158+
testing_env!(ctx.build());
159+
auth_ids.push(AuthenticatedParticipantId::new(&participants).unwrap());
160+
}
161+
(participants, auth_ids)
162+
}
163+
148164
pub fn gen_seed() -> [u8; 32] {
149165
let mut rng = rand::thread_rng();
150166
let mut seed = [0u8; 32];

crates/contract/src/tee/verifier_votes.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -110,27 +110,13 @@ impl TeeVerifierVotes {
110110
#[expect(non_snake_case)]
111111
mod tests {
112112
use super::*;
113-
use crate::primitives::test_utils::gen_participants;
113+
use crate::primitives::test_utils::{gen_authenticated_participants, gen_participants};
114114
use mpc_primitives::Threshold;
115-
use near_sdk::{test_utils::VMContextBuilder, testing_env};
116115

117116
fn threshold_params(participants: &Participants, threshold: u64) -> ThresholdParameters {
118117
ThresholdParameters::new_unvalidated(participants.clone(), Threshold::new(threshold))
119118
}
120119

121-
/// Build `n` participants and pre-authenticate each.
122-
fn setup(n: usize) -> (Participants, Vec<AuthenticatedParticipantId>) {
123-
let participants = gen_participants(n);
124-
let mut auth_ids = Vec::with_capacity(n);
125-
for (account_id, _, _) in participants.participants() {
126-
let mut ctx = VMContextBuilder::new();
127-
ctx.signer_account_id(account_id.clone());
128-
testing_env!(ctx.build());
129-
auth_ids.push(AuthenticatedParticipantId::new(&participants).unwrap());
130-
}
131-
(participants, auth_ids)
132-
}
133-
134120
fn proposal(account: &str, hash_byte: u8) -> VerifierChangeProposal {
135121
VerifierChangeProposal {
136122
candidate_account_id: account.parse().unwrap(),
@@ -148,7 +134,7 @@ mod tests {
148134
Vec<AuthenticatedParticipantId>,
149135
TeeVerifierVotes,
150136
) {
151-
let (participants, voters) = setup(3);
137+
let (participants, voters) = gen_authenticated_participants(3);
152138
let params = threshold_params(&participants, threshold);
153139
(
154140
participants.clone(),

0 commit comments

Comments
 (0)