Skip to content

Commit

Permalink
Merge pull request #507 from TheCharlatan/persistSwapHistory
Browse files Browse the repository at this point in the history
Persist offer history
  • Loading branch information
zkao authored Jul 1, 2022
2 parents 42ee892 + 169b636 commit 1c0633c
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 2 deletions.
114 changes: 113 additions & 1 deletion src/databased/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use crate::databased::runtime::request::OfferStatus;
use crate::databased::runtime::request::OfferStatusPair;
use crate::databased::runtime::request::OfferStatusSelector;
use crate::farcaster_core::consensus::Encodable;
use crate::walletd::runtime::{CheckpointWallet, Wallet};
use farcaster_core::negotiation::PublicOffer;
Expand Down Expand Up @@ -307,6 +310,20 @@ impl Runtime {
)?;
}

Request::SetOfferStatus(OfferStatusPair { offer, status }) => {
self.database.set_offer_status(&offer, &status)?;
}

Request::RetrieveOffers(selector) => {
let offer_status_pairs = self.database.get_offers(selector)?;
endpoints.send_to(
ServiceBus::Ctl,
ServiceId::Database,
source,
Request::OfferStatusList(offer_status_pairs.into()),
)?;
}

_ => {
error!("Request {} is not supported by the CTL interface", request);
}
Expand Down Expand Up @@ -466,18 +483,71 @@ struct Database(lmdb::Environment);

const LMDB_CHECKPOINTS: &str = "checkpoints";
const LMDB_ADDRESSES: &str = "addresses";
const LMDB_OFFER_HISTORY: &str = "offer_history";

