Skip to content

feat(protocol): поля транзакций, потерянные моделями, и приведение TxFormat к rippled (10.10.0.0) - #66

Merged
Platonenkov merged 6 commits into
devfrom
claude/xrpl-csharp-missing-tx-fields-add4ba
Jul 29, 2026
Merged

feat(protocol): поля транзакций, потерянные моделями, и приведение TxFormat к rippled (10.10.0.0)#66
Platonenkov merged 6 commits into
devfrom
claude/xrpl-csharp-missing-tx-fields-add4ba

Conversation

@Platonenkov

@Platonenkov Platonenkov commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Что и зачем

Две связанные проблемы одного класса: SDK объявляет поле на уровне протокола, но типизированный слой его не выражает — и это ничем не проявляется.

1. Поля протокола, отсутствовавшие в моделях транзакций

TxFormat их перечислял, кодек знал по definitions.json, поэтому через Dictionary<string, object> значения доезжали до сети. Но свойства у моделей не было: чтение молча теряло значение, а задать через типизированный API было нельзя вообще.

Поле Куда добавлено Обоснование
Delegate TransactionRequest / TransactionResponse входит в commonFields rippled — допустимо на любом типе транзакции
OperationLimit там же тоже commonFields; инертен на XRPL, но именно его читает Burn-2-Mint на Xahau
WalletLocator AccountSet (+Response, +интерфейс) стоит в формате AccountSet у rippled, обрабатывается транзактором
WalletSize там же легаси, транзактором не обрабатывается — добавлен ради целостности чтения
Target не добавлено не поле протокола: sfTarget выведен из обращения (AccountID nth 7 помечен unused в sfields.macro, имени нет в definitions.json)

Поля объявлены в ITransactionCommon — там же, где остальные общие поля. Заодно туда подняты Sponsor/SponsorFlags (XLS-68), которые раньше жили только на классах: иначе часть common-полей в интерфейсе есть, а часть нет, и правило размещения становится непонятным.

Это важно для всего, что типизировано интерфейсом, — раньше такие места добирались до полей только через каст: Batch.RawTransactionBatchUtils именно по Delegate внутренней транзакции определяет обязательных подписантов), SimulateRequest.Transaction/TxJson, HashOrTransaction.Transaction.

Реализации в классах не менялись — только сняты дублирующие докблоки в пользу <inheritdoc />. Сериализация не затронута: она идёт по конкретному рантайм-типу, golden-blob тест это подтверждает.

ValidateBaseTransaction типизированно проверяет два новых common-поля, как и все остальные.

2. TxFormat приведён к rippled и удерживается там

Таблица инертна в рантайме: TxFormat.Validate не вызывается нигде в продакшн-коде, кодек сериализует по definitions.json. Поэтому неверные записи не давали симптомов и жили годами. Диff по transactions.macro нашёл 6 неверных форматов из 82:

  • CheckCreate / CheckCash / CheckCancel — все три были дословной копией записи PaymentChannelClaim, стоящей выше по файлу
  • NFTokenMint — не хватало Amount/Destination/Expiration: поля NFTokenMintOffer попали в модель ещё в 10.7.0, а формат за ними не последовал
  • OracleSet (BaseAsset/QuoteAsset/AssetPrice/Scale) и SignerListSet (WalletLocator) — поля вложенных объектов, поднятые на верхний уровень
  • VaultCreate — лишнее Amount

Сейчас все 82 формата совпадают с rippled поле в поле.

3. TestUTxFormatConformance — чтобы это не повторилось

Диффает все 82 формата с вендоренным transactions.macro и называет расхождения поимённо.

Макрос пиннится по ref, а не тянется с develop, намеренно: дрейф вверху уже ловит protocol-watch (transactions.macro в его списке), а сетевой тест краснел бы по расписанию Ripple вместо нашего. Порядок при срабатывании protocol-watch: заменить вендоренный файл целиком, обновить sha в .ref, тест покажет, какие записи TxFormat обязаны последовать.

