Skip to content

Commit 023090c

Browse files
committed
feat: PostgreSQL support
1 parent 6550127 commit 023090c

File tree

8 files changed

+125
-25
lines changed

8 files changed

+125
-25
lines changed

.env

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
RUST_LOG=trace,hyper=info,tracing=info,reqwest=info
22

33
# The database that should be used
4+
# SQLite and PostgreSQL are supported:
5+
# - sqlite://./db.sqlite
6+
# - postgresql://boltz:[email protected]:5432/covclaim
47
DATABASE_URL=sqlite://./db.sqlite
58

69
# When finding a lockup transaction, how many seconds to wait before broadcasting the covenant claim (0 for instantly)

Cargo.lock

+20-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "covclaim"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2021"
55
build = "build.rs"
66

@@ -14,7 +14,7 @@ panic = "abort"
1414
[dependencies]
1515
tokio = { version = "1.38.0", features = ["full"] }
1616
axum = "0.7.5"
17-
diesel = { version = "2.2.1", features = ["sqlite", "r2d2", "chrono"] }
17+
diesel = { version = "2.2.1", features = ["sqlite", "postgres", "r2d2", "chrono"] }
1818
diesel_migrations = "2.2.0"
1919
dotenvy = "0.15.7"
2020
env_logger = "0.11.3"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DROP TABLE parameters;
2+
DROP TABLE pending_covenants;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CREATE TABLE parameters (
2+
name VARCHAR PRIMARY KEY NOT NULL,
3+
value VARCHAR NOT NULL
4+
);
5+
6+
CREATE TABLE pending_covenants (
7+
output_script BYTEA PRIMARY KEY NOT NULL,
8+
status INT NOT NULL,
9+
internal_key BYTEA NOT NULL,
10+
preimage BYTEA NOT NULL,
11+
swap_tree VARCHAR NOT NULL,
12+
address BYTEA NOT NULL,
13+
blinding_key BYTEA,
14+
tx_id BYTEA,
15+
tx_time TIMESTAMP,
16+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
17+
);
18+
19+
CREATE INDEX pending_covenants_status_idx ON pending_covenants (status);

src/db/helpers.rs

+29-7
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,40 @@ use crate::db::schema::pending_covenants;
99

1010
const BLOCK_HEIGHT_NAME: &str = "block_height";
1111

