db

package
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: GPL-3.0 Imports: 11 Imported by: 0

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

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

func (d *Database) AppendAuditLog(entry AuditLog) error

AppendAuditLog inserts an audit entry and prunes the table to maxAuditLogs rows. No-op when the database is disabled.

func (*Database) Close

func (d *Database) Close() error

Close closes the database connection. No-op when disabled.

func (*Database) Enabled

func (d *Database) Enabled() bool

Enabled reports whether persistence is active (a file path was configured).

func (*Database) GetAuditLogs

func (d *Database) GetAuditLogs(offset, limit int) ([]AuditLog, int, error)

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

func (d *Database) Init() error

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.

func (*Database) RunDBTransaction

func (d *Database) RunDBTransaction(handler func(tx *sqlx.Tx) error) error

RunDBTransaction runs handler inside a write transaction, serialised against other writers. Returns an error when the database is disabled.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL