Documentation
¶
Overview ¶
Package db provides optional SQLite-backed persistence for buildoor runtime state: settings overrides, won blocks, validator registrations, proposer preferences and an audit log. It mirrors the database patterns used by the sibling spamoor project (glebarez/go-sqlite + sqlx + goose migrations).
Persistence is opt-in: when the configured file path is empty the Database runs in a disabled mode where every method is a no-op (reads return empty, writes are dropped). This keeps callers free of nil-checks while preserving the original in-memory-only behaviour when --state-db is not set.
Index ¶
- type AuditLog
- type Config
- type Database
- func (d *Database) AppendAuditLog(entry AuditLog) error
- func (d *Database) Close() error
- func (d *Database) Enabled() bool
- func (d *Database) GetAuditLogs(offset, limit int) ([]AuditLog, int, error)
- func (d *Database) GetSettings() ([]SettingRow, error)
- func (d *Database) Init() error
- func (d *Database) PutSetting(row SettingRow) error
- func (d *Database) RunDBTransaction(handler func(tx *sqlx.Tx) error) error
- type KVCodec
- type KVPersistence
- type SettingRow
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuditLog ¶
type AuditLog struct {
ID int64 `db:"id" json:"id"`
Timestamp int64 `db:"timestamp" json:"timestamp"`
Actor string `db:"actor" json:"actor"`
RemoteAddr string `db:"remote_addr" json:"remote_addr"`
Action string `db:"action" json:"action"`
Target string `db:"target" json:"target"`
Detail string `db:"detail" json:"detail"`
Result string `db:"result" json:"result"`
}
AuditLog records a single authenticated mutating action against the API.
type Config ¶
type Config struct {
// File is the path to the SQLite database file. When empty the database
// is disabled and all operations become no-ops.
File string
// MaxOpenConns and MaxIdleConns bound the connection pool. Zero values
// fall back to sensible defaults.
MaxOpenConns int
MaxIdleConns int
}
Config configures the SQLite database connection.
type Database ¶
type Database struct {
// contains filtered or unexported fields
}
Database wraps a SQLite connection and exposes the buildoor persistence repositories. A single connection is shared for reads and writes; writes are serialised by writerMutex to avoid "database is locked" under WAL.
func NewDatabase ¶
func NewDatabase(config *Config, logger logrus.FieldLogger) *Database
NewDatabase creates a Database. When config.File is empty the database is disabled and Init/repository methods become no-ops.
func (*Database) AppendAuditLog ¶
AppendAuditLog inserts an audit entry and prunes the table to maxAuditLogs rows. No-op when the database is disabled.
func (*Database) Enabled ¶
Enabled reports whether persistence is active (a file path was configured).
func (*Database) GetAuditLogs ¶
GetAuditLogs returns a page of audit entries (newest first) and the total count. Returns an empty page when the database is disabled.
func (*Database) GetSettings ¶
func (d *Database) GetSettings() ([]SettingRow, error)
GetSettings returns all persisted settings rows. Returns an empty slice when the database is disabled.
func (*Database) Init ¶
Init opens the SQLite connection (WAL mode) and applies embedded migrations. It is a no-op when the database is disabled.
func (*Database) PutSetting ¶
func (d *Database) PutSetting(row SettingRow) error
PutSetting upserts the full 3-way state for a settings key. No-op when the database is disabled. The settings service owns the in-memory authority and always writes the complete row, so a plain INSERT OR REPLACE is correct.
type KVCodec ¶ added in v0.0.2
type KVCodec[K comparable, V any] interface { EncodeKey(key K) string DecodeKey(key string) (K, error) EncodeValue(value V) ([]byte, error) DecodeValue(value []byte) (V, error) }
KVCodec translates a store's key/value types to their persisted form. Implementations live with the flavor owner (the module that manages the data); values are opaque blobs (typically SSZ-encoded).
type KVPersistence ¶ added in v0.0.2
type KVPersistence[K comparable, V any] struct { // contains filtered or unexported fields }
KVPersistence is the single generic memstore.Persistence implementation over the namespaced kv_store table: Load reads a namespace, PersistBatch applies upserts and deletes in a single transaction. Honors the disabled no-op mode (Load returns empty, PersistBatch returns nil).
func NewKVPersistence ¶ added in v0.0.2
func NewKVPersistence[K comparable, V any](d *Database, namespace string, codec KVCodec[K, V]) *KVPersistence[K, V]
NewKVPersistence creates a persistence adapter for one kv_store namespace.
func (*KVPersistence[K, V]) Load ¶ added in v0.0.2
func (p *KVPersistence[K, V]) Load() (map[K]V, error)
Load returns all decodable entries of the namespace. Undecodable rows are skipped with a debug log (best-effort cache data). Returns an empty map when the database is disabled.
func (*KVPersistence[K, V]) PersistBatch ¶ added in v0.0.2
func (p *KVPersistence[K, V]) PersistBatch(upserts map[K]V, deletes []K) error
PersistBatch upserts and deletes the given entries in a single transaction. Values that fail to encode are skipped with a warning (retrying them can never succeed). No-op when the database is disabled.
type SettingRow ¶
type SettingRow struct {
Key string `db:"key"`
CLIValue sql.NullString `db:"cli_value"`
CLISeq int64 `db:"cli_seq"`
UIValue sql.NullString `db:"ui_value"`
UISeq int64 `db:"ui_seq"`
UpdatedAt int64 `db:"updated_at"`
Actor string `db:"actor"`
}
SettingRow is the persisted 3-way state for a single settings key.
Resolution: the hardcoded default (in code) is the floor; cli_value and ui_value override it, and whichever has the higher seq wins. A seq of 0 means that layer is absent. cli_value tracks the last operator-supplied value (flag/env/config); a change to it is detected by value-diff on startup and bumps cli_seq so the CLI write "wins" until the UI sets a newer value.