The participants storage system provides a robust map-based storage solution for managing participant records in the Scavngr smart contract. It ensures data integrity, prevents duplicate registrations, and provides efficient access to participant information.
Key: (Address,) → ParticipantParticipants are stored using their address as the key, enabling O(1) lookup performance.
pub fn register_participant(
env: Env,
address: Address,
role: ParticipantRole,
) -> ParticipantRegisters a new participant with the specified role.
Features:
- Requires authentication from the registering address
- Prevents duplicate registrations
- Records registration timestamp
- Returns the created Participant struct
Panics:
- If participant is already registered
Example:
let participant = client.register_participant(
&user_address,
&ParticipantRole::Recycler
);pub fn is_participant_registered(env: Env, address: Address) -> boolChecks if an address is registered as a participant.
Returns: true if registered, false otherwise
fn set_participant(env: &Env, address: &Address, participant: &Participant)Internal helper function for storing participant records efficiently.
Features:
- Encapsulates storage key logic
- Used by registration and update functions
- Ensures consistent storage patterns
pub fn get_participant(env: Env, address: Address) -> Option<Participant>Retrieves participant information by address.
Returns: Some(Participant) if found, None otherwise
pub fn update_role(
env: Env,
address: Address,
new_role: ParticipantRole
) -> ParticipantUpdates a participant's role while preserving other data.
Features:
- Requires authentication from the participant
- Preserves registration timestamp
- Validates participant exists before update
Panics:
- If participant not found
The system prevents duplicate registrations by checking existence before creating new records:
if Self::is_participant_registered(env.clone(), address.clone()) {
panic!("Participant already registered");
}Updates preserve critical data like registration timestamps:
// Original registration_at is maintained
participant.role = new_role;
Self::set_participant(&env, &address, &participant);// Register a recycler
let recycler = client.register_participant(
&recycler_address,
&ParticipantRole::Recycler
);
// Check registration status
let is_registered = client.is_participant_registered(&recycler_address);
assert!(is_registered);
// Retrieve participant info
let participant = client.get_participant(&recycler_address).unwrap();
assert_eq!(participant.role, ParticipantRole::Recycler);// Update role from Recycler to Collector
let updated = client.update_role(
&user_address,
&ParticipantRole::Collector
);
assert_eq!(updated.role, ParticipantRole::Collector);
// registration_at remains unchanged// Check if user can collect materials
let can_collect = client.can_collect(&user_address);
// Check if user can manufacture
let can_manufacture = client.can_manufacture(&user_address);- Registration: O(1) - Single storage write
- Lookup: O(1) - Direct key access
- Update: O(1) - Single storage read + write
- Existence Check: O(1) - Storage has() operation
- Authentication Required: All write operations require address authentication
- Duplicate Prevention: System prevents multiple registrations for same address
- Data Validation: Role updates validate participant existence
- Immutable History: Registration timestamps cannot be modified
The implementation includes comprehensive tests:
test_register_participant- Basic registrationtest_register_participant_duplicate- Duplicate preventiontest_is_participant_registered- Registration checkstest_get_participant- Data retrievaltest_update_role- Role updatestest_all_role_types- All role variants
Participants must be registered to submit materials:
// Participant registration is checked during transfers
if !Self::is_participant_registered(env.clone(), address.clone()) {
panic!("Participant not registered");
}Only recyclers can verify materials:
let participant = Self::get_participant(env.clone(), verifier.clone())
.expect("Verifier not registered");
if !participant.role.can_process_recyclables() {
panic!("Only recyclers can verify materials");
}Both sender and receiver must be registered:
if !Self::is_participant_registered(env.clone(), from.clone()) {
panic!("Sender not registered");
}
if !Self::is_participant_registered(env.clone(), to.clone()) {
panic!("Receiver not registered");
}Potential improvements for future versions:
- Batch Operations: Register multiple participants in one transaction
- Role History: Track role changes over time
- Participant Metadata: Add optional profile information
- Deactivation: Soft-delete functionality for inactive participants
- Indexing: Efficient queries by role type