Skip to content

Commit 63aa8e4

Browse files
committed
feat(Epoch): apply Hanssen feedback
1 parent b0810f1 commit 63aa8e4

File tree

3 files changed

+97
-95
lines changed

3 files changed

+97
-95
lines changed

packages/core/src/ckb/epoch.ts

Lines changed: 83 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -40,86 +40,86 @@ export function epochToHex(epochLike: EpochLike): Hex {
4040

4141
export 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+
denominator: mol.uint(2, true),
53+
numerator: mol.uint(2, true),
54+
integer: mol.uint(3, true),
5555
})
5656
.mapIn((encodable: EpochLike) => Epoch.from(encodable)),
5757
)
5858
/**
5959
* Epoch
6060
*
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)
61+
* Represents a timestamp-like epoch as a mixed whole integer and fractional part:
62+
* - integer: whole units
63+
* - numerator: numerator of the fractional part
64+
* - denominator: denominator of the fractional part (must be > 0)
6565
*
66-
* The fractional portion is index/length. Instances normalize fractions where
66+
* The fractional portion is numerator/denominator. Instances normalize fractions where
6767
* appropriate (e.g., reduce by GCD, carry whole units).
6868
*/
6969
export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
7070
/**
7171
* Construct a new Epoch.
7272
*
73-
* The constructor enforces a positive `length` (denominator). If `length`
73+
* The constructor enforces a positive `denominator`. If `denominator`
7474
* is non-positive an Error is thrown.
7575
*
76-
* @param number - Whole number portion of the epoch.
77-
* @param index - Fractional numerator.
78-
* @param length - Fractional denominator (must be > 0).
76+
* @param integer - Whole number portion of the epoch.
77+
* @param numerator - Fractional numerator.
78+
* @param denominator - Fractional denominator (must be > 0).
7979
*/
8080
public constructor(
81-
public readonly number: Num,
82-
public readonly index: Num,
83-
public readonly length: Num,
81+
public readonly integer: Num,
82+
public readonly numerator: Num,
83+
public readonly denominator: Num,
8484
) {
8585
// Ensure the epoch has a positive denominator.
86-
if (length <= Zero) {
87-
throw new Error("Non positive Epoch length");
86+
if (denominator <= Zero) {
87+
throw new Error("Non positive Epoch denominator");
8888
}
8989
super();
9090
}
9191

9292
/**
93-
* @deprecated use `number` instead
94-
* Backwards-compatible array-style index 0 referencing the whole epoch number.
93+
* @deprecated use `integer` instead
94+
* Backwards-compatible array-style index 0 referencing the whole epoch integer.
9595
*/
9696
get 0(): Num {
97-
return this.number;
97+
return this.integer;
9898
}
9999

100100
/**
101-
* @deprecated use `index` instead
101+
* @deprecated use `numerator` instead
102102
* Backwards-compatible array-style index 1 referencing the epoch fractional numerator.
103103
*/
104104
get 1(): Num {
105-
return this.index;
105+
return this.numerator;
106106
}
107107

108108
/**
109-
* @deprecated use `length` instead
109+
* @deprecated use `denominator` instead
110110
* Backwards-compatible array-style index 2 referencing the epoch fractional denominator.
111111
*/
112112
get 2(): Num {
113-
return this.length;
113+
return this.denominator;
114114
}
115115

116116
/**
117117
* Create an Epoch from an EpochLike value.
118118
*
119119
* Accepts:
120120
* - 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
121+
* - an object { integer, numerator, denominator } where each field is NumLike
122+
* - a tuple [integer, numerator, denominator] where each element is NumLike
123123
*
124124
* All returned fields are converted to `Num` using `numFrom`.
125125
*
@@ -131,14 +131,18 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
131131
return epochLike;
132132
}
133133

134-
let number: NumLike, index: NumLike, length: NumLike;
135-
if (epochLike instanceof Array) {
136-
[number, index, length] = epochLike;
134+
let integer: NumLike, numerator: NumLike, denominator: NumLike;
135+
if (Array.isArray(epochLike)) {
136+
[integer, numerator, denominator] = epochLike;
137137
} else {
138-
({ number, index, length } = epochLike);
138+
({ integer, numerator, denominator } = epochLike);
139139
}
140140

141-
return new Epoch(numFrom(number), numFrom(index), numFrom(length));
141+
return new Epoch(
142+
numFrom(integer),
143+
numFrom(numerator),
144+
numFrom(denominator),
145+
);
142146
}
143147

144148
/**
@@ -148,13 +152,6 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
148152
return new Epoch(0n, 0n, numFrom(1));
149153
}
150154

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-
158155
/**
159156
* Return an epoch representing one cycle (180 + 0/1).
160157
*
@@ -168,7 +165,7 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
168165
* Compare this epoch to another EpochLike.
169166
*
170167
* Comparison is performed by converting both epochs to a common integer
171-
* representation: (number * length + index) scaled by the other's length.
168+
* representation: (integer * denominator + numerator) scaled by the other's denominator.
172169
*
173170
* @param other - EpochLike value to compare against.
174171
* @returns 1 if this > other, 0 if equal, -1 if this < other.
@@ -178,9 +175,10 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
178175
return 0;
179176
}
180177

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;
178+
const o = Epoch.from(other);
179+
const a =
180+
(this.integer * this.denominator + this.numerator) * o.denominator;
181+
const b = (o.integer * o.denominator + o.numerator) * this.denominator;
184182

185183
return a > b ? 1 : a < b ? -1 : 0;
186184
}
@@ -197,35 +195,35 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
197195

198196
/**
199197
* 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`.
198+
* - Ensures numerator is non-negative by borrowing from `integer` if needed.
199+
* - Reduces the fraction (numerator/denominator) by their GCD.
200+
* - Carries any whole units from the fraction into `integer`.
203201
*
204202
* @returns A new, normalized Epoch instance.
205203
*/
206204
normalized(): Epoch {
207-
let { number, index, length } = this;
205+
let { integer, numerator, denominator } = this;
208206

209-
// Normalize negative index values by borrowing from the whole number.
210-
if (index < Zero) {
207+
// Normalize negative numerator values by borrowing from the whole integer.
208+
if (numerator < Zero) {
211209
// Calculate how many whole units to borrow.
212-
const n = (-index + length - 1n) / length;
213-
number -= n;
214-
index += length * n;
210+
const n = (-numerator + denominator - 1n) / denominator;
211+
integer -= n;
212+
numerator += denominator * n;
215213
}
216214

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;
215+
// Reduce the fraction (numerator / denominator) to its simplest form using the greatest common divisor.
216+
const g = gcd(numerator, denominator);
217+
numerator /= g;
218+
denominator /= g;
221219

222-
// Add any whole number overflow from the fraction.
223-
number += index / length;
220+
// Add any whole integer overflow from the fraction.
221+
integer += numerator / denominator;
224222

225-
// Calculate the leftover index after accounting for the whole number part from the fraction.
226-
index %= length;
223+
// Calculate the leftover numerator after accounting for the whole integer part from the fraction.
224+
numerator %= denominator;
227225

228-
return new Epoch(number, index, length);
226+
return new Epoch(integer, numerator, denominator);
229227
}
230228

231229
/**
@@ -238,24 +236,25 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
238236
* @returns New Epoch equal to this + other.
239237
*/
240238
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;
239+
const o = Epoch.from(other);
240+
241+
// Sum the whole integer parts.
242+
const integer = this.integer + o.integer;
243+
let numerator: Num;
244+
let denominator: Num;
245+
246+
// If the epochs have different denominators, align them to a common denominator.
247+
if (this.denominator !== o.denominator) {
248+
numerator =
249+
o.numerator * this.denominator + this.numerator * o.denominator;
250+
denominator = this.denominator * o.denominator;
252251
} else {
253-
// If denominators are equal, simply add the indices.
254-
index = this.index + other_.index;
255-
length = this.length;
252+
// If denominators are equal, simply add the numerators.
253+
numerator = this.numerator + o.numerator;
254+
denominator = this.denominator;
256255
}
257256

258-
return new Epoch(number, index, length).normalized();
257+
return new Epoch(integer, numerator, denominator).normalized();
259258
}
260259

261260
/**
@@ -265,8 +264,8 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
265264
* @returns New Epoch equal to this - other.
266265
*/
267266
sub(other: EpochLike): Epoch {
268-
const { number, index, length } = Epoch.from(other);
269-
return this.add(new Epoch(-number, -index, length));
267+
const { integer, numerator, denominator } = Epoch.from(other);
268+
return this.add(new Epoch(-integer, -numerator, denominator));
270269
}
271270

272271
/**
@@ -277,12 +276,12 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
277276
*/
278277
toUnix(reference: ClientBlockHeader): bigint {
279278
// Calculate the difference between the provided epoch and the reference epoch.
280-
const { number, index, length } = this.sub(reference.epoch);
279+
const { integer, numerator, denominator } = this.sub(reference.epoch);
281280

282281
return (
283282
reference.timestamp +
284-
epochInMilliseconds * number +
285-
(epochInMilliseconds * index) / length
283+
EPOCH_IN_MILLISECONDS * integer +
284+
(EPOCH_IN_MILLISECONDS * numerator) / denominator
286285
);
287286
}
288287
}
@@ -293,4 +292,4 @@ export class Epoch extends mol.Entity.Base<EpochLike, Epoch>() {
293292
* Calculated as 4 hours in milliseconds:
294293
* 4 hours * 60 minutes per hour * 60 seconds per minute * 1000 milliseconds per second.
295294
*/
296-
const epochInMilliseconds = numFrom(14400000); // (Number.isSafeInteger(14400000) === true)
295+
const EPOCH_IN_MILLISECONDS = numFrom(4 * 60 * 60 * 1000);

packages/core/src/ckb/transaction.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,12 +2467,12 @@ export function calcDaoProfit(
24672467
*
24682468
* @param depositHeader - The block header when the DAO deposit was made.
24692469
* @param withdrawHeader - The block header when the DAO withdrawal was initiated.
2470-
* @returns The epoch when the withdrawal can be claimed, represented as [number, index, length].
2470+
* @returns The epoch when the withdrawal can be claimed, represented as [integer, numerator, denominator].
24712471
*
24722472
* @example
24732473
* ```typescript
24742474
* const epoch = calcDaoClaimEpoch(depositHeader, withdrawHeader);
2475-
* console.log(`Can claim at epoch: ${epoch.number}, index: ${epoch.index}, length: ${epoch.length}`);
2475+
* console.log(`Can claim at epoch: ${epoch.integer}, numerator: ${epoch.numerator}, denominator: ${epoch.denominator}`);
24762476
* ```
24772477
*
24782478
* @remarks
@@ -2489,20 +2489,21 @@ export function calcDaoClaimEpoch(
24892489
const deposit = ClientBlockHeader.from(depositHeader).epoch;
24902490
const withdraw = ClientBlockHeader.from(withdrawHeader).epoch;
24912491

2492-
const partialCycle = (withdraw.number - deposit.number) % fullCycle;
2493-
let withdrawNumber = withdraw.number;
2492+
const partialCycle = (withdraw.integer - deposit.integer) % fullCycle;
2493+
let withdrawNumber = withdraw.integer;
24942494
if (
24952495
partialCycle !== Zero ||
2496-
// deposit.index withdraw.index
2497-
// --------------- <= -----------------
2498-
// deposit.length withdraw.length
2499-
deposit.index * withdraw.length <= withdraw.index * deposit.length
2496+
// deposit.numerator withdraw.numerator
2497+
// --------------------- <= ----------------------
2498+
// deposit.denominator withdraw.denominator
2499+
deposit.numerator * withdraw.denominator <=
2500+
withdraw.numerator * deposit.denominator
25002501
) {
25012502
// Need to wait for the next cycle
25022503
withdrawNumber += -partialCycle + fullCycle;
25032504
}
25042505

2505-
return new Epoch(withdrawNumber, deposit.index, deposit.length);
2506+
return new Epoch(withdrawNumber, deposit.numerator, deposit.denominator);
25062507
}
25072508

25082509
const fullCycle = numFrom(180);

packages/core/src/utils/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,15 @@ export function stringify(val: unknown) {
267267
}
268268

269269
/**
270-
* Calculate the greatest common divisor (GCD) of two Num values using the Euclidean algorithm.
270+
* Calculate the greatest common divisor (GCD) of two NumLike values using the Euclidean algorithm.
271271
*
272272
* @param a - First operand.
273273
* @param b - Second operand.
274274
* @returns GCD(a, b) as a Num.
275275
*/
276-
export function gcd(a: Num, b: Num): Num {
276+
export function gcd(a: NumLike, b: NumLike): Num {
277+
a = numFrom(a);
278+
b = numFrom(b);
277279
a = a < Zero ? -a : a;
278280
b = b < Zero ? -b : b;
279281
while (b !== Zero) {

0 commit comments

Comments
 (0)