latency_entropy_with_callback.ts 3.8 KB

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