Skip to content

Commit 647d285

Browse files
committed
Merge bitcoindevkit/bdk#1643: feat(chain,wallet)!: rm ConfirmationTime
a3d4eef feat(chain,wallet)!: rm `ConfirmationTime` (志宇) Pull request description: ### Description This PR removes `ConfirmationTime`, and favors `ChainPosition<ConfirmationBlockTime>` instead. The only difference between these two structures is that `ChainPosition<ConfirmationBlockTime>` contains an additional `BlockHash`. Additionally, `ConfirmationTime` was not used in many places. It was mainly for displaying information in `bdk_wallet::Wallet`. We also impl `serde::Deserialize` and `serde::Serialize` for `ChainPosition`. ### Notes to the reviewers ### Changelog notice * Remove `bdk_chain::ConfirmationTime`. Use `ChainPosition<ConfirmationBlockTime>` in place. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing ACKs for top commit: LagginTimes: ACK a3d4eef oleonardolima: ACK a3d4eef ValuedMammal: ACK a3d4eef Tree-SHA512: d94db70885e6987774da586b92ee826098a0da4ae808ff9b23632bd68bbb3d6babbba1aac9d79b78bcf4affa48404f5cca3c7c00ad2db02e1f47f78e094a5f76
2 parents 7969898 + a3d4eef commit 647d285

File tree

7 files changed

+179
-223
lines changed

7 files changed

+179
-223
lines changed

crates/chain/src/chain_data.rs

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::ConfirmationBlockTime;
21
use bitcoin::{OutPoint, TxOut, Txid};
32

43
use crate::{Anchor, COINBASE_MATURITY};
@@ -7,6 +6,14 @@ use crate::{Anchor, COINBASE_MATURITY};
76
///
87
/// The generic `A` should be a [`Anchor`] implementation.
98
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, core::hash::Hash)]
9+
#[cfg_attr(
10+
feature = "serde",
11+
derive(serde::Deserialize, serde::Serialize),
12+
serde(bound(
13+
deserialize = "A: Ord + serde::Deserialize<'de>",
14+
serialize = "A: Ord + serde::Serialize",
15+
))
16+
)]
1017
pub enum ChainPosition<A> {
1118
/// The chain data is seen as confirmed, and in anchored by `A`.
1219
Confirmed(A),
@@ -41,48 +48,6 @@ impl<A: Anchor> ChainPosition<A> {
4148
}
4249
}
4350

