Skip to content

Commit

Permalink
Merge pull request #2084 from get10101/chore/record-contract-transact…
Browse files Browse the repository at this point in the history
…ions

fix: Create trade after finished dlc protocol
  • Loading branch information
holzeis authored Feb 28, 2024
2 parents da7d8e2 + 3c58a99 commit 7933a96
Show file tree
Hide file tree
Showing 24 changed files with 1,010 additions and 240 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ resolver = "2"
# We are using our own fork of `rust-dlc` at least until we can drop all the LN-DLC features. Also,
# `p2pderivatives/rust-dlc#master` is missing certain patches that can only be found in the LN-DLC
# branch.
dlc-manager = { git = "https://github.com/get10101/rust-dlc", rev = "0191dc4" }
dlc-messages = { git = "https://github.com/get10101/rust-dlc", rev = "0191dc4" }
dlc = { git = "https://github.com/get10101/rust-dlc", rev = "0191dc4" }
p2pd-oracle-client = { git = "https://github.com/get10101/rust-dlc", rev = "0191dc4" }
dlc-trie = { git = "https://github.com/get10101/rust-dlc", rev = "0191dc4" }
dlc-manager = { git = "https://github.com/get10101/rust-dlc", rev = "aa487662a8af75174bf0e60f24e07e171820d0c3" }
dlc-messages = { git = "https://github.com/get10101/rust-dlc", rev = "aa487662a8af75174bf0e60f24e07e171820d0c3" }
dlc = { git = "https://github.com/get10101/rust-dlc", rev = "aa487662a8af75174bf0e60f24e07e171820d0c3" }
p2pd-oracle-client = { git = "https://github.com/get10101/rust-dlc", rev = "aa487662a8af75174bf0e60f24e07e171820d0c3" }
dlc-trie = { git = "https://github.com/get10101/rust-dlc", rev = "aa487662a8af75174bf0e60f24e07e171820d0c3" }

# We should usually track the `p2pderivatives/split-tx-experiment[-10101]` branch. For now we depend
# on a special fork which removes a panic in `rust-lightning`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
-- Your SQL goes here
ALTER TYPE "OrderState_Type" ADD VALUE 'Expired';
ALTER TYPE "OrderState_Type" ADD VALUE IF NOT EXISTS 'Expired';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DROP TABLE if exists trade_params;
DROP TABLE if exists dlc_protocols;

DROP TYPE IF EXISTS "Protocol_State_Type";
25 changes: 25 additions & 0 deletions coordinator/migrations/2024-02-27-113100_add_dlc_protocols/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

CREATE TYPE "Protocol_State_Type" AS ENUM ('Pending', 'Success', 'Failed');

CREATE TABLE "dlc_protocols"
(
id SERIAL PRIMARY KEY NOT NULL,
protocol_id UUID UNIQUE NOT NULL,
previous_protocol_id UUID REFERENCES dlc_protocols (protocol_id),
channel_id TEXT NOT NULL,
contract_id TEXT NOT NULL,
protocol_state "Protocol_State_Type" NOT NULL,
trader_pubkey TEXT NOT NULL REFERENCES users (pubkey),
timestamp timestamp WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE "trade_params"
(
id SERIAL PRIMARY KEY NOT NULL,
protocol_id UUID NOT NULL REFERENCES dlc_protocols(protocol_id),
trader_pubkey TEXT NOT NULL,
quantity REAL NOT NULL,
leverage REAL NOT NULL,
average_price REAL NOT NULL,
direction "Direction_Type" NOT NULL
);
1 change: 1 addition & 0 deletions coordinator/src/collaborative_revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ pub fn confirm_collaborative_revert(
counter_party: signed_channel.counter_party,
temporary_channel_id: signed_channel.temporary_channel_id,
channel_id: signed_channel.channel_id,
reference_id: None,
}),
// The contract doesn't matter anymore.
None,
Expand Down
24 changes: 24 additions & 0 deletions coordinator/src/db/custom_types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::db::channels::ChannelState;
use crate::db::dlc_messages::MessageType;
use crate::db::dlc_protocols::DlcProtocolState;
use crate::db::payments::HtlcStatus;
use crate::db::payments::PaymentFlow;
use crate::db::polls::PollType;
Expand All @@ -13,6 +14,7 @@ use crate::schema::sql_types::MessageTypeType;
use crate::schema::sql_types::PaymentFlowType;
use crate::schema::sql_types::PollTypeType;
use crate::schema::sql_types::PositionStateType;
use crate::schema::sql_types::ProtocolStateType;
use diesel::deserialize;
use diesel::deserialize::FromSql;
use diesel::pg::Pg;
Expand Down Expand Up @@ -225,3 +227,25 @@ impl FromSql<PollTypeType, Pg> for PollType {
}
}
}

