Skip to content

Commit

Permalink
config: add comments, remove koanf tag, fix toml Duration
Browse files Browse the repository at this point in the history
This change adds "comment" tags, which are used in two places:
 - TOML comments for each field or section
 - cli flag descriptions

This also removes the unneeded "koanf" tags and now specify "toml"
as the attribute tag used for config merging.

Replace a few time.Duration fields with config.Duration so these
durations are set correctly as duration strings in TOML rather
than giant integers.

Finally, remove the replaces from go.mod and go mod tidy.
  • Loading branch information
jchappelow committed Dec 12, 2024
1 parent 7353f27 commit 2855286
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 104 deletions.
6 changes: 3 additions & 3 deletions app/node/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,14 @@ func buildServer(ctx context.Context, d *coreDependencies) *server {
jsonRPCTxSvc := usersvc.NewService(db, e, node, bp, vs, rpcSvcLogger,
usersvc.WithReadTxTimeout(time.Duration(d.cfg.DB.ReadTxTimeout)),
usersvc.WithPrivateMode(d.cfg.RPC.Private),
usersvc.WithChallengeExpiry(d.cfg.RPC.ChallengeExpiry),
usersvc.WithChallengeExpiry(time.Duration(d.cfg.RPC.ChallengeExpiry)),
usersvc.WithChallengeRateLimit(d.cfg.RPC.ChallengeRateLimit),
// usersvc.WithBlockAgeHealth(6*totalConsensusTimeouts.Dur()),
)

rpcServerLogger := d.logger.New("RPC")
jsonRPCServer, err := rpcserver.NewServer(d.cfg.RPC.ListenAddress,
rpcServerLogger, rpcserver.WithTimeout(d.cfg.RPC.Timeout),
rpcServerLogger, rpcserver.WithTimeout(time.Duration(d.cfg.RPC.Timeout)),
rpcserver.WithReqSizeLimit(d.cfg.RPC.MaxReqSize),
rpcserver.WithCORS(), rpcserver.WithServerInfo(&usersvc.SpecInfo),
rpcserver.WithMetricsNamespace("kwil_json_rpc_user_server"))
Expand Down Expand Up @@ -245,7 +245,7 @@ func buildConsensusEngine(_ context.Context, d *coreDependencies, db *pg.DB,
Mempool: mempool,
ValidatorSet: valSet,
Logger: d.logger.New("CONS"),
ProposeTimeout: d.cfg.Consensus.ProposeTimeout,
ProposeTimeout: time.Duration(d.cfg.Consensus.ProposeTimeout),
}

ce := consensus.New(ceCfg)
Expand Down
2 changes: 1 addition & 1 deletion app/node/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import (
// that combines multiple config sources according to the enabled preruns.
var k = koanf.New(".")

const koanfTag = "koanf"
const koanfTag = "toml"

// ActiveConfig retrieves the current merged config. This is influenced by the
// other functions in this package, including: BindDefaults,
Expand Down
145 changes: 72 additions & 73 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,16 @@ func DefaultConfig() *Config {
return &Config{
LogLevel: log.LevelInfo,
LogFormat: log.FormatUnstructured,
// Private key is empty by default.
// Private key is empty by default. This should probably be moved back
// to a key file again to avoid accidentally leaking the key.
P2P: PeerConfig{
IP: "0.0.0.0",
Port: 6600,
Pex: true,
BootNodes: []string{},
},
Consensus: ConsensusConfig{
ProposeTimeout: 1000 * time.Millisecond,
ProposeTimeout: Duration(1000 * time.Millisecond),
MaxBlockSize: 50_000_000,
MaxTxsPerBlock: 20_000,
},
Expand All @@ -131,15 +132,15 @@ func DefaultConfig() *Config {
},
RPC: RPCConfig{
ListenAddress: "0.0.0.0:8484",
Timeout: 20 * time.Second,
Timeout: Duration(20 * time.Second),
MaxReqSize: 6_000_000,
Private: false,
ChallengeExpiry: 30 * time.Second,
ChallengeExpiry: Duration(30 * time.Second),
ChallengeRateLimit: 10,
},
Admin: AdminConfig{
Enable: true,
ListenAddress: "/tmp/kwil2-admin.socket",
ListenAddress: "/tmp/kwild.socket",
Pass: "",
NoTLS: false,
TLSCertFile: "admin.cert",
Expand All @@ -152,54 +153,38 @@ func DefaultConfig() *Config {
},
StateSync: StateSyncConfig{
Enable: false,
DiscoveryTimeout: 30 * time.Second,
DiscoveryTimeout: Duration(30 * time.Second),
MaxRetries: 3,
},
}
}

// Config is the node's config.
type Config struct {
// NOTE about tags:
//
// - toml tags are used to marshal into a toml file with pelletier's go-toml
// (gotoml.Marshal: Config{} => []byte(tomlString))
//
// - koanf tags are used to unmarshal into this struct from a koanf instance
// (k.Unmarshal: map[string]interface{} => Config{})
//
// Presently these tags are the same. If we change the canonicalization,
// such as removing both dashes and underscores, the tags would be different.

LogLevel log.Level `koanf:"log_level" toml:"log_level" comment:"log level"`
LogFormat log.Format `koanf:"log_format" toml:"log_format" comment:"log format"`
// LogOutput []string `koanf:"log_output" toml:"log_output" comment:"output paths for the log"`

PrivateKey types.HexBytes `koanf:"privkey" toml:"privkey" comment:"private key to use for node"`

// ProfileMode string `koanf:"profile_mode" toml:"profile_mode"`
// ProfileFile string `koanf:"profile_file" toml:"profile_file"`

// subsections below

P2P PeerConfig `koanf:"p2p" toml:"p2p"`

Consensus ConsensusConfig `koanf:"consensus" toml:"consensus"`
DB DBConfig `koanf:"db" toml:"db"`
RPC RPCConfig `koanf:"rpc" toml:"rpc"`
Admin AdminConfig `koanf:"admin" toml:"admin"`
Snapshots SnapshotConfig `koanf:"snapshots" toml:"snapshots"`
StateSync StateSyncConfig `koanf:"state_sync" toml:"state_sync"`
LogLevel log.Level `toml:"log_level" comment:"log level\npossible values: 'debug', 'info', 'warn', and 'error'"`
LogFormat log.Format `toml:"log_format" comment:"log format\npossible values: 'json', 'text' (kv), and 'plain' (fmt-style)"`
// LogOutput []string `toml:"log_output" comment:"output paths for the log"`

PrivateKey types.HexBytes `toml:"privkey" comment:"private key to use for node"`

// ProfileMode string `toml:"profile_mode"`
// ProfileFile string `toml:"profile_file"`

P2P PeerConfig `toml:"p2p" comment:"P2P related configuration"`
Consensus ConsensusConfig `toml:"consensus" comment:"Consensus related configuration"`
DB DBConfig `toml:"db" comment:"DB (PostgreSQL) related configuration"`
RPC RPCConfig `toml:"rpc" comment:"User RPC service configuration"`
Admin AdminConfig `toml:"admin" comment:"Admin RPC service configuration"`
Snapshots SnapshotConfig `toml:"snapshots" comment:"Snapshot creation and provider configuration"`
StateSync StateSyncConfig `toml:"state_sync" comment:"Statesync configuration (vs block sync)"`
}

// PeerConfig corresponds to the [peer] section of the config.
type PeerConfig struct {
IP string `koanf:"ip" toml:"ip" comment:"ip to listen on for P2P connections"`
Port uint64 `koanf:"port" toml:"port" comment:"port to listen on for P2P connections"`
Pex bool `koanf:"pex" toml:"pex" comment:"enable peer exchange"`
BootNodes []string `koanf:"bootnodes" toml:"bootnodes" comment:"bootnodes to connect to on startup"`

// ListenAddr string // "127.0.0.1:6600"
IP string `toml:"ip" comment:"IP address to listen on for P2P connections"`
Port uint64 `toml:"port" comment:"port to listen on for P2P connections"`
Pex bool `toml:"pex" comment:"enable peer exchange"`
BootNodes []string `toml:"bootnodes" comment:"bootnodes to connect to on startup"`
}

type DBConfig struct {
Expand All @@ -215,55 +200,63 @@ type DBConfig struct {
// However, this is less error prone, and prevents passing settings that
// would alter the functionality of the connection. An advanced option could
// be added to supplement the conn string if that seems useful.
Host string `koanf:"host" toml:"host"`
Port string `koanf:"port" toml:"port"`
User string `koanf:"user" toml:"user"`
Pass string `koanf:"pass" toml:"pass"`
DBName string `koanf:"dbname" toml:"dbname"`
ReadTxTimeout Duration `koanf:"read_timeout" toml:"read_timeout"`
MaxConns uint32 `koanf:"max_connections" toml:"max_connections"`
Host string `toml:"host" comment:"postgres host name (IP or UNIX socket path)"`
Port string `toml:"port" comment:"postgres TCP port (leave empty for UNIX socket)"`
User string `toml:"user" comment:"postgres role/user name"`
Pass string `toml:"pass" comment:"postgres password if required for the user and host"`
DBName string `toml:"dbname" comment:"postgres database name"`
ReadTxTimeout Duration `toml:"read_timeout" comment:"timeout on read transactions from user RPC calls and queries"`
MaxConns uint32 `toml:"max_connections" comment:"maximum number of DB connections to permit"`
}

type ConsensusConfig struct {
ProposeTimeout time.Duration `koanf:"propose_timeout" toml:"propose_timeout" comment:"timeout for proposing a block"`
MaxBlockSize uint64 `koanf:"max_block_size" toml:"max_block_size" comment:"max size of a block in bytes"`
MaxTxsPerBlock uint64 `koanf:"max_txs_per_block" toml:"max_txs_per_block" comment:"max number of transactions per block"`
ProposeTimeout Duration `toml:"propose_timeout" comment:"timeout for proposing a block (applies to leader)"`
MaxBlockSize uint64 `toml:"max_block_size" comment:"max size of a block in bytes"`
MaxTxsPerBlock uint64 `toml:"max_txs_per_block" comment:"max number of transactions per block"`
// ? reannounce intervals?
}

type RPCConfig struct {
ListenAddress string `koanf:"listen" toml:"listen"`
Timeout time.Duration `koanf:"timeout" toml:"timeout"`
MaxReqSize int `koanf:"max_req_size" toml:"max_req_size"`
Private bool `koanf:"private" toml:"private"`
ChallengeExpiry time.Duration `koanf:"challenge_expiry" toml:"challenge_expiry"`
ChallengeRateLimit float64 `koanf:"challenge_rate_limit" toml:"challenge_rate_limit"`
ListenAddress string `toml:"listen" comment:"address in host:port format on which the RPC server will listen"`
Timeout Duration `toml:"timeout" comment:"user request duration limit after which it is cancelled"`
MaxReqSize int `toml:"max_req_size" comment:"largest permissible user request size"`
Private bool `toml:"private" comment:"enable private mode that requires challenge authentication for each call"`
ChallengeExpiry Duration `toml:"challenge_expiry" comment:"lifetime of a server-generated challenge"`
ChallengeRateLimit float64 `toml:"challenge_rate_limit" comment:"maximum number of challenges per second that a user can request"`
}

type AdminConfig struct {
Enable bool `koanf:"enable" toml:"enable"`
ListenAddress string `koanf:"listen" toml:"listen"`
Pass string `koanf:"pass" toml:"pass"`
NoTLS bool `koanf:"notls" toml:"notls"`
TLSCertFile string `koanf:"cert" toml:"cert"`
TLSKeyFile string `koanf:"key" toml:"key"`
Enable bool `toml:"enable" comment:"enable the admin RPC service"`
ListenAddress string `toml:"listen" comment:"address in host:port format or UNIX socket path on which the admin RPC server will listen"`
Pass string `toml:"pass" comment:"optional password for the admin service"`
NoTLS bool `toml:"notls" comment:"disable TLS when the listen address is not a loopback IP or UNIX socket"`
TLSCertFile string `toml:"cert" comment:"TLS certificate for use with a non-loopback listen address when notls is not true"`
TLSKeyFile string `toml:"key" comment:"TLS key for use with a non-loopback listen address when notls is not true"`
}

type SnapshotConfig struct {
Enable bool `koanf:"enable" toml:"enable"`
RecurringHeight uint64 `koanf:"recurring_height" toml:"recurring_height"`
MaxSnapshots uint64 `koanf:"max_snapshots" toml:"max_snapshots"`
Enable bool `toml:"enable" comment:"enable creating and providing snapshots for peers using statesync"`
RecurringHeight uint64 `toml:"recurring_height" comment:"snapshot creation period in blocks"`
MaxSnapshots uint64 `toml:"max_snapshots" comment:"number of snapshots to keep, after the oldest is removed when creating a new one"`
}

type StateSyncConfig struct {
Enable bool `koanf:"enable" toml:"enable"`
TrustedProviders []string `koanf:"trusted_providers" toml:"trusted_providers"`
Enable bool `toml:"enable" comment:"enable using statesync rather than blocksync"`
TrustedProviders []string `toml:"trusted_providers" comment:"trusted snapshot providers in node ID format (see bootnodes)"`

DiscoveryTimeout time.Duration `koanf:"discovery_timeout" toml:"discovery_time"`
MaxRetries uint64 `koanf:"max_retries" toml:"max_retries"`
DiscoveryTimeout Duration `toml:"discovery_time" comment:"how long to discover snapshots before selecting one to use"`
MaxRetries uint64 `toml:"max_retries" comment:"how many times to try after failing to apply a snapshot before switching to blocksync"`
}

// ConfigToTOML marshals the config to TOML.
// ConfigToTOML marshals the config to TOML. The `toml` struct field tag
// specifies the field names. For example:
//
// Enable bool `toml:"enable,commented" comment:"enable the thing"`
//
// The above field will be written like:
//
// # enable the thing
// #enable=false
func (nc Config) ToTOML() ([]byte, error) {
return toml.Marshal(nc)
}
Expand All @@ -272,13 +265,19 @@ func (nc *Config) FromTOML(b []byte) error {
return toml.Unmarshal(b, &nc)
}

// SaveAs writes the Config to the specified TOML file.
func (nc *Config) SaveAs(filename string) error {
bts, err := nc.ToTOML()
if err != nil {
return err
}

// TODO: write a toml header/comment or perhaps use a text/template toml file
// TODO: write a toml header/comment or do some prettification. The template
// was a maintenance burden, and we get setting and section comment with
// field tags, so I do not prefer ea template. If it does not look pretty
// enough, we may consider some basic post-processing of bts before writing
// it. For example, insert newlines before each "#", write a header at the
// top, etc.

return os.WriteFile(filename, bts, 0644)
}
Expand Down
2 changes: 1 addition & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func TestMarshalConfig(t *testing.T) {
k.Print()

var inCfg Config
k.UnmarshalWithConf("", &inCfg, koanf.UnmarshalConf{Tag: "koanf"})
k.UnmarshalWithConf("", &inCfg, koanf.UnmarshalConf{Tag: "toml"})

k.KeyMap()
spew.Dump(inCfg)
Expand Down
20 changes: 7 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ module github.com/kwilteam/kwil-db

go 1.22.0

// These replaces can be removed after this is merged to main.
replace (
github.com/kwilteam/kwil-db/core => ./core
github.com/kwilteam/kwil-db/parse => ./parse
)

require (
github.com/dgraph-io/badger/v4 v4.3.1
github.com/go-chi/chi/v5 v5.1.0
Expand All @@ -20,10 +14,10 @@ require (
github.com/knadh/koanf/providers/posflag v0.1.0
github.com/knadh/koanf/providers/rawbytes v0.1.0
github.com/knadh/koanf/providers/structs v0.1.0
github.com/knadh/koanf/v2 v2.1.1
github.com/kwilteam/kwil-db/core v0.3.1
github.com/kwilteam/kwil-db/parse v0.3.3
github.com/libp2p/go-libp2p v0.37.1
github.com/knadh/koanf/v2 v2.1.2
github.com/kwilteam/kwil-db/core v0.3.1-0.20241212163115-7353f2761884
github.com/kwilteam/kwil-db/parse v0.3.1-0.20241212163115-7353f2761884
github.com/libp2p/go-libp2p v0.37.2
github.com/libp2p/go-libp2p-kad-dht v0.28.1
github.com/libp2p/go-libp2p-pubsub v0.12.0
github.com/manifoldco/promptui v0.9.0
Expand All @@ -35,7 +29,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.10.0
golang.org/x/sync v0.9.0
golang.org/x/sync v0.10.0
golang.org/x/time v0.8.0
)

Expand Down Expand Up @@ -137,7 +131,7 @@ require (
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr-dns v0.4.0 // indirect
github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
Expand Down Expand Up @@ -170,7 +164,7 @@ require (
github.com/prometheus/common v0.60.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.48.1 // indirect
github.com/quic-go/quic-go v0.48.2 // indirect
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
Expand Down
Loading

0 comments on commit 2855286

Please sign in to comment.