Skip to content

ingest: one ledger walk — ExtractLedgerTxParts + EventsFromTxParts/FeesFromTxParts (supersedes the extractor bundles) - #5966

Merged
karthikiyer56 merged 10 commits into
mainfrom
extract-fees-view
Aug 4, 2026
Merged

karthikiyer56 merged 10 commits into
mainfrom
extract-fees-view

Conversation

@karthikiyer56

@karthikiyer56 karthikiyer56 commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

Reshape of the experimental view-extractor family per tamirms' review, spec'd in stellar/stellar-rpc#912: one function walks the ledger; every product is a plain function of the walk's output.

Before (bundles) After (parts + products)
• ExtractTxHashes — hashes, one walk
• ExtractLedgerEvents — hashes + events, one walk
• ExtractFees(lcm, passphrase) — fees, ANOTHER walk + whole-TxSet SHA-256 pairing pass
• ExtractLedgerTxParts(lcmView) — the ONLY TxProcessing walk, returns per-tx handles
• EventsFromTxParts(txParts) — events product, no walking
• FeesFromTxParts(txParts) — fees product, no walking, no passphrase
• "one walk per ledger" is a doc-comment promise each bundle must make
• rpc v2's hot path walks twice to get all three products
• "one walk per ledger" is a structural property of the API
• each consumer composes exactly the subset it needs

Why the old functions are DELETED, not kept alongside