impl ToSql<ProtocolStateType, Pg> for DlcProtocolState {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
match *self {
DlcProtocolState::Pending => out.write_all(b"Pending")?,
DlcProtocolState::Success => out.write_all(b"Success")?,
DlcProtocolState::Failed => out.write_all(b"Failed")?,
}
Ok(IsNull::No)
}
}

impl FromSql<ProtocolStateType, Pg> for DlcProtocolState {
fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
match bytes.as_bytes() {
b"Pending" => Ok(DlcProtocolState::Pending),
b"Success" => Ok(DlcProtocolState::Success),
b"Failed" => Ok(DlcProtocolState::Failed),
_ => Err("Unrecognized enum variant for ContractTransactionType".into()),
}
}
}
162 changes: 162 additions & 0 deletions coordinator/src/db/dlc_protocols.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use crate::dlc_protocol;
use crate::dlc_protocol::ProtocolId;
use crate::schema::dlc_protocols;
use crate::schema::sql_types::ProtocolStateType;
use bitcoin::hashes::hex::FromHex;
use bitcoin::hashes::hex::ToHex;
use bitcoin::secp256k1::PublicKey;
use diesel::query_builder::QueryId;
use diesel::AsExpression;
use diesel::ExpressionMethods;
use diesel::FromSqlRow;
use diesel::PgConnection;
use diesel::QueryDsl;
use diesel::QueryResult;
use diesel::Queryable;
use diesel::RunQueryDsl;
use dlc_manager::ContractId;
use dlc_manager::DlcChannelId;
use std::any::TypeId;
use std::str::FromStr;
use time::OffsetDateTime;
use uuid::Uuid;

#[derive(Debug, Clone, Copy, PartialEq, FromSqlRow, AsExpression, Eq, Hash)]
#[diesel(sql_type = ProtocolStateType)]
pub(crate) enum DlcProtocolState {
Pending,
Success,
Failed,
}

impl QueryId for ProtocolStateType {
type QueryId = ProtocolStateType;
const HAS_STATIC_QUERY_ID: bool = false;

fn query_id() -> Option<TypeId> {
None
}
}

#[derive(Queryable, Debug)]
#[diesel(table_name = protocols)]
#[allow(dead_code)] // We have to allow dead code here because diesel needs the fields to be able to derive queryable.
pub(crate) struct DlcProtocol {
pub id: i32,
pub protocol_id: Uuid,
pub previous_protocol_id: Option<Uuid>,
pub channel_id: String,
pub contract_id: String,
pub protocol_state: DlcProtocolState,
pub trader_pubkey: String,
pub timestamp: OffsetDateTime,
}

pub(crate) fn get_dlc_protocol(
conn: &mut PgConnection,
protocol_id: ProtocolId,
) -> QueryResult<dlc_protocol::DlcProtocol> {
let contract_transaction: DlcProtocol = dlc_protocols::table
.filter(dlc_protocols::protocol_id.eq(protocol_id.to_uuid()))
.first(conn)?;

Ok(dlc_protocol::DlcProtocol::from(contract_transaction))
}

pub(crate) fn set_dlc_protocol_state_to_failed(
conn: &mut PgConnection,
protocol_id: ProtocolId,
) -> QueryResult<()> {
let affected_rows = diesel::update(dlc_protocols::table)
.filter(dlc_protocols::protocol_id.eq(protocol_id.to_uuid()))
.set((dlc_protocols::protocol_state.eq(DlcProtocolState::Failed),))
.execute(conn)?;

if affected_rows == 0 {
return Err(diesel::result::Error::NotFound);
}

Ok(())
}

pub(crate) fn set_dlc_protocol_state_to_success(
conn: &mut PgConnection,
protocol_id: ProtocolId,
contract_id: ContractId,
channel_id: DlcChannelId,
) -> QueryResult<()> {
let affected_rows = diesel::update(dlc_protocols::table)
.filter(dlc_protocols::protocol_id.eq(protocol_id.to_uuid()))
.set((
dlc_protocols::protocol_state.eq(DlcProtocolState::Success),
dlc_protocols::contract_id.eq(contract_id.to_hex()),
dlc_protocols::channel_id.eq(channel_id.to_hex()),
))
.execute(conn)?;

if affected_rows == 0 {
return Err(diesel::result::Error::NotFound);
}

Ok(())
}

