Skip to content

Commit 952b568

Browse files
committed
feat: add redb as an alternative to sqlite
1 parent 7a71b14 commit 952b568

File tree

8 files changed

+203
-23
lines changed

8 files changed

+203
-23
lines changed

Cargo.lock

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ bdk_bitcoind_rpc = { version = "0.20.0", optional = true }
2727
bdk_electrum = { version = "0.23.0", optional = true }
2828
bdk_esplora = { version = "0.22.0", features = ["async-https", "tokio"], optional = true }
2929
bdk_kyoto = { version = "0.11.0", optional = true }
30+
bdk_redb = { git = "https://github.com/110CodingP/bdk_redb", features = ["wallet"], optional = true }
3031
shlex = { version = "1.3.0", optional = true }
3132
tracing = "0.1.41"
3233
tracing-subscriber = "0.3.19"
@@ -39,12 +40,13 @@ repl = ["shlex"]
3940

4041
# Available database options
4142
sqlite = ["bdk_wallet/rusqlite"]
43+
redb = ["bdk_redb"]
4244

4345
# Available blockchain client options
4446
cbf = ["bdk_kyoto"]
4547
electrum = ["bdk_electrum"]
4648
esplora = ["bdk_esplora"]
47-
rpc = ["bdk_bitcoind_rpc"]
49+
rpc = ["bdk_bitcoind_rpc"]
4850

4951
# Use this to consensus verify transactions at sync time
5052
verify = []

src/commands.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ pub enum DatabaseType {
126126
/// Sqlite database
127127
#[cfg(feature = "sqlite")]
128128
Sqlite,
129+
/// Redb database
130+
#[cfg(feature = "redb")]
131+
Redb,
129132
}
130133

131134
#[cfg(any(
@@ -169,7 +172,7 @@ pub struct WalletOpts {
169172
))]
170173
#[arg(env = "CLIENT_TYPE", short = 'c', long, value_enum, required = true)]
171174
pub client_type: ClientType,
172-
#[cfg(feature = "sqlite")]
175+
#[cfg(any(feature = "sqlite", feature = "redb"))]
173176
#[arg(env = "DATABASE_TYPE", short = 'd', long, value_enum, required = true)]
174177
pub database_type: DatabaseType,
175178
/// Sets the server url.