impl Database {
fn new(path: PathBuf) -> Result<Database, lmdb::Error> {
let env = lmdb::Environment::new()
.set_map_size(10485760 * 1024 * 64)
.set_max_dbs(2)
.set_max_dbs(3)
.open(&path)?;
env.create_db(Some(LMDB_CHECKPOINTS), lmdb::DatabaseFlags::empty())?;
env.create_db(Some(LMDB_ADDRESSES), lmdb::DatabaseFlags::empty())?;
env.create_db(Some(LMDB_OFFER_HISTORY), lmdb::DatabaseFlags::empty())?;
Ok(Database(env))
}

fn set_offer_status(
&mut self,
offer: &PublicOffer<BtcXmr>,
status: &OfferStatus,
) -> Result<(), lmdb::Error> {
let db = self.0.open_db(Some(LMDB_OFFER_HISTORY))?;
let mut tx = self.0.begin_rw_txn()?;
let mut key = vec![];
let _key_size = offer.strict_encode(&mut key);
if !tx.get(db, &key).is_err() {
tx.del(db, &key.clone(), None)?;
}
let mut val = vec![];
let _key_size = status.strict_encode(&mut val);
tx.put(db, &key, &val, lmdb::WriteFlags::empty())?;
tx.commit()?;
Ok(())
}

fn get_offers(
&mut self,
selector: OfferStatusSelector,
) -> Result<Vec<OfferStatusPair>, lmdb::Error> {
let db = self.0.open_db(Some(LMDB_OFFER_HISTORY))?;
let tx = self.0.begin_ro_txn()?;
let mut cursor = tx.open_ro_cursor(db)?;
let res = cursor
.iter()
.filter_map(|(key, val)| {
let status = OfferStatus::strict_decode(std::io::Cursor::new(val.to_vec())).ok()?;
let filtered_status = match status {
OfferStatus::Open if selector == OfferStatusSelector::Open => Some(status),
OfferStatus::InProgress if selector == OfferStatusSelector::InProgress => {
Some(status)
}
OfferStatus::Ended(_) if selector == OfferStatusSelector::Ended => Some(status),
_ if selector == OfferStatusSelector::All => Some(status),
_ => None,
}?;
let offer =
PublicOffer::<BtcXmr>::strict_decode(std::io::Cursor::new(key.to_vec()))
.ok()?;
Some(OfferStatusPair {
offer,
status: filtered_status,
})
})
.collect();
Ok(res)
}

fn set_address(
&mut self,
address: &bitcoin::Address,
Expand Down Expand Up @@ -616,4 +686,46 @@ fn test_lmdb_state() {
assert_eq!(sk, val_retrieved);
let addrs = database.get_all_addresses().unwrap();
assert!(addrs.contains(&addr));

let offer_1 = PublicOffer::<BtcXmr>::from_str("Offer:Cke4ftrP5A71LQM2fvVdFMNR4gmBqNCsR11111uMFuZTAsNgpdK8DiK11111TB9zym113GTvtvqfD1111114A4TUGURtskxM3BUGLBGAdFDhJQVMQmiPUsL5vSTKhyBKw3Lh11111111111111111111111111111111111111111AfZ113XRBuStRU5H").unwrap();
let offer_2 = PublicOffer::<BtcXmr>::from_str("Offer:Cke4ftrP5A71LQM2fvVdFMNR4grq1wi1D11111uMFuZTAsNgpdK8DiK11111TB9zym113GTvtvqfD1111114A4TUGURtskxM3BUGLBGAdFDhJQVMQmiPUsL5vSTKhyBKw3Lh11111111111111111111111111111111111111111AfZ113W5EEpvY61v").unwrap();

database
.set_offer_status(&offer_1, &OfferStatus::Open)
.unwrap();
let offers_retrieved = database.get_offers(OfferStatusSelector::All).unwrap();
assert_eq!(offer_1, offers_retrieved[0].offer);

let offers_retrieved = database.get_offers(OfferStatusSelector::Open).unwrap();
assert_eq!(offer_1, offers_retrieved[0].offer);

database
.set_offer_status(&offer_1, &OfferStatus::InProgress)
.unwrap();
let offers_retrieved = database
.get_offers(OfferStatusSelector::InProgress)
.unwrap();
assert_eq!(offer_1, offers_retrieved[0].offer);

database
.set_offer_status(&offer_1, &OfferStatus::Ended(request::Outcome::Buy))
.unwrap();
let offers_retrieved = database.get_offers(OfferStatusSelector::Ended).unwrap();
assert_eq!(offer_1, offers_retrieved[0].offer);

database
.set_offer_status(&offer_2, &OfferStatus::Open)
.unwrap();
let offers_retrieved = database.get_offers(OfferStatusSelector::All).unwrap();
let status_1 = OfferStatusPair {
offer: offer_1,
status: OfferStatus::Ended(request::Outcome::Buy),
};
let status_2 = OfferStatusPair {
offer: offer_2,
status: OfferStatus::Open,
};
assert!(offers_retrieved.len() == 2);
assert!(offers_retrieved.contains(&status_1));
assert!(offers_retrieved.contains(&status_2));
}
62 changes: 61 additions & 1 deletion src/rpc/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,9 +718,66 @@ pub enum Request {
#[api(type = 1314)]
#[display("address_secret_key")]
AddressSecretKey(AddressSecretKey),

#[api(type = 1315)]
#[display("set_offer_history({0})")]
SetOfferStatus(OfferStatusPair),

#[api(type = 1316)]
#[display("retrieve_offers")]
RetrieveOffers(OfferStatusSelector),

#[api(type = 1317)]
#[display("offer_status_list({0})")]
OfferStatusList(List<OfferStatusPair>),
}

#[derive(Clone, Debug, Display, StrictEncode, StrictDecode)]
#[derive(Clone, Debug, Eq, PartialEq, Display, StrictEncode, StrictDecode)]
#[display("{offer}, {status}")]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(OfferStatusPair::to_yaml_string)]
pub struct OfferStatusPair {
pub offer: PublicOffer<BtcXmr>,
pub status: OfferStatus,
}

#[derive(Clone, Debug, Eq, PartialEq, Display, StrictEncode, StrictDecode)]
pub enum OfferStatusSelector {
#[display("Open")]
Open,
#[display("In Progress")]
InProgress,
#[display("Ended")]
Ended,
#[display("All")]
All,
}

#[derive(Clone, Debug, Eq, PartialEq, Display, StrictEncode, StrictDecode)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
pub enum OfferStatus {
#[display("Open")]
Open,
#[display("In Progress")]
InProgress,
#[display("Ended({0})")]
Ended(Outcome),
}

#[derive(Clone, Debug, Eq, PartialEq, Display, StrictEncode, StrictDecode)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
pub enum Outcome {
#[display("Success(Swapped)")]
Buy,
Expand All @@ -731,6 +788,7 @@ pub enum Outcome {
#[display("Failure(Canceled)")]
Cancel,
}

#[derive(Clone, Debug, Display, StrictDecode, StrictEncode)]
#[display("funding_info")]
pub enum FundingInfo {
Expand Down Expand Up @@ -1129,6 +1187,8 @@ impl ToYamlString for SwapProgress {}
impl ToYamlString for ProgressEvent {}
#[cfg(feature = "serde")]
impl ToYamlString for CheckpointEntry {}
#[cfg(feature = "serde")]
impl ToYamlString for OfferStatusPair {}

#[derive(Wrapper, Clone, PartialEq, Eq, Debug, From, StrictEncode, StrictDecode)]
#[wrapper(IndexRange)]
Expand Down

0 comments on commit 1c0633c

Please sign in to comment.