Skip to content

Commit

Permalink
Merge pull request #1569 from get10101/chore/setup-prod-oracle
Browse files Browse the repository at this point in the history
feat: Support multiple oracles
  • Loading branch information
holzeis authored Nov 16, 2023
2 parents 95461d3 + e4c280c commit d955e9f
Show file tree
Hide file tree
Showing 17 changed files with 158 additions and 83 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build-release-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ jobs:
coordinator_port_http: 80
network: mainnet
tag: ${{ github.ref_name }}
oracle_endpoint: https://oracle.holzeis.me
oracle_pubkey: 16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0
oracle_endpoint: http://oracle.10101.finance
oracle_pubkey: 93051f54feefdb4765492a85139c436d4857e2e331a360c89a16d6bc02ba9cd0
fastlane_developer_app_identifier: finance.get10101.app
fastlane_provisioning_profile_specifier: match AppStore finance.get10101.app 1692208014
app_scheme: Runner
Expand All @@ -54,5 +54,5 @@ jobs:
coordinator_p2p_endpoint: 022ae8dbec1caa4dac93f07f2ebf5ad7a5dd08d375b79f11095e81b065c2155156@46.17.98.29:9045
coordinator_port_http: 80
network: mainnet
oracle_endpoint: https://oracle.holzeis.me
oracle_pubkey: 16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0
oracle_endpoint: http://oracle.10101.finance
oracle_pubkey: 93051f54feefdb4765492a85139c436d4857e2e331a360c89a16d6bc02ba9cd0
10 changes: 9 additions & 1 deletion coordinator/src/bin/coordinator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::Context;
use anyhow::Result;
use bitcoin::XOnlyPublicKey;
use coordinator::backup::SledBackup;
use coordinator::cli::Opts;
use coordinator::logger;
Expand Down Expand Up @@ -37,6 +38,7 @@ use std::backtrace::Backtrace;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::broadcast;
Expand Down Expand Up @@ -124,7 +126,11 @@ async fn main() -> Result<()> {
seed,
ephemeral_randomness,
settings.ln_dlc.clone(),
opts.get_oracle_info().into(),
opts.get_oracle_infos()
.into_iter()
.map(|o| o.into())
.collect(),
XOnlyPublicKey::from_str(&opts.oracle_pubkey).expect("valid public key"),
)?);

let event_handler = CoordinatorEventHandler::new(node.clone(), Some(node_event_sender));
Expand Down Expand Up @@ -220,12 +226,14 @@ async fn main() -> Result<()> {
tx_price_feed.clone(),
auth_users_notifier.clone(),
network,
node.inner.oracle_pubkey,
);
let _handle = async_match::monitor(
pool.clone(),
tx_user_feed.clone(),
auth_users_notifier.clone(),
network,
node.inner.oracle_pubkey,
);
let _handle = rollover::monitor(
pool.clone(),
Expand Down
39 changes: 28 additions & 11 deletions coordinator/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,24 @@ pub struct Opts {
pub fcm_api_key: String,

/// The endpoint of the p2p-derivatives oracle
#[clap(long, default_value = "http://localhost:8081")]
oracle_endpoint: String,

/// The public key of the oracle
#[arg(num_args(0..))]
#[clap(
long,
default_value = "16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0@http://localhost:8081"
)]
oracle: Vec<String>,

/// Defines the default oracle to be used for propose a dlc channel. Note this pubkey has to be
/// included in the oracle arguments.
///
/// FIXME(holzeis): Remove this argument once we have migrated successfully from the old oracle
/// to the new one. This is needed to instruct the coordinator to use only the new oracle for
/// proposing dlc channels.
#[clap(
long,
default_value = "16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0"
)]
oracle_pubkey: String,
pub oracle_pubkey: String,
}

#[derive(Debug, Clone, Copy, clap::ValueEnum)]
Expand Down Expand Up @@ -100,12 +109,20 @@ impl Opts {
self.network.into()
}

