Skip to content

Commit 2f810b6

Browse files
authored
Merge pull request #168 from everdimension/update-payload-id-generator
Improve payloadId generator
2 parents 4cf8684 + cbaedce commit 2f810b6

File tree

2 files changed

+88
-9
lines changed

2 files changed

+88
-9
lines changed

jsonrpc/utils/src/format.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,34 @@ import { getError, getErrorByCode, isReservedErrorCode } from "./error";
22
import { INTERNAL_ERROR, SERVER_ERROR } from "./constants";
33
import { ErrorResponse, JsonRpcError, JsonRpcRequest, JsonRpcResult } from "./types";
44

5-
export function payloadId(entropy = 3): number {
6-
const date = Date.now() * Math.pow(10, entropy);
7-
const extra = Math.floor(Math.random() * Math.pow(10, entropy));
5+
class IncrementalRandomGenerator {
6+
private initialValue: number;
7+
private i = 1;
8+
9+
constructor(bits: 8 | 16 | 32) {
10+
const typedArray =
11+
bits === 8 ? new Uint8Array(1) : bits === 16 ? new Uint16Array(1) : new Uint32Array(1);
12+
this.initialValue = crypto.getRandomValues(typedArray)[0];
13+
}
14+
15+
getNextValue() {
16+
return this.initialValue + this.i++;
17+
}
18+
}
19+
20+
const uint8Generator = new IncrementalRandomGenerator(8);
21+
const uint16Generator = new IncrementalRandomGenerator(16);
22+
23+
export function payloadId(): number {
24+
const date = Date.now() * 1000;
25+
const extra = uint8Generator.getNextValue();
826
return date + extra;
927
}
1028

11-
export function getBigIntRpcId(entropy = 6): bigint {
12-
return BigInt(payloadId(entropy));
29+
export function getBigIntRpcId(): bigint {
30+
const date = BigInt(Date.now()) * BigInt(1000000);
31+
const extra = BigInt(uint16Generator.getNextValue());
32+
return date + extra;
1333
}
1434

1535
export function formatJsonRpcRequest<T = any>(

jsonrpc/utils/test/payloadId.test.ts

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ describe("Payload Id", () => {
2525
chai.expect(payloadId().toString().length).to.equal(16);
2626
});
2727

28-
it("returns a bigint with 19 digits", () => {
29-
chai.expect(getBigIntRpcId().toString().length).to.equal(19);
30-
});
31-
3228
// Context: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
3329
it("returns a safe integer", () => {
3430
chai.expect(Number.isSafeInteger(payloadId())).to.be.true;
@@ -46,4 +42,67 @@ describe("Payload Id", () => {
4642
const duplicates = findDuplicates(results);
4743
chai.expect(duplicates.length === 0).to.be.true;
4844
});
45+
46+
it("generates increasing values when called within same tick", () => {
47+
let i = 0;
48+
while (i++ < 10000) {
49+
const value1 = payloadId();
50+
const value2 = payloadId();
51+
const value3 = payloadId();
52+
const value4 = payloadId();
53+
if (value1 >= value2 || value2 >= value3 || value3 >= value4) {
54+
chai.assert.fail("Not increasing values");
55+
}
56+
}
57+
chai.assert.isOk("Pass");
58+
});
59+
60+
it("generates non-repeating values when called within same tick", () => {
61+
let i = 0;
62+
while (i++ < 10000) {
63+
const values = [payloadId(), payloadId(), payloadId(), payloadId()];
64+
const set = new Set(values);
65+
if (set.size !== values.length) {
66+
chai.assert.fail("Not unique values");
67+
}
68+
}
69+
chai.assert.isOk("Pass");
70+
});
71+
});
72+
73+
describe("Get BigInt Rpc Id", () => {
74+
it("returns a bigint", () => {
75+
const value = getBigIntRpcId();
76+
chai.expect(typeof value === "bigint").to.be.true;
77+
});
78+
79+
it("returns a bigint with 19 digits", () => {
80+
chai.expect(getBigIntRpcId().toString().length).to.equal(19);
81+
});
82+
83+
it("generates increasing values when called within same tick", () => {
84+
let i = 0;
85+
while (i++ < 10000) {
86+
const value1 = getBigIntRpcId();
87+
const value2 = getBigIntRpcId();
88+
const value3 = getBigIntRpcId();
89+
const value4 = getBigIntRpcId();
90+
if (value1 >= value2 || value2 >= value3 || value3 >= value4) {
91+
chai.assert.fail("Not increasing values");
92+
}
93+
}
94+
chai.assert.isOk("Pass");
95+
});
96+
97+
it("generates non-repeating values when called within same tick", () => {
98+
let i = 0;
99+
while (i++ < 10000) {
100+
const values = [getBigIntRpcId(), getBigIntRpcId(), getBigIntRpcId(), getBigIntRpcId()];
101+
const set = new Set(values);
102+
if (set.size !== values.length) {
103+
chai.assert.fail("Not unique values");
104+
}
105+
}
106+
chai.assert.isOk("Pass");
107+
});
49108
});

0 commit comments

Comments
 (0)