mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-03 09:29:39 +00:00
begin prepare msig orchestration
This commit is contained in:
parent
a5dfc3f6d5
commit
01405e3d6f
4 changed files with 178 additions and 28 deletions
|
@ -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
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,11 +298,16 @@ 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;
|
||||
|
@ -301,7 +317,11 @@ impl eframe::App for MarketApp {
|
|||
.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();
|
||||
}
|
||||
|
|
|
@ -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>")]
|
||||
|
|
Loading…
Reference in a new issue