12-
pub fn upsert_block_height(con: db::Pool, height: u64) -> QueryResult<usize> {
12+
pub fn upsert_block_height(con: db::Pool, height: u64) -> Result<(), diesel::result::Error> {
1313
let values = Parameter {
1414
name: BLOCK_HEIGHT_NAME.to_string(),
1515
value: height.to_string(),
1616
};
1717

18-
insert_into(parameters::dsl::parameters)
19-
.values(&values)
20-
.on_conflict(parameters::dsl::name)
21-
.do_update()
22-
.set(parameters::dsl::value.eq(height.to_string()))
23-
.execute(&mut con.get().unwrap())
18+
match parameters::dsl::parameters
19+
.select(Parameter::as_select())
20+
.filter(parameters::dsl::name.eq(BLOCK_HEIGHT_NAME.to_string()))
21+
.limit(1)
22+
.load(&mut con.get().unwrap())
23+
{
24+
Ok(res) => {
25+
if res.is_empty() {
26+
match insert_into(parameters::dsl::parameters)
27+
.values(&values)
28+
.execute(&mut con.get().unwrap())
29+
{
30+
Ok(_) => Ok(()),
31+
Err(err) => Err(err),
32+
}
33+
} else {
34+
match update(parameters::dsl::parameters)
35+
.filter(parameters::dsl::name.eq(BLOCK_HEIGHT_NAME.to_string()))
36+
.set((parameters::dsl::value.eq(height.to_string()),))
37+
.execute(&mut con.get().unwrap())
38+
{
39+
Ok(_) => Ok(()),
40+
Err(err) => Err(err),
41+
}
42+
}
43+
}
44+
Err(err) => Err(err),
45+
}
2446
}
2547

2648
pub fn get_block_height(con: db::Pool) -> Option<u64> {

src/db/mod.rs

+37-10
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,58 @@
1+
use std::error::Error;
2+
3+
use diesel::prelude::*;
14
use diesel::r2d2::ConnectionManager;
2-
use diesel::sqlite::Sqlite;
3-
use diesel::{Connection, SqliteConnection};
5+
use diesel::Connection;
46
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
5-
use std::error::Error;
7+
use log::info;
68

79
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations");
10+
pub const MIGRATIONS_POSTGRES: EmbeddedMigrations = embed_migrations!("./migrations_postgres");
811

912
pub mod helpers;
1013

1114
pub mod models;
1215
mod schema;
1316

14-
pub type DatabaseConnection = SqliteConnection;
15-
pub type Pool = r2d2::Pool<ConnectionManager<DatabaseConnection>>;
17+
#[derive(diesel::MultiConnection)]
18+
pub enum AnyConnection {
19+
Postgresql(PgConnection),
20+
Sqlite(SqliteConnection),
21+
}
1622

17-
pub fn establish_connection(url: &str) -> Result<Pool, Box<dyn Error + Send + Sync>> {
18-
run_migrations(&mut SqliteConnection::establish(url)?)?;
23+
pub type Pool = r2d2::Pool<ConnectionManager<AnyConnection>>;
1924

20-
let manager = ConnectionManager::<DatabaseConnection>::new(url);
25+
pub fn establish_connection(url: &str) -> Result<Pool, Box<dyn Error + Send + Sync>> {
26+
info!(
27+
"Using {} database",
28+
if is_postgres_connection_url(url) {
29+
"PostgreSQL"
30+
} else {
31+
"SQLite"
32+
}
33+
);
34+
35+
let manager = ConnectionManager::new(url);
2136
let pool = Pool::builder().build(manager)?;
2237

38+
run_migrations(is_postgres_connection_url(url), &pool)?;
39+
2340
Ok(pool)
2441
}
2542

2643
fn run_migrations(
27-
connection: &mut impl MigrationHarness<Sqlite>,
44+
is_postgres: bool,
45+
pool: &Pool,
2846
) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
29-
connection.run_pending_migrations(MIGRATIONS)?;
47+
let mut con = pool.get()?;
48+
con.run_pending_migrations(if is_postgres {
49+
MIGRATIONS_POSTGRES
50+
} else {
51+
MIGRATIONS
52+
})?;
3053
Ok(())
3154
}
55+
56+
fn is_postgres_connection_url(url: &str) -> bool {
57+
url.starts_with("postgresql")
58+
}

src/main.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,20 @@ async fn main() {
2424
env_logger::init();
2525

2626
info!(
27-
"Starting covclaim v{}-{}",
27+
"Starting {} v{}-{}{}",
28+
built_info::PKG_NAME,
2829
built_info::PKG_VERSION,
29-
built_info::GIT_VERSION.unwrap_or("")
30+
built_info::GIT_VERSION.unwrap_or(""),
31+
if built_info::GIT_DIRTY.unwrap_or(false) {
32+
"-dirty"
33+
} else {
34+
""
35+
}
3036
);
37+
3138
debug!(
32-
"Compiled with {} for {}",
39+
"Compiled {} with {} for {}",
40+
built_info::PROFILE,
3341
built_info::RUSTC_VERSION,
3442
built_info::TARGET
3543
);
@@ -101,8 +109,8 @@ async fn get_chain_backend() -> Arc<Box<dyn ChainBackend + Send + Sync>> {
101109
.expect("ELEMENTS_PORT invalid"),
102110
env::var("ELEMENTS_COOKIE").expect("ELEMENTS_COOKIE must be set"),
103111
)
104-
.connect()
105-
.await
112+
.connect()
113+
.await
106114
{
107115
Ok(client) => Box::new(client),
108116
Err(err) => {

0 commit comments

Comments
 (0)