begin prepare msig orchestration

This commit is contained in:
creating2morrow 2023-07-11 08:21:11 -04:00
parent a5dfc3f6d5
commit 01405e3d6f
4 changed files with 178 additions and 28 deletions

View file

@ -140,11 +140,12 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
return Default::default();
}
let orid: String = v.remove(0);
let customer_info: String = v.remove(0);
let mut info = String::from(&customer_info);
if sub_type != TXSET_MSIG {
let mediator_info: String = v.remove(0);
info = format!("{}:{}", customer_info, mediator_info);
let a_info: String = v.remove(0);
let mut info = String::from(&a_info);
// on prepare info customer only receives one set of info
if sub_type != TXSET_MSIG || !v.is_empty() {
let b_info: String = v.remove(0);
info = format!("{}:{}", a_info, b_info);
}
bytes = Vec::new();
debug!("zero decryption bytes: {:?}", bytes);
@ -174,8 +175,6 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
/// let s = db::Interface::open();
/// let key = "prepare-o123-test.b32.i2p";
/// let info_str = db::Interface::read(&s.env, &s.handle, &key);
/// let info_split = info_str.split(":");
/// let mut v_info: Vec<String> = info_split.map(|s| String::from(s)).collect();
/// ```
pub async fn rx_multisig(m: Json<Message>) {
// make sure the message isn't something strange
@ -207,7 +206,7 @@ pub async fn rx_multisig(m: Json<Message>) {
&data.sub_type, &data.orid
);
// lookup msig message data by {type}-{order id}-{contact .b32.i2p address}
// store info as {customer_info}:{mediator_info}
// store info as {a_info}:{a_info (optional)}
let msig_key = format!("{}-{}-{}", &data.sub_type, &data.orid, &m.from);
db::Interface::async_write(&s.env, &s.handle, &msig_key, &data.info).await;
}
@ -564,6 +563,68 @@ pub async fn send_export_info(orid: &String, contact: &String) {
create(j_message, jwp, MessageType::Multisig).await;
}
/// Customer begins multisig orchestration by requesting the prepare info
///
/// from the mediator and the vendor. In response they create an encrypted
///
/// multisig message with the requested data. Cusomter manages multisig by
///
/// injecting
async fn trigger_msig_info_request(
contact: String,
jwp: String,
request: reqres::MultisigInfoRequest,
) -> Result<Order, Box<dyn Error>> {
let host = utils::get_i2p_http_proxy();
let proxy = reqwest::Proxy::http(&host)?;
let client = reqwest::Client::builder().proxy(proxy).build();
match client?
.post(format!("http://{}/multisig/info", contact))
.header("proof", jwp)
.json(&request)
.send()
.await
{
Ok(response) => {
let res = response.json::<Order>().await;
debug!("{} info for order response: {:?}", &request.msig_type, res);
match res {
Ok(r) => Ok(r),
_ => Ok(Default::default()),
}
}
Err(e) => {
error!("failed to {} info for order due to: {:?}", &request.msig_type, e);
Ok(Default::default())
}
}
}
/// Deconstruction pass-through so that we can send the request from an async
///
/// channel in the neveko-gui module.
pub async fn d_trigger_msig_info(
contact: &String,
jwp: &String,
request: &reqres::MultisigInfoRequest,
) -> Order {
let d_contact: String = String::from(contact);
let d_jwp: String = String::from(jwp);
let d_request: reqres::MultisigInfoRequest = reqres::MultisigInfoRequest {
contact: String::from(&request.contact),
info: request.info.clone(),
init_mediator: request.init_mediator,
msig_type: String::from(&request.msig_type),
orid: String::from(&request.orid),
};
let pre = trigger_msig_info_request(d_contact, d_jwp, d_request).await;
if pre.is_err() {
log::error!("faile to trigger {} info request", request.msig_type);
return Default::default();
}
pre.unwrap_or(Default::default())
}
// Tests
//-------------------------------------------------------------------------------

View file

@ -366,3 +366,12 @@ pub async fn transmit_order_request(
}
}
}
pub async fn init_mediator_wallet(orid: &String) {
let password = std::env::var(crate::MONERO_WALLET_PASSWORD)
.unwrap_or(utils::empty_string());
let m_wallet = monero::create_wallet(orid, &password).await;
if !m_wallet {
log::error!("failed to create mediator wallet");
}
}

