Skip to content

Commit

Permalink
draft: add effective_value method
Browse files Browse the repository at this point in the history
  • Loading branch information
yancy committed Dec 2, 2023
1 parent 56c0d6c commit 4822b07
Showing 1 changed file with 48 additions and 3 deletions.
51 changes: 48 additions & 3 deletions bitcoin/src/blockdata/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::blockdata::locktime::absolute::{self, Height, Time};
use crate::blockdata::locktime::relative;
use crate::blockdata::script::{Script, ScriptBuf};
use crate::blockdata::witness::Witness;
use crate::blockdata::FeeRate;
use crate::consensus::{encode, Decodable, Encodable};
use crate::hash_types::{Txid, Wtxid};
use crate::internal_macros::impl_consensus_encoding;
Expand All @@ -31,7 +32,7 @@ use crate::script::Push;
#[cfg(doc)]
use crate::sighash::{EcdsaSighashType, TapSighashType};
use crate::string::FromHexStr;
use crate::{io, Amount, VarInt};
use crate::{io, Amount, SignedAmount, VarInt};

#[rustfmt::skip] // Keep public re-exports separate.
#[cfg(feature = "bitcoinconsensus")]
Expand Down Expand Up @@ -214,8 +215,6 @@ impl TxIn {
/// Returns the input base weight.
///
/// Base weight excludes the witness and script.
// to be used in up-coming commit to add effective_value()
#[allow(dead_code)]
const BASE_WEIGHT: Weight =
Weight::from_vb_unwrap(OutPoint::SIZE as u64 + Sequence::SIZE as u64);

Expand Down Expand Up @@ -534,6 +533,35 @@ impl TxOut {
Weight::from_vb(self.size() as u64).expect("should never happen under normal conditions")
}

/// Returns the effective_value `Amount` returning `None` on overflow.
///
/// The effective value is the value of this output minus the amount to spend it. That is,
/// the effective_value can be calculated as value - (fee_rate * weight).
///
/// # Arguments
///
/// * `fee_rate` - `FeeRate`in sat/kwu
/// * `satisfaction_weight` - output weight once the spending conditions are satisfied
pub fn effective_value(
&self,
fee_rate: FeeRate,
satisfaction_weight: Weight,
) -> Option<SignedAmount> {
println!("base weight: {}", TxIn::BASE_WEIGHT);
println!("fee_rate: {}", fee_rate);
let weight = satisfaction_weight.checked_add(TxIn::BASE_WEIGHT)?;
println!("weight {}", weight);
let input_fee = fee_rate.checked_mul_by_weight(weight)?;
println!("input fee: {}", input_fee);

// Note, this method could return Result instead of Option instead of
// discarding the error type here.
let signed_input_fee = input_fee.to_signed().ok()?;
let signed_value = self.value.to_signed().ok()?;

signed_value.checked_sub(signed_input_fee)
}

/// Returns the total number of bytes that this output contributes to a transaction.
///
/// There is no difference between base size vs total size for outputs.
Expand Down Expand Up @@ -1968,6 +1996,23 @@ mod tests {
assert!(result.is_err());
}

#[test]
fn txout_effective_weight() {
let tx_out = TxOut {
value: Amount::from_str("1 cBTC").unwrap(),
script_pubkey: ScriptBuf::default()
};

let fee_rate = FeeRate::from_sat_per_kwu(10);
let satisfaction_weight = Weight::from_wu(204);
let effective_value = tx_out.effective_value(fee_rate, satisfaction_weight).unwrap();

// 10 sat/kwu * 204wu + BASE_WEIGHT = 4 sats
let expected_fee = SignedAmount::from_str("4 sats").unwrap();
let expected_effective_value = tx_out.value.to_signed().unwrap() - expected_fee;
assert_eq!(effective_value, expected_effective_value);
}

#[test]
fn txin_txout_weight() {
// [(is_segwit, tx_hex, expected_weight)]
Expand Down

0 comments on commit 4822b07

Please sign in to comment.