Skip to content

Commit 42b3a8e

Browse files
Add pseudo random jitter generator
1 parent f16cb65 commit 42b3a8e

File tree

14 files changed

+130
-40
lines changed

14 files changed

+130
-40
lines changed

bun.lockb

722 Bytes
Binary file not shown.

crawler/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { getSigningCosmWasmClient } from '../lib/stargate';
1717
import { validateOnChainContractInfo } from '../lib/validations/config';
1818
import { getValidData } from '../types/utils';
1919
import { dropletRuleSchema } from '../types/config/dropletRule';
20+
import { getPseudoRandom, getTrueRandom } from './random';
2021

2122
const program = new Command();
2223
program.option('--config <config>', 'Config file path', 'config.toml');
@@ -126,7 +127,10 @@ program
126127

127128
const assetsToGetPrice = new Set<string>();
128129
const protocolIds = new Set<string>();
129-
const timeShift = Math.random();
130+
const timeShift =
131+
config.random && config.random === 'pseudo'
132+
? await getPseudoRandom(config.protocols['neutron']?.rpc)
133+
: getTrueRandom();
130134

131135
for (const protocol of protocolsInDb) {
132136
if (protocolIds.has(protocol.protocol_id)) {
@@ -140,7 +144,7 @@ program
140144
assetsToGetPrice.add(assetId.split('_')[0]);
141145
}
142146

143-
const jitter = (protocolObj.jitter * timeShift) | 0;
147+
const jitter = Math.round(protocolObj.jitter * timeShift) | 0;
144148
if (!jitter) {
145149
logger.warn('Jitter is 0 for protocol %s', protocol.protocol_id);
146150
}

crawler/random.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
2+
import seedrandom from 'seedrandom';
3+
4+
const getTrueRandom = () => Math.random();
5+
6+
const uint8ArrayToHex = (array: Uint8Array): string =>
7+
Array.from(array)
8+
.map((byte) => byte.toString(16).padStart(2, '0'))
9+
.join('');
10+
11+
const getPseudoRandom = async (neutronRpc: string) => {
12+
if (!neutronRpc) {
13+
throw new Error('neutron RPC is not specified!');
14+
}
15+
16+
const client = await Tendermint34Client.connect(neutronRpc);
17+
const status = await client.status();
18+
19+
const blockHeight = Math.floor(status.syncInfo.latestBlockHeight / 100) * 100;
20+
const block = await client.block(blockHeight);
21+
const blockHash = block?.blockId?.hash;
22+
const hexHash = blockHash ? uint8ArrayToHex(blockHash) : undefined;
23+
24+
client.disconnect();
25+
26+
const rng = seedrandom(hexHash);
27+
return rng();
28+
};
29+
30+
export { getTrueRandom, getPseudoRandom };

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@trpc/server": "^10.45.2",
2020
"@types/lodash": "^4.17.4",
2121
"@types/pg": "^8.11.10",
22+
"@types/seedrandom": "^3.0.8",
2223
"bech32": "^2.0.0",
2324
"commander": "^12.0.0",
2425
"cosmjs-types": "^0.9.0",
@@ -36,6 +37,7 @@
3637
"pm2": "^5.4.2",
3738
"prom-client": "^15.1.2",
3839
"rimraf": "^5.0.7",
40+
"seedrandom": "^3.0.5",
3941
"toml": "^3.0.0",
4042
"zod": "^3.24.0-canary.20240523T174819"
4143
},

server/controllers/getDroplets/index.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { TRPCError } from '@trpc/server';
2-
import { Client } from 'pg';
32

43
import {
54
tRPCGetDropletsRequest,
65
tRPCGetDropletsResponse,
76
} from '../../../types/tRPC/tRPCGetDroplets';
87
import { Logger } from 'pino';
8+
import { connect } from '../../../db';
99

