From 8ce804eb77946655755f4da51490bdc2e03dbc58 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Sat, 16 May 2026 15:33:20 +0300 Subject: [PATCH] shine_users: switch user record to v1.0 status-key layout and login<=25 --- SHINY_USER_FORMAT_V1_0_DRAFT.md | 2 +- shine/programs/shine_users/src/users.rs | 27 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/SHINY_USER_FORMAT_V1_0_DRAFT.md b/SHINY_USER_FORMAT_V1_0_DRAFT.md index e065528..746a860 100644 --- a/SHINY_USER_FORMAT_V1_0_DRAFT.md +++ b/SHINY_USER_FORMAT_V1_0_DRAFT.md @@ -69,7 +69,7 @@ 10. `login` Размер: `login_len` байт (UTF-8). Назначение: логин пользователя. - Текущие ограничения: от 1 до 20 символов, только `a-z`, `0-9`, `_`. + Текущие ограничения: от 1 до 25 символов, только `a-z`, `0-9`, `_`. 11. `root_key_status` Размер: 1 байт (`u8`). diff --git a/shine/programs/shine_users/src/users.rs b/shine/programs/shine_users/src/users.rs index 586a403..307d962 100644 --- a/shine/programs/shine_users/src/users.rs +++ b/shine/programs/shine_users/src/users.rs @@ -14,6 +14,7 @@ use std::str::FromStr; const MAGIC: &[u8; 5] = b"SHiNE"; const FORMAT_MAJOR: u8 = 1; const FORMAT_MINOR: u8 = 0; +const KEY_STATUS_CREATED: u8 = 0; const RESERVED_BYTES: [u8; 5] = [0, 0, 0, 0, 0]; const ZERO_HASH: [u8; 32] = [0; 32]; @@ -58,8 +59,11 @@ pub struct UserRecord { pub version: u32, pub prev_hash: [u8; 32], pub login: String, + pub root_key_status: u8, pub root_key: Pubkey, + pub blockchain_key_status: u8, pub blockchain_key: Pubkey, + pub device_key_status: u8, pub device_key: Pubkey, pub chain_number: u16, pub balance: u64, @@ -133,8 +137,11 @@ pub fn create_user_pda(ctx: Context, args: CreateUserPdaArgs) -> version: 0, prev_hash: ZERO_HASH, login: args.login.clone(), + root_key_status: KEY_STATUS_CREATED, root_key: args.root_key, + blockchain_key_status: KEY_STATUS_CREATED, blockchain_key: args.fields.blockchain_key, + device_key_status: KEY_STATUS_CREATED, device_key: args.fields.device_key, chain_number: args.fields.chain_number, balance: start_balance, @@ -226,6 +233,12 @@ pub fn update_user_pda(ctx: Context, args: UpdateUserPdaArgs) -> args.root_key, ErrCode::ImmutableFieldChanged ); + require!( + old_record.root_key_status == KEY_STATUS_CREATED + && old_record.blockchain_key_status == KEY_STATUS_CREATED + && old_record.device_key_status == KEY_STATUS_CREATED, + ErrCode::InvalidRecordData + ); require!( args.version == old_record.version.saturating_add(1), ErrCode::InvalidVersion @@ -250,8 +263,11 @@ pub fn update_user_pda(ctx: Context, args: UpdateUserPdaArgs) -> version: args.version, prev_hash: provided_prev_hash, login: old_record.login.clone(), + root_key_status: old_record.root_key_status, root_key: old_record.root_key, + blockchain_key_status: old_record.blockchain_key_status, blockchain_key: args.fields.blockchain_key, + device_key_status: old_record.device_key_status, device_key: args.fields.device_key, chain_number: args.fields.chain_number, balance: new_balance, @@ -320,8 +336,11 @@ fn serialize_unsigned_record(record: &UserRecord) -> Result> { out.push(login_bytes.len() as u8); out.extend_from_slice(login_bytes); + out.push(record.root_key_status); out.extend_from_slice(record.root_key.as_ref()); + out.push(record.blockchain_key_status); out.extend_from_slice(record.blockchain_key.as_ref()); + out.push(record.device_key_status); out.extend_from_slice(record.device_key.as_ref()); out.extend_from_slice(&record.chain_number.to_le_bytes()); @@ -384,8 +403,11 @@ fn deserialize_record_from_pda(raw: &[u8]) -> Result { let prev_hash = read_fixed_32(useful, &mut cursor)?; let login = read_len_prefixed_string(useful, &mut cursor)?; + let root_key_status = read_u8(useful, &mut cursor)?; let root_key = Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?); + let blockchain_key_status = read_u8(useful, &mut cursor)?; let blockchain_key = Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?); + let device_key_status = read_u8(useful, &mut cursor)?; let device_key = Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?); let chain_number = read_u16(useful, &mut cursor)?; @@ -423,8 +445,11 @@ fn deserialize_record_from_pda(raw: &[u8]) -> Result { version, prev_hash, login, + root_key_status, root_key, + blockchain_key_status, blockchain_key, + device_key_status, device_key, chain_number, balance, @@ -551,7 +576,7 @@ fn le_u16(data: &[u8], offset: usize) -> Result { fn validate_login(login: &str) -> Result<()> { require!(!login.is_empty(), ErrCode::InvalidLogin); - require!(login.len() <= 30, ErrCode::InvalidLogin); + require!(login.len() <= 25, ErrCode::InvalidLogin); for ch in login.chars() { if !(ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_') { return Err(error!(ErrCode::InvalidLogin));