# Solana `user_pda`: формат 1.2 Актуальный бинарный формат пользовательской PDA программы `shine_users`. Формат пользовательских SHiNE-блоков и Arweave этим изменением не меняется. ## Назначение PDA 1.2 хранит идентичность и authority пользователя, append-only историю blockchain keys, оплаченный лимит и маршрутизацию. Состояние вершины пользовательского blockchain в Solana больше не хранится. Из PDA 1.2 удалены `RecoveryKeyBlock`, `SessionsBlock`, `TrustedStateBlock`, `ArchiveHeadBlock`, `sync_servers[]`, а также старые `used_bytes`, `last_block_*`, `arweave_tx_id`, `blockchain_name/type`. ## Общие правила кодирования - Little Endian; - `Pubkey` — 32 байта; - Ed25519 signature — 64 байта; - hash — 32 байта; - строка — `len:u8 + UTF-8 bytes`; - `block_type:u8 + block_version:u8` есть у каждого typed block; - фиксированные `RootKeyBlock` и `ClientKeyBlock` не содержат длину; - любой variable block: `block_type:u8 + block_version:u8 + payload_len:u16 + payload`; - неизвестный variable block можно пропустить по `payload_len`. Все известные блоки PDA 1.2 имеют `block_version = 0`. ## Header ```text magic: [u8;5] = "SHiNE" format_major: u8 = 1 format_minor: u8 = 2 record_len: u16 created_at_ms: u64 updated_at_ms: u64 record_number: u32 prev_record_hash: [u8;32] login_len: u8 login: [u8;login_len] blocks_count: u8 blocks: TypedBlock[blocks_count] signature: [u8;64] ``` `record_len` включает подпись и не включает padding Solana account. `record_number=0` на create и увеличивается программой на 1 после каждого успешного update. `prev_record_hash=0` на create; при update это hash unsigned-части предыдущей PDA. ## Типы блоков | type | блок | статус | |---:|---|---| | 1 | `RootKeyBlock` | обязательный | | 2 | `ClientKeyBlock` | обязательный | | 3 | `BlockchainRegistryBlock` | обязательный | | 30 | `ServerProfileBlock` | опциональный | | 40 | `AccessServersBlock` | опциональный | ## RootKeyBlock ```text block_type: u8 = 1 block_version: u8 = 0 root_key: [u8;32] ``` `root_key` — холодный recovery authority. Blockchain authority не может изменить root. Root authority может изменить root и остальные поля. ## ClientKeyBlock ```text block_type: u8 = 2 block_version: u8 = 0 client_key: [u8;32] ``` Client key не является authority PDA. Он может использоваться клиентским уровнем и как fee payer Solana-транзакции. ## BlockchainRegistryBlock ```text block_type: u8 = 3 block_version: u8 = 0 payload_len: u16 fork_count: u16 forks[fork_count]: blockchain_key: [u8;32] created_at_ms: u64 paid_limit_bytes: u32 ``` Одна fork-запись занимает 44 байта. Правила: - `fork_count >= 1`; - последний fork — активный; - старые fork-записи append-only: их нельзя удалить, переставить или изменить; - один blockchain key нельзя добавить повторно; - `paid_limit_bytes` старых fork неизменяем; - лимит можно пополнять только у последнего fork; - новый fork наследует текущий лимит плюс оплаченный top-up; - обычный blockchain authority может создать новый fork не раньше чем через 72 часа после `created_at_ms` активного fork; - root recovery может создать fork без 72-часового ожидания. `created_at_ms` передаёт клиент и включает в подписываемую PDA. Программа принимает его только если он отличается от Solana Clock не более чем на ±5 минут. ## ServerProfileBlock Блок отсутствует у обычного пользователя. Наличие блока означает, что PDA публикует SHiNE-server endpoint. ```text block_type: u8 = 30 block_version: u8 = 0 payload_len: u16 address_count: u8 addresses[address_count]: address_format_type: u8 address_format_version: u8 address_len: u8 address: [u8;address_len] ``` PDA 1.2 разрешает **ровно один адрес**, если `ServerProfileBlock` присутствует. Массив/count сохранён для будущего увеличения лимита без изменения бинарной структуры. `address_format_type + address_format_version` позволяют позже стандартизовать URL, IPv4, IPv6, Tor/I2P и другие адресные форматы. ## AccessServersBlock ```text block_type: u8 = 40 block_version: u8 = 0 payload_len: u16 server_count: u8 servers[server_count]: login_len: u8 login: [u8;login_len] ``` PDA 1.2 разрешает `server_count = 0` или `1`. Count оставлен для будущего расширения. ## Authority и подпись Новая PDA хранит `signature[64]` authority **нового состояния** по hash unsigned PDA: - обычный update — активный blockchain key; - новый fork — новый blockchain key; - root-mode — root нового состояния; - смена root — новый root. На update программа дополнительно требует Ed25519-подпись authority предыдущего состояния по тому же hash нового unsigned state. Эта transition-подпись не хранится внутри PDA. Blockchain-mode не может изменить root. Root-mode может изменить root и выполнить recovery. Одновременно менять root и добавлять blockchain fork одной транзакцией запрещено. ## Create Создаются только PDA 1.2. ```text record_number = 0 prev_record_hash = 0x00 * 32 fork_count = 1 fork[0].blockchain_key = initial blockchain key fork[0].created_at_ms = created_at_ms fork[0].paid_limit_bytes = start_bonus + paid top-up ``` Root доказывает владение recovery-key отдельной Ed25519 instruction, а `signature[64]` новой PDA делает initial blockchain key. ## Legacy 1.0 Нормальные create/update/read flows нового клиента и сервера поддерживают только PDA 1.2. Временно существует instruction `close_legacy_pda` для тестовых PDA 1.0. Она: - принимает только PDA с `format_major=1`, `format_minor=0`; - не может закрыть 1.2; - закрывает старый program-owned account; - переводит его lamports вызывающему signer. Legacy migration в 1.2 отсутствует. После удаления тестовых PDA временную close-инструкцию можно удалить из программы.