Skip to content

Commit

Permalink
Declarative, type-safe handling of RocksDB key/value encoding/decoding (
Browse files Browse the repository at this point in the history
#682)

⚠️ This builds on top of
#677

This is a 100% pure refactoring.
It adds a piece of infra next to our RocksDB layer, and uses it for
**all** DB access.

### Why refactor our DB access logic?

The approach so far was error-prone:
- When working on #677 I
found a months-old bug where we stored a
`scrypto_encode<LocalTransactionExecution>` to a CF and then tried to
read `scrypto_decode< LocalTransactionReceipt>`.
- I thought "of course we gotta be careful with what types we serialize,
doh", and then in that same PR, I introduced a very similar bug myself
(I stored a versioned wrapper, but was trying to read a non-versioned
struct) and spent hours debugging.

### How that infra changes the DB access logic?

**Before:**
```
        self.db
            .get_cf(
                self.cf_handle(&StateVersionToCommittedTransactionIdentifiers),
                state_version.to_bytes(),
            )
            .expect("DB error loading identifiers")
            .map(|v| {
                scrypto_decode::<VersionedCommittedTransactionIdentifiers>(&v)
                    .expect("Failed to decode identifiers")
                    .into_latest()
            })
```

**After:**
```
        self.cfs.committed_transaction_identifiers().get(&state_version)
```

### What does it give us?

Apart from the line count:
- No need to remember that `state_version.to_bytes()` is THE way to
encode a `StateVersion` key in the DB.
- No way to confuse what type is stored in that table.
- No need to remember about unwrapping a versioning wrapper.

### Cool, but you had to implement
`self.cfs.committed_transaction_identifiers()` somehow first, right?

Yes, but it is 100% declarative, in one place:
```
    pub fn committed_transaction_identifiers(
        &self,
    ) -> impl TypedCfApi<StateVersion, CommittedTransactionIdentifiers> { // see key and value types
        self.create_with_codecs(
            StateVersionToCommittedTransactionIdentifiers, // declare which ColumnFamily it is
            StateVersionDbCodec::default(), // use this codec for the state version
            VersionedDbCodec::new( // apply auto-version-wrapping/unwrapping
                SborDbCodec::<VersionedCommittedTransactionIdentifiers>::default(), // use SBOR
            ),
        )
    }
```
  • Loading branch information
jakrawcz-rdx authored Sep 19, 2023
2 parents 4d8c065 + f068aeb commit ee9ccf6
Show file tree
Hide file tree
Showing 3 changed files with 1,055 additions and 598 deletions.
1 change: 1 addition & 0 deletions core-rust/state-manager/src/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ mod db;
mod in_memory;
mod rocks_db;
pub mod traits;
mod typed_cf_api;

pub use db::{DatabaseBackendConfig, StateManagerDatabase};
pub use in_memory::InMemoryStore;
Expand Down
Loading

0 comments on commit ee9ccf6

Please sign in to comment.