Deleted Replaced by
ExtractTxHashes txParts[i].Hash off the walk
ExtractLedgerEvents + LedgerTransactionEvents EventsFromTxParts + TxEvents (hash lives on txParts)
ExtractFees(lcm, passphrase) + LedgerFees.LedgerSequence/CloseTime FeesFromTxParts (no passphrase; seq/close-time are the caller's)
  • None of these ever shipped — all Experimental:, still under CHANGELOG Pending. Deleting now is free; one release later it's a deprecation cycle + major-version break.
  • Keeping ExtractFees would keep a SECOND fee definition (envelope gate, uint64 wrap) — same ledger, different buckets, permanent "which one is right?" trap.
  • "One walk per ledger" is only a structural property if the API offers no second way to walk — a surviving bundle is exactly that second way.

The API

txParts, err := ingest.ExtractLedgerTxParts(lcmView) // the one walk
// txParts[i]: Hash, InnerHash, FeeBump, Result view, Meta view (views alias the buffer)

txEvents, err := ingest.EventsFromTxParts(txParts)   // []TxEvents, index-aligned with txParts
fees, err := ingest.FeesFromTxParts(txParts)         // LedgerFees{ClassicFeesPerOp, SorobanInclusionFees}
Consumer (stellar-rpc v2) Composition
Hot ingestion (live streaming) • parts → events + fees
• one walk, all three products
Cold backfill (bulk path) • parts → events
• fees never computed
Fee warm-up replay on restart (stellar/stellar-rpc#888) • parts → fees
• events never computed, no passphrase to plumb

Fee classification — TxProcessing only

The envelope leaves fee ingestion entirely: soroban-ness and op count are read from the result + meta, so the TxSet pairing pass, the per-envelope hashing, and the passphrase parameter all delete.

Transaction shape (all read from TxProcessing) Contribution
Meta V3/V4 carries SorobanMeta, Ext.V == 1 • FeeCharged − (TotalNonRefundable + TotalRefundable resource fee charged) → Soroban bucket
SorobanMeta present, ext absent • skipped (always present since P21 — safety net)
SorobanMeta absent • FeeCharged / opCount → classic bucket
• opCount = number of per-op results (outer result for txSUCCESS/txFAILED, INNER result pair's for fee-bumps)
No per-op result list (txINTERNAL_ERROR) or empty • skipped
Fee-bump • FeeCharged from the OUTER result, opCount from the INNER result
Negative FeeCharged / negative resource-fee component (or int64-overflowing sum) / resource fee > FeeCharged • error
Delta from v1's IngestFees Why it's deliberate
Transactions whose operations never ran are skipped — their results carry no per-op list (v1 counted them via envelope ops) • two ways in: core malfunction (txINTERNAL_ERROR), or an account invalidating its own pending tx with an operation it signed inside another account's tx (merge / signer removal / sequence bump — the godoc has the worked example); pre-P20 tx sets also produced these organically
• the dropped fee says nothing about what a fee bidder should pay
• a stellar-rpc#883 getFeeStats divergence therefore means "go look at that ledger", not automatically "core had an incident"
Resource fee > FeeCharged is an error (v1 wrapped the uint64) • with mechanism parity gone, there's no reason to let corrupt input drop a ~2^64 sample into the fee window

Parity contract: identical output to v1 on organic current-protocol traffic — deltas confined to never-ran transactions — verified empirically on the recorded pubnet ledger (envelope-derived and results/meta-derived definitions agree per-tx on op count, soroban gate, and ext presence across all 249 txs, incl. 41 failed and 113 fee-bumps).

How it's verified

Layer What it checks
Fixture matrix (extract_fees_test.go) • one cell per classification rule row: LCM V0/V1/V2 × meta V0–V4 × envelope V0/V1/fee-bump × result shapes
• results-derived op counts: failed multi-op, fee-bump inner counts, results_count_is_authoritative (result count ≠ envelope count)
• the no-op-list family skipped: txINTERNAL_ERROR, self-invalidated txNO_ACCOUNT, fee-bump-inner-internal-error
• soroban gate flips pinned: SorobanMeta present w/ classic op → soroban; soroban op w/o SorobanMeta → classic
• error cells: negative fees, int64 overflow, resource fee > FeeCharged
TestFeesFromTxParts_TxSetNotConsulted • gutting every envelope from the TxSet changes nothing (was a missing-envelope ERROR under the old extractor)
Real-ledger equivalence (extract_real_ledger_test.go) • pubnet ledger 58752000 (249 txs)
• parts: hash/inner-hash/fee-bump/result-bytes/meta-bytes vs the parsed reader
• events: wire-identical vs GetTransactionEvents
• fees: re-derived with the OLD envelope-based oracle — deliberately kept as the standing cross-definition check
V4 meta walker (metaEventRaws) • one Fields() locate pass instead of per-field prefix walks (DiagnosticEvents is the LAST field — its accessor re-walked the whole meta per tx on the read path)
• ~10% on a synthetic V4 walker (10 ops × 3 events), growing with op count; the pubnet fixture is protocol 22 / all-V3, where measurements show parity
• V3 arm uses the locate pass only when both event sets are wanted
Benchmarks (same ledger) • walk alone: 0.29 ms / 17 allocs
• walk + events: 0.42 ms / 137 allocs
• walk + fees: 0.42 ms / 34 allocs (old ExtractFees bundle: 0.58 ms / 67 allocs)
• walk + all products: 0.58 ms / 154 allocs — the hot composition now costs what the fee bundle alone used to
• parsed path: ~5.7 ms / ~95k allocs

ExtractFees(lcm xdr.LedgerCloseMetaView, passphrase) returns one ledger's
fee observations (LedgerFees) split into classic per-op fees and Soroban
inclusion fees — the buckets stellar-rpc's getFeeStats windows consume —
from one TxProcessing walk plus by-hash envelope pairing, decoding nothing
beyond FeeCharged, op count/type, and the Soroban resource-fee extension.

The classification replicates stellar-rpc v1's FeeWindows.IngestFees
bug-for-bug (soroban gate is the op type alone; soroban-shaped txs without
SorobanTransactionMetaExtV1 are skipped, not classic; fee-bump reads inner
ops with the outer FeeCharged; uint64 subtraction wraps when the charged
resource fee exceeds FeeCharged). A verbatim test-only port of that walk is
the primary oracle; the parsed LedgerTransaction fee helpers are the
secondary oracle, cross-asserted where semantics align and pinned where
they deliberately diverge.

Part 1 of stellar/stellar-rpc#881.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 23:37
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a zero-copy, view-based fee extractor matching stellar-rpc v1 fee classification.

Changes:

  • Introduces LedgerFees and ExtractFees.
  • Adds comprehensive synthetic, real-ledger, multiphase, and benchmark coverage.
  • Extends transaction fixtures with fee-processing data.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ingest/extract.go Implements fee extraction and classification.
ingest/extract_fees_test.go Adds fee matrix and oracle tests.
ingest/extract_fees_multiphase_test.go Tests mixed transaction-set phases.
ingest/extract_real_ledger_test.go Tests real-ledger equivalence.
ingest/extract_bench_test.go Benchmarks parsed and view paths.
ingest/transaction_view_test.go Enhances shared transaction fixtures.
ingest/CHANGELOG.md Documents the experimental API.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ingest/extract.go Outdated
karthikiyer56 and others added 4 commits July 27, 2026 17:12
Code-review follow-ups:

- Replicate the parsed reader's pre-protocol-10 meta guard (badMetaVersionErr)
  so ExtractFees rejects the same outdated-stellar-core ledgers v1 does; adds
  xdr.LedgerCloseMetaView.ProtocolVersion and FeeProcessing on the
  TxProcessing projection to support it.
- Hash the ENTIRE TxSet like v1's reader (no early break, hasher built on the
  first envelope): an invalid passphrase or malformed envelope anywhere in a
  non-empty TxSet errors exactly when it does on the parsed path, while an
  empty TxSet still skips passphrase validation.
- Resolve each envelope's fee shape (op count + sole-op type) in the same
  pairing pass instead of computing the unused isSoroban flag and re-parsing
  the envelope afterwards.
- Tests: reuse the production feeBucket enum, drop the duplicated wrap test,
  consolidate the LCM builders (shared header/TxProcessing/result helpers,
  explicit setLedgerVersion override), strip test-function docstrings, and add
  guard/passphrase parity tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The parsed LedgerTransaction fee helpers computed overlapping quantities via
independent routes (balance deltas, the protocol inclusion-fee equation), and
a block of tests cross-asserted or pinned every agreement and disagreement.
Confusing in practice, and the helpers have no production callers — the
contract that matters is the one the remaining tests state directly:
ExtractFees returns exactly what stellar-rpc v1's IngestFees returns, verified
against the verbatim ported walk on every fixture and on a real pubnet ledger
(where each transaction's fee is also re-derived from the raw parsed fields).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fee stats only ever ingest ledgers at the tip (protocol 23+), so the parsed
reader's stale-meta check for pre-2019 ledgers can never fire here. Removing
it also removes the ProtocolVersion view helper and the FeeProcessing
projection field it required — xdr/ledger_close_meta_view.go and
ingest/ledger_close_meta_view_nav.go revert to untouched. The deliberate
non-goal is noted in the ExtractFees godoc.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ExtractFees itself is the port of v1's walk; carrying a second copy of that
walk in the test file to diff against added 100 lines without adding trust.
The tests now assert v1's documented rules directly: hand-computed expected
buckets for every fixture in the matrix, and a per-transaction re-derivation
from the parsed fields on the real pubnet ledger. The benchmark measures the
view path alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tamirms

tamirms commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Wiring this into rpc v2 surfaces an API-shape problem worth fixing while the extractor family is still experimental.

rpc v2 has three consumers of per-ledger extraction, and each wants a different subset of the same three products. Hot ingestion wants events, txhashes, and fees. Cold backfill wants events and txhashes, and since it is the bulk path, it should never pay for fees it will not serve. The fee-window warm-up replay (stellar/stellar-rpc#888) wants fees alone. But the API sells fixed bundles rather than products: ExtractLedgerEvents is hashes plus events in one walk, ExtractFees is fees in another. So the hot path has to walk TxProcessing twice per ledger to get all three, and the only fix the current shape allows is a third combined function, then a fourth for whatever subset comes next.

The intuition for the fix: walking the ledger and reading products off it are different jobs, and only the walk is worth sharing. Let one function own the walk and return per-transaction handles, and make each product a plain function of those handles:

// The only function in the package that walks TxProcessing.
func ExtractLedgerTxParts(lcm xdr.LedgerCloseMetaView) ([]LedgerTxParts, error)

type LedgerTxParts struct {
    Hash, InnerHash [32]byte // filled during the walk; everything pairs by hash
    FeeBump         bool
    Result xdr.TransactionResultPairView // lazy handle into the buffer
    Meta   xdr.TransactionMetaView       // lazy handle into the buffer
}

// Products. No walking, just reads off the handles.
func EventsFromTxParts(parts []LedgerTxParts) ([]TxEvents, error)
func FeesFromTxParts(parts []LedgerTxParts) (LedgerFees, error)

Each consumer composes exactly what it needs, and "one walk per ledger" becomes a property of the API instead of a promise each bundle's doc comment has to make:

// hot: one walk, both products
parts, err := ingest.ExtractLedgerTxParts(lcm)
events, err := ingest.EventsFromTxParts(parts)
fees, err := ingest.FeesFromTxParts(parts)

// cold: one walk, fees never computed
parts, err := ingest.ExtractLedgerTxParts(lcm)
events, err := ingest.EventsFromTxParts(parts)

// fee-only replay (stellar/stellar-rpc#888): same two calls, fees instead of events
parts, err := ingest.ExtractLedgerTxParts(lcm)
fees, err := ingest.FeesFromTxParts(parts)

There is a catch: that signature is only possible if we stop copying v1 exactly. v1 answers two questions by reading the envelope: is this transaction soroban, and how many operations does it have. Envelopes live in the TxSet, and the only way to match a TxSet envelope to its result is to hash every envelope with the network passphrase. That matching is the entire reason ExtractFees needs a passphrase and a second pass over the ledger.

But on any ledger the current protocol can produce, both answers are already sitting in TxProcessing. A transaction is soroban exactly when its meta carries SorobanMeta (soroban transactions always have exactly one operation, and the fee-breakdown ext is always present since protocol 21). The operation count is just the number of per-operation results in the result. So on real ledgers the envelope adds nothing.

The one real difference is txINTERNAL_ERROR, a result core emits only when it malfunctions. It has no per-operation list, so v1 counts that transaction and this definition skips it. That is one sample in a distribution over dozens of ledgers, from a transaction that says nothing about what a fee bidder should pay. For the stellar/stellar-rpc#883 harness this means getFeeStats compares identical on all real traffic, and if the soak ever shows a difference, core had an incident, not rpc a bug.

In exchange, the pairing pass, the per-envelope hashing, and the passphrase leave ingestion entirely. Fees become a plain fold over the walk output like every other product, and hot and cold are both exactly one walk per ledger with nothing extra.

For this PR that means the classification arithmetic and the meta reading carry over (sorobanFeesFromMeta, the negative-fee errors; the deliberate uint64 underflow wrap should become an error, since with the parity requirement gone there is no reason to preserve it), while the pairing machinery (feeShapesByHash, the envelope shape reading) deletes, and the tests re-target the TxProcessing-only rules: the TxSet-shape and passphrase cases go away, and cells for results-derived op counts (failed multi-op, fee-bump inner results, txINTERNAL_ERROR skipped) come in. The fallout for the rest of the family is the bundles themselves, all three of which delete: ExtractTxHashes (that consumer reads parts[i].Hash), ExtractLedgerEvents (with LedgerTransactionEvents slimming to an events-only type aligned with parts), and ExtractFees (its classification moves to FeesFromTxParts). LedgerFees slims to the two buckets, since the ledger sequence and close time are the caller's. After the reshape the package exports one walk and one function per product, nothing else.

@karthikiyer56

Copy link
Copy Markdown
Contributor Author

@tamirms - responding here to segments of your comment here


Re:

walking the ledger and reading products off it are different jobs, and only the walk is worth sharing (...) "one walk per ledger" becomes a property of the API instead of a promise each bundle's doc comment has to make

this wasnt lost on me fwiw.
i had it penciled in as a fast followup once 772 landed — unify the ingestion facets so hot/cold/replay all ride a single walk.
That being said, I see no reason to punt it anymore.
everything here is still Experimental: so reshaping now is cheap, and it only gets more expensive once rpc v2 starts consuming it or changing it after the fact

the bigger consequence is what this does to the tickets.
this body of work stops being "fee stuff" and becomes "walk the ledger exactly once during ingestion — backfill or streaming — and derive everything you need off that one walk".
fees then falls out naturally as one more product of the walk, same as events and txhashes.


Re:

The one real difference is txINTERNAL_ERROR, a result core emits only when it malfunctions. (...) if the soak ever shows a difference, core had an incident, not rpc a bug.

ngl this is a refreshing take, and one i shouldve arrived at myself. i was treating v1's mechanism as the contract and porting its misgivings over bug-for-bug just so i could say "parity".
but parity for paritys sake isnt the goal — identical answers on real traffic is.
I will make the changes for it to error out

…as functions

Per tamirms' review on #5966 (spec: stellar/stellar-rpc#912): walking the
ledger and reading products off it are different jobs, and only the walk
is worth sharing. ExtractLedgerTxParts owns the single TxProcessing walk
and returns per-tx handles; EventsFromTxParts and FeesFromTxParts are
plain functions of those handles. The ExtractTxHashes /
ExtractLedgerEvents / ExtractFees bundles delete, along with the fee
path's envelope pairing, whole-TxSet hashing, and passphrase parameter.

Fee classification now reads TxProcessing alone: soroban iff SorobanMeta
present, opCount = per-operation result count. Matches v1's IngestFees on
every ledger a correctly functioning core produces; deliberate deltas:
txINTERNAL_ERROR skipped, resource fee above FeeCharged errors instead
of wrapping.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikiyer56 karthikiyer56 changed the title ingest: add ExtractFees, a zero-copy view-based fee extractor ingest: one ledger walk — ExtractLedgerTxParts + EventsFromTxParts/FeesFromTxParts (supersedes the extractor bundles) Aug 3, 2026
@karthikiyer56
karthikiyer56 requested a review from Copilot August 3, 2026 06:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (1)

ingest/extract.go:234

  • The signed addition can underflow back to a non-negative value: for example, two math.MinInt64 components produce 0, bypass this check, and yield an inclusion fee even though the resource-fee sum is negative. Reject negative components before adding them so corrupt values cannot wrap through the validation; a regression case for this boundary would also prevent recurrence.
		// int64 addition first: two huge fees wrap negative and hit the error
		// below rather than summing wide.
		resourceFee := nonRefundable + refundable
		if resourceFee < 0 {
			return 0, feeBucketNone, fmt.Errorf("ingest: tx %x: resource fee charged cannot be negative", txParts.Hash)

…Parts

A sum-only negativity check can be wrapped through: two huge negative
components sum back to non-negative (two MinInt64s make exactly 0) and a
negative component can hide behind a larger positive one. Check each
component first; with both non-negative, a negative sum can only be int64
overflow, reported as such.

Surfaced by Copilot's re-review (its one suppressed comment).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tamirms

tamirms commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

The reshape lands exactly as proposed: the classification, the error edges, and the test matrix all read right to me, and TestFeesFromTxParts_TxSetNotConsulted pins the property this was all for. One correction, to a claim that originated in my comment and that the PR now states in several places: that txINTERNAL_ERROR is the only transaction core can put in a ledger without a per-operation result list, so the only skip-divergence from v1 short of a core malfunction.

That is not quite true. Core re-runs transaction validation at apply time (TransactionFrame::commonPreApply runs commonValid with applying=true), and a transaction that fails there still lands in TxProcessing with its fee charged, a tx-level error code, and no per-operation results. On current protocol the consensus rules close every accidental path to this: generalized tx sets enforce one transaction per source account, and both the queue and the set validity check key fee-bumps by the inner source, so ordinary sequence races cannot produce it. One path stays open: an account can sign an operation inside another account's transaction that invalidates its own pending transaction in the same ledger. Account merge produces txNO_ACCOUNT, removing its own signer produces txBAD_AUTH, bump-sequence produces txBAD_SEQ. All of these need the account's own signature, so they are self-inflicted and absent from organic traffic, but a correctly functioning network will happily include them. Separately, pre-protocol-20 tx sets allowed several transactions per account, so old ledgers contain such failures organically; fee stats only ever ingests tip, but the doc comment describes a public function someone can point at history.

I think the behavior should stay exactly as is. Skipping these is the same principled rule as the rest of the classification (count a transaction when its record carries what the observation needs), the dropped samples say nothing a fee bidder should act on, and the soroban bucket is untouched by all of this: core writes the fee ext before validation runs (setNonRefundableResourceFee is called from commonPreApply), so even a never-executed soroban transaction carries its charged fees and v1 and this code count it identically. So this is a wording fix, plus one framing fix for the stellar/stellar-rpc#883 soak: a getFeeStats divergence means "go look at that ledger" (core malfunction, or someone constructed a self-invalidating pair), not "core had an incident" full stop.

Suggested wording for the comparison paragraph on FeesFromTxParts:

// The output matches stellar-rpc v1's FeeWindows.IngestFees on organic
// current-protocol traffic, but the definition differs: v1 classifies from
// the ENVELOPE (a single operation of a soroban type; opCount = envelope
// operations), this classifies from TxProcessing alone as described above.
// The behavioral deltas are confined to classic transactions whose
// operations never ran, so their results carry no per-operation list: v1
// counts them from the envelope, this skips them. Only two things put such
// a transaction in a ledger: a core malfunction (txINTERNAL_ERROR), or an
// account invalidating its own pending transaction with an operation it
// signed inside another account's transaction in the same ledger (account
// merge, signer removal, sequence bump). Pre-protocol-20 tx sets also
// allowed several transactions per account, so old ledgers contain such
// failures organically; fee stats only ever ingests tip ledgers. v1 also
// lets a resource fee above FeeCharged wrap around uint64 where this
// errors.

and for the LedgerFees skip bullet:

//   - A transaction with no per-operation result list is skipped. That
//     covers txINTERNAL_ERROR (core malfunction) and transactions
//     invalidated by an earlier transaction in the same ledger before their
//     operations ran (possible when an account signs an operation against
//     itself inside another account's transaction).

The same sentence recurs in the classifyTxFee inline comment, the feeInternalErrorResult helper comment, the changelog entry, and the description's parity-contract line (and the stellar/stellar-rpc#912 copy); they all take the same one-line widening. Two cheap additions while in there, both optional: a no_account_skipped cell in the matrix (same code path as txINTERNAL_ERROR, but it pins that the skip is intentional for the whole void-code family, not a txINTERNAL_ERROR special case), and one sentence on LedgerTxParts noting that FeeBump is derived from the result code, so a fee-bump that never executed reports FeeBump=false with no inner hash. That last one is inherent to reading TxProcessing only (a void outer result carries no inner pair) and only reachable through the same constructed cases, but consumers building hash indexes off the walk should get to read it rather than discover it.

One item from auditing the view usage, separate from the parity note. v4EventRaws is the multi-field case Fields() exists for: it reads the V4 meta through single-field accessors, and each accessor re-sizes the struct prefix from the top. On the product path (wantEvents only) the overlap is just ext plus txChangesBefore, but on the read path (metaEventRaws with wantDiag) DiagnosticEvents is the last field, so MustDiagnosticEvents walks the entire meta interior, operations included, a second time per transaction:

// today: three prefix walks over the same V4 meta
tev.TransactionEvents = collectRaws(metaV4View.MustEvents().MustIter())
opsView := metaV4View.MustOperations()
// ...
*diag = collectRaws(metaV4View.MustDiagnosticEvents().MustIter())

// one locate pass
f := mustView(metaV4View.Fields())
tev.TransactionEvents = collectRaws(f.Events.MustIter())
// ... f.Operations ...
*diag = collectRaws(f.DiagnosticEvents.MustIter())

The V3 arm has the same shape one level down when both event sets are wanted: MustEvents plus MustDiagnosticEvents on the SorobanMeta view re-sizes the events vector, and SorobanTransactionMetaView.Fields() covers it. Fields() is error-returning with no generated Must twin, so the Must-style walkers need either a small local shim that panics with the returned *xdr.ViewError (TryVoid already recovers those) or a generated MustFields(), which may be worth adding to the generator regardless. The per-op double sizing inside the loop (Iter() advances by re-sizing elements the body also reads) is a generator limitation rather than a call-site problem, fine to leave as is.

… walker

Per tamirms' review: the no-per-op-results family is not just
txINTERNAL_ERROR. An account can invalidate its own pending transaction
via an operation it signed inside another account's transaction (account
merge, signer removal, sequence bump), and pre-protocol-20 tx sets
allowed several transactions per account, so old ledgers carry such
never-ran failures organically. The docs now say so in plain English
with a worked example; classification behavior is unchanged. Adds the
no_account_skipped matrix cell (the skip is a family rule, not a
txINTERNAL_ERROR special case) and the LedgerTxParts disclosure that
FeeBump derives from the result code — a never-ran fee-bump reads as a
plain transaction with no inner hash.

metaEventRaws' V4 arm now locates all fields in one Fields() pass
instead of per-field prefix walks: DiagnosticEvents is the last field,
so its accessor re-walked the whole meta interior once more per
transaction on the read path (~10% on a synthetic V4 walker, growing
with op count; the pubnet fixture is protocol 22/all-V3 where the arm
never runs). V3 uses the locate pass only when both event sets are
wanted; with one set the single accessor sizes strictly less. mustFields
is the local Must twin that Fields() lacks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikiyer56

Copy link
Copy Markdown
Contributor Author

That is not quite true. (...) One path stays open: an account can sign an operation inside another account's transaction that invalidates its own pending transaction in the same ledger.

Taken in full — thanks for the catch, and for the pre-protocol-20 history note. All the doc sites now describe the whole never-ran family instead of "txINTERNAL_ERROR only": the FeesFromTxParts comparison paragraph, the LedgerFees skip bullet, the classifyTxFee / txOperationCount inline comments, the test-helper comment, and the changelog. I kept your content but wrote it out in plain English with the self-invalidation example inline (Alice's payment + Bob's transaction carrying an Alice-signed merge/signer-removal/sequence-bump), so the next reader doesn't have to re-derive how such a transaction gets into a ledger. Your soroban note landed too — the docs now say why the soroban bucket is untouched (the fee ext is written before validation can kill the tx).

Behavior unchanged everywhere. The PR description, stellar/stellar-rpc#912, and stellar/stellar-rpc#881 got the same widening, and the #883 framing everywhere is now "a divergence means go look at that ledger", not "core had an incident" full stop. (fa830cc)

@karthikiyer56

Copy link
Copy Markdown
Contributor Author

Both optional additions taken as well:

  • no_account_skipped now sits next to internal_error_skipped in the matrix (the builder generalized to feeNoOpListResult(fee, code)). Two different codes, same outcome — the tests now read as "any transaction whose result has no per-operation list skips", so nobody later mistakes the skip for a txINTERNAL_ERROR special case and "fixes" it.
  • LedgerTxParts discloses the FeeBump derivation: FeeBump comes from the result code (the only place TxProcessing carries the inner hash), so a fee-bump whose operations never ran reports FeeBump=false with a zero InnerHash — and a hash index built from the walk will not find that transaction by its inner hash. Index builders read it in the doc now instead of discovering it in production. (fa830cc)

@karthikiyer56

Copy link
Copy Markdown
Contributor Author

v4EventRaws is the multi-field case Fields() exists for

Done, with measurements — and one honest wrinkle: the pubnet fixture can't show this fix at all. ledger_58752000 is protocol 22, so all 249 metas are V3 and the V4 arm never runs there. So I benchmarked the walker directly on a synthetic V4 meta (10 ops × 3 events each, both event sets wanted): ~4.5µs → ~4.1µs per meta (~10%), and the win grows with op count since the saved work is exactly the DiagnosticEvents accessor re-walking every operation. Events-only measured parity on that shape.

  • V4 arm: one Fields() locate pass unconditionally — Events and Operations sit deep in the struct, so even single-set reads paid overlapping prefix walks.
  • V3 arm: locate pass only when BOTH sets are wanted, per your scoping. With one set wanted the single accessor sizes strictly less than a full locate, and on the real all-V3 ledger the read path measured parity both ways — V3's prefix fields (a 4-byte ext, a small events vector) are too cheap for the dedup to matter.
  • The shim: a local mustFields that panics with the returned *xdr.ViewError (the existing TryVoid wrappers recover it), mirroring the generated Must accessors. I left MustFields() on the generator as a follow-up rather than smuggling a regen of xdr_views_generated.go into this PR.
  • Per-op double-sizing inside the loop left as is, as you said. (fa830cc)

@karthikiyer56
karthikiyer56 merged commit 3114a80 into main Aug 4, 2026
11 checks passed
@karthikiyer56
karthikiyer56 deleted the extract-fees-view branch August 4, 2026 00:48
hypekostas pushed a commit to stellar/stellar-disbursement-platform-backend that referenced this pull request Aug 17, 2026
… updates (#1185)

Yes — the previous response still rendered the Markdown. You want the **literal Markdown source**, with no HTML tags at all.

```markdown
Bumps the minor-and-patch group with 7 updates in the `/` directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.43.0` | `1.43.5` |
| [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) | `1.32.31` | `1.32.36` |
| [github.com/aws/aws-sdk-go-v2/service/ses](https://github.com/aws/aws-sdk-go-v2) | `1.37.0` | `1.37.5` |
| [github.com/aws/aws-sdk-go-v2/service/sns](https://github.com/aws/aws-sdk-go-v2) | `1.42.0` | `1.42.5` |
| [github.com/stellar/go-stellar-sdk](https://github.com/stellar/go-stellar-sdk) | `0.6.0` | `0.7.2` |
| [golang.org/x/crypto](https://github.com/golang/crypto) | `0.54.0` | `0.55.0` |
| [golang.org/x/net](https://github.com/golang/net) | `0.57.0` | `0.58.0` |

Updates `github.com/aws/aws-sdk-go-v2` from 1.43.0 to 1.43.5

### Commits

- [`a14f5f1`](aws/aws-sdk-go-v2@a14f5f1) Release 2026-08-10
- [`339f0b6`](aws/aws-sdk-go-v2@339f0b6) Regenerated Clients
- [`0978e3d`](aws/aws-sdk-go-v2@0978e3d) Update API model
- [`3cc614d`](aws/aws-sdk-go-v2@3cc614d) Fix codegen mp ([#3508](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3508))
- [`1434b18`](aws/aws-sdk-go-v2@1434b18) generate response snapshots for json ([#3507](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3507))
- [`ad58f77`](aws/aws-sdk-go-v2@ad58f77) Checkout smithy-go on PRs at the commit pointed out by SMITHY_GO_CODEGEN_VERS...
- [`c002860`](aws/aws-sdk-go-v2@c002860) feat: move close-body, logger, and service-metadata work out of the middlewar...
- [`f152336`](aws/aws-sdk-go-v2@f152336) Release 2026-08-07
- [`37d88d7`](aws/aws-sdk-go-v2@37d88d7) Regenerated Clients
- [`c54b278`](aws/aws-sdk-go-v2@c54b278) Update endpoints model
- Additional commits viewable in [compare view](aws/aws-sdk-go-v2@v1.43.0...v1.43.5)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.32.31 to 1.32.36

### Commits

- [`a14f5f1`](aws/aws-sdk-go-v2@a14f5f1) Release 2026-08-10
- [`339f0b6`](aws/aws-sdk-go-v2@339f0b6) Regenerated Clients
- [`0978e3d`](aws/aws-sdk-go-v2@0978e3d) Update API model
- [`3cc614d`](aws/aws-sdk-go-v2@3cc614d) Fix codegen mp ([#3508](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3508))
- [`1434b18`](aws/aws-sdk-go-v2@1434b18) generate response snapshots for json ([#3507](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3507))
- [`ad58f77`](aws/aws-sdk-go-v2@ad58f77) Checkout smithy-go on PRs at the commit pointed out by SMITHY_GO_CODEGEN_VERS...
- [`c002860`](aws/aws-sdk-go-v2@c002860) feat: move close-body, logger, and service-metadata work out of the middlewar...
- [`f152336`](aws/aws-sdk-go-v2@f152336) Release 2026-08-07
- [`37d88d7`](aws/aws-sdk-go-v2@37d88d7) Regenerated Clients
- [`c54b278`](aws/aws-sdk-go-v2@c54b278) Update endpoints model
- Additional commits viewable in [compare view](aws/aws-sdk-go-v2@config/v1.32.31...config/v1.32.36)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.30 to 1.19.35

### Commits

- [`a14f5f1`](aws/aws-sdk-go-v2@a14f5f1) Release 2026-08-10
- [`339f0b6`](aws/aws-sdk-go-v2@339f0b6) Regenerated Clients
- [`0978e3d`](aws/aws-sdk-go-v2@0978e3d) Update API model
- [`3cc614d`](aws/aws-sdk-go-v2@3cc614d) Fix codegen mp ([#3508](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3508))
- [`1434b18`](aws/aws-sdk-go-v2@1434b18) generate response snapshots for json ([#3507](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3507))
- [`ad58f77`](aws/aws-sdk-go-v2@ad58f77) Checkout smithy-go on PRs at the commit pointed out by SMITHY_GO_CODEGEN_VERS...
- [`c002860`](aws/aws-sdk-go-v2@c002860) feat: move close-body, logger, and service-metadata work out of the middlewar...
- [`f152336`](aws/aws-sdk-go-v2@f152336) Release 2026-08-07
- [`37d88d7`](aws/aws-sdk-go-v2@37d88d7) Regenerated Clients
- [`c54b278`](aws/aws-sdk-go-v2@c54b278) Update endpoints model
- Additional commits viewable in [compare view](aws/aws-sdk-go-v2@credentials/v1.19.30...credentials/v1.19.35)

Updates `github.com/aws/aws-sdk-go-v2/service/ses` from 1.37.0 to 1.37.5

### Commits

- [`b4784c1`](aws/aws-sdk-go-v2@b4784c1) Release 2026-07-01
- [`97c0201`](aws/aws-sdk-go-v2@97c0201) Regenerated Clients
- [`6687238`](aws/aws-sdk-go-v2@6687238) Update endpoints model
- [`995297f`](aws/aws-sdk-go-v2@995297f) Update API model
- [`c26cfc6`](aws/aws-sdk-go-v2@c26cfc6) Fix bump smithy-go to cover multiple issues ([#3461](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3461))
- [`fae66b8`](aws/aws-sdk-go-v2@fae66b8) Set transfer manager error as the first error seen, preventing race condition...
- [`cf0eabd`](aws/aws-sdk-go-v2@cf0eabd) Release 2026-06-30
- [`ad0c091`](aws/aws-sdk-go-v2@ad0c091) Regenerated Clients
- [`196e961`](aws/aws-sdk-go-v2@196e961) Update endpoints model
- [`1529ead`](aws/aws-sdk-go-v2@1529ead) Update API model
- Additional commits viewable in [compare view](aws/aws-sdk-go-v2@v1.37.0...service/pi/v1.37.5)

Updates `github.com/aws/aws-sdk-go-v2/service/sns` from 1.42.0 to 1.42.5

### Commits

- [`dcbed91`](aws/aws-sdk-go-v2@dcbed91) Release 2026-01-09
- [`08120e8`](aws/aws-sdk-go-v2@08120e8) Regenerated Clients
- [`1d7a925`](aws/aws-sdk-go-v2@1d7a925) Update endpoints model
- [`482067d`](aws/aws-sdk-go-v2@482067d) Update API model
- [`4662404`](aws/aws-sdk-go-v2@4662404) remove example ([#3282](https://redirect.github.com/aws/aws-sdk-go-v2/issues/3282))
- [`c28a6f4`](aws/aws-sdk-go-v2@c28a6f4) Release 2026-01-07
- [`2fa7a72`](aws/aws-sdk-go-v2@2fa7a72) Regenerated Clients
- [`077cbaa`](aws/aws-sdk-go-v2@077cbaa) Update endpoints model
- [`3282dbc`](aws/aws-sdk-go-v2@3282dbc) Update API model
- [`3daa74a`](aws/aws-sdk-go-v2@3daa74a) Release 2026-01-06
- Additional commits viewable in [compare view](aws/aws-sdk-go-v2@v1.42.0...service/amp/v1.42.5)

Updates `github.com/stellar/go-stellar-sdk` from 0.6.0 to 0.7.2

### Release Notes

Source: [github.com/stellar/go-stellar-sdk releases](https://github.com/stellar/go-stellar-sdk/releases)

#### v0.7.2

##### What's Changed

- xdr: compare assets by their XDR encoding, and use Equals for asset equality by [@karthikiyer56](https://github.com/karthikiyer56) in [stellar/go-stellar-sdk#5974](https://redirect.github.com/stellar/go-stellar-sdk/pull/5974)
- txnbuild: consolidate liquidity pool ordering guards; xdr and ingest cleanups by [@karthikiyer56](https://github.com/karthikiyer56) in [stellar/go-stellar-sdk#5978](https://redirect.github.com/stellar/go-stellar-sdk/pull/5978)
- strkey: enforce SEP-23 payload lengths in Decode and DecodeAny by [@karthikiyer56](https://github.com/karthikiyer56) in [stellar/go-stellar-sdk#5977](https://redirect.github.com/stellar/go-stellar-sdk/pull/5977)

**Full Changelog:** [v0.7.1...v0.7.2](stellar/go-stellar-sdk@v0.7.1...v0.7.2)

#### v0.7.1

##### What's Changed

- stellartoml: validate domain in GetStellarToml for parity with sibling by [@karthikiyer56](https://github.com/karthikiyer56) in [stellar/go-stellar-sdk#5970](https://redirect.github.com/stellar/go-stellar-sdk/pull/5970)
- ingest: one ledger walk — ExtractLedgerTxParts + EventsFromTxParts/FeesFromTxParts (supersedes the extractor bundles) by [@karthikiyer56](https://github.com/karthikiyer56) in [stellar/go-stellar-sdk#5966](https://redirect.github.com/stellar/go-stellar-sdk/pull/5966)

**Full Changelog:** [v0.7.0...v0.7.1](stellar/go-stellar-sdk@v0.7.0...v0.7.1)

#### v0.7.0

##### What's Changed

- ingest,network,xdr: zero-copy XDR view extractors for full-history ingestion by [@chowbao](https://github.com/chowbao) in [stellar/go-stellar-sdk#5949](https://redirect.github.com/stellar/go-stellar-sdk/pull/5949)
- xdr,xdrgen,ingest: extend xdr views (decoded discriminants, typed opaque, count validation, Fields) and rebuild the view extractors on them by [@tamirms](https://github.com/tamirms) in [stellar/go-stellar-sdk#5951](https://redirect.github.com/stellar/go-stellar-sdk/pull/5951)
- protocols/rpc: add UseUpgradedAuth flag to SimulateTransactionRequest by [@Ryang-21](https://github.com/Ryang-21) in [stellar/go-stellar-sdk#5948](https://redirect.github.com/stellar/go-stellar-sdk/pull/5948)
- protocols/rpc: Add LedgerCloseTime to GetHealthResponse by [@felixl256](https://github.com/felixl256) in [stellar/go-stellar-sdk#5958](https://redirect.github.com/stellar/go-stellar-sdk/pull/5958)
- ingest/loadtest: expand loadtest functionality to handle multiple ledger bundles by [@cjonas9](https://github.com/cjonas9) in [stellar/go-stellar-sdk#5959](https://redirect.github.com/stellar/go-stellar-sdk/pull/5959)
- ingest: expose fee-bump inner hashes on the view extractors by [@tamirms](https://github.com/tamirms) in [stellar/go-stellar-sdk#5964](https://redirect.github.com/stellar/go-stellar-sdk/pull/5964)
- ingest/ledgerbackend: Update captive-core-pubnet.cfg: swap SP with Obsrvr by [@drebelsky](https://github.com/drebelsky) in [stellar/go-stellar-sdk#5963](https://redirect.github.com/stellar/go-stellar-sdk/pull/5963)
- Protocol 28 (CAP-0085) by [@sisuresh](https://github.com/sisuresh) in [stellar/go-stellar-sdk#5965](https://redirect.github.com/stellar/go-stellar-sdk/pull/5965)

##### New Contributors

- [@Ryang-21](https://github.com/Ryang-21) made their first contribution in [stellar/go-stellar-sdk#5948](https://redirect.github.com/stellar/go-stellar-sdk/pull/5948)
- [@felixl256](https://github.com/felixl256) made their first contribution in [stellar/go-stellar-sdk#5958](https://redirect.github.com/stellar/go-stellar-sdk/pull/5958)

**Full Changelog:** [v0.6.0...v0.7.0](stellar/go-stellar-sdk@v0.6.0...v0.7.0)

#### v0.6.1

##### What's Changed

- Backports for Horizon 27.0.1 (release-0.6.1) by [@karthikiyer56](https://github.com/karthikiyer56) in [stellar/go-stellar-sdk#5979](https://redirect.github.com/stellar/go-stellar-sdk/pull/5979)

**Full Changelog:** [v0.6.0...v0.6.1](stellar/go-stellar-sdk@v0.6.0...v0.6.1)

### Changelog

Source: [github.com/stellar/go-stellar-sdk changelog](https://github.com/stellar/go-stellar-sdk/blob/main/CHANGELOG.md)

# Changelog

This repository adheres to [Go module Versioning](https://go.dev/doc/modules/version-numbers).

This monorepo contains a number of SDKs:

- `horizonclient` ([changelog](https://github.com/stellar/go-stellar-sdk/blob/main/clients/horizonclient/CHANGELOG.md))
- `txnbuild` ([changelog](https://github.com/stellar/go-stellar-sdk/blob/main/txnbuild/CHANGELOG.md))
- `rpcclient` ([changelog](https://github.com/stellar/go-stellar-sdk/blob/main/clients/rpcclient/CHANGELOG.md))
- `corelient` ([changelog](https://github.com/stellar/go-stellar-sdk/blob/main/clients/stellarcore/CHANGELOG.md))

Official project releases may be found here: [https://github.com/stellar/go-stellar-sdk/releases](https://github.com/stellar/go-stellar-sdk/releases)

## Pending

### New Features

- protocols/rpc: Add `LatestLedgerCloseTime` and `OldestLedgerCloseTime` to `GetHealthResponse`, exposing the latest and oldest ledgers' close times (unix seconds) on the `getHealth` response ([#5958](https://redirect.github.com/stellar/go-stellar-sdk/pull/5958))

### Breaking Changes

- strkey: `Decode` and `DecodeAny` now validate the payload length against the version byte per [SEP-23](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md). Fixed-length keys (account ID, seed, muxed account, contract, liquidity pool, claimable balance, hashTx, hashX) must decode to their exact canonical size, and signed payloads must carry a declared payload length of 1–64 bytes matched by their zero padding. Inputs with a valid checksum but a wrong-length payload — previously accepted by `Decode`, `DecodeAny`, and every `IsValid*` helper — are now rejected ([#5977](https://redirect.github.com/stellar/go-stellar-sdk/pull/5977)).
  - `NewSignedPayload` rejects empty payloads, matching CAP-40 (the protocol fails such signers with `SET_OPTIONS_BAD_SIGNER`/`txMALFORMED`) and keeping `SignedPayload.Encode` output decodable.
  - Length re-checks that `Decode` now subsumes were removed from `xdr.AccountId.SetAddress`, `xdr.MuxedAccount.SetAddress`, `xdr.SignerKey.SetAddress`, `xdr.ClaimableBalanceId.DecodeFromStrkey`, `strkey.DecodeMuxedAccount`, `strkey.MuxedAccount.SetAccountID`, and txnbuild contract-address parsing. For wrong-length inputs, the xdr and txnbuild callers now return strkey's `invalid payload length` error instead of their own; the strkey muxed-account helpers keep their generic `invalid muxed account` / `invalid ed25519 public key` errors; `xdr.MuxedAccount.SetAddress` is unchanged (it rejects on encoded string length before decoding).
  - `keypair.ParseAddress` wraps every decode failure with `ErrInvalidKey`, so `errors.Is(err, ErrInvalidKey)` keeps matching wrong-length keys (and now also matches checksum/encoding failures, which previously returned the bare strkey error).
  - `DecodeSignedPayload` delegates structure validation to `Decode`; structurally invalid inputs now uniformly error with `invalid signed payload` (previously `signed payload too short: ...` or `invalid signed payload padding`).
- xdr: `Asset.LessThan` now orders assets the way the protocol does — by the raw 32-byte issuer key — instead of by base32 strkey text, and `xdr.NewPoolId` requires strictly `a < b`, rejecting reversed and identical pairs ([#5974](https://redirect.github.com/stellar/go-stellar-sdk/pull/5974))
- txnbuild: liquidity pool operations reject asset pairs that are not strictly ordered; see the [txnbuild changelog](https://github.com/stellar/go-stellar-sdk/blob/main/txnbuild/CHANGELOG.md) ([#5974](https://redirect.github.com/stellar/go-stellar-sdk/pull/5974))

### Bug Fixes

- processors/token_transfer: trustline revocation now compares liquidity pool assets by value instead of pointer identity, fixing wrong-leg selection when burning pool shares ([#5974](https://redirect.github.com/stellar/go-stellar-sdk/pull/5974))

## [0.7.0]

### New Features

- xdr: Protocol 28 support (CAP-0083, CAP-0085). XDR regenerated from [stellar-xdr@9c9c1459](stellar/stellar-xdr@9c9c145), the commit stellar-core 28.0.0 pins; both CAPs are ungated upstream so `XDR_FEATURES` is now empty.

### Commits

- [`b46a463`](stellar/go-stellar-sdk@b46a463) strkey: enforce SEP-23 payload lengths in Decode and DecodeAny ([#5977](https://redirect.github.com/stellar/go-stellar-sdk/issues/5977))
- [`f8cd5df`](stellar/go-stellar-sdk@f8cd5df) txnbuild: consolidate liquidity pool ordering guards; xdr and ingest cleanups...
- [`d2f530f`](stellar/go-stellar-sdk@d2f530f) xdr: compare assets by their XDR encoding, and use Equals for asset equality ...
- [`3114a80`](stellar/go-stellar-sdk@3114a80) ingest: one ledger walk — ExtractLedgerTxParts + EventsFromTxParts/FeesFromTx...
- [`3c3872f`](stellar/go-stellar-sdk@3c3872f) stellartoml: validate domain in GetStellarToml for parity with sibling ([#5970](https://redirect.github.com/stellar/go-stellar-sdk/issues/5970))
- [`2b16db0`](stellar/go-stellar-sdk@2b16db0) Protocol 28 Support ([#5969](https://redirect.github.com/stellar/go-stellar-sdk/issues/5969))
- [`e5d0cb9`](stellar/go-stellar-sdk@e5d0cb9) Merge main into protocol-next ahead of the Protocol 28 GA merge
- [`149b994`](stellar/go-stellar-sdk@149b994) Finalize Protocol 28: pin stellar-xdr @ `9c9c1459` ([#5968](https://redirect.github.com/stellar/go-stellar-sdk/issues/5968))
- [`82df764`](stellar/go-stellar-sdk@82df764) Protocol 28 (CAP-0085) XDR regeneration ([#5965](https://redirect.github.com/stellar/go-stellar-sdk/issues/5965))
- [`8dd9cad`](stellar/go-stellar-sdk@8dd9cad) Update captive-core-pubnet.cfg: swap SP with Obsrvr ([#5963](https://redirect.github.com/stellar/go-stellar-sdk/issues/5963))
- Additional commits viewable in [compare view](stellar/go-stellar-sdk@v0.6.0...v0.7.2)

Updates `golang.org/x/crypto` from 0.54.0 to 0.55.0

### Commits

- [`f44d03d`](golang/crypto@f44d03d) go.mod: update golang.org/x dependencies
- [`5ed4944`](golang/crypto@5ed4944) crypto/internal/poly1305: provide optimised assembly for riscv64
- [`b07833c`](golang/crypto@b07833c) ssh: return window credit for discarded extended data
- [`d701c51`](golang/crypto@d701c51) acme: fix nil pointer dereference in pebble test error reporting
- [`999d053`](golang/crypto@999d053) ssh: fix parsing of GSSAPI payloads offering multiple mechanisms
- [`90f76b8`](golang/crypto@90f76b8) ssh: reject certificate signature keys before recursing
- [`b53964a`](golang/crypto@b53964a) ssh: permit empty but non-nil HostKeyAlgorithms, KeyExchanges, Ciphers, MACs
- [`626e40f`](golang/crypto@626e40f) ssh: drain stderr on forwarded TCP and Unix channels
- [`31914c6`](golang/crypto@31914c6) x509roots/fallback: update bundle
- [`f2135b8`](golang/crypto@f2135b8) all: clean up minor issues found by staticcheck
- Additional commits viewable in [compare view](golang/crypto@v0.54.0...v0.55.0)

Updates `golang.org/x/net` from 0.57.0 to 0.58.0

### Commits

- [`acc78e0`](golang/net@acc78e0) go.mod: update golang.org/x dependencies
- [`90d10f0`](golang/net@90d10f0) internal/http3: delete invalid Content-Length if declared in server handler
- [`08abf4d`](golang/net@08abf4d) internal/http3: infer headers when Content-Encoding is set but is empty
- [`8d10596`](golang/net@8d10596) http2: avoid deadlocks in wrapped ClientConn state callback
- [`99c3b0a`](golang/net@99c3b0a) http2/hpack: build the table lookup maps lazily, only for encoders
- [`5a920b1`](golang/net@5a920b1) http3: rework registration to allow using a fake network
- [`7fd2842`](golang/net@7fd2842) quic: return an error from Accept after PacketConn reader exits
- [`825111d`](golang/net@825111d) quic: avoid busy-loop when keep-alive is blocked by congestion control
- [`a02ddfa`](golang/net@a02ddfa) http/httpproxy: prioritize lowercase proxy environment variables
- [`574e5eb`](golang/net@574e5eb) quic: halt conn goroutines on close when listener exits early
- Additional commits viewable in [compare view](golang/net@v0.57.0...v0.58.0)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

---

You can trigger Dependabot actions by commenting on this PR:

- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove all of the ignore conditions of the specified dependency
```
Shaptic added a commit that referenced this pull request Aug 17, 2026
* changelog: cut the Pending section as 0.7.2, and record 0.7.1

v0.7.2 was tagged at b46a463 so that stellar-rpc, Horizon and Galexie
v28.0.0 all pin a released SDK tag for Protocol 28; Horizon had been
pinning a pseudo-version to get #5974. Everything the Pending section
listed ships in it, with two corrections:

* the `protocols/rpc` GetHealthResponse close-time fields (#5958) moved to
  [0.7.0] — that commit is an ancestor of the v0.7.0 tag, so it has been
  released since 2026-08-03.
* added a [0.7.1] section for #5966 and #5970, which were tagged on
  2026-08-04 without a changelog entry, so 0.7.2 does not absorb them.

The ingest/ and txnbuild/ sub-changelogs still carry Pending sections whose
contents span several released versions; untangling those is left alone
here.

* ingest: ApplyLedgerMetadata closes the datastore and ledger backend and
  propagates the PrepareRange error, so an early return no longer strands a
  goroutine per worker and a failed prepare no longer passes silently.
* go.mod: the go-xdr bump to dc590f1, which fixes decoder bound handling for a
  variable-length field whose length prefix ends the input. 0.6.1 recorded this
  bump under Updates; 0.7.2 carries the same one.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

SDK: one TxProcessing walk per ledger — ExtractLedgerTxParts + per-product functions (supersedes the extractor bundles)

3 participants