diff --git a/ingest/ledgerbackend/toml.go b/ingest/ledgerbackend/toml.go index 188c6a56da..d4e0711674 100644 --- a/ingest/ledgerbackend/toml.go +++ b/ingest/ledgerbackend/toml.go @@ -3,7 +3,7 @@ package ledgerbackend import ( "bytes" "fmt" - "io/ioutil" + "os" "os/exec" "regexp" "strconv" @@ -330,13 +330,19 @@ type CaptiveCoreTomlParams struct { // NewCaptiveCoreTomlFromFile constructs a new CaptiveCoreToml instance by merging configuration // from the toml file located at `configPath` and the configuration provided by `params`. func NewCaptiveCoreTomlFromFile(configPath string, params CaptiveCoreTomlParams) (*CaptiveCoreToml, error) { - var captiveCoreToml CaptiveCoreToml - data, err := ioutil.ReadFile(configPath) + data, err := os.ReadFile(configPath) if err != nil { return nil, errors.Wrap(err, "could not load toml path") } + return NewCaptiveCoreTomlFromData(data, params) +} + +// NewCaptiveCoreTomlFromData constructs a new CaptiveCoreToml instance by merging configuration +// from the toml data and the configuration provided by `params`. +func NewCaptiveCoreTomlFromData(data []byte, params CaptiveCoreTomlParams) (*CaptiveCoreToml, error) { + var captiveCoreToml CaptiveCoreToml - if err = captiveCoreToml.unmarshal(data, params.Strict); err != nil { + if err := captiveCoreToml.unmarshal(data, params.Strict); err != nil { return nil, errors.Wrap(err, "could not unmarshal captive core toml") } // disallow setting BUCKET_DIR_PATH through a file since it can cause multiple @@ -345,14 +351,13 @@ func NewCaptiveCoreTomlFromFile(configPath string, params CaptiveCoreTomlParams) return nil, errors.New("could not unmarshal captive core toml: setting BUCKET_DIR_PATH is disallowed for Captive Core, use CAPTIVE_CORE_STORAGE_PATH instead") } - if err = captiveCoreToml.validate(params); err != nil { + if err := captiveCoreToml.validate(params); err != nil { return nil, errors.Wrap(err, "invalid captive core toml") } if len(captiveCoreToml.HistoryEntries) > 0 { log.Warnf( - "Configuring captive core with history archive from %s instead of %v", - configPath, + "Configuring captive core with history archive from %s", params.HistoryArchiveURLs, ) } diff --git a/network/main.go b/network/main.go index 2e5a8a0d73..0325d877b4 100644 --- a/network/main.go +++ b/network/main.go @@ -19,6 +19,18 @@ const ( TestNetworkPassphrase = "Test SDF Network ; September 2015" ) +var ( + // PublicNetworkhistoryArchiveURLs is a list of history archive URLs for stellar 'pubnet' + PublicNetworkhistoryArchiveURLs = []string{"https://history.stellar.org/prd/core-live/core_live_001/", + "https://history.stellar.org/prd/core-live/core_live_002/", + "https://history.stellar.org/prd/core-live/core_live_003/"} + + // TestNetworkhistoryArchiveURLs is a list of history archive URLs for stellar 'testnet' + TestNetworkhistoryArchiveURLs = []string{"https://history.stellar.org/prd/core-testnet/core_testnet_001/", + "https://history.stellar.org/prd/core-testnet/core_testnet_002/", + "https://history.stellar.org/prd/core-testnet/core_testnet_003"} +) + // ID returns the network ID derived from the provided passphrase. This value // also happens to be the raw (i.e. not strkey encoded) secret key for the root // account of the network. diff --git a/services/horizon/CHANGELOG.md b/services/horizon/CHANGELOG.md index 772fe42af0..9ade9c77c2 100644 --- a/services/horizon/CHANGELOG.md +++ b/services/horizon/CHANGELOG.md @@ -7,6 +7,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - The command line flag --remote-captive-core-url has been removed as remote captive core functionality is now deprecated ([4940](https://github.com/stellar/go/pull/4940)). +- Added new command-line flag --network to specify the Stellar network (pubnet or testnet), aiming at simplifying the configuration process by automatically configuring the following parameters based on the chosen network: --history-archive-urls, --network-passphrase, --captive-core-config-path. ([4949](https://github.com/stellar/go/pull/4949)). ## 2.26.0 ### Changes diff --git a/services/horizon/docker/captive-core-pubnet.cfg b/services/horizon/docker/captive-core-pubnet.cfg deleted file mode 100644 index 177de5d9d9..0000000000 --- a/services/horizon/docker/captive-core-pubnet.cfg +++ /dev/null @@ -1,192 +0,0 @@ -PEER_PORT=11725 - -FAILURE_SAFETY=1 - -[[HOME_DOMAINS]] -HOME_DOMAIN="stellar.org" -QUALITY="HIGH" - -[[HOME_DOMAINS]] -HOME_DOMAIN="satoshipay.io" -QUALITY="HIGH" - -[[HOME_DOMAINS]] -HOME_DOMAIN="lobstr.co" -QUALITY="HIGH" - -[[HOME_DOMAINS]] -HOME_DOMAIN="www.coinqvest.com" -QUALITY="HIGH" - -[[HOME_DOMAINS]] -HOME_DOMAIN="publicnode.org" -QUALITY="HIGH" - -[[HOME_DOMAINS]] -HOME_DOMAIN="stellar.blockdaemon.com" -QUALITY="HIGH" - -[[HOME_DOMAINS]] -HOME_DOMAIN = "www.franklintempleton.com" -QUALITY = "HIGH" - -[[VALIDATORS]] -NAME="sdf_1" -HOME_DOMAIN="stellar.org" -PUBLIC_KEY="GCGB2S2KGYARPVIA37HYZXVRM2YZUEXA6S33ZU5BUDC6THSB62LZSTYH" -ADDRESS="core-live-a.stellar.org:11625" -HISTORY="curl -sf https://history.stellar.org/prd/core-live/core_live_001/{0} -o {1}" - -[[VALIDATORS]] -NAME="sdf_2" -HOME_DOMAIN="stellar.org" -PUBLIC_KEY="GCM6QMP3DLRPTAZW2UZPCPX2LF3SXWXKPMP3GKFZBDSF3QZGV2G5QSTK" -ADDRESS="core-live-b.stellar.org:11625" -HISTORY="curl -sf https://history.stellar.org/prd/core-live/core_live_002/{0} -o {1}" - -[[VALIDATORS]] -NAME="sdf_3" -HOME_DOMAIN="stellar.org" -PUBLIC_KEY="GABMKJM6I25XI4K7U6XWMULOUQIQ27BCTMLS6BYYSOWKTBUXVRJSXHYQ" -ADDRESS="core-live-c.stellar.org:11625" -HISTORY="curl -sf https://history.stellar.org/prd/core-live/core_live_003/{0} -o {1}" - -[[VALIDATORS]] -NAME="satoshipay_singapore" -HOME_DOMAIN="satoshipay.io" -PUBLIC_KEY="GBJQUIXUO4XSNPAUT6ODLZUJRV2NPXYASKUBY4G5MYP3M47PCVI55MNT" -ADDRESS="stellar-sg-sin.satoshipay.io:11625" -HISTORY="curl -sf https://stellar-history-sg-sin.satoshipay.io/{0} -o {1}" - -[[VALIDATORS]] -NAME="satoshipay_iowa" -HOME_DOMAIN="satoshipay.io" -PUBLIC_KEY="GAK6Z5UVGUVSEK6PEOCAYJISTT5EJBB34PN3NOLEQG2SUKXRVV2F6HZY" -ADDRESS="stellar-us-iowa.satoshipay.io:11625" -HISTORY="curl -sf https://stellar-history-us-iowa.satoshipay.io/{0} -o {1}" - -[[VALIDATORS]] -NAME="satoshipay_frankfurt" -HOME_DOMAIN="satoshipay.io" -PUBLIC_KEY="GC5SXLNAM3C4NMGK2PXK4R34B5GNZ47FYQ24ZIBFDFOCU6D4KBN4POAE" -ADDRESS="stellar-de-fra.satoshipay.io:11625" -HISTORY="curl -sf https://stellar-history-de-fra.satoshipay.io/{0} -o {1}" - -[[VALIDATORS]] -NAME="lobstr_1_europe" -HOME_DOMAIN="lobstr.co" -PUBLIC_KEY="GCFONE23AB7Y6C5YZOMKUKGETPIAJA4QOYLS5VNS4JHBGKRZCPYHDLW7" -ADDRESS="v1.stellar.lobstr.co:11625" -HISTORY="curl -sf https://stellar-archive-1-lobstr.s3.amazonaws.com/{0} -o {1}" - -[[VALIDATORS]] -NAME="lobstr_2_europe" -HOME_DOMAIN="lobstr.co" -PUBLIC_KEY="GDXQB3OMMQ6MGG43PWFBZWBFKBBDUZIVSUDAZZTRAWQZKES2CDSE5HKJ" -ADDRESS="v2.stellar.lobstr.co:11625" -HISTORY="curl -sf https://stellar-archive-2-lobstr.s3.amazonaws.com/{0} -o {1}" - -[[VALIDATORS]] -NAME="lobstr_3_north_america" -HOME_DOMAIN="lobstr.co" -PUBLIC_KEY="GD5QWEVV4GZZTQP46BRXV5CUMMMLP4JTGFD7FWYJJWRL54CELY6JGQ63" -ADDRESS="v3.stellar.lobstr.co:11625" -HISTORY="curl -sf https://stellar-archive-3-lobstr.s3.amazonaws.com/{0} -o {1}" - -[[VALIDATORS]] -NAME="lobstr_4_asia" -HOME_DOMAIN="lobstr.co" -PUBLIC_KEY="GA7TEPCBDQKI7JQLQ34ZURRMK44DVYCIGVXQQWNSWAEQR6KB4FMCBT7J" -ADDRESS="v4.stellar.lobstr.co:11625" -HISTORY="curl -sf https://stellar-archive-4-lobstr.s3.amazonaws.com/{0} -o {1}" - -[[VALIDATORS]] -NAME="lobstr_5_australia" -HOME_DOMAIN="lobstr.co" -PUBLIC_KEY="GA5STBMV6QDXFDGD62MEHLLHZTPDI77U3PFOD2SELU5RJDHQWBR5NNK7" -ADDRESS="v5.stellar.lobstr.co:11625" -HISTORY="curl -sf https://stellar-archive-5-lobstr.s3.amazonaws.com/{0} -o {1}" - -[[VALIDATORS]] -NAME="coinqvest_hong_kong" -HOME_DOMAIN="www.coinqvest.com" -PUBLIC_KEY="GAZ437J46SCFPZEDLVGDMKZPLFO77XJ4QVAURSJVRZK2T5S7XUFHXI2Z" -ADDRESS="hongkong.stellar.coinqvest.com:11625" -HISTORY="curl -sf https://hongkong.stellar.coinqvest.com/history/{0} -o {1}" - -[[VALIDATORS]] -NAME="coinqvest_germany" -HOME_DOMAIN="www.coinqvest.com" -PUBLIC_KEY="GD6SZQV3WEJUH352NTVLKEV2JM2RH266VPEM7EH5QLLI7ZZAALMLNUVN" -ADDRESS="germany.stellar.coinqvest.com:11625" -HISTORY="curl -sf https://germany.stellar.coinqvest.com/history/{0} -o {1}" - -[[VALIDATORS]] -NAME="coinqvest_finland" -HOME_DOMAIN="www.coinqvest.com" -PUBLIC_KEY="GADLA6BJK6VK33EM2IDQM37L5KGVCY5MSHSHVJA4SCNGNUIEOTCR6J5T" -ADDRESS="finland.stellar.coinqvest.com:11625" -HISTORY="curl -sf https://finland.stellar.coinqvest.com/history/{0} -o {1}" - -[[VALIDATORS]] -NAME="bootes" -HOME_DOMAIN="publicnode.org" -PUBLIC_KEY="GCVJ4Z6TI6Z2SOGENSPXDQ2U4RKH3CNQKYUHNSSPYFPNWTLGS6EBH7I2" -ADDRESS="bootes.publicnode.org" -HISTORY="curl -sf https://bootes-history.publicnode.org/{0} -o {1}" - -[[VALIDATORS]] -NAME="hercules" -HOME_DOMAIN="publicnode.org" -PUBLIC_KEY="GBLJNN3AVZZPG2FYAYTYQKECNWTQYYUUY2KVFN2OUKZKBULXIXBZ4FCT" -ADDRESS="hercules.publicnode.org" -HISTORY="curl -sf https://hercules-history.publicnode.org/{0} -o {1}" - -[[VALIDATORS]] -NAME="lyra" -HOME_DOMAIN="publicnode.org" -PUBLIC_KEY="GCIXVKNFPKWVMKJKVK2V4NK7D4TC6W3BUMXSIJ365QUAXWBRPPJXIR2Z" -ADDRESS="lyra.publicnode.org" -HISTORY="curl -sf https://lyra-history.publicnode.org/{0} -o {1}" - -[[VALIDATORS]] -NAME="Blockdaemon_Validator_1" -HOME_DOMAIN="stellar.blockdaemon.com" -PUBLIC_KEY="GAAV2GCVFLNN522ORUYFV33E76VPC22E72S75AQ6MBR5V45Z5DWVPWEU" -ADDRESS="stellar-full-validator1.bdnodes.net" -HISTORY="curl -sf https://stellar-full-history1.bdnodes.net/{0} -o {1}" - -[[VALIDATORS]] -NAME="Blockdaemon_Validator_2" -HOME_DOMAIN="stellar.blockdaemon.com" -PUBLIC_KEY="GAVXB7SBJRYHSG6KSQHY74N7JAFRL4PFVZCNWW2ARI6ZEKNBJSMSKW7C" -ADDRESS="stellar-full-validator2.bdnodes.net" -HISTORY="curl -sf https://stellar-full-history2.bdnodes.net/{0} -o {1}" - -[[VALIDATORS]] -NAME="Blockdaemon_Validator_3" -HOME_DOMAIN="stellar.blockdaemon.com" -PUBLIC_KEY="GAYXZ4PZ7P6QOX7EBHPIZXNWY4KCOBYWJCA4WKWRKC7XIUS3UJPT6EZ4" -ADDRESS="stellar-full-validator3.bdnodes.net" -HISTORY="curl -sf https://stellar-full-history3.bdnodes.net/{0} -o {1}" - -[[VALIDATORS]] -NAME = "FT_SCV_1" -HOME_DOMAIN = "www.franklintempleton.com" -PUBLIC_KEY = "GARYGQ5F2IJEBCZJCBNPWNWVDOFK7IBOHLJKKSG2TMHDQKEEC6P4PE4V" -ADDRESS = "stellar1.franklintempleton.com:11625" -HISTORY = "curl -sf https://stellar-history-usw.franklintempleton.com/azuswshf401/{0} -o {1}" - -[[VALIDATORS]] -NAME = "FT_SCV_2" -HOME_DOMAIN = "www.franklintempleton.com" -PUBLIC_KEY = "GCMSM2VFZGRPTZKPH5OABHGH4F3AVS6XTNJXDGCZ3MKCOSUBH3FL6DOB" -ADDRESS = "stellar2.franklintempleton.com:11625" -HISTORY = "curl -sf https://stellar-history-usc.franklintempleton.com/azuscshf401/{0} -o {1}" - -[[VALIDATORS]] -NAME = "FT_SCV_3" -HOME_DOMAIN = "www.franklintempleton.com" -PUBLIC_KEY = "GA7DV63PBUUWNUFAF4GAZVXU2OZMYRATDLKTC7VTCG7AU4XUPN5VRX4A" -ADDRESS = "stellar3.franklintempleton.com:11625" -HISTORY = "curl -sf https://stellar-history-ins.franklintempleton.com/azinsshf401/{0} -o {1}" \ No newline at end of file diff --git a/services/horizon/docker/captive-core-testnet.cfg b/services/horizon/docker/captive-core-testnet.cfg deleted file mode 100644 index af327834d7..0000000000 --- a/services/horizon/docker/captive-core-testnet.cfg +++ /dev/null @@ -1,29 +0,0 @@ -PEER_PORT=11725 - -UNSAFE_QUORUM=true -FAILURE_SAFETY=1 - -[[HOME_DOMAINS]] -HOME_DOMAIN="testnet.stellar.org" -QUALITY="HIGH" - -[[VALIDATORS]] -NAME="sdf_testnet_1" -HOME_DOMAIN="testnet.stellar.org" -PUBLIC_KEY="GDKXE2OZMJIPOSLNA6N6F2BVCI3O777I2OOC4BV7VOYUEHYX7RTRYA7Y" -ADDRESS="core-testnet1.stellar.org" -HISTORY="curl -sf http://history.stellar.org/prd/core-testnet/core_testnet_001/{0} -o {1}" - -[[VALIDATORS]] -NAME="sdf_testnet_2" -HOME_DOMAIN="testnet.stellar.org" -PUBLIC_KEY="GCUCJTIYXSOXKBSNFGNFWW5MUQ54HKRPGJUTQFJ5RQXZXNOLNXYDHRAP" -ADDRESS="core-testnet2.stellar.org" -HISTORY="curl -sf http://history.stellar.org/prd/core-testnet/core_testnet_002/{0} -o {1}" - -[[VALIDATORS]] -NAME="sdf_testnet_3" -HOME_DOMAIN="testnet.stellar.org" -PUBLIC_KEY="GC2V2EFSXN6SQTWVYA5EPJPBWWIMSD2XQNKUOHGEKB535AQE2I6IXV2Z" -ADDRESS="core-testnet3.stellar.org" -HISTORY="curl -sf http://history.stellar.org/prd/core-testnet/core_testnet_003/{0} -o {1}" \ No newline at end of file diff --git a/services/horizon/docker/docker-compose.pubnet.yml b/services/horizon/docker/docker-compose.pubnet.yml index f6e380749d..169045d7d1 100644 --- a/services/horizon/docker/docker-compose.pubnet.yml +++ b/services/horizon/docker/docker-compose.pubnet.yml @@ -3,8 +3,4 @@ services: horizon: platform: linux/amd64 environment: - - HISTORY_ARCHIVE_URLS=https://history.stellar.org/prd/core-live/core_live_001 - - NETWORK_PASSPHRASE=Public Global Stellar Network ; September 2015 - - CAPTIVE_CORE_CONFIG_APPEND_PATH=/captive-core-pubnet.cfg - volumes: - - ./captive-core-pubnet.cfg:/captive-core-pubnet.cfg + - NETWORK=pubnet \ No newline at end of file diff --git a/services/horizon/docker/docker-compose.yml b/services/horizon/docker/docker-compose.yml index 40bced6677..af0b6721b6 100644 --- a/services/horizon/docker/docker-compose.yml +++ b/services/horizon/docker/docker-compose.yml @@ -27,13 +27,8 @@ services: - "11725:11725" environment: - DATABASE_URL=postgres://postgres@host.docker.internal:5432/horizon?sslmode=disable - - CAPTIVE_CORE_CONFIG_APPEND_PATH=/captive-core-testnet.cfg - - HISTORY_ARCHIVE_URLS=https://history.stellar.org/prd/core-testnet/core_testnet_001 - - NETWORK_PASSPHRASE=Test SDF Network ; September 2015 - - INGEST=true + - NETWORK=testnet - PER_HOUR_RATE_LIMIT=0 - volumes: - - ./captive-core-testnet.cfg:/captive-core-testnet.cfg command: ["--apply-migrations"] extra_hosts: - "host.docker.internal:host-gateway" diff --git a/services/horizon/internal/app.go b/services/horizon/internal/app.go index 119e875787..f5373d07a8 100644 --- a/services/horizon/internal/app.go +++ b/services/horizon/internal/app.go @@ -118,22 +118,6 @@ func (a *App) Serve() error { signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - if a.config.UsingDefaultPubnetConfig { - const warnMsg = "Horizon started using the default pubnet configuration. " + - "This is not safe! Please provide a custom --captive-core-config-path." - log.Warn(warnMsg) - go func() { - for { - select { - case <-time.After(time.Hour): - log.Warn(warnMsg) - case <-a.done: - return - } - } - }() - } - go func() { select { case <-signalChan: diff --git a/services/horizon/internal/config.go b/services/horizon/internal/config.go index 23329423a5..5a9776e5e2 100644 --- a/services/horizon/internal/config.go +++ b/services/horizon/internal/config.go @@ -21,7 +21,6 @@ type Config struct { EnableCaptiveCoreIngestion bool EnableIngestionFiltering bool - UsingDefaultPubnetConfig bool CaptiveCoreBinaryPath string RemoteCaptiveCoreURL string CaptiveCoreConfigPath string @@ -114,4 +113,6 @@ type Config struct { BehindAWSLoadBalancer bool // RoundingSlippageFilter excludes trades from /trade_aggregations with rounding slippage >x bps RoundingSlippageFilter int + // Stellar network: 'testnet' or 'pubnet' + Network string } diff --git a/services/horizon/configs/captive-core-pubnet.cfg b/services/horizon/internal/configs/captive-core-pubnet.cfg similarity index 100% rename from services/horizon/configs/captive-core-pubnet.cfg rename to services/horizon/internal/configs/captive-core-pubnet.cfg diff --git a/services/horizon/configs/captive-core-testnet.cfg b/services/horizon/internal/configs/captive-core-testnet.cfg similarity index 100% rename from services/horizon/configs/captive-core-testnet.cfg rename to services/horizon/internal/configs/captive-core-testnet.cfg diff --git a/services/horizon/internal/flags.go b/services/horizon/internal/flags.go index 64982e3068..db36cacb63 100644 --- a/services/horizon/internal/flags.go +++ b/services/horizon/internal/flags.go @@ -1,12 +1,12 @@ package horizon import ( + _ "embed" "fmt" "go/types" stdLog "log" "os" "os/exec" - "path/filepath" "strings" "github.com/sirupsen/logrus" @@ -18,6 +18,7 @@ import ( apkg "github.com/stellar/go/support/app" support "github.com/stellar/go/support/config" "github.com/stellar/go/support/db" + "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" "github.com/stellar/throttled" ) @@ -38,10 +39,21 @@ const ( captiveCoreConfigAppendPathName = "captive-core-config-append-path" // CaptiveCoreConfigPathName is the command line flag for configuring the path to the captive core configuration file CaptiveCoreConfigPathName = "captive-core-config-path" - // captive-core-use-db is the command line flag for enabling captive core runtime to use an external db url connection rather than RAM for ledger states + // CaptiveCoreConfigUseDB is the command line flag for enabling captive core runtime to use an external db url + // connection rather than RAM for ledger states CaptiveCoreConfigUseDB = "captive-core-use-db" + // NetworkPassphraseFlagName is the command line flag for specifying the network passphrase + NetworkPassphraseFlagName = "network-passphrase" + // HistoryArchiveURLsFlagName is the command line flag for specifying the history archive URLs + HistoryArchiveURLsFlagName = "history-archive-urls" + // NetworkFlagName is the command line flag for specifying the "network" + NetworkFlagName = "network" captiveCoreMigrationHint = "If you are migrating from Horizon 1.x.y, start with the Migration Guide here: https://developers.stellar.org/docs/run-api-server/migrating/" + // StellarPubnet is a constant representing the Stellar public network + StellarPubnet = "pubnet" + // StellarTestnet is a constant representing the Stellar test network + StellarTestnet = "testnet" ) // validateBothOrNeither ensures that both options are provided, if either is provided. @@ -226,7 +238,7 @@ func Flags() (*Config, support.ConfigOptions) { return nil }, Required: false, - Usage: "Storage location for Captive Core bucket data", + Usage: "Storage location for Captive Core bucket data. If not set, the current working directory is used as the default location.", ConfigKey: &config.CaptiveCoreStoragePath, }, &support.ConfigOption{ @@ -253,15 +265,19 @@ func Flags() (*Config, support.ConfigOptions) { Usage: "stellar-core to connect with (for http commands). If unset and the local Captive core is enabled, it will use http://localhost:", }, &support.ConfigOption{ - Name: "history-archive-urls", - ConfigKey: &config.HistoryArchiveURLs, - OptType: types.String, - Required: false, - FlagDefault: "", + Name: HistoryArchiveURLsFlagName, + ConfigKey: &config.HistoryArchiveURLs, + OptType: types.String, + Required: false, CustomSetValue: func(co *support.ConfigOption) error { stringOfUrls := viper.GetString(co.Name) urlStrings := strings.Split(stringOfUrls, ",") - *(co.ConfigKey.(*[]string)) = urlStrings + //urlStrings contains a single empty value when stringOfUrls is empty + if len(urlStrings) == 1 && urlStrings[0] == "" { + *(co.ConfigKey.(*[]string)) = []string{} + } else { + *(co.ConfigKey.(*[]string)) = urlStrings + } return nil }, Usage: "comma-separated list of stellar history archives to connect with", @@ -412,10 +428,10 @@ func Flags() (*Config, support.ConfigOptions) { " A value of zero (the default) disables the limit.", }, &support.ConfigOption{ - Name: "network-passphrase", + Name: NetworkPassphraseFlagName, ConfigKey: &config.NetworkPassphrase, OptType: types.String, - Required: true, + Required: false, Usage: "Override the network passphrase", }, &support.ConfigOption{ @@ -557,6 +573,25 @@ func Flags() (*Config, support.ConfigOptions) { Required: false, Usage: "excludes trades from /trade_aggregations unless their rounding slippage is 0 { + return fmt.Errorf("invalid config: %s not allowed with %s network", HistoryArchiveURLsFlagName, config.Network) + } + + var defaultNetworkConfig networkConfig + switch config.Network { + case StellarPubnet: + defaultNetworkConfig = pubnetConf + case StellarTestnet: + defaultNetworkConfig = testnetConf + default: + return fmt.Errorf("no default configuration found for network %s", config.Network) + } + config.NetworkPassphrase = defaultNetworkConfig.networkPassphrase + config.HistoryArchiveURLs = defaultNetworkConfig.historyArchiveURLs + + if config.CaptiveCoreConfigPath == "" { + return loadDefaultCaptiveCoreToml(config, defaultNetworkConfig.defaultConfig) + } + + return loadCaptiveCoreTomlFromFile(config) +} + +// createCaptiveCoreConfigFromParameters generates the Captive Core configuration. +// validates the configuration settings, sets necessary values, and loads the Captive Core TOML file. +func createCaptiveCoreConfigFromParameters(config *Config) error { + + if config.NetworkPassphrase == "" { + return fmt.Errorf("%s must be set", NetworkPassphraseFlagName) + } + + if len(config.HistoryArchiveURLs) == 0 { + return fmt.Errorf("%s must be set", HistoryArchiveURLsFlagName) + } + + if config.CaptiveCoreConfigPath != "" { + return loadCaptiveCoreTomlFromFile(config) + } else { + var err error + config.CaptiveCoreToml, err = ledgerbackend.NewCaptiveCoreToml(config.CaptiveCoreTomlParams) + if err != nil { + return errors.Wrap(err, "invalid captive core toml file") + } + } + + return nil +} + +// setCaptiveCoreConfiguration prepares configuration for the Captive Core +func setCaptiveCoreConfiguration(config *Config) error { + stdLog.Println("Preparing captive core...") + + // If the user didn't specify a Stellar Core binary, we can check the + // $PATH and possibly fill it in for them. + if config.CaptiveCoreBinaryPath == "" { + var err error + if config.CaptiveCoreBinaryPath, err = getCaptiveCoreBinaryPath(); err != nil { + return fmt.Errorf("captive core requires %s", StellarCoreBinaryPathName) + } + } + + if config.Network != "" { + err := createCaptiveCoreConfigFromNetwork(config) + if err != nil { + return errors.Wrap(err, "error generating default captive core config.") + } + } else { + err := createCaptiveCoreConfigFromParameters(config) + if err != nil { + return errors.Wrap(err, "error generating captive core config.") + } + } + + // If we don't supply an explicit core URL and running captive core process with the http port enabled, + // point to it. + if config.StellarCoreURL == "" && config.CaptiveCoreToml.HTTPPort != 0 { + config.StellarCoreURL = fmt.Sprintf("http://localhost:%d", config.CaptiveCoreToml.HTTPPort) + } + + return nil +} + // ApplyFlags applies the command line flags on the given Config instance func ApplyFlags(config *Config, flags support.ConfigOptions, options ApplyOptions) error { // Verify required options and load the config struct @@ -623,94 +814,10 @@ func ApplyFlags(config *Config, flags support.ConfigOptions, options ApplyOption return err } - // config.HistoryArchiveURLs contains a single empty value when empty so using - // viper.GetString is easier. - if len(config.HistoryArchiveURLs) == 1 && config.HistoryArchiveURLs[0] == "" { - return fmt.Errorf("--history-archive-urls must be set when --ingest is set") - } - if config.EnableCaptiveCoreIngestion { - stdLog.Println("Preparing captive core...") - - binaryPath := viper.GetString(StellarCoreBinaryPathName) - - // If the user didn't specify a Stellar Core binary, we can check the - // $PATH and possibly fill it in for them. - if binaryPath == "" { - if result, err := exec.LookPath("stellar-core"); err == nil { - binaryPath = result - viper.Set(StellarCoreBinaryPathName, binaryPath) - config.CaptiveCoreBinaryPath = binaryPath - } else { - return fmt.Errorf("invalid config: captive core requires --%s. %s", - StellarCoreBinaryPathName, captiveCoreMigrationHint) - } - } else { - config.CaptiveCoreBinaryPath = binaryPath - } - - config.CaptiveCoreTomlParams.CoreBinaryPath = config.CaptiveCoreBinaryPath - if config.CaptiveCoreConfigPath == "" { - if options.RequireCaptiveCoreConfig { - var err error - errorMessage := fmt.Errorf( - "invalid config: captive core requires that --%s is set. %s", - CaptiveCoreConfigPathName, captiveCoreMigrationHint, - ) - - var configFileName string - // Default config files will be located along the binary in the release archive. - switch config.NetworkPassphrase { - case network.TestNetworkPassphrase: - configFileName = "captive-core-testnet.cfg" - config.HistoryArchiveURLs = []string{"https://history.stellar.org/prd/core-testnet/core_testnet_001/"} - case network.PublicNetworkPassphrase: - configFileName = "captive-core-pubnet.cfg" - config.HistoryArchiveURLs = []string{"https://history.stellar.org/prd/core-live/core_live_001/"} - config.UsingDefaultPubnetConfig = true - default: - return errorMessage - } - - executablePath, err := os.Executable() - if err != nil { - return errorMessage - } - - config.CaptiveCoreConfigPath = filepath.Join(filepath.Dir(executablePath), configFileName) - if _, err = os.Stat(config.CaptiveCoreConfigPath); os.IsNotExist(err) { - return errorMessage - } - - config.CaptiveCoreTomlParams.NetworkPassphrase = config.NetworkPassphrase - config.CaptiveCoreToml, err = ledgerbackend.NewCaptiveCoreTomlFromFile(config.CaptiveCoreConfigPath, config.CaptiveCoreTomlParams) - if err != nil { - return fmt.Errorf("Invalid captive core toml file %v", err) - } - } else { - var err error - config.CaptiveCoreTomlParams.HistoryArchiveURLs = config.HistoryArchiveURLs - config.CaptiveCoreTomlParams.NetworkPassphrase = config.NetworkPassphrase - config.CaptiveCoreToml, err = ledgerbackend.NewCaptiveCoreToml(config.CaptiveCoreTomlParams) - if err != nil { - return fmt.Errorf("Invalid captive core toml file %v", err) - } - } - } else { - var err error - config.CaptiveCoreTomlParams.HistoryArchiveURLs = config.HistoryArchiveURLs - config.CaptiveCoreTomlParams.NetworkPassphrase = config.NetworkPassphrase - config.CaptiveCoreToml, err = ledgerbackend.NewCaptiveCoreTomlFromFile(config.CaptiveCoreConfigPath, config.CaptiveCoreTomlParams) - if err != nil { - return fmt.Errorf("Invalid captive core toml file %v", err) - } - } - - // If we don't supply an explicit core URL and we are running a local - // captive core process with the http port enabled, point to it. - if config.StellarCoreURL == "" && config.CaptiveCoreToml.HTTPPort != 0 { - config.StellarCoreURL = fmt.Sprintf("http://localhost:%d", config.CaptiveCoreToml.HTTPPort) - viper.Set(StellarCoreURLFlagName, config.StellarCoreURL) + err := setCaptiveCoreConfiguration(config) + if err != nil { + return errors.Wrap(err, "error generating captive core configuration") } } } else { diff --git a/services/horizon/internal/flags_test.go b/services/horizon/internal/flags_test.go new file mode 100644 index 0000000000..9505fbe44e --- /dev/null +++ b/services/horizon/internal/flags_test.go @@ -0,0 +1,133 @@ +package horizon + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_createCaptiveCoreDefaultConfig(t *testing.T) { + + var errorMsgDefaultConfig = "invalid config: %s not allowed with %s network" + tests := []struct { + name string + config Config + networkPassphrase string + historyArchiveURLs []string + errStr string + }{ + { + name: "testnet default config", + config: Config{Network: StellarTestnet}, + networkPassphrase: testnetConf.networkPassphrase, + historyArchiveURLs: testnetConf.historyArchiveURLs, + }, + { + name: "pubnet default config", + config: Config{Network: StellarPubnet}, + networkPassphrase: pubnetConf.networkPassphrase, + historyArchiveURLs: pubnetConf.historyArchiveURLs, + }, + { + name: "testnet validation; history archive urls supplied", + config: Config{Network: StellarTestnet, + HistoryArchiveURLs: []string{"network history archive urls supplied"}, + }, + errStr: fmt.Sprintf(errorMsgDefaultConfig, HistoryArchiveURLsFlagName, StellarTestnet), + }, + { + name: "pubnet validation; history archive urls supplied", + config: Config{Network: StellarPubnet, + HistoryArchiveURLs: []string{"network history archive urls supplied"}, + }, + errStr: fmt.Sprintf(errorMsgDefaultConfig, HistoryArchiveURLsFlagName, StellarPubnet), + }, + { + name: "testnet validation; network passphrase supplied", + config: Config{Network: StellarTestnet, + NetworkPassphrase: "network passphrase supplied", + HistoryArchiveURLs: []string{}, + }, + errStr: fmt.Sprintf(errorMsgDefaultConfig, NetworkPassphraseFlagName, StellarTestnet), + }, + { + name: "pubnet validation; network passphrase supplied", + config: Config{Network: StellarPubnet, + NetworkPassphrase: "pubnet network passphrase supplied", + HistoryArchiveURLs: []string{}, + }, + errStr: fmt.Sprintf(errorMsgDefaultConfig, NetworkPassphraseFlagName, StellarPubnet), + }, + { + name: "unknown network specified", + config: Config{Network: "unknown", + NetworkPassphrase: "", + HistoryArchiveURLs: []string{}, + }, + errStr: "no default configuration found for network unknown", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := createCaptiveCoreConfigFromNetwork(&tt.config) + if tt.errStr == "" { + assert.NoError(t, e) + assert.Equal(t, tt.networkPassphrase, tt.config.NetworkPassphrase) + assert.Equal(t, tt.historyArchiveURLs, tt.config.HistoryArchiveURLs) + } else { + assert.Equal(t, tt.errStr, e.Error()) + } + }) + } +} + +func Test_createCaptiveCoreConfig(t *testing.T) { + + var errorMsgConfig = "%s must be set" + tests := []struct { + name string + config Config + networkPassphrase string + historyArchiveURLs []string + errStr string + }{ + { + name: "no network specified", + config: Config{ + NetworkPassphrase: "NetworkPassphrase", + HistoryArchiveURLs: []string{"HistoryArchiveURLs"}, + }, + networkPassphrase: "NetworkPassphrase", + historyArchiveURLs: []string{"HistoryArchiveURLs"}, + }, + { + name: "no network specified; passphrase not supplied", + config: Config{ + HistoryArchiveURLs: []string{"HistoryArchiveURLs"}, + }, + errStr: fmt.Sprintf(errorMsgConfig, NetworkPassphraseFlagName), + }, + { + name: "no network specified; history archive urls not supplied", + config: Config{ + NetworkPassphrase: "NetworkPassphrase", + }, + errStr: fmt.Sprintf(errorMsgConfig, HistoryArchiveURLsFlagName), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := createCaptiveCoreConfigFromParameters(&tt.config) + if tt.errStr == "" { + assert.NoError(t, e) + assert.Equal(t, tt.networkPassphrase, tt.config.NetworkPassphrase) + assert.Equal(t, tt.historyArchiveURLs, tt.config.HistoryArchiveURLs) + } else { + require.Error(t, e) + assert.Equal(t, tt.errStr, e.Error()) + } + }) + } +} diff --git a/support/scripts/build_release_artifacts/main.go b/support/scripts/build_release_artifacts/main.go index 4acbba1b2c..0a96d627fa 100644 --- a/support/scripts/build_release_artifacts/main.go +++ b/support/scripts/build_release_artifacts/main.go @@ -321,11 +321,6 @@ func prepareDest(pkg, bin, version, os, arch string) string { run("cp", "COPYING", dest) run("cp", filepath.Join(pkg, "README.md"), dest) run("cp", filepath.Join(pkg, "CHANGELOG.md"), dest) - if bin == "horizon" { - // Add default config files for Captive-Core - run("cp", filepath.Join(pkg, "configs/captive-core-pubnet.cfg"), dest) - run("cp", filepath.Join(pkg, "configs/captive-core-testnet.cfg"), dest) - } return dest }