2021-01-21 06:09:53 +00:00
|
|
|
pub use alice::Alice;
|
|
|
|
pub use bob::Bob;
|
|
|
|
|
2020-11-03 04:49:00 +00:00
|
|
|
use anyhow::{anyhow, bail, Context, Result};
|
2021-03-26 04:16:19 +00:00
|
|
|
use itertools::Itertools;
|
2021-03-30 04:40:59 +00:00
|
|
|
use libp2p::PeerId;
|
2021-03-04 00:28:58 +00:00
|
|
|
use serde::de::DeserializeOwned;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::fmt::Display;
|
|
|
|
use std::path::Path;
|
2021-03-30 04:40:59 +00:00
|
|
|
use std::str::FromStr;
|
2020-11-03 03:23:03 +00:00
|
|
|
use uuid::Uuid;
|
2020-11-03 05:44:04 +00:00
|
|
|
|
2021-01-08 00:04:32 +00:00
|
|
|
mod alice;
|
|
|
|
mod bob;
|
2021-01-05 03:08:36 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
|
|
|
pub enum Swap {
|
|
|
|
Alice(Alice),
|
|
|
|
Bob(Bob),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Alice> for Swap {
|
|
|
|
fn from(from: Alice) -> Self {
|
|
|
|
Swap::Alice(from)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Bob> for Swap {
|
|
|
|
fn from(from: Bob) -> Self {
|
|
|
|
Swap::Bob(from)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Swap {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
Swap::Alice(alice) => Display::fmt(alice, f),
|
|
|
|
Swap::Bob(bob) => Display::fmt(bob, f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-23 04:26:08 +00:00
|
|
|
|
2021-03-26 04:16:19 +00:00
|
|
|
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq)]
|
|
|
|
#[error("Not in the role of Alice")]
|
|
|
|
struct NotAlice;
|
|
|
|
|
|
|
|
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq)]
|
|
|
|
#[error("Not in the role of Bob")]
|
|
|
|
struct NotBob;
|
|
|
|
|
2021-03-03 02:17:09 +00:00
|
|
|
impl Swap {
|
2021-03-26 04:16:19 +00:00
|
|
|
pub fn try_into_alice(self) -> Result<Alice> {
|
|
|
|
match self {
|
|
|
|
Swap::Alice(alice) => Ok(alice),
|
|
|
|
Swap::Bob(_) => bail!(NotAlice),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-03 02:17:09 +00:00
|
|
|
pub fn try_into_bob(self) -> Result<Bob> {
|
|
|
|
match self {
|
|
|
|
Swap::Bob(bob) => Ok(bob),
|
2021-03-26 04:16:19 +00:00
|
|
|
Swap::Alice(_) => bail!(NotBob),
|
2021-03-03 02:17:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 04:40:59 +00:00
|
|
|
pub struct Database {
|
|
|
|
swaps: sled::Tree,
|
|
|
|
peers: sled::Tree,
|
|
|
|
}
|
2020-11-03 04:26:47 +00:00
|
|
|
|
|
|
|
impl Database {
|
2020-10-13 22:32:25 +00:00
|
|
|
pub fn open(path: &Path) -> Result<Self> {
|
2021-03-04 05:52:29 +00:00
|
|
|
tracing::debug!("Opening database at {}", path.display());
|
|
|
|
|
2020-10-21 22:52:57 +00:00
|
|
|
let db =
|
|
|
|
sled::open(path).with_context(|| format!("Could not open the DB at {:?}", path))?;
|
2020-10-13 22:32:25 +00:00
|
|
|
|
2021-03-30 04:40:59 +00:00
|
|
|
let swaps = db.open_tree("swaps")?;
|
|
|
|
let peers = db.open_tree("peers")?;
|
|
|
|
|
|
|
|
Ok(Database { swaps, peers })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn insert_peer_id(&self, swap_id: Uuid, peer_id: PeerId) -> Result<()> {
|
|
|
|
let peer_id_str = peer_id.to_string();
|
|
|
|
|
|
|
|
let key = serialize(&swap_id)?;
|
|
|
|
let value = serialize(&peer_id_str).context("Could not serialize peer-id")?;
|
|
|
|
|
|
|
|
self.peers.insert(key, value)?;
|
|
|
|
|
|
|
|
self.peers
|
|
|
|
.flush_async()
|
|
|
|
.await
|
|
|
|
.map(|_| ())
|
|
|
|
.context("Could not flush db")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_peer_id(&self, swap_id: Uuid) -> Result<PeerId> {
|
|
|
|
let key = serialize(&swap_id)?;
|
|
|
|
|
|
|
|
let encoded = self
|
|
|
|
.peers
|
|
|
|
.get(&key)?
|
|
|
|
.ok_or_else(|| anyhow!("No peer-id found for swap id {} in database", swap_id))?;
|
|
|
|
|
|
|
|
let peer_id: String = deserialize(&encoded).context("Could not deserialize peer-id")?;
|
|
|
|
Ok(PeerId::from_str(peer_id.as_str())?)
|
2020-10-13 22:32:25 +00:00
|
|
|
}
|
|
|
|
|
2020-11-03 04:26:47 +00:00
|
|
|
pub async fn insert_latest_state(&self, swap_id: Uuid, state: Swap) -> Result<()> {
|
2020-11-03 03:23:03 +00:00
|
|
|
let key = serialize(&swap_id)?;
|
2020-10-13 22:32:25 +00:00
|
|
|
let new_value = serialize(&state).context("Could not serialize new state value")?;
|
|
|
|
|
2021-03-30 04:40:59 +00:00
|
|
|
let old_value = self.swaps.get(&key)?;
|
2020-10-13 22:32:25 +00:00
|
|
|
|
2021-03-30 04:40:59 +00:00
|
|
|
self.swaps
|
2020-10-13 22:32:25 +00:00
|
|
|
.compare_and_swap(key, old_value, Some(new_value))
|
|
|
|
.context("Could not write in the DB")?
|
2020-10-21 22:52:57 +00:00
|
|
|
.context("Stored swap somehow changed, aborting saving")?;
|
2020-10-13 22:32:25 +00:00
|
|
|
|
2021-03-30 04:40:59 +00:00
|
|
|
self.swaps
|
2020-10-13 22:32:25 +00:00
|
|
|
.flush_async()
|
|
|
|
.await
|
|
|
|
.map(|_| ())
|
|
|
|
.context("Could not flush db")
|
|
|
|
}
|
|
|
|
|
2021-02-19 06:00:45 +00:00
|
|
|
pub fn get_state(&self, swap_id: Uuid) -> Result<Swap> {
|
2020-11-03 03:23:03 +00:00
|
|
|
let key = serialize(&swap_id)?;
|
2020-10-13 22:32:25 +00:00
|
|
|
|
|
|
|
let encoded = self
|
2021-03-30 04:40:59 +00:00
|
|
|
.swaps
|
2020-10-13 22:32:25 +00:00
|
|
|
.get(&key)?
|
2020-12-15 10:26:02 +00:00
|
|
|
.ok_or_else(|| anyhow!("Swap with id {} not found in database", swap_id))?;
|
2020-10-13 22:32:25 +00:00
|
|
|
|
|
|
|
let state = deserialize(&encoded).context("Could not deserialize state")?;
|
|
|
|
Ok(state)
|
|
|
|
}
|
2020-11-03 04:49:00 +00:00
|
|
|
|
2021-03-26 04:16:19 +00:00
|
|
|
pub fn all_alice(&self) -> Result<Vec<(Uuid, Alice)>> {
|
|
|
|
self.all_alice_iter().collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn all_alice_iter(&self) -> impl Iterator<Item = Result<(Uuid, Alice)>> {
|
|
|
|
self.all_swaps_iter().map(|item| {
|
|
|
|
let (swap_id, swap) = item?;
|
|
|
|
Ok((swap_id, swap.try_into_alice()?))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn all_bob(&self) -> Result<Vec<(Uuid, Bob)>> {
|
|
|
|
self.all_bob_iter().collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn all_bob_iter(&self) -> impl Iterator<Item = Result<(Uuid, Bob)>> {
|
|
|
|
self.all_swaps_iter().map(|item| {
|
|
|
|
let (swap_id, swap) = item?;
|
|
|
|
Ok((swap_id, swap.try_into_bob()?))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn all_swaps_iter(&self) -> impl Iterator<Item = Result<(Uuid, Swap)>> {
|
2021-03-30 04:40:59 +00:00
|
|
|
self.swaps.iter().map(|item| {
|
2021-03-26 04:16:19 +00:00
|
|
|
let (key, value) = item.context("Failed to retrieve swap from DB")?;
|
|
|
|
|
|
|
|
let swap_id = deserialize::<Uuid>(&key)?;
|
|
|
|
let swap = deserialize::<Swap>(&value).context("Failed to deserialize swap")?;
|
|
|
|
|
|
|
|
Ok((swap_id, swap))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unfinished_alice(&self) -> Result<Vec<(Uuid, Alice)>> {
|
|
|
|
self.all_alice_iter()
|
|
|
|
.filter_ok(|(_swap_id, alice)| !matches!(alice, Alice::Done(_)))
|
2020-11-03 04:49:00 +00:00
|
|
|
.collect()
|
|
|
|
}
|
2020-10-13 22:32:25 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 06:00:45 +00:00
|
|
|
pub fn serialize<T>(t: &T) -> Result<Vec<u8>>
|
2020-10-13 22:32:25 +00:00
|
|
|
where
|
|
|
|
T: Serialize,
|
|
|
|
{
|
|
|
|
Ok(serde_cbor::to_vec(t)?)
|
|
|
|
}
|
|
|
|
|
2021-02-19 06:00:45 +00:00
|
|
|
pub fn deserialize<T>(v: &[u8]) -> Result<T>
|
2020-10-13 22:32:25 +00:00
|
|
|
where
|
|
|
|
T: DeserializeOwned,
|
|
|
|
{
|
|
|
|
Ok(serde_cbor::from_slice(&v)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2021-03-04 00:28:58 +00:00
|
|
|
use crate::database::alice::{Alice, AliceEndState};
|
|
|
|
use crate::database::bob::{Bob, BobEndState};
|
2020-11-03 04:26:47 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn can_write_and_read_to_multiple_keys() {
|
|
|
|
let db_dir = tempfile::tempdir().unwrap();
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
|
|
|
|
2020-12-23 01:08:51 +00:00
|
|
|
let state_1 = Swap::Alice(Alice::Done(AliceEndState::BtcRedeemed));
|
2020-11-03 04:26:47 +00:00
|
|
|
let swap_id_1 = Uuid::new_v4();
|
|
|
|
db.insert_latest_state(swap_id_1, state_1.clone())
|
|
|
|
.await
|
|
|
|
.expect("Failed to save second state");
|
|
|
|
|
2021-01-18 03:45:47 +00:00
|
|
|
let state_2 = Swap::Bob(Bob::Done(BobEndState::SafelyAborted));
|
2020-11-03 04:26:47 +00:00
|
|
|
let swap_id_2 = Uuid::new_v4();
|
|
|
|
db.insert_latest_state(swap_id_2, state_2.clone())
|
|
|
|
.await
|
|
|
|
.expect("Failed to save first state");
|
|
|
|
|
|
|
|
let recovered_1 = db
|
2020-11-03 06:08:31 +00:00
|
|
|
.get_state(swap_id_1)
|
2020-11-03 04:26:47 +00:00
|
|
|
.expect("Failed to recover first state");
|
|
|
|
|
|
|
|
let recovered_2 = db
|
2020-11-03 06:08:31 +00:00
|
|
|
.get_state(swap_id_2)
|
2020-11-03 04:26:47 +00:00
|
|
|
.expect("Failed to recover second state");
|
|
|
|
|
|
|
|
assert_eq!(recovered_1, state_1);
|
|
|
|
assert_eq!(recovered_2, state_2);
|
2020-10-13 22:32:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
2020-11-03 04:26:47 +00:00
|
|
|
async fn can_write_twice_to_one_key() {
|
2020-10-22 08:34:53 +00:00
|
|
|
let db_dir = tempfile::tempdir().unwrap();
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
2020-10-13 22:32:25 +00:00
|
|
|
|
2020-12-23 01:08:51 +00:00
|
|
|
let state = Swap::Alice(Alice::Done(AliceEndState::SafelyAborted));
|
2020-10-13 22:32:25 +00:00
|
|
|
|
2020-11-03 03:23:03 +00:00
|
|
|
let swap_id = Uuid::new_v4();
|
2020-11-03 04:26:47 +00:00
|
|
|
db.insert_latest_state(swap_id, state.clone())
|
2020-10-13 22:32:25 +00:00
|
|
|
.await
|
|
|
|
.expect("Failed to save state the first time");
|
2020-11-03 04:26:47 +00:00
|
|
|
let recovered = db
|
2020-11-03 06:08:31 +00:00
|
|
|
.get_state(swap_id)
|
2020-10-13 22:32:25 +00:00
|
|
|
.expect("Failed to recover state the first time");
|
|
|
|
|
|
|
|
// We insert and recover twice to ensure database implementation allows the
|
|
|
|
// caller to write to an existing key
|
2020-11-03 04:26:47 +00:00
|
|
|
db.insert_latest_state(swap_id, recovered)
|
2020-10-13 22:32:25 +00:00
|
|
|
.await
|
|
|
|
.expect("Failed to save state the second time");
|
2020-11-03 04:26:47 +00:00
|
|
|
let recovered = db
|
2020-11-03 06:08:31 +00:00
|
|
|
.get_state(swap_id)
|
2020-10-13 22:32:25 +00:00
|
|
|
.expect("Failed to recover state the second time");
|
|
|
|
|
2020-11-03 04:26:47 +00:00
|
|
|
assert_eq!(recovered, state);
|
2020-10-13 22:32:25 +00:00
|
|
|
}
|
2020-11-03 04:49:00 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
2021-03-26 04:16:19 +00:00
|
|
|
async fn all_swaps_as_alice() {
|
2020-11-03 04:49:00 +00:00
|
|
|
let db_dir = tempfile::tempdir().unwrap();
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
|
|
|
|
2021-03-26 04:16:19 +00:00
|
|
|
let alice_state = Alice::Done(AliceEndState::BtcPunished);
|
|
|
|
let alice_swap = Swap::Alice(alice_state.clone());
|
|
|
|
let alice_swap_id = Uuid::new_v4();
|
|
|
|
db.insert_latest_state(alice_swap_id, alice_swap)
|
2020-11-03 04:49:00 +00:00
|
|
|
.await
|
2021-03-26 04:16:19 +00:00
|
|
|
.expect("Failed to save alice state 1");
|
2020-11-03 04:49:00 +00:00
|
|
|
|
2021-03-26 04:16:19 +00:00
|
|
|
let alice_swaps = db.all_alice().unwrap();
|
|
|
|
assert_eq!(alice_swaps.len(), 1);
|
|
|
|
assert!(alice_swaps.contains(&(alice_swap_id, alice_state)));
|
|
|
|
|
|
|
|
let bob_state = Bob::Done(BobEndState::SafelyAborted);
|
|
|
|
let bob_swap = Swap::Bob(bob_state);
|
|
|
|
let bob_swap_id = Uuid::new_v4();
|
|
|
|
db.insert_latest_state(bob_swap_id, bob_swap)
|
2020-11-03 04:49:00 +00:00
|
|
|
.await
|
2021-03-26 04:16:19 +00:00
|
|
|
.expect("Failed to save bob state 1");
|
|
|
|
|
|
|
|
let err = db.all_alice().unwrap_err();
|
|
|
|
|
|
|
|
assert_eq!(err.downcast_ref::<NotAlice>().unwrap(), &NotAlice);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn all_swaps_as_bob() {
|
|
|
|
let db_dir = tempfile::tempdir().unwrap();
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
|
|
|
|
|
|
|
let bob_state = Bob::Done(BobEndState::SafelyAborted);
|
|
|
|
let bob_swap = Swap::Bob(bob_state.clone());
|
|
|
|
let bob_swap_id = Uuid::new_v4();
|
|
|
|
db.insert_latest_state(bob_swap_id, bob_swap)
|
|
|
|
.await
|
|
|
|
.expect("Failed to save bob state 1");
|
|
|
|
|
|
|
|
let bob_swaps = db.all_bob().unwrap();
|
|
|
|
assert_eq!(bob_swaps.len(), 1);
|
|
|
|
assert!(bob_swaps.contains(&(bob_swap_id, bob_state)));
|
|
|
|
|
|
|
|
let alice_state = Alice::Done(AliceEndState::BtcPunished);
|
|
|
|
let alice_swap = Swap::Alice(alice_state);
|
|
|
|
let alice_swap_id = Uuid::new_v4();
|
|
|
|
db.insert_latest_state(alice_swap_id, alice_swap)
|
|
|
|
.await
|
|
|
|
.expect("Failed to save alice state 1");
|
2020-11-03 04:49:00 +00:00
|
|
|
|
2021-03-26 04:16:19 +00:00
|
|
|
let err = db.all_bob().unwrap_err();
|
2020-11-03 04:49:00 +00:00
|
|
|
|
2021-03-26 04:16:19 +00:00
|
|
|
assert_eq!(err.downcast_ref::<NotBob>().unwrap(), &NotBob);
|
2020-11-03 04:49:00 +00:00
|
|
|
}
|
2021-03-30 04:40:59 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn can_save_swap_state_and_peer_id_with_same_swap_id() -> Result<()> {
|
|
|
|
let db_dir = tempfile::tempdir().unwrap();
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
|
|
|
|
|
|
|
let alice_id = Uuid::new_v4();
|
|
|
|
let alice_state = Alice::Done(AliceEndState::BtcPunished);
|
|
|
|
let alice_swap = Swap::Alice(alice_state);
|
|
|
|
let peer_id = PeerId::random();
|
|
|
|
|
|
|
|
db.insert_latest_state(alice_id, alice_swap.clone()).await?;
|
|
|
|
db.insert_peer_id(alice_id, peer_id).await?;
|
|
|
|
|
|
|
|
let loaded_swap = db.get_state(alice_id)?;
|
|
|
|
let loaded_peer_id = db.get_peer_id(alice_id)?;
|
|
|
|
|
|
|
|
assert_eq!(alice_swap, loaded_swap);
|
|
|
|
assert_eq!(peer_id, loaded_peer_id);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn test_reopen_db() -> Result<()> {
|
|
|
|
let db_dir = tempfile::tempdir().unwrap();
|
|
|
|
let alice_id = Uuid::new_v4();
|
|
|
|
let alice_state = Alice::Done(AliceEndState::BtcPunished);
|
|
|
|
let alice_swap = Swap::Alice(alice_state);
|
|
|
|
|
|
|
|
let peer_id = PeerId::random();
|
|
|
|
|
|
|
|
{
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
|
|
|
db.insert_latest_state(alice_id, alice_swap.clone()).await?;
|
|
|
|
db.insert_peer_id(alice_id, peer_id).await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let db = Database::open(db_dir.path()).unwrap();
|
|
|
|
|
|
|
|
let loaded_swap = db.get_state(alice_id)?;
|
|
|
|
let loaded_peer_id = db.get_peer_id(alice_id)?;
|
|
|
|
|
|
|
|
assert_eq!(alice_swap, loaded_swap);
|
|
|
|
assert_eq!(peer_id, loaded_peer_id);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-10-13 22:32:25 +00:00
|
|
|
}
|