Skip to content

Commit 4ca6cd6

Browse files
committed
Merge rust-bitcoin#4458: locktimes: replace MtpAndHeight type with pair of BlockMtp and BlockHeight
47c77af units: delete MtpAndHeight type (Andrew Poelstra) d82b8c0 primitives: stop using MtpAndHeight (Andrew Poelstra) 72d5fba units: stop using MtpAndHeight in locktime::relative is_satisfied_by methods (Andrew Poelstra) d933c75 units: change type of MtpHeight::to_mtp to BlockMtp (Andrew Poelstra) dcbdb7c units: add checked arithmetic to Block{Height,Mtp}{Interval,} (Andrew Poelstra) 4300271 units: add constructor for absolute::Mtp from timestamps (Andrew Poelstra) 4e4601b units: rename BlockInterval to BlockHeightInterval (Andrew Poelstra) cb882c5 units: add global `BlockMtpInterval` type (Andrew Poelstra) 4e3af51 units: add global `BlockMtp` type (Andrew Poelstra) a3228d4 units: pull u32 conversions for BlockHeight/BlockInterval into macro (Andrew Poelstra) Pull request description: This is a more involved PR than I'd expected but hopefully the individual commits make sense and are well-motivated. Essentially, my goal was to replace `MtpAndHeight` as used by relative locktimes with a pair of `Mtp` and `Height`. However, relative locktimes, when given a MTP/Height for the UTXO creation and the chain tip, are roughly modeled as "take a diff of MTPs to get a `relative::MtpInterval`, a diff of heights to get a `relative::HeightInterval`, and compare to the locktimes". *However*, we have no standalone MTP type to "take a diff of", and also there are failure modes when creating the diffs (e.g. if the diff would exceed the range of `MtpInterval` or `HeightInterval`). So I backed up and decided to use the existing `BlockHeight`/`BlockInterval` as the type to "take a diff of". I needed to introduce a `BlockMtp`/`BlockMtpInterval` to work with MTPs. These types have full-u32 range, unlike the similarly-named types in `units::locktimes::absolute`. I then needed to add some conversion methods. Along the way, I cleaned up the APIs and documentation, added checked arithmetic, etc., as needed. See the individual commit messages for more detail. I believe the resulting API is much more consistent and discoverable, even though it has more surface than the old API. I considered splitting this into 2 PRs but I think the first half of the changes aren't well-motivated with out the second half. Let me know. ACKs for top commit: tcharding: ACK 47c77af Tree-SHA512: ebe19a5b1684db8c2d913274347c994026aaa0dcdd79349c237920a82fe55560777278efdbbc7f1b1424c9391d9bbd891ae844db885deea75288000437a8a287
2 parents 8a563ef + 47c77af commit 4ca6cd6

File tree

11 files changed

+522
-306
lines changed

11 files changed

+522
-306
lines changed

bitcoin/src/blockdata/block.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ use crate::transaction::{Transaction, TransactionExt as _, Wtxid};
3030
#[doc(inline)]
3131
pub use primitives::block::{Block, Checked, Unchecked, Validation, Version, BlockHash, Header, WitnessCommitment};
3232
#[doc(inline)]
33-
pub use units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightIntervalError};
33+
pub use units::block::{
34+
BlockHeight, BlockHeightInterval, TooBigForRelativeBlockHeightIntervalError,
35+
};
36+
37+
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
38+
#[doc(hidden)]
39+
pub type BlockInterval = BlockHeightInterval;
3440

3541
impl_hashencode!(BlockHash);
3642

