@@ -6,138 +6,163 @@ import fs from "fs";
66import pino , { Logger } from "pino" ;
77import { DefaultStore } from "@pythnetwork/contract-manager/node/store" ;
88import { EvmEntropyContract } from "@pythnetwork/contract-manager/core/contracts/evm" ;
9- import { PrivateKey , toPrivateKey } from "@pythnetwork/contract-manager/core/base" ;
9+ import {
10+ PrivateKey ,
11+ toPrivateKey ,
12+ } from "@pythnetwork/contract-manager/core/base" ;
1013
1114type DurationSeconds = number ;
1215type LoadedConfig = {
13- contract : EvmEntropyContract ,
14- interval : DurationSeconds
15- }
16+ contract : EvmEntropyContract ;
17+ interval: DurationSeconds ;
18+ } ;
1619
1720function timeToSeconds ( timeStr : string ) : number {
18- const match = timeStr . match ( / ^ ( \d + ) ( [ h m s ] ) $ / i) ;
19- if ( ! match ) throw new Error ( "Invalid format. Use formats like '6h', '15m', or '30s'." ) ;
21+ const match = timeStr . match ( / ^ ( \d + ) ( [ h m s ] ) $ / i) ;
22+ if ( ! match )
23+ throw new Error ( "Invalid format. Use formats like '6h', '15m', or '30s'." ) ;
2024
21- const value = parseInt ( match [ 1 ] , 10 ) ;
22- const unit = match [ 2 ] . toLowerCase ( ) ;
25+ const value = parseInt ( match [ 1 ] , 10 ) ;
26+ const unit = match [ 2 ] . toLowerCase ( ) ;
2327
24- switch ( unit ) {
25- case 'h' : return value * 3600 ;
26- case 'm' : return value * 60 ;
27- case 's' : return value ;
28- default : throw new Error ( "Unsupported time unit." ) ;
29- }
28+ switch ( unit ) {
29+ case "h" :
30+ return value * 3600 ;
31+ case "m" :
32+ return value * 60 ;
33+ case "s" :
34+ return value ;
35+ default :
36+ throw new Error ( "Unsupported time unit." ) ;
37+ }
3038}
3139
32-
3340function loadConfig ( configPath : string ) : LoadedConfig [ ] {
34- const configs = YAML . parse ( fs . readFileSync ( configPath , "utf-8" ) ) ;
35- const loadedConfigs = [ ] ;
36- for ( const config of configs ) {
37- const interval = timeToSeconds ( config [ 'interval' ] ) ;
38- const contracts = Object . values ( DefaultStore . entropy_contracts ) . filter ( ( contract ) => (
39- contract . chain . getId ( ) == config [ 'chain-id' ]
40- ) )
41- if ( contracts . length === 0 ) {
42- throw new Error ( `Can not find the contract for chain ${ config [ 'chain-id' ] } , check contract manager store.` )
43- }
44- if ( contracts . length > 1 ) {
45- throw new Error ( `Multiple contracts found for chain ${ config [ 'chain-id' ] } , check contract manager store.` )
46- }
47- loadedConfigs . push ( { contract : contracts [ 0 ] , interval } )
41+ const configs = YAML . parse ( fs . readFileSync ( configPath , "utf-8" ) ) ;
42+ const loadedConfigs = [ ] ;
43+ for ( const config of configs ) {
44+ const interval = timeToSeconds ( config [ "interval" ] ) ;
45+ const contracts = Object . values ( DefaultStore . entropy_contracts ) . filter (
46+ ( contract ) => contract . chain . getId ( ) == config [ "chain-id" ] ,
47+ ) ;
48+ if ( contracts . length === 0 ) {
49+ throw new Error (
50+ `Can not find the contract for chain ${ config [ "chain-id" ] } , check contract manager store.` ,
51+ ) ;
52+ }
53+ if ( contracts . length > 1 ) {
54+ throw new Error (
55+ `Multiple contracts found for chain ${ config [ "chain-id" ] } , check contract manager store.` ,
56+ ) ;
4857 }
49- return loadedConfigs
58+ loadedConfigs . push ( { contract : contracts [ 0 ] , interval } ) ;
59+ }
60+ return loadedConfigs ;
5061}
5162
52-
5363async function testLatency (
54- contract : EvmEntropyContract ,
55- privateKey : PrivateKey ,
56- logger : Logger
64+ contract : EvmEntropyContract ,
65+ privateKey : PrivateKey ,
66+ logger : Logger ,
5767) {
58- const provider = await contract . getDefaultProvider ( ) ;
59- const userRandomNumber = contract . generateUserRandomNumber ( ) ;
60- const requestResponse = await contract . requestRandomness (
61- userRandomNumber ,
62- provider ,
63- privateKey ,
64- true , // with callback
65- ) ;
66- // Read the sequence number for the request from the transaction events.
67- const sequenceNumber =
68- parseInt ( requestResponse . events . RequestedWithCallback . returnValues . sequenceNumber ) ;
69- logger . info ( { sequenceNumber, txHash : requestResponse . transactionHash } , `Request submitted` ) ;
68+ const provider = await contract . getDefaultProvider ( ) ;
69+ const userRandomNumber = contract . generateUserRandomNumber ( ) ;
70+ const requestResponse = await contract . requestRandomness (
71+ userRandomNumber ,
72+ provider ,
73+ privateKey ,
74+ true , // with callback
75+ ) ;
76+ // Read the sequence number for the request from the transaction events.
77+ const sequenceNumber = parseInt (
78+ requestResponse . events . RequestedWithCallback . returnValues . sequenceNumber ,
79+ ) ;
80+ logger . info (
81+ { sequenceNumber, txHash : requestResponse . transactionHash } ,
82+ `Request submitted` ,
83+ ) ;
7084
71- const startTime = Date . now ( ) ;
85+ const startTime = Date . now ( ) ;
7286
73- // eslint-disable-next-line no-constant-condition
74- while ( true ) {
75- await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ;
76- const request = await contract . getRequest ( provider , sequenceNumber ) ;
77- logger . debug ( request )
87+ // eslint-disable-next-line no-constant-condition
88+ while ( true ) {
89+ await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ;
90+ const request = await contract . getRequest ( provider , sequenceNumber ) ;
91+ logger . debug ( request ) ;
7892
79- if ( parseInt ( request . sequenceNumber ) === 0 ) { // 0 means the request is cleared
80- const endTime = Date . now ( ) ;
81- logger . info ( { sequenceNumber, latency : endTime - startTime } , `Successful callback` ) ;
82- break ;
83- }
84- if ( Date . now ( ) - startTime > 60000 ) {
85- logger . error ( { sequenceNumber } , "Timeout: 60s passed without the callback being called" ) ;
86- break ;
87- }
93+ if ( parseInt ( request . sequenceNumber ) === 0 ) {
94+ // 0 means the request is cleared
95+ const endTime = Date . now ( ) ;
96+ logger . info (
97+ { sequenceNumber, latency : endTime - startTime } ,
98+ `Successful callback` ,
99+ ) ;
100+ break ;
101+ }
102+ if ( Date . now ( ) - startTime > 60000 ) {
103+ logger . error (
104+ { sequenceNumber } ,
105+ "Timeout: 60s passed without the callback being called" ,
106+ ) ;
107+ break ;
88108 }
109+ }
89110}
90111
91-
92112yargs ( hideBin ( process . argv ) )
93- . parserConfiguration ( {
94- "parse-numbers" : false ,
95- } )
96- . command ( {
97- command : "run" ,
98- describe : "run the tester until manually stopped" ,
99- builder : {
100- validate : {
101- description : "Only validate the configs and exit" ,
102- type : "boolean" ,
103- default : false ,
104- required : false
105- } ,
106- config : {
107- description : "Yaml config file" ,
108- type : "string" ,
109- required : true ,
110- } ,
111- "private-key" : {
112- type : "string" ,
113- required : true ,
114- description : "Path to the private key to sign the transactions with. Should be hex encoded" ,
115- } ,
116- } ,
117- handler : async ( argv : any ) => {
118- const logger = pino ( ) ;
119- const configs = loadConfig ( argv . config ) ;
120- if ( argv . validate ) {
121- logger . info ( "Config validated" )
122- return ;
123- }
124- const privateKey = toPrivateKey ( fs . readFileSync ( argv [ 'private-key' ] , "utf-8" ) . replace ( '0x' , '' ) . trimEnd ( ) )
125- logger . info ( "Running" )
126- const promises = configs . map ( async ( { contract, interval } ) => {
127- const child = logger . child ( { chain : contract . chain . getId ( ) } )
128- // eslint-disable-next-line no-constant-condition
129- while ( true ) {
130- try {
131- await testLatency ( contract , privateKey , child ) ;
132- }
133- catch ( e ) {
134- child . error ( e , "Error testing latency" )
135- }
136- await new Promise ( ( resolve ) => setTimeout ( resolve , interval * 1000 ) ) ;
137- }
138- } ) ;
139- await Promise . all ( promises ) ;
113+ . parserConfiguration ( {
114+ "parse-numbers" : false ,
115+ } )
116+ . command ( {
117+ command : "run" ,
118+ describe : "run the tester until manually stopped" ,
119+ builder : {
120+ validate : {
121+ description : "Only validate the configs and exit" ,
122+ type : "boolean" ,
123+ default : false ,
124+ required : false ,
125+ } ,
126+ config : {
127+ description : "Yaml config file" ,
128+ type : "string" ,
129+ required : true ,
130+ } ,
131+ "private-key" : {
132+ type : "string" ,
133+ required : true ,
134+ description :
135+ "Path to the private key to sign the transactions with. Should be hex encoded" ,
136+ } ,
137+ } ,
138+ handler : async ( argv : any ) => {
139+ const logger = pino ( ) ;
140+ const configs = loadConfig ( argv . config ) ;
141+ if ( argv . validate ) {
142+ logger . info ( "Config validated" ) ;
143+ return ;
144+ }
145+ const privateKey = toPrivateKey (
146+ fs
147+ . readFileSync ( argv [ "private-key" ] , "utf-8" )
148+ . replace ( "0x" , "" )
149+ . trimEnd ( ) ,
150+ ) ;
151+ logger . info ( "Running" ) ;
152+ const promises = configs . map ( async ( { contract, interval } ) => {
153+ const child = logger . child ( { chain : contract . chain . getId ( ) } ) ;
154+ // eslint-disable-next-line no-constant-condition
155+ while ( true ) {
156+ try {
157+ await testLatency ( contract , privateKey , child ) ;
158+ } catch ( e ) {
159+ child . error ( e , "Error testing latency" ) ;
160+ }
161+ await new Promise ( ( resolve ) => setTimeout ( resolve , interval * 1000 ) ) ;
140162 }
141- } )
142- . demandCommand ( )
143- . help ( ) . argv ;
163+ } ) ;
164+ await Promise . all ( promises ) ;
165+ } ,
166+ } )
167+ . demandCommand ( )
168+ . help ( ) . argv ;
0 commit comments