瀏覽代碼

requested_changes

Aditya Arora 7 月之前
父節點
當前提交
9a11f60b80
共有 1 個文件被更改,包括 101 次插入26 次删除
  1. 101 26
      contract_manager/scripts/latency_entropy_with_callback.ts

+ 101 - 26
contract_manager/scripts/latency_entropy_with_callback.ts

@@ -11,9 +11,9 @@ import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common";
 
 const parser = yargs(hideBin(process.argv))
   .usage(
-    "Requests a random number from an entropy contract and measures the\n" +
+    "Requests random numbers from an entropy contract and measures the\n" +
       "latency between request submission and fulfillment by the Fortuna keeper service.\n" +
-      "Usage: $0 --private-key <private-key> --chain <chain-id> | --all-chains <testnet|mainnet>",
+      "Usage: $0 --private-key <private-key> --chain <chain-id> | --all-chains <testnet|mainnet> --nrequests <number> --delay <delay>",
   )
   .options({
     chain: {
@@ -28,29 +28,43 @@ const parser = yargs(hideBin(process.argv))
       desc: "test latency for all entropy contracts deployed either on mainnet or testnet",
     },
     "private-key": COMMON_DEPLOY_OPTIONS["private-key"],
+    "nrequests": {
+      type: "number",
+      desc: "number of requests to make",
+      default: 1,
+    },
+    "delay": {
+      type: "number",
+      desc: "delay between requests in milliseconds",
+      default: 25,
+    },
   });
 
