A Stellar blockchain data ingester that processes ledgers, transactions, and Soroban contract events into PostgreSQL.
├── main.go # Application entry point
├── controllers/ # HTTP routing and request handling
│ ├── ingester.go # Ingester API endpoints
│ └── user.go # Accounts controller
├── handlers/ # Business logic implementation
│ └── ingester.go # Stellar ingestion processing
├── models/ # Data models split by entity
│ ├── stats.go # Ingestion statistics
│ ├── transaction.go # Transaction model
│ ├── operation.go # Operation model
│ ├── event.go # Contract event model
│ └── ledger.go # Ledger model
├── db/ # Database connection
├── server/ # HTTP server setup
├── migrations/ # Database migrations
└── cmd/ # Command line utilities
├── migrate/ # Database migration tool
└── healthcheck/ # System health verification
For local development, set up PostgreSQL with:
# Create user and database
createuser -s stellar
psql -c "ALTER USER stellar PASSWORD 'stellar123';"
createdb -O stellar sorobangraphReference Database URL:
postgres://stellar:stellar123@localhost:5432/sorobangraph?sslmode=disable
The application supports both environment variables and YAML configuration files. YAML configs are located in /config and support environment-specific overrides.
DATABASE_URL=postgres://stellar:stellar123@localhost:5432/sorobangraph?sslmode=disable
NETWORK_PASSPHRASE=Test SDF Network ; September 2015
HISTORY_ARCHIVE_URLS=https://history.stellar.org/prd/core-testnet/core_testnet_001
START_LEDGER=0
END_LEDGER=0
ENABLE_WEBSOCKET=true
LOG_LEVEL=info
GIN_MODE=debug
PORT=8080The /config directory contains environment-specific YAML files:
default.yaml- Base configuration with default valuesdevelopment.yaml- Development overrides (debug logging, smaller batches)production.yaml- Production overrides (performance optimized, env vars)test.yaml- Test overrides (minimal logging, small datasets)
Usage:
# Run with development config
GO_ENV=development ./sorobangraph.attest.so
# Run with production config
GO_ENV=production ./sorobangraph.attest.so
# Default behavior uses 'default' config
./sorobangraph.attest.soConfiguration Structure:
database:
url: "${DATABASE_URL}" # References .env file
max_open_connections: 25
max_idle_connections: 10
stellar:
network_passphrase: "Test SDF Network ; September 2015"
history_archive_urls:
- "https://history.stellar.org/prd/core-testnet/core_testnet_001"
start_ledger: 0
end_ledger: 0
server:
port: 8080
gin_mode: "debug"
enable_websocket: true
logging:
level: "info"
format: "json"
ingestion:
batch_size: 1000
retry_attempts: 3
enable_captive_core: false✅ Migrations completed successfully:
go run cmd/migrate/main.go up✅ All tests passed:
go run cmd/healthcheck/main.go# Build the application
make build
# Run the application
./sorobangraph.attest.soGET /health- Health checkGET /api/v1/ledgers- List ledgersGET /api/v1/ledgers/:sequence- Get specific ledgerGET /api/v1/transactions- List transactionsGET /api/v1/transactions/:hash- Get specific transactionGET /api/v1/operations- List operationsGET /api/v1/contract-events- List Soroban eventsGET /api/v1/stats- Ingestion statistics
Connect to /api/v1/ws for real-time updates:
const ws = new WebSocket('ws://localhost:8080/api/v1/ws');
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log(message.type, message.data);
};For better performance, you can use a local Captive Core instance:
-
Install stellar-core:
wget https://github.com/stellar/stellar-core/releases/download/v20.1.0/stellar-core_20.1.0_amd64.deb sudo dpkg -i stellar-core_20.1.0_amd64.deb
-
Set environment variables:
export CAPTIVE_CORE_BINARY_PATH=/usr/bin/stellar-core export CAPTIVE_CORE_CONFIG_PATH=/etc/stellar-core.cfg
-
The ingester will automatically use Captive Core for ledger access
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | Required |
NETWORK_PASSPHRASE |
Stellar network to connect to | Testnet |
HISTORY_ARCHIVE_URLS |
History archive for ledger data | SDF Testnet |
CAPTIVE_CORE_BINARY_PATH |
Path to stellar-core binary | Optional |
CAPTIVE_CORE_CONFIG_PATH |
Path to stellar-core config | Optional |
START_LEDGER |
Ledger to start ingestion from | 0 (resume/genesis) |
END_LEDGER |
Ledger to stop at | 0 (continuous) |
PORT |
API server port | 8080 |
ENABLE_WEBSOCKET |
Enable WebSocket streaming | true |
LOG_LEVEL |
Logging verbosity | info |
The ingester creates the following tables:
ledgers- Ledger headers and metadatatransactions- Transaction envelopes and resultsoperations- Parsed operations with detailscontract_events- Soroban contract eventsingestion_state- Tracks ingestion progress
- Use Local Captive Core for faster ledger access
- Batch Processing: The ingester processes entire ledgers atomically
- Indexing: Proper indexes are created for common query patterns
Check ingestion statistics:
curl http://localhost:8080/api/v1/statsThe ingester supports filtering data to only include operations, transactions, and events for specific smart contract addresses.
By default, the ingester is configured to filter for these two contracts:
CADB73DZ7QP5BG5ZG6MRRL3J3X4WWHBCJ7PMCVZXYG7ZGCPIO2XCDBOMCAD6YMZCO4Q3L5XZT2FD3MDHP3ZHFMYL24RZYG4YQAL4XQKVGVXYPSQQ
You can override the default contracts by setting the FILTER_CONTRACTS environment variable:
export FILTER_CONTRACTS="CONTRACT_ADDRESS_1,CONTRACT_ADDRESS_2,CONTRACT_ADDRESS_3"To disable filtering and ingest all data, set an empty value:
export FILTER_CONTRACTS=""When contract filtering is enabled, the ingester will only store:
- Transactions - Only transactions that contain at least one operation invoking one of the filtered contracts
- Operations - Only
invoke_host_functionoperations that target one of the filtered contracts - Contract Events - Only events emitted by one of the filtered contracts
All other data (ledgers, accounts, etc. not related to these contracts) will be skipped to keep the database focused on your specific contracts.
When the ingester starts, it will log which contracts it's filtering for:
INFO[0000] Ingester configured to filter for contracts: [CADB73DZ7QP5BG5ZG6MRRL3J3X4WWHBCJ7PMCVZXYG7ZGCPIO2XCDBOM CAD6YMZCO4Q3L5XZT2FD3MDHP3ZHFMYL24RZYG4YQAL4XQKVGVXYPSQQ]
MIT