src/error.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(any(feature = "sqlite", feature = "redb"))]
2+
use crate::persister::PersisterError;
13
use bdk_wallet::bitcoin::hex::HexToBytesError;
24
use bdk_wallet::bitcoin::psbt::ExtractTxError;
35
use bdk_wallet::bitcoin::{base64, consensus};
@@ -57,8 +59,9 @@ pub enum BDKCliError {
5759
#[error("PsbtError: {0}")]
5860
PsbtError(#[from] bdk_wallet::bitcoin::psbt::Error),
5961

60-
#[error("Rusqlite error: {0}")]
61-
RusqliteError(#[from] bdk_wallet::rusqlite::Error),
62+
#[cfg(any(feature = "redb", feature = "sqlite"))]
63+
#[error("Persistence error: {0}")]
64+
PersistenceError(#[from] PersisterError),
6265

6366
#[error("Serde json error: {0}")]
6467
SerdeJson(#[from] serde_json::Error),

src/handlers.rs

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
use crate::commands::OfflineWalletSubCommand::*;
1414
use crate::commands::*;
1515
use crate::error::BDKCliError as Error;
16+
#[cfg(any(feature = "sqlite", feature = "redb"))]
17+
use crate::persister::{Persister, PersisterError};
1618
#[cfg(feature = "cbf")]
1719
use crate::utils::BlockchainClient::KyotoClient;
1820
use crate::utils::*;
21+
#[cfg(feature = "redb")]
22+
use bdk_redb::Store as RedbStore;
1923
use bdk_wallet::bip39::{Language, Mnemonic};
2024
use bdk_wallet::bitcoin::bip32::{DerivationPath, KeySource};
2125
use bdk_wallet::bitcoin::consensus::encode::serialize_hex;
@@ -51,6 +55,8 @@ use crate::utils::BlockchainClient::Electrum;
5155
#[cfg(feature = "cbf")]
5256
use bdk_kyoto::{Info, LightClient};
5357
use bdk_wallet::bitcoin::base64::prelude::*;
58+
#[cfg(feature = "redb")]
59+
use std::sync::Arc;
5460
#[cfg(feature = "cbf")]
5561
use tokio::select;
5662
#[cfg(any(
@@ -751,15 +757,32 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
751757
let home_dir = prepare_home_dir(cli_opts.datadir)?;
752758
let wallet_name = &wallet_opts.wallet;
753759
let database_path = prepare_wallet_db_dir(wallet_name, &home_dir)?;
754-
#[cfg(feature = "sqlite")]
760+
761+
#[cfg(any(feature = "sqlite", feature = "redb"))]
755762
let result = {
756-
let mut persister = match &wallet_opts.database_type {
763+
let mut persister: Persister = match &wallet_opts.database_type {
757764
#[cfg(feature = "sqlite")]
758765
DatabaseType::Sqlite => {
759766
let db_file = database_path.join("wallet.sqlite");
760-
let connection = Connection::open(db_file)?;
767+
let connection = Connection::open(db_file).map_err(PersisterError::from)?;
761768
log::debug!("Sqlite database opened successfully");
762-
connection
769+
Persister::Connection(connection)
770+
}
771+
#[cfg(feature = "redb")]
772+
DatabaseType::Redb => {
773+
let db = Arc::new(
774+
bdk_redb::redb::Database::create(database_path.join("wallet.redb"))
775+
.map_err(bdk_redb::redb::Error::from)
776+
.map_err(bdk_redb::error::StoreError::from)
777+
.map_err(PersisterError::from)?,
778+
);
779+
let store = RedbStore::new(
780+
db,
781+
wallet_name.as_deref().unwrap_or("wallet1").to_string(),
782+
)
783+
.map_err(PersisterError::from)?;
784+
log::debug!("Redb database opened successfully");
785+
Persister::RedbStore(store)
763786
}
764787
};
765788

@@ -776,7 +799,7 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
776799
wallet.persist(&mut persister)?;
777800
result
778801
};
779-
#[cfg(not(any(feature = "sqlite")))]
802+
#[cfg(not(any(feature = "sqlite", feature = "redb")))]
780803
let result = {
781804
let wallet = new_wallet(network, &wallet_opts)?;
782805
let blockchain_client =
@@ -792,18 +815,34 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
792815
subcommand: WalletSubCommand::OfflineWalletSubCommand(offline_subcommand),
793816
} => {
794817
let network = cli_opts.network;
795-
#[cfg(feature = "sqlite")]
818+
#[cfg(any(feature = "sqlite", feature = "redb"))]
796819
let result = {
797820
let home_dir = prepare_home_dir(cli_opts.datadir)?;
798821
let wallet_name = &wallet_opts.wallet;
799822
let database_path = prepare_wallet_db_dir(wallet_name, &home_dir)?;
800-
let mut persister = match &wallet_opts.database_type {
823+
let mut persister: Persister = match &wallet_opts.database_type {
801824
#[cfg(feature = "sqlite")]
802825
DatabaseType::Sqlite => {
803826
let db_file = database_path.join("wallet.sqlite");
804-
let connection = Connection::open(db_file)?;
827+
let connection = Connection::open(db_file).map_err(PersisterError::from)?;
805828
log::debug!("Sqlite database opened successfully");
806-
connection
829+
Persister::Connection(connection)
830+
}
831+
#[cfg(feature = "redb")]
832+
DatabaseType::Redb => {
833+
let db = Arc::new(
834+
bdk_redb::redb::Database::create(database_path.join("wallet.redb"))
835+
.map_err(bdk_redb::redb::Error::from)
836+
.map_err(bdk_redb::error::StoreError::from)
837+
.map_err(PersisterError::from)?,
838+
);
839+
let store = RedbStore::new(
840+
db,
841+
wallet_name.as_deref().unwrap_or("wallet1").to_string(),
842+
)
843+
.map_err(PersisterError::from)?;
844+
log::debug!("Redb database opened successfully");
845+
Persister::RedbStore(store)
807846
}
808847
};
809848

@@ -816,7 +855,7 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
816855
wallet.persist(&mut persister)?;
817856
result
818857
};
819-
#[cfg(not(any(feature = "sqlite")))]
858+
#[cfg(not(any(feature = "sqlite", feature = "redb")))]
820859
let result = {
821860
let mut wallet = new_wallet(network, &wallet_opts)?;
822861
handle_offline_wallet_subcommand(&mut wallet, &wallet_opts, offline_subcommand)?
@@ -840,27 +879,43 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
840879
#[cfg(feature = "repl")]
841880
CliSubCommand::Repl { wallet_opts } => {
842881
let network = cli_opts.network;
843-
#[cfg(feature = "sqlite")]
882+
#[cfg(any(feature = "sqlite", feature = "redb"))]
844883
let (mut wallet, mut persister) = {
845884
let wallet_name = &wallet_opts.wallet;
846885

847886
let home_dir = prepare_home_dir(cli_opts.datadir.clone())?;
848887

849888
let database_path = prepare_wallet_db_dir(wallet_name, &home_dir)?;
850889

851-
let mut persister = match &wallet_opts.database_type {
890+
let mut persister: Persister = match &wallet_opts.database_type {
852891
#[cfg(feature = "sqlite")]
853892
DatabaseType::Sqlite => {
854893
let db_file = database_path.join("wallet.sqlite");
855-
let connection = Connection::open(db_file)?;
894+
let connection = Connection::open(db_file).map_err(PersisterError::from)?;
856895
log::debug!("Sqlite database opened successfully");
857-
connection
896+
Persister::Connection(connection)
897+
}
898+
#[cfg(feature = "redb")]
899+
DatabaseType::Redb => {
900+
let db = Arc::new(
901+
bdk_redb::redb::Database::create(database_path.join("wallet.redb"))
902+
.map_err(bdk_redb::redb::Error::from)
903+
.map_err(bdk_redb::error::StoreError::from)
904+
.map_err(PersisterError::from)?,
905+
);
906+
let store = RedbStore::new(
907+
db,
908+
wallet_name.as_deref().unwrap_or("wallet1").to_string(),
909+
)
910+
.map_err(PersisterError::from)?;
911+
log::debug!("Redb database opened successfully");
912+
Persister::RedbStore(store)
858913
}
859914
};
860915
let wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
861916
(wallet, persister)
862917
};
863-
#[cfg(not(any(feature = "sqlite")))]
918+
#[cfg(not(any(feature = "sqlite", feature = "redb")))]
864919
let mut wallet = new_wallet(network, &wallet_opts)?;
865920
let home_dir = prepare_home_dir(cli_opts.datadir.clone())?;
866921
let database_path = prepare_wallet_db_dir(&wallet_opts.wallet, &home_dir)?;
@@ -880,7 +935,7 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
880935
database_path.clone(),
881936
)
882937
.await;
883-
#[cfg(feature = "sqlite")]
938+
#[cfg(any(feature = "sqlite", feature = "redb"))]
884939
wallet.persist(&mut persister)?;
885940

886941
match result {

src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
mod commands;
1414
mod error;
1515
mod handlers;
16+
#[cfg(any(feature = "sqlite", feature = "redb"))]
17+
mod persister;
1618
mod utils;
1719

1820
use bdk_wallet::bitcoin::Network;

0 commit comments

Comments
 (0)