Парсер падает громко на неизвестном Soe*-ключевом слове и на коротком разборе — чтобы смена раскладки макроса не сделала проверку зелёной на пустой таблице. Отдельный тест сторожит сторожа.

definitions.json и server_definitions для этой сверки непригодны: в них есть коды полей, но нет пер-транзакционных форматов. Единственный источник — transactions.macro.

Ломающие изменения

1. ITransactionCommon получил четыре новых членаDelegate, OperationLimit, Sponsor, SponsorFlags. Source-breaking для внешних реализаторов интерфейса (моки, обёртки). Внутри репозитория интерфейс реализуют только TransactionRequest и TransactionResponse, которые уже несут эти свойства.

**2.
CheckCreate.InvoiceID: uint?string.

sfInvoiceID — это Hash256. У Payment поле уже было string, а ValidateCheckCreate в том же файле уже требовал строку — модель противоречила собственной валидации. Любое непустое значение падало при подписи:

InvalidJsonException: Can't decode `InvoiceID` from `123`

То есть поле было нерабочим во всех релизах, где существует. Сигнатура формально ломается, но рабочего кода, который его выставляет, существовать не может. Найдено при написании интеграционного покрытия для исправленного формата CheckCreate.

Тесты

  • TestUTransactionProtocolFields — полный цикл новых полей: десериализация, round-trip ToJson/ToDictionary, побайтовый паритет типизированной подписи со словарным путём и, как защита от регрессии при правке общей базы, blob'ы транзакций без новых полей против подписей, снятых с 10.9.1.0
  • TestUTxFormatConformance — сверка всех 82 форматов + защита парсера
  • TestUProtocolCompleteness — точные наборы полей исправленных Check-транзакций и SignerListSet
  • TestIProtocolFieldSets (standalone) — исправленные наборы против живой ноды: CheckCreate с Expiration/DestinationTag/InvoiceID, CheckCash через ранее непокрытую ветку DeliverMin, NFTokenMint с полями оффера, и AccountSet с WalletLocator/WalletSize/OperationLimit, пережившим полный цикл через реестр обратно в типизированный AccountSetResponse

Сам TxFormat end-to-end не проверяется — он инертен; интеграционные тесты пинят утверждение под ним: нода принимает ровно те наборы полей, которые SDK теперь объявляет.

Прогоны (локально)

юнит:                 1001 пройдено /  0 падений
интеграция, CI-стенд:  217 пройдено / 39 пропущено / 0 падений   (rippled 3.2.0)
интеграция, nightly:   256 пройдено /  0 пропущено / 0 падений   (xrpld 3.3.0-b1)

На CI-стенде 39 тестов уходят в Inconclusive: четырёх амендментов (Sponsor, BatchV1_1, PermissionDelegationV1_1, ConfidentialTransfer) в релизной сборке 3.2.0 нет вообще — это TestIBatch (19), TestISponsorship (7), TestISponsorshipSigningMatrix (7), TestIBatchSponsorship (3), TestIDelegateSet (2), TestIConfidentialMPT (1). Штатное поведение, а не сбой.

Поэтому набор прогнан ещё и на nightly-стенде (docker-compose.batchv11.yml, запиннутый xrpld 3.3.0~b1+202607110018.8306ac77), где все восемь релевантных амендментов активны на генезисе: 0 пропусков, 0 падений.

Это важно именно для этого PR: BatchUtils определяет обязательных подписантов батча по полю Delegate внутренней транзакции, а Delegate вместе с Sponsor/SponsorFlags поднят в ITransactionCommon. На CI-стенде вся эта область пропускалась и живьём не проверялась; на nightly она отработала — включая матрицу со-подписания XLS-68 и DelegateSet.

Версии

Xrpl поднят до 10.10.0.0. Базовые пакеты (Xrpl.AddressCodec, Xrpl.BinaryCodec, Xrpl.Keypairs) оставлены на 10.9.0.0 — их код не менялся, в Base/ нет ни одной правки. Это соответствует принципу из 10.8.0 («Xrpl.BinaryCodec bumped — the codec changed») и текущему состоянию репозитория, где версии уже не в локстепе.

