chain: rename BlockHeight to block::Height
This commit is contained in:
parent
61dea90e2f
commit
103b663c40
|
@ -13,7 +13,7 @@ mod tests;
|
|||
|
||||
pub use hash::Hash;
|
||||
pub use header::BlockHeader;
|
||||
pub use height::BlockHeight;
|
||||
pub use height::Height;
|
||||
pub use root_hash::RootHash;
|
||||
|
||||
/// The error type for Block checks.
|
||||
|
@ -45,7 +45,7 @@ pub struct Block {
|
|||
|
||||
impl Block {
|
||||
/// Return the block height reported in the coinbase transaction, if any.
|
||||
pub fn coinbase_height(&self) -> Option<BlockHeight> {
|
||||
pub fn coinbase_height(&self) -> Option<Height> {
|
||||
use crate::transaction::TransparentInput;
|
||||
self.transactions
|
||||
.get(0)
|
||||
|
|
|
@ -6,13 +6,13 @@ use crate::serialization::SerializationError;
|
|||
///
|
||||
/// Users should not construct block heights greater than `BlockHeight::MAX`.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct BlockHeight(pub u32);
|
||||
pub struct Height(pub u32);
|
||||
|
||||
impl std::str::FromStr for BlockHeight {
|
||||
impl std::str::FromStr for Height {
|
||||
type Err = SerializationError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.parse() {
|
||||
Ok(h) if (BlockHeight(h) <= BlockHeight::MAX) => Ok(BlockHeight(h)),
|
||||
Ok(h) if (Height(h) <= Height::MAX) => Ok(Height(h)),
|
||||
Ok(_) => Err(SerializationError::Parse(
|
||||
"BlockHeight exceeds maximum height",
|
||||
)),
|
||||
|
@ -23,7 +23,7 @@ impl std::str::FromStr for BlockHeight {
|
|||
}
|
||||
}
|
||||
|
||||
impl BlockHeight {
|
||||
impl Height {
|
||||
/// The minimum BlockHeight.
|
||||
///
|
||||
/// Due to the underlying type, it is impossible to construct block heights
|
||||
|
@ -31,12 +31,12 @@ impl BlockHeight {
|
|||
///
|
||||
/// Style note: Sometimes, `BlockHeight::MIN` is less readable than
|
||||
/// `BlockHeight(0)`. Use whichever makes sense in context.
|
||||
pub const MIN: BlockHeight = BlockHeight(0);
|
||||
pub const MIN: Height = Height(0);
|
||||
|
||||
/// The maximum BlockHeight.
|
||||
///
|
||||
/// Users should not construct block heights greater than `BlockHeight::MAX`.
|
||||
pub const MAX: BlockHeight = BlockHeight(499_999_999);
|
||||
pub const MAX: Height = Height(499_999_999);
|
||||
|
||||
/// The maximum BlockHeight as a u32, for range patterns.
|
||||
///
|
||||
|
@ -48,13 +48,11 @@ impl BlockHeight {
|
|||
#[cfg(test)]
|
||||
use proptest::prelude::*;
|
||||
#[cfg(test)]
|
||||
impl Arbitrary for BlockHeight {
|
||||
impl Arbitrary for Height {
|
||||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: ()) -> Self::Strategy {
|
||||
(BlockHeight::MIN.0..=BlockHeight::MAX.0)
|
||||
.prop_map(BlockHeight)
|
||||
.boxed()
|
||||
(Height::MIN.0..=Height::MAX.0).prop_map(Height).boxed()
|
||||
}
|
||||
|
||||
type Strategy = BoxedStrategy<Self>;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use crate::parameters::{Network, NetworkUpgrade, NetworkUpgrade::*};
|
||||
use crate::sapling::tree::SaplingNoteTreeRootHash;
|
||||
|
||||
use super::BlockHeight;
|
||||
use super::Height;
|
||||
|
||||
/// Zcash blocks contain different kinds of root hashes, depending on the network upgrade.
|
||||
///
|
||||
|
@ -46,7 +46,7 @@ pub enum RootHash {
|
|||
impl RootHash {
|
||||
/// Returns `bytes` as the LightClientRootHash variant for `network` and
|
||||
/// `height`.
|
||||
pub(super) fn from_bytes(bytes: [u8; 32], network: Network, height: BlockHeight) -> RootHash {
|
||||
pub(super) fn from_bytes(bytes: [u8; 32], network: Network, height: Height) -> RootHash {
|
||||
use RootHash::*;
|
||||
|
||||
match NetworkUpgrade::current(network, height) {
|
||||
|
|
|
@ -13,7 +13,7 @@ impl Arbitrary for RootHash {
|
|||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: ()) -> Self::Strategy {
|
||||
(any::<[u8; 32]>(), any::<Network>(), any::<BlockHeight>())
|
||||
(any::<[u8; 32]>(), any::<Network>(), any::<Height>())
|
||||
.prop_map(|(root_bytes, network, block_height)| {
|
||||
RootHash::from_bytes(root_bytes, network, block_height)
|
||||
})
|
||||
|
|
|
@ -26,7 +26,11 @@ proptest! {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn root_hash_roundtrip(bytes in any::<[u8; 32]>(), network in any::<Network>(), block_height in any::<BlockHeight>()) {
|
||||
fn root_hash_roundtrip(
|
||||
bytes in any::<[u8; 32]>(),
|
||||
network in any::<Network>(),
|
||||
block_height in any::<Height>()
|
||||
) {
|
||||
let root_hash = RootHash::from_bytes(bytes, network, block_height);
|
||||
let other_bytes = root_hash.to_bytes();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use NetworkUpgrade::*;
|
||||
|
||||
use crate::block::BlockHeight;
|
||||
use crate::block;
|
||||
use crate::parameters::{Network, Network::*};
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
@ -41,30 +41,30 @@ pub enum NetworkUpgrade {
|
|||
///
|
||||
/// This is actually a bijective map, but it is const, so we use a vector, and
|
||||
/// do the uniqueness check in the unit tests.
|
||||
pub(crate) const MAINNET_ACTIVATION_HEIGHTS: &[(BlockHeight, NetworkUpgrade)] = &[
|
||||
(BlockHeight(0), Genesis),
|
||||
(BlockHeight(1), BeforeOverwinter),
|
||||
(BlockHeight(347_500), Overwinter),
|
||||
(BlockHeight(419_200), Sapling),
|
||||
(BlockHeight(653_600), Blossom),
|
||||
(BlockHeight(903_000), Heartwood),
|
||||
(BlockHeight(1_046_400), Canopy),
|
||||
pub(crate) const MAINNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
|
||||
(block::Height(0), Genesis),
|
||||
(block::Height(1), BeforeOverwinter),
|
||||
(block::Height(347_500), Overwinter),
|
||||
(block::Height(419_200), Sapling),
|
||||
(block::Height(653_600), Blossom),
|
||||
(block::Height(903_000), Heartwood),
|
||||
(block::Height(1_046_400), Canopy),
|
||||
];
|
||||
|
||||
/// Testnet network upgrade activation heights.
|
||||
///
|
||||
/// This is actually a bijective map, but it is const, so we use a vector, and
|
||||
/// do the uniqueness check in the unit tests.
|
||||
pub(crate) const TESTNET_ACTIVATION_HEIGHTS: &[(BlockHeight, NetworkUpgrade)] = &[
|
||||
(BlockHeight(0), Genesis),
|
||||
(BlockHeight(1), BeforeOverwinter),
|
||||
(BlockHeight(207_500), Overwinter),
|
||||
(BlockHeight(280_000), Sapling),
|
||||
(BlockHeight(584_000), Blossom),
|
||||
(BlockHeight(903_800), Heartwood),
|
||||
pub(crate) const TESTNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
|
||||
(block::Height(0), Genesis),
|
||||
(block::Height(1), BeforeOverwinter),
|
||||
(block::Height(207_500), Overwinter),
|
||||
(block::Height(280_000), Sapling),
|
||||
(block::Height(584_000), Blossom),
|
||||
(block::Height(903_800), Heartwood),
|
||||
// As of 27 July 2020, the Canopy testnet height is under final review.
|
||||
// See ZIP 251 for any updates.
|
||||
(BlockHeight(1_028_500), Canopy),
|
||||
(block::Height(1_028_500), Canopy),
|
||||
];
|
||||
|
||||
/// The Consensus Branch Id, used to bind transactions and blocks to a
|
||||
|
@ -101,7 +101,7 @@ impl NetworkUpgrade {
|
|||
/// network upgrade does not appear in the list.
|
||||
///
|
||||
/// This is actually a bijective map.
|
||||
pub(crate) fn activation_list(network: Network) -> BTreeMap<BlockHeight, NetworkUpgrade> {
|
||||
pub(crate) fn activation_list(network: Network) -> BTreeMap<block::Height, NetworkUpgrade> {
|
||||
match network {
|
||||
Mainnet => MAINNET_ACTIVATION_HEIGHTS,
|
||||
Testnet => TESTNET_ACTIVATION_HEIGHTS,
|
||||
|
@ -112,7 +112,7 @@ impl NetworkUpgrade {
|
|||
}
|
||||
|
||||
/// Returns the current network upgrade for `network` and `height`.
|
||||
pub fn current(network: Network, height: BlockHeight) -> NetworkUpgrade {
|
||||
pub fn current(network: Network, height: block::Height) -> NetworkUpgrade {
|
||||
NetworkUpgrade::activation_list(network)
|
||||
.range(..=height)
|
||||
.map(|(_, nu)| *nu)
|
||||
|
@ -123,7 +123,7 @@ impl NetworkUpgrade {
|
|||
/// Returns the next network upgrade for `network` and `height`.
|
||||
///
|
||||
/// Returns None if the name of the next upgrade has not been decided yet.
|
||||
pub fn next(network: Network, height: BlockHeight) -> Option<NetworkUpgrade> {
|
||||
pub fn next(network: Network, height: block::Height) -> Option<NetworkUpgrade> {
|
||||
NetworkUpgrade::activation_list(network)
|
||||
.range((Excluded(height), Unbounded))
|
||||
.map(|(_, nu)| *nu)
|
||||
|
@ -134,7 +134,7 @@ impl NetworkUpgrade {
|
|||
///
|
||||
/// Returns None if this network upgrade is a future upgrade, and its
|
||||
/// activation height has not been set yet.
|
||||
pub fn activation_height(&self, network: Network) -> Option<BlockHeight> {
|
||||
pub fn activation_height(&self, network: Network) -> Option<block::Height> {
|
||||
NetworkUpgrade::activation_list(network)
|
||||
.iter()
|
||||
.filter(|(_, nu)| nu == &self)
|
||||
|
@ -166,7 +166,7 @@ impl ConsensusBranchId {
|
|||
/// Returns the current consensus branch id for `network` and `height`.
|
||||
///
|
||||
/// Returns None if the network has no branch id at this height.
|
||||
pub fn current(network: Network, height: BlockHeight) -> Option<ConsensusBranchId> {
|
||||
pub fn current(network: Network, height: block::Height) -> Option<ConsensusBranchId> {
|
||||
NetworkUpgrade::current(network, height).branch_id()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::block::BlockHeight;
|
||||
use crate::block;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -13,14 +13,14 @@ use NetworkUpgrade::*;
|
|||
#[test]
|
||||
fn activation_bijective() {
|
||||
let mainnet_activations = NetworkUpgrade::activation_list(Mainnet);
|
||||
let mainnet_heights: HashSet<&BlockHeight> = mainnet_activations.keys().collect();
|
||||
let mainnet_heights: HashSet<&block::Height> = mainnet_activations.keys().collect();
|
||||
assert_eq!(MAINNET_ACTIVATION_HEIGHTS.len(), mainnet_heights.len());
|
||||
|
||||
let mainnet_nus: HashSet<&NetworkUpgrade> = mainnet_activations.values().collect();
|
||||
assert_eq!(MAINNET_ACTIVATION_HEIGHTS.len(), mainnet_nus.len());
|
||||
|
||||
let testnet_activations = NetworkUpgrade::activation_list(Testnet);
|
||||
let testnet_heights: HashSet<&BlockHeight> = testnet_activations.keys().collect();
|
||||
let testnet_heights: HashSet<&block::Height> = testnet_activations.keys().collect();
|
||||
assert_eq!(TESTNET_ACTIVATION_HEIGHTS.len(), testnet_heights.len());
|
||||
|
||||
let testnet_nus: HashSet<&NetworkUpgrade> = testnet_activations.values().collect();
|
||||
|
@ -42,41 +42,44 @@ fn activation_extremes_testnet() {
|
|||
fn activation_extremes(network: Network) {
|
||||
// The first three upgrades are Genesis, BeforeOverwinter, and Overwinter
|
||||
assert_eq!(
|
||||
NetworkUpgrade::activation_list(network).get(&BlockHeight(0)),
|
||||
NetworkUpgrade::activation_list(network).get(&block::Height(0)),
|
||||
Some(&Genesis)
|
||||
);
|
||||
assert_eq!(Genesis.activation_height(network), Some(BlockHeight(0)));
|
||||
assert_eq!(NetworkUpgrade::current(network, BlockHeight(0)), Genesis);
|
||||
assert_eq!(Genesis.activation_height(network), Some(block::Height(0)));
|
||||
assert_eq!(NetworkUpgrade::current(network, block::Height(0)), Genesis);
|
||||
assert_eq!(
|
||||
NetworkUpgrade::next(network, BlockHeight(0)),
|
||||
NetworkUpgrade::next(network, block::Height(0)),
|
||||
Some(BeforeOverwinter)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
NetworkUpgrade::activation_list(network).get(&BlockHeight(1)),
|
||||
NetworkUpgrade::activation_list(network).get(&block::Height(1)),
|
||||
Some(&BeforeOverwinter)
|
||||
);
|
||||
assert_eq!(
|
||||
BeforeOverwinter.activation_height(network),
|
||||
Some(BlockHeight(1))
|
||||
Some(block::Height(1))
|
||||
);
|
||||
assert_eq!(
|
||||
NetworkUpgrade::current(network, BlockHeight(1)),
|
||||
NetworkUpgrade::current(network, block::Height(1)),
|
||||
BeforeOverwinter
|
||||
);
|
||||
assert_eq!(
|
||||
NetworkUpgrade::next(network, BlockHeight(1)),
|
||||
NetworkUpgrade::next(network, block::Height(1)),
|
||||
Some(Overwinter)
|
||||
);
|
||||
|
||||
// We assume that the last upgrade we know about continues forever
|
||||
// (even if we suspect that won't be true)
|
||||
assert_ne!(
|
||||
NetworkUpgrade::activation_list(network).get(&BlockHeight::MAX),
|
||||
NetworkUpgrade::activation_list(network).get(&block::Height::MAX),
|
||||
Some(&Genesis)
|
||||
);
|
||||
assert_ne!(NetworkUpgrade::current(network, BlockHeight::MAX), Genesis);
|
||||
assert_eq!(NetworkUpgrade::next(network, BlockHeight::MAX), None);
|
||||
assert_ne!(
|
||||
NetworkUpgrade::current(network, block::Height::MAX),
|
||||
Genesis
|
||||
);
|
||||
assert_eq!(NetworkUpgrade::next(network, block::Height::MAX), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -103,11 +106,11 @@ fn activation_consistent(network: Network) {
|
|||
// Network upgrades don't repeat
|
||||
assert_ne!(NetworkUpgrade::next(network, height), Some(network_upgrade));
|
||||
assert_ne!(
|
||||
NetworkUpgrade::next(network, BlockHeight(height.0 + 1)),
|
||||
NetworkUpgrade::next(network, block::Height(height.0 + 1)),
|
||||
Some(network_upgrade)
|
||||
);
|
||||
assert_ne!(
|
||||
NetworkUpgrade::next(network, BlockHeight::MAX),
|
||||
NetworkUpgrade::next(network, block::Height::MAX),
|
||||
Some(network_upgrade)
|
||||
);
|
||||
}
|
||||
|
@ -142,7 +145,7 @@ fn branch_id_extremes(network: Network) {
|
|||
NetworkUpgrade::branch_id_list().get(&BeforeOverwinter),
|
||||
None
|
||||
);
|
||||
assert_eq!(ConsensusBranchId::current(network, BlockHeight(0)), None);
|
||||
assert_eq!(ConsensusBranchId::current(network, block::Height(0)), None);
|
||||
assert_eq!(
|
||||
NetworkUpgrade::branch_id_list().get(&Overwinter).cloned(),
|
||||
Overwinter.branch_id()
|
||||
|
@ -151,10 +154,13 @@ fn branch_id_extremes(network: Network) {
|
|||
// We assume that the last upgrade we know about continues forever
|
||||
// (even if we suspect that won't be true)
|
||||
assert_ne!(
|
||||
NetworkUpgrade::branch_id_list().get(&NetworkUpgrade::current(network, BlockHeight::MAX)),
|
||||
NetworkUpgrade::branch_id_list().get(&NetworkUpgrade::current(network, block::Height::MAX)),
|
||||
None
|
||||
);
|
||||
assert_ne!(
|
||||
ConsensusBranchId::current(network, block::Height::MAX),
|
||||
None
|
||||
);
|
||||
assert_ne!(ConsensusBranchId::current(network, BlockHeight::MAX), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -21,7 +21,7 @@ pub use shielded_data::{Output, ShieldedData, Spend};
|
|||
pub use transparent::{CoinbaseData, OutPoint, TransparentInput, TransparentOutput};
|
||||
|
||||
use crate::amount::Amount;
|
||||
use crate::block::BlockHeight;
|
||||
use crate::block;
|
||||
use crate::primitives::{Bctv14Proof, Groth16Proof};
|
||||
|
||||
/// A Zcash transaction.
|
||||
|
@ -71,7 +71,7 @@ pub enum Transaction {
|
|||
/// chain.
|
||||
lock_time: LockTime,
|
||||
/// The latest block height that this transaction can be added to the chain.
|
||||
expiry_height: BlockHeight,
|
||||
expiry_height: block::Height,
|
||||
/// The JoinSplit data for this transaction, if any.
|
||||
joinsplit_data: Option<JoinSplitData<Bctv14Proof>>,
|
||||
},
|
||||
|
@ -85,7 +85,7 @@ pub enum Transaction {
|
|||
/// chain.
|
||||
lock_time: LockTime,
|
||||
/// The latest block height that this transaction can be added to the chain.
|
||||
expiry_height: BlockHeight,
|
||||
expiry_height: block::Height,
|
||||
/// The net value of Sapling spend transfers minus output transfers.
|
||||
value_balance: Amount,
|
||||
/// The shielded data for this transaction, if any.
|
||||
|
@ -127,7 +127,7 @@ impl Transaction {
|
|||
}
|
||||
|
||||
/// Get this transaction's expiry height, if any.
|
||||
pub fn expiry_height(&self) -> Option<BlockHeight> {
|
||||
pub fn expiry_height(&self) -> Option<block::Height> {
|
||||
match self {
|
||||
Transaction::V1 { .. } => None,
|
||||
Transaction::V2 { .. } => None,
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::io;
|
|||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
|
||||
use crate::block::BlockHeight;
|
||||
use crate::block;
|
||||
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
||||
|
||||
/// A Bitcoin-style `locktime`, representing either a block height or an epoch
|
||||
|
@ -20,7 +20,7 @@ use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LockTime {
|
||||
/// Unlock at a particular block height.
|
||||
Height(BlockHeight),
|
||||
Height(block::Height),
|
||||
/// Unlock at a particular time.
|
||||
Time(DateTime<Utc>),
|
||||
}
|
||||
|
@ -63,10 +63,9 @@ impl ZcashSerialize for LockTime {
|
|||
// This implementation does not check the invariants on `LockTime` so that the
|
||||
// serialization is fallible only if the underlying writer is. This ensures that
|
||||
// we can always compute a hash of a transaction object.
|
||||
use LockTime::*;
|
||||
match self {
|
||||
Height(BlockHeight(n)) => writer.write_u32::<LittleEndian>(*n)?,
|
||||
Time(t) => writer.write_u32::<LittleEndian>(t.timestamp() as u32)?,
|
||||
LockTime::Height(block::Height(n)) => writer.write_u32::<LittleEndian>(*n)?,
|
||||
LockTime::Time(t) => writer.write_u32::<LittleEndian>(t.timestamp() as u32)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -75,8 +74,8 @@ impl ZcashSerialize for LockTime {
|
|||
impl ZcashDeserialize for LockTime {
|
||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||
let n = reader.read_u32::<LittleEndian>()?;
|
||||
if n <= BlockHeight::MAX.0 {
|
||||
Ok(LockTime::Height(BlockHeight(n)))
|
||||
if n <= block::Height::MAX.0 {
|
||||
Ok(LockTime::Height(block::Height(n)))
|
||||
} else {
|
||||
Ok(LockTime::Time(Utc.timestamp(n as i64, 0)))
|
||||
}
|
||||
|
|
|
@ -72,35 +72,36 @@ impl ZcashDeserialize for OutPoint {
|
|||
|
||||
fn parse_coinbase_height(
|
||||
mut data: Vec<u8>,
|
||||
) -> Result<(BlockHeight, CoinbaseData), SerializationError> {
|
||||
) -> Result<(block::Height, CoinbaseData), SerializationError> {
|
||||
use block::Height;
|
||||
match (data.get(0), data.len()) {
|
||||
// Blocks 1 through 16 inclusive encode block height with OP_N opcodes.
|
||||
(Some(op_n @ 0x51..=0x60), len) if len >= 1 => Ok((
|
||||
BlockHeight((op_n - 0x50) as u32),
|
||||
Height((op_n - 0x50) as u32),
|
||||
CoinbaseData(data.split_off(1)),
|
||||
)),
|
||||
// Blocks 17 through 256 exclusive encode block height with the `0x01` opcode.
|
||||
(Some(0x01), len) if len >= 2 => {
|
||||
Ok((BlockHeight(data[1] as u32), CoinbaseData(data.split_off(2))))
|
||||
Ok((Height(data[1] as u32), CoinbaseData(data.split_off(2))))
|
||||
}
|
||||
// Blocks 256 through 65536 exclusive encode block height with the `0x02` opcode.
|
||||
(Some(0x02), len) if len >= 3 => Ok((
|
||||
BlockHeight(data[1] as u32 + ((data[2] as u32) << 8)),
|
||||
Height(data[1] as u32 + ((data[2] as u32) << 8)),
|
||||
CoinbaseData(data.split_off(3)),
|
||||
)),
|
||||
// Blocks 65536 through 2**24 exclusive encode block height with the `0x03` opcode.
|
||||
(Some(0x03), len) if len >= 4 => Ok((
|
||||
BlockHeight(data[1] as u32 + ((data[2] as u32) << 8) + ((data[3] as u32) << 16)),
|
||||
Height(data[1] as u32 + ((data[2] as u32) << 8) + ((data[3] as u32) << 16)),
|
||||
CoinbaseData(data.split_off(4)),
|
||||
)),
|
||||
// The genesis block does not encode the block height by mistake; special case it.
|
||||
// The first five bytes are [4, 255, 255, 7, 31], the little-endian encoding of
|
||||
// 520_617_983. This is lucky because it means we can special-case the genesis block
|
||||
// while remaining below the maximum `BlockHeight` of 500_000_000 forced by `LockTime`.
|
||||
// while remaining below the maximum `block::Height` of 500_000_000 forced by `LockTime`.
|
||||
// While it's unlikely this code will ever process a block height that high, this means
|
||||
// we don't need to maintain a cascade of different invariants for allowable `BlockHeight`s.
|
||||
// we don't need to maintain a cascade of different invariants for allowable heights.
|
||||
(Some(0x04), _) if data[..] == GENESIS_COINBASE_DATA[..] => {
|
||||
Ok((BlockHeight(0), CoinbaseData(data)))
|
||||
Ok((Height(0), CoinbaseData(data)))
|
||||
}
|
||||
// As noted above, this is included for completeness.
|
||||
(Some(0x04), len) if len >= 5 => {
|
||||
|
@ -108,8 +109,8 @@ fn parse_coinbase_height(
|
|||
+ ((data[2] as u32) << 8)
|
||||
+ ((data[3] as u32) << 16)
|
||||
+ ((data[4] as u32) << 24);
|
||||
if h <= BlockHeight::MAX.0 {
|
||||
Ok((BlockHeight(h), CoinbaseData(data.split_off(5))))
|
||||
if h <= Height::MAX.0 {
|
||||
Ok((Height(h), CoinbaseData(data.split_off(5))))
|
||||
} else {
|
||||
Err(SerializationError::Parse("Invalid block height"))
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ fn parse_coinbase_height(
|
|||
}
|
||||
}
|
||||
|
||||
fn coinbase_height_len(height: BlockHeight) -> usize {
|
||||
fn coinbase_height_len(height: block::Height) -> usize {
|
||||
// We can't write this as a match statement on stable until exclusive range
|
||||
// guards are stabilized.
|
||||
if let 0 = height.0 {
|
||||
|
@ -133,14 +134,14 @@ fn coinbase_height_len(height: BlockHeight) -> usize {
|
|||
3
|
||||
} else if let _h @ 65536..=16_777_215 = height.0 {
|
||||
4
|
||||
} else if let _h @ 16_777_216..=BlockHeight::MAX_AS_U32 = height.0 {
|
||||
} else if let _h @ 16_777_216..=block::Height::MAX_AS_U32 = height.0 {
|
||||
5
|
||||
} else {
|
||||
panic!("Invalid coinbase height");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_coinbase_height<W: io::Write>(height: BlockHeight, mut w: W) -> Result<(), io::Error> {
|
||||
fn write_coinbase_height<W: io::Write>(height: block::Height, mut w: W) -> Result<(), io::Error> {
|
||||
// We can't write this as a match statement on stable until exclusive range
|
||||
// guards are stabilized.
|
||||
if let 0 = height.0 {
|
||||
|
@ -158,7 +159,7 @@ fn write_coinbase_height<W: io::Write>(height: BlockHeight, mut w: W) -> Result<
|
|||
w.write_u8(h as u8)?;
|
||||
w.write_u8((h >> 8) as u8)?;
|
||||
w.write_u8((h >> 16) as u8)?;
|
||||
} else if let h @ 16_777_216..=BlockHeight::MAX_AS_U32 = height.0 {
|
||||
} else if let h @ 16_777_216..=block::Height::MAX_AS_U32 = height.0 {
|
||||
w.write_u8(0x04)?;
|
||||
w.write_u32::<LittleEndian>(h)?;
|
||||
} else {
|
||||
|
@ -549,7 +550,7 @@ impl ZcashDeserialize for Transaction {
|
|||
inputs: Vec::zcash_deserialize(&mut reader)?,
|
||||
outputs: Vec::zcash_deserialize(&mut reader)?,
|
||||
lock_time: LockTime::zcash_deserialize(&mut reader)?,
|
||||
expiry_height: BlockHeight(reader.read_u32::<LittleEndian>()?),
|
||||
expiry_height: block::Height(reader.read_u32::<LittleEndian>()?),
|
||||
joinsplit_data: OptV3JSD::zcash_deserialize(&mut reader)?,
|
||||
})
|
||||
}
|
||||
|
@ -574,7 +575,7 @@ impl ZcashDeserialize for Transaction {
|
|||
let inputs = Vec::zcash_deserialize(&mut reader)?;
|
||||
let outputs = Vec::zcash_deserialize(&mut reader)?;
|
||||
let lock_time = LockTime::zcash_deserialize(&mut reader)?;
|
||||
let expiry_height = BlockHeight(reader.read_u32::<LittleEndian>()?);
|
||||
let expiry_height = block::Height(reader.read_u32::<LittleEndian>()?);
|
||||
let value_balance = reader.read_i64::<LittleEndian>()?.try_into()?;
|
||||
let mut shielded_spends = Vec::zcash_deserialize(&mut reader)?;
|
||||
let mut shielded_outputs = Vec::zcash_deserialize(&mut reader)?;
|
||||
|
|
|
@ -4,7 +4,7 @@ use proptest::{arbitrary::any, array, collection::vec, option, prelude::*};
|
|||
|
||||
use crate::{
|
||||
amount::{Amount, NonNegative},
|
||||
block::BlockHeight,
|
||||
block,
|
||||
primitives::{Bctv14Proof, Groth16Proof, Script, ZkSnarkProof},
|
||||
sapling, sprout,
|
||||
};
|
||||
|
@ -52,7 +52,7 @@ impl Transaction {
|
|||
vec(any::<TransparentInput>(), 0..10),
|
||||
vec(any::<TransparentOutput>(), 0..10),
|
||||
any::<LockTime>(),
|
||||
any::<BlockHeight>(),
|
||||
any::<block::Height>(),
|
||||
option::of(any::<JoinSplitData<Bctv14Proof>>()),
|
||||
)
|
||||
.prop_map(
|
||||
|
@ -72,7 +72,7 @@ impl Transaction {
|
|||
vec(any::<TransparentInput>(), 0..10),
|
||||
vec(any::<TransparentOutput>(), 0..10),
|
||||
any::<LockTime>(),
|
||||
any::<BlockHeight>(),
|
||||
any::<block::Height>(),
|
||||
any::<Amount>(),
|
||||
option::of(any::<ShieldedData>()),
|
||||
option::of(any::<JoinSplitData<Groth16Proof>>()),
|
||||
|
@ -121,8 +121,8 @@ impl Arbitrary for LockTime {
|
|||
|
||||
fn arbitrary_with(_args: ()) -> Self::Strategy {
|
||||
prop_oneof![
|
||||
(BlockHeight::MIN.0..=BlockHeight::MAX.0)
|
||||
.prop_map(|n| LockTime::Height(BlockHeight(n))),
|
||||
(block::Height::MIN.0..=block::Height::MAX.0)
|
||||
.prop_map(|n| LockTime::Height(block::Height(n))),
|
||||
(LockTime::MIN_TIMESTAMP..=LockTime::MAX_TIMESTAMP)
|
||||
.prop_map(|n| { LockTime::Time(Utc.timestamp(n as i64, 0)) })
|
||||
]
|
||||
|
@ -326,7 +326,11 @@ impl Arbitrary for TransparentInput {
|
|||
}
|
||||
})
|
||||
.boxed(),
|
||||
(any::<BlockHeight>(), vec(any::<u8>(), 0..95), any::<u32>())
|
||||
(
|
||||
any::<block::Height>(),
|
||||
vec(any::<u8>(), 0..95),
|
||||
any::<u32>()
|
||||
)
|
||||
.prop_map(|(height, data, sequence)| {
|
||||
TransparentInput::Coinbase {
|
||||
height,
|
||||
|
|
|
@ -6,7 +6,7 @@ use proptest_derive::Arbitrary;
|
|||
|
||||
use crate::{
|
||||
amount::{Amount, NonNegative},
|
||||
block::BlockHeight,
|
||||
block,
|
||||
primitives::Script,
|
||||
};
|
||||
|
||||
|
@ -59,7 +59,7 @@ pub enum TransparentInput {
|
|||
/// New coins created by the block reward.
|
||||
Coinbase {
|
||||
/// The height of this block.
|
||||
height: BlockHeight,
|
||||
height: block::Height,
|
||||
/// Free data inserted by miners after the block height.
|
||||
data: CoinbaseData,
|
||||
/// The sequence number for the output.
|
||||
|
|
|
@ -25,8 +25,7 @@ use std::{
|
|||
use tokio::time;
|
||||
use tower::{buffer::Buffer, Service, ServiceExt};
|
||||
|
||||
use zebra_chain::block::BlockHeight;
|
||||
use zebra_chain::block::{Block, self};
|
||||
use zebra_chain::block::{self, Block};
|
||||
|
||||
/// A service that verifies blocks.
|
||||
#[derive(Debug)]
|
||||
|
@ -84,7 +83,7 @@ where
|
|||
let height = block
|
||||
.coinbase_height()
|
||||
.ok_or("Invalid block: missing block height.")?;
|
||||
if height > BlockHeight::MAX {
|
||||
if height > block::Height::MAX {
|
||||
Err("Invalid block height: greater than the maximum height.")?;
|
||||
}
|
||||
|
||||
|
@ -126,7 +125,7 @@ where
|
|||
let previous_block = BlockVerifier::await_block(
|
||||
&mut state,
|
||||
previous_block_hash,
|
||||
BlockHeight(height.0 - 1),
|
||||
block::Height(height.0 - 1),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
@ -180,7 +179,7 @@ where
|
|||
async fn await_block(
|
||||
state: &mut S,
|
||||
hash: block::Hash,
|
||||
height: BlockHeight,
|
||||
height: block::Height,
|
||||
) -> Result<Arc<Block>, Report> {
|
||||
loop {
|
||||
match BlockVerifier::get_block(state, hash).await? {
|
||||
|
|
|
@ -6,8 +6,8 @@ use chrono::Utc;
|
|||
use color_eyre::eyre::{eyre, Report};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use zebra_chain::block::{Block, self};
|
||||
use zebra_chain::block::BlockHeader;
|
||||
use zebra_chain::block::{self, Block};
|
||||
use zebra_chain::serialization::{ZcashDeserialize, ZcashDeserializeInto};
|
||||
use zebra_test::transcript::{TransError, Transcript};
|
||||
|
||||
|
|
|
@ -27,8 +27,7 @@ use std::{
|
|||
use tower::{buffer::Buffer, Service, ServiceExt};
|
||||
use tracing_futures::Instrument;
|
||||
|
||||
use zebra_chain::block::BlockHeight;
|
||||
use zebra_chain::block::{Block, self};
|
||||
use zebra_chain::block::{self, Block};
|
||||
use zebra_chain::parameters::{Network, NetworkUpgrade::Sapling};
|
||||
|
||||
/// The maximum expected gap between blocks.
|
||||
|
@ -45,7 +44,7 @@ struct ChainCheckpointVerifier {
|
|||
verifier: Buffer<CheckpointVerifier, Arc<Block>>,
|
||||
|
||||
/// The maximum checkpoint height for `checkpoint_verifier`.
|
||||
max_height: BlockHeight,
|
||||
max_height: block::Height,
|
||||
}
|
||||
|
||||
/// A service that verifies the chain, using its associated `CheckpointVerifier`
|
||||
|
@ -77,7 +76,7 @@ where
|
|||
/// Used for debugging.
|
||||
///
|
||||
/// Updated before verification: the block at this height might not be valid.
|
||||
last_block_height: Option<BlockHeight>,
|
||||
last_block_height: Option<block::Height>,
|
||||
}
|
||||
|
||||
/// The error type for the ChainVerifier Service.
|
||||
|
@ -125,10 +124,10 @@ where
|
|||
|
||||
// Log an info-level message on unexpected high blocks
|
||||
let is_unexpected_high_block = match (block_height, self.last_block_height) {
|
||||
(Some(BlockHeight(block_height)), Some(BlockHeight(last_block_height)))
|
||||
(Some(block::Height(block_height)), Some(block::Height(last_block_height)))
|
||||
if (block_height > last_block_height + MAX_EXPECTED_BLOCK_GAP) =>
|
||||
{
|
||||
self.last_block_height = Some(BlockHeight(block_height));
|
||||
self.last_block_height = Some(block::Height(block_height));
|
||||
true
|
||||
}
|
||||
(Some(block_height), _) => {
|
||||
|
@ -190,8 +189,8 @@ where
|
|||
///
|
||||
/// Returns false if the block does not have a height.
|
||||
fn is_higher_than_max_checkpoint(
|
||||
block_height: Option<BlockHeight>,
|
||||
max_checkpoint_height: Option<BlockHeight>,
|
||||
block_height: Option<block::Height>,
|
||||
max_checkpoint_height: Option<block::Height>,
|
||||
) -> bool {
|
||||
match (block_height, max_checkpoint_height) {
|
||||
(Some(block_height), Some(max_checkpoint_height)) => block_height > max_checkpoint_height,
|
||||
|
|
|
@ -11,7 +11,7 @@ use tower::{layer::Layer, timeout::TimeoutLayer, Service, ServiceExt};
|
|||
use tracing_futures::Instrument;
|
||||
|
||||
use zebra_chain::{
|
||||
block::{Block, BlockHeader},
|
||||
block::{self, Block, BlockHeader},
|
||||
parameters::Network,
|
||||
serialization::ZcashDeserialize,
|
||||
};
|
||||
|
@ -107,17 +107,16 @@ fn verifiers_from_network(
|
|||
verifiers_from_checkpoint_list(network, CheckpointList::new(network))
|
||||
}
|
||||
|
||||
static BLOCK_VERIFY_TRANSCRIPT_GENESIS: Lazy<
|
||||
Vec<(Arc<Block>, Result<block::Hash, TransError>)>,
|
||||
> = Lazy::new(|| {
|
||||
let block: Arc<_> =
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
|
||||
.unwrap()
|
||||
.into();
|
||||
let hash = Ok(block.hash());
|
||||
static BLOCK_VERIFY_TRANSCRIPT_GENESIS: Lazy<Vec<(Arc<Block>, Result<block::Hash, TransError>)>> =
|
||||
Lazy::new(|| {
|
||||
let block: Arc<_> =
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
|
||||
.unwrap()
|
||||
.into();
|
||||
let hash = Ok(block.hash());
|
||||
|
||||
vec![(block, hash)]
|
||||
});
|
||||
vec![(block, hash)]
|
||||
});
|
||||
|
||||
static BLOCK_VERIFY_TRANSCRIPT_GENESIS_FAIL: Lazy<
|
||||
Vec<(Arc<Block>, Result<block::Hash, TransError>)>,
|
||||
|
@ -212,7 +211,7 @@ async fn verify_block() -> Result<(), Report> {
|
|||
));
|
||||
|
||||
// Make a checkpoint list containing the genesis block
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> =
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let checkpoint_list = CheckpointList::from_list(checkpoint_list).map_err(|e| eyre!(e))?;
|
||||
|
||||
|
@ -338,7 +337,7 @@ async fn verify_fail_add_block_checkpoint() -> Result<(), Report> {
|
|||
async fn continuous_blockchain_test() -> Result<(), Report> {
|
||||
continuous_blockchain(None).await?;
|
||||
for height in 0..=10 {
|
||||
continuous_blockchain(Some(BlockHeight(height))).await?;
|
||||
continuous_blockchain(Some(block::Height(height))).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -346,7 +345,7 @@ async fn continuous_blockchain_test() -> Result<(), Report> {
|
|||
/// Test a continuous blockchain in the BlockVerifier and CheckpointVerifier,
|
||||
/// restarting verification at `restart_height`.
|
||||
#[spandoc::spandoc]
|
||||
async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<(), Report> {
|
||||
async fn continuous_blockchain(restart_height: Option<block::Height>) -> Result<(), Report> {
|
||||
zebra_test::init();
|
||||
|
||||
// A continuous blockchain
|
||||
|
@ -381,7 +380,7 @@ async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<()
|
|||
}
|
||||
|
||||
// The checkpoint list will contain only blocks 0 and 4
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoints
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoints
|
||||
.iter()
|
||||
.map(|(_block, height, hash)| (*height, *hash))
|
||||
.collect();
|
||||
|
@ -407,7 +406,7 @@ async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<()
|
|||
}
|
||||
}
|
||||
let initial_tip = restart_height
|
||||
.map(|BlockHeight(height)| &blockchain[height as usize].0)
|
||||
.map(|block::Height(height)| &blockchain[height as usize].0)
|
||||
.cloned();
|
||||
|
||||
let block_verifier = crate::block::init(state_service.clone());
|
||||
|
|
|
@ -39,8 +39,7 @@ use tokio::sync::oneshot;
|
|||
use tower::Service;
|
||||
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block::{Block, self},
|
||||
block::{self, Block},
|
||||
parameters::Network,
|
||||
};
|
||||
|
||||
|
@ -109,10 +108,10 @@ pub struct CheckpointVerifier {
|
|||
///
|
||||
/// The first checkpoint does not have any ancestors, so it only verifies the
|
||||
/// genesis block.
|
||||
queued: BTreeMap<BlockHeight, QueuedBlockList>,
|
||||
queued: BTreeMap<block::Height, QueuedBlockList>,
|
||||
|
||||
/// The current progress of this verifier.
|
||||
verifier_progress: Progress<BlockHeight>,
|
||||
verifier_progress: Progress<block::Height>,
|
||||
}
|
||||
|
||||
/// The CheckpointVerifier implementation.
|
||||
|
@ -152,7 +151,7 @@ impl CheckpointVerifier {
|
|||
// This function is designed for use in tests.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn from_list(
|
||||
list: impl IntoIterator<Item = (BlockHeight, block::Hash)>,
|
||||
list: impl IntoIterator<Item = (block::Height, block::Hash)>,
|
||||
initial_tip: Option<Arc<Block>>,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self::from_checkpoint_list(
|
||||
|
@ -213,14 +212,14 @@ impl CheckpointVerifier {
|
|||
/// `height` increases as checkpoints are verified.
|
||||
///
|
||||
/// If verification has finished, returns `FinalCheckpoint`.
|
||||
fn previous_checkpoint_height(&self) -> Progress<BlockHeight> {
|
||||
fn previous_checkpoint_height(&self) -> Progress<block::Height> {
|
||||
self.verifier_progress
|
||||
}
|
||||
|
||||
/// Return the start of the current checkpoint range.
|
||||
///
|
||||
/// Returns None if verification has finished.
|
||||
fn current_start_bound(&self) -> Option<Bound<BlockHeight>> {
|
||||
fn current_start_bound(&self) -> Option<Bound<block::Height>> {
|
||||
match self.previous_checkpoint_height() {
|
||||
BeforeGenesis => Some(Unbounded),
|
||||
InitialTip(height) | PreviousCheckpoint(height) => Some(Excluded(height)),
|
||||
|
@ -239,14 +238,14 @@ impl CheckpointVerifier {
|
|||
/// `height` increases as checkpoints are verified.
|
||||
///
|
||||
/// If verification has finished, returns `FinishedVerifying`.
|
||||
fn target_checkpoint_height(&self) -> Target<BlockHeight> {
|
||||
fn target_checkpoint_height(&self) -> Target<block::Height> {
|
||||
// Find the height we want to start searching at
|
||||
let mut pending_height = match self.previous_checkpoint_height() {
|
||||
// Check if we have the genesis block as a special case, to simplify the loop
|
||||
BeforeGenesis if !self.queued.contains_key(&BlockHeight(0)) => {
|
||||
BeforeGenesis if !self.queued.contains_key(&block::Height(0)) => {
|
||||
return WaitingForBlocks;
|
||||
}
|
||||
BeforeGenesis => BlockHeight(0),
|
||||
BeforeGenesis => block::Height(0),
|
||||
InitialTip(height) | PreviousCheckpoint(height) => height,
|
||||
FinalCheckpoint => return FinishedVerifying,
|
||||
};
|
||||
|
@ -265,7 +264,7 @@ impl CheckpointVerifier {
|
|||
// it stops after the first gap.
|
||||
for (&height, _) in self.queued.range((Excluded(pending_height), Unbounded)) {
|
||||
// If the queued blocks are continuous.
|
||||
if height == BlockHeight(pending_height.0 + 1) {
|
||||
if height == block::Height(pending_height.0 + 1) {
|
||||
pending_height = height;
|
||||
} else {
|
||||
break;
|
||||
|
@ -320,7 +319,7 @@ impl CheckpointVerifier {
|
|||
/// - the block's height is less than or equal to the previously verified
|
||||
/// checkpoint
|
||||
/// - verification has finished
|
||||
fn check_height(&self, height: BlockHeight) -> Result<(), Error> {
|
||||
fn check_height(&self, height: block::Height) -> Result<(), Error> {
|
||||
if height > self.checkpoint_list.max_height() {
|
||||
Err("block is higher than the maximum checkpoint")?;
|
||||
}
|
||||
|
@ -343,7 +342,7 @@ impl CheckpointVerifier {
|
|||
}
|
||||
|
||||
/// Increase the current checkpoint height to `verified_height`,
|
||||
fn update_progress(&mut self, verified_height: BlockHeight) {
|
||||
fn update_progress(&mut self, verified_height: block::Height) {
|
||||
// Ignore blocks that are below the previous checkpoint, or otherwise
|
||||
// have invalid heights.
|
||||
//
|
||||
|
@ -369,7 +368,7 @@ impl CheckpointVerifier {
|
|||
///
|
||||
/// Returns an error if the block's height is invalid, see `check_height()`
|
||||
/// for details.
|
||||
fn check_block(&self, block: &Block) -> Result<BlockHeight, Error> {
|
||||
fn check_block(&self, block: &Block) -> Result<block::Height, Error> {
|
||||
let block_height = block
|
||||
.coinbase_height()
|
||||
.ok_or("the block does not have a coinbase height")?;
|
||||
|
@ -385,10 +384,7 @@ impl CheckpointVerifier {
|
|||
///
|
||||
/// If the block does not have a coinbase height, sends an error on `tx`,
|
||||
/// and does not queue the block.
|
||||
fn queue_block(
|
||||
&mut self,
|
||||
block: Arc<Block>,
|
||||
) -> oneshot::Receiver<Result<block::Hash, Error>> {
|
||||
fn queue_block(&mut self, block: Arc<Block>) -> oneshot::Receiver<Result<block::Hash, Error>> {
|
||||
// Set up a oneshot channel to send results
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
|
@ -459,7 +455,7 @@ impl CheckpointVerifier {
|
|||
/// Returns the first valid block. If there is no valid block, returns None.
|
||||
fn process_height(
|
||||
&mut self,
|
||||
height: BlockHeight,
|
||||
height: block::Height,
|
||||
expected_hash: block::Hash,
|
||||
) -> Option<QueuedBlock> {
|
||||
let mut qblocks = self
|
||||
|
@ -567,7 +563,7 @@ impl CheckpointVerifier {
|
|||
.expect("earlier code checks if verification has finished"),
|
||||
Included(target_checkpoint_height),
|
||||
);
|
||||
let range_heights: Vec<BlockHeight> = self
|
||||
let range_heights: Vec<block::Height> = self
|
||||
.queued
|
||||
.range_mut(current_range)
|
||||
.rev()
|
||||
|
|
|
@ -18,7 +18,6 @@ use std::{
|
|||
};
|
||||
|
||||
use zebra_chain::block;
|
||||
use zebra_chain::block::BlockHeight;
|
||||
use zebra_chain::parameters::Network;
|
||||
|
||||
const MAINNET_CHECKPOINTS: &str = include_str!("main-checkpoints.txt");
|
||||
|
@ -38,19 +37,19 @@ type Error = Box<dyn error::Error + Send + Sync + 'static>;
|
|||
/// This is actually a bijective map, but since it is read-only, we use a
|
||||
/// BTreeMap, and do the value uniqueness check on initialisation.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub(crate) struct CheckpointList(BTreeMap<BlockHeight, block::Hash>);
|
||||
pub(crate) struct CheckpointList(BTreeMap<block::Height, block::Hash>);
|
||||
|
||||
impl FromStr for CheckpointList {
|
||||
type Err = Error;
|
||||
|
||||
/// Parse a string into a CheckpointList.
|
||||
///
|
||||
/// Each line has one checkpoint, consisting of a `BlockHeight` and
|
||||
/// Each line has one checkpoint, consisting of a `block::Height` and
|
||||
/// `block::Hash`, separated by a single space.
|
||||
///
|
||||
/// Assumes that the provided genesis checkpoint is correct.
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut checkpoint_list: Vec<(BlockHeight, block::Hash)> = Vec::new();
|
||||
let mut checkpoint_list: Vec<(block::Height, block::Hash)> = Vec::new();
|
||||
|
||||
for checkpoint in s.lines() {
|
||||
let fields = checkpoint.split(' ').collect::<Vec<_>>();
|
||||
|
@ -78,7 +77,7 @@ impl CheckpointList {
|
|||
.expect("Hard-coded Testnet checkpoint list parses and validates"),
|
||||
};
|
||||
|
||||
match checkpoint_list.hash(BlockHeight(0)) {
|
||||
match checkpoint_list.hash(block::Height(0)) {
|
||||
Some(hash) if hash == parameters::genesis_hash(network) => checkpoint_list,
|
||||
Some(_) => {
|
||||
panic!("The hard-coded genesis checkpoint does not match the network genesis hash")
|
||||
|
@ -92,25 +91,25 @@ impl CheckpointList {
|
|||
/// Assumes that the provided genesis checkpoint is correct.
|
||||
///
|
||||
/// Checkpoint heights and checkpoint hashes must be unique.
|
||||
/// There must be a checkpoint for a genesis block at BlockHeight 0.
|
||||
/// There must be a checkpoint for a genesis block at block::Height 0.
|
||||
/// (All other checkpoints are optional.)
|
||||
pub(crate) fn from_list(
|
||||
list: impl IntoIterator<Item = (BlockHeight, block::Hash)>,
|
||||
list: impl IntoIterator<Item = (block::Height, block::Hash)>,
|
||||
) -> Result<Self, Error> {
|
||||
// BTreeMap silently ignores duplicates, so we count the checkpoints
|
||||
// before adding them to the map
|
||||
let original_checkpoints: Vec<(BlockHeight, block::Hash)> = list.into_iter().collect();
|
||||
let original_checkpoints: Vec<(block::Height, block::Hash)> = list.into_iter().collect();
|
||||
let original_len = original_checkpoints.len();
|
||||
|
||||
let checkpoints: BTreeMap<BlockHeight, block::Hash> =
|
||||
let checkpoints: BTreeMap<block::Height, block::Hash> =
|
||||
original_checkpoints.into_iter().collect();
|
||||
|
||||
// Check that the list starts with the correct genesis block
|
||||
match checkpoints.iter().next() {
|
||||
Some((BlockHeight(0), hash))
|
||||
Some((block::Height(0), hash))
|
||||
if (hash == ¶meters::genesis_hash(Network::Mainnet)
|
||||
|| hash == ¶meters::genesis_hash(Network::Testnet)) => {}
|
||||
Some((BlockHeight(0), _)) => {
|
||||
Some((block::Height(0), _)) => {
|
||||
Err("the genesis checkpoint does not match the Mainnet or Testnet genesis hash")?
|
||||
}
|
||||
Some(_) => Err("checkpoints must start at the genesis block height 0")?,
|
||||
|
@ -135,7 +134,7 @@ impl CheckpointList {
|
|||
}
|
||||
|
||||
let checkpoints = CheckpointList(checkpoints);
|
||||
if checkpoints.max_height() > BlockHeight::MAX {
|
||||
if checkpoints.max_height() > block::Height::MAX {
|
||||
Err("checkpoint list contains invalid checkpoint: checkpoint height is greater than the maximum block height")?;
|
||||
}
|
||||
|
||||
|
@ -145,7 +144,7 @@ impl CheckpointList {
|
|||
/// Return true if there is a checkpoint at `height`.
|
||||
///
|
||||
/// See `BTreeMap::contains_key()` for details.
|
||||
pub fn contains(&self, height: BlockHeight) -> bool {
|
||||
pub fn contains(&self, height: block::Height) -> bool {
|
||||
self.0.contains_key(&height)
|
||||
}
|
||||
|
||||
|
@ -153,7 +152,7 @@ impl CheckpointList {
|
|||
/// or None if there is no checkpoint at that height.
|
||||
///
|
||||
/// See `BTreeMap::get()` for details.
|
||||
pub fn hash(&self, height: BlockHeight) -> Option<block::Hash> {
|
||||
pub fn hash(&self, height: block::Height) -> Option<block::Hash> {
|
||||
self.0.get(&height).cloned()
|
||||
}
|
||||
|
||||
|
@ -161,15 +160,15 @@ impl CheckpointList {
|
|||
///
|
||||
/// If there is only a single checkpoint, then the maximum height will be
|
||||
/// zero. (The genesis block.)
|
||||
pub fn max_height(&self) -> BlockHeight {
|
||||
pub fn max_height(&self) -> block::Height {
|
||||
self.max_height_in_range(..)
|
||||
.expect("checkpoint lists must have at least one checkpoint")
|
||||
}
|
||||
|
||||
/// Return the block height of the highest checkpoint in a sub-range.
|
||||
pub fn max_height_in_range<R>(&self, range: R) -> Option<BlockHeight>
|
||||
pub fn max_height_in_range<R>(&self, range: R) -> Option<block::Height>
|
||||
where
|
||||
R: RangeBounds<BlockHeight>,
|
||||
R: RangeBounds<block::Height>,
|
||||
{
|
||||
self.0.range(range).map(|(height, _)| *height).next_back()
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ fn checkpoint_list_genesis() -> Result<(), Error> {
|
|||
));
|
||||
|
||||
// Make a checkpoint list containing the genesis block
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> =
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let _ = CheckpointList::from_list(checkpoint_list)?;
|
||||
|
||||
|
@ -55,7 +55,8 @@ fn checkpoint_list_multiple() -> Result<(), Error> {
|
|||
}
|
||||
|
||||
// Make a checkpoint list containing all the blocks
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data.iter().cloned().collect();
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let _ = CheckpointList::from_list(checkpoint_list)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -86,7 +87,8 @@ fn checkpoint_list_no_genesis_fail() -> Result<(), Error> {
|
|||
));
|
||||
|
||||
// Make a checkpoint list containing the non-genesis block
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data.iter().cloned().collect();
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let _ = CheckpointList::from_list(checkpoint_list)
|
||||
.expect_err("a checkpoint list with no genesis block should fail");
|
||||
|
||||
|
@ -98,10 +100,11 @@ fn checkpoint_list_no_genesis_fail() -> Result<(), Error> {
|
|||
fn checkpoint_list_null_hash_fail() -> Result<(), Error> {
|
||||
zebra_test::init();
|
||||
|
||||
let checkpoint_data = vec![(BlockHeight(0), block::Hash([0; 32]))];
|
||||
let checkpoint_data = vec![(block::Height(0), block::Hash([0; 32]))];
|
||||
|
||||
// Make a checkpoint list containing the non-genesis block
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data.iter().cloned().collect();
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let _ = CheckpointList::from_list(checkpoint_list)
|
||||
.expect_err("a checkpoint list with a null block hash should fail");
|
||||
|
||||
|
@ -113,18 +116,23 @@ fn checkpoint_list_null_hash_fail() -> Result<(), Error> {
|
|||
fn checkpoint_list_bad_height_fail() -> Result<(), Error> {
|
||||
zebra_test::init();
|
||||
|
||||
let checkpoint_data = vec![(BlockHeight(BlockHeight::MAX.0 + 1), block::Hash([1; 32]))];
|
||||
let checkpoint_data = vec![(
|
||||
block::Height(block::Height::MAX.0 + 1),
|
||||
block::Hash([1; 32]),
|
||||
)];
|
||||
|
||||
// Make a checkpoint list containing the non-genesis block
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data.iter().cloned().collect();
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let _ = CheckpointList::from_list(checkpoint_list).expect_err(
|
||||
"a checkpoint list with an invalid block height (BlockHeight::MAX + 1) should fail",
|
||||
"a checkpoint list with an invalid block height (block::Height::MAX + 1) should fail",
|
||||
);
|
||||
|
||||
let checkpoint_data = vec![(BlockHeight(u32::MAX), block::Hash([1; 32]))];
|
||||
let checkpoint_data = vec![(block::Height(u32::MAX), block::Hash([1; 32]))];
|
||||
|
||||
// Make a checkpoint list containing the non-genesis block
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data.iter().cloned().collect();
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
checkpoint_data.iter().cloned().collect();
|
||||
let _ = CheckpointList::from_list(checkpoint_list)
|
||||
.expect_err("a checkpoint list with an invalid block height (u32::MAX) should fail");
|
||||
|
||||
|
@ -176,8 +184,8 @@ fn checkpoint_list_duplicate_heights_fail() -> Result<(), Error> {
|
|||
}
|
||||
|
||||
// Then add some fake entries with duplicate heights
|
||||
checkpoint_data.push((BlockHeight(1), block::Hash([0xaa; 32])));
|
||||
checkpoint_data.push((BlockHeight(1), block::Hash([0xbb; 32])));
|
||||
checkpoint_data.push((block::Height(1), block::Hash([0xaa; 32])));
|
||||
checkpoint_data.push((block::Height(1), block::Hash([0xbb; 32])));
|
||||
|
||||
// Make a checkpoint list containing some duplicate blocks
|
||||
let _ = CheckpointList::from_list(checkpoint_data)
|
||||
|
@ -204,8 +212,8 @@ fn checkpoint_list_duplicate_hashes_fail() -> Result<(), Error> {
|
|||
}
|
||||
|
||||
// Then add some fake entries with duplicate hashes
|
||||
checkpoint_data.push((BlockHeight(1), block::Hash([0xcc; 32])));
|
||||
checkpoint_data.push((BlockHeight(2), block::Hash([0xcc; 32])));
|
||||
checkpoint_data.push((block::Height(1), block::Hash([0xcc; 32])));
|
||||
checkpoint_data.push((block::Height(2), block::Hash([0xcc; 32])));
|
||||
|
||||
// Make a checkpoint list containing some duplicate blocks
|
||||
let _ = CheckpointList::from_list(checkpoint_data)
|
||||
|
|
|
@ -38,7 +38,7 @@ async fn single_item_checkpoint_list() -> Result<(), Report> {
|
|||
let hash0 = block0.hash();
|
||||
|
||||
// Make a checkpoint list containing only the genesis block
|
||||
let genesis_checkpoint_list: BTreeMap<BlockHeight, block::Hash> =
|
||||
let genesis_checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
[(block0.coinbase_height().unwrap(), hash0)]
|
||||
.iter()
|
||||
.cloned()
|
||||
|
@ -57,7 +57,7 @@ async fn single_item_checkpoint_list() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready
|
||||
|
@ -90,7 +90,7 @@ async fn single_item_checkpoint_list() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -119,7 +119,7 @@ async fn multi_item_checkpoint_list() -> Result<(), Report> {
|
|||
}
|
||||
|
||||
// Make a checkpoint list containing all the blocks
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoint_data
|
||||
.iter()
|
||||
.map(|(_block, height, hash)| (*height, *hash))
|
||||
.collect();
|
||||
|
@ -137,7 +137,7 @@ async fn multi_item_checkpoint_list() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(1)
|
||||
block::Height(1)
|
||||
);
|
||||
|
||||
// Now verify each block
|
||||
|
@ -184,7 +184,7 @@ async fn multi_item_checkpoint_list() -> Result<(), Report> {
|
|||
}
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(1)
|
||||
block::Height(1)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ async fn multi_item_checkpoint_list() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(1)
|
||||
block::Height(1)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -208,14 +208,14 @@ async fn multi_item_checkpoint_list() -> Result<(), Report> {
|
|||
async fn continuous_blockchain_test() -> Result<(), Report> {
|
||||
continuous_blockchain(None).await?;
|
||||
for height in 0..=10 {
|
||||
continuous_blockchain(Some(BlockHeight(height))).await?;
|
||||
continuous_blockchain(Some(block::Height(height))).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test a continuous blockchain, restarting verification at `restart_height`.
|
||||
#[spandoc::spandoc]
|
||||
async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<(), Report> {
|
||||
async fn continuous_blockchain(restart_height: Option<block::Height>) -> Result<(), Report> {
|
||||
zebra_test::init();
|
||||
|
||||
// A continuous blockchain
|
||||
|
@ -251,7 +251,7 @@ async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<()
|
|||
}
|
||||
|
||||
// The checkpoint list will contain only block 0, 5 and 9
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoints
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoints
|
||||
.iter()
|
||||
.map(|(_block, height, hash)| (*height, *hash))
|
||||
.collect();
|
||||
|
@ -259,7 +259,7 @@ async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<()
|
|||
/// SPANDOC: Verify blocks, restarting at {?restart_height}
|
||||
{
|
||||
let initial_tip = restart_height
|
||||
.map(|BlockHeight(height)| &blockchain[height as usize].0)
|
||||
.map(|block::Height(height)| &blockchain[height as usize].0)
|
||||
.cloned();
|
||||
let mut checkpoint_verifier =
|
||||
CheckpointVerifier::from_list(checkpoint_list, initial_tip).map_err(|e| eyre!(e))?;
|
||||
|
@ -289,7 +289,7 @@ async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<()
|
|||
}
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(9)
|
||||
block::Height(9)
|
||||
);
|
||||
|
||||
let mut handles = FuturesUnordered::new();
|
||||
|
@ -354,7 +354,7 @@ async fn continuous_blockchain(restart_height: Option<BlockHeight>) -> Result<()
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(9)
|
||||
block::Height(9)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -376,7 +376,7 @@ async fn block_higher_than_max_checkpoint_fail() -> Result<(), Report> {
|
|||
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])?;
|
||||
|
||||
// Make a checkpoint list containing only the genesis block
|
||||
let genesis_checkpoint_list: BTreeMap<BlockHeight, block::Hash> =
|
||||
let genesis_checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
[(block0.coinbase_height().unwrap(), block0.as_ref().into())]
|
||||
.iter()
|
||||
.cloned()
|
||||
|
@ -395,7 +395,7 @@ async fn block_higher_than_max_checkpoint_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready
|
||||
|
@ -426,7 +426,7 @@ async fn block_higher_than_max_checkpoint_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -451,7 +451,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
let bad_block0: Arc<Block> = bad_block0.clone().into();
|
||||
|
||||
// Make a checkpoint list containing the genesis block checkpoint
|
||||
let genesis_checkpoint_list: BTreeMap<BlockHeight, block::Hash> =
|
||||
let genesis_checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
||||
[(good_block0.coinbase_height().unwrap(), good_block0_hash)]
|
||||
.iter()
|
||||
.cloned()
|
||||
|
@ -470,7 +470,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready (1/3)
|
||||
|
@ -497,7 +497,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready (2/3)
|
||||
|
@ -524,7 +524,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready (3/3)
|
||||
|
@ -557,7 +557,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
// Now, await the bad futures, which should have completed
|
||||
|
@ -580,7 +580,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
/// SPANDOC: Wait for the response for block 0, and expect failure again (2/3)
|
||||
|
@ -601,7 +601,7 @@ async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(0)
|
||||
block::Height(0)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -632,7 +632,7 @@ async fn checkpoint_drop_cancel() -> Result<(), Report> {
|
|||
}
|
||||
|
||||
// Make a checkpoint list containing all the blocks
|
||||
let checkpoint_list: BTreeMap<BlockHeight, block::Hash> = checkpoint_data
|
||||
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoint_data
|
||||
.iter()
|
||||
.map(|(_block, height, hash)| (*height, *hash))
|
||||
.collect();
|
||||
|
@ -650,7 +650,7 @@ async fn checkpoint_drop_cancel() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(434873)
|
||||
block::Height(434873)
|
||||
);
|
||||
|
||||
let mut futures = Vec::new();
|
||||
|
@ -673,7 +673,7 @@ async fn checkpoint_drop_cancel() -> Result<(), Report> {
|
|||
// Only continuous checkpoints verify
|
||||
assert_eq!(
|
||||
checkpoint_verifier.previous_checkpoint_height(),
|
||||
PreviousCheckpoint(BlockHeight(min(height.0, 1)))
|
||||
PreviousCheckpoint(block::Height(min(height.0, 1)))
|
||||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.target_checkpoint_height(),
|
||||
|
@ -681,7 +681,7 @@ async fn checkpoint_drop_cancel() -> Result<(), Report> {
|
|||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.checkpoint_list.max_height(),
|
||||
BlockHeight(434873)
|
||||
block::Height(434873)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -695,7 +695,7 @@ async fn checkpoint_drop_cancel() -> Result<(), Report> {
|
|||
.await
|
||||
.expect("timeout should not happen");
|
||||
|
||||
if height <= BlockHeight(1) {
|
||||
if height <= block::Height(1) {
|
||||
let verify_hash =
|
||||
verify_response.expect("Continuous checkpoints should have succeeded before drop");
|
||||
assert_eq!(verify_hash, hash);
|
||||
|
@ -732,7 +732,7 @@ async fn hard_coded_mainnet() -> Result<(), Report> {
|
|||
checkpoint_verifier.target_checkpoint_height(),
|
||||
WaitingForBlocks
|
||||
);
|
||||
assert!(checkpoint_verifier.checkpoint_list.max_height() > BlockHeight(0));
|
||||
assert!(checkpoint_verifier.checkpoint_list.max_height() > block::Height(0));
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready
|
||||
let ready_verifier_service = checkpoint_verifier
|
||||
|
@ -756,14 +756,14 @@ async fn hard_coded_mainnet() -> Result<(), Report> {
|
|||
|
||||
assert_eq!(
|
||||
checkpoint_verifier.previous_checkpoint_height(),
|
||||
PreviousCheckpoint(BlockHeight(0))
|
||||
PreviousCheckpoint(block::Height(0))
|
||||
);
|
||||
assert_eq!(
|
||||
checkpoint_verifier.target_checkpoint_height(),
|
||||
WaitingForBlocks
|
||||
);
|
||||
// The lists will get bigger over time, so we just pick a recent height
|
||||
assert!(checkpoint_verifier.checkpoint_list.max_height() > BlockHeight(900_000));
|
||||
assert!(checkpoint_verifier.checkpoint_list.max_height() > block::Height(900_000));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use zebra_chain::block::BlockHeight;
|
||||
use zebra_chain::block;
|
||||
|
||||
use Progress::*;
|
||||
use Target::*;
|
||||
|
@ -33,7 +33,7 @@ pub enum Progress<HeightOrHash> {
|
|||
}
|
||||
|
||||
/// Block height progress, in chain order.
|
||||
impl Ord for Progress<BlockHeight> {
|
||||
impl Ord for Progress<block::Height> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
if self == other {
|
||||
return Ordering::Equal;
|
||||
|
@ -56,7 +56,7 @@ impl Ord for Progress<BlockHeight> {
|
|||
/// Partial order for block height progress.
|
||||
///
|
||||
/// The partial order must match the total order.
|
||||
impl PartialOrd for Progress<BlockHeight> {
|
||||
impl PartialOrd for Progress<block::Height> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ pub enum Target<HeightOrHash> {
|
|||
/// Block height target, in chain order.
|
||||
///
|
||||
/// `WaitingForBlocks` is incomparable with itself and `Checkpoint(_)`.
|
||||
impl PartialOrd for Target<BlockHeight> {
|
||||
impl PartialOrd for Target<block::Height> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
// FinishedVerifying is the final state
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! The minimum difficulty block rule for Zcash.
|
||||
|
||||
use zebra_chain::{block::BlockHeight, parameters::Network};
|
||||
use zebra_chain::{block, parameters::Network};
|
||||
|
||||
/// The testnet block height when minimum difficulty blocks start being
|
||||
/// accepted.
|
||||
pub(crate) const TESTNET_MINIMUM_DIFFICULTY_HEIGHT: BlockHeight = BlockHeight(299_188);
|
||||
pub(crate) const TESTNET_MINIMUM_DIFFICULTY_HEIGHT: block::Height = block::Height(299_188);
|
||||
|
||||
/// The Zcash Testnet consensus rules were changed to allow
|
||||
/// minimum-difficulty blocks, shortly after Testnet Sapling activation.
|
||||
|
@ -26,7 +26,7 @@ pub enum MinimumDifficulty {
|
|||
|
||||
impl MinimumDifficulty {
|
||||
/// Returns the current minimum difficulty rule for `network` and `height`.
|
||||
pub fn current(network: Network, height: BlockHeight) -> MinimumDifficulty {
|
||||
pub fn current(network: Network, height: block::Height) -> MinimumDifficulty {
|
||||
use MinimumDifficulty::*;
|
||||
use Network::*;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use super::*;
|
||||
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block,
|
||||
parameters::Network::{self, *},
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@ fn minimum_difficulty_testnet() {
|
|||
|
||||
/// Test MinimumDifficulty
|
||||
fn minimum_difficulty(network: Network) {
|
||||
use block::Height;
|
||||
use MinimumDifficulty::*;
|
||||
|
||||
let allowed_if_testnet = match network {
|
||||
|
@ -26,24 +27,21 @@ fn minimum_difficulty(network: Network) {
|
|||
Testnet => AllowedOnTestnet,
|
||||
};
|
||||
|
||||
assert_eq!(MinimumDifficulty::current(network, Height(0)), Rejected);
|
||||
assert_eq!(
|
||||
MinimumDifficulty::current(network, BlockHeight(0)),
|
||||
MinimumDifficulty::current(network, Height(299_187)),
|
||||
Rejected
|
||||
);
|
||||
assert_eq!(
|
||||
MinimumDifficulty::current(network, BlockHeight(299_187)),
|
||||
Rejected
|
||||
);
|
||||
assert_eq!(
|
||||
MinimumDifficulty::current(network, BlockHeight(299_188)),
|
||||
MinimumDifficulty::current(network, Height(299_188)),
|
||||
allowed_if_testnet
|
||||
);
|
||||
assert_eq!(
|
||||
MinimumDifficulty::current(network, BlockHeight(299_189)),
|
||||
MinimumDifficulty::current(network, Height(299_189)),
|
||||
allowed_if_testnet
|
||||
);
|
||||
assert_eq!(
|
||||
MinimumDifficulty::current(network, BlockHeight::MAX),
|
||||
MinimumDifficulty::current(network, Height::MAX),
|
||||
allowed_if_testnet
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ use tower::Service;
|
|||
use tracing_futures::Instrument;
|
||||
|
||||
use zebra_chain::{
|
||||
block::{Block, self},
|
||||
block::{self, Block},
|
||||
serialization::SerializationError,
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use tower::Service;
|
|||
use tracing::{span, Level};
|
||||
use tracing_futures::Instrument;
|
||||
|
||||
use zebra_chain::block::BlockHeight;
|
||||
use zebra_chain::block;
|
||||
|
||||
use crate::{
|
||||
constants,
|
||||
|
@ -137,7 +137,7 @@ where
|
|||
// for a service that gets the current block height. Among other
|
||||
// things we need it to reject peers who don't know about the
|
||||
// current protocol epoch.
|
||||
start_height: BlockHeight(0),
|
||||
start_height: block::Height(0),
|
||||
relay: false,
|
||||
};
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ use chrono::{TimeZone, Utc};
|
|||
use tokio_util::codec::{Decoder, Encoder};
|
||||
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block::{Block, self},
|
||||
block::{self, Block},
|
||||
parameters::Network,
|
||||
serialization::{
|
||||
sha256d, ReadZcashExt, SerializationError as Error, WriteZcashExt, ZcashDeserialize,
|
||||
|
@ -429,7 +428,7 @@ impl Codec {
|
|||
),
|
||||
nonce: Nonce(reader.read_u64::<LittleEndian>()?),
|
||||
user_agent: reader.read_string()?,
|
||||
start_height: BlockHeight(reader.read_u32::<LittleEndian>()?),
|
||||
start_height: block::Height(reader.read_u32::<LittleEndian>()?),
|
||||
relay: match reader.read_u8()? {
|
||||
0 => false,
|
||||
1 => true,
|
||||
|
@ -599,7 +598,7 @@ mod tests {
|
|||
),
|
||||
nonce: Nonce(0x9082_4908_8927_9238),
|
||||
user_agent: "Zebra".to_owned(),
|
||||
start_height: BlockHeight(540_000),
|
||||
start_height: block::Height(540_000),
|
||||
relay: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ use std::{net, sync::Arc};
|
|||
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use zebra_chain::block::{Block, self};
|
||||
use zebra_chain::{block::BlockHeight, block::BlockHeader, transaction::Transaction};
|
||||
use zebra_chain::block::{self, Block};
|
||||
use zebra_chain::{block::BlockHeader, transaction::Transaction};
|
||||
|
||||
use super::inv::InventoryHash;
|
||||
use super::types::*;
|
||||
|
@ -66,7 +66,7 @@ pub enum Message {
|
|||
user_agent: String,
|
||||
|
||||
/// The last block received by the emitting node.
|
||||
start_height: BlockHeight,
|
||||
start_height: block::Height,
|
||||
|
||||
/// Whether the remote peer should announce relayed
|
||||
/// transactions or not, see [BIP 0037](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki)
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::constants::magics;
|
|||
use std::fmt;
|
||||
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block,
|
||||
parameters::{
|
||||
Network::{self, *},
|
||||
NetworkUpgrade::{self, *},
|
||||
|
@ -64,7 +64,7 @@ impl Version {
|
|||
///
|
||||
/// Returns None if the network has no branch id at this height.
|
||||
#[allow(dead_code)]
|
||||
pub fn current_min(network: Network, height: BlockHeight) -> Version {
|
||||
pub fn current_min(network: Network, height: block::Height) -> Version {
|
||||
let network_upgrade = NetworkUpgrade::current(network, height);
|
||||
Version::min_for_upgrade(network, network_upgrade)
|
||||
}
|
||||
|
@ -153,14 +153,14 @@ mod test {
|
|||
/// extreme values.
|
||||
fn version_extremes(network: Network) {
|
||||
assert_eq!(
|
||||
Version::current_min(network, BlockHeight(0)),
|
||||
Version::current_min(network, block::Height(0)),
|
||||
Version::min_for_upgrade(network, BeforeOverwinter),
|
||||
);
|
||||
|
||||
// We assume that the last version we know about continues forever
|
||||
// (even if we suspect that won't be true)
|
||||
assert_ne!(
|
||||
Version::current_min(network, BlockHeight::MAX),
|
||||
Version::current_min(network, block::Height::MAX),
|
||||
Version::min_for_upgrade(network, BeforeOverwinter),
|
||||
);
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ mod test {
|
|||
/// Check that the min_for_upgrade and current_min functions
|
||||
/// are consistent for `network`.
|
||||
fn version_consistent(network: Network) {
|
||||
let highest_network_upgrade = NetworkUpgrade::current(network, BlockHeight::MAX);
|
||||
let highest_network_upgrade = NetworkUpgrade::current(network, block::Height::MAX);
|
||||
assert!(highest_network_upgrade == Canopy || highest_network_upgrade == Heartwood,
|
||||
"expected coverage of all network upgrades: add the new network upgrade to the list in this test");
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use zebra_chain::block::{Block, self};
|
||||
use zebra_chain::block::{self, Block};
|
||||
|
||||
use crate::meta_addr::MetaAddr;
|
||||
use std::sync::Arc;
|
||||
|
|
|
@ -3,14 +3,11 @@ use std::{
|
|||
error::Error,
|
||||
sync::Arc,
|
||||
};
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block::{Block, self},
|
||||
};
|
||||
use zebra_chain::block::{self, Block};
|
||||
#[derive(Default)]
|
||||
pub(super) struct BlockIndex {
|
||||
by_hash: HashMap<block::Hash, Arc<Block>>,
|
||||
height_map: BTreeMap<BlockHeight, block::Hash>,
|
||||
height_map: BTreeMap<block::Height, block::Hash>,
|
||||
}
|
||||
|
||||
impl BlockIndex {
|
||||
|
@ -36,7 +33,7 @@ impl BlockIndex {
|
|||
self.by_hash.get(&hash).cloned()
|
||||
}
|
||||
|
||||
pub(super) fn get_main_chain_at(&self, height: BlockHeight) -> Option<block::Hash> {
|
||||
pub(super) fn get_main_chain_at(&self, height: block::Height) -> Option<block::Hash> {
|
||||
self.height_map.get(&height).cloned()
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ use std::{error, iter, sync::Arc};
|
|||
use tower::{Service, ServiceExt};
|
||||
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block::{Block, self},
|
||||
block::{self, Block},
|
||||
parameters::Network,
|
||||
};
|
||||
|
||||
|
@ -35,13 +34,13 @@ pub mod on_disk;
|
|||
/// A transaction MUST NOT spend a transparent output of a coinbase transaction
|
||||
/// from a block less than 100 blocks prior to the spend. Note that transparent
|
||||
/// outputs of coinbase transactions include Founders' Reward outputs.
|
||||
const MIN_TRASPARENT_COINBASE_MATURITY: BlockHeight = BlockHeight(100);
|
||||
const MIN_TRASPARENT_COINBASE_MATURITY: block::Height = block::Height(100);
|
||||
|
||||
/// The maximum chain reorganisation height.
|
||||
///
|
||||
/// Allowing reorganisations past this height could allow double-spends of
|
||||
/// coinbase transactions.
|
||||
const MAX_BLOCK_REORG_HEIGHT: BlockHeight = BlockHeight(MIN_TRASPARENT_COINBASE_MATURITY.0 - 1);
|
||||
const MAX_BLOCK_REORG_HEIGHT: block::Height = block::Height(MIN_TRASPARENT_COINBASE_MATURITY.0 - 1);
|
||||
|
||||
/// Configuration for the state service.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
@ -162,7 +161,7 @@ pub enum Response {
|
|||
}
|
||||
|
||||
/// Get the heights of the blocks for constructing a block_locator list
|
||||
fn block_locator_heights(tip_height: BlockHeight) -> impl Iterator<Item = BlockHeight> {
|
||||
fn block_locator_heights(tip_height: block::Height) -> impl Iterator<Item = block::Height> {
|
||||
// Stop at the reorg limit, or the genesis block.
|
||||
let min_locator_height = tip_height.0.saturating_sub(MAX_BLOCK_REORG_HEIGHT.0);
|
||||
let locators = iter::successors(Some(1u32), |h| h.checked_mul(2))
|
||||
|
@ -171,7 +170,7 @@ fn block_locator_heights(tip_height: BlockHeight) -> impl Iterator<Item = BlockH
|
|||
.chain(locators)
|
||||
.take_while(move |&height| height > min_locator_height)
|
||||
.chain(iter::once(min_locator_height))
|
||||
.map(BlockHeight);
|
||||
.map(block::Height);
|
||||
|
||||
let locators: Vec<_> = locators.collect();
|
||||
tracing::info!(
|
||||
|
@ -279,7 +278,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_block_locator_heights() {
|
||||
for (height, min_height) in BLOCK_LOCATOR_CASES.iter().cloned() {
|
||||
let locator = block_locator_heights(BlockHeight(height)).collect::<Vec<_>>();
|
||||
let locator = block_locator_heights(block::Height(height)).collect::<Vec<_>>();
|
||||
|
||||
assert!(!locator.is_empty(), "locators must not be empty");
|
||||
if (height - min_height) > 1 {
|
||||
|
@ -291,7 +290,7 @@ mod tests {
|
|||
|
||||
assert_eq!(
|
||||
locator[0],
|
||||
BlockHeight(height),
|
||||
block::Height(height),
|
||||
"locators must start with the tip height"
|
||||
);
|
||||
|
||||
|
@ -305,7 +304,7 @@ mod tests {
|
|||
let final_height = locator[locator.len() - 1];
|
||||
assert_eq!(
|
||||
final_height,
|
||||
BlockHeight(min_height),
|
||||
block::Height(min_height),
|
||||
"locators must end with the specified final height"
|
||||
);
|
||||
assert!(height - final_height.0 <= MAX_BLOCK_REORG_HEIGHT.0,
|
||||
|
|
|
@ -13,8 +13,7 @@ use tower::{buffer::Buffer, util::BoxService, Service};
|
|||
use tracing::instrument;
|
||||
use zebra_chain::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
||||
use zebra_chain::{
|
||||
block::BlockHeight,
|
||||
block::{Block, self},
|
||||
block::{self, Block},
|
||||
parameters::Network,
|
||||
};
|
||||
|
||||
|
@ -75,7 +74,7 @@ impl SledState {
|
|||
#[instrument(skip(self))]
|
||||
pub(super) fn get_main_chain_at(
|
||||
&self,
|
||||
height: BlockHeight,
|
||||
height: block::Height,
|
||||
) -> Result<Option<block::Hash>, Error> {
|
||||
let height_map = self.storage.open_tree(b"height_map")?;
|
||||
let key = height.0.to_be_bytes();
|
||||
|
@ -212,12 +211,12 @@ impl Service<Request> for SledState {
|
|||
}
|
||||
}
|
||||
|
||||
/// An alternate repr for `BlockHeight` that implements `AsRef<[u8]>` for usage
|
||||
/// An alternate repr for `block::Height` that implements `AsRef<[u8]>` for usage
|
||||
/// with sled
|
||||
struct BytesHeight(u32, [u8; 4]);
|
||||
|
||||
impl From<BlockHeight> for BytesHeight {
|
||||
fn from(height: BlockHeight) -> Self {
|
||||
impl From<block::Height> for BytesHeight {
|
||||
fn from(height: block::Height) -> Self {
|
||||
let bytes = height.0.to_be_bytes();
|
||||
Self(height.0, bytes)
|
||||
}
|
||||
|
@ -231,7 +230,7 @@ impl AsRef<[u8]> for BytesHeight {
|
|||
|
||||
pub(super) enum BlockQuery {
|
||||
ByHash(block::Hash),
|
||||
ByHeight(BlockHeight),
|
||||
ByHeight(block::Height),
|
||||
}
|
||||
|
||||
impl From<block::Hash> for BlockQuery {
|
||||
|
@ -240,8 +239,8 @@ impl From<block::Hash> for BlockQuery {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<BlockHeight> for BlockQuery {
|
||||
fn from(height: BlockHeight) -> Self {
|
||||
impl From<block::Height> for BlockQuery {
|
||||
fn from(height: block::Height) -> Self {
|
||||
Self::ByHeight(height)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ use structopt::StructOpt;
|
|||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
use zebra_chain::block;
|
||||
use zebra_chain::block::BlockHeight;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
@ -47,7 +46,7 @@ const MAX_CHECKPOINT_BYTE_COUNT: u64 = 256 * 1024 * 1024;
|
|||
|
||||
/// Checkpoints must be on the main chain, so we skip blocks that are within the
|
||||
/// zcashd reorg limit.
|
||||
const BLOCK_REORG_LIMIT: BlockHeight = BlockHeight(100);
|
||||
const BLOCK_REORG_LIMIT: block::Height = block::Height(100);
|
||||
|
||||
/// Initialise tracing using its defaults.
|
||||
fn init_tracing() {
|
||||
|
@ -102,22 +101,22 @@ fn main() -> Result<()> {
|
|||
let mut cmd = passthrough_cmd();
|
||||
cmd.arg("getblockcount");
|
||||
// calculate the maximum height
|
||||
let height_limit: BlockHeight = cmd_output(&mut cmd)?.trim().parse()?;
|
||||
assert!(height_limit <= BlockHeight::MAX);
|
||||
let height_limit: block::Height = cmd_output(&mut cmd)?.trim().parse()?;
|
||||
assert!(height_limit <= block::Height::MAX);
|
||||
let height_limit = height_limit
|
||||
.0
|
||||
.checked_sub(BLOCK_REORG_LIMIT.0)
|
||||
.map(BlockHeight)
|
||||
.map(block::Height)
|
||||
.expect("zcashd has some mature blocks: wait for zcashd to sync more blocks");
|
||||
|
||||
let starting_height = args::Args::from_args().last_checkpoint.map(BlockHeight);
|
||||
let starting_height = args::Args::from_args().last_checkpoint.map(block::Height);
|
||||
if starting_height.is_some() {
|
||||
// Since we're about to add 1, height needs to be strictly less than the maximum
|
||||
assert!(starting_height.unwrap() < BlockHeight::MAX);
|
||||
assert!(starting_height.unwrap() < block::Height::MAX);
|
||||
}
|
||||
// Start at the next block after the last checkpoint.
|
||||
// If there is no last checkpoint, start at genesis (height 0).
|
||||
let starting_height = starting_height.map_or(0, |BlockHeight(h)| h + 1);
|
||||
let starting_height = starting_height.map_or(0, |block::Height(h)| h + 1);
|
||||
|
||||
assert!(
|
||||
starting_height < height_limit.0,
|
||||
|
@ -126,7 +125,7 @@ fn main() -> Result<()> {
|
|||
|
||||
// set up counters
|
||||
let mut cumulative_bytes: u64 = 0;
|
||||
let mut height_gap: BlockHeight = BlockHeight(0);
|
||||
let mut height_gap: block::Height = block::Height(0);
|
||||
|
||||
// loop through all blocks
|
||||
for x in starting_height..height_limit.0 {
|
||||
|
@ -141,17 +140,17 @@ fn main() -> Result<()> {
|
|||
|
||||
// get the values we are interested in
|
||||
let hash: block::Hash = v["hash"].as_str().map(byte_reverse_hex).unwrap().parse()?;
|
||||
let height = BlockHeight(v["height"].as_u64().unwrap() as u32);
|
||||
assert!(height <= BlockHeight::MAX);
|
||||
let height = block::Height(v["height"].as_u64().unwrap() as u32);
|
||||
assert!(height <= block::Height::MAX);
|
||||
assert_eq!(x, height.0);
|
||||
let size = v["size"].as_u64().unwrap();
|
||||
|
||||
// compute
|
||||
cumulative_bytes += size;
|
||||
height_gap = BlockHeight(height_gap.0 + 1);
|
||||
height_gap = block::Height(height_gap.0 + 1);
|
||||
|
||||
// check if checkpoint
|
||||
if height == BlockHeight(0)
|
||||
if height == block::Height(0)
|
||||
|| cumulative_bytes >= MAX_CHECKPOINT_BYTE_COUNT
|
||||
|| height_gap.0 >= zebra_consensus::checkpoint::MAX_CHECKPOINT_HEIGHT_GAP as u32
|
||||
{
|
||||
|
@ -160,7 +159,7 @@ fn main() -> Result<()> {
|
|||
|
||||
// reset counters
|
||||
cumulative_bytes = 0;
|
||||
height_gap = BlockHeight(0);
|
||||
height_gap = block::Height(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use tower::{builder::ServiceBuilder, retry::Retry, timeout::Timeout, Service, Se
|
|||
use tracing_futures::Instrument;
|
||||
|
||||
use zebra_chain::{
|
||||
block::{Block, self},
|
||||
block::{self, Block},
|
||||
parameters::Network,
|
||||
};
|
||||
use zebra_consensus::checkpoint;
|
||||
|
|
Loading…
Reference in New Issue