Skip to content

Commit

Permalink
chore: add vbyte / fee to utxos (#397)
Browse files Browse the repository at this point in the history
* chore: add vbyte / fee to utxos

* chore: add origin_tx_trusted_input_tx_ids to utxos
  • Loading branch information
bodymindarts authored Nov 18, 2023
1 parent 910c533 commit 6fcbdbf
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 27 deletions.

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

1 change: 1 addition & 0 deletions migrations/20231117120618_add-fee-weight-to-utxos.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- Add down migration script here
4 changes: 4 additions & 0 deletions migrations/20231117120618_add-fee-weight-to-utxos.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE bria_utxos
ADD COLUMN origin_tx_vbytes INTEGER,
ADD COLUMN origin_tx_fee INTEGER,
ADD COLUMN trusted_origin_tx_input_tx_ids VARCHAR[];
9 changes: 4 additions & 5 deletions src/bdk/pg/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{bdk::error::BdkError, primitives::*};
pub struct UnsyncedTransaction {
pub tx_id: bitcoin::Txid,
pub confirmation_time: Option<bitcoin::BlockTime>,
pub sats_per_vbyte_when_created: f32,
pub vsize: u64,
pub total_utxo_in_sats: Satoshis,
pub fee_sats: Satoshis,
pub inputs: Vec<(LocalUtxo, u32)>,
Expand Down Expand Up @@ -148,7 +148,7 @@ impl Transactions {
let mut outputs = Vec::new();
let mut tx_id = None;
let mut confirmation_time = None;
let mut sats_per_vbyte_when_created = 0.0;
let mut vsize = 0;

let mut total_utxo_in_sats = Satoshis::ZERO;
let mut fee_sats = Satoshis::ZERO;
Expand All @@ -165,8 +165,7 @@ impl Transactions {
let details: TransactionDetails = serde_json::from_value(row.details_json)?;
total_utxo_in_sats = Satoshis::from(details.sent);
fee_sats = Satoshis::from(details.fee.expect("Fee"));
sats_per_vbyte_when_created = details.fee.expect("Fee") as f32
/ details.transaction.expect("transaction").vsize() as f32;
vsize = details.transaction.expect("transaction").vsize() as u64;
confirmation_time = details.confirmation_time;
}
}
Expand All @@ -175,7 +174,7 @@ impl Transactions {
total_utxo_in_sats,
fee_sats,
confirmation_time,
sats_per_vbyte_when_created,
vsize,
inputs,
outputs,
}))
Expand Down
6 changes: 4 additions & 2 deletions src/job/sync_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ pub async fn execute(
keychain_id,
&address_info,
&local_utxo,
unsynced_tx.sats_per_vbyte_when_created,
unsynced_tx.fee_sats,
unsynced_tx.vsize,
spend_tx,
)
.await?
Expand Down Expand Up @@ -298,7 +299,8 @@ pub async fn execute(
.iter()
.map(|WalletUtxo { outpoint, .. }| outpoint),
&change_utxos,
unsynced_tx.sats_per_vbyte_when_created,
unsynced_tx.fee_sats,
unsynced_tx.vsize,
)
.await?
{
Expand Down
14 changes: 9 additions & 5 deletions src/utxo/entity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::primitives::{bitcoin::*, *};
use derive_builder::Builder;

use crate::primitives::{bitcoin::*, *};

pub struct WalletUtxo {
pub wallet_id: WalletId,
pub keychain_id: KeychainId,
Expand Down Expand Up @@ -40,7 +41,7 @@ pub struct KeychainUtxos {
}

#[derive(Builder)]
pub struct NewUtxo {
pub struct NewUtxo<'a> {
pub(super) account_id: AccountId,
pub(super) wallet_id: WalletId,
pub(super) keychain_id: KeychainId,
Expand All @@ -51,14 +52,17 @@ pub struct NewUtxo {
pub(super) value: Satoshis,
pub(super) address: String,
pub(super) script_hex: String,
pub(super) sats_per_vbyte_when_created: f32,
pub(super) origin_tx_vbytes: u64,
pub(super) origin_tx_fee: Satoshis,
#[builder(default)]
pub(super) origin_tx_trusted_input_tx_ids: Option<&'a [String]>,
pub(super) self_pay: bool,
pub(super) bdk_spent: bool,
pub(super) utxo_detected_ledger_tx_id: LedgerTransactionId,
}

impl NewUtxo {
pub fn builder() -> NewUtxoBuilder {
impl<'a> NewUtxo<'a> {
pub fn builder() -> NewUtxoBuilder<'a> {
let mut builder = NewUtxoBuilder::default();
builder.utxo_detected_ledger_tx_id(LedgerTransactionId::new());
builder
Expand Down
27 changes: 20 additions & 7 deletions src/utxo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ impl Utxos {
keychain_id: KeychainId,
address: &AddressInfo,
utxo: &LocalUtxo,
sats_per_vbyte_when_created: f32,
origin_tx_fee: Satoshis,
origin_tx_vbytes: u64,
self_pay: bool,
) -> Result<Option<(LedgerTransactionId, Transaction<'_, Postgres>)>, UtxoError> {
let new_utxo = NewUtxo::builder()
Expand All @@ -51,7 +52,8 @@ impl Utxos {
.script_hex(format!("{:x}", utxo.txout.script_pubkey))
.value(utxo.txout.value)
.bdk_spent(utxo.is_spent)
.sats_per_vbyte_when_created(sats_per_vbyte_when_created)
.origin_tx_fee(origin_tx_fee)
.origin_tx_vbytes(origin_tx_vbytes)
.self_pay(self_pay)
.build()
.expect("Could not build NewUtxo");
Expand All @@ -74,7 +76,7 @@ impl Utxos {
.await
}

#[instrument(name = "utxos.spend_detected", skip(self, inputs), err)]
#[instrument(name = "utxos.spend_detected", skip(self, inputs_iter), err)]
#[allow(clippy::type_complexity)]
#[allow(clippy::too_many_arguments)]
pub async fn spend_detected(
Expand All @@ -84,10 +86,19 @@ impl Utxos {
wallet_id: WalletId,
keychain_id: KeychainId,
tx_id: LedgerTransactionId,
inputs: impl Iterator<Item = &OutPoint>,
inputs_iter: impl Iterator<Item = &OutPoint>,
change_utxos: &Vec<(&LocalUtxo, AddressInfo)>,
sats_per_vbyte: f32,
tx_fee: Satoshis,
tx_vbytes: u64,
) -> Result<Option<(Satoshis, HashMap<bitcoin::OutPoint, Satoshis>)>, UtxoError> {
let mut inputs = Vec::new();
let mut input_tx_ids = Vec::new();

for input in inputs_iter {
input_tx_ids.push(input.txid.to_string());
inputs.push(input);
}

for (utxo, address) in change_utxos.iter() {
let new_utxo = NewUtxo::builder()
.account_id(account_id)
Expand All @@ -101,8 +112,10 @@ impl Utxos {
.script_hex(format!("{:x}", utxo.txout.script_pubkey))
.value(utxo.txout.value)
.bdk_spent(utxo.is_spent)
.sats_per_vbyte_when_created(sats_per_vbyte)
.origin_tx_vbytes(tx_vbytes)
.origin_tx_fee(tx_fee)
.self_pay(true)
.origin_tx_trusted_input_tx_ids(Some(&input_tx_ids))
.build()
.expect("Could not build NewUtxo");
let res = self.utxos.persist_utxo(tx, new_utxo).await?;
Expand All @@ -112,7 +125,7 @@ impl Utxos {
}
let utxos = self
.utxos
.mark_spent(tx, keychain_id, inputs, tx_id)
.mark_spent(tx, keychain_id, inputs.into_iter(), tx_id)
.await?;
if utxos.is_empty() {
return Ok(None);
Expand Down
14 changes: 9 additions & 5 deletions src/utxo/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,23 @@ impl UtxoRepo {
Self { pool }
}

pub async fn persist_utxo(
pub async fn persist_utxo<'a>(
&self,
tx: &mut Transaction<'_, Postgres>,
utxo: NewUtxo,
utxo: NewUtxo<'a>,
) -> Result<Option<LedgerTransactionId>, UtxoError> {
let sats_per_vbyte = u64::from(utxo.origin_tx_fee) as f32 / utxo.origin_tx_vbytes as f32;
let result = sqlx::query!(
r#"INSERT INTO bria_utxos
(account_id, wallet_id, keychain_id, tx_id, vout, sats_per_vbyte_when_created, self_pay, kind, address_idx, value, address, script_hex, income_detected_ledger_tx_id, bdk_spent)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
(account_id, wallet_id, keychain_id, tx_id, vout, sats_per_vbyte_when_created, self_pay, kind, address_idx, value, address, script_hex, income_detected_ledger_tx_id, bdk_spent, origin_tx_vbytes, origin_tx_fee, trusted_origin_tx_input_tx_ids)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
ON CONFLICT (keychain_id, tx_id, vout) DO NOTHING"#,
utxo.account_id as AccountId,
utxo.wallet_id as WalletId,
utxo.keychain_id as KeychainId,
utxo.outpoint.txid.to_string(),
utxo.outpoint.vout as i32,
utxo.sats_per_vbyte_when_created,
sats_per_vbyte,
utxo.self_pay,
pg::PgKeychainKind::from(utxo.kind) as pg::PgKeychainKind,
utxo.address_idx as i32,
Expand All @@ -48,6 +49,9 @@ impl UtxoRepo {
utxo.script_hex,
utxo.utxo_detected_ledger_tx_id as LedgerTransactionId,
utxo.bdk_spent,
utxo.origin_tx_vbytes as i64,
u64::from(utxo.origin_tx_fee) as i64,
utxo.origin_tx_trusted_input_tx_ids,
)
.execute(&mut **tx)
.await?;
Expand Down

0 comments on commit 6fcbdbf

Please sign in to comment.