Summary by CodeRabbit

  • New Features
    • Added support for additional transaction protocol fields, including Delegate, OperationLimit, and AccountSet wallet settings (WalletLocator, WalletSize).
    • Enhanced transaction field-format coverage for checks, NFT minting, oracle configuration, vault creation, and ticket creation.
  • Bug Fixes
    • Updated transaction format definitions to better match XRPL protocol expectations and validation behavior.
    • Improved round-trip behavior for ledger-submitted field sets.
  • Breaking Change
    • CheckCreate.InvoiceID is now a string (was uint?).
  • Documentation
    • Added/updated release notes for version 10.10.0.0.

Прочее

.coderabbit.yamlauto_review.enabled: false. Автоматическое ревью выключено, ревью запрашивается по требованию комментарием @coderabbitai review. Остальные настройки (base_branches, инкрементальное ревью) оставлены на месте и снова заработают, если автоматику вернут. Изменение общерепозиторное — действует на все будущие PR, не только на этот.

…Format к rippled (10.10.0.0)

Поля, объявленные протоколом транзакционными, но отсутствовавшие в типизированных
моделях: TxFormat их перечислял и кодек знал, поэтому через Dictionary<string, object>
значения доезжали, но у моделей не было свойства — чтение молча теряло их, а задать
через типизированный API было нельзя вообще.

* TransactionRequest/TransactionResponse + Delegate и OperationLimit — оба поля входят
  в commonFields rippled (TxFormats.cpp), то есть допустимы на любом типе транзакции,
  поэтому размещены на общей базе, а не на отдельных транзакциях. Delegate помечает
  транзакцию, отправленную по правам DelegateSet (BatchUtils уже учитывал его при сборе
  обязательных подписантов батча). OperationLimit инертен на XRPL, но именно его читает
  Burn-2-Mint на Xahau — потребителям больше не нужен обходной путь через словарь.
* AccountSet/AccountSetResponse + WalletLocator и WalletSize — оба стоят в формате
  AccountSet у rippled. WalletSize легаси и транзактором не обрабатывается, добавлен
  ради целостности чтения.
* ValidateBaseTransaction типизированно проверяет два новых common-поля.
* Target намеренно не добавлен: sfTarget выведен из обращения (AccountID nth 7 помечен
  unused в sfields.macro, имени нет в definitions.json), а TicketCreate после амендмента
  TicketBatch несёт только sfTicketCount. Протухшие Target/Expiration убраны из
  TicketCreate в TxFormat; Field.Target оставлен в кодеке для декодирования старых blob.

TxFormat приведён к rippled полностью. Таблица инертна в рантайме (TxFormat.Validate не
на пути подписи, кодек сериализует по definitions.json), поэтому неверные записи не давали
симптомов и жили годами. Диff по transactions.macro нашёл 6 неверных форматов из 82:

* CheckCreate/CheckCash/CheckCancel — все три были дословной копией записи
  PaymentChannelClaim, стоящей выше по файлу.
* NFTokenMint — не хватало Amount/Destination/Expiration: поля NFTokenMintOffer попали
  в модель ещё в 10.7.0, а формат за ними не последовал.
* OracleSet (BaseAsset/QuoteAsset/AssetPrice/Scale) и SignerListSet (WalletLocator) —
  поля вложенных объектов, поднятые на верхний уровень.
* VaultCreate — лишнее Amount.

TestUTxFormatConformance диффает все 82 формата с вендоренным ref-пиннутым макросом и
называет расхождения поимённо. Пиннинг вместо живого develop намеренный: дрейф вверху уже
ловит protocol-watch, а сетевой тест краснел бы по расписанию Ripple. Парсер падает громко
на неизвестном Soe*-ключевом слове и на коротком разборе, чтобы смена раскладки макроса не
сделала проверку зелёной на пустой таблице.

Попутно: CheckCreate.InvoiceID был uint?, хотя sfInvoiceID это Hash256, у Payment он string,
а ValidateCheckCreate уже требовал строку. Любое непустое значение падало при подписи
("Can't decode InvoiceID from 123") — поле было нерабочим во всех релизах. Тип изменён на
string: формально ломающее изменение сигнатуры, фактически ломать нечего.

