Skip to content

Commit

Permalink
ingest: Allow enabling Captive Core's fast HTTP server (#5586)
Browse files Browse the repository at this point in the history
  • Loading branch information
2opremio authored Feb 5, 2025
1 parent e30ccf4 commit 5cf7ddc
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 15 deletions.
4 changes: 2 additions & 2 deletions .github/actions/setup-go/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ runs:
run: echo 'PREFIX=${{ github.workflow }}-${{ github.job }}-${{ runner.os }}-${{ inputs.go-version }}-matrix(${{ join(matrix.*,'|') }})' >> $GITHUB_ENV

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

# Cache any build and test artifacts during the job, which will speed up
# rebuilds and cause test runs to skip tests that have no reason to rerun.
- uses: actions/cache@v2
- uses: actions/cache@v4
with:
path: ~/.cache/go-build
key: ${{ env.PREFIX }}-go-build-${{ github.ref }}-${{ hashFiles('**', '!.git') }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/horizon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ jobs:
- name: Restore Horizon binary and integration tests source hash to cache
id: horizon_binary_tests_hash
uses: actions/cache/restore@v3
uses: actions/cache/restore@v4
with:
path: ./empty
lookup-only: true
Expand All @@ -114,7 +114,7 @@ jobs:

- name: Save Horizon binary and integration tests source hash to cache
if: ${{ success() && steps.horizon_binary_tests_hash.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
uses: actions/cache/save@v4
with:
path: ./empty
key: ${{ env.COMBINED_SOURCE_HASH }}
Expand Down
24 changes: 24 additions & 0 deletions ingest/ledgerbackend/testdata/expected-query-params.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated file, do not edit
BUCKETLIST_DB_INDEX_PAGE_SIZE_EXPONENT = 12
DATABASE = "sqlite3://stellar.db"
DEPRECATED_SQL_LEDGER_STATE = false
FAILURE_SAFETY = -1
HTTP_PORT = 11626
HTTP_QUERY_PORT = 11628
LOG_FILE_PATH = ""
NETWORK_PASSPHRASE = "Public Global Stellar Network ; September 2015"
QUERY_SNAPSHOT_LEDGERS = 2
QUERY_THREAD_POOL_SIZE = 4

[[HOME_DOMAINS]]
HOME_DOMAIN = "testnet.stellar.org"
QUALITY = "MEDIUM"

[[VALIDATORS]]
ADDRESS = "localhost:123"
HOME_DOMAIN = "testnet.stellar.org"
NAME = "sdf_testnet_1"
PUBLIC_KEY = "GDKXE2OZMJIPOSLNA6N6F2BVCI3O777I2OOC4BV7VOYUEHYX7RTRYA7Y"

[HISTORY.h0]
get = "curl -sf http://localhost:1170/{0} -o {1}"
14 changes: 14 additions & 0 deletions ingest/ledgerbackend/testdata/sample-appendix-query-params.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# parameters to enable Captive Core's high-performance HTTP server
HTTP_QUERY_PORT=11628
QUERY_THREAD_POOL_SIZE=4
QUERY_SNAPSHOT_LEDGERS=2

[[HOME_DOMAINS]]
HOME_DOMAIN="testnet.stellar.org"
QUALITY="MEDIUM"

[[VALIDATORS]]
NAME="sdf_testnet_1"
HOME_DOMAIN="testnet.stellar.org"
PUBLIC_KEY="GDKXE2OZMJIPOSLNA6N6F2BVCI3O777I2OOC4BV7VOYUEHYX7RTRYA7Y"
ADDRESS="localhost:123"
57 changes: 53 additions & 4 deletions ingest/ledgerbackend/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ type captiveCoreTomlValues struct {
EnableDiagnosticsForTxSubmission *bool `toml:"ENABLE_DIAGNOSTICS_FOR_TX_SUBMISSION,omitempty"`
EnableEmitSorobanTransactionMetaExtV1 *bool `toml:"EMIT_SOROBAN_TRANSACTION_META_EXT_V1,omitempty"`
EnableEmitLedgerCloseMetaExtV1 *bool `toml:"EMIT_LEDGER_CLOSE_META_EXT_V1,omitempty"`
HTTPQueryPort *uint `toml:"HTTP_QUERY_PORT,omitempty"`
QueryThreadPoolSize *uint `toml:"QUERY_THREAD_POOL_SIZE,omitempty"`
QuerySnapshotLedgers *uint `toml:"QUERY_SNAPSHOT_LEDGERS,omitempty"`
}

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

type HTTPQueryServerParams struct {
Port uint16
ThreadPoolSize uint16
SnapshotLedgers uint16
}

// CaptiveCoreTomlParams defines captive core configuration provided by Horizon flags.
type CaptiveCoreTomlParams struct {
// NetworkPassphrase is the Stellar network passphrase used by captive core when connecting to the Stellar network.
Expand All @@ -346,6 +355,8 @@ type CaptiveCoreTomlParams struct {
EnforceSorobanDiagnosticEvents bool
// Enfore EnableSorobanTransactionMetaExtV1 when not disabled explicitly
EnforceSorobanTransactionMetaExtV1 bool
// Fast HTTP Query Server parameters
HTTPQueryServerParams *HTTPQueryServerParams
}

// NewCaptiveCoreTomlFromFile constructs a new CaptiveCoreToml instance by merging configuration
Expand Down Expand Up @@ -498,6 +509,18 @@ func (c *CaptiveCoreToml) setDefaults(params CaptiveCoreTomlParams) {
if params.EnforceSorobanTransactionMetaExtV1 {
enforceOption(&c.EnableEmitSorobanTransactionMetaExtV1)
}

if params.HTTPQueryServerParams != nil {
port := uint(params.HTTPQueryServerParams.Port)
c.HTTPQueryPort = &port

ledgers := uint(params.HTTPQueryServerParams.SnapshotLedgers)
c.QuerySnapshotLedgers = &ledgers

poolSize := uint(params.HTTPQueryServerParams.ThreadPoolSize)
c.QueryThreadPoolSize = &poolSize

}
}

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

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

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

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

if params.HTTPQueryServerParams != nil {
if c.HTTPQueryPort != nil && *c.HTTPQueryPort != uint(params.HTTPQueryServerParams.Port) {
return fmt.Errorf(
"HTTP_QUERY_PORT in captive core config file: %d does not match passed configuration (%d)",
c.PeerPort,
*params.PeerPort,
)
}

if c.QueryThreadPoolSize != nil && *c.QueryThreadPoolSize != uint(params.HTTPQueryServerParams.ThreadPoolSize) {
return fmt.Errorf(
"QUERY_THREADPOOL_SIZE in captive core config file: %d does not match passed configuration (%d)",
c.PeerPort,
*params.PeerPort,
)
}

if c.QuerySnapshotLedgers != nil && *c.QuerySnapshotLedgers != uint(params.HTTPQueryServerParams.SnapshotLedgers) {
return fmt.Errorf(
"QUERY_SNAPSHOT_LEDGERS in captive core config file: %d does not match passed configuration (%d)",
c.PeerPort,
*params.PeerPort,
)
}
}

if c.tree.Has("DEPRECATED_SQL_LEDGER_STATE") {
if params.UseDB && *c.DeprecatedSqlLedgerState {
return fmt.Errorf("CAPTIVE_CORE_USE_DB parameter is set to true, indicating stellar-core on-disk mode," +
Expand Down
55 changes: 50 additions & 5 deletions ingest/ledgerbackend/toml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
peerPort: newUint(12345),
logPath: nil,
expectedError: "invalid captive core toml: NETWORK_PASSPHRASE in captive core config file: " +
"Public Global Stellar Network ; September 2015 does not match Horizon network-passphrase " +
"flag: bogus passphrase",
"Public Global Stellar Network ; September 2015 does not match passed configuration (bogus passphrase)",
},
{
name: "mismatching HTTP_PORT",
Expand All @@ -47,7 +46,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
peerPort: newUint(12345),
logPath: nil,
expectedError: "invalid captive core toml: HTTP_PORT in captive core config file: 6789 " +
"does not match Horizon captive-core-http-port flag: 1161",
"does not match passed configuration (1161)",
},
{
name: "mismatching PEER_PORT",
Expand All @@ -57,7 +56,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
peerPort: newUint(2346),
logPath: nil,
expectedError: "invalid captive core toml: PEER_PORT in captive core config file: 12345 " +
"does not match Horizon captive-core-peer-port flag: 2346",
"does not match passed configuration (2346)",
},
{
name: "mismatching LOG_FILE_PATH",
Expand All @@ -67,7 +66,7 @@ func TestCaptiveCoreTomlValidation(t *testing.T) {
peerPort: newUint(12345),
logPath: newString("/my/test/path"),
expectedError: "invalid captive core toml: LOG_FILE_PATH in captive core config file: " +
"does not match Horizon captive-core-log-path flag: /my/test/path",
"does not match passed configuration (/my/test/path)",
},
{
name: "duplicate HOME_DOMAIN entry",
Expand Down Expand Up @@ -369,6 +368,14 @@ func TestGenerateConfig(t *testing.T) {
useDB: true,
logPath: nil,
},
{
name: "Query parameters in appendix",
mode: stellarCoreRunnerModeOnline,
appendPath: filepath.Join("testdata", "sample-appendix-query-params.cfg"),
expectedPath: filepath.Join("testdata", "expected-query-params.cfg"),
useDB: true,
logPath: nil,
},
} {
t.Run(testCase.name, func(t *testing.T) {
var err error
Expand Down Expand Up @@ -533,3 +540,41 @@ func TestNonDBConfigDoesNotUpdateDatabase(t *testing.T) {
require.NoError(t, toml.unmarshal(configBytes, true))
assert.Equal(t, toml.Database, "")
}

func TestHTTPQueryParameters(t *testing.T) {
var err error
var captiveCoreToml *CaptiveCoreToml
httpPort := uint(8000)
peerPort := uint(8000)
logPath := "logPath"

params := CaptiveCoreTomlParams{
NetworkPassphrase: "Public Global Stellar Network ; September 2015",
HistoryArchiveURLs: []string{"http://localhost:1170"},
HTTPPort: &httpPort,
PeerPort: &peerPort,
LogPath: &logPath,
Strict: false,
UseDB: true,
HTTPQueryServerParams: &HTTPQueryServerParams{
Port: 100,
ThreadPoolSize: 200,
SnapshotLedgers: 300,
},
}

captiveCoreToml, err = NewCaptiveCoreToml(params)
assert.NoError(t, err)

configBytes, err := generateConfig(captiveCoreToml, stellarCoreRunnerModeOffline)

assert.NoError(t, err)
toml := CaptiveCoreToml{}
require.NoError(t, toml.unmarshal(configBytes, true))
require.NotNil(t, *toml.HTTPQueryPort)
assert.Equal(t, *toml.HTTPQueryPort, uint(100))
require.NotNil(t, *toml.QueryThreadPoolSize)
assert.Equal(t, *toml.QueryThreadPoolSize, uint(200))
require.NotNil(t, *toml.QuerySnapshotLedgers)
assert.Equal(t, *toml.QuerySnapshotLedgers, uint(300))
}
4 changes: 2 additions & 2 deletions services/horizon/internal/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ func TestSetCaptiveCoreConfig(t *testing.T) {
CaptiveCoreBinaryPath: "/path/to/captive-core/binary",
},
errStr: fmt.Sprintf("invalid captive core toml file: invalid captive core toml: "+
"NETWORK_PASSPHRASE in captive core config file: %s does not match Horizon "+
"network-passphrase flag: %s", network.TestNetworkPassphrase, network.PublicNetworkPassphrase),
"NETWORK_PASSPHRASE in captive core config file: %s does not match passed configuration (%s)",
network.TestNetworkPassphrase, network.PublicNetworkPassphrase),
},
{
name: "no network specified; full captive-core-config not required",
Expand Down

0 comments on commit 5cf7ddc

Please sign in to comment.