1010
const getDroplets =
11-
(db: Client, logger: Logger) =>
11+
(config: any, logger: Logger) =>
1212
async (req: tRPCGetDropletsRequest): Promise<tRPCGetDropletsResponse> => {
13+
const db = await connect(true, config, logger);
14+
1315
const {
1416
input: { address },
1517
} = req;
@@ -18,8 +20,12 @@ const getDroplets =
1820

1921
let row = null;
2022
try {
21-
const result = await db.query(
22-
'SELECT points + points_l1 + points_l2 as points, change, place FROM user_points_public WHERE address = $1 LIMIT 1',
23+
const result = await db.query<{
24+
points: number;
25+
change: number;
26+
place: number;
27+
}>(
28+
'SELECT (points + points_l1 + points_l2)::int as points, change::int as change, place::int as place FROM user_points_public WHERE address = $1 LIMIT 1',
2329
[address],
2430
);
2531
row = result.rows[0];
@@ -29,6 +35,8 @@ const getDroplets =
2935
(e as Error).message,
3036
);
3137

38+
await db.end();
39+
3240
throw new TRPCError({
3341
code: 'INTERNAL_SERVER_ERROR',
3442
message: 'Unexpected error occurred',
@@ -40,6 +48,9 @@ const getDroplets =
4048
'Address %s not found in public user points table',
4149
req.input.address,
4250
);
51+
52+
await db.end();
53+
4354
throw new TRPCError({
4455
code: 'NOT_FOUND',
4556
message: 'Address not found',
@@ -49,7 +60,7 @@ const getDroplets =
4960
let countResult;
5061
try {
5162
const countRes = await db.query(
52-
'SELECT count(*) as total FROM user_points_public',
63+
'SELECT count(*)::int as total FROM user_points_public',
5364
);
5465
countResult = countRes.rows[0];
5566
} catch (e) {
@@ -62,6 +73,8 @@ const getDroplets =
6273
code: 'INTERNAL_SERVER_ERROR',
6374
message: 'Unexpected error occurred',
6475
});
76+
} finally {
77+
await db.end();
6578
}
6679

6780
if (!countResult) {

server/controllers/getKVData/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import {
66
tRPCGetKVDataRequest,
77
tRPCGetKVDataResponse,
88
} from '../../../types/tRPC/tRPCGetKVData';
9+
import { connect } from '../../../db';
910

1011
const getKVData =
11-
(db: Client, logger: Logger) =>
12+
(config: any, logger: Logger) =>
1213
async (req: tRPCGetKVDataRequest): Promise<tRPCGetKVDataResponse> => {
14+
const db = await connect(true, config, logger);
15+
1316
const {
1417
input: { key },
1518
} = req;
@@ -32,6 +35,8 @@ const getKVData =
3235
code: 'INTERNAL_SERVER_ERROR',
3336
message: 'Unexpected error occurred',
3437
});
38+
} finally {
39+
await db.end();
3540
}
3641

3742
if (!row) {

server/controllers/getReferralCode/index.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
import { TRPCError } from '@trpc/server';
2-
import { Client } from 'pg';
32

43
import {
54
tRPCGetReferralCodeRequest,
65
tRPCGetReferralCodeResponse,
76
} from '../../../types/tRPC/tRPCGetReferralCode';
87
import { Logger } from 'pino';
8+
import { connect } from '../../../db';
99

1010
const UNEXPECTED_TRPC_ERROR = new TRPCError({
1111
code: 'INTERNAL_SERVER_ERROR',
1212
message: 'Unexpected error occurred',
1313
});
1414

1515
const getReferralCode =
16-
(db: Client, logger: Logger) =>
16+
(config: any, logger: Logger) =>
1717
async (
1818
req: tRPCGetReferralCodeRequest,
1919
): Promise<tRPCGetReferralCodeResponse> => {
20+
const db = await connect(true, config, logger);
21+
2022
const {
2123
input: { address },
2224
} = req;
@@ -30,9 +32,9 @@ const getReferralCode =
3032
try {
3133
const { rows } = await db.query(
3234
`SELECT
33-
uk.referral_code AS referralCode,
34-
CASE WHEN b.address IS NULL THEN 0 ELSE 1 END AS blacklisted,
35-
CASE WHEN uk.address IS NULL THEN 0 ELSE 1 END AS kycPassed
35+
uk.referral_code AS "referralCode",
36+
CASE WHEN b.address IS NULL THEN 0 ELSE 1 END AS "blacklisted",
37+
CASE WHEN uk.address IS NULL THEN 0 ELSE 1 END AS "kycPassed"
3638
FROM
3739
(SELECT $1 AS address) f
3840
LEFT JOIN blacklist b ON b.address = f.address
@@ -49,13 +51,16 @@ const getReferralCode =
4951
);
5052

5153
throw UNEXPECTED_TRPC_ERROR;
54+
} finally {
55+
await db.end();
5256
}
5357

5458
if (!row) {
5559
logger.error(
5660
'Referral code cannot be fetched for %s from user KYC table',
5761
address,
5862
);
63+
5964
throw new TRPCError({
6065
code: 'UNPROCESSABLE_CONTENT',
6166
message: 'Failed to fetch data',
@@ -66,6 +71,7 @@ const getReferralCode =
6671

6772
if (blacklisted) {
6873
logger.error('The address %s is blacklisted', address);
74+
6975
throw new TRPCError({
7076
code: 'FORBIDDEN',
7177
message: 'This address is blacklisted',
@@ -74,6 +80,7 @@ const getReferralCode =
7480

7581
if (!kycPassed) {
7682
logger.error('KYC is not passed for %s', address);
83+
7784
throw new TRPCError({
7885
code: 'NOT_FOUND',
7986
message: 'KYC is not passed',
@@ -85,6 +92,7 @@ const getReferralCode =
8592
'KYC passed for %s but referral code not found in user KYC table',
8693
address,
8794
);
95+
8896
throw new TRPCError({
8997
code: 'CONFLICT',
9098
message: 'Referral code not found',

server/controllers/getReferrals/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import { TRPCError } from '@trpc/server';
2-
import { Client } from 'pg';
32

43
import {
54
referral,
65
tRPCGetReferralsRequest,
76
tRPCGetReferralsResponse,
87
} from '../../../types/tRPC/tRPCGetReferrals';
98
import { Logger } from 'pino';
9+
import { connect } from '../../../db';
1010

1111
const getReferrals =
12-
(db: Client, config: any, logger: Logger) =>
12+
(config: any, logger: Logger) =>
1313
async (req: tRPCGetReferralsRequest): Promise<tRPCGetReferralsResponse> => {
14+
const db = await connect(true, config, logger);
15+
1416
const {
1517
input: { address },
1618
} = req;
@@ -25,7 +27,7 @@ const getReferrals =
2527
let rows: dbResponse[] | null = [];
2628
try {
2729
const queryResult = await db.query(
28-
`SELECT r1.referral as l1Referral, r2.referral as l2Referral
30+
`SELECT r1.referral as "l1Referral", r2.referral as "l2Referral"
2931
FROM referrals r1
3032
LEFT JOIN referrals r2 ON r2.referrer = r1.referral
3133
WHERE r1.referrer = $1`,
@@ -42,6 +44,8 @@ const getReferrals =
4244
code: 'INTERNAL_SERVER_ERROR',
4345
message: 'Unexpected error occurred',
4446
});
47+
} finally {
48+
await db.end();
4549
}
4650

4751
if (!rows) {
@@ -93,6 +97,8 @@ const getReferrals =
9397
});
9498
}
9599
}
100+
101+
console.log(referrals);
96102
return { referrals };
97103
};
98104

