@@ -40,86 +40,96 @@ export function epochToHex(epochLike: EpochLike): Hex {
4040
4141export type EpochLike =
4242 | {
43- number : NumLike ;
44- index : NumLike ;
45- length : NumLike ;
43+ integer : NumLike ;
44+ numerator : NumLike ;
45+ denominator : NumLike ;
4646 }
4747 | [ NumLike , NumLike , NumLike ] ;
4848
4949@mol . codec (
5050 mol
5151 . struct ( {
52- length : mol . uint ( 2 , true ) ,
53- index : mol . uint ( 2 , true ) ,
54- number : mol . uint ( 3 , true ) ,
52+ padding : mol . Byte8 ,
53+ value : mol . struct ( {
54+ denominator : mol . Uint16LE ,
55+ numerator : mol . Uint16LE ,
56+ integer : mol . uint ( 3 , true ) ,
57+ } ) ,
5558 } )
56- . mapIn ( ( encodable : EpochLike ) => Epoch . from ( encodable ) ) ,
59+ . mapIn ( ( encodable : EpochLike ) => {
60+ const value = Epoch . from ( encodable ) ;
61+ return {
62+ padding : "0x0000000000000000" ,
63+ value,
64+ } ;
65+ } )
66+ . mapOut ( ( v ) => v . value as Epoch ) ,
5767)
5868/**
5969 * Epoch
6070 *
61- * Represents a timestamp-like epoch as a mixed whole number and fractional part:
62- * - number : whole units
63- * - index : numerator of the fractional part
64- * - length : denominator of the fractional part (must be > 0)
71+ * Represents a timestamp-like epoch as a mixed whole integer and fractional part:
72+ * - integer : whole units
73+ * - numerator : numerator of the fractional part
74+ * - denominator : denominator of the fractional part (must be > 0)
6575 *
66- * The fractional portion is index/length . Instances normalize fractions where
76+ * The fractional portion is numerator/denominator . Instances normalize fractions where
6777 * appropriate (e.g., reduce by GCD, carry whole units).
6878 */
6979export class Epoch extends mol . Entity . Base < EpochLike , Epoch > ( ) {
7080 /**
7181 * Construct a new Epoch.
7282 *
73- * The constructor enforces a positive `length` ( denominator) . If `length `
83+ * The constructor enforces a positive `denominator` . If `denominator `
7484 * is non-positive an Error is thrown.
7585 *
76- * @param number - Whole number portion of the epoch.
77- * @param index - Fractional numerator.
78- * @param length - Fractional denominator (must be > 0).
86+ * @param integer - Whole number portion of the epoch.
87+ * @param numerator - Fractional numerator.
88+ * @param denominator - Fractional denominator (must be > 0).
7989 */
8090 public constructor (
81- public readonly number : Num ,
82- public readonly index : Num ,
83- public readonly length : Num ,
91+ public readonly integer : Num ,
92+ public readonly numerator : Num ,
93+ public readonly denominator : Num ,
8494 ) {
8595 // Ensure the epoch has a positive denominator.
86- if ( length <= Zero ) {
87- throw new Error ( "Non positive Epoch length " ) ;
96+ if ( denominator <= Zero ) {
97+ throw new Error ( "Non positive Epoch denominator " ) ;
8898 }
8999 super ( ) ;
90100 }
91101
92102 /**
93- * @deprecated use `number ` instead
94- * Backwards-compatible array-style index 0 referencing the whole epoch number .
103+ * @deprecated use `integer ` instead
104+ * Backwards-compatible array-style index 0 referencing the whole epoch integer .
95105 */
96106 get 0 ( ) : Num {
97- return this . number ;
107+ return this . integer ;
98108 }
99109
100110 /**
101- * @deprecated use `index ` instead
111+ * @deprecated use `numerator ` instead
102112 * Backwards-compatible array-style index 1 referencing the epoch fractional numerator.
103113 */
104114 get 1 ( ) : Num {
105- return this . index ;
115+ return this . numerator ;
106116 }
107117
108118 /**
109- * @deprecated use `length ` instead
119+ * @deprecated use `denominator ` instead
110120 * Backwards-compatible array-style index 2 referencing the epoch fractional denominator.
111121 */
112122 get 2 ( ) : Num {
113- return this . length ;
123+ return this . denominator ;
114124 }
115125
116126 /**
117127 * Create an Epoch from an EpochLike value.
118128 *
119129 * Accepts:
120130 * - an Epoch instance (returned as-is)
121- * - an object { number, index, length } where each field is NumLike
122- * - a tuple [number, index, length ] where each element is NumLike
131+ * - an object { integer, numerator, denominator } where each field is NumLike
132+ * - a tuple [integer, numerator, denominator ] where each element is NumLike
123133 *
124134 * All returned fields are converted to `Num` using `numFrom`.
125135 *
@@ -131,14 +141,18 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
131141 return epochLike ;
132142 }
133143
134- let number : NumLike , index : NumLike , length : NumLike ;
135- if ( epochLike instanceof Array ) {
136- [ number , index , length ] = epochLike ;
144+ let integer : NumLike , numerator : NumLike , denominator : NumLike ;
145+ if ( Array . isArray ( epochLike ) ) {
146+ [ integer , numerator , denominator ] = epochLike ;
137147 } else {
138- ( { number , index , length } = epochLike ) ;
148+ ( { integer , numerator , denominator } = epochLike ) ;
139149 }
140150
141- return new Epoch ( numFrom ( number ) , numFrom ( index ) , numFrom ( length ) ) ;
151+ return new Epoch (
152+ numFrom ( integer ) ,
153+ numFrom ( numerator ) ,
154+ numFrom ( denominator ) ,
155+ ) ;
142156 }
143157
144158 /**
@@ -148,27 +162,20 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
148162 return new Epoch ( 0n , 0n , numFrom ( 1 ) ) ;
149163 }
150164
151- /**
152- * Return an epoch representing one (1 + 0/1).
153- */
154- static one ( ) : Epoch {
155- return new Epoch ( numFrom ( 1 ) , 0n , numFrom ( 1 ) ) ;
156- }
157-
158165 /**
159166 * Return an epoch representing one cycle (180 + 0/1).
160167 *
161168 * This is a NervosDAO convenience constant.
162169 */
163- static oneCycle ( ) : Epoch {
170+ static oneNervosDaoCycle ( ) : Epoch {
164171 return new Epoch ( numFrom ( 180 ) , 0n , numFrom ( 1 ) ) ;
165172 }
166173
167174 /**
168175 * Compare this epoch to another EpochLike.
169176 *
170177 * Comparison is performed by converting both epochs to a common integer
171- * representation: (number * length + index ) scaled by the other's length .
178+ * representation: (integer * denominator + numerator ) scaled by the other's denominator .
172179 *
173180 * @param other - EpochLike value to compare against.
174181 * @returns 1 if this > other, 0 if equal, -1 if this < other.
@@ -178,54 +185,95 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
178185 return 0 ;
179186 }
180187
181- const other_ = Epoch . from ( other ) ;
182- const a = ( this . number * this . length + this . index ) * other_ . length ;
183- const b = ( other_ . number * other_ . length + other_ . index ) * this . length ;
188+ const o = Epoch . from ( other ) ;
189+ const a =
190+ ( this . integer * this . denominator + this . numerator ) * o . denominator ;
191+ const b = ( o . integer * o . denominator + o . numerator ) * this . denominator ;
184192
185193 return a > b ? 1 : a < b ? - 1 : 0 ;
186194 }
187195
188196 /**
189- * Check equality with another EpochLike.
197+ * Check whether this epoch is less than another EpochLike.
198+ *
199+ * @param other - EpochLike to compare against.
200+ * @returns true if this epoch is strictly less than the other.
201+ */
202+ lt ( other : EpochLike ) : boolean {
203+ return this . compare ( other ) < 0 ;
204+ }
205+
206+ /**
207+ * Check whether this epoch is less than or equal to another EpochLike.
208+ *
209+ * @param other - EpochLike to compare against.
210+ * @returns true if this epoch is less than or equal to the other.
211+ */
212+ le ( other : EpochLike ) : boolean {
213+ return this . compare ( other ) <= 0 ;
214+ }
215+
216+ /**
217+ * Check whether this epoch is equal to another EpochLike.
190218 *
191- * @param other - EpochLike to test equality against.
219+ * @param other - EpochLike to compare against.
192220 * @returns true if both epochs represent the same value.
193221 */
194222 eq ( other : EpochLike ) : boolean {
195223 return this . compare ( other ) === 0 ;
196224 }
197225
226+ /**
227+ * Check whether this epoch is greater than or equal to another EpochLike.
228+ *
229+ * @param other - EpochLike to compare against.
230+ * @returns true if this epoch is greater than or equal to the other.
231+ */
232+ ge ( other : EpochLike ) : boolean {
233+ return this . compare ( other ) >= 0 ;
234+ }
235+
236+ /**
237+ * Check whether this epoch is greater than another EpochLike.
238+ *
239+ * @param other - EpochLike to compare against.
240+ * @returns true if this epoch is strictly greater than the other.
241+ */
242+ gt ( other : EpochLike ) : boolean {
243+ return this . compare ( other ) > 0 ;
244+ }
245+
198246 /**
199247 * Return a normalized epoch:
200- * - Ensures index is non-negative by borrowing from `number ` if needed.
201- * - Reduces the fraction (index/length ) by their GCD.
202- * - Carries any whole units from the fraction into `number `.
248+ * - Ensures numerator is non-negative by borrowing from `integer ` if needed.
249+ * - Reduces the fraction (numerator/denominator ) by their GCD.
250+ * - Carries any whole units from the fraction into `integer `.
203251 *
204252 * @returns A new, normalized Epoch instance.
205253 */
206254 normalized ( ) : Epoch {
207- let { number , index , length } = this ;
255+ let { integer , numerator , denominator } = this ;
208256
209- // Normalize negative index values by borrowing from the whole number .
210- if ( index < Zero ) {
257+ // Normalize negative numerator values by borrowing from the whole integer .
258+ if ( numerator < Zero ) {
211259 // Calculate how many whole units to borrow.
212- const n = ( - index + length - 1n ) / length ;
213- number -= n ;
214- index += length * n ;
260+ const n = ( - numerator + denominator - 1n ) / denominator ;
261+ integer -= n ;
262+ numerator += denominator * n ;
215263 }
216264
217- // Reduce the fraction (index / length ) to its simplest form using the greatest common divisor.
218- const g = gcd ( index , length ) ;
219- index /= g ;
220- length /= g ;
265+ // Reduce the fraction (numerator / denominator ) to its simplest form using the greatest common divisor.
266+ const g = gcd ( numerator , denominator ) ;
267+ numerator /= g ;
268+ denominator /= g ;
221269
222- // Add any whole number overflow from the fraction.
223- number += index / length ;
270+ // Add any whole integer overflow from the fraction.
271+ integer += numerator / denominator ;
224272
225- // Calculate the leftover index after accounting for the whole number part from the fraction.
226- index %= length ;
273+ // Calculate the leftover numerator after accounting for the whole integer part from the fraction.
274+ numerator %= denominator ;
227275
228- return new Epoch ( number , index , length ) ;
276+ return new Epoch ( integer , numerator , denominator ) ;
229277 }
230278
231279 /**
@@ -238,24 +286,25 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
238286 * @returns New Epoch equal to this + other.
239287 */
240288 add ( other : EpochLike ) : Epoch {
241- const other_ = Epoch . from ( other ) ;
242-
243- // Sum the whole number parts.
244- const number = this . number + other_ . number ;
245- let index : Num ;
246- let length : Num ;
247-
248- // If the epochs have different denominators (lengths), align them to a common denominator.
249- if ( this . length !== other_ . length ) {
250- index = other_ . index * this . length + this . index * other_ . length ;
251- length = this . length * other_ . length ;
289+ const o = Epoch . from ( other ) ;
290+
291+ // Sum the whole integer parts.
292+ const integer = this . integer + o . integer ;
293+ let numerator : Num ;
294+ let denominator : Num ;
295+
296+ // If the epochs have different denominators, align them to a common denominator.
297+ if ( this . denominator !== o . denominator ) {
298+ numerator =
299+ o . numerator * this . denominator + this . numerator * o . denominator ;
300+ denominator = this . denominator * o . denominator ;
252301 } else {
253- // If denominators are equal, simply add the indices .
254- index = this . index + other_ . index ;
255- length = this . length ;
302+ // If denominators are equal, simply add the numerators .
303+ numerator = this . numerator + o . numerator ;
304+ denominator = this . denominator ;
256305 }
257306
258- return new Epoch ( number , index , length ) . normalized ( ) ;
307+ return new Epoch ( integer , numerator , denominator ) . normalized ( ) ;
259308 }
260309
261310 /**
@@ -265,8 +314,8 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
265314 * @returns New Epoch equal to this - other.
266315 */
267316 sub ( other : EpochLike ) : Epoch {
268- const { number , index , length } = Epoch . from ( other ) ;
269- return this . add ( new Epoch ( - number , - index , length ) ) ;
317+ const { integer , numerator , denominator } = Epoch . from ( other ) ;
318+ return this . add ( new Epoch ( - integer , - numerator , denominator ) ) ;
270319 }
271320
272321 /**
@@ -277,12 +326,12 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
277326 */
278327 toUnix ( reference : ClientBlockHeader ) : bigint {
279328 // Calculate the difference between the provided epoch and the reference epoch.
280- const { number , index , length } = this . sub ( reference . epoch ) ;
329+ const { integer , numerator , denominator } = this . sub ( reference . epoch ) ;
281330
282331 return (
283332 reference . timestamp +
284- epochInMilliseconds * number +
285- ( epochInMilliseconds * index ) / length
333+ EPOCH_IN_MILLISECONDS * integer +
334+ ( EPOCH_IN_MILLISECONDS * numerator ) / denominator
286335 ) ;
287336 }
288337}
@@ -293,4 +342,4 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
293342 * Calculated as 4 hours in milliseconds:
294343 * 4 hours * 60 minutes per hour * 60 seconds per minute * 1000 milliseconds per second.
295344 */
296- const epochInMilliseconds = numFrom ( 14400000 ) ; // (Number.isSafeInteger(14400000) === true)
345+ const EPOCH_IN_MILLISECONDS = numFrom ( 4 * 60 * 60 * 1000 ) ;
0 commit comments