bitcoin/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,16 @@ pub use primitives::{
135135
#[doc(inline)]
136136
pub use units::{
137137
amount::{Amount, Denomination, SignedAmount},
138-
block::{BlockHeight, BlockInterval},
138+
block::{BlockHeight, BlockHeightInterval, BlockMtp},
139139
fee_rate::FeeRate,
140140
time::{self, BlockTime},
141141
weight::Weight,
142142
};
143143

144+
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
145+
#[doc(hidden)]
146+
pub type BlockInterval = BlockHeightInterval;
147+
144148
#[doc(inline)]
145149
pub use crate::{
146150
address::{Address, AddressType, KnownHrp},
@@ -243,7 +247,7 @@ mod encode_impls {
243247
//! Encodable/Decodable implementations.
244248
// While we are deprecating, re-exporting, and generally moving things around just put these here.
245249

246-
use units::{BlockHeight, BlockInterval};
250+
use units::{BlockHeight, BlockHeightInterval};
247251

248252
use crate::consensus::{encode, Decodable, Encodable};
249253
use crate::io::{BufRead, Write};
@@ -275,5 +279,5 @@ mod encode_impls {
275279
}
276280

277281
impl_encodable_for_u32_wrapper!(BlockHeight);
278-
impl_encodable_for_u32_wrapper!(BlockInterval);
282+
impl_encodable_for_u32_wrapper!(BlockHeightInterval);
279283
}

bitcoin/src/network/params.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
//! # }
6868
//! ```
6969
70-
use units::{BlockHeight, BlockInterval};
70+
use units::{BlockHeight, BlockHeightInterval};
7171

7272
use crate::network::Network;
7373
#[cfg(doc)]
@@ -92,9 +92,9 @@ pub struct Params {
9292
/// Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period,
9393
/// (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
9494
/// Examples: 1916 for 95%, 1512 for testchains.
95-
pub rule_change_activation_threshold: BlockInterval,
95+
pub rule_change_activation_threshold: BlockHeightInterval,
9696
/// Number of blocks with the same set of rules.
97-
pub miner_confirmation_window: BlockInterval,
97+
pub miner_confirmation_window: BlockHeightInterval,
9898
/// Proof of work limit value. It contains the lowest possible difficulty.
9999
#[deprecated(since = "0.32.0", note = "use `max_attainable_target` instead")]
100100
pub pow_limit: Target,
@@ -152,8 +152,8 @@ impl Params {
152152
bip34_height: BlockHeight::from_u32(227931), // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
153153
bip65_height: BlockHeight::from_u32(388381), // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
154154
bip66_height: BlockHeight::from_u32(363725), // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
155-
rule_change_activation_threshold: BlockInterval::from_u32(1916), // 95%
156-
miner_confirmation_window: BlockInterval::from_u32(2016),
155+
rule_change_activation_threshold: BlockHeightInterval::from_u32(1916), // 95%
156+
miner_confirmation_window: BlockHeightInterval::from_u32(2016),
157157
pow_limit: Target::MAX_ATTAINABLE_MAINNET,
158158
max_attainable_target: Target::MAX_ATTAINABLE_MAINNET,
159159
pow_target_spacing: 10 * 60, // 10 minutes.
@@ -170,8 +170,8 @@ impl Params {
170170
bip34_height: BlockHeight::from_u32(21111), // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
171171
bip65_height: BlockHeight::from_u32(581885), // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
172172
bip66_height: BlockHeight::from_u32(330776), // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
173-
rule_change_activation_threshold: BlockInterval::from_u32(1512), // 75%
174-
miner_confirmation_window: BlockInterval::from_u32(2016),
173+
rule_change_activation_threshold: BlockHeightInterval::from_u32(1512), // 75%
174+
miner_confirmation_window: BlockHeightInterval::from_u32(2016),
175175
pow_limit: Target::MAX_ATTAINABLE_TESTNET,
176176
max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
177177
pow_target_spacing: 10 * 60, // 10 minutes.
@@ -187,8 +187,8 @@ impl Params {
187187
bip34_height: BlockHeight::from_u32(21111), // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
188188
bip65_height: BlockHeight::from_u32(581885), // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
189189
bip66_height: BlockHeight::from_u32(330776), // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
190-
rule_change_activation_threshold: BlockInterval::from_u32(1512), // 75%
191-
miner_confirmation_window: BlockInterval::from_u32(2016),
190+
rule_change_activation_threshold: BlockHeightInterval::from_u32(1512), // 75%
191+
miner_confirmation_window: BlockHeightInterval::from_u32(2016),
192192
pow_limit: Target::MAX_ATTAINABLE_TESTNET,
193193
max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
194194
pow_target_spacing: 10 * 60, // 10 minutes.
@@ -204,8 +204,8 @@ impl Params {
204204
bip34_height: BlockHeight::from_u32(1),
205205
bip65_height: BlockHeight::from_u32(1),
206206
bip66_height: BlockHeight::from_u32(1),
207-
rule_change_activation_threshold: BlockInterval::from_u32(1512), // 75%
208-
miner_confirmation_window: BlockInterval::from_u32(2016),
207+
rule_change_activation_threshold: BlockHeightInterval::from_u32(1512), // 75%
208+
miner_confirmation_window: BlockHeightInterval::from_u32(2016),
209209
pow_limit: Target::MAX_ATTAINABLE_TESTNET,
210210
max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
211211
pow_target_spacing: 10 * 60, // 10 minutes.
@@ -221,8 +221,8 @@ impl Params {
221221
bip34_height: BlockHeight::from_u32(1),
222222
bip65_height: BlockHeight::from_u32(1),
223223
bip66_height: BlockHeight::from_u32(1),
224-
rule_change_activation_threshold: BlockInterval::from_u32(1916), // 95%
225-
miner_confirmation_window: BlockInterval::from_u32(2016),
224+
rule_change_activation_threshold: BlockHeightInterval::from_u32(1916), // 95%
225+
miner_confirmation_window: BlockHeightInterval::from_u32(2016),
226226
pow_limit: Target::MAX_ATTAINABLE_SIGNET,
227227
max_attainable_target: Target::MAX_ATTAINABLE_SIGNET,
228228
pow_target_spacing: 10 * 60, // 10 minutes.
@@ -238,8 +238,8 @@ impl Params {
238238
bip34_height: BlockHeight::from_u32(100000000), // not activated on regtest
239239
bip65_height: BlockHeight::from_u32(1351),
240240
bip66_height: BlockHeight::from_u32(1251), // used only in rpc tests
241-
rule_change_activation_threshold: BlockInterval::from_u32(108), // 75%
242-
miner_confirmation_window: BlockInterval::from_u32(144),
241+
rule_change_activation_threshold: BlockHeightInterval::from_u32(108), // 75%
242+
miner_confirmation_window: BlockHeightInterval::from_u32(144),
243243
pow_limit: Target::MAX_ATTAINABLE_REGTEST,
244244
max_attainable_target: Target::MAX_ATTAINABLE_REGTEST,
245245
pow_target_spacing: 10 * 60, // 10 minutes.

primitives/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,16 @@ pub mod witness;
5252
#[doc(inline)]
5353
pub use units::{
5454
amount::{self, Amount, SignedAmount},
55-
block::{BlockHeight, BlockInterval},
55+
block::{BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval},
5656
fee_rate::{self, FeeRate},
5757
time::{self, BlockTime},
5858
weight::{self, Weight},
5959
};
6060

61+
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
62+
#[doc(hidden)]
63+
pub type BlockInterval = BlockHeightInterval;
64+
6165
#[doc(inline)]
6266
#[cfg(feature = "alloc")]
6367
pub use self::{

primitives/src/locktime/relative.rs

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{relative, TxIn};
1414
#[rustfmt::skip] // Keep public re-exports separate.
1515
#[doc(inline)]
1616
pub use units::locktime::relative::{HeightInterval, MtpInterval, TimeOverflowError};
17-
use units::mtp_height::MtpAndHeight;
17+
use units::{BlockHeight, BlockMtp};
1818

1919
#[deprecated(since = "TBD", note = "use `Mtp` instead")]
2020
#[doc(hidden)]
@@ -44,9 +44,7 @@ pub type Time = MtpInterval;
4444
///
4545
/// ```
4646
/// use bitcoin_primitives::relative;
47-
/// use bitcoin_primitives::BlockTime;
48-
/// use bitcoin_primitives::BlockHeight;
49-
/// use units::mtp_height::MtpAndHeight;
47+
/// use bitcoin_primitives::{BlockHeight, BlockMtp, BlockTime};
5048
/// let lock_by_height = relative::LockTime::from_height(144); // 144 blocks, approx 24h.
5149
/// assert!(lock_by_height.is_block_height());
5250
///
@@ -65,14 +63,15 @@ pub type Time = MtpInterval;
6563
/// let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
6664
///
6765
/// let current_height = BlockHeight::from(100);
66+
/// let current_mtp = BlockMtp::new(timestamps);
67+
///
6868
/// let utxo_height = BlockHeight::from(80);
69+
/// let utxo_mtp = BlockMtp::new(utxo_timestamps);
6970
///
70-
/// let chain_tip = MtpAndHeight::new(current_height, timestamps);
71-
/// let utxo_mined_at = MtpAndHeight::new(utxo_height, utxo_timestamps);
7271
/// let locktime = relative::LockTime::Time(relative::MtpInterval::from_512_second_intervals(10));
7372
///
7473
/// // Check if locktime is satisfied
75-
/// assert!(locktime.is_satisfied_by(chain_tip, utxo_mined_at));
74+
/// assert!(locktime.is_satisfied_by(current_height, current_mtp, utxo_height, utxo_mtp));
7675
/// ```
7776
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7877
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -226,10 +225,8 @@ impl LockTime {
226225
///
227226
/// ```rust
228227
/// # use bitcoin_primitives::relative::Time;
229-
/// # use units::mtp_height::MtpAndHeight;
230-
/// # use bitcoin_primitives::BlockHeight;
228+
/// # use bitcoin_primitives::{BlockHeight, BlockMtp, BlockTime};
231229
/// # use bitcoin_primitives::relative::LockTime;
232-
/// # use bitcoin_primitives::BlockTime;
233230
///
234231
/// fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] {
235232
/// let mut timestamps = [BlockTime::from_u32(0); 11];
@@ -243,19 +240,26 @@ impl LockTime {
243240
/// let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
244241
///
245242
/// let current_height = BlockHeight::from_u32(100);
243+
/// let current_mtp = BlockMtp::new(timestamps);
246244
/// let utxo_height = BlockHeight::from_u32(80);
245+
/// let utxo_mtp = BlockMtp::new(utxo_timestamps);
247246
///
248-
/// let chain_tip = MtpAndHeight::new(current_height, timestamps);
249-
/// let utxo_mined_at = MtpAndHeight::new(utxo_height, utxo_timestamps);
250247
/// let locktime = LockTime::Time(Time::from_512_second_intervals(10));
251248
///
252249
/// // Check if locktime is satisfied
253-
/// assert!(locktime.is_satisfied_by(chain_tip, utxo_mined_at));
250+
/// assert!(locktime.is_satisfied_by(current_height, current_mtp, utxo_height, utxo_mtp));
254251
/// ```
255-
pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool {
252+
pub fn is_satisfied_by(
253+
self,
254+
chain_tip_height: BlockHeight,
255+
chain_tip_mtp: BlockMtp,
256+
utxo_mined_at_height: BlockHeight,
257+
utxo_mined_at_mtp: BlockMtp,
258+
) -> bool {
256259
match self {
257-
LockTime::Blocks(blocks) => blocks.is_satisfied_by(chain_tip, utxo_mined_at),
258-
LockTime::Time(time) => time.is_satisfied_by(chain_tip, utxo_mined_at),
260+
LockTime::Blocks(blocks) =>
261+
blocks.is_satisfied_by(chain_tip_height, utxo_mined_at_height),
262+
LockTime::Time(time) => time.is_satisfied_by(chain_tip_mtp, utxo_mined_at_mtp),
259263
}
260264
}
261265

@@ -695,38 +699,55 @@ mod tests {
695699
let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200);
696700
let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
697701

698-
let chain_tip = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
699-
let utxo_mined_at = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
702+
let chain_height = BlockHeight::from_u32(100);
703+
let chain_mtp = BlockMtp::new(timestamps);
704+
let utxo_height = BlockHeight::from_u32(80);
705+
let utxo_mtp = BlockMtp::new(utxo_timestamps);
700706

701707
let lock1 = LockTime::Blocks(HeightInterval::from(10));
702-
assert!(lock1.is_satisfied_by(chain_tip, utxo_mined_at));
708+
assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
703709

704710
let lock2 = LockTime::Blocks(HeightInterval::from(21));
705-
assert!(!lock2.is_satisfied_by(chain_tip, utxo_mined_at));
711+
assert!(!lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
706712

707713
let lock3 = LockTime::Time(MtpInterval::from_512_second_intervals(10));
708-
assert!(lock3.is_satisfied_by(chain_tip, utxo_mined_at));
714+
assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
709715

710716
let lock4 = LockTime::Time(MtpInterval::from_512_second_intervals(20000));
711-
assert!(!lock4.is_satisfied_by(chain_tip, utxo_mined_at));
717+
assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
712718

713-
assert!(LockTime::ZERO.is_satisfied_by(chain_tip, utxo_mined_at));
714-
assert!(LockTime::from_512_second_intervals(0).is_satisfied_by(chain_tip, utxo_mined_at));
719+
assert!(LockTime::ZERO.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
720+
assert!(LockTime::from_512_second_intervals(0).is_satisfied_by(
721+
chain_height,
722+
chain_mtp,
723+
utxo_height,
724+
utxo_mtp
725+
));
715726

716727
let lock6 = LockTime::from_seconds_floor(5000).unwrap();
717-
assert!(lock6.is_satisfied_by(chain_tip, utxo_mined_at));
728+
assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
718729

719730
let max_height_lock = LockTime::Blocks(HeightInterval::MAX);
720-
assert!(!max_height_lock.is_satisfied_by(chain_tip, utxo_mined_at));
731+
assert!(!max_height_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
721732

722733
let max_time_lock = LockTime::Time(MtpInterval::MAX);
723-
assert!(!max_time_lock.is_satisfied_by(chain_tip, utxo_mined_at));
724-
725-
let max_chain_tip =
726-
MtpAndHeight::new(BlockHeight::from_u32(u32::MAX), generate_timestamps(u32::MAX, 100));
727-
let max_utxo_mined_at =
728-
MtpAndHeight::new(BlockHeight::MAX, generate_timestamps(u32::MAX, 100));
729-
assert!(!max_height_lock.is_satisfied_by(max_chain_tip, max_utxo_mined_at));
730-
assert!(!max_time_lock.is_satisfied_by(max_chain_tip, max_utxo_mined_at));
734+
assert!(!max_time_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
735+
736+
let max_chain_height = BlockHeight::from_u32(u32::MAX);
737+
let max_chain_mtp = BlockMtp::new(generate_timestamps(u32::MAX, 100));
738+
let max_utxo_height = BlockHeight::MAX;
739+
let max_utxo_mtp = max_chain_mtp;
740+
assert!(!max_height_lock.is_satisfied_by(
741+
max_chain_height,
742+
max_chain_mtp,
743+
max_utxo_height,
744+
max_utxo_mtp
745+
));
746+
assert!(!max_time_lock.is_satisfied_by(
747+
max_chain_height,
748+
max_chain_mtp,
749+
max_utxo_height,
750+
max_utxo_mtp
751+
));
731752
}
732753
}

0 commit comments

Comments
 (0)