pub fn get_oracle_info(&self) -> OracleInfo {
OracleInfo {
endpoint: self.oracle_endpoint.clone(),
public_key: XOnlyPublicKey::from_str(self.oracle_pubkey.as_str())
.expect("Valid oracle public key"),
}
pub fn get_oracle_infos(&self) -> Vec<OracleInfo> {
self.oracle
.iter()
.map(|oracle| {
let oracle: Vec<&str> = oracle.split('@').collect();
OracleInfo {
public_key: XOnlyPublicKey::from_str(
oracle.first().expect("public key to be set"),
)
.expect("Valid oracle public key"),
endpoint: oracle.get(1).expect("endpoint to be set").to_string(),
}
})
.collect()
}

pub fn data_dir(&self) -> Result<PathBuf> {
Expand Down
4 changes: 2 additions & 2 deletions coordinator/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl Node {
// The contract input to be used for setting up the trade between the trader and the
// coordinator
let event_id = format!("{contract_symbol}{maturity_time}");
tracing::debug!(event_id, "Proposing dlc channel");
tracing::debug!(event_id, oracle=%trade_params.filled_with.oracle_pk, "Proposing dlc channel");
let contract_input = ContractInput {
offer_collateral: margin_coordinator - fee,
// the accepting party has do bring in additional margin for the fees
Expand All @@ -303,7 +303,7 @@ impl Node {
contract_infos: vec![ContractInputInfo {
contract_descriptor,
oracles: OracleInput {
public_keys: vec![self.inner.oracle_pk()],
public_keys: vec![trade_params.filled_with.oracle_pk],
event_id,
threshold: 1,
},
Expand Down
2 changes: 1 addition & 1 deletion coordinator/src/node/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl Node {
contract_infos: vec![ContractInputInfo {
contract_descriptor,
oracles: OracleInput {
public_keys: vec![self.inner.oracle_pk()],
public_keys: vec![self.inner.oracle_pubkey],
event_id,
threshold: 1,
},
Expand Down
17 changes: 9 additions & 8 deletions coordinator/src/orderbook/async_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use orderbook_commons::Matches;
use orderbook_commons::Message;
use orderbook_commons::OrderReason;
use orderbook_commons::OrderState;
use std::str::FromStr;
use time::OffsetDateTime;
use tokio::sync::broadcast;
use tokio::sync::mpsc;
Expand All @@ -28,6 +27,7 @@ pub fn monitor(
tx_user_feed: broadcast::Sender<NewUserMessage>,
notifier: mpsc::Sender<OrderbookMessage>,
network: Network,
oracle_pk: XOnlyPublicKey,
) -> RemoteHandle<Result<()>> {
let mut user_feed = tx_user_feed.subscribe();
let (fut, remote_handle) = async move {
Expand All @@ -37,7 +37,7 @@ pub fn monitor(
let notifier = notifier.clone();
async move {
tracing::debug!(trader_id=%new_user_msg.new_user, "Checking if the user needs to be notified about pending matches");
if let Err(e) = process_pending_match(&mut conn, notifier, new_user_msg.new_user, network).await {
if let Err(e) = process_pending_match(&mut conn, notifier, new_user_msg.new_user, network, oracle_pk).await {
tracing::error!("Failed to process pending match. Error: {e:#}");
}
}
Expand All @@ -57,12 +57,13 @@ async fn process_pending_match(
notifier: mpsc::Sender<OrderbookMessage>,
trader_id: PublicKey,
network: Network,
oracle_pk: XOnlyPublicKey,
) -> Result<()> {
if let Some(order) = orders::get_by_trader_id_and_state(conn, trader_id, OrderState::Matched)? {
tracing::debug!(%trader_id, order_id=%order.id, "Notifying trader about pending match");

let matches = matches::get_matches_by_order_id(conn, order.id)?;
let filled_with = get_filled_with_from_matches(matches, network)?;
let filled_with = get_filled_with_from_matches(matches, network, oracle_pk)?;

let message = match order.order_reason {
OrderReason::Manual => Message::Match(filled_with),
Expand All @@ -85,7 +86,11 @@ async fn process_pending_match(
Ok(())
}

fn get_filled_with_from_matches(matches: Vec<Matches>, network: Network) -> Result<FilledWith> {
fn get_filled_with_from_matches(
matches: Vec<Matches>,
network: Network,
oracle_pk: XOnlyPublicKey,
) -> Result<FilledWith> {
ensure!(
!matches.is_empty(),
"Need at least one matches record to construct a FilledWith"
Expand All @@ -95,10 +100,6 @@ fn get_filled_with_from_matches(matches: Vec<Matches>, network: Network) -> Resu
.first()
.expect("to have at least one match")
.order_id;
let oracle_pk = XOnlyPublicKey::from_str(
"16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0",
)
.expect("To be a valid pubkey");

let expiry_timestamp =
coordinator_commons::calculate_next_expiry(OffsetDateTime::now_utc(), network);
Expand Down
85 changes: 53 additions & 32 deletions coordinator/src/orderbook/trading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use orderbook_commons::OrderState;
use orderbook_commons::OrderType;
use rust_decimal::Decimal;
use std::cmp::Ordering;
use std::str::FromStr;
use thiserror::Error;
use time::OffsetDateTime;
use tokio::sync::broadcast;
Expand Down Expand Up @@ -88,6 +87,7 @@ pub fn start(
tx_price_feed: broadcast::Sender<Message>,
notifier: mpsc::Sender<OrderbookMessage>,
network: Network,
oracle_pk: XOnlyPublicKey,
) -> (RemoteHandle<Result<()>>, mpsc::Sender<NewOrderMessage>) {
let (sender, mut receiver) = mpsc::channel::<NewOrderMessage>(NEW_ORDERS_BUFFER_SIZE);

Expand All @@ -106,6 +106,7 @@ pub fn start(
new_order,
new_order_msg.order_reason,
network,
oracle_pk,
)
.await;
if let Err(e) = new_order_msg.sender.send(result).await {
Expand Down Expand Up @@ -138,6 +139,7 @@ async fn process_new_order(
new_order: NewOrder,
order_reason: OrderReason,
network: Network,
oracle_pk: XOnlyPublicKey,
) -> Result<Order> {
tracing::info!(trader_id=%new_order.trader_id, "Received a new {:?} order", new_order.order_type);

Expand Down Expand Up @@ -183,26 +185,27 @@ async fn process_new_order(
true,
)?;

let matched_orders = match match_order(&order, opposite_direction_orders, network) {
Ok(Some(matched_orders)) => matched_orders,
Ok(None) => {
// TODO(holzeis): Currently we still respond to the user immediately if there
// has been a match or not, that's the reason why we also
// have to set the order to failed here. But actually we
// could keep the order until either expired or a
// match has been found and then update the state correspondingly.

orders::set_order_state(conn, order.id, OrderState::Failed)?;
bail!(TradingError::NoMatchFound(format!(
"Could not match order {}",
order.id
)));
}
Err(e) => {
orders::set_order_state(conn, order.id, OrderState::Failed)?;
bail!("Failed to match order. Error {e:#}")
}
};
let matched_orders =
match match_order(&order, opposite_direction_orders, network, oracle_pk) {
Ok(Some(matched_orders)) => matched_orders,
Ok(None) => {
// TODO(holzeis): Currently we still respond to the user immediately if there
// has been a match or not, that's the reason why we also
// have to set the order to failed here. But actually we
// could keep the order until either expired or a
// match has been found and then update the state correspondingly.

orders::set_order_state(conn, order.id, OrderState::Failed)?;
bail!(TradingError::NoMatchFound(format!(
"Could not match order {}",
order.id
)));
}
Err(e) => {
orders::set_order_state(conn, order.id, OrderState::Failed)?;
bail!("Failed to match order. Error {e:#}")
}
};

tracing::info!(trader_id=%order.trader_id, order_id=%order.id, "Found a match with {} makers for new order.", matched_orders.taker_match.filled_with.matches.len());

Expand Down Expand Up @@ -277,6 +280,7 @@ fn match_order(
order: &Order,
opposite_direction_orders: Vec<Order>,
network: Network,
oracle_pk: XOnlyPublicKey,
) -> Result<Option<MatchParams>> {
if order.order_type == OrderType::Limit {
// we don't match limit and limit at the moment
Expand Down Expand Up @@ -315,12 +319,6 @@ fn match_order(
let expiry_timestamp =
coordinator_commons::calculate_next_expiry(OffsetDateTime::now_utc(), network);

// For now we hardcode the oracle pubkey here
let oracle_pk = XOnlyPublicKey::from_str(
"16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0",
)
.expect("To be a valid pubkey");

let matches = matched_orders
.iter()
.map(|maker_order| {
Expand Down Expand Up @@ -404,6 +402,7 @@ pub mod tests {
use crate::orderbook::trading::sort_orders;
use bitcoin::secp256k1::PublicKey;
use bitcoin::Network;
use bitcoin::XOnlyPublicKey;
use orderbook_commons::Order;
use orderbook_commons::OrderReason;
use orderbook_commons::OrderState;
Expand Down Expand Up @@ -583,9 +582,14 @@ pub mod tests {
stable: false,
};

let matched_orders = match_order(&order, all_orders, Network::Bitcoin)
.unwrap()
.unwrap();
let matched_orders = match_order(
&order,
all_orders,
Network::Bitcoin,
get_oracle_public_key(),
)
.unwrap()
.unwrap();

assert_eq!(matched_orders.makers_matches.len(), 1);
let maker_matches = matched_orders
Expand Down Expand Up @@ -660,7 +664,13 @@ pub mod tests {
stable: false,
};

assert!(match_order(&order, all_orders, Network::Bitcoin).is_err());
assert!(match_order(
&order,
all_orders,
Network::Bitcoin,
get_oracle_public_key()
)
.is_err());
}

#[test]
Expand Down Expand Up @@ -711,8 +721,19 @@ pub mod tests {
stable: false,
};

let matched_orders = match_order(&order, all_orders, Network::Bitcoin).unwrap();
let matched_orders = match_order(
&order,
all_orders,
Network::Bitcoin,
get_oracle_public_key(),
)
.unwrap();

assert!(matched_orders.is_none());
}

fn get_oracle_public_key() -> XOnlyPublicKey {
XOnlyPublicKey::from_str("16f88cf7d21e6c0f46bcbc983a4e3b19726c6c98858cc31c83551a88fde171c0")
.unwrap()
}
}
Loading

0 comments on commit d955e9f

Please sign in to comment.