-async function testLatency(
+async function sendRequest(
   contract: EvmEntropyContract,
   privateKey: PrivateKey,
-) {
-  const provider = await contract.getDefaultProvider();
+  requestId: number,
+): Promise<{ entropyRequestResponse: any; startTime: number }> {
+  const fortunaProvider = await contract.getDefaultProvider();
   const userRandomNumber = contract.generateUserRandomNumber();
-  const requestResponse = await contract.requestRandomness(
+  const entropyRequestResponse = await contract.requestRandomness(
     userRandomNumber,
-    provider,
+    fortunaProvider,
     privateKey,
     true, // with callback
   );
-  console.log(`Request tx hash  : ${requestResponse.transactionHash}`);
-  // Read the sequence number for the request from the transaction events.
-  const sequenceNumber =
-    requestResponse.events.RequestedWithCallback.returnValues.sequenceNumber;
-  console.log(`sequence         : ${sequenceNumber}`);
-
   const startTime = Date.now();
+  console.log(`[Request ${requestId}] Request tx hash  : ${entropyRequestResponse.transactionHash}`);
+  return { entropyRequestResponse, startTime };
+}
 
-  const fromBlock = requestResponse.blockNumber;
+async function waitForCallback(
+  contract: EvmEntropyContract,
+  entropyRequestResponse: any,
+  startTime: number,
+  requestId: number,
+): Promise<{ success: boolean; latency?: number }> {
+  const fromBlock = entropyRequestResponse.blockNumber;
   const web3 = contract.chain.getWeb3();
   const entropyContract = contract.getContract();
 
@@ -58,7 +72,6 @@ async function testLatency(
   while (true) {
     await new Promise((resolve) => setTimeout(resolve, 1000));
     const currentBlock = await web3.eth.getBlockNumber();
-
     if (fromBlock > currentBlock) {
       continue;
     }
@@ -69,25 +82,87 @@ async function testLatency(
     });
 
     const event = events.find(
-      (event) => event.returnValues.request[1] == sequenceNumber,
+      (event) => event.returnValues.request[1] == entropyRequestResponse.events.RequestedWithCallback.returnValues.sequenceNumber,
     );
 
     if (event !== undefined) {
-      console.log(`Random number    : ${event.returnValues.randomNumber}`);
-      const endTime = Date.now();
-      console.log(`Fortuna Latency  : ${endTime - startTime}ms`);
+      console.log(`[Request ${requestId}] Random number    : ${event.returnValues.randomNumber}`);
+      const eventBlockTimestamp = Number(await web3.eth.getBlock(event.blockNumber).then(block => block.timestamp));
+      const entropyRequestBlockTimestamp = Number(await web3.eth.getBlock(entropyRequestResponse.blockNumber).then(block => block.timestamp));
+      const latency = eventBlockTimestamp - entropyRequestBlockTimestamp;
+      console.log(`[Request ${requestId}] Fortuna Latency  : ${latency}ms`);
       console.log(
-        `Revealed after   : ${
-          currentBlock - requestResponse.blockNumber
+        `[Request ${requestId}] Revealed after   : ${
+          event.blockNumber - entropyRequestResponse.blockNumber
         } blocks`,
       );
-      break;
+      return { success: true, latency };
     }
     if (Date.now() - startTime > 60000) {
-      console.log("Timeout: 60s passed without the callback being called.");
-      break;
+      console.log(`[Request ${requestId}] Timeout: 60s passed without the callback being called.`);
+      return { success: false };
+    }
+  }
+}
+
+async function testParallelLatency(
+  contract: EvmEntropyContract,
+  privateKey: PrivateKey,
+  numRequests: number,
+  delay: number,
+) {
+  console.log(`Starting ${numRequests} requests...`);
+
+  // First send all requests
+  const requests: { entropyRequestResponse: any; startTime: number; requestId: number }[] = [];
+  for (let i = 0; i < numRequests; i++) {
+    if (i > 0) {
+      await new Promise(resolve => setTimeout(resolve, delay));
     }
+    const { entropyRequestResponse, startTime } = await sendRequest(contract, privateKey, i + 1);
+    requests.push({ entropyRequestResponse, startTime, requestId: i + 1 });
+  }
+
+
+
+
+  // Then wait for all callbacks
+  // The response time won't be accurate here.
+  const results: { success: boolean; latency?: number }[] = [];
+  for (const request of requests) {
+    const sequenceNumber =
+    request.entropyRequestResponse.events.RequestedWithCallback.returnValues.sequenceNumber;
+    console.log(`[Request ${request.requestId}] sequence         : ${sequenceNumber}`);
+    results.push(await waitForCallback(
+      contract,
+      request.entropyRequestResponse,
+      request.startTime,
+      request.requestId
+    ));
+  }
+
+  // Calculate statistics
+  const successfulRequests = results.filter(r => r.success).length;
+  const failedRequests = numRequests - successfulRequests;
+  const successRate = (successfulRequests / numRequests) * 100;
+
+  // Calculate average latency for successful requests
+  const successfulLatencies = results
+    .filter((r): r is { success: true; latency: number } => r.success && r.latency !== undefined)
+    .map(r => r.latency);
+  const avgLatency = successfulLatencies.length > 0
+    ? successfulLatencies.reduce((a, b) => a + b, 0) / successfulLatencies.length
+    : 0;
+
+  console.log("\n=== Test Results ===");
+  console.log(`Total Requests    : ${numRequests}`);
+  console.log(`Successful        : ${successfulRequests}`);
+  console.log(`Failed           : ${failedRequests}`);
+  console.log(`Success Rate     : ${successRate.toFixed(2)}%`);
+  if (successfulLatencies.length > 0) {
+    console.log(`Average Latency  : ${avgLatency.toFixed(2)}ms`);
   }
+  console.log("===================");
 }
 
 async function main() {
@@ -103,13 +178,13 @@ async function main() {
         (argv["all-chains"] === "mainnet")
       ) {
         console.log(`Testing latency for ${contract.getId()}...`);
-        await testLatency(contract, privateKey);
+        await testParallelLatency(contract, privateKey, argv["nrequests"], argv["delay"]);
       }
     }
   } else if (argv.chain) {
     const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain);
     const contract = findEntropyContract(chain);
-    await testLatency(contract, privateKey);
+    await testParallelLatency(contract, privateKey, argv["nrequests"], argv["delay"]);
   }
 }