44-
/// Block height and timestamp at which a transaction is confirmed.
45-
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
46-
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
47-
pub enum ConfirmationTime {
48-
/// The transaction is confirmed
49-
Confirmed {
50-
/// Confirmation height.
51-
height: u32,
52-
/// Confirmation time in unix seconds.
53-
time: u64,
54-
},
55-
/// The transaction is unconfirmed
56-
Unconfirmed {
57-
/// The last-seen timestamp in unix seconds.
58-
last_seen: u64,
59-
},
60-
}
61-
62-
impl ConfirmationTime {
63-
/// Construct an unconfirmed variant using the given `last_seen` time in unix seconds.
64-
pub fn unconfirmed(last_seen: u64) -> Self {
65-
Self::Unconfirmed { last_seen }
66-
}
67-
68-
/// Returns whether [`ConfirmationTime`] is the confirmed variant.
69-
pub fn is_confirmed(&self) -> bool {
70-
matches!(self, Self::Confirmed { .. })
71-
}
72-
}
73-
74-
impl From<ChainPosition<ConfirmationBlockTime>> for ConfirmationTime {
75-
fn from(observed_as: ChainPosition<ConfirmationBlockTime>) -> Self {
76-
match observed_as {
77-
ChainPosition::Confirmed(a) => Self::Confirmed {
78-
height: a.block_id.height,
79-
time: a.confirmation_time,
80-
},
81-
ChainPosition::Unconfirmed(last_seen) => Self::Unconfirmed { last_seen },
82-
}
83-
}
84-
}
85-
8651
/// A `TxOut` with as much data as we can retrieve about it
8752
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
8853
pub struct FullTxOut<A> {
@@ -159,6 +124,8 @@ impl<A: Anchor> FullTxOut<A> {
159124

160125
#[cfg(test)]
161126
mod test {
127+
use bdk_core::ConfirmationBlockTime;
128+
162129
use crate::BlockId;
163130

164131
use super::*;

crates/wallet/src/types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
// licenses.
1111

1212
use alloc::boxed::Box;
13+
use chain::{ChainPosition, ConfirmationBlockTime};
1314
use core::convert::AsRef;
1415

15-
use bdk_chain::ConfirmationTime;
1616
use bitcoin::transaction::{OutPoint, Sequence, TxOut};
1717
use bitcoin::{psbt, Weight};
1818

@@ -61,8 +61,8 @@ pub struct LocalOutput {
6161
pub is_spent: bool,
6262
/// The derivation index for the script pubkey in the wallet
6363
pub derivation_index: u32,
64-
/// The confirmation time for transaction containing this utxo
65-
pub confirmation_time: ConfirmationTime,
64+
/// The position of the output in the blockchain.
65+
pub chain_position: ChainPosition<ConfirmationBlockTime>,
6666
}
6767

6868
/// A [`Utxo`] with its `satisfaction_weight`.

crates/wallet/src/wallet/coin_selection.rs

Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ impl CoinSelectionAlgorithm for OldestFirstCoinSelection {
278278
// For utxo that doesn't exist in DB, they will have lowest priority to be selected
279279
let utxos = {
280280
optional_utxos.sort_unstable_by_key(|wu| match &wu.utxo {
281-
Utxo::Local(local) => Some(local.confirmation_time),
281+
Utxo::Local(local) => Some(local.chain_position),
282282
Utxo::Foreign { .. } => None,
283283
});
284284

@@ -733,11 +733,12 @@ where
733733
#[cfg(test)]
734734
mod test {
735735
use assert_matches::assert_matches;
736+
use bitcoin::hashes::Hash;
737+
use chain::{BlockId, ChainPosition, ConfirmationBlockTime};
736738
use core::str::FromStr;
737739
use rand::rngs::StdRng;
738740

739-
use bdk_chain::ConfirmationTime;
740-
use bitcoin::{Amount, ScriptBuf, TxIn, TxOut};
741+
use bitcoin::{Amount, BlockHash, ScriptBuf, TxIn, TxOut};
741742

742743
use super::*;
743744
use crate::types::*;
@@ -752,7 +753,34 @@ mod test {
752753

753754
const FEE_AMOUNT: u64 = 50;
754755

755-
fn utxo(value: u64, index: u32, confirmation_time: ConfirmationTime) -> WeightedUtxo {
756+
fn unconfirmed_utxo(value: u64, index: u32, last_seen: u64) -> WeightedUtxo {
757+
utxo(value, index, ChainPosition::Unconfirmed(last_seen))
758+
}
759+
760+
fn confirmed_utxo(
761+
value: u64,
762+
index: u32,
763+
confirmation_height: u32,
764+
confirmation_time: u64,
765+
) -> WeightedUtxo {
766+
utxo(
767+
value,
768+
index,
769+
ChainPosition::Confirmed(ConfirmationBlockTime {
770+
block_id: chain::BlockId {
771+
height: confirmation_height,
772+
hash: bitcoin::BlockHash::all_zeros(),
773+
},
774+
confirmation_time,
775+
}),
776+
)
777+
}
778+
779+
fn utxo(
780+
value: u64,
781+
index: u32,
782+
chain_position: ChainPosition<ConfirmationBlockTime>,
783+
) -> WeightedUtxo {
756784
assert!(index < 10);
757785
let outpoint = OutPoint::from_str(&format!(
758786
"000000000000000000000000000000000000000000000000000000000000000{}:0",
@@ -770,49 +798,24 @@ mod test {
770798
keychain: KeychainKind::External,
771799
is_spent: false,
772800
derivation_index: 42,
773-
confirmation_time,
801+
chain_position,
774802
}),
775803
}
776804
}
777805

778806
fn get_test_utxos() -> Vec<WeightedUtxo> {
779807
vec![
780-
utxo(100_000, 0, ConfirmationTime::Unconfirmed { last_seen: 0 }),
781-
utxo(
782-
FEE_AMOUNT - 40,
783-
1,
784-
ConfirmationTime::Unconfirmed { last_seen: 0 },
785-
),
786-
utxo(200_000, 2, ConfirmationTime::Unconfirmed { last_seen: 0 }),
808+
unconfirmed_utxo(100_000, 0, 0),
809+
unconfirmed_utxo(FEE_AMOUNT - 40, 1, 0),
810+
unconfirmed_utxo(200_000, 2, 0),
787811
]
788812
}
789813

790814
fn get_oldest_first_test_utxos() -> Vec<WeightedUtxo> {
791815
// ensure utxos are from different tx
792-
let utxo1 = utxo(
793-
120_000,
794-
1,
795-
ConfirmationTime::Confirmed {
796-
height: 1,
797-
time: 1231006505,
798-
},
799-
);
800-
let utxo2 = utxo(
801-
80_000,
802-
2,
803-
ConfirmationTime::Confirmed {
804-
height: 2,
805-
time: 1231006505,
806-
},
807-
);
808-
let utxo3 = utxo(
809-
300_000,
810-
3,
811-
ConfirmationTime::Confirmed {
812-
height: 3,
813-
time: 1231006505,
814-
},
815-
);
816+
let utxo1 = confirmed_utxo(120_000, 1, 1, 1231006505);
817+
let utxo2 = confirmed_utxo(80_000, 2, 2, 1231006505);
818+
let utxo3 = confirmed_utxo(300_000, 3, 3, 1231006505);
816819
vec![utxo1, utxo2, utxo3]
817820
}
818821

@@ -834,13 +837,16 @@ mod test {
834837
keychain: KeychainKind::External,
835838
is_spent: false,
836839
derivation_index: rng.next_u32(),
837-
confirmation_time: if rng.gen_bool(0.5) {
838-
ConfirmationTime::Confirmed {
839-
height: rng.next_u32(),
840-
time: rng.next_u64(),
841-
}
840+
chain_position: if rng.gen_bool(0.5) {
841+
ChainPosition::Confirmed(ConfirmationBlockTime {
842+
block_id: chain::BlockId {
843+
height: rng.next_u32(),
844+
hash: BlockHash::all_zeros(),
845+
},
846+
confirmation_time: rng.next_u64(),
847+
})
842848
} else {
843-
ConfirmationTime::Unconfirmed { last_seen: 0 }
849+
ChainPosition::Unconfirmed(0)
844850
},
845851
}),
846852
});
@@ -865,7 +871,7 @@ mod test {
865871
keychain: KeychainKind::External,
866872
is_spent: false,
867873
derivation_index: 42,
868-
confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 },
874+
chain_position: ChainPosition::Unconfirmed(0),
869875
}),
870876
})
871877
.collect()
@@ -1222,7 +1228,7 @@ mod test {
12221228
optional.push(utxo(
12231229
500_000,
12241230
3,
1225-
ConfirmationTime::Unconfirmed { last_seen: 0 },
1231+
ChainPosition::<ConfirmationBlockTime>::Unconfirmed(0),
12261232
));
12271233

12281234
// Defensive assertions, for sanity and in case someone changes the test utxos vector.
@@ -1584,10 +1590,13 @@ mod test {
15841590
keychain: KeychainKind::External,
15851591
is_spent: false,
15861592
derivation_index: 0,
1587-
confirmation_time: ConfirmationTime::Confirmed {
1588-
height: 12345,
1589-
time: 12345,
1590-
},
1593+
chain_position: ChainPosition::Confirmed(ConfirmationBlockTime {
1594+
block_id: BlockId {
1595+
height: 12345,
1596+
hash: BlockHash::all_zeros(),
1597+
},
1598+
confirmation_time: 12345,
1599+
}),
15911600
}),
15921601
}
15931602
}

crates/wallet/src/wallet/mod.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ use bdk_chain::{
3434
SyncResult,
3535
},
3636
tx_graph::{CanonicalTx, TxGraph, TxNode, TxUpdate},
37-
BlockId, ChainPosition, ConfirmationBlockTime, ConfirmationTime, DescriptorExt, FullTxOut,
38-
Indexed, IndexedTxGraph, Merge,
37+
BlockId, ChainPosition, ConfirmationBlockTime, DescriptorExt, FullTxOut, Indexed,
38+
IndexedTxGraph, Merge,
3939
};
4040
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
4141
use bitcoin::{
@@ -1660,11 +1660,10 @@ impl Wallet {
16601660
.ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?;
16611661
let txout = &prev_tx.output[txin.previous_output.vout as usize];
16621662

1663-
let confirmation_time: ConfirmationTime = graph
1663+
let chain_position = graph
16641664
.get_chain_position(&self.chain, chain_tip, txin.previous_output.txid)
16651665
.ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?
1666-
.cloned()
1667-
.into();
1666+
.cloned();
16681667

16691668
let weighted_utxo = match txout_index.index_of_spk(txout.script_pubkey.clone()) {
16701669
Some(&(keychain, derivation_index)) => {
@@ -1679,7 +1678,7 @@ impl Wallet {
16791678
keychain,
16801679
is_spent: true,
16811680
derivation_index,
1682-
confirmation_time,
1681+
chain_position,
16831682
}),
16841683
satisfaction_weight,
16851684
}
@@ -2051,33 +2050,33 @@ impl Wallet {
20512050
Some(tx) => tx,
20522051
None => return false,
20532052
};
2054-
let confirmation_time: ConfirmationTime = match self
2055-
.indexed_graph
2056-
.graph()
2057-
.get_chain_position(&self.chain, chain_tip, txid)
2058-
{
2059-
Some(chain_position) => chain_position.cloned().into(),
2053+
let chain_position = match self.indexed_graph.graph().get_chain_position(
2054+
&self.chain,
2055+
chain_tip,
2056+
txid,
2057+
) {
2058+
Some(chain_position) => chain_position.cloned(),
20602059
None => return false,
20612060
};
20622061

20632062
// Whether the UTXO is mature and, if needed, confirmed
20642063
let mut spendable = true;
2065-
if must_only_use_confirmed_tx && !confirmation_time.is_confirmed() {
2064+
if must_only_use_confirmed_tx && !chain_position.is_confirmed() {
20662065
return false;
20672066
}
20682067
if tx.is_coinbase() {
20692068
debug_assert!(
2070-
confirmation_time.is_confirmed(),
2069+
chain_position.is_confirmed(),
20712070
"coinbase must always be confirmed"
20722071
);
20732072
if let Some(current_height) = current_height {
2074-
match confirmation_time {
2075-
ConfirmationTime::Confirmed { height, .. } => {
2073+
match chain_position {
2074+
ChainPosition::Confirmed(a) => {
20762075
// https://github.com/bitcoin/bitcoin/blob/c5e67be03bb06a5d7885c55db1f016fbf2333fe3/src/validation.cpp#L373-L375
2077-
spendable &=
2078-
(current_height.saturating_sub(height)) >= COINBASE_MATURITY;
2076+
spendable &= (current_height.saturating_sub(a.block_id.height))
2077+
>= COINBASE_MATURITY;
20792078
}
2080-
ConfirmationTime::Unconfirmed { .. } => spendable = false,
2079+
ChainPosition::Unconfirmed { .. } => spendable = false,
20812080
}
20822081
}
20832082
}
@@ -2546,7 +2545,7 @@ fn new_local_utxo(
25462545
outpoint: full_txo.outpoint,
25472546
txout: full_txo.txout,
25482547
is_spent: full_txo.spent_by.is_some(),
2549-
confirmation_time: full_txo.chain_position.into(),
2548+
chain_position: full_txo.chain_position,
25502549
keychain,
25512550
derivation_index,
25522551
}

0 commit comments

Comments
 (0)