diff --git a/zebra-chain/src/block/height.rs b/zebra-chain/src/block/height.rs index e367e180c..d66c670e8 100644 --- a/zebra-chain/src/block/height.rs +++ b/zebra-chain/src/block/height.rs @@ -4,6 +4,10 @@ use std::ops::{Add, Sub}; /// The height of a block is the length of the chain back to the genesis block. /// +/// Block heights can't be added, but they can be *subtracted*, +/// to get a difference of block heights, represented as an `i32`, +/// and height differences can be added to block heights to get new heights. +/// /// # Invariants /// /// Users should not construct block heights greater than `Height::MAX`. @@ -43,50 +47,34 @@ impl Height { pub const MAX_AS_U32: u32 = Self::MAX.0; } -// Block heights live in a torsor, they can only be contructed but not computed directly. -// Addition and substraction is done in the underlying types(u32) and not in the heights themselves. -// This u32 numbers are a group and they can be added and substracted normally to get a new integer. -// Having the result of the computation the `Height(X)` constructor can be used to build a new `Height`. - -// N = Height1.U - Height2.U -// Given two `Height`s use the underlying value of them to compute the difference, -// return this number as it is. impl Sub for Height { - type Output = Option; + type Output = i32; - fn sub(self, rhs: Height) -> Option { - self.0.checked_sub(rhs.0) + fn sub(self, rhs: Height) -> i32 { + (self.0 as i32) - (rhs.0 as i32) } } -// H = Height(Height.U + N) -// Given a `Height` and a number, sum the underlying value to the number, -// with the result construct a new `Height` and return it. -impl Add for Height { +impl Add for Height { type Output = Option; - fn add(self, rhs: u32) -> Option { - let result = self.0.checked_add(rhs); + fn add(self, rhs: i32) -> Option { + let result = ((self.0 as i32) + rhs) as u32; match result { - Some(h) if (Height(h) <= Height::MAX) => Some(Height(h)), - Some(_) => None, - None => None, + h if (Height(h) <= Height::MAX && Height(h) >= Height::MIN) => Some(Height(h)), + _ => None, } } } -// H = Height(Height.U - N) -// Given a `Height` and a number, substract the number to the underlying value, -// with the result construct a new `Height` and return it. -impl Sub for Height { +impl Sub for Height { type Output = Option; - fn sub(self, rhs: u32) -> Option { - let result = self.0.checked_sub(rhs); + fn sub(self, rhs: i32) -> Option { + let result = ((self.0 as i32) - rhs) as u32; match result { - Some(h) if (Height(h) >= Height::MIN) => Some(Height(h)), - Some(_) => None, - None => None, + h if (Height(h) <= Height::MAX && Height(h) >= Height::MIN) => Some(Height(h)), + _ => None, } } } @@ -113,7 +101,7 @@ fn operator_tests() { assert_eq!(Some(Height(0)), Height(1) - 1); assert_eq!(None, Height(0) - 1); - assert_eq!(Some(1), Height(2) - Height(1)); - assert_eq!(Some(0), Height(1) - Height(1)); - assert_eq!(None, Height(0) - Height(1)); + assert_eq!(1, Height(2) - Height(1)); + assert_eq!(0, Height(1) - Height(1)); + assert_eq!(-1, Height(0) - Height(1)); }