Files
SHiNE-server/shine-solana/shine/doc/formats/shine-user-pda-format-v.1.2.md
T

185 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-инструкцию можно удалить из программы.