Skip to content

feat(models)!: гвард полей ledger-объектов и чистка моделей по ledger_entries.macro (10.11.0.0) - #75

Merged
Platonenkov merged 3 commits into
devfrom
claude/ledger-entry-fields-guard-778740
Aug 4, 2026
Merged

feat(models)!: гвард полей ledger-объектов и чистка моделей по ledger_entries.macro (10.11.0.0)#75
Platonenkov merged 3 commits into
devfrom
claude/ledger-entry-fields-guard-778740

Conversation

@Platonenkov

@Platonenkov Platonenkov commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Зачем

Третья и последняя поверхность конформанса. TestUTxFormatConformance держит поля транзакций, TestULedgerFlagsConformance (из #71) — флаги ledger-объектов, а поля самих объектов не проверял никто. ledger_entries.macro — единственное место, где протокол объявляет состав объекта: definitions.json несёт коды полей и типы объектов, но не пофайловые списки.

Пропущенное поле симптома не даёт — чтение объекта проходит, значение молча теряется. Именно так LOAccountRoot жил без WalletLocator/WalletSize до ручного completeness-прохода, и так же sfLEVersion пришлось ловить уведомлением protocol-watch вместо красного теста.

Гвард

  • Tests/Xrpl.Tests/Fixtures/ledger_entries.macro, вендорен байт-в-байт, пин по sha в .ref. Пин на develop-коммит, а не на тег — в отличие от LedgerFormats.h: по полям модели следуют develop, и sfLEVersion существует только после 30.07, так что тег объявил бы его выдумкой SDK.
  • Диф в обе стороны + обязательная регистрация каждого объекта: новый ledger-объект роняет сборку, а не проезжает молча.
  • Четыре common-поля rippled (LedgerIndex, LedgerEntryType, Flags, Sponsor из LedgerFormats::getCommonFields()) исключены с обеих сторон — ровно как TxFormat-гвард обходится с commonFields. [JsonIgnore]-свойства (вычисляемые хелперы DataParsed, MPTokenMetadataRow) на провод не попадают и тоже исключены.
  • Проверен мутацией: переименование JsonPropertyName даёт обе половины отчёта — Loan.Borrower … missing from LOLoan и LOLoan.BorrowerX … not a field of Loan.

Удалены свойства, которых нет в протоколе (breaking)

Без [Obsolete] — как при удалении инертных ConnectionOptions в 10.10.0.0. Держать значение они не могли: rippled собирает объект по фиксированному SOTemplate, поле вне шаблона в него не попадает.

Проверено двумя независимыми способами: на живой ноде (nightly, 3.3.0-b1) и кросс-версионно по четырём точкам — 3.2.1 (мейннет), 3.3.0-b1, 3.3.0-rc1 (то, что выйдет) и develop. Нет ни в одной, включая невышедшую.

свойство доказательство
LOVault.DomainID positive control: VaultCreate с Data, AssetsMaximum и DomainID прошёл; первые два вернулись на объекте, DomainID — нет, и обнаружился на связанном share-MPTokenIssuance. Ровно как гласят комментарий в макросе (no PermissionedDomainID ever (use MPTIssuance.sfDomainID)) и код VaultCreate.cpp (.domainId = tx[~sfDomainID])
LOLoan.PrincipalRequested поле транзакции LoanSet; настоящий займ, созданный с PrincipalRequested = 10000000, хранит сумму как PrincipalOutstanding, самого поля у объекта нет
LOCredential.OwnerNode у объекта IssuerNode/SubjectNode — он висит в двух директориях. Нулевые hint'ы сериализуются (объект Loan вернул "OwnerNode":"0"), так что отсутствие настоящее, а не опущенный дефолт
LONFTokenPage.NFTokenPage объект состоит из NFTokens, PreviousPageMin, NextPageMin, PreviousTxn*
LOAmm.LedgerCurrentIndex, LOAmm.Validated принадлежат конверту ответа amm_info (ledger_current_index, validated, snake_case), а не объекту; LOAmm десериализуется только как ledger-объект, у amm_info своя модель AMMInfo

Positive control здесь принципиален: без него «поля не было в ответе» означало бы лишь «поле не заполнено» — SoeDefault/SoeOptional с пустым значением нода не сериализует вовсе.

Починено в LOAmm

  • AMMAccount никогда не десериализовался: поле объекта называется Account, а атрибута [JsonPropertyName] не было — свойство молча оставалось null на каждом прочитанном AMM. Теперь замаплено на Account; имя свойства не менялось, вызовы не ломаются.
  • Конструктор ставил LedgerEntryType = LedgerEntryType.AccountRoot — объект AMM представлялся AccountRoot'ом. Теперь LedgerEntryType.AMM.

Добавлены отсутствовавшие поля

PreviousTxnID и PreviousTxnLgrSeq в LOAmm, LOAmendments, LODirectoryNode, LOFeeSettings, LONegativeUNL — все SoeOptional в протоколе. Без них нельзя было прочитать через типизированный API, какая транзакция последней тронула объект.

Проверка

Прогон Результат
Юнит-тесты 879/879 passed
nightly-стенд: TestILoan|TestIVault|TestICredential|TestINFToken|TestIAmm 64/64 passed
Сборка решения 0 ошибок

Интеграцию гонял намеренно по всем затронутым моделям: удаление свойств и добавление PreviousTxn* меняет десериализацию, и это стоило проверить на живых объектах.

Версия

Все накопившиеся в dev изменения выпускаются одним номером — 10.11.0.0. На NuGet последняя опубликованная Xrpl — 10.10.0, поэтому 10.10.1.0 (фикс OnConnected), 10.11.0.0 (флаги ledger-объектов, гвард по LedgerFormats.h, DynamicMPT, sfLEVersion) и 10.12.0.0 (этот PR) существовали только в ветке и наружу не уходили. Три раздела CHANGES.md слиты в один, версия пакета откачена с 10.12.0.0 до 10.11.0.0 — потребитель получает один релиз вместо трёх номеров, два из которых никогда не были артефактами.

Xrpl.BinaryCodec уже стоял на 10.11.0.0, так что после схлопывания совпадает с Xrpl ровно, как и задумывалось при выравнивании. Xrpl.AddressCodec и Xrpl.Keypairs не менялись и остаются на 10.9.0.0.

Summary by CodeRabbit

  • New Features

    • Added missing ledger metadata fields for improved ledger-entry responses.
    • Corrected AMM ledger-entry deserialization and type identification.
  • Bug Fixes

    • Removed invalid or obsolete ledger-object properties.
    • Corrected loan, credential, NFT page, and vault field definitions.
    • Improved ledger-entry field conformance validation against the XRPL protocol.
  • Documentation

    • Added release notes for version 10.11.0.0 and updated prior release headings.

…_entries.macro

Третья и последняя поверхность конформанса: TestUTxFormatConformance держит
поля транзакций, TestULedgerFlagsConformance — флаги ledger-объектов, а поля
самих объектов не проверял никто. ledger_entries.macro — единственное место,
где протокол объявляет состав объекта (definitions.json несёт коды полей и
типы, но не списки), и пропущенное поле симптома не даёт: чтение объекта
проходит, значение просто теряется.

Гвард:
* вендоренный Fixtures/ledger_entries.macro с пином по sha. Пин на develop,
  а не на тег (в отличие от LedgerFormats.h): модели по полям следуют develop,
  и sfLEVersion существует только после 30.07 — тег объявил бы его выдумкой SDK
* диф в обе стороны + обязательная регистрация каждого объекта, поэтому новый
  ledger-объект роняет сборку, а не пропускается
* четыре common-поля rippled (LedgerIndex, LedgerEntryType, Flags, Sponsor из
  LedgerFormats::getCommonFields()) исключаются с обеих сторон, как это уже
  сделано для commonFields в TxFormat-гварде; [JsonIgnore]-свойства не в счёт
* проверен мутацией: переименование JsonPropertyName даёт обе половины отчёта

Удалены свойства, которых нет в протоколе (BREAKING, без [Obsolete] — как при
удалении инертных ConnectionOptions в 10.10.0.0). Значение они держать не могли:
объект собирается по фиксированному SOTemplate. Проверено и на живой ноде, и по
четырём версиям (3.2.1, 3.3.0-b1, 3.3.0-rc1, develop) — нет нигде:
* LOVault.DomainID — positive control: VaultCreate с Data, AssetsMaximum и
  DomainID прошёл, первые два вернулись на объекте, DomainID — нет, он уехал
  на связанный share MPTokenIssuance
* LOLoan.PrincipalRequested — поле транзакции LoanSet; реальный займ хранит
  сумму как PrincipalOutstanding
* LOCredential.OwnerNode — у объекта IssuerNode/SubjectNode; нулевые hint'ы
  сериализуются ("OwnerNode":"0" у Loan), так что отсутствие настоящее
* LONFTokenPage.NFTokenPage, LOAmm.LedgerCurrentIndex, LOAmm.Validated —
  последние два принадлежат конверту ответа amm_info (snake_case)

Починено в LOAmm:
* AMMAccount никогда не десериализовался — поле объекта называется Account,
  а атрибута не было; имя свойства не меняется, вызовы не ломаются
* конструктор ставил LedgerEntryType.AccountRoot вместо AMM

Добавлены PreviousTxnID/PreviousTxnLgrSeq в LOAmm, LOAmendments,
LODirectoryNode, LOFeeSettings, LONegativeUNL.

Xrpl 10.11.0.0 -> 10.12.0.0. Xrpl.BinaryCodec не менялся и остаётся 10.11.0.0.

Проверено: юнит-тесты 879/879; на nightly-стенде TestILoan/TestIVault/
TestICredential/TestINFToken/TestIAmm — 64/64; сборка решения без ошибок.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d28677c7-8fc9-4adc-8691-43a1715b7070

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

…0.0 в один 10.11.0.0

На NuGet последняя опубликованная версия Xrpl — 10.10.0. Значит 10.10.1.0
(фикс OnConnected), 10.11.0.0 (флаги ledger-объектов, гвард по LedgerFormats.h,
DynamicMPT, sfLEVersion) и 10.12.0.0 (гвард полей ledger-объектов и чистка
моделей) существуют только в dev и ни один из номеров наружу не уходил.

Три раздела CHANGES.md слиты в один 10.11.0.0 от 08/04/2026, версия пакета
Xrpl откачена с 10.12.0.0 на 10.11.0.0. Потребитель получит один релиз вместо
трёх номеров, из которых два никогда не существовали как артефакты.

Xrpl.BinaryCodec уже стоял на 10.11.0.0 — после схлопывания он совпадает с Xrpl
ровно, как и задумывалось при выравнивании. AddressCodec и Keypairs остаются
на 10.9.0.0: они не менялись.

Проверено: сборка решения без ошибок, юнит-тесты 879/879.
@Platonenkov Platonenkov changed the title feat(models)!: гвард полей ledger-объектов и чистка моделей по ledger_entries.macro (10.12.0.0) feat(models)!: гвард полей ledger-объектов и чистка моделей по ledger_entries.macro (10.11.0.0) Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
Xrpl/Models/Ledger/LONegativeUNL.cs (1)

32-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider the short attribute form for consistency with the sibling models.

LOAmendments, LODirectoryNode, LOFeeSettings, and LOAmm all use [JsonPropertyName("...")]. This file uses the fully qualified form. The fully qualified form compiles either way, so this is style only. If using System.Text.Json.Serialization; is already present in this file, shorten both attributes.

♻️ Proposed alignment
-        [System.Text.Json.Serialization.JsonPropertyName("PreviousTxnID")]
+        [JsonPropertyName("PreviousTxnID")]
         public string PreviousTxnID { get; set; }
 
         /// <summary>
         /// The index of the ledger that contains the transaction that most recently modified this object.
         /// </summary>
-        [System.Text.Json.Serialization.JsonPropertyName("PreviousTxnLgrSeq")]
+        [JsonPropertyName("PreviousTxnLgrSeq")]
         public uint? PreviousTxnLgrSeq { get; set; }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Ledger/LONegativeUNL.cs` around lines 32 - 39, Use the imported
JsonPropertyName symbol in both attributes on PreviousTxnID and
PreviousTxnLgrSeq within the LONegativeUNL model, replacing the fully qualified
System.Text.Json.Serialization.JsonPropertyName form while preserving the
property names and behavior.
Tests/Xrpl.Tests/Models/RippledLedgerEntryFormats.cs (1)

131-132: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider failing on a duplicate ledger-object name instead of overwriting.

Line 131 uses indexer assignment. If two blocks ever declare the same object name, the second silently replaces the first, and that object leaves the conformance table. Line 132 still counts both field sets, so the minimum-count guard at Line 135 does not detect the loss. No duplicate name exists in the current fixture, so this is forward-looking only.

♻️ Proposed guard
-                entries[name] = fields;
+                if (entries.ContainsKey(name))
+                {
+                    throw new InvalidOperationException(
+                        $"{name}: declared twice in ledger_entries.macro — the parser would drop one " +
+                        "definition, update it before trusting this test");
+                }
+
+                entries.Add(name, fields);
                 fieldCount += fields.Count;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Models/RippledLedgerEntryFormats.cs` around lines 131 - 132,
Update the ledger-entry aggregation around the entries assignment to detect
duplicate object names before inserting into entries, and fail immediately
instead of overwriting the existing fields. Keep fieldCount updates only for
successfully unique entries so duplicate declarations cannot inflate the count
while removing an object from the conformance table.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Tests/Xrpl.Tests/Models/RippledLedgerEntryFormats.cs`:
- Around line 131-132: Update the ledger-entry aggregation around the entries
assignment to detect duplicate object names before inserting into entries, and
fail immediately instead of overwriting the existing fields. Keep fieldCount
updates only for successfully unique entries so duplicate declarations cannot
inflate the count while removing an object from the conformance table.

In `@Xrpl/Models/Ledger/LONegativeUNL.cs`:
- Around line 32-39: Use the imported JsonPropertyName symbol in both attributes
on PreviousTxnID and PreviousTxnLgrSeq within the LONegativeUNL model, replacing
the fully qualified System.Text.Json.Serialization.JsonPropertyName form while
preserving the property names and behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1ab48fae-be1b-4882-801d-dec94ebca4c8

📥 Commits

Reviewing files that changed from the base of the PR and between 7639041 and 2bab0af.

📒 Files selected for processing (16)
  • CHANGES.md
  • Tests/Xrpl.Tests/Fixtures/ledger_entries.macro
  • Tests/Xrpl.Tests/Fixtures/ledger_entries.macro.ref
  • Tests/Xrpl.Tests/Integration/transactions/TestILoan.cs
  • Tests/Xrpl.Tests/Models/RippledLedgerEntryFormats.cs
  • Tests/Xrpl.Tests/Models/TestULedgerEntryFieldsConformance.cs
  • Tests/Xrpl.Tests/Xrpl.Tests.csproj
  • Xrpl/Models/Ledger/LOAmendments.cs
  • Xrpl/Models/Ledger/LOAmm.cs
  • Xrpl/Models/Ledger/LOCredential.cs
  • Xrpl/Models/Ledger/LODirectoryNode.cs
  • Xrpl/Models/Ledger/LOFeeSettings.cs
  • Xrpl/Models/Ledger/LOLoan.cs
  • Xrpl/Models/Ledger/LONFTokenPage.cs
  • Xrpl/Models/Ledger/LONegativeUNL.cs
  • Xrpl/Models/Ledger/LOVault.cs
💤 Files with no reviewable changes (4)
  • Xrpl/Models/Ledger/LOVault.cs
  • Xrpl/Models/Ledger/LOCredential.cs
  • Xrpl/Models/Ledger/LONFTokenPage.cs
  • Xrpl/Models/Ledger/LOLoan.cs

* LONegativeUNL: добавлен using System.Text.Json.Serialization и атрибуты
  сокращены до [JsonPropertyName] — как в LOAmendments, LODirectoryNode,
  LOFeeSettings и LOAmm. Полная форма стояла потому, что файл этот namespace
  не импортировал; теперь импортирует
* RippledLedgerEntryFormats: парсер падает на повторно объявленном объекте
  вместо тихой перезаписи. Индексаторное присваивание позволяло второму
  объявлению вытеснить первое — объект молча уходил из таблицы конформанса,
  а fieldCount продолжал расти, так что порог минимального разбора потерю
  не замечал. Это ровно тот класс тихого отказа, против которого написан
  остальной парсер

Дубликатов имён в текущей фикстуре нет (единственный LEDGER_ENTRY_DUPLICATE —
DepositPreauth, и обычного объявления с этим именем не существует), так что
гвард forward-looking. Проверен мутацией: дублирование блока Ticket даёт
"Ticket: declared twice in ledger_entries.macro"; фикстура после проверки
восстановлена и снова байт-в-байт совпадает с пином.

Проверено: сборка без ошибок, юнит-тесты 879/879.
@Platonenkov

Copy link
Copy Markdown
Collaborator Author

Оба нитпика проверил и принял — коммит ad6b408.

1. LONegativeUNL.cs — полная форма атрибута. Валидно. Полная форма стояла не по стилю, а по необходимости: файл импортировал только System.Collections.Generic, namespace System.Text.Json.Serialization в нём отсутствовал. Добавил using и сократил оба атрибута до [JsonPropertyName] — теперь единообразно с LOAmendments, LODirectoryNode, LOFeeSettings и LOAmm.

2. RippledLedgerEntryFormats.cs — падать на дубликате имени. Валидно и по делу. Индексаторное присваивание позволяло второму объявлению вытеснить первое: объект молча уходил из таблицы конформанса, а fieldCount продолжал расти, поэтому порог минимального разбора потерю не ловил. Это ровно тот класс тихого отказа, против которого написан весь остальной парсер (неизвестный Soe*-ключ, тощий разбор), так что непоследовательно было бы оставить.

Замечание forward-looking: дубликатов имён в текущей фикстуре нет. Единственный LEDGER_ENTRY_DUPLICATE — это DepositPreauth (макрос нужен из-за конфликта JSS-имён), и обычного объявления с тем же именем не существует.

Проверил мутацией, а не только тем, что тесты зелёные: продублировал блок Ticket в фикстуре — парсер упал с Ticket: declared twice in ledger_entries.macro — the parser would drop one definition, update it before trusting this test. После проверки фикстура восстановлена, curl … | diff против пина ecdd457f показывает совпадение байт-в-байт.

Сборка без ошибок, юнит-тесты 879/879.

@Platonenkov
Platonenkov added this pull request to the merge queue Aug 4, 2026
Merged via the queue into dev with commit 713da1a Aug 4, 2026
4 checks passed
@Platonenkov
Platonenkov deleted the claude/ledger-entry-fields-guard-778740 branch August 4, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant