name: Test ${{ matrix.blockchain.name }}
runs-on: ubuntu-16.04
strategy:
+ fail-fast: false
matrix:
blockchain:
- name: electrum
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
use crate::error::Error;
use crate::types::{KeychainKind, LocalUtxo, TransactionDetails};
-use crate::FeeRate;
+use crate::{ConfirmationTime, FeeRate};
use peer::*;
use store::*;
database: &mut D,
tx: &Transaction,
height: Option<u32>,
- timestamp: u64,
+ timestamp: Option<u64>,
internal_max_deriv: &mut Option<u32>,
external_max_deriv: &mut Option<u32>,
) -> Result<(), Error> {
transaction: Some(tx.clone()),
received: incoming,
sent: outgoing,
- height,
- timestamp,
- fees: inputs_sum.saturating_sub(outputs_sum),
+ confirmation_time: ConfirmationTime::new(height, timestamp),
+ fee: Some(inputs_sum.saturating_sub(outputs_sum)),
};
info!("Saving tx {}", tx.txid);
);
let mut updates = database.begin_batch();
for details in database.iter_txs(false)? {
- match details.height {
- Some(height) if (height as usize) < last_synced_block => continue,
+ match details.confirmation_time {
+ Some(c) if (c.height as usize) < last_synced_block => continue,
_ => updates.del_tx(&details.txid, false)?,
};
}
database,
tx,
Some(height as u32),
- 0,
+ None,
&mut internal_max_deriv,
&mut external_max_deriv,
)?;
database,
tx,
None,
- 0,
+ None,
&mut internal_max_deriv,
&mut external_max_deriv,
)?;
use crate::database::{BatchDatabase, DatabaseUtils};
use crate::descriptor::{get_checksum, IntoWalletDescriptor};
use crate::wallet::utils::SecpCtx;
-use crate::{Error, FeeRate, KeychainKind, LocalUtxo, TransactionDetails};
+use crate::{ConfirmationTime, Error, FeeRate, KeychainKind, LocalUtxo, TransactionDetails};
use bitcoincore_rpc::json::{
GetAddressInfoResultLabel, ImportMultiOptions, ImportMultiRequest,
ImportMultiRequestScriptPubkey, ImportMultiRescanSince,
let txid = tx_result.info.txid;
list_txs_ids.insert(txid);
if let Some(mut known_tx) = known_txs.get_mut(&txid) {
- if tx_result.info.blockheight != known_tx.height {
+ let confirmation_time =
+ ConfirmationTime::new(tx_result.info.blockheight, tx_result.info.blocktime);
+ if confirmation_time != known_tx.confirmation_time {
// reorg may change tx height
debug!(
- "updating tx({}) height to: {:?}",
- txid, tx_result.info.blockheight
+ "updating tx({}) confirmation time to: {:?}",
+ txid, confirmation_time
);
- known_tx.height = tx_result.info.blockheight;
+ known_tx.confirmation_time = confirmation_time;
db.set_tx(&known_tx)?;
}
} else {
let td = TransactionDetails {
transaction: Some(tx),
txid: tx_result.info.txid,
- timestamp: tx_result.info.time,
+ confirmation_time: ConfirmationTime::new(
+ tx_result.info.blockheight,
+ tx_result.info.blocktime,
+ ),
received,
sent,
- //TODO it could happen according to the node situation/configuration that the
- // fee is not known [TransactionDetails:fee] should be made [Option]
- fees: tx_result.fee.map(|f| f.as_sat().abs() as u64).unwrap_or(0),
- height: tx_result.info.blockheight,
+ fee: tx_result.fee.map(|f| f.as_sat().abs() as u64),
};
debug!(
"saving tx: {} tx_result.fee:{:?} td.fees:{:?}",
- td.txid, tx_result.fee, td.fees
+ td.txid, tx_result.fee, td.fee
);
db.set_tx(&td)?;
}
wallet.sync(noop_progress(), None).unwrap();
assert_eq!(
wallet.get_balance().unwrap(),
- 100_000 - 50_000 - details.fees
+ 100_000 - 50_000 - details.fee.unwrap_or(0)
);
drop(wallet);
use super::*;
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
use crate::error::Error;
-use crate::types::{KeychainKind, LocalUtxo, TransactionDetails};
+use crate::types::{ConfirmationTime, KeychainKind, LocalUtxo, TransactionDetails};
use crate::wallet::time::Instant;
use crate::wallet::utils::ChunksIterator;
// save any tx details not in db but in history_txs_id or with different height/timestamp
for txid in history_txs_id.iter() {
let height = txid_height.get(txid).cloned().flatten();
- let timestamp = *new_timestamps.get(txid).unwrap_or(&0u64);
+ let timestamp = new_timestamps.get(txid).cloned();
if let Some(tx_details) = txs_details_in_db.get(txid) {
- // check if height matches, otherwise updates it
- if tx_details.height != height {
+ // check if tx height matches, otherwise updates it. timestamp is not in the if clause
+ // because we are not asking headers for confirmed tx we know about
+ if tx_details.confirmation_time.as_ref().map(|c| c.height) != height {
+ let confirmation_time = ConfirmationTime::new(height, timestamp);
let mut new_tx_details = tx_details.clone();
- new_tx_details.height = height;
- new_tx_details.timestamp = timestamp;
+ new_tx_details.confirmation_time = confirmation_time;
batch.set_tx(&new_tx_details)?;
}
} else {
chunk_size: usize,
) -> Result<HashMap<Txid, u64>, Error> {
let mut txid_timestamp = HashMap::new();
+ let txid_in_db_with_conf: HashSet<_> = txs_details_in_db
+ .values()
+ .filter_map(|details| details.confirmation_time.as_ref().map(|_| details.txid))
+ .collect();
let needed_txid_height: HashMap<&Txid, u32> = txid_height
.iter()
- .filter(|(t, _)| txs_details_in_db.get(*t).is_none())
+ .filter(|(t, _)| !txid_in_db_with_conf.contains(*t))
.filter_map(|(t, o)| o.map(|h| (t, h)))
.collect();
let needed_heights: HashSet<u32> = needed_txid_height.values().cloned().collect();
fn save_transaction_details_and_utxos<D: BatchDatabase>(
txid: &Txid,
db: &mut D,
- timestamp: u64,
+ timestamp: Option<u64>,
height: Option<u32>,
updates: &mut dyn BatchOperations,
utxo_deps: &HashMap<OutPoint, OutPoint>,
transaction: Some(tx),
received: incoming,
sent: outgoing,
- height,
- timestamp,
- fees: inputs_sum.saturating_sub(outputs_sum), /* if the tx is a coinbase, fees would be negative */
+ confirmation_time: ConfirmationTime::new(height, timestamp),
+ fee: Some(inputs_sum.saturating_sub(outputs_sum)), /* if the tx is a coinbase, fees would be negative */
};
updates.set_tx(&tx_details)?;
};
let txid = tx.txid();
- let height = tx_meta
- .min_confirmations
- .map(|conf| current_height.unwrap().checked_sub(conf as u32).unwrap());
+ let confirmation_time = tx_meta.min_confirmations.map(|conf| ConfirmationTime {
+ height: current_height.unwrap().checked_sub(conf as u32).unwrap(),
+ timestamp: 0,
+ });
let tx_details = TransactionDetails {
transaction: Some(tx.clone()),
txid,
- timestamp: 0,
- height,
+ fee: Some(0),
received: 0,
sent: 0,
- fees: 0,
+ confirmation_time,
};
db.set_tx(&tx_details).unwrap();
let mut tx_details = TransactionDetails {
transaction: Some(tx),
txid,
- timestamp: 123456,
received: 1337,
sent: 420420,
- fees: 140,
- height: Some(1000),
+ fee: Some(140),
+ confirmation_time: Some(ConfirmationTime {
+ timestamp: 123456,
+ height: 1000,
+ }),
};
tree.set_tx(&tx_details).unwrap();
assert_eq!(list_tx_item.txid, txid, "incorrect txid");
assert_eq!(list_tx_item.received, 50_000, "incorrect received");
assert_eq!(list_tx_item.sent, 0, "incorrect sent");
- assert_eq!(list_tx_item.height, None, "incorrect height");
+ assert_eq!(list_tx_item.confirmation_time, None, "incorrect confirmation time");
}
#[test]
assert_eq!(list_tx_item.txid, txid, "incorrect txid");
assert_eq!(list_tx_item.received, 105_000, "incorrect received");
assert_eq!(list_tx_item.sent, 0, "incorrect sent");
- assert_eq!(list_tx_item.height, None, "incorrect height");
+ assert_eq!(list_tx_item.confirmation_time, None, "incorrect confirmation_time");
}
#[test]
assert_eq!(list_tx_item.txid, txid, "incorrect txid");
assert_eq!(list_tx_item.received, 50_000, "incorrect received");
assert_eq!(list_tx_item.sent, 0, "incorrect sent");
- assert_eq!(list_tx_item.height, None, "incorrect height");
+ assert_eq!(list_tx_item.confirmation_time, None, "incorrect confirmation_time");
let new_txid = test_client.bump_fee(&txid);
assert_eq!(list_tx_item.txid, new_txid, "incorrect txid after bump");
assert_eq!(list_tx_item.received, 50_000, "incorrect received after bump");
assert_eq!(list_tx_item.sent, 0, "incorrect sent after bump");
- assert_eq!(list_tx_item.height, None, "incorrect height after bump");
+ assert_eq!(list_tx_item.confirmation_time, None, "incorrect height after bump");
}
// FIXME: I would like this to be cfg_attr(not(feature = "test-esplora"), ignore) but it
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
assert_eq!(list_tx_item.txid, txid, "incorrect txid");
- assert!(list_tx_item.height.is_some(), "incorrect height");
+ assert!(list_tx_item.confirmation_time.is_some(), "incorrect confirmation_time");
// Invalidate 1 block
test_client.invalidate(1);
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
assert_eq!(list_tx_item.txid, txid, "incorrect txid after invalidate");
- assert_eq!(list_tx_item.height, None, "incorrect height after invalidate");
+ assert_eq!(list_tx_item.confirmation_time, None, "incorrect confirmation time after invalidate");
}
#[test]
assert_eq!(wallet.list_unspent().unwrap().len(), 1, "incorrect number of unspents");
}
+ #[test]
+ #[serial]
+ fn test_update_confirmation_time_after_generate() {
+ let (wallet, descriptors, mut test_client) = init_single_sig();
+ println!("{}", descriptors.0);
+ let node_addr = test_client.get_node_address(None);
+
+ let received_txid = test_client.receive(testutils! {
+ @tx ( (@external descriptors, 0) => 50_000 )
+ });
+
+ wallet.sync(noop_progress(), None).unwrap();
+ assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
+
+ let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
+ let details = tx_map.get(&received_txid).unwrap();
+ assert!(details.confirmation_time.is_none());
+
+ test_client.generate(1, Some(node_addr));
+ wallet.sync(noop_progress(), None).unwrap();
+
+ let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
+ let details = tx_map.get(&received_txid).unwrap();
+ assert!(details.confirmation_time.is_some());
+
+ }
+
+
#[test]
#[serial]
fn test_sync_outgoing_from_scratch() {
let sent = tx_map.get(&sent_txid).unwrap();
assert_eq!(sent.received, details.received, "incorrect received from sender");
assert_eq!(sent.sent, details.sent, "incorrect sent from sender");
- assert_eq!(sent.fees, details.fees, "incorrect fees from sender");
+ assert_eq!(sent.fee.unwrap_or(0), details.fee.unwrap_or(0), "incorrect fees from sender");
}
#[test]
wallet.sync(noop_progress(), None).unwrap();
- total_sent += 5_000 + details.fees;
+ total_sent += 5_000 + details.fee.unwrap_or(0);
}
wallet.sync(noop_progress(), None).unwrap();
assert!(finalized, "Cannot finalize transaction");
wallet.broadcast(psbt.extract_tx()).unwrap();
wallet.sync(noop_progress(), None).unwrap();
- assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fees - 5_000, "incorrect balance from fees");
+ assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fee.unwrap_or(0) - 5_000, "incorrect balance from fees");
assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance from received");
let mut builder = wallet.build_fee_bump(details.txid).unwrap();
assert!(finalized, "Cannot finalize transaction");
wallet.broadcast(new_psbt.extract_tx()).unwrap();
wallet.sync(noop_progress(), None).unwrap();
- assert_eq!(wallet.get_balance().unwrap(), 50_000 - new_details.fees - 5_000, "incorrect balance from fees after bump");
+ assert_eq!(wallet.get_balance().unwrap(), 50_000 - new_details.fee.unwrap_or(0) - 5_000, "incorrect balance from fees after bump");
assert_eq!(wallet.get_balance().unwrap(), new_details.received, "incorrect balance from received after bump");
- assert!(new_details.fees > details.fees, "incorrect fees");
+ assert!(new_details.fee.unwrap_or(0) > details.fee.unwrap_or(0), "incorrect fees");
}
#[test]
assert!(finalized, "Cannot finalize transaction");
wallet.broadcast(psbt.extract_tx()).unwrap();
wallet.sync(noop_progress(), None).unwrap();
- assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fees, "incorrect balance after send");
+ assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fee.unwrap_or(0), "incorrect balance after send");
assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect received after send");
let mut builder = wallet.build_fee_bump(details.txid).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 0, "incorrect balance after change removal");
assert_eq!(new_details.received, 0, "incorrect received after change removal");
- assert!(new_details.fees > details.fees, "incorrect fees");
+ assert!(new_details.fee.unwrap_or(0) > details.fee.unwrap_or(0), "incorrect fees");
}
#[test]
#[serial]
- fn test_sync_bump_fee_add_input() {
+ fn test_sync_bump_fee_add_input_simple() {
let (wallet, descriptors, mut test_client) = init_single_sig();
let node_addr = test_client.get_node_address(None);
assert!(finalized, "Cannot finalize transaction");
wallet.broadcast(psbt.extract_tx()).unwrap();
wallet.sync(noop_progress(), None).unwrap();
- assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees, "incorrect balance after send");
- assert_eq!(details.received, 1_000 - details.fees, "incorrect received after send");
+ assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fee.unwrap_or(0), "incorrect balance after send");
+ assert_eq!(details.received, 1_000 - details.fee.unwrap_or(0), "incorrect received after send");
let mut builder = wallet.build_fee_bump(details.txid).unwrap();
builder.fee_rate(FeeRate::from_sat_per_vb(10.0));
assert!(finalized, "Cannot finalize transaction");
wallet.broadcast(psbt.extract_tx()).unwrap();
wallet.sync(noop_progress(), None).unwrap();
- assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees, "incorrect balance after send");
- assert_eq!(details.received, 1_000 - details.fees, "incorrect received after send");
+ assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fee.unwrap_or(0), "incorrect balance after send");
+ assert_eq!(details.received, 1_000 - details.fee.unwrap_or(0), "incorrect received after send");
let mut builder = wallet.build_fee_bump(details.txid).unwrap();
builder.fee_rate(FeeRate::from_sat_per_vb(123.0));
pub transaction: Option<Transaction>,
/// Transaction id
pub txid: Txid,
- /// Timestamp
- pub timestamp: u64,
+
/// Received value (sats)
pub received: u64,
/// Sent value (sats)
pub sent: u64,
- /// Fee value (sats)
- pub fees: u64,
- /// Confirmed in block height, `None` means unconfirmed
- pub height: Option<u32>,
+ /// Fee value (sats) if available
+ pub fee: Option<u64>,
+ /// If the transaction is confirmed, contains height and timestamp of the block containing the
+ /// transaction, unconfirmed transaction contains `None`.
+ pub confirmation_time: Option<ConfirmationTime>,
+}
+
+/// Block height and timestamp of the block containing the confirmed transaction
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
+pub struct ConfirmationTime {
+ /// confirmation block height
+ pub height: u32,
+ /// confirmation block timestamp
+ pub timestamp: u64,
+}
+
+impl ConfirmationTime {
+ /// Returns `Some` `ConfirmationTime` if both `height` and `timestamp` are `Some`
+ pub fn new(height: Option<u32>, timestamp: Option<u64>) -> Option<Self> {
+ match (height, timestamp) {
+ (Some(height), Some(timestamp)) => Some(ConfirmationTime { height, timestamp }),
+ _ => None,
+ }
+ }
}
#[cfg(test)]
Ok(txs) => {
let mut heights = txs
.into_iter()
- .map(|tx| tx.height.unwrap_or(0))
+ .map(|tx| tx.confirmation_time.map(|c| c.height).unwrap_or(0))
.collect::<Vec<_>>();
heights.sort_unstable();
use crate::database::{memory::MemoryDatabase, BatchOperations};
use crate::types::TransactionDetails;
use crate::wallet::Wallet;
+ use crate::ConfirmationTime;
fn get_test_db() -> MemoryDatabase {
let mut db = MemoryDatabase::new();
"4ddff1fa33af17f377f62b72357b43107c19110a8009b36fb832af505efed98a",
)
.unwrap(),
- timestamp: 12345678,
+
received: 100_000,
sent: 0,
- fees: 500,
- height: Some(5000),
+ fee: Some(500),
+ confirmation_time: Some(ConfirmationTime {
+ timestamp: 12345678,
+ height: 5000,
+ }),
})
.unwrap();
let transaction_details = TransactionDetails {
transaction: None,
txid,
- timestamp: time::get_timestamp(),
+ confirmation_time: None,
received,
sent,
- fees: fee_amount,
- height: None,
+ fee: Some(fee_amount),
};
Ok((psbt, transaction_details))
let mut details = match self.database.borrow().get_tx(&txid, true)? {
None => return Err(Error::TransactionNotFound),
Some(tx) if tx.transaction.is_none() => return Err(Error::TransactionNotFound),
- Some(tx) if tx.height.is_some() => return Err(Error::TransactionConfirmed),
+ Some(tx) if tx.confirmation_time.is_some() => return Err(Error::TransactionConfirmed),
Some(tx) => tx,
};
let mut tx = details.transaction.take().unwrap();
}
let vbytes = tx.get_weight() as f32 / 4.0;
- let feerate = details.fees as f32 / vbytes;
+ let feerate = details.fee.ok_or(Error::FeeRateUnavailable)? as f32 / vbytes;
// remove the inputs from the tx and process them
let original_txin = tx.input.drain(..).collect::<Vec<_>>();
.collect(),
utxos: original_utxos,
bumping_fee: Some(tx_builder::PreviousFee {
- absolute: details.fees,
+ absolute: details.fee.ok_or(Error::FeeRateUnavailable)?,
rate: feerate,
}),
..Default::default()
.database
.borrow()
.get_tx(&input.previous_output.txid, false)?
- .map(|tx| tx.height.unwrap_or(std::u32::MAX));
+ .map(|tx| tx.confirmation_time.map(|c| c.height).unwrap_or(u32::MAX));
let current_height = sign_options.assume_height.or(self.current_height);
debug!(
let satisfies_confirmed = match must_only_use_confirmed_tx {
true => {
- let database = self.database.borrow_mut();
+ let database = self.database.borrow();
may_spend
.iter()
.map(|u| {
.get_tx(&u.0.outpoint.txid, true)
.map(|tx| match tx {
None => false,
- Some(tx) => tx.height.is_some(),
+ Some(tx) => tx.confirmation_time.is_some(),
})
})
.collect::<Result<Vec<_>, _>>()?
assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
assert_eq!(
psbt.global.unsigned_tx.output[0].value,
- 50_000 - details.fees
+ 50_000 - details.fee.unwrap_or(0)
);
}
builder.add_recipient(addr.script_pubkey(), 25_000);
let (psbt, details) = builder.finish().unwrap();
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::default(), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::default(), @add_signature);
}
#[test]
.fee_rate(FeeRate::from_sat_per_vb(5.0));
let (psbt, details) = builder.finish().unwrap();
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(5.0), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature);
}
#[test]
.fee_absolute(100);
let (psbt, details) = builder.finish().unwrap();
- assert_eq!(details.fees, 100);
+ assert_eq!(details.fee.unwrap_or(0), 100);
assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
assert_eq!(
psbt.global.unsigned_tx.output[0].value,
- 50_000 - details.fees
+ 50_000 - details.fee.unwrap_or(0)
);
}
.fee_absolute(0);
let (psbt, details) = builder.finish().unwrap();
- assert_eq!(details.fees, 0);
+ assert_eq!(details.fee.unwrap_or(0), 0);
assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
assert_eq!(
psbt.global.unsigned_tx.output[0].value,
- 50_000 - details.fees
+ 50_000 - details.fee.unwrap_or(0)
);
}
assert_eq!(psbt.global.unsigned_tx.output[0].value, 25_000);
assert_eq!(
psbt.global.unsigned_tx.output[1].value,
- 25_000 - details.fees
+ 25_000 - details.fee.unwrap_or(0)
);
}
assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
assert_eq!(psbt.global.unsigned_tx.output[0].value, 49_800);
- assert_eq!(details.fees, 200);
+ assert_eq!(details.fee.unwrap_or(0), 200);
}
#[test]
assert_eq!(psbt.global.unsigned_tx.output.len(), 3);
assert_eq!(
psbt.global.unsigned_tx.output[0].value,
- 10_000 - details.fees
+ 10_000 - details.fee.unwrap_or(0)
);
assert_eq!(psbt.global.unsigned_tx.output[1].value, 10_000);
assert_eq!(psbt.global.unsigned_tx.output[2].value, 30_000);
assert_eq!(
details.sent - details.received,
- 10_000 + details.fees,
+ 10_000 + details.fee.unwrap_or(0),
"we should have only net spent ~10_000"
);
let txid = tx.txid();
// skip saving the utxos, we know they can't be used anyways
details.transaction = Some(tx);
- details.height = Some(42);
+ details.confirmation_time = Some(ConfirmationTime {
+ timestamp: 12345678,
+ height: 42,
+ });
wallet.database.borrow_mut().set_tx(&details).unwrap();
wallet.build_fee_bump(txid).unwrap().finish().unwrap();
assert_eq!(details.sent, original_details.sent);
assert_eq!(
- details.received + details.fees,
- original_details.received + original_details.fees
+ details.received + details.fee.unwrap_or(0),
+ original_details.received + original_details.fee.unwrap_or(0)
);
- assert!(details.fees > original_details.fees);
+ assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0));
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.output.len(), 2);
details.received
);
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(2.5), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(2.5), @add_signature);
}
#[test]
assert_eq!(details.sent, original_details.sent);
assert_eq!(
- details.received + details.fees,
- original_details.received + original_details.fees
+ details.received + details.fee.unwrap_or(0),
+ original_details.received + original_details.fee.unwrap_or(0)
);
assert!(
- details.fees > original_details.fees,
+ details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0),
"{} > {}",
- details.fees,
- original_details.fees
+ details.fee.unwrap_or(0),
+ original_details.fee.unwrap_or(0)
);
let tx = &psbt.global.unsigned_tx;
details.received
);
- assert_eq!(details.fees, 200);
+ assert_eq!(details.fee.unwrap_or(0), 200);
}
#[test]
let (psbt, details) = builder.finish().unwrap();
assert_eq!(details.sent, original_details.sent);
- assert!(details.fees > original_details.fees);
+ assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0));
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.output.len(), 1);
- assert_eq!(tx.output[0].value + details.fees, details.sent);
+ assert_eq!(tx.output[0].value + details.fee.unwrap_or(0), details.sent);
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(2.5), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(2.5), @add_signature);
}
#[test]
let (psbt, details) = builder.finish().unwrap();
assert_eq!(details.sent, original_details.sent);
- assert!(details.fees > original_details.fees);
+ assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0));
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.output.len(), 1);
- assert_eq!(tx.output[0].value + details.fees, details.sent);
+ assert_eq!(tx.output[0].value + details.fee.unwrap_or(0), details.sent);
- assert_eq!(details.fees, 300);
+ assert_eq!(details.fee.unwrap_or(0), 300);
}
#[test]
let (psbt, details) = builder.finish().unwrap();
assert_eq!(details.sent, original_details.sent + 25_000);
- assert_eq!(details.fees + details.received, 30_000);
+ assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000);
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.input.len(), 2);
details.received
);
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(50.0), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature);
}
#[test]
let (psbt, details) = builder.finish().unwrap();
assert_eq!(details.sent, original_details.sent + 25_000);
- assert_eq!(details.fees + details.received, 30_000);
+ assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000);
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.input.len(), 2);
details.received
);
- assert_eq!(details.fees, 6_000);
+ assert_eq!(details.fee.unwrap_or(0), 6_000);
}
#[test]
builder.fee_rate(FeeRate::from_sat_per_vb(50.0));
let (psbt, details) = builder.finish().unwrap();
- let original_send_all_amount = original_details.sent - original_details.fees;
+ let original_send_all_amount = original_details.sent - original_details.fee.unwrap_or(0);
assert_eq!(details.sent, original_details.sent + 50_000);
assert_eq!(
details.received,
- 75_000 - original_send_all_amount - details.fees
+ 75_000 - original_send_all_amount - details.fee.unwrap_or(0)
);
let tx = &psbt.global.unsigned_tx;
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value,
- 75_000 - original_send_all_amount - details.fees
+ 75_000 - original_send_all_amount - details.fee.unwrap_or(0)
);
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(50.0), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature);
}
#[test]
builder.fee_rate(FeeRate::from_sat_per_vb(140.0));
let (psbt, details) = builder.finish().unwrap();
- assert_eq!(original_details.received, 5_000 - original_details.fees);
+ assert_eq!(
+ original_details.received,
+ 5_000 - original_details.fee.unwrap_or(0)
+ );
assert_eq!(details.sent, original_details.sent + 25_000);
- assert_eq!(details.fees, 30_000);
+ assert_eq!(details.fee.unwrap_or(0), 30_000);
assert_eq!(details.received, 0);
let tx = &psbt.global.unsigned_tx;
45_000
);
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(140.0), @dust_change, @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(140.0), @dust_change, @add_signature);
}
#[test]
let (psbt, details) = builder.finish().unwrap();
assert_eq!(details.sent, original_details.sent + 25_000);
- assert_eq!(details.fees + details.received, 30_000);
+ assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000);
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.input.len(), 2);
details.received
);
- assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(5.0), @add_signature);
+ assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature);
}
#[test]
let (psbt, details) = builder.finish().unwrap();
assert_eq!(details.sent, original_details.sent + 25_000);
- assert_eq!(details.fees + details.received, 30_000);
+ assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000);
let tx = &psbt.global.unsigned_tx;
assert_eq!(tx.input.len(), 2);
details.received
);
- assert_eq!(details.fees, 250);
+ assert_eq!(details.fee.unwrap_or(0), 250);
}
#[test]