View file

@ -62,6 +62,8 @@ pub struct MarketApp {
/// order currently being acted on
m_order: models::Order,
orders: Vec<models::Order>,
our_prepare_info_tx: Sender<String>,
our_prepare_info_rx: Receiver<String>,
product_from_vendor: models::Product,
product_image: egui_extras::RetainedImage,
products: Vec<models::Product>,
@ -98,6 +100,7 @@ impl Default for MarketApp {
let (get_vendor_products_tx, get_vendor_products_rx) = std::sync::mpsc::channel();
let (get_vendor_product_tx, get_vendor_product_rx) = std::sync::mpsc::channel();
let (submit_order_tx, submit_order_rx) = std::sync::mpsc::channel();
let (our_prepare_info_tx, our_prepare_info_rx) = std::sync::mpsc::channel();
MarketApp {
contact_info_rx,
contact_info_tx,
@ -126,6 +129,8 @@ impl Default for MarketApp {
is_window_shopping: false,
msig: Default::default(),
m_order: Default::default(),
our_prepare_info_rx,
our_prepare_info_tx,
new_order: Default::default(),
new_order_price: 0,
new_order_shipping_address: utils::empty_string(),
@ -224,6 +229,12 @@ impl eframe::App for MarketApp {
}
}
// TODO(c2m): extract from db after initialization
if let Ok(our_prepare_info) = self.our_prepare_info_rx.try_recv() {
self.msig.prepare_info = our_prepare_info;
self.is_loading = false;
}
// Vendor status window
//-----------------------------------------------------------------------------------
let mut is_showing_vendor_status = self.is_showing_vendor_status;
@ -287,21 +298,30 @@ impl eframe::App for MarketApp {
.vscroll(true)
.show(ctx, |ui| {
ui.heading("Multisig Management");
if self.is_loading {
ui.add(egui::Spinner::new());
ui.label("msig request in progress...");
}
ui.horizontal(|ui| {
let mediator = ui.label("Mediator: ");
let prefix = String::from(crate::GUI_MSIG_MEDIATOR_DB_KEY);
if !self.msig.query_mediator {
let mediator_db = utils::search_gui_db(String::from(&prefix), self.m_order.orid.clone());
let mediator_db =
utils::search_gui_db(String::from(&prefix), self.m_order.orid.clone());
log::debug!("mediator db: {}", mediator_db);
self.msig.has_mediator = mediator_db != utils::empty_string();
self.msig.mediator = mediator_db;
self.msig.query_mediator = true;
} else if self.msig.query_mediator && !self.msig.has_mediator {
ui.text_edit_singleline(&mut self.msig.mediator)
.labelled_by(mediator.id);
.labelled_by(mediator.id);
ui.label("\t");
if ui.button("Set Mediator").clicked() {
utils::write_gui_db(prefix, self.m_order.orid.clone(), self.msig.mediator.clone());
utils::write_gui_db(
prefix,
self.m_order.orid.clone(),
self.msig.mediator.clone(),
);
self.msig.has_mediator = true;
}
} else {
@ -318,38 +338,47 @@ impl eframe::App for MarketApp {
ui.horizontal(|ui| {
ui.label("Prepare: \t\t\t\t\t");
if ui.button("Prepare").clicked() {
self.is_loading = true;
let mediator_prefix = String::from(crate::GUI_MSIG_MEDIATOR_DB_KEY);
let vendor_prefix = String::from(crate::GUI_OVL_DB_KEY);
let mediator =
utils::search_gui_db(mediator_prefix, self.m_order.orid.clone());
let vendor = utils::search_gui_db(vendor_prefix, self.m_order.orid.clone());
// get prepare multisig info from vendor and mediator
// call prepare multisig and save to db
send_prepare_info_req(
self.our_prepare_info_tx.clone(),
ctx.clone(),
self.vendor_status.jwp.clone(),
mediator,
&self.m_order.orid.clone(),
vendor,
)
}
});
ui.horizontal(|ui| {
ui.label("Make: \t\t\t\t\t\t");
if ui.button("Make").clicked() {
}
if ui.button("Make").clicked() {}
});
ui.horizontal(|ui| {
ui.label("Exchange Keys: \t\t");
if ui.button("Exchange").clicked() {
}
if ui.button("Exchange").clicked() {}
});
ui.horizontal(|ui| {
ui.label("Fund:\t\t\t\t\t\t\t");
if ui.button("Fund").clicked() {
}
if ui.button("Fund").clicked() {}
});
ui.horizontal(|ui| {
ui.label("Export Info: \t\t\t\t");
if ui.button("Export").clicked() {
}
if ui.button("Export").clicked() {}
});
ui.horizontal(|ui| {
ui.label("Release Payment: \t");
if ui.button("Sign Txset").clicked() {
}
if ui.button("Sign Txset").clicked() {}
});
ui.horizontal(|ui| {
ui.label("Create Dispute: \t\t");
if ui.button("Dispute").clicked() {}
});
ui.label("\n");
if ui.button("Exit").clicked() {
@ -1225,7 +1254,54 @@ fn submit_order_req(
let u_order = order.unwrap_or_else(|_| Default::default());
// cache order request to db
order::backup(&u_order);
let prefix = String::from(crate::GUI_OVL_DB_KEY);
let orid = String::from(&u_order.orid);
let i2p = String::from(&contact);
utils::write_gui_db(prefix, orid, i2p);
let _ = tx.send(u_order);
ctx.request_repaint();
});
}
fn send_prepare_info_req(
tx: Sender<String>,
ctx: egui::Context,
jwp: String,
mediator: String,
orid: &String,
vendor: String,
)
{
let m_orid: String = String::from(orid);
let v_orid: String = String::from(orid);
tokio::spawn(async move {
let prepare_info = monero::prepare_wallet().await;
let ref_prepare_info: &String = &prepare_info.result.multisig_info;
utils::write_gui_db(
String::from(crate::GUI_MSIG_PREPARE_DB_KEY),
utils::empty_string(),
String::from(ref_prepare_info)
);
// Request mediator and vendor while we're at it
// Will coordinating send this on make requests next
log::debug!("constructing {} msig messages", message::PREPARE_MSIG);
let v_msig_request: reqres::MultisigInfoRequest = reqres::MultisigInfoRequest {
contact: i2p::get_destination(None),
info: Vec::new(),
init_mediator: false,
msig_type: String::from(message::PREPARE_MSIG),
orid: String::from(v_orid),
};
let _v_result = message::d_trigger_msig_info(&vendor, &jwp, &v_msig_request).await;
let m_msig_request: reqres::MultisigInfoRequest = reqres::MultisigInfoRequest {
contact: i2p::get_destination(None),
info: Vec::new(),
init_mediator: false,
msig_type: String::from(message::PREPARE_MSIG),
orid: String::from(m_orid),
};
let _m_result = message::d_trigger_msig_info(&mediator, &jwp, &m_msig_request).await;
let _ = tx.send(String::from(ref_prepare_info));
});
ctx.request_repaint();
}

View file

@ -145,6 +145,10 @@ pub async fn get_multisig_info(
) -> Custom<Json<models::Order>> {
let info: Vec<String> = r_info.info.iter().cloned().collect();
if r_info.msig_type == String::from(message::PREPARE_MSIG) {
// mediator won't have wallet for order yet do that first
if r_info.init_mediator {
order::init_mediator_wallet(&r_info.orid).await;
}
message::send_prepare_info(&r_info.orid, &r_info.contact).await;
} else if r_info.msig_type == String::from(message::MAKE_MSIG) {
message::send_make_info(&r_info.orid, &r_info.contact, info).await;
@ -156,7 +160,7 @@ pub async fn get_multisig_info(
Custom(Status::Ok, Json(Default::default()))
}
/// Recieve multisig messages here
/// Recieve multisig messages here for vendor order processing
///
/// Protected: true
#[post("/", data = "<message>")]