mirror of
https://gitlab.com/pezkuwichain/pezkuwi-sdk.git
synced 2026-10-30 15:39:53 +00:00
- taplo.toml: add .cargo/** to exclude list (prevents scanning cached registry files) - deny.toml: reformat with taplo (tab indentation, proper spacing) - pezpallets: add Apache-2.0 SPDX license header to 51 files missing headers (referral, trust, perwerde, pez-treasury, pez-rewards, welati, token-wrapper, messaging, staking-score, presale, identity-kyc) - ci: check-zepter: prepend $HOME/.cargo/bin to PATH after cargo install so newly installed 1.82.1 takes precedence over system 1.78.2 - identity-kyc: fix clippy::needless_borrows_for_generic_args at lib.rs:326
386 lines
9.7 KiB
Rust
386 lines
9.7 KiB
Rust
// 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<u8> {
|
|
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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::get(era, 2u64).len(), 1);
|
|
|
|
// Acknowledge
|
|
assert_ok!(Messaging::acknowledge_messages(RuntimeOrigin::signed(2)));
|
|
assert_eq!(Inbox::<Test>::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);
|
|
});
|
|
}
|