69 lines
2.2 KiB
Rust
69 lines
2.2 KiB
Rust
// SPDX-License-Identifier: CC0-1.0
|
||
|
||
//! Median Time Past (MTP) and height - used for working lock times.
|
||
|
||
use crate::{BlockHeight, BlockTime};
|
||
|
||
/// A structure containing both Median Time Past (MTP) and current
|
||
/// absolute block height, used for validating relative locktimes.
|
||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||
pub struct MtpAndHeight {
|
||
/// The Median Time Past (median of the last 11 blocks' timestamps)
|
||
mtp: BlockTime,
|
||
/// The current block height,
|
||
height: BlockHeight,
|
||
}
|
||
|
||
impl MtpAndHeight {
|
||
/// Constructs an [`MtpAndHeight`] by computing the median‐time‐past from the last 11 block timestamps
|
||
///
|
||
/// # Parameters
|
||
///
|
||
/// * `height` - The absolute height of the chain tip
|
||
/// * `timestamps` - An array of timestamps from the most recent 11 blocks, where
|
||
/// - `timestamps[0]` is the timestamp at height `height - 10`
|
||
/// - `timestamps[1]` is the timestamp at height `height - 9`
|
||
/// - …
|
||
/// - `timestamps[10]` is the timestamp at height `height`
|
||
pub fn new(height: BlockHeight, timestamps: [BlockTime; 11]) -> Self {
|
||
let mut mtp_timestamps = timestamps;
|
||
mtp_timestamps.sort_unstable();
|
||
let mtp = mtp_timestamps[5];
|
||
|
||
MtpAndHeight { mtp, height }
|
||
}
|
||
|
||
/// Returns the median-time-past component.
|
||
pub fn to_mtp(self) -> BlockTime { self.mtp }
|
||
|
||
/// Returns the block-height component.
|
||
pub fn to_height(self) -> BlockHeight { self.height }
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn valid_chain_computes_mtp() {
|
||
let height = BlockHeight::from_u32(100);
|
||
let timestamps = [
|
||
BlockTime::from_u32(10),
|
||
BlockTime::from_u32(3),
|
||
BlockTime::from_u32(5),
|
||
BlockTime::from_u32(8),
|
||
BlockTime::from_u32(1),
|
||
BlockTime::from_u32(4),
|
||
BlockTime::from_u32(6),
|
||
BlockTime::from_u32(9),
|
||
BlockTime::from_u32(2),
|
||
BlockTime::from_u32(7),
|
||
BlockTime::from_u32(0),
|
||
];
|
||
|
||
let result = MtpAndHeight::new(height, timestamps);
|
||
assert_eq!(result.height, height);
|
||
assert_eq!(result.mtp.to_u32(), 5);
|
||
}
|
||
}
|