latency_entropy_with_callback.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /* eslint-disable @typescript-eslint/no-unsafe-member-access */
  2. /* eslint-disable @typescript-eslint/restrict-template-expressions */
  3. /* eslint-disable no-console */
  4. /* eslint-disable @typescript-eslint/no-unsafe-assignment */
  5. /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
  6. import yargs from "yargs";
  7. import { hideBin } from "yargs/helpers";
  8. import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common";
  9. import type { PrivateKey } from "../src/core/base";
  10. import { toPrivateKey } from "../src/core/base";
  11. import { EvmChain } from "../src/core/chains";
  12. import { EvmEntropyContract } from "../src/core/contracts";
  13. import { DefaultStore } from "../src/node/utils/store";
  14. const parser = yargs(hideBin(process.argv))
  15. .usage(
  16. "Requests a random number from an entropy contract and measures the\n" +
  17. "latency between request submission and fulfillment by the Fortuna keeper service.\n" +
  18. "Usage: $0 --private-key <private-key> --chain <chain-id> | --all-chains <testnet|mainnet>",
  19. )
  20. .options({
  21. provider: {
  22. type: "string",
  23. desc: "Provider address to use for the request. Will use the default provider if not specified",
  24. demandOption: false,
  25. },
  26. chain: {
  27. type: "string",
  28. desc: "test latency for the contract on this chain",
  29. conflicts: "all-chains",
  30. },
  31. "all-chains": {
  32. type: "string",
  33. conflicts: "chain",
  34. choices: ["testnet", "mainnet"],
  35. desc: "test latency for all entropy contracts deployed either on mainnet or testnet",
  36. },
  37. "private-key": COMMON_DEPLOY_OPTIONS["private-key"],
  38. });
  39. async function testLatency(
  40. contract: EvmEntropyContract,
  41. privateKey: PrivateKey,
  42. provider?: string,
  43. ) {
  44. provider = provider || (await contract.getDefaultProvider());
  45. const userRandomNumber = contract.generateUserRandomNumber();
  46. const requestResponse = await contract.requestRandomness(
  47. userRandomNumber,
  48. provider,
  49. privateKey,
  50. true, // with callback
  51. );
  52. console.log(`Request tx hash : ${requestResponse.transactionHash}`);
  53. // Read the sequence number for the request from the transaction events.
  54. const sequenceNumber =
  55. requestResponse.events.RequestedWithCallback.returnValues.sequenceNumber;
  56. console.log(`sequence : ${sequenceNumber}`);
  57. const startTime = Date.now();
  58. const fromBlock = requestResponse.blockNumber;
  59. const web3 = contract.chain.getWeb3();
  60. const entropyContract = contract.getContract();
  61. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
  62. while (true) {
  63. await new Promise((resolve) => setTimeout(resolve, 1000));
  64. const currentBlock = await web3.eth.getBlockNumber();
  65. if (fromBlock > currentBlock) {
  66. continue;
  67. }
  68. const events = await entropyContract.getPastEvents("RevealedWithCallback", {
  69. fromBlock: fromBlock,
  70. toBlock: currentBlock,
  71. });
  72. const event = events.find(
  73. (event) => event.returnValues.request[1] == sequenceNumber,
  74. );
  75. if (event !== undefined) {
  76. console.log(`Random number : ${event.returnValues.randomNumber}`);
  77. const endTime = Date.now();
  78. console.log(`Fortuna Latency : ${endTime - startTime}ms`);
  79. console.log(
  80. `Revealed after : ${
  81. currentBlock - requestResponse.blockNumber
  82. } blocks`,
  83. );
  84. break;
  85. }
  86. if (Date.now() - startTime > 60_000) {
  87. console.log("Timeout: 60s passed without the callback being called.");
  88. break;
  89. }
  90. }
  91. }
  92. async function main() {
  93. const argv = await parser.argv;
  94. if (!argv.chain && !argv["all-chains"]) {
  95. throw new Error("Must specify either --chain or --all-chains");
  96. }
  97. const privateKey = toPrivateKey(argv.privateKey);
  98. if (argv["all-chains"]) {
  99. for (const contract of Object.values(DefaultStore.entropy_contracts)) {
  100. if (
  101. contract.getChain().isMainnet() ===
  102. (argv["all-chains"] === "mainnet")
  103. ) {
  104. console.log(`Testing latency for ${contract.getId()}...`);
  105. await testLatency(contract, privateKey);
  106. }
  107. }
  108. } else if (argv.chain) {
  109. const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain);
  110. const contract = findEntropyContract(chain);
  111. await testLatency(contract, privateKey, argv.provider);
  112. }
  113. }
  114. // eslint-disable-next-line @typescript-eslint/no-floating-promises, unicorn/prefer-top-level-await
  115. main();