Skip to content

Commit aaa52e9

Browse files
authored
Merge pull request #8 from comit-network/master
Merge parent repository
2 parents cf87f19 + ce8d3af commit aaa52e9

File tree

10 files changed

+111
-51
lines changed

10 files changed

+111
-51
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
- ASB: The `history` command can now be used while the asb is running.
11+
1012
## [0.13.3] - 2024-07-22
1113

1214
- Introduced a cooperative Monero redeem feature for Bob to request from Alice if Bob is punished for not refunding in time. Alice can choose to cooperate but is not obligated to do so. This change is backwards compatible. To attempt recovery, resume a swap in the "Bitcoin punished" state. Success depends on Alice being active and still having a record of the swap. Note that Alice's cooperation is voluntary and recovery is not guaranteed

swap/src/api.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub mod request;
22
use crate::cli::command::{Bitcoin, Monero, Tor};
3-
use crate::database::open_db;
3+
use crate::database::{open_db, AccessMode};
44
use crate::env::{Config as EnvConfig, GetConfig, Mainnet, Testnet};
55
use crate::fs::system_data_dir;
66
use crate::network::rendezvous::XmrBtcNamespace;
@@ -224,7 +224,7 @@ impl Context {
224224
let tor_socks5_port = tor.map_or(9050, |tor| tor.tor_socks5_port);
225225

226226
let context = Context {
227-
db: open_db(data_dir.join("sqlite")).await?,
227+
db: open_db(data_dir.join("sqlite"), AccessMode::ReadWrite).await?,
228228
bitcoin_wallet,
229229
monero_wallet,
230230
monero_rpc_process,
@@ -259,7 +259,7 @@ impl Context {
259259
bitcoin_wallet: Some(bob_bitcoin_wallet),
260260
monero_wallet: Some(bob_monero_wallet),
261261
config,
262-
db: open_db(db_path)
262+
db: open_db(db_path, AccessMode::ReadWrite)
263263
.await
264264
.expect("Could not open sqlite database"),
265265
monero_rpc_process: None,
@@ -437,7 +437,7 @@ pub mod api_test {
437437

438438
Request::new(Method::BuyXmr {
439439
seller,
440-
bitcoin_change_address,
440+
bitcoin_change_address: Some(bitcoin_change_address),
441441
monero_receive_address,
442442
swap_id: Uuid::new_v4(),
443443
})

swap/src/api/request.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct Request {
3131
pub enum Method {
3232
BuyXmr {
3333
seller: Multiaddr,
34-
bitcoin_change_address: bitcoin::Address,
34+
bitcoin_change_address: Option<bitcoin::Address>,
3535
monero_receive_address: monero::Address,
3636
swap_id: Uuid,
3737
},
@@ -335,6 +335,25 @@ impl Request {
335335
let env_config = context.config.env_config;
336336
let seed = context.config.seed.clone().context("Could not get seed")?;
337337

338+
// When no change address was provided we default to the internal wallet
339+
let bitcoin_change_address = match bitcoin_change_address {
340+
Some(addr) => addr,
341+
None => {
342+
let internal_wallet_address = context
343+
.bitcoin_wallet()
344+
.expect("bitcoin wallet should exist")
345+
.new_address()
346+
.await?;
347+
348+
tracing::info!(
349+
internal_wallet_address=%internal_wallet_address,
350+
"No --change-address supplied. Any change will be received to the internal wallet."
351+
);
352+
353+
internal_wallet_address
354+
}
355+
};
356+
338357
let seller_peer_id = seller
339358
.extract_peer_id()
340359
.context("Seller address must contain peer ID")?;

swap/src/bin/asb.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use swap::asb::config::{
3030
};
3131
use swap::asb::{cancel, punish, redeem, refund, safely_abort, EventLoop, Finality, KrakenRate};
3232
use swap::common::check_latest_version;
33-
use swap::database::open_db;
33+
use swap::database::{open_db, AccessMode};
3434
use swap::network::rendezvous::XmrBtcNamespace;
3535
use swap::network::swarm;
3636
use swap::protocol::alice::{run, AliceState};
@@ -95,13 +95,13 @@ async fn main() -> Result<()> {
9595
));
9696
}
9797

98-
let db = open_db(config.data.dir.join("sqlite")).await?;
99-
10098
let seed =
10199
Seed::from_file_or_generate(&config.data.dir).expect("Could not retrieve/initialize seed");
102100

103101
match cmd {
104102
Command::Start { resume_only } => {
103+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadWrite).await?;
104+
105105
// check and warn for duplicate rendezvous points
106106
let mut rendezvous_addrs = config.network.rendezvous_point.clone();
107107
let prev_len = rendezvous_addrs.len();
@@ -225,6 +225,8 @@ async fn main() -> Result<()> {
225225
event_loop.run().await;
226226
}
227227
Command::History => {
228+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadOnly).await?;
229+
228230
let mut table = Table::new();
229231

230232
table.set_header(vec!["SWAP ID", "STATE"]);
@@ -270,13 +272,17 @@ async fn main() -> Result<()> {
270272
tracing::info!(%bitcoin_balance, %monero_balance, "Current balance");
271273
}
272274
Command::Cancel { swap_id } => {
275+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadWrite).await?;
276+
273277
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
274278

275279
let (txid, _) = cancel(swap_id, Arc::new(bitcoin_wallet), db).await?;
276280

277281
tracing::info!("Cancel transaction successfully published with id {}", txid);
278282
}
279283
Command::Refund { swap_id } => {
284+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadWrite).await?;
285+
280286
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
281287
let monero_wallet = init_monero_wallet(&config, env_config).await?;
282288

@@ -291,13 +297,17 @@ async fn main() -> Result<()> {
291297
tracing::info!("Monero successfully refunded");
292298
}
293299
Command::Punish { swap_id } => {
300+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadWrite).await?;
301+
294302
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
295303

296304
let (txid, _) = punish(swap_id, Arc::new(bitcoin_wallet), db).await?;
297305

298306
tracing::info!("Punish transaction successfully published with id {}", txid);
299307
}
300308
Command::SafelyAbort { swap_id } => {
309+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadWrite).await?;
310+
301311
safely_abort(swap_id, db).await?;
302312

303313
tracing::info!("Swap safely aborted");
@@ -306,6 +316,8 @@ async fn main() -> Result<()> {
306316
swap_id,
307317
do_not_await_finality,
308318
} => {
319+
let db = open_db(config.data.dir.join("sqlite"), AccessMode::ReadWrite).await?;
320+
309321
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
310322

311323
let (txid, _) = redeem(

swap/src/cli/command.rs

+3-21
Original file line numberDiff line numberDiff line change
@@ -81,29 +81,11 @@ where
8181
)
8282
.await?;
8383

84-
// when no refund address was provided we default to the internal wallet
85-
let bitcoin_change_address = match bitcoin_change_address {
86-
Some(addr) => addr,
87-
None => {
88-
let internal_wallet_address = context
89-
.bitcoin_wallet()
90-
.expect("bitcoin wallet should exist")
91-
.new_address()
92-
.await?;
93-
94-
tracing::info!(
95-
internal_wallet_address=%internal_wallet_address,
96-
"No --change-address supplied. Any change will be received to the internal wallet."
97-
);
98-
99-
internal_wallet_address
100-
}
101-
};
102-
10384
let monero_receive_address =
10485
monero_address::validate_is_testnet(monero_receive_address, is_testnet)?;
105-
let bitcoin_change_address =
106-
bitcoin_address::validate_is_testnet(bitcoin_change_address, is_testnet)?;
86+
let bitcoin_change_address = bitcoin_change_address
87+
.map(|address| bitcoin_address::validate_is_testnet(address, is_testnet))
88+
.transpose()?;
10789

10890
let request = Request::new(Method::BuyXmr {
10991
seller,

swap/src/database.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,25 @@ impl Swap {
8383
}
8484
}
8585

86-
pub async fn open_db(sqlite_path: impl AsRef<Path>) -> Result<Arc<dyn Database + Send + Sync>> {
86+
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, PartialEq)]
87+
pub enum AccessMode {
88+
ReadWrite,
89+
ReadOnly,
90+
}
91+
92+
pub async fn open_db(
93+
sqlite_path: impl AsRef<Path>,
94+
access_mode: AccessMode,
95+
) -> Result<Arc<dyn Database + Send + Sync>> {
8796
if sqlite_path.as_ref().exists() {
8897
tracing::debug!("Using existing sqlite database.");
89-
let sqlite = SqliteDatabase::open(sqlite_path).await?;
98+
let sqlite = SqliteDatabase::open(sqlite_path, access_mode).await?;
9099
Ok(Arc::new(sqlite))
91100
} else {
92101
tracing::debug!("Creating and using new sqlite database.");
93102
ensure_directory_exists(sqlite_path.as_ref())?;
94103
tokio::fs::File::create(&sqlite_path).await?;
95-
let sqlite = SqliteDatabase::open(sqlite_path).await?;
104+
let sqlite = SqliteDatabase::open(sqlite_path, access_mode).await?;
96105
Ok(Arc::new(sqlite))
97106
}
98107
}

swap/src/database/sqlite.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,37 @@ use crate::protocol::{Database, State};
44
use anyhow::{anyhow, Context, Result};
55
use async_trait::async_trait;
66
use libp2p::{Multiaddr, PeerId};
7-
use sqlx::sqlite::Sqlite;
7+
use sqlx::sqlite::{Sqlite, SqliteConnectOptions};
88
use sqlx::{Pool, SqlitePool};
99
use std::collections::HashMap;
1010
use std::path::Path;
1111
use std::str::FromStr;
1212
use time::OffsetDateTime;
1313
use uuid::Uuid;
1414

15+
use super::AccessMode;
16+
1517
pub struct SqliteDatabase {
1618
pool: Pool<Sqlite>,
1719
}
1820

1921
impl SqliteDatabase {
20-
pub async fn open(path: impl AsRef<Path>) -> Result<Self>
22+
pub async fn open(path: impl AsRef<Path>, access_mode: AccessMode) -> Result<Self>
2123
where
2224
Self: std::marker::Sized,
2325
{
26+
let read_only = matches!(access_mode, AccessMode::ReadOnly);
27+
2428
let path_str = format!("sqlite:{}", path.as_ref().display());
25-
let pool = SqlitePool::connect(&path_str).await?;
29+
let options = SqliteConnectOptions::from_str(&path_str)?.read_only(read_only);
30+
31+
let pool = SqlitePool::connect_with(options).await?;
2632
let mut sqlite = Self { pool };
27-
sqlite.run_migrations().await?;
33+
34+
if !read_only {
35+
sqlite.run_migrations().await?;
36+
}
37+
2838
Ok(sqlite)
2939
}
3040

@@ -504,7 +514,7 @@ mod tests {
504514
// file has to exist in order to connect with sqlite
505515
File::create(temp_db.clone()).unwrap();
506516

507-
let db = SqliteDatabase::open(temp_db).await?;
517+
let db = SqliteDatabase::open(temp_db, AccessMode::ReadWrite).await?;
508518

509519
Ok(db)
510520
}

swap/src/rpc/methods.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,25 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
135135
module.register_async_method("buy_xmr", |params_raw, context| async move {
136136
let params: HashMap<String, String> = params_raw.parse()?;
137137

138-
let bitcoin_change_address =
139-
bitcoin::Address::from_str(params.get("bitcoin_change_address").ok_or_else(|| {
140-
jsonrpsee_core::Error::Custom("Does not contain bitcoin_change_address".to_string())
141-
})?)
142-
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?;
143-
144-
let bitcoin_change_address = bitcoin_address::validate(
145-
bitcoin_change_address,
146-
context.config.env_config.bitcoin_network,
147-
)?;
138+
let bitcoin_change_address = params
139+
.get("bitcoin_change_address")
140+
.map(|addr_str| {
141+
bitcoin::Address::from_str(addr_str)
142+
.map_err(|err| {
143+
jsonrpsee_core::Error::Custom(format!(
144+
"Could not parse bitcoin address: {}",
145+
err
146+
))
147+
})
148+
.and_then(|address| {
149+
bitcoin_address::validate(
150+
address,
151+
context.config.env_config.bitcoin_network,
152+
)
153+
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
154+
})
155+
})
156+
.transpose()?;
148157

149158
let monero_receive_address =
150159
monero::Address::from_str(params.get("monero_receive_address").ok_or_else(|| {

swap/tests/harness/mod.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::sync::Arc;
1616
use std::time::Duration;
1717
use swap::asb::FixedRate;
1818
use swap::bitcoin::{CancelTimelock, PunishTimelock, TxCancel, TxPunish, TxRedeem, TxRefund};
19-
use swap::database::SqliteDatabase;
19+
use swap::database::{AccessMode, SqliteDatabase};
2020
use swap::env::{Config, GetConfig};
2121
use swap::fs::ensure_directory_exists;
2222
use swap::network::rendezvous::XmrBtcNamespace;
@@ -231,7 +231,11 @@ async fn start_alice(
231231
if !&db_path.exists() {
232232
tokio::fs::File::create(&db_path).await.unwrap();
233233
}
234-
let db = Arc::new(SqliteDatabase::open(db_path.as_path()).await.unwrap());
234+
let db = Arc::new(
235+
SqliteDatabase::open(db_path.as_path(), AccessMode::ReadWrite)
236+
.await
237+
.unwrap(),
238+
);
235239

236240
let min_buy = bitcoin::Amount::from_sat(u64::MIN);
237241
let max_buy = bitcoin::Amount::from_sat(u64::MAX);
@@ -433,7 +437,7 @@ impl BobParams {
433437
if !self.db_path.exists() {
434438
tokio::fs::File::create(&self.db_path).await?;
435439
}
436-
let db = Arc::new(SqliteDatabase::open(&self.db_path).await?);
440+
let db = Arc::new(SqliteDatabase::open(&self.db_path, AccessMode::ReadWrite).await?);
437441

438442
let (event_loop, handle) = self.new_eventloop(swap_id, db.clone()).await?;
439443

@@ -463,7 +467,7 @@ impl BobParams {
463467
if !self.db_path.exists() {
464468
tokio::fs::File::create(&self.db_path).await?;
465469
}
466-
let db = Arc::new(SqliteDatabase::open(&self.db_path).await?);
470+
let db = Arc::new(SqliteDatabase::open(&self.db_path, AccessMode::ReadWrite).await?);
467471

468472
let (event_loop, handle) = self.new_eventloop(swap_id, db.clone()).await?;
469473

utils/gpg_keys/binarybaron.asc

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN PGP PUBLIC KEY BLOCK-----
2+
3+
mDMEZp+avRYJKwYBBAHaRw8BAQdAD99LhR+cHlXDsYPjRJr0Ag7BXsjGZKfdWCtx
4+
CPA0fwG0LWJpbmFyeWJhcm9uIDxiaW5hcnliYXJvbkB1bnN0b3BwYWJsZXN3YXAu
5+
bmV0PoiTBBMWCgA7FiEENahE1/S1W8ROGA/xmbddPhR2om4FAmafmr0CGwMFCwkI
6+
BwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQmbddPhR2om5IQQD/d/EmD/yKMKRl
7+
Hw9RSP4bhcALmrZPri8sYkPteus8OhIA+wWTaIxXZJgydpXv95yECTfUXZ0UhuJq
8+
6UH0FQL8mosJuDgEZp+avRIKKwYBBAGXVQEFAQEHQOd1tQ46YVKxyUKluPAvGJLY
9+
LQ+3UWFWQJavLblkrYE2AwEIB4h4BBgWCgAgFiEENahE1/S1W8ROGA/xmbddPhR2
10+
om4FAmafmr0CGwwACgkQmbddPhR2om6mmQEAn7vufrOp/HSYgn9l5tmJxMkyxJ3W
11+
2WNo9u+JdnSik1IBAMsNcc4zm5ewfFr/qAnTHzHRId7dWR2+hs1oH7JOlf8L
12+
=Rxij
13+
-----END PGP PUBLIC KEY BLOCK-----

0 commit comments

Comments
 (0)