server/controllers/getReferrer/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { TRPCError } from '@trpc/server';
2-
import { Client } from 'pg';
32

43
import {
54
tRPCGetReferrerRequest,
65
tRPCGetReferrerResponse,
76
} from '../../../types/tRPC/tRPCGetReferrer';
87
import { Logger } from 'pino';
8+
import { connect } from '../../../db';
99

1010
const getReferrer =
11-
(db: Client, logger: Logger) =>
11+
(config: any, logger: Logger) =>
1212
async (req: tRPCGetReferrerRequest): Promise<tRPCGetReferrerResponse> => {
13+
const db = await connect(true, config, logger);
14+
1315
const {
1416
input: { referralCode },
1517
} = req;
@@ -32,17 +34,22 @@ const getReferrer =
3234
(e as Error).message,
3335
);
3436

37+
await db.end();
38+
3539
throw new TRPCError({
3640
code: 'INTERNAL_SERVER_ERROR',
3741
message: 'Unexpected error occurred',
3842
});
43+
} finally {
44+
await db.end();
3945
}
4046

4147
if (!row) {
4248
logger.error(
4349
'Referrer address for code %s not found in user KYC table',
4450
referralCode,
4551
);
52+
4653
throw new TRPCError({
4754
code: 'NOT_FOUND',
4855
message: 'Referrer not found',

server/controllers/getRules/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { Client } from 'pg';
21
import { Logger } from 'pino';
32
import { tRPCGetRulesResponse } from '../../../types/tRPC/tRPCGetRules';
43
import { TRPCError } from '@trpc/server';
4+
import { connect } from '../../../db';
55

66
const getRules =
7-
(db: Client, logger: Logger) => async (): Promise<tRPCGetRulesResponse> => {
7+
(config: any, logger: Logger) => async (): Promise<tRPCGetRulesResponse> => {
88
logger.debug('Receiving request to get Droplet rules');
99

10+
const db = await connect(true, config, logger);
11+
1012
type dbResponse = {
1113
strategy: string;
1214
description: string;
@@ -25,11 +27,11 @@ const getRules =
2527
`SELECT
2628
strategy,
2729
description,
28-
multiplier AS dropRate,
30+
multiplier AS "dropRate",
2931
chain,
3032
status,
3133
link,
32-
link_text AS linkText,
34+
link_text AS "linkText",
3335
type,
3436
featured
3537
FROM user_points_rules
@@ -43,6 +45,8 @@ const getRules =
4345
code: 'INTERNAL_SERVER_ERROR',
4446
message: 'Unexpected error occurred',
4547
});
48+
} finally {
49+
await db.end();
4650
}
4751

4852
if (rows.length === 0) {

0 commit comments

Comments
 (0)