Skip to content

Commit 9a11f60

Browse files
committed
requested_changes
1 parent bde7b66 commit 9a11f60

File tree

1 file changed

+101
-26
lines changed

1 file changed

+101
-26
lines changed

contract_manager/scripts/latency_entropy_with_callback.ts

Lines changed: 101 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common";
1111

1212
const parser = yargs(hideBin(process.argv))
1313
.usage(
14-
"Requests a random number from an entropy contract and measures the\n" +
14+
"Requests random numbers from an entropy contract and measures the\n" +
1515
"latency between request submission and fulfillment by the Fortuna keeper service.\n" +
16-
"Usage: $0 --private-key <private-key> --chain <chain-id> | --all-chains <testnet|mainnet>",
16+
"Usage: $0 --private-key <private-key> --chain <chain-id> | --all-chains <testnet|mainnet> --nrequests <number> --delay <delay>",
1717
)
1818
.options({
1919
chain: {
@@ -28,37 +28,50 @@ const parser = yargs(hideBin(process.argv))
2828
desc: "test latency for all entropy contracts deployed either on mainnet or testnet",
2929
},
3030
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
31+
"nrequests": {
32+
type: "number",
33+
desc: "number of requests to make",
34+
default: 1,
35+
},
36+
"delay": {
37+
type: "number",
38+
desc: "delay between requests in milliseconds",
39+
default: 25,
40+
},
3141
});
3242