Тесты:
* TestUTransactionProtocolFields — полный цикл новых полей: десериализация, round-trip
  ToJson/ToDictionary, побайтовый паритет типизированной подписи со словарным путём и, как
  защита от регрессии при правке общей базы, blob транзакций без новых полей против подписей,
  снятых с 10.9.1.0.
* TestIProtocolFieldSets — исправленные наборы полей против живой ноды: CheckCreate с
  Expiration/DestinationTag/InvoiceID, CheckCash через ветку DeliverMin, NFTokenMint с
  полями оффера, и AccountSet с WalletLocator/WalletSize/OperationLimit, пережившим полный
  цикл через реестр обратно в типизированный AccountSetResponse.

Прогон: юнит 999/0, интеграция 217 пройдено / 39 пропущено (amendment-gated) / 0 падений.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

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: 3b9c0481-d6a9-4e33-98d0-dad9d2f159ef

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
📝 Walkthrough

Walkthrough

The release adds typed support for protocol-declared transaction fields, aligns transaction formats with a pinned rippled macro fixture, expands conformance and codec tests, and verifies corrected field sets through real-node ledger integration tests.

Changes

Protocol field and format conformance

Layer / File(s) Summary
Typed protocol field support
Xrpl/Models/Transactions/{Common,AccountSet,CheckCreate}.cs, Tests/Xrpl.Tests/Models/*Protocol*
Adds common and account wallet fields, changes CheckCreate.InvoiceID to string, validates new values, and covers JSON, signing, binary round trips, unset fields, and interface access.
TxFormat alignment and conformance
Xrpl/Models/Transactions/TxFormat.cs, Tests/Xrpl.Tests/Fixtures/*, Tests/Xrpl.Tests/Models/*
Corrects transaction field requirements, vendors and parses the rippled macro fixture, and compares local formats and requirements against it.
Ledger integration and release metadata
Tests/Xrpl.Tests/Integration/transactions/*, CHANGES.md, Xrpl/Xrpl.csproj, .coderabbit.yaml
Verifies corrected fields against a real node, records the 10.10.0.0 release, updates package metadata, and disables automatic reviews.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TestIProtocolFieldSets
  participant XRPLNode
  participant LedgerObjects
  TestIProtocolFieldSets->>XRPLNode: Submit CheckCreate, CheckCash, NFTokenMint, or AccountSet
  XRPLNode->>LedgerObjects: Accept transaction and update ledger state
  TestIProtocolFieldSets->>LedgerObjects: Query typed ledger objects
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок точно отражает основные изменения: добавление полей протокола в модели и приведение TxFormat к rippled 10.10.0.0.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/xrpl-csharp-missing-tx-fields-add4ba

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

@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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
Xrpl/Models/Transactions/AccountSet.cs (1)

142-145: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider type-validating the new WalletLocator/WalletSize fields.

ValidateAccountSet doesn't type-check WalletLocator/WalletSize the way ValidateCheckCreate does for InvoiceID (is not string/IsUInt32). Not a regression, but since these are newly-exposed protocol fields, adding the same lightweight type guard would catch malformed input earlier and keep this transaction's validation consistent with CheckCreate.

♻️ Proposed validation addition
             if (tx.TryGetValue("TickSize", out var TickSize) && TickSize is not null)
             {
                 if (!Common.TryGetUInt32(TickSize, out uint size))
                     throw new ValidationException("AccountSet: out of TickSize");
             }
+
+            if (tx.TryGetValue("WalletLocator", out var WalletLocator) && WalletLocator is not string { })
+                throw new ValidationException("AccountSet: invalid WalletLocator");
+
+            if (tx.TryGetValue("WalletSize", out var WalletSize) && !Common.IsUInt32(WalletSize))
+                throw new ValidationException("AccountSet: invalid WalletSize");

Also applies to: 194-205, 228-233

🤖 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/Transactions/AccountSet.cs` around lines 142 - 145, Update
ValidateAccountSet to type-validate WalletLocator as a string and WalletSize as
a UInt32, matching the lightweight guards used by ValidateCheckCreate for
protocol fields. Apply the checks wherever AccountSet validation handles these
properties, while preserving existing validation behavior for valid values.
🤖 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.

Inline comments:
In `@CHANGES.md`:
- Around line 11-15: Reconcile the “six wrong formats” statement in the TxFormat
changelog entry with the seven named formats: CheckCreate, CheckCash,
CheckCancel, NFTokenMint, OracleSet, SignerListSet, and VaultCreate. Update the
count or enumeration so both accurately describe the changes.
- Line 3: Update the 10.10.0.0 release heading in CHANGES.md so its level
follows the document’s preceding heading hierarchy without skipping from h2 to
h3. Preserve the release title and date while using the appropriate incremental
Markdown heading level.

In `@Xrpl/Xrpl.csproj`:
- Line 17: Update the package version across the Xrpl, Xrpl.AddressCodec,
Xrpl.BinaryCodec, and Xrpl.Keypairs project files so they consistently use
10.10.0.0, or confirm and document the approved release policy if the base
packages intentionally remain at 10.9.0.0.

---

Nitpick comments:
In `@Xrpl/Models/Transactions/AccountSet.cs`:
- Around line 142-145: Update ValidateAccountSet to type-validate WalletLocator
as a string and WalletSize as a UInt32, matching the lightweight guards used by
ValidateCheckCreate for protocol fields. Apply the checks wherever AccountSet
validation handles these properties, while preserving existing validation
behavior for valid values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cbca45bd-84e0-4501-b999-25a0bb62caef

📥 Commits

Reviewing files that changed from the base of the PR and between 2368ef7 and c7b7c6a.

📒 Files selected for processing (15)
  • CHANGES.md
  • Tests/Xrpl.Tests/Fixtures/transactions.macro
  • Tests/Xrpl.Tests/Fixtures/transactions.macro.ref
  • Tests/Xrpl.Tests/Integration/transactions/TestIProtocolFieldSets.cs
  • Tests/Xrpl.Tests/Models/RippledTransactionFormats.cs
  • Tests/Xrpl.Tests/Models/TestCheckCreate.cs
  • Tests/Xrpl.Tests/Models/TestUProtocolCompleteness.cs
  • Tests/Xrpl.Tests/Models/TestUTransactionProtocolFields.cs
  • Tests/Xrpl.Tests/Models/TestUTxFormatConformance.cs
  • Tests/Xrpl.Tests/Xrpl.Tests.csproj
  • Xrpl/Models/Transactions/AccountSet.cs
  • Xrpl/Models/Transactions/CheckCreate.cs
  • Xrpl/Models/Transactions/Common.cs
  • Xrpl/Models/Transactions/TxFormat.cs
  • Xrpl/Xrpl.csproj

Comment thread CHANGES.md Outdated
Comment thread CHANGES.md Outdated
Comment thread Xrpl/Xrpl.csproj
<PackageProjectUrl>https://github.com/StaticBit-io/XrplCSharp</PackageProjectUrl>
<Title>XrplCSharp</Title>
<PackageVersion>10.9.1.0</PackageVersion>
<PackageVersion>10.10.0.0</PackageVersion>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Base package versions left at 10.9.0.0 while Xrpl moves to 10.10.0.0.

Per the repo's release guideline, package versions should be updated consistently across Xrpl, Xrpl.AddressCodec, Xrpl.BinaryCodec, and Xrpl.Keypairs. This release only bumps Xrpl. If the base packages truly have no changes this cycle, this may be intentional — please confirm that's the accepted release policy here rather than an oversight.

As per coding guidelines, `**/*.csproj`: When releasing, update the package version consistently in the `Xrpl`, `Xrpl.AddressCodec`, `Xrpl.BinaryCodec`, and `Xrpl.Keypairs` project files.

🤖 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/Xrpl.csproj` at line 17, Update the package version across the Xrpl,
Xrpl.AddressCodec, Xrpl.BinaryCodec, and Xrpl.Keypairs project files so they
consistently use 10.10.0.0, or confirm and document the approved release policy
if the base packages intentionally remain at 10.9.0.0.

