main.go
Overview
The `main.go` file serves as the entry point for the Thorchain v1 API server within the ShapeShift Unchained project. Its primary responsibility is to initialize and configure the necessary components to run the API server, including loading configuration, setting up Cosmos SDK clients, initializing metrics, and managing lifecycle events such as graceful shutdown on system signals.
This file orchestrates the main runtime environment by:
Parsing command-line flags for environment configuration and Swagger specification location.
Loading configuration parameters from environment variables or an env file.
Setting up Cosmos SDK encoding and client configurations specific to Thorchain.
Creating HTTP and WebSocket clients to interact with Thorchain nodes.
Instantiating the API server with all dependencies.
Starting the HTTP server to serve API requests.
Handling OS signals for graceful termination.
Detailed Explanation
Package and Imports
Package:
mainImports: Standard libraries (
flag,os,os/signal,syscall) for CLI flags and signal handling; internal packages for configuration, logging, metrics, Cosmos SDK client utilities; Thorchain-specific types and API package.
Global Variables
var (
logger = log.WithoutFields()
envPath = flag.String("env", "", "path to env file (default: use os env)")
swaggerPath = flag.String("swagger", "coinstacks/thorchain-v1/api/swagger.json", "path to swagger spec")
)
logger: Logger instance without pre-set fields for general logging.envPath: CLI flag to specify a path to an environment file for configuration loading. Defaults to empty, which means use OS environment variables.swaggerPath: CLI flag specifying the path to the OpenAPI (Swagger) specification JSON file.
Config Struct
type Config struct {
LCDURL string `mapstructure:"LCD_URL"`
RPCURL string `mapstructure:"RPC_URL"`
WSURL string `mapstructure:"WS_URL"`
}
Holds URLs for Thorchain node endpoints:
LCDURL: REST endpoint (Light Client Daemon).RPCURL: RPC endpoint.WSURL: WebSocket endpoint.
These URLs are used to configure clients that interact with the Thorchain network.
main() Function
The `main` function executes the following sequence:
1. Parse CLI Flags
flag.Parse()
Reads `-env` and `-swagger` flag values.
2. Setup Channels and Signal Handling
errChan := make(chan error, 1)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
errChan: Buffered channel to receive runtime errors from goroutines.sigChan: Channel to listen for OS signals for graceful shutdown.
Supported signals:
SIGHUP(terminal line hangup)SIGINT(interrupt from keyboard)SIGTERM(termination signal)SIGQUIT(quit from keyboard)
3. Load Configuration
conf := &Config{}
if *envPath == "" {
if err := config.LoadFromEnv(conf, "LCD_URL", "RPC_URL", "WS_URL"); err != nil {
logger.Panicf("failed to load config from env: %+v", err)
}
} else {
if err := config.Load(*envPath, conf); err != nil {
logger.Panicf("failed to load config: %+v", err)
}
}
If no env file path is provided, load config from OS environment variables.
Otherwise, load from the specified
.envfile.Panic if configuration loading fails (stops the application).
4. Setup Cosmos Encoding and Client Config
encoding := cosmos.NewEncoding(thortypes.RegisterInterfaces)
Initializes protobuf encoding for Thorchain types using the interface registry from Thorchain's thornode repo.
cfg := cosmos.Config{
Bech32AddrPrefix: "thor",
Bech32PkPrefix: "thorpub",
Bech32ValPrefix: "thorv",
Bech32PkValPrefix: "thorvpub",
Denom: "rune",
NativeFee: 2000000,
Encoding: encoding,
LCDURL: conf.LCDURL,
RPCURL: conf.RPCURL,
WSURL: conf.WSURL,
}
Configures Cosmos client with Thorchain-specific Bech32 address prefixes.
Sets the native token denomination as "rune".
Sets a native fee constant (
2000000units) as per Thorchain documentation.Assigns the URLs from loaded config.
Injects the protobuf encoding.
5. Initialize Metrics
prometheus := metrics.NewPrometheus("thorchain-v1")
Sets up Prometheus metrics under the namespace
thorchain-v1.
6. Create Cosmos SDK HTTP Client
httpClient, err := cosmos.NewHTTPClient(cfg)
if err != nil {
logger.Panicf("failed to create new http client: %+v", err)
}
HTTP client used for REST API calls to Thorchain nodes.
7. Create Block Service
blockService, err := cosmos.NewBlockService(httpClient)
if err != nil {
logger.Panicf("failed to create new block service: %+v", err)
}
Service to query and process blockchain blocks.
8. Create WebSocket Client
wsClient, err := cosmos.NewWebsocketClient(cfg, blockService, errChan)
if err != nil {
logger.Panicf("failed to create new websocket client: %+v", err)
}
WebSocket client for real-time event subscriptions.
Passes
errChanto propagate client errors.
9. Initialize and Start API Server
api := api.New(cfg, httpClient, wsClient, blockService, *swaggerPath, prometheus)
defer api.Shutdown()
go api.Serve(errChan)
Constructs the API server, passing all dependencies.
Defers shutdown to clean up resources on exit.
Starts the API HTTP server in a separate goroutine, sending errors to
errChan.
10. Wait for Errors or OS Signals
select {
case err := <-errChan:
logger.Panicf("%+v", err)
case <-sigChan:
api.Shutdown()
os.Exit(0)
}
Blocks until either:
An error occurs in the API or clients (logged and panics).
OS signal received, which triggers graceful shutdown and exit.
Usage Examples
Running with Environment Variables
Set the required environment variables and run:
export LCD_URL=https://thorchain-node.com/lcd
export RPC_URL=https://thorchain-node.com/rpc
export WS_URL=wss://thorchain-node.com/ws
go run main.go
Running with an Env File and Custom Swagger Spec
go run main.go -env ./config/thorchain.env -swagger ./api/swagger.json
Important Implementation Details
Configuration Loading: Supports flexible configuration via environment variables or env files using
config.Loadandconfig.LoadFromEnv.Cosmos SDK Client Setup: Uses a custom encoding registry for Thorchain protobuf types and sets address prefixes to ensure proper address encoding/decoding.
Graceful Shutdown: Listens to common termination signals and shuts down the API server cleanly.
Error Propagation: Uses a buffered error channel to catch asynchronous errors from WebSocket client and API server.
Metrics: Integrates Prometheus metrics under a dedicated namespace for monitoring.
Interaction with Other Components
github.com/shapeshift/unchained/coinstacks/thorchain-v1/api
Theapipackage provides the HTTP server exposing Thorchain blockchain data and services.main.gocreates and runs the API server instance.github.com/shapeshift/unchained/pkg/cosmos
Provides Cosmos SDK clients and helpers such as HTTP client, WebSocket client, block service, and encoding utilities used to interact with Thorchain nodes.github.com/shapeshift/unchained/internal/config
Utilities for loading configuration from environment files or system environment variables.github.com/shapeshift/unchained/internal/log
Logging infrastructure used to log runtime information and fatal errors.github.com/shapeshift/unchained/pkg/metrics
Prometheus metrics setup for monitoring API server performance.gitlab.com/thorchain/thornode/v3/x/thorchain/types
Thorchain-specific protobuf type registration used during encoding setup.
Mermaid Flowchart Diagram
The following flowchart illustrates the startup workflow and interactions between the main components initialized in this file:
flowchart TD
A[Start main.go] --> B[Parse CLI flags]
B --> C[Load configuration]
C --> D[Setup Cosmos encoding & config]
D --> E[Initialize Prometheus metrics]
E --> F[Create Cosmos HTTP client]
F --> G[Create Block Service]
G --> H[Create WebSocket client]
H --> I[Initialize API server]
I --> J[Start API server (goroutine)]
J --> K[Wait for errors or OS signals]
K -->|Error received| L[Log and Panic]
K -->|Signal received| M[Shutdown API server]
M --> N[Exit process]
Summary
`main.go` is the bootstrap file that sets up the Thorchain v1 API server environment. It handles configuration, client creation, metrics, and lifecycle management to expose Thorchain blockchain data via a RESTful API and WebSocket. The file uses best practices for configuration flexibility, error handling, and graceful shutdown, integrating several internal and external packages to provide a robust server foundation.