33-
async function testLatency(
43+
async function sendRequest(
3444
contract: EvmEntropyContract,
3545
privateKey: PrivateKey,
36-
) {
37-
const provider = await contract.getDefaultProvider();
46+
requestId: number,
47+
): Promise<{ entropyRequestResponse: any; startTime: number }> {
48+
const fortunaProvider = await contract.getDefaultProvider();
3849
const userRandomNumber = contract.generateUserRandomNumber();
39-
const requestResponse = await contract.requestRandomness(
50+
const entropyRequestResponse = await contract.requestRandomness(
4051
userRandomNumber,
41-
provider,
52+
fortunaProvider,
4253
privateKey,
4354
true, // with callback
4455
);
45-
console.log(`Request tx hash : ${requestResponse.transactionHash}`);
46-
// Read the sequence number for the request from the transaction events.
47-
const sequenceNumber =
48-
requestResponse.events.RequestedWithCallback.returnValues.sequenceNumber;
49-
console.log(`sequence : ${sequenceNumber}`);
50-
5156
const startTime = Date.now();
57+
console.log(`[Request ${requestId}] Request tx hash : ${entropyRequestResponse.transactionHash}`);
58+
return { entropyRequestResponse, startTime };
59+
}
5260

53-
const fromBlock = requestResponse.blockNumber;
61+
async function waitForCallback(
62+
contract: EvmEntropyContract,
63+
entropyRequestResponse: any,
64+
startTime: number,
65+
requestId: number,
66+
): Promise<{ success: boolean; latency?: number }> {
67+
const fromBlock = entropyRequestResponse.blockNumber;
5468
const web3 = contract.chain.getWeb3();
5569
const entropyContract = contract.getContract();
5670

5771
// eslint-disable-next-line no-constant-condition
5872
while (true) {
5973
await new Promise((resolve) => setTimeout(resolve, 1000));
6074
const currentBlock = await web3.eth.getBlockNumber();
61-
6275
if (fromBlock > currentBlock) {
6376
continue;
6477
}
@@ -69,25 +82,87 @@ async function testLatency(
6982
});
7083

7184
const event = events.find(
72-
(event) => event.returnValues.request[1] == sequenceNumber,
85+
(event) => event.returnValues.request[1] == entropyRequestResponse.events.RequestedWithCallback.returnValues.sequenceNumber,
7386
);
7487

7588
if (event !== undefined) {
76-
console.log(`Random number : ${event.returnValues.randomNumber}`);
77-
const endTime = Date.now();
78-
console.log(`Fortuna Latency : ${endTime - startTime}ms`);
89+
console.log(`[Request ${requestId}] Random number : ${event.returnValues.randomNumber}`);
90+
const eventBlockTimestamp = Number(await web3.eth.getBlock(event.blockNumber).then(block => block.timestamp));
91+
const entropyRequestBlockTimestamp = Number(await web3.eth.getBlock(entropyRequestResponse.blockNumber).then(block => block.timestamp));
92+
const latency = eventBlockTimestamp - entropyRequestBlockTimestamp;
93+
console.log(`[Request ${requestId}] Fortuna Latency : ${latency}ms`);
7994
console.log(
80-
`Revealed after : ${
81-
currentBlock - requestResponse.blockNumber
95+
`[Request ${requestId}] Revealed after : ${
96+
event.blockNumber - entropyRequestResponse.blockNumber
8297
} blocks`,
8398
);
84-
break;
99+
return { success: true, latency };
85100
}
86101
if (Date.now() - startTime > 60000) {
87-
console.log("Timeout: 60s passed without the callback being called.");
88-
break;
102+
console.log(`[Request ${requestId}] Timeout: 60s passed without the callback being called.`);
103+
return { success: false };
104+
}
105+
}
106+
}
107+
108+
async function testParallelLatency(
109+
contract: EvmEntropyContract,
110+
privateKey: PrivateKey,
111+
numRequests: number,
112+
delay: number,
113+
) {
114+
console.log(`Starting ${numRequests} requests...`);
115+
116+
// First send all requests
117+
const requests: { entropyRequestResponse: any; startTime: number; requestId: number }[] = [];
118+
for (let i = 0; i < numRequests; i++) {
119+
if (i > 0) {
120+
await new Promise(resolve => setTimeout(resolve, delay));
89121
}
122+
const { entropyRequestResponse, startTime } = await sendRequest(contract, privateKey, i + 1);
123+
requests.push({ entropyRequestResponse, startTime, requestId: i + 1 });
124+
}
125+
126+
127+
128+
129+
// Then wait for all callbacks
130+
// The response time won't be accurate here.
131+
const results: { success: boolean; latency?: number }[] = [];
132+
for (const request of requests) {
133+
const sequenceNumber =
134+
request.entropyRequestResponse.events.RequestedWithCallback.returnValues.sequenceNumber;
135+
console.log(`[Request ${request.requestId}] sequence : ${sequenceNumber}`);
136+
results.push(await waitForCallback(
137+
contract,
138+
request.entropyRequestResponse,
139+
request.startTime,
140+
request.requestId
141+
));
142+
}
143+
144+
// Calculate statistics
145+
const successfulRequests = results.filter(r => r.success).length;
146+
const failedRequests = numRequests - successfulRequests;
147+
const successRate = (successfulRequests / numRequests) * 100;
148+
149+
// Calculate average latency for successful requests
150+
const successfulLatencies = results
151+
.filter((r): r is { success: true; latency: number } => r.success && r.latency !== undefined)
152+
.map(r => r.latency);
153+
const avgLatency = successfulLatencies.length > 0
154+
? successfulLatencies.reduce((a, b) => a + b, 0) / successfulLatencies.length
155+
: 0;
156+
157+
console.log("\n=== Test Results ===");
158+
console.log(`Total Requests : ${numRequests}`);
159+
console.log(`Successful : ${successfulRequests}`);
160+
console.log(`Failed : ${failedRequests}`);
161+
console.log(`Success Rate : ${successRate.toFixed(2)}%`);
162+
if (successfulLatencies.length > 0) {
163+
console.log(`Average Latency : ${avgLatency.toFixed(2)}ms`);
90164
}
165+
console.log("===================");
91166
}
92167

93168
async function main() {
@@ -103,13 +178,13 @@ async function main() {
103178
(argv["all-chains"] === "mainnet")
104179
) {
105180
console.log(`Testing latency for ${contract.getId()}...`);
106-
await testLatency(contract, privateKey);
181+
await testParallelLatency(contract, privateKey, argv["nrequests"], argv["delay"]);
107182
}
108183
}
109184
} else if (argv.chain) {
110185
const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain);
111186
const contract = findEntropyContract(chain);
112-
await testLatency(contract, privateKey);
187+
await testParallelLatency(contract, privateKey, argv["nrequests"], argv["delay"]);
113188
}
114189
}
115190

0 commit comments

Comments
 (0)