Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
79d1ed1
add socket tier 1 reachability analysis
kanwalpreetd Jun 30, 2026
41b2f0f
ci: registration stub for the bench-campaign dispatch workflow (#922)
marwen-abid Aug 6, 2026
c86b292
Optimize backfill (#854)
cjonas9 Aug 10, 2026
e3627ca
Bump P28 core package and image to 28.0.0-3494.a9b861321 (#927)
Shaptic Aug 13, 2026
39080fb
Bump grpc to v1.79.3 and install stellar-core without Recommends (#928)
Shaptic Aug 13, 2026
cd243c5
ci: pin the GA stellar-core docker image for the v28.0.0 release
Shaptic Aug 13, 2026
9758b75
CHANGELOG: cover the commits main gained after the release branch was…
Shaptic Aug 13, 2026
e29c911
Pin go-stellar-sdk v0.7.2 for the v28.0.0 release
Shaptic Aug 14, 2026
ca47579
Merge pull request #929 from stellar/release/v28.0.0
Shaptic Aug 17, 2026
58cdd33
Add GetLedgerRaw to LedgerReader, use in getLatestLedger handler (#941)
cjonas9 Aug 22, 2026
93fb51d
socket-scan: address review comments
kanwalpreetd Aug 26, 2026
1dc7b2d
Merge branch 'main' into main
kanwalpreetd Aug 26, 2026
e3e5a3c
Bump grpc, go-jose and opentelemetry to latest (#958)
Shaptic Aug 27, 2026
273f19e
Point integration tests at stellar-core 28.0.1 stable (#957)
karthikiyer56 Aug 27, 2026
ba6b5f6
Merge branch 'main' into release/v28.0.1
karthikiyer56 Aug 28, 2026
9c13d41
Merge pull request #829 from kanwalpreetd/main
kanwalpreetd Aug 28, 2026
7b2f73b
Merge branch 'main' into release/v28.0.1
karthikiyer56 Aug 31, 2026
1ec5abe
Merge pull request #966 from stellar/release/v28.0.1
karthikiyer56 Sep 1, 2026
993efe8
Merge origin/main into feature/full-history
karthikiyer56 Sep 5, 2026
a448bd8
docker: drop the stale 22.04 notes from both Dockerfiles
karthikiyer56 Sep 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .github/workflows/bench-campaign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Bench campaign (EC2)
# Registration stub. GitHub only lists a workflow_dispatch workflow once a file
# exists at this path on the default branch; the real bench-campaign workflow
# lives on feature/full-history until that branch merges.
# The inputs mirror the real workflow's so the dispatch form renders the same
# fields either way.

on:
workflow_dispatch:
inputs:
phase:
description: 'Pacing phase (selects close_interval + the dataset profiles)'
required: true
type: choice
options: ['1', '2', '3']
ingest:
description: 'Which ingest benchmarks to run'
required: false
type: choice
default: both
options: [both, cold, hot, none]
query:
description: 'Run the query suites after ingest'
required: false
type: choice
default: 'no'
options: ['no', 'yes']
runs:
description: 'Repetitions per (dataset, chunk) cell'
required: false
type: string
default: '1'
workers:
description: 'bench-ingest cold --workers (empty = the per-machine default)'
required: false
type: string
default: ''
machine:
description: 'Box size: 2x = m6id.2xlarge, 8x = c6id.8xlarge'
required: false
type: choice
default: 2x
options: [2x, 8x]
ref:
description: 'stellar-rpc ref to benchmark (resolved on the box, not here)'
required: false
type: string
default: feature/full-history
hot_num_ledgers:
description: 'Cap the hot ingest at N ledgers (0 = the whole chunk); shortens a smoke run'
required: false
type: string
default: '0'
run_name:
description: 'Campaign name (empty = phase<N>-<machine>)'
required: false
type: string
default: ''
benchmarks_ref:
description: 'stellar-rpc-benchmarks ref the box runs the campaign from'
required: false
type: string
default: main

jobs:
stub:
name: Registration stub
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- run: |
echo "::error::this ref carries only the registration stub — re-run the dispatch with a branch that has the real bench-campaign workflow (feature/full-history)"
Comment thread
karthikiyer56 marked this conversation as resolved.
exit 1
7 changes: 5 additions & 2 deletions .github/workflows/load-test-coordinator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ jobs:
load-test:
name: ${{ matrix.leg.label }}
needs: plan
if: ${{ needs.plan.outputs.matrix_legs != '[]' }}
strategy:
fail-fast: false # stops one leg's failure from cancelling other legs
matrix:
Expand Down Expand Up @@ -184,7 +185,8 @@ jobs:
CID=""; PREV=""
if [ -n "$PR" ]; then
CID=$(gh api "repos/$REPO/issues/$PR/comments" --paginate \
--jq "map(select(.user.login == \"github-actions[bot]\" and (.body | startswith(\"$MARKER\")))) | .[0].id // empty" || true)
--jq "map(select(.user.login == \"github-actions[bot]\" and
(.body | startswith(\"$MARKER\")))) | .[0].id // empty" || true)
[ -n "$CID" ] && PREV=$(gh api "repos/$REPO/issues/comments/$CID" --jq '.body' || true)
fi

Expand Down Expand Up @@ -221,7 +223,8 @@ jobs:
env:
NEEDS: ${{ toJSON(needs) }}
run: |
FAILED=$(jq -r '[to_entries[] | select(.value.result != "success") | .key] | join(", ")' <<<"$NEEDS")
FAILED=$(jq -r '[to_entries[] | select(.value.result == "failure" or .value.result == "cancelled")
| .key] | join(", ")' <<<"$NEEDS")
if [ -n "$FAILED" ]; then
echo "::error::jobs did not pass: $FAILED"
exit 1
Expand Down
75 changes: 75 additions & 0 deletions .github/workflows/socket-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Socket reachability scan for stellar-rpc.
# For general Socket reachability documentation, see https://docs.socket.dev/docs/full-application-reachability
# Multi-eco: Go (root go.mod) + Rust (Cargo workspace and/or sub-Cargos).
#
# Schedule: Sun 22:00 UTC weekly. Use workflow_dispatch to run on demand.
#
# ============================================================================
# Socket scan — reading the job status. (The scan step below produces this: an
# exit code + an optional ::warning:: annotation, which GitHub Actions renders
# as the job's state.)
# ============================================================================
# GREEN (exit 0, no warning): scan completed and every analyzed vulnerability
# got full Tier 1 reachability (precise, your-code-aware). Nothing to do.
# YELLOW (exit 0 + "::warning:: Socket scan completed with Tier 2 fallbacks"):
# scan completed, but Tier 1 could NOT be computed for some/all
# vulnerabilities, which fell back to Tier 2 (precomputed) reachability.
# You still get CVE detection + Tier 2 results, just reduced precision
# for the affected CVEs. The job is NOT failing.
# RED (non-zero exit): scan did not complete. Do not assume any part
# succeeded — could be reachability hard-failing, a missing language
# toolchain, the runner out of memory, a network/API error, or even the
# underlying CVE/SBOM detection failing. Check the logs and fix before
# relying on results.
# ============================================================================

name: Socket reachability scan

on:
schedule:
- cron: '0 22 * * 0'
workflow_dispatch:

permissions:
contents: read

jobs:
socket-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- run: rustup update
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24.18.0"

- name: Install Socket CLI
run: npm install -g socket

- name: Run Socket reachability scan
env:
SOCKET_SECURITY_API_TOKEN: ${{ secrets.SOCKET_SECURITY_API_TOKEN }}
run: |
# Stream the scan output through tee so the run log captures it AND
# we can grep it for Tier-2-fallback markers; capture the scan's
# exit code via ${PIPESTATUS[0]} (tee always exits 0). If the scan
# succeeded but logged a Tier 2 fallback, emit a ::warning::
# annotation that GitHub Actions renders as a yellow run-level
# warning without failing the job.
set +e
socket scan create --reach \
--org=stellar \
--no-interactive \
--reach-continue-on-no-source-files \
--reach-continue-on-analysis-errors \
--reach-continue-on-install-errors \
--reach-continue-on-missing-lock-files \
. 2>&1 | tee /tmp/scan.log
rc=${PIPESTATUS[0]}
if [ $rc -eq 0 ] && grep -qE "Reachability falls back to Tier 2|fallback to the results from the pre-computed|Reachability falls back to precomputed" /tmp/scan.log; then
echo "::warning::Socket scan completed with Tier 2 fallbacks - some vulnerabilities used precomputed reachability instead of full Tier 1"
fi
exit $rc
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,23 @@
* `getTransactions` now scans at most 10,000 ledgers per request. On a sparse range a page can come back short — or even empty — while still carrying a `cursor`, so a response shorter than `limit` no longer implies end-of-data. Every response carries a `cursor`; to tell a sparse scan window from the tip, compare the cursor's ledger part against `latestLedger` and keep paging while it is below ([#908](https://github.com/stellar/stellar-rpc/pull/908)).
* `getEvents` now rejects malformed contract IDs in filters with `-32602`: a `C…` string with a valid checksum but wrong-length payload used to decode and silently match nothing, and now errors under the SDK's stricter SEP-23 strkey parsing ([#908](https://github.com/stellar/stellar-rpc/pull/908)).

## [v28.0.1](https://github.com/stellar/stellar-rpc/compare/v28.0.0...v28.0.1)

### Fixed
* Integration tests and docker images now use the stellar-core 28.0.1 stable release (`28.0.1-3508.947aad841`).
* Bumped dependencies to latest versions, including `grpc`, `go-jose` and `opentelemetry` ([#958](https://github.com/stellar/stellar-rpc/pull/958)).

## [v28.0.0](https://github.com/stellar/stellar-rpc/compare/v27.1.1...v28.0.0)

### Added
* XDR has been updated to support Protocol 28 (CAP-0083, CAP-0085) ([#913](https://github.com/stellar/stellar-rpc/pull/913)).
* The preflight hosts have been rotated to soroban-env-host 28.0.1 (27.0.1 for the previous protocol) and integration tests now run against stellar-core 28.0.0 ([#913](https://github.com/stellar/stellar-rpc/pull/913)).

### Fixed
* Backfill ingestion is significantly faster: the bulk load defers index creation and batches its writes ([#854](https://github.com/stellar/stellar-rpc/pull/854)).
* Bumped dependencies to latest versions, and the release image no longer installs recommended packages ([#928](https://github.com/stellar/stellar-rpc/pull/928)).
* Bumped `go-stellar-sdk` to [v0.7.2](https://github.com/stellar/go-stellar-sdk/releases/tag/v0.7.2), so strkeys in requests are validated against their [SEP-23](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md) payload length: an address, contract ID or claimable balance ID whose checksum is valid but whose payload length is wrong is now rejected instead of accepted ([#929](https://github.com/stellar/stellar-rpc/pull/929)).

## [v27.1.1](https://github.com/stellar/stellar-rpc/compare/v27.1.0...v27.1.1)

### Fixed
Expand Down
4 changes: 1 addition & 3 deletions cmd/stellar-rpc/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Runtime is ubuntu:22.04 (jammy) with jammy stellar-core packages — v1's long-standing
# production base, kept as-is. v2 (Dockerfile.rpcv2) ships on 24.04; divergence is deliberate.
FROM golang:1.26-bookworm AS build
ARG RUST_TOOLCHAIN_VERSION=stable
ARG REPOSITORY_VERSION
Expand Down Expand Up @@ -42,7 +40,7 @@ RUN wget -O /etc/apt/trusted.gpg.d/apt.llvm.org.asc https://apt.llvm.org/llvm-sn
RUN echo 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main' > /etc/apt/sources.list.d/llvm.list
RUN echo 'deb-src http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main' >> /etc/apt/sources.list.d/llvm.list

RUN apt update && apt install -y stellar-core=${STELLAR_CORE_VERSION}
RUN apt update && apt install -y --no-install-recommends stellar-core=${STELLAR_CORE_VERSION}
RUN apt clean

# Copy the binary from the build stage
Expand Down
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/docker/Dockerfile.release
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ RUN echo 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main' > /etc/ap
RUN echo 'deb-src http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main' >> /etc/apt/sources.list.d/llvm.list

RUN apt update && \
apt install -y stellar-core=${STELLAR_CORE_VERSION} stellar-rpc=${STELLAR_RPC_VERSION} && \
apt install -y --no-install-recommends stellar-core=${STELLAR_CORE_VERSION} stellar-rpc=${STELLAR_RPC_VERSION} && \
apt clean

ENTRYPOINT ["/usr/bin/stellar-rpc"]
6 changes: 3 additions & 3 deletions cmd/stellar-rpc/docker/Dockerfile.rpcv2
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# All stages use ubuntu:24.04 so shared libs built in one stage work in any
# other (same glibc). zstd and RocksDB are built from source to pin versions;
# Go and Rust come from upstream tarballs (there's no golang:1.26-noble image).
# Note: v1 (Dockerfile) ships on ubuntu:22.04, its long-standing production base —
# the 22.04/24.04 divergence between the two images is deliberate.
# Both images (this one and v1's Dockerfile) ship on ubuntu:24.04 with noble
# stellar-core packages.

# --- Stage 1: zstd ---
FROM ubuntu:24.04 AS zstd-build
Expand Down Expand Up @@ -72,7 +72,7 @@ RUN apt update && apt install -y --no-install-recommends \
RUN curl -sSL https://apt.stellar.org/SDF.asc | gpg --dearmor >/etc/apt/trusted.gpg.d/SDF.gpg
RUN echo "deb https://apt.stellar.org noble stable" >/etc/apt/sources.list.d/SDF.list
RUN echo "deb https://apt.stellar.org noble unstable" >/etc/apt/sources.list.d/SDF-unstable.list
RUN apt update && apt install -y stellar-core=${STELLAR_CORE_VERSION}
RUN apt update && apt install -y --no-install-recommends stellar-core=${STELLAR_CORE_VERSION}
RUN apt clean

COPY --from=zstd-build /usr/local/lib/libzstd.so* /usr/local/lib/
Expand Down
61 changes: 46 additions & 15 deletions cmd/stellar-rpc/internal/rpcv1/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/rpcv1/feewindow"
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/rpcv1/ingest"
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/rpcv1/sqlitedb"
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/store"
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/util"
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/version"
)
Expand Down Expand Up @@ -207,22 +208,32 @@ func MustNew(cfg *config.Config, logger *supportlog.Entry) *Daemon {
var ingestCfg ingest.Config
daemon.ingestService, ingestCfg = createIngestService(cfg, logger, daemon, feewindows, historyArchive, rw)
if cfg.Backfill {
backfillMeta, err := ingest.NewBackfillMeta(
logger,
daemon.ingestService,
sqlitedb.NewLedgerReader(daemon.db),
daemon.dataStore,
daemon.dataStoreSchema,
)
if err != nil {
logger.WithError(err).Fatal("failed to create backfill metadata")
}
if err := backfillMeta.RunBackfill(cfg); err != nil {
logger.WithError(err).Fatal("failed to backfill ledgers")
// On a fresh DB, reshape the schema for the bulk-load; FinalizeBulkLoad
// restores it below
_, err := sqlitedb.NewLedgerReader(daemon.db).GetLedgerRange(context.Background())
if errors.Is(err, store.ErrEmptyDB) {
if err := sqlitedb.PrepareBulkLoad(context.Background(), daemon.db, logger); err != nil {
logger.WithError(err).Fatal("failed to prepare database for backfill bulk-load")
}
} else if err != nil {
logger.WithError(err).Fatal("failed to check database emptiness for backfill")
}
// Clear the DB cache and fee windows so they re-populate from the database
daemon.db.ResetCache()
feewindows.Reset()

daemon.mustBackfill(cfg, feewindows)
}

// Restore the canonical schema after a bulk-load, including one interrupted
// by a crash. Must finish before ingestService.Start to avoid starving it.
finalizeStart := time.Now()
if err := sqlitedb.FinalizeBulkLoad(context.Background(), daemon.db, cfg.SQLiteDBPath, logger); err != nil {
logger.WithError(err).Fatal("failed to finalize backfill bulk-load")
}
// The backfill perf-eval runner keys off this line; keep it stable
logger.WithField("duration", time.Since(finalizeStart).String()).Info("Bulk-load finalize complete")

if cfg.Backfill {
// Top-up frontfill after finalize so captive core starts nearer the live tip
daemon.mustBackfill(cfg, feewindows)
}
// Start ingestion service only after backfill is complete
daemon.ingestService.Start(ingestCfg)
Expand Down Expand Up @@ -515,6 +526,26 @@ func (d *Daemon) mustInitializeStorage(cfg *config.Config) *feewindow.FeeWindows
return feeWindows
}

func (d *Daemon) mustBackfill(cfg *config.Config, feeWindows *feewindow.FeeWindows) {
backfillMeta, err := ingest.NewBackfillMeta(
d.logger,
d.ingestService,
sqlitedb.NewLedgerReader(d.db),
d.dataStore,
d.dataStoreSchema,
)
if err != nil {
d.logger.WithError(err).Fatal("failed to create backfill metadata")
}
if err := backfillMeta.RunBackfill(cfg); err != nil {
d.logger.WithError(err).Fatal("failed to backfill ledgers")
}

// Clear the DB cache and fee windows so they re-populate from the database
d.db.ResetCache()
feeWindows.Reset()
}

func (d *Daemon) buildMigrations(ctx context.Context, cfg *config.Config, retentionRange sqlitedb.LedgerSeqRange,
feeWindows *feewindow.FeeWindows,
) sqlitedb.MultiMigration {
Expand Down
7 changes: 4 additions & 3 deletions cmd/stellar-rpc/internal/rpcv1/ingest/backfill.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func (b *BackfillMeta) runFrontfill(ctx context.Context, bounds fillBounds) (fil
b.logger.Infof("No extra filling needed, local DB head already at most recent checkpoint in datastore")
}
// Update frontfill.First for next iteration (if any)
bounds.frontfill.First = bounds.frontfill.Last + 1
bounds.frontfill.First = max(bounds.frontfill.First, bounds.frontfill.Last+1)
}
b.dbInfo.sequences.Last = max(bounds.frontfill.First-1, b.dbInfo.sequences.Last)
b.logger.Infof("Forward backfill of recent ledgers complete")
Expand All @@ -238,6 +238,7 @@ func (b *BackfillMeta) verifyBounds(nBackfill, minSeq, maxSeq uint32) error {
"got %d ledgers (exceeds acceptable threshold of %d missing ledgers)", nBackfill, count, ledgerThreshold)
b.logger.Warn("You may wish to run backfill again to avoid a long post-backfill catch-up period")
}
// The backfill perf-eval runner keys off this line; keep it stable
b.logger.Infof("Backfill process complete, ledgers [%d -> %d] are now in local DB", minSeq, maxSeq)
return nil
}
Expand Down Expand Up @@ -364,8 +365,8 @@ func (b *BackfillMeta) frontfillChunks(ctx context.Context, bounds fillBounds) e
// Returns a buffered storage backend for the given datastore
func makeBackend(dsInfo datastoreInfo) (ledgerbackend.LedgerBackend, error) {
ledgersPerFile := dsInfo.schema.LedgersPerFile
bufferSize := max(1024/ledgersPerFile, 10) // use fewer files if many ledgers per file
numWorkers := max(bufferSize/10, 5) // approx. 1 worker per 10 buffered files
bufferSize := min(max(1024/ledgersPerFile, 10), 256) // use many files if few ledgers per file, cap at 256
numWorkers := max(bufferSize/10, 5) // approx. 1 worker per 10 buffered files
return ledgerbackend.NewBufferedStorageBackend(
ledgerbackend.BufferedStorageBackendConfig{
BufferSize: bufferSize, // number of files to buffer
Expand Down
31 changes: 27 additions & 4 deletions cmd/stellar-rpc/internal/rpcv1/ingest/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,35 @@ func (s *Service) ingestRange(ctx context.Context, backend backends.LedgerBacken
}
}()

// Fetch (and decode) ledgers ahead of the DB writes
type fetched struct {
lcm xdr.LedgerCloseMeta
err error
}
fetchCtx, cancelFetch := context.WithCancel(ctx)
defer cancelFetch()
fetches := make(chan fetched, 8) //nolint:mnd
go func() {
defer close(fetches)
for seq := seqRange.From(); seq <= seqRange.To(); seq++ {
lcm, err := backend.GetLedger(fetchCtx, seq)
select {
case fetches <- fetched{lcm, err}:
case <-fetchCtx.Done():
return
}
if err != nil {
return
}
}
}()

var ledgerCloseMeta xdr.LedgerCloseMeta
for seq := seqRange.From(); seq <= seqRange.To(); seq++ {
ledgerCloseMeta, err = backend.GetLedger(ctx, seq)
if err != nil {
return err
for f := range fetches {
if f.err != nil {
return f.err
}
ledgerCloseMeta = f.lcm
if err := s.ingestLedgerCloseMeta(tx, ledgerCloseMeta); err != nil {
return err
}
Expand Down
Loading
Loading