Source: Coding guidelines

Delegate/OperationLimit (commonFields rippled) и Sponsor/SponsorFlags (XLS-68)
объявлены общими для всех транзакций, но жили только на классах TransactionRequest
и TransactionResponse. Всё, что типизировано интерфейсом, добиралось до них лишь
через каст: Batch.RawTransaction, SimulateRequest.Transaction/TxJson,
HashOrTransaction.Transaction.

Sponsor/SponsorFlags подняты тем же движением намеренно: иначе часть common-полей
в интерфейсе есть, а часть нет, и правило размещения становится непонятным.

Реализации в классах не изменились — только сняты дублирующие XML-докблоки в пользу
<inheritdoc />, документация теперь одна на интерфейсе. Сериализация не затронута:
она идёт по конкретному рантайм-типу, и golden-blob тест это подтверждает.

Source-breaking для внешних реализаторов ITransactionCommon. Внутри репозитория
интерфейс реализуют только два базовых класса, которые уже несут эти свойства.

Тесты: чтение всех четырёх полей через ITransactionCommon на request и response,
плюс Delegate у внутренней транзакции Batch без каста.

chore(coderabbit): выключить автоматическое ревью

auto_review.enabled: false — ревью запрашивается по требованию комментарием
"@coderabbitai review". Остальные настройки (base_branches, incremental) оставлены
на месте и снова заработают, если автоматику вернут.

