fix(client)!: Request(Dictionary) отправляет api_version, а не ApiVersion - #99
Conversation
…sion
Словарный путь клеймил версию под nameof(ApiVersion), то есть буквально
"ApiVersion". Словарь сериализуется дословно, а rippled знает только
api_version: незнакомые поля он игнорирует и отвечает по своей версии по
умолчанию, то есть по v1.
Замер на mainnet показывает, что три написания не равнозначны: "api_version":2
даёт форму v2, а "ApiVersion":2 и полное отсутствие поля — одинаково v1. То
есть client.AccountInfo(...) уходил по v2, а client.Request({command:
account_info}) у того же клиента — по v1, и формы ответов расходились без
всякого сигнала. Типизированный путь был исправен всегда: BaseRequest.ApiVersion
помечен [JsonPropertyName("api_version")].
Теперь ключ — имя с провода, а версия, заданная вызывающим в самом словаре,
по-прежнему уважается. Мусорное поле "ApiVersion" больше не едет в каждом
запросе. Заодно убраны двойные скобки и неиспользуемый out var value.
TestURequestApiVersion читает то, что клиент реально кладёт на провод, через
сервер-перехватчик: поле, которое узел игнорирует, из ответа не видно, и именно
поэтому дефект прожил так долго. Чтобы не плодить третью копию разбора
клиентских фреймов, ReadTextFrameAsync поднят из PagedResponseServer в общий
WebSocketTestServerBase.
BREAKING CHANGE: вызывающие нетипизированный путь переезжают с API v1 на
значение ApiVersion, а оно по умолчанию 2 — формы ответов меняются под кодом,
который сам не менялся. Это и есть починка: прежнее поведение игнорировало
настройку целиком. Кому нужна v1 — задают ["api_version"] = 1 в словаре или
ApiVersion на клиенте.
Closes #97
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
Included review availability: 3 reviews are currently available. Based on recent review activity, included reviews refill at 4 per hour. 📝 WalkthroughWalkthroughThe change corrects ChangesAPI version propagation and WebSocket test support
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to The change corrects the request version field while preserving explicit caller overrides, with no actionable merge-blocking risk remaining after normal checks and review. Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Закрывает #97.
Дефект
IXrplClient.Request(Dictionary<string, object>)клеймил версию под ключомnameof(ApiVersion)— буквально"ApiVersion". Словарь сериализуется дословно, а rippled знает толькоapi_version: незнакомые поля он игнорирует и отвечает по своей версии по умолчанию.Три написания, замеренные на mainnet, не равнозначны:
Написание с большой буквы неотличимо от полного отсутствия поля. Следствие:
client.AccountInfo(…)уходил по v2, аclient.Request(new Dictionary { ["command"] = "account_info" })у того же клиента — по v1, формы ответов расходились, и ничто об этом не сигналило. Типизированный путь был исправен всегда —BaseRequest.ApiVersionпомечен[JsonPropertyName("api_version")].Доказательство на одном клиенте, дискриминатор — версия, которую узел заведомо не умеет:
Правка
Ключ — имя с провода. Версия, заданная вызывающим прямо в словаре, по-прежнему уважается. Мусорное поле
"ApiVersion"больше не едет в каждом запросе. Заодно убраны двойные скобки и неиспользуемыйout var value.Слом контракта
Выбран первый из трёх вариантов, описанных в #97. Вызывающие нетипизированный путь переезжают с API v1 на значение
ApiVersion, а оно по умолчанию 2 — формы ответов меняются под кодом, который сам не менялся. Это и есть починка, а не побочный эффект: прежнее поведение игнорировало настройку целиком, так что «работает как раньше» здесь означает «настройка не работает». Кому нужна v1 — задают["api_version"] = 1в словаре илиApiVersionна клиенте.Внутри репозитория словарный путь используют только тесты и демо-консоль (
ledger_accept,server_info, бенчмаркledger_data); боевой код SDK на нём не завязан.Тесты
TestURequestApiVersionчитает то, что клиент реально кладёт на провод, через сервер-перехватчик запросов. Это принципиально: поле, которое узел игнорирует, из ответа не видно — именно поэтому дефект прожил так долго и не ловился ни одним существующим тестом. Написаны до правки, падали все три; в сообщении об ошибке был виден сам провод:{"command":"ledger_current","ApiVersion":2,"id":"…"}.Пинуется: имя поля на нетипизированном пути, что явный
api_versionот вызывающего не перезаписывается, и что оба пути одного клиента несут одну версию.Отдельно отмечу пойманную ошибку в собственном тесте: первый вариант третьего теста проходил по неверной причине — я разводил пути по имени команды
server_info, аConnect()сам шлёт типизированныйserver_infoи подменял собой словарный запрос. Переписан на отдельную команду для словарного пути.Чтобы не заводить третью копию разбора клиентских фреймов,
ReadTextFrameAsyncподнят изPagedResponseServerв общийWebSocketTestServerBase.Проверки
.ci-config/docker-compose.ci.yml, xrpld 3.3.0): 265 / 265, ноль пропусковИнтеграционные здесь не формальность, а проверка главного риска правки: словарный путь в тестах и демо теперь ходит по v2, и если бы какая-то команда отвечала в v2 иначе, чем ожидают модели, это вылезло бы именно там.
Версия остаётся 10.12.0.0 — она ещё не уехала в
release, запись добавлена в ту же секцию.Summary by CodeRabbit
Bug Fixes
Tests