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

7.9 KiB
Raw Blame History

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

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

block_type:       u8 = 1
block_version:    u8 = 0
root_key:         [u8;32]

root_key — холодный recovery authority. Blockchain authority не может изменить root. Root authority может изменить root и остальные поля.

ClientKeyBlock

block_type:       u8 = 2
block_version:    u8 = 0
client_key:       [u8;32]

Client key не является authority PDA. Он может использоваться клиентским уровнем и как fee payer Solana-транзакции.

BlockchainRegistryBlock

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.

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

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.

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-инструкцию можно удалить из программы.