Прогон: юнит 1001/0, интеграция 217 пройдено / 39 пропущено / 0 падений.
@Platonenkov

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

* «six wrong formats» -> «seven»: перечислено семь (CheckCreate, CheckCash,
  CheckCancel, NFTokenMint, OracleSet, SignerListSet, VaultCreate). SignerListSet
  был упомянут внутри пункта про OracleSet и потерялся при подсчёте. Ошибка только
  в тексте release notes — в TxFormat исправлены все семь, conformance-тест это
  подтверждает.

* Заголовки версий переведены с h3 на h2. markdownlint MD001 ругался на скачок
  h1 -> h3, но это сквозная конвенция файла, а не свойство новой секции: правка
  только своего заголовка оставила бы её единственной h2 среди 58 h3 и не убрала бы
  предупреждение с остальных. Переведены все 59 разом — файл стал и консистентным,
  и чистым по линтеру. Текст записей не тронут.
…ountSet

Новые поля AccountSet не проверялись по типу, хотя все соседние проверяются —
несогласованность, внесённая вместе с самими полями.

WalletLocator проверяется как 256-битное hex-значение, а не просто как строка:
sfWalletLocator объявлен Hash256, и то же правило уже применяет валидатор
SignerListSet к WalletLocator внутри SignerEntry. Форма проверки взята из
Common.ValidateDomainId, где 256-битные поля валидируются так же.

WalletSize проверяется через Common.IsUInt32.

На путь подписи это не влияет: валидаторы вызываются явно, из Submit не дёргаются
(единственный внутренний вызов Validation.Validate — в BatchUtils).

Найдено ревью CodeRabbit (nitpick). Предложенная им проверка WalletLocator была
слабее нужной — "is not string" пропустил бы любую строку, включая ту, что не
пройдёт кодек.
@Platonenkov

Copy link
Copy Markdown
Collaborator Author

Разобран nitpick по AccountSet.cs (свёрнутая секция ревью) — исправлено в 26dd2be, но проверка сделана строже предложенной.

Замечание по сути верное: ValidateAccountSet не проверял типы новых полей, хотя все соседние проверяет. Несогласованность внесена вместе с самими полями.

Однако предложенный вариант для WalletLocatorWalletLocator is not string { } — слишком слабый. sfWalletLocator объявлен в definitions.json как Hash256, поэтому любая строка, не являющаяся 64-символьным hex, всё равно не пройдёт бинарный кодек: валидатор пропустил бы вперёд то, что гарантированно упадёт позже. В этом же репозитории то же поле уже валидируется строго — SignerListSet требует от WalletLocator внутри SignerEntry 256-битное hex-значение.

