Skip to content

feat: Database abstraction layer#81

Open
mitfik wants to merge 25 commits intomasterfrom
feat_db_abstraction
Open

feat: Database abstraction layer#81
mitfik wants to merge 25 commits intomasterfrom
feat_db_abstraction

Conversation

@mitfik
Copy link
Copy Markdown
Contributor

@mitfik mitfik commented Apr 2, 2026

Rebased and review changes from @zdravko61:

Few changes on top:

  • Make SimpleController generic over OobiStorageBackend
  • Fix Witness::setup_with_redb() to use separate oobi_database path
  • Fix WitnessListener::setup_with_redb() to use separate oobi_database path
  • Fix Watcher::setup_with_redb() to use separate oobi_database path
  • Fix WatcherListener::setup_with_redb() to use separate oobi_database path
  • Update all test files to use setup_with_redb() convenience methods
  • Fix witness tests to create separate oobi_database paths
  • Update broadcast.rs and delegated_incept tests to use new API

seriouscoderone and others added 25 commits April 1, 2026 20:53
…ry db

Gate redb behind `storage-redb` feature flag (default ON) in keri-core and
teliox so the core protocol logic can compile and run without redb. This
enables future alternative storage backends (e.g., DynamoDB for serverless).

Key changes:
- Split EventStorage constructors: generic `new()` (no mailbox) vs
  `new_redb()` (RedbDatabase with mailbox) vs `new_with_mailbox()` (inject)
- Make mailbox_data an Option<MailboxData> to support non-redb backends
- Remove Any bound from EventValidator
- Gate TelLogDatabase, teliox EscrowDatabase, and escrow module behind
  storage-redb feature
- Genericize teliox escrow structs over K: EventDatabase for KEL storage
- Add in-memory MemoryDatabase implementing all database traits for
  validation and testing
- Move rkyv_adapter to database::rkyv_adapter (not under database::redb)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the concrete HashMap-based NotificationBus with a trait-based
dispatch architecture. NotificationBus is now a Clone-able wrapper around
Arc<dyn NotificationDispatch>, enabling alternative notification backends
(e.g. SQS for serverless) without adding generic type parameters anywhere
in the codebase.

- Add NotificationDispatch trait with dispatch() and register_observer()
- Extract current HashMap logic into InProcessDispatch (RwLock + OnceLock)
- Add NotificationBus::from_dispatch() for custom implementations
- Change register_observer from &mut self to &self across all processors
- Add RwLockingError variant to keri-core Error enum

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the anonymous 5-tuple return from default_escrow_bus with a named
EscrowSet<D> struct, accept an optional NotificationBus parameter, and
introduce KeriRuntime<D> in keri-sdk as a shared composition layer.

These changes address three problems that block serverless (Lambda) use:

- Anonymous tuple was fragile: callers positionally destructured five
  Arc'd escrows and adding a sixth would break every call site. EscrowSet
  gives named fields so callers pick what they need.

- Bus couldn't be injected: default_escrow_bus always created an
  in-process NotificationBus internally. Lambda handlers need SQS-backed
  dispatch so notifications fan out to queues instead of running inline.
  Accepting Option<NotificationBus> lets callers pass a custom bus while
  None preserves existing default behavior.

- Controller buried its internals: the SDK Controller created processor,
  storage, bus, and escrows in new(), discarded escrows, and kept fields
  private. KeriRuntime<D> extracts the shared KERI processing stack
  (processor, storage, escrows, notification_bus) into a standalone
  public struct so Lambda handlers can be thin shells — deserialize
  request, call runtime, serialize response.

All 13 callers of default_escrow_bus updated. Controller<D,T> now
composes over KeriRuntime<D> via a public `kel` field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Introduce `storage-postgres` feature and dependencies
- Implement PostgresDatabase, log, escrow, and KSN log modules
- Add SQL migrations for all KERI tables
- Integrate with existing database traits and event flows

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
storage

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
- Replace dual cfg-gated OobiManager struct definitions with a single
  generic struct and per-backend type aliases (RedbOobiManager,
  PostgresOobiManager)
- Make process_reply and process_signed_oobi generic over
  OobiStorageBackend
- Propagate CBOR deserialization errors instead of silently dropping
  corrupted rows
- Replace unwrap() on serde_json/serde_cbor serialization with ? via
  new Cbor/Json variants on PostgresError

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
- Split EndRoleAdd and EndRoleCut into separate arms (was incorrectly
  merged)
- Add TODO comment on EndRoleCut matching redb's pending delete
  semantics
- Replace silent _ => {} catch-all with explicit Ksn => todo!()
- Add Cbor and Json error variants to PostgresError and propagate
  serialization/deserialization errors instead of panicking or silently
  dropping failures

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Extract TelEventDatabase and TelEscrowDatabase traits to decouple
teliox from redb. Make escrow structs and default_escrow_bus generic
over the new traits. Implement PostgresTelDatabase and
PostgresTelEscrowDatabase backed by sqlx/PgPool, sharing the schema
and migrations from keriox_core. Add postgres integration tests.

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
- Refactor get_events_from_index to return Result, propagating SQL and
  CBOR deserialization errors instead of silently returning empty
  results
- Replace unwrap() in escrow error branches with map_err(...)? in
  missing_issuer and missing_registry processors

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
… Identifier generic over storage backends

Introduces three type parameters <D, T, S> across the controller crate,
where D: EventDatabase + EscrowCreator, T: TelEventDatabase, and
S: OobiStorageBackend. Adds RedbController and RedbKnownEvents type
aliases behind the storage-redb feature flag (default). Replaces the
hardcoded RedbError variant in ControllerError with a generic
DatabaseError(String).

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Adds PostgresController and PostgresKnownEvents type aliases behind the
storage-postgres feature flag, with PostgresController::new_postgres and
PostgresKnownEvents::with_postgres async constructors. Adds postgres
integration tests matching the full redb test suite (KEL, TEL, group
inception, delegated inception). Fixes a bug in PostgresSnKeyDatabase
where get_greater_than used sn > $3 instead of sn >= $3, causing sn=0
events (inception) to be excluded from the partially witnessed escrow.

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
- Export new type aliases from controller and lib modules
- Update tests and helpers to use RedbIdentifier
- Ensure test databases are unique per test binary to avoid conflicts

Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
Signed-off-by: Zdravko Iliev <zdravko.iliev@vereign.com>
…onflicts

Refactor OobiManager and all dependent components to be generic over
OobiStorageBackend, allowing users to choose between Redb and Postgres
storage backends. Fix critical database path conflicts in setup_with_redb()
methods where OOBI and witness databases were attempting to use the same
file path.

Changes:
- Make SimpleController generic over OobiStorageBackend
- Fix Witness::setup_with_redb() to use separate oobi_database path
- Fix WitnessListener::setup_with_redb() to use separate oobi_database path
- Fix Watcher::setup_with_redb() to use separate oobi_database path
- Fix WatcherListener::setup_with_redb() to use separate oobi_database path
- Update all test files to use setup_with_redb() convenience methods
- Fix witness tests to create separate oobi_database paths
- Update broadcast.rs and delegated_incept tests to use new API

Database separation:
- event_db_path/events_database: Witness's internal event storage
- event_db_path/oobi_database: OOBI manager storage (separate to avoid conflicts)

This resolves a critical bug where both RedbDatabase instances would attempt
to access the same file simultaneously
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants