Skip to content

Commit 5cf7ddc

Browse files
authored
ingest: Allow enabling Captive Core's fast HTTP server (#5586)
1 parent e30ccf4 commit 5cf7ddc

File tree

7 files changed

+147
-15
lines changed

7 files changed

+147
-15
lines changed

.github/actions/setup-go/action.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ runs:
3232
run: echo 'PREFIX=${{ github.workflow }}-${{ github.job }}-${{ runner.os }}-${{ inputs.go-version }}-matrix(${{ join(matrix.*,'|') }})' >> $GITHUB_ENV
3333

3434
# Cache the Go Modules downloaded during the job.
35-
- uses: actions/cache@v2
35+
- uses: actions/cache@v4
3636
with:
3737
path: ~/go/pkg/mod
3838
key: ${{ env.PREFIX }}-go-mod-${{ hashFiles('**/go.sum') }}
3939
restore-keys: ${{ env.PREFIX }}-go-mod-
4040

4141
# Cache any build and test artifacts during the job, which will speed up
4242
# rebuilds and cause test runs to skip tests that have no reason to rerun.
43-
- uses: actions/cache@v2
43+
- uses: actions/cache@v4
4444
with:
4545
path: ~/.cache/go-build
4646
key: ${{ env.PREFIX }}-go-build-${{ github.ref }}-${{ hashFiles('**', '!.git') }}

.github/workflows/horizon.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
104104
- name: Restore Horizon binary and integration tests source hash to cache
105105
id: horizon_binary_tests_hash
106-
uses: actions/cache/restore@v3
106+
uses: actions/cache/restore@v4
107107
with:
108108
path: ./empty
109109
lookup-only: true
@@ -114,7 +114,7 @@ jobs:
114114

115115
- name: Save Horizon binary and integration tests source hash to cache
116116
if: ${{ success() && steps.horizon_binary_tests_hash.outputs.cache-hit != 'true' }}
117-
uses: actions/cache/save@v3
117+
uses: actions/cache/save@v4
118118
with:
119119
path: ./empty
120120
key: ${{ env.COMBINED_SOURCE_HASH }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated file, do not edit
2+
BUCKETLIST_DB_INDEX_PAGE_SIZE_EXPONENT = 12
3+
DATABASE = "sqlite3://stellar.db"
4+
DEPRECATED_SQL_LEDGER_STATE = false
5+
FAILURE_SAFETY = -1
6+
HTTP_PORT = 11626
7+
HTTP_QUERY_PORT = 11628
8+
LOG_FILE_PATH = ""
9+
NETWORK_PASSPHRASE = "Public Global Stellar Network ; September 2015"
10+
QUERY_SNAPSHOT_LEDGERS = 2
11+
QUERY_THREAD_POOL_SIZE = 4
12+
13+
[[HOME_DOMAINS]]
14+
HOME_DOMAIN = "testnet.stellar.org"
15+
QUALITY = "MEDIUM"
16+
17+
[[VALIDATORS]]
18+
ADDRESS = "localhost:123"
19+
HOME_DOMAIN = "testnet.stellar.org"
20+
NAME = "sdf_testnet_1"
21+
PUBLIC_KEY = "GDKXE2OZMJIPOSLNA6N6F2BVCI3O777I2OOC4BV7VOYUEHYX7RTRYA7Y"
22+
23+
[HISTORY.h0]
24+
get = "curl -sf http://localhost:1170/{0} -o {1}"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# parameters to enable Captive Core's high-performance HTTP server
2+
HTTP_QUERY_PORT=11628
3+
QUERY_THREAD_POOL_SIZE=4
4+
QUERY_SNAPSHOT_LEDGERS=2
5+
6+
[[HOME_DOMAINS]]
7+
HOME_DOMAIN="testnet.stellar.org"
8+
QUALITY="MEDIUM"
9+
10+
[[VALIDATORS]]
11+
NAME="sdf_testnet_1"
12+
HOME_DOMAIN="testnet.stellar.org"
13+
PUBLIC_KEY="GDKXE2OZMJIPOSLNA6N6F2BVCI3O777I2OOC4BV7VOYUEHYX7RTRYA7Y"
14+
ADDRESS="localhost:123"

ingest/ledgerbackend/toml.go

+53-4
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ type captiveCoreTomlValues struct {
106106
EnableDiagnosticsForTxSubmission *bool `toml:"ENABLE_DIAGNOSTICS_FOR_TX_SUBMISSION,omitempty"`
107107
EnableEmitSorobanTransactionMetaExtV1 *bool `toml:"EMIT_SOROBAN_TRANSACTION_META_EXT_V1,omitempty"`
108108
EnableEmitLedgerCloseMetaExtV1 *bool `toml:"EMIT_LEDGER_CLOSE_META_EXT_V1,omitempty"`
109+
HTTPQueryPort *uint `toml:"HTTP_QUERY_PORT,omitempty"`
110+
QueryThreadPoolSize *uint `toml:"QUERY_THREAD_POOL_SIZE,omitempty"`
111+
QuerySnapshotLedgers *uint `toml:"QUERY_SNAPSHOT_LEDGERS,omitempty"`
109112
}
110113

111114
// QuorumSetIsConfigured returns true if there is a quorum set defined in the configuration.
@@ -321,6 +324,12 @@ func (c *CaptiveCoreToml) unmarshal(data []byte, strict bool) error {
321324
return nil
322325
}
323326

327+
type HTTPQueryServerParams struct {
328+
Port uint16
329+
ThreadPoolSize uint16
330+
SnapshotLedgers uint16
331+
}
332+
324333
// CaptiveCoreTomlParams defines captive core configuration provided by Horizon flags.
325334
type CaptiveCoreTomlParams struct {
326335
// NetworkPassphrase is the Stellar network passphrase used by captive core when connecting to the Stellar network.
@@ -346,6 +355,8 @@ type CaptiveCoreTomlParams struct {
346355
EnforceSorobanDiagnosticEvents bool
347356
// Enfore EnableSorobanTransactionMetaExtV1 when not disabled explicitly
348357
EnforceSorobanTransactionMetaExtV1 bool
358+
// Fast HTTP Query Server parameters
359+
HTTPQueryServerParams *HTTPQueryServerParams
349360
}
350361

351362
// NewCaptiveCoreTomlFromFile constructs a new CaptiveCoreToml instance by merging configuration
@@ -498,6 +509,18 @@ func (c *CaptiveCoreToml) setDefaults(params CaptiveCoreTomlParams) {
498509
if params.EnforceSorobanTransactionMetaExtV1 {
499510
enforceOption(&c.EnableEmitSorobanTransactionMetaExtV1)
500511
}
512+
513+
if params.HTTPQueryServerParams != nil {
514+
port := uint(params.HTTPQueryServerParams.Port)
515+
c.HTTPQueryPort = &port
516+
517+
ledgers := uint(params.HTTPQueryServerParams.SnapshotLedgers)
518+
c.QuerySnapshotLedgers = &ledgers
519+
520+
poolSize := uint(params.HTTPQueryServerParams.ThreadPoolSize)
521+
c.QueryThreadPoolSize = &poolSize
522+
523+
}
501524
}
502525

503526
func enforceOption(opt **bool) {
@@ -516,36 +539,62 @@ func enforceOption(opt **bool) {
516539
func (c *CaptiveCoreToml) validate(params CaptiveCoreTomlParams) error {
517540
if def := c.tree.Has("NETWORK_PASSPHRASE"); def && c.NetworkPassphrase != params.NetworkPassphrase {
518541
return fmt.Errorf(
519-
"NETWORK_PASSPHRASE in captive core config file: %s does not match Horizon network-passphrase flag: %s",
542+
"NETWORK_PASSPHRASE in captive core config file: %s does not match passed configuration (%s)",
520543
c.NetworkPassphrase,
521544
params.NetworkPassphrase,
522545
)
523546
}
524547

525548
if def := c.tree.Has("HTTP_PORT"); def && params.HTTPPort != nil && c.HTTPPort != *params.HTTPPort {
526549
return fmt.Errorf(
527-
"HTTP_PORT in captive core config file: %d does not match Horizon captive-core-http-port flag: %d",
550+
"HTTP_PORT in captive core config file: %d does not match passed configuration (%d)",
528551
c.HTTPPort,
529552
*params.HTTPPort,
530553
)
531554
}
532555

533556
if def := c.tree.Has("PEER_PORT"); def && params.PeerPort != nil && c.PeerPort != *params.PeerPort {
534557
return fmt.Errorf(
535-
"PEER_PORT in captive core config file: %d does not match Horizon captive-core-peer-port flag: %d",
558+
"PEER_PORT in captive core config file: %d does not match passed configuration (%d)",
536559
c.PeerPort,
537560
*params.PeerPort,
538561
)
539562
}
540563

541564
if def := c.tree.Has("LOG_FILE_PATH"); def && params.LogPath != nil && c.LogFilePath != *params.LogPath {
542565
return fmt.Errorf(
543-
"LOG_FILE_PATH in captive core config file: %s does not match Horizon captive-core-log-path flag: %s",
566+
"LOG_FILE_PATH in captive core config file: %s does not match passed configuration (%s)",
544567
c.LogFilePath,
545568
*params.LogPath,
546569
)
547570
}
548571

572+
if params.HTTPQueryServerParams != nil {
573+
if c.HTTPQueryPort != nil && *c.HTTPQueryPort != uint(params.HTTPQueryServerParams.Port) {
574+
return fmt.Errorf(
575+
"HTTP_QUERY_PORT in captive core config file: %d does not match passed configuration (%d)",
576+
c.PeerPort,
577+
*params.PeerPort,
578+
)
579+
}
580+
581+
if c.QueryThreadPoolSize != nil && *c.QueryThreadPoolSize != uint(params.HTTPQueryServerParams.ThreadPoolSize) {
582+
return fmt.Errorf(
583+
"QUERY_THREADPOOL_SIZE in captive core config file: %d does not match passed configuration (%d)",
584+
c.PeerPort,
585+
*params.PeerPort,
586+
)
587+
}
588+
589+
if c.QuerySnapshotLedgers != nil && *c.QuerySnapshotLedgers != uint(params.HTTPQueryServerParams.SnapshotLedgers) {
590+
return fmt.Errorf(
591+
"QUERY_SNAPSHOT_LEDGERS in captive core config file: %d does not match passed configuration (%d)",
592+
c.PeerPort,
593+
*params.PeerPort,
594+
)
595+
}
596+
}
597+
549598
if c.tree.Has("DEPRECATED_SQL_LEDGER_STATE") {
550599
if params.UseDB && *c.DeprecatedSqlLedgerState {
551600
return fmt.Errorf("CAPTIVE_CORE_USE_DB parameter is set to true, indicating stellar-core on-disk mode," +

ingest/ledgerbackend/toml_test.go

+50-5
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
3636
peerPort: newUint(12345),
3737
logPath: nil,
3838
expectedError: "invalid captive core toml: NETWORK_PASSPHRASE in captive core config file: " +
39-
"Public Global Stellar Network ; September 2015 does not match Horizon network-passphrase " +
40-
"flag: bogus passphrase",
39+
"Public Global Stellar Network ; September 2015 does not match passed configuration (bogus passphrase)",
4140
},
4241
{
4342
name: "mismatching HTTP_PORT",
@@ -47,7 +46,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
4746
peerPort: newUint(12345),
4847
logPath: nil,
4948
expectedError: "invalid captive core toml: HTTP_PORT in captive core config file: 6789 " +
50-
"does not match Horizon captive-core-http-port flag: 1161",
49+
"does not match passed configuration (1161)",
5150
},
5251
{
5352
name: "mismatching PEER_PORT",
@@ -57,7 +56,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
5756
peerPort: newUint(2346),
5857
logPath: nil,
5958
expectedError: "invalid captive core toml: PEER_PORT in captive core config file: 12345 " +
60-
"does not match Horizon captive-core-peer-port flag: 2346",
59+
"does not match passed configuration (2346)",
6160
},
6261
{
6362
name: "mismatching LOG_FILE_PATH",
@@ -67,7 +66,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
6766
peerPort: newUint(12345),
6867
logPath: newString("/my/test/path"),
6968
expectedError: "invalid captive core toml: LOG_FILE_PATH in captive core config file: " +
70-
"does not match Horizon captive-core-log-path flag: /my/test/path",
69+
"does not match passed configuration (/my/test/path)",
7170
},
7271
{
7372
name: "duplicate HOME_DOMAIN entry",
@@ -369,6 +368,14 @@ func TestGenerateConfig(t *testing.T) {
369368
useDB: true,
370369
logPath: nil,
371370
},
371+
{
372+
name: "Query parameters in appendix",
373+
mode: stellarCoreRunnerModeOnline,
374+
appendPath: filepath.Join("testdata", "sample-appendix-query-params.cfg"),
375+
expectedPath: filepath.Join("testdata", "expected-query-params.cfg"),
376+
useDB: true,
377+
logPath: nil,
378+
},
372379
} {
373380
t.Run(testCase.name, func(t *testing.T) {
374381
var err error
@@ -533,3 +540,41 @@ func TestNonDBConfigDoesNotUpdateDatabase(t *testing.T) {
533540
require.NoError(t, toml.unmarshal(configBytes, true))
534541
assert.Equal(t, toml.Database, "")
535542
}
543+
544+
func TestHTTPQueryParameters(t *testing.T) {
545+
var err error
546+
var captiveCoreToml *CaptiveCoreToml
547+
httpPort := uint(8000)
548+
peerPort := uint(8000)
549+
logPath := "logPath"
550+
551+
params := CaptiveCoreTomlParams{
552+
NetworkPassphrase: "Public Global Stellar Network ; September 2015",
553+
HistoryArchiveURLs: []string{"http://localhost:1170"},
554+
HTTPPort: &httpPort,
555+
PeerPort: &peerPort,
556+
LogPath: &logPath,
557+
Strict: false,
558+
UseDB: true,
559+
HTTPQueryServerParams: &HTTPQueryServerParams{
560+
Port: 100,
561+
ThreadPoolSize: 200,
562+
SnapshotLedgers: 300,
563+
},
564+
}
565+
566+
captiveCoreToml, err = NewCaptiveCoreToml(params)
567+
assert.NoError(t, err)
568+
569+
configBytes, err := generateConfig(captiveCoreToml, stellarCoreRunnerModeOffline)
570+
571+
assert.NoError(t, err)
572+
toml := CaptiveCoreToml{}
573+
require.NoError(t, toml.unmarshal(configBytes, true))
574+
require.NotNil(t, *toml.HTTPQueryPort)
575+
assert.Equal(t, *toml.HTTPQueryPort, uint(100))
576+
require.NotNil(t, *toml.QueryThreadPoolSize)
577+
assert.Equal(t, *toml.QueryThreadPoolSize, uint(200))
578+
require.NotNil(t, *toml.QuerySnapshotLedgers)
579+
assert.Equal(t, *toml.QuerySnapshotLedgers, uint(300))
580+
}

services/horizon/internal/flags_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ func TestSetCaptiveCoreConfig(t *testing.T) {
197197
CaptiveCoreBinaryPath: "/path/to/captive-core/binary",
198198
},
199199
errStr: fmt.Sprintf("invalid captive core toml file: invalid captive core toml: "+
200-
"NETWORK_PASSPHRASE in captive core config file: %s does not match Horizon "+
201-
"network-passphrase flag: %s", network.TestNetworkPassphrase, network.PublicNetworkPassphrase),
200+
"NETWORK_PASSPHRASE in captive core config file: %s does not match passed configuration (%s)",
201+
network.TestNetworkPassphrase, network.PublicNetworkPassphrase),
202202
},
203203
{
204204
name: "no network specified; full captive-core-config not required",

0 commit comments

Comments
 (0)