Реализовано:

if (tx.TryGetValue("WalletLocator", out var WalletLocator) && WalletLocator is not null)
{
    if (WalletLocator is not string walletLocator ||
        walletLocator.Length != 64 || !walletLocator.All(Uri.IsHexDigit))
        throw new ValidationException("AccountSet: invalid WalletLocator");
}

if (tx.TryGetValue("WalletSize", out var WalletSize) && !Common.IsUInt32(WalletSize))
    throw new ValidationException("AccountSet: invalid WalletSize");

Форма 256-битной проверки взята из Common.ValidateDomainId, где такие поля валидируются так же. Для WalletSize предложенный Common.IsUInt32 подходит без изменений.

Покрыто TestUAccountSet_ValidatesWalletFieldTypes: валидное 64-hex значение проходит, число вместо строки и строка не-hex отвергаются, нестроковый WalletSize отвергается.

На путь подписи это не влияет — валидаторы вызываются явно, из Submit не дёргаются (единственный внутренний вызов Validation.Validate — в BatchUtils). Юнит 1002/0; интеграционный срез по AccountSet перепрогнан на standalone — без изменений.

…закции

Delegate был единственным из новых полей без интеграционного покрытия: оно
существовало только на юнит-уровне. TestIDelegateSet проверял выдачу прав
(DelegateSet -> ledger-объект), но транзакции, отправленной ОТ ИМЕНИ делегата,
не собирал ни один тест.

TestDelegatedPayment_DelegateFieldSurvivesTheLedgerRoundTrip закрывает вторую
половину: владелец выдаёт право на Payment, делегат подписывает Payment, у которого
Account — владелец, а Delegate — он сам, и транзакция читается обратно в
типизированную модель с заполненным Delegate (напрямую и через ITransactionCommon).

Тест не вырожденный: без sfDelegate rippled отверг бы подпись как чужую
(подписывает делегат, Account — владельца), так что зелёный результат означает,
что поле реально доехало и было учтено, а не просто отражено в ответе.

Гейтится PermissionDelegationV1_1, то есть выполняется на nightly-стенде;
на CI уходит в Inconclusive, как и остальные тесты этого класса.

Дополнительно TestICheckCreate_OptionalFieldsLandOnTheLedger читает InvoiceID
не только из ledger-объекта Check, но и из модели транзакции через client.Tx() —
поле было uint? и не могло пережить такой цикл вообще.
Два места в наборе ходили в интернет, из-за чего зелёный CI зависел от доступности
чужих сервисов.

TestIConnectionStates (7 тестов) работал против публичного testnet и devnet. Ничего
специфичного для публичной сети в них нет — все проверки про машину состояний самого
клиента, — поэтому переведены на локальный стенд. Кейс с несуществующим хостом,
проверяющий исчерпание реконнектов, резолвил DNS; заменён на закрытый порт loopback:
отказ мгновенный и резолвер не участвует. ChangeServer между двумя эндпоинтами
сохранён через другое написание того же адреса (localhost / 127.0.0.1), второй
контейнер для этого не нужен.

Вторая половина флейка — фиксированные Task.Delay. Один из этих тестов упал в полном
прогоне и прошёл при перезапуске. Ожидание состояния заменено на опрос с таймаутом:
класс с ~40 секунд сна ушёл на доли секунды (12-370 мс там, где раньше стояло 3 с).

Live-тесты x402 (t54) требуют публичного faucet И стороннего хостед-фасилитатора.
Помечены TestCategory("Live") и исключены из прогона CI фильтром
"TestI&TestCategory!=Live"; шесть герметичных x402 E2E остаются. Запуск вручную:
--filter "TestCategory=Live".

Прогон: юнит 1002/0; интеграция Xrpl.Tests 217 пройдено / 40 пропущено (amendment-gated)
/ 0 падений; x402 герметичные 6/6.
@Platonenkov
Platonenkov added this pull request to the merge queue Jul 29, 2026
Merged via the queue into dev with commit 3a2328c Jul 29, 2026
4 checks passed
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