pub(crate) fn create(
conn: &mut PgConnection,
protocol_id: ProtocolId,
previous_protocol_id: Option<ProtocolId>,
contract_id: ContractId,
channel_id: DlcChannelId,
trader: &PublicKey,
) -> QueryResult<()> {
let affected_rows = diesel::insert_into(dlc_protocols::table)
.values(&(
dlc_protocols::protocol_id.eq(protocol_id.to_uuid()),
dlc_protocols::previous_protocol_id.eq(previous_protocol_id.map(|ppid| ppid.to_uuid())),
dlc_protocols::contract_id.eq(contract_id.to_hex()),
dlc_protocols::channel_id.eq(channel_id.to_hex()),
dlc_protocols::protocol_state.eq(DlcProtocolState::Pending),
dlc_protocols::trader_pubkey.eq(trader.to_string()),
dlc_protocols::timestamp.eq(OffsetDateTime::now_utc()),
))
.execute(conn)?;

if affected_rows == 0 {
return Err(diesel::result::Error::NotFound);
}

Ok(())
}

impl From<DlcProtocol> for dlc_protocol::DlcProtocol {
fn from(value: DlcProtocol) -> Self {
dlc_protocol::DlcProtocol {
id: value.protocol_id.into(),
timestamp: value.timestamp,
channel_id: DlcChannelId::from_hex(&value.channel_id).expect("valid dlc channel id"),
contract_id: ContractId::from_hex(&value.contract_id).expect("valid contract id"),
trader: PublicKey::from_str(&value.trader_pubkey).expect("valid public key"),
protocol_state: value.protocol_state.into(),
}
}
}

impl From<dlc_protocol::DlcProtocolState> for DlcProtocolState {
fn from(value: dlc_protocol::DlcProtocolState) -> Self {
match value {
dlc_protocol::DlcProtocolState::Pending => DlcProtocolState::Pending,
dlc_protocol::DlcProtocolState::Success => DlcProtocolState::Success,
dlc_protocol::DlcProtocolState::Failed => DlcProtocolState::Failed,
}
}
}

impl From<DlcProtocolState> for dlc_protocol::DlcProtocolState {
fn from(value: DlcProtocolState) -> Self {
match value {
DlcProtocolState::Pending => dlc_protocol::DlcProtocolState::Pending,
DlcProtocolState::Success => dlc_protocol::DlcProtocolState::Success,
DlcProtocolState::Failed => dlc_protocol::DlcProtocolState::Failed,
}
}
}
2 changes: 2 additions & 0 deletions coordinator/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod channels;
pub mod collaborative_reverts;
pub mod custom_types;
pub mod dlc_messages;
pub mod dlc_protocols;
pub mod last_outbound_dlc_message;
pub mod legacy_collaborative_reverts;
pub mod liquidity;
Expand All @@ -12,6 +13,7 @@ pub mod positions;
pub mod positions_helper;
pub mod routing_fees;
pub mod spendable_outputs;
pub mod trade_params;
pub mod trades;
pub mod transactions;
pub mod user;
24 changes: 8 additions & 16 deletions coordinator/src/db/positions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ impl Position {
conn: &mut PgConnection,
trader_pubkey: String,
state: crate::position::models::PositionState,
) -> Result<()> {
) -> QueryResult<crate::position::models::Position> {
let state = PositionState::from(state);
let affected_rows = diesel::update(positions::table)
let position: Position = diesel::update(positions::table)
.filter(positions::trader_pubkey.eq(trader_pubkey.clone()))
.filter(
positions::position_state
Expand All @@ -150,13 +150,9 @@ impl Position {
positions::position_state.eq(state),
positions::update_timestamp.eq(OffsetDateTime::now_utc()),
))
.execute(conn)?;

if affected_rows == 0 {
bail!("Could not update position to {state:?} for {trader_pubkey}")
}
.get_result(conn)?;

Ok(())
Ok(crate::position::models::Position::from(position))
}

/// sets the status of the position in state `Closing` to a new state
Expand Down Expand Up @@ -272,21 +268,17 @@ impl Position {
conn: &mut PgConnection,
id: i32,
pnl: i64,
) -> Result<()> {
let affected_rows = diesel::update(positions::table)
) -> QueryResult<crate::position::models::Position> {
let position: Position = diesel::update(positions::table)
.filter(positions::id.eq(id))
.set((
positions::position_state.eq(PositionState::Closed),
positions::trader_realized_pnl_sat.eq(Some(pnl)),
positions::update_timestamp.eq(OffsetDateTime::now_utc()),
))
.execute(conn)?;

if affected_rows == 0 {
bail!("Could not update position to Closed with realized pnl {pnl} for position {id}")
}
.get_result(conn)?;

Ok(())
Ok(crate::position::models::Position::from(position))
}

pub fn set_position_to_closed(conn: &mut PgConnection, id: i32) -> Result<()> {
Expand Down
Loading

0 comments on commit 7933a96

Please sign in to comment.