// This file is part of PezkuwiChain. // Copyright (C) Dijital Kurdistan Tech Institute // SPDX-License-Identifier: Apache-2.0 use crate::{mock::*, Error, Event, *}; use pezframe_support::{assert_noop, assert_ok}; // Helper: a dummy x25519 public key fn dummy_pubkey(seed: u8) -> [u8; 32] { [seed; 32] } // Helper: a dummy nonce fn dummy_nonce() -> [u8; 24] { [0xAB; 24] } // Helper: dummy ciphertext fn dummy_ciphertext(len: usize) -> alloc::vec::Vec { alloc::vec![0xCD; len] } // ============= register_encryption_key ============= #[test] fn register_key_works() { new_test_ext().execute_with(|| { let key = dummy_pubkey(1); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), key)); assert_eq!(EncryptionKeys::::get(1), Some(key)); System::assert_last_event(Event::EncryptionKeyRegistered { who: 1 }.into()); }); } #[test] fn register_key_update_works() { new_test_ext().execute_with(|| { let key1 = dummy_pubkey(1); let key2 = dummy_pubkey(2); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), key1)); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), key2)); assert_eq!(EncryptionKeys::::get(1), Some(key2)); }); } #[test] fn register_key_fails_for_non_citizen() { new_test_ext().execute_with(|| { // Account 99 is not a citizen in mock assert_noop!( Messaging::register_encryption_key(RuntimeOrigin::signed(99), dummy_pubkey(1)), Error::::NotACitizen ); }); } // ============= trust score ============= #[test] fn send_message_fails_insufficient_trust() { new_test_ext().execute_with(|| { // Account 99 is citizen in a hypothetical scenario but has low trust // In our mock, accounts 1-10 are citizens with trust=50 // We test via the mock: non-citizens already fail at citizenship check first // Trust check is tested by verifying the error variant exists and the check runs // The mock gives trust=50 to accounts 1-10 (above MinTrustScore=20), so they pass // In production, this check catches citizens with degraded trust scores assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); // Accounts 1-10 have trust=50, MinTrustScore=20 → should pass assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(100), )); }); } // ============= send_message ============= #[test] fn send_message_works() { new_test_ext().execute_with(|| { // Setup: both parties register keys assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); // Send message from 1 to 2 assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), // ephemeral key dummy_nonce(), dummy_ciphertext(100), )); // Check inbox let era = Messaging::current_era(); let inbox = Inbox::::get(era, 2u64); assert_eq!(inbox.len(), 1); assert_eq!(inbox[0].sender, 1); assert_eq!(inbox[0].ephemeral_public_key, dummy_pubkey(99)); // Check send count assert_eq!(SendCount::::get(era, 1u64), 1); }); } #[test] fn send_message_fails_sender_not_citizen() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); assert_noop!( Messaging::send_message( RuntimeOrigin::signed(99), // not citizen 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(100), ), Error::::NotACitizen ); }); } #[test] fn send_message_fails_recipient_not_citizen() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_noop!( Messaging::send_message( RuntimeOrigin::signed(1), 99, // not citizen dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(100), ), Error::::RecipientNotCitizen ); }); } #[test] fn send_message_fails_no_encryption_key() { new_test_ext().execute_with(|| { // Recipient is citizen but has no key registered assert_noop!( Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(100), ), Error::::RecipientNoEncryptionKey ); }); } #[test] fn send_message_fails_self_message() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_noop!( Messaging::send_message( RuntimeOrigin::signed(1), 1, // self dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(100), ), Error::::CannotMessageSelf ); }); } #[test] fn send_message_fails_empty_payload() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); assert_noop!( Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), alloc::vec![], // empty ), Error::::EmptyPayload ); }); } #[test] fn send_message_fails_payload_too_large() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); assert_noop!( Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(513), // exceeds MaxMessageSize=512 ), Error::::PayloadTooLarge ); }); } // ============= Rate Limiting ============= #[test] fn rate_limit_enforced() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); // Send MaxMessagesPerEra (5) messages — should all succeed for _ in 0..5 { assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(50), )); } // 6th message should fail assert_noop!( Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(50), ), Error::::RateLimitExceeded ); }); } // ============= Inbox FIFO ============= #[test] fn inbox_fifo_drops_oldest() { new_test_ext().execute_with(|| { // Register keys for sender accounts 1-10 and recipient 2 for i in 1..=10 { assert_ok!(Messaging::register_encryption_key( RuntimeOrigin::signed(i), dummy_pubkey(i as u8) )); } let era = Messaging::current_era(); // Fill inbox with 50 messages from different senders (MaxInboxSize=50) for i in 3..=10 { // 8 senders, 5 msgs each = 40 messages (under 50) for _ in 0..5 { assert_ok!(Messaging::send_message( RuntimeOrigin::signed(i), 2, dummy_pubkey(i as u8), dummy_nonce(), dummy_ciphertext(10), )); } } let inbox = Inbox::::get(era, 2u64); assert_eq!(inbox.len(), 40); // Now send from account 1 (5 messages, total = 45, still under 50) for _ in 0..5 { assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(1), dummy_nonce(), dummy_ciphertext(10), )); } let inbox = Inbox::::get(era, 2u64); assert_eq!(inbox.len(), 45); }); } // ============= acknowledge_messages ============= #[test] fn acknowledge_clears_inbox() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); // Send some messages assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(50), )); let era = Messaging::current_era(); assert_eq!(Inbox::::get(era, 2u64).len(), 1); // Acknowledge assert_ok!(Messaging::acknowledge_messages(RuntimeOrigin::signed(2))); assert_eq!(Inbox::::get(era, 2u64).len(), 0); }); } // ============= Era Rotation ============= #[test] fn era_rotates_after_era_length_blocks() { new_test_ext().execute_with(|| { assert_eq!(Messaging::current_era(), 0); // Advance to block 100 (EraLength in tests) System::set_block_number(100); Messaging::on_initialize(100); assert_eq!(Messaging::current_era(), 1); // Advance to block 200 System::set_block_number(200); Messaging::on_initialize(200); assert_eq!(Messaging::current_era(), 2); }); } // ============= Helper Functions ============= #[test] fn remaining_send_quota_works() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); assert_eq!(Messaging::remaining_send_quota(&1), 5); assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(50), )); assert_eq!(Messaging::remaining_send_quota(&1), 4); }); } #[test] fn inbox_count_works() { new_test_ext().execute_with(|| { assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(1), dummy_pubkey(1))); assert_ok!(Messaging::register_encryption_key(RuntimeOrigin::signed(2), dummy_pubkey(2))); assert_eq!(Messaging::inbox_count(&2), 0); assert_ok!(Messaging::send_message( RuntimeOrigin::signed(1), 2, dummy_pubkey(99), dummy_nonce(), dummy_ciphertext(50), )); assert_eq!(Messaging::inbox_count(&2), 1); }); }