Files
SHiNE-server/shine-solana/shine/doc/programs/shine_login_guard.md
T

147 lines
5.9 KiB
Markdown

# Программа `shine_login_guard`
Документ описывает целевое поведение программы классификации логинов SHiNE.
Задача программы:
- по логину определить класс регистрации;
- вернуть результат в `return_data`;
- не хранить PDA и не вести собственное состояние.
## 1. Назначение
`shine_login_guard` — маленькая служебная программа, которую вызывает `shine_users` через CPI до регистрации пользователя.
Она отвечает только на вопрос:
- можно ли зарегистрировать логин автоматически;
- является ли логин premium;
- является ли логин trademark/company.
## 2. Program ID
Текущий program id:
- `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo`
## 3. Состояние
У программы нет PDA-состояний и persistent storage.
Она опирается на статически сгенерированные словари, встроенные в бинарник на этапе сборки.
## 4. Внешние артефакты
Словари хранятся в:
- `src/dictionaries/premium/**/*.txt`
- `src/dictionaries/trademarks/**/*.txt`
На этапе build:
- все `.txt` файлы рекурсивно собираются;
- слова нормализуются;
- дубль-слова детектятся и логируются как warning;
- итоговые массивы слов вшиваются в generated Rust file.
## 5. Нормализация словаря
Слово словаря считается валидным, если:
- не пустое;
- длина не больше `20`;
- содержит только ASCII-буквы и цифры;
- после `trim()` и `lowercase()` остаётся валидным.
Символ `_` в словарных словах не допускается.
## 6. Единственная инструкция
Инструкция:
- `classify_login(login: String)`
Бинарный ABI инструкции:
```text
- tag: u8 = 1
- login_len: u32 LE
- login_bytes[login_len]: UTF-8
```
Аккаунты:
- аккаунты не требуются
Подпись транзакции для самой классификации не имеет бизнес-смысла. Если вызов идёт через CPI из `shine_users`, программа `shine_login_guard` не требует signer-аккаунтов вообще.
## 7. Выходные классы
Программа возвращает `u32` через `set_return_data`:
- `0``CLASS_FREE`
- `1``CLASS_PREMIUM`
- `2``CLASS_TRADEMARK`
## 8. Правила нормализации логина
Перед классификацией логин нормализуется:
- пустой логин запрещён;
- длина исходного логина не больше `20`;
- символ `_` удаляется;
- остальные символы обязаны быть ASCII alnum;
- буквы приводятся к нижнему регистру.
Если нормализация не удалась:
- логин считается `CLASS_PREMIUM`.
Это намеренно жёсткое поведение: сомнительный логин не должен автоматически попадать в free-класс.
## 9. Правила классификации
Алгоритм:
1. Нормализовать логин.
2. Попробовать разрезать его на `1..3` слов из словарей.
3. Если среди найденных частей есть trademark-слово, вернуть `CLASS_TRADEMARK`.
4. Если есть только premium-слова, вернуть `CLASS_PREMIUM`.
5. Если словарное совпадение не найдено и длина нормализованного логина `<= 7`, вернуть `CLASS_PREMIUM`.
6. Иначе вернуть `CLASS_FREE`.
## 10. Разбиение на слова
Максимум слов в логине:
- `3`
Алгоритм разбиения:
- DFS/backtracking по префиксам строки;
- на каждом шаге берётся префикс длиной `1..20`;
- если префикс найден в premium или trademark словаре, поиск продолжается на остатке строки;
- если найден хотя бы один путь с trademark-словом, итог = `CLASS_TRADEMARK`;
- если найден путь только с premium-словами, итог = `CLASS_PREMIUM`.
## 11. Инварианты
Должно быть сохранено при переписи:
- тот же способ нормализации логина;
- та же семантика классов `0/1/2`;
- тот же лимит `MAX_WORDS_PER_LOGIN = 3`;
- тот же fallback `len <= 7 => premium`, если словарь ничего не нашёл;
- тот же порядок приоритета `TRADEMARK > PREMIUM > FREE`.
## 12. Что не обязано сохраниться при переписи
Можно менять без изменения бизнес-логики:
- build pipeline словарей;
- структуру хранения слов внутри бинарника;
- способ поиска слов, если сохраняется тот же результат;
- техническую форму возврата, если внешний контракт для `shine_users` останется совместимым.
Но если меняется именно интерфейс `return_data` или классы, это уже требует обновления `shine_users` и документации.