Entropy.t.sol 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792
  1. // SPDX-License-Identifier: Apache 2
  2. pragma solidity ^0.8.0;
  3. import "forge-std/Test.sol";
  4. import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
  5. import "@pythnetwork/entropy-sdk-solidity/EntropyStructsV2.sol";
  6. import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol";
  7. import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
  8. import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
  9. import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
  10. import "./utils/EntropyTestUtils.t.sol";
  11. import "../contracts/entropy/EntropyUpgradable.sol";
  12. import "@pythnetwork/entropy-sdk-solidity/EntropyStatusConstants.sol";
  13. // TODO
  14. // - fuzz test?
  15. contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
  16. ERC1967Proxy public proxy;
  17. EntropyUpgradable public random;
  18. uint128 pythFeeInWei = 7;
  19. address public provider1 = address(1);
  20. bytes32[] provider1Proofs;
  21. uint128 provider1FeeInWei = 8;
  22. uint64 provider1ChainLength = 1000;
  23. uint32 provider1MaxNumHashes = 500;
  24. bytes provider1Uri = bytes("https://foo.com");
  25. bytes provider1CommitmentMetadata = hex"0100";
  26. address public provider2 = address(2);
  27. bytes32[] provider2Proofs;
  28. uint128 provider2FeeInWei = 20;
  29. bytes provider2Uri = bytes("https://bar.com");
  30. address public user1 = address(3);
  31. address public user2 = address(4);
  32. address public unregisteredProvider = address(7);
  33. uint128 MAX_UINT128 = 2 ** 128 - 1;
  34. bytes32 ALL_ZEROS = bytes32(uint256(0));
  35. address public owner = address(8);
  36. address public admin = address(9);
  37. address public admin2 = address(10);
  38. function setUp() public {
  39. EntropyUpgradable _random = new EntropyUpgradable();
  40. // deploy proxy contract and point it to implementation
  41. proxy = new ERC1967Proxy(address(_random), "");
  42. // wrap in ABI to support easier calls
  43. random = EntropyUpgradable(address(proxy));
  44. random.initialize(owner, admin, pythFeeInWei, provider1, false);
  45. bytes32[] memory hashChain1 = generateHashChain(
  46. provider1,
  47. 0,
  48. provider1ChainLength
  49. );
  50. provider1Proofs = hashChain1;
  51. vm.prank(provider1);
  52. random.register(
  53. provider1FeeInWei,
  54. provider1Proofs[0],
  55. provider1CommitmentMetadata,
  56. provider1ChainLength,
  57. provider1Uri
  58. );
  59. vm.prank(provider1);
  60. random.setMaxNumHashes(provider1MaxNumHashes);
  61. bytes32[] memory hashChain2 = generateHashChain(provider2, 0, 100);
  62. provider2Proofs = hashChain2;
  63. vm.prank(provider2);
  64. random.register(
  65. provider2FeeInWei,
  66. provider2Proofs[0],
  67. hex"0200",
  68. 100,
  69. provider2Uri
  70. );
  71. }
  72. // Test helper method for requesting a random value as user from provider.
  73. function request(
  74. address user,
  75. address provider,
  76. uint randomNumber,
  77. bool useBlockhash
  78. ) public returns (uint64 sequenceNumber) {
  79. sequenceNumber = requestWithFee(
  80. user,
  81. random.getFee(provider),
  82. provider,
  83. randomNumber,
  84. useBlockhash
  85. );
  86. }
  87. function requestWithFee(
  88. address user,
  89. uint fee,
  90. address provider,
  91. uint randomNumber,
  92. bool useBlockhash
  93. ) public returns (uint64 sequenceNumber) {
  94. vm.deal(user, fee);
  95. vm.startPrank(user);
  96. sequenceNumber = random.request{value: fee}(
  97. provider,
  98. random.constructUserCommitment(bytes32(randomNumber)),
  99. useBlockhash
  100. );
  101. vm.stopPrank();
  102. }
  103. function assertRequestReverts(
  104. uint fee,
  105. address provider,
  106. uint randomNumber,
  107. bool useBlockhash,
  108. bytes4 revertReason
  109. ) public {
  110. bytes32 userCommitment = random.constructUserCommitment(
  111. bytes32(uint256(randomNumber))
  112. );
  113. vm.deal(address(this), fee);
  114. vm.expectRevert(revertReason);
  115. random.request{value: fee}(provider, userCommitment, useBlockhash);
  116. }
  117. function assertRevealSucceeds(
  118. address user,
  119. address provider,
  120. uint64 sequenceNumber,
  121. uint userRandom,
  122. bytes32 providerRevelation,
  123. bytes32 hash
  124. ) public {
  125. vm.prank(user);
  126. bytes32 randomNumber = random.reveal(
  127. provider,
  128. sequenceNumber,
  129. bytes32(userRandom),
  130. providerRevelation
  131. );
  132. assertEq(
  133. randomNumber,
  134. random.combineRandomValues(
  135. bytes32(userRandom),
  136. providerRevelation,
  137. hash
  138. )
  139. );
  140. }
  141. function assertRevealReverts(
  142. address user,
  143. address provider,
  144. uint64 sequenceNumber,
  145. uint userRandom,
  146. bytes32 providerRevelation
  147. ) public {
  148. vm.startPrank(user);
  149. vm.expectRevert();
  150. random.reveal(
  151. provider,
  152. sequenceNumber,
  153. bytes32(uint256(userRandom)),
  154. providerRevelation
  155. );
  156. vm.stopPrank();
  157. }
  158. function assertInvariants() public {
  159. uint expectedBalance = random
  160. .getProviderInfo(provider1)
  161. .accruedFeesInWei +
  162. random.getProviderInfo(provider2).accruedFeesInWei +
  163. random.getAccruedPythFees();
  164. assertEq(address(random).balance, expectedBalance);
  165. EntropyStructsV2.ProviderInfo memory info1 = random.getProviderInfo(
  166. provider1
  167. );
  168. assert(
  169. info1.originalCommitmentSequenceNumber <=
  170. info1.currentCommitmentSequenceNumber
  171. );
  172. assert(info1.currentCommitmentSequenceNumber < info1.sequenceNumber);
  173. assert(info1.sequenceNumber <= info1.endSequenceNumber);
  174. EntropyStructsV2.ProviderInfo memory info2 = random.getProviderInfo(
  175. provider2
  176. );
  177. assert(
  178. info2.originalCommitmentSequenceNumber <=
  179. info2.currentCommitmentSequenceNumber
  180. );
  181. assert(info2.sequenceNumber > info2.currentCommitmentSequenceNumber);
  182. assert(info2.sequenceNumber <= info2.endSequenceNumber);
  183. }
  184. function testBasicFlow() public {
  185. vm.roll(17);
  186. uint64 sequenceNumber = request(user2, provider1, 42, false);
  187. assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 17);
  188. assertEq(
  189. random.getRequest(provider1, sequenceNumber).useBlockhash,
  190. false
  191. );
  192. assertRevealSucceeds(
  193. user2,
  194. provider1,
  195. sequenceNumber,
  196. 42,
  197. provider1Proofs[sequenceNumber],
  198. ALL_ZEROS
  199. );
  200. EntropyStructsV2.Request memory reqAfterReveal = random.getRequest(
  201. provider1,
  202. sequenceNumber
  203. );
  204. assertEq(reqAfterReveal.sequenceNumber, 0);
  205. // You can only reveal the random number once. This isn't a feature of the contract per se, but it is
  206. // the expected behavior.
  207. assertRevealReverts(
  208. user2,
  209. provider1,
  210. sequenceNumber,
  211. 42,
  212. provider1Proofs[sequenceNumber]
  213. );
  214. }
  215. function testDefaultProvider() public {
  216. vm.roll(20);
  217. uint64 sequenceNumber = request(
  218. user2,
  219. random.getDefaultProvider(),
  220. 42,
  221. false
  222. );
  223. assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 20);
  224. assertEq(
  225. random.getRequest(provider1, sequenceNumber).useBlockhash,
  226. false
  227. );
  228. assertRevealReverts(
  229. user2,
  230. random.getDefaultProvider(),
  231. sequenceNumber,
  232. 42,
  233. provider2Proofs[sequenceNumber]
  234. );
  235. assertRevealSucceeds(
  236. user2,
  237. random.getDefaultProvider(),
  238. sequenceNumber,
  239. 42,
  240. provider1Proofs[sequenceNumber],
  241. ALL_ZEROS
  242. );
  243. }
  244. function testNoSuchProvider() public {
  245. assertRequestReverts(
  246. 10000000,
  247. unregisteredProvider,
  248. 42,
  249. false,
  250. EntropyErrors.NoSuchProvider.selector
  251. );
  252. }
  253. function testAuthorization() public {
  254. uint64 sequenceNumber = request(user2, provider1, 42, false);
  255. assertEq(random.getRequest(provider1, sequenceNumber).requester, user2);
  256. // user1 not authorized, must be user2.
  257. assertRevealReverts(
  258. user1,
  259. provider1,
  260. sequenceNumber,
  261. 42,
  262. provider1Proofs[sequenceNumber]
  263. );
  264. assertRevealSucceeds(
  265. user2,
  266. provider1,
  267. sequenceNumber,
  268. 42,
  269. provider1Proofs[sequenceNumber],
  270. ALL_ZEROS
  271. );
  272. }
  273. function testAdversarialReveal() public {
  274. uint64 sequenceNumber = request(user2, provider1, 42, false);
  275. // test revealing with the wrong hashes in the same chain
  276. for (uint256 i = 0; i < 10; i++) {
  277. if (i != sequenceNumber) {
  278. assertRevealReverts(
  279. user2,
  280. provider1,
  281. sequenceNumber,
  282. 42,
  283. provider1Proofs[i]
  284. );
  285. }
  286. }
  287. // test revealing with the wrong user revealed value.
  288. for (uint256 i = 0; i < 42; i++) {
  289. assertRevealReverts(
  290. user2,
  291. provider1,
  292. sequenceNumber,
  293. i,
  294. provider1Proofs[sequenceNumber]
  295. );
  296. }
  297. // test revealing sequence numbers that haven't been requested yet.
  298. for (uint64 i = sequenceNumber + 1; i < sequenceNumber + 3; i++) {
  299. assertRevealReverts(
  300. user2,
  301. provider1,
  302. i,
  303. 42,
  304. provider1Proofs[sequenceNumber]
  305. );
  306. assertRevealReverts(user2, provider1, i, 42, provider1Proofs[i]);
  307. }
  308. }
  309. function testConcurrentRequests() public {
  310. uint64 s1 = request(user1, provider1, 1, false);
  311. uint64 s2 = request(user2, provider1, 2, false);
  312. uint64 s3 = request(user1, provider1, 3, false);
  313. uint64 s4 = request(user1, provider1, 4, false);
  314. assertRevealSucceeds(
  315. user1,
  316. provider1,
  317. s3,
  318. 3,
  319. provider1Proofs[s3],
  320. ALL_ZEROS
  321. );
  322. assertInvariants();
  323. uint64 s5 = request(user1, provider1, 5, false);
  324. assertRevealSucceeds(
  325. user1,
  326. provider1,
  327. s4,
  328. 4,
  329. provider1Proofs[s4],
  330. ALL_ZEROS
  331. );
  332. assertInvariants();
  333. assertRevealSucceeds(
  334. user1,
  335. provider1,
  336. s1,
  337. 1,
  338. provider1Proofs[s1],
  339. ALL_ZEROS
  340. );
  341. assertInvariants();
  342. assertRevealSucceeds(
  343. user2,
  344. provider1,
  345. s2,
  346. 2,
  347. provider1Proofs[s2],
  348. ALL_ZEROS
  349. );
  350. assertInvariants();
  351. assertRevealSucceeds(
  352. user1,
  353. provider1,
  354. s5,
  355. 5,
  356. provider1Proofs[s5],
  357. ALL_ZEROS
  358. );
  359. assertInvariants();
  360. }
  361. function testBlockhash() public {
  362. vm.roll(1234);
  363. uint64 sequenceNumber = request(user2, provider1, 42, true);
  364. assertEq(
  365. random.getRequest(provider1, sequenceNumber).blockNumber,
  366. 1234
  367. );
  368. assertEq(
  369. random.getRequest(provider1, sequenceNumber).useBlockhash,
  370. true
  371. );
  372. vm.roll(1235);
  373. assertRevealSucceeds(
  374. user2,
  375. provider1,
  376. sequenceNumber,
  377. 42,
  378. provider1Proofs[sequenceNumber],
  379. blockhash(1234)
  380. );
  381. }
  382. function testNoCheckOnBlockNumberWhenNoBlockHashUsed() public {
  383. vm.roll(1234);
  384. uint64 sequenceNumber = request(user2, provider1, 42, false);
  385. vm.roll(1236);
  386. assertRevealSucceeds(
  387. user2,
  388. provider1,
  389. sequenceNumber,
  390. 42,
  391. provider1Proofs[sequenceNumber],
  392. ALL_ZEROS
  393. );
  394. vm.roll(1234);
  395. sequenceNumber = request(user2, provider1, 42, false);
  396. vm.roll(1234);
  397. assertRevealSucceeds(
  398. user2,
  399. provider1,
  400. sequenceNumber,
  401. 42,
  402. provider1Proofs[sequenceNumber],
  403. ALL_ZEROS
  404. );
  405. vm.roll(1234);
  406. sequenceNumber = request(user2, provider1, 42, false);
  407. vm.roll(1234 + 257);
  408. assertRevealSucceeds(
  409. user2,
  410. provider1,
  411. sequenceNumber,
  412. 42,
  413. provider1Proofs[sequenceNumber],
  414. ALL_ZEROS
  415. );
  416. }
  417. function testCheckOnBlockNumberWhenBlockHashUsed() public {
  418. vm.roll(1234);
  419. uint64 sequenceNumber = request(user2, provider1, 42, true);
  420. vm.roll(1234);
  421. assertRevealReverts(
  422. user2,
  423. provider1,
  424. sequenceNumber,
  425. 42,
  426. provider1Proofs[sequenceNumber]
  427. );
  428. vm.roll(1234 + 257);
  429. assertRevealReverts(
  430. user2,
  431. provider1,
  432. sequenceNumber,
  433. 42,
  434. provider1Proofs[sequenceNumber]
  435. );
  436. vm.roll(1235);
  437. assertRevealSucceeds(
  438. user2,
  439. provider1,
  440. sequenceNumber,
  441. 42,
  442. provider1Proofs[sequenceNumber],
  443. blockhash(1234)
  444. );
  445. }
  446. function testProviderCommitmentRotation() public {
  447. uint userRandom = 42;
  448. uint64 sequenceNumber1 = request(user2, provider1, userRandom, false);
  449. uint64 sequenceNumber2 = request(user2, provider1, userRandom, false);
  450. assertInvariants();
  451. uint64 newHashChainOffset = sequenceNumber2 + 1;
  452. bytes32[] memory newHashChain = generateHashChain(
  453. provider1,
  454. newHashChainOffset,
  455. 10
  456. );
  457. vm.prank(provider1);
  458. random.register(
  459. provider1FeeInWei,
  460. newHashChain[0],
  461. hex"0100",
  462. 10,
  463. provider1Uri
  464. );
  465. assertInvariants();
  466. EntropyStructsV2.ProviderInfo memory info1 = random.getProviderInfo(
  467. provider1
  468. );
  469. assertEq(info1.endSequenceNumber, newHashChainOffset + 10);
  470. uint64 sequenceNumber3 = request(user2, provider1, 42, false);
  471. // Rotating the provider key uses a sequence number
  472. assertEq(sequenceNumber3, sequenceNumber2 + 2);
  473. // Requests that were in-flight at the time of rotation use the commitment from the time of request
  474. for (uint256 i = 0; i < 10; i++) {
  475. assertRevealReverts(
  476. user2,
  477. provider1,
  478. sequenceNumber1,
  479. userRandom,
  480. newHashChain[i]
  481. );
  482. }
  483. assertRevealSucceeds(
  484. user2,
  485. provider1,
  486. sequenceNumber1,
  487. userRandom,
  488. provider1Proofs[sequenceNumber1],
  489. ALL_ZEROS
  490. );
  491. assertInvariants();
  492. // Requests after the rotation use the new commitment
  493. assertRevealReverts(
  494. user2,
  495. provider1,
  496. sequenceNumber3,
  497. userRandom,
  498. provider1Proofs[sequenceNumber3]
  499. );
  500. assertRevealSucceeds(
  501. user2,
  502. provider1,
  503. sequenceNumber3,
  504. userRandom,
  505. newHashChain[sequenceNumber3 - newHashChainOffset],
  506. ALL_ZEROS
  507. );
  508. assertInvariants();
  509. }
  510. function testOutOfRandomness() public {
  511. // Should be able to request chainLength - 1 random numbers successfully.
  512. for (uint64 i = 0; i < provider1ChainLength - 1; i++) {
  513. uint64 sequenceNumber = request(user2, provider1, 42, false);
  514. assertRevealSucceeds(
  515. user2,
  516. provider1,
  517. sequenceNumber,
  518. 42,
  519. provider1Proofs[sequenceNumber],
  520. ALL_ZEROS
  521. );
  522. }
  523. assertRequestReverts(
  524. random.getFee(provider1),
  525. provider1,
  526. provider1ChainLength - 1,
  527. false,
  528. EntropyErrors.OutOfRandomness.selector
  529. );
  530. }
  531. function testGetFee() public {
  532. assertEq(random.getFee(provider1), pythFeeInWei + provider1FeeInWei);
  533. assertEq(random.getFee(provider2), pythFeeInWei + provider2FeeInWei);
  534. // Requesting the fee for a nonexistent provider returns pythFeeInWei. This isn't necessarily desirable behavior,
  535. // but it's unlikely to cause a problem.
  536. assertEq(random.getFee(unregisteredProvider), pythFeeInWei);
  537. // Check that overflowing the fee arithmetic causes the transaction to revert.
  538. vm.prank(provider1);
  539. random.register(
  540. MAX_UINT128,
  541. provider1Proofs[0],
  542. hex"0100",
  543. 100,
  544. provider1Uri
  545. );
  546. vm.expectRevert();
  547. random.getFee(provider1);
  548. }
  549. function testOverflow() public {
  550. bytes32 userCommitment = random.constructUserCommitment(
  551. bytes32(uint256(42))
  552. );
  553. // msg.value overflows the uint128 fee variable
  554. uint fee = 2 ** 128;
  555. vm.deal(address(this), fee);
  556. vm.expectRevert("SafeCast: value doesn't fit in 128 bits");
  557. random.request{value: fee}(provider1, userCommitment, false);
  558. // block number is too large
  559. vm.roll(2 ** 96);
  560. vm.expectRevert("SafeCast: value doesn't fit in 64 bits");
  561. random.request{value: pythFeeInWei + provider1FeeInWei}(
  562. provider1,
  563. userCommitment,
  564. true
  565. );
  566. }
  567. function testFees() public {
  568. // Insufficient fees causes a revert
  569. assertRequestReverts(
  570. 0,
  571. provider1,
  572. 42,
  573. false,
  574. EntropyErrors.InsufficientFee.selector
  575. );
  576. assertRequestReverts(
  577. pythFeeInWei + provider1FeeInWei - 1,
  578. provider1,
  579. 42,
  580. false,
  581. EntropyErrors.InsufficientFee.selector
  582. );
  583. assertRequestReverts(
  584. 0,
  585. provider2,
  586. 42,
  587. false,
  588. EntropyErrors.InsufficientFee.selector
  589. );
  590. assertRequestReverts(
  591. pythFeeInWei + provider2FeeInWei - 1,
  592. provider2,
  593. 42,
  594. false,
  595. EntropyErrors.InsufficientFee.selector
  596. );
  597. // Accrue some fees for both providers
  598. for (uint i = 0; i < 3; i++) {
  599. request(user2, provider1, 42, false);
  600. }
  601. request(user2, provider2, 42, false);
  602. // this call overpays for the random number
  603. requestWithFee(
  604. user2,
  605. pythFeeInWei + provider2FeeInWei + 10000,
  606. provider2,
  607. 42,
  608. false
  609. );
  610. assertEq(
  611. random.getProviderInfo(provider1).accruedFeesInWei,
  612. provider1FeeInWei * 3
  613. );
  614. assertEq(
  615. random.getProviderInfo(provider2).accruedFeesInWei,
  616. provider2FeeInWei * 2
  617. );
  618. assertEq(random.getAccruedPythFees(), pythFeeInWei * 5 + 10000);
  619. assertInvariants();
  620. // Reregistering updates the required fees
  621. vm.prank(provider1);
  622. random.register(
  623. 12345,
  624. provider1Proofs[0],
  625. hex"0100",
  626. 100,
  627. provider1Uri
  628. );
  629. assertRequestReverts(
  630. pythFeeInWei + 12345 - 1,
  631. provider1,
  632. 42,
  633. false,
  634. EntropyErrors.InsufficientFee.selector
  635. );
  636. requestWithFee(user2, pythFeeInWei + 12345, provider1, 42, false);
  637. uint128 providerOneBalance = provider1FeeInWei * 3 + 12345;
  638. assertEq(
  639. random.getProviderInfo(provider1).accruedFeesInWei,
  640. providerOneBalance
  641. );
  642. assertInvariants();
  643. vm.prank(unregisteredProvider);
  644. vm.expectRevert();
  645. random.withdraw(1000);
  646. vm.prank(provider1);
  647. random.withdraw(1000);
  648. assertEq(
  649. random.getProviderInfo(provider1).accruedFeesInWei,
  650. providerOneBalance - 1000
  651. );
  652. assertInvariants();
  653. vm.prank(provider1);
  654. vm.expectRevert();
  655. random.withdraw(providerOneBalance);
  656. }
  657. function testGetProviderInfo() public {
  658. EntropyStructsV2.ProviderInfo memory providerInfo1 = random
  659. .getProviderInfo(provider1);
  660. // These two fields aren't used by the Entropy contract itself -- they're just convenient info to store
  661. // on-chain -- so they aren't tested in the other tests.
  662. assertEq(providerInfo1.uri, provider1Uri);
  663. assertEq(providerInfo1.commitmentMetadata, provider1CommitmentMetadata);
  664. }
  665. function testSetProviderFee() public {
  666. assertNotEq(random.getProviderInfo(provider1).feeInWei, 1);
  667. vm.prank(provider1);
  668. random.setProviderFee(1);
  669. assertEq(random.getProviderInfo(provider1).feeInWei, 1);
  670. }
  671. function testSetProviderFeeByUnregistered() public {
  672. vm.prank(unregisteredProvider);
  673. vm.expectRevert();
  674. random.setProviderFee(1);
  675. }
  676. function testSetProviderUri() public {
  677. bytes memory newUri = bytes("https://new.com");
  678. assertNotEq0(random.getProviderInfo(provider1).uri, newUri);
  679. vm.prank(provider1);
  680. random.setProviderUri(newUri);
  681. assertEq0(random.getProviderInfo(provider1).uri, newUri);
  682. }
  683. function testSetProviderUriByUnregistered() public {
  684. bytes memory newUri = bytes("https://new.com");
  685. vm.prank(unregisteredProvider);
  686. vm.expectRevert();
  687. random.setProviderUri(newUri);
  688. }
  689. function testRequestWithCallbackAndReveal() public {
  690. bytes32 userRandomNumber = bytes32(uint(42));
  691. uint fee = random.getFee(provider1);
  692. EntropyStructsV2.ProviderInfo memory providerInfo = random
  693. .getProviderInfo(provider1);
  694. vm.roll(1234);
  695. vm.deal(user1, fee);
  696. vm.startPrank(user1);
  697. vm.expectEmit(false, false, false, true, address(random));
  698. emit RequestedWithCallback(
  699. provider1,
  700. user1,
  701. providerInfo.sequenceNumber,
  702. userRandomNumber,
  703. EntropyStructs.Request({
  704. provider: provider1,
  705. sequenceNumber: providerInfo.sequenceNumber,
  706. numHashes: SafeCast.toUint32(
  707. providerInfo.sequenceNumber -
  708. providerInfo.currentCommitmentSequenceNumber
  709. ),
  710. commitment: keccak256(
  711. bytes.concat(
  712. random.constructUserCommitment(userRandomNumber),
  713. providerInfo.currentCommitment
  714. )
  715. ),
  716. blockNumber: 1234,
  717. requester: user1,
  718. useBlockhash: false,
  719. isRequestWithCallback: true
  720. })
  721. );
  722. vm.roll(1234);
  723. uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
  724. provider1,
  725. userRandomNumber
  726. );
  727. assertEq(
  728. random.getRequest(provider1, assignedSequenceNumber).requester,
  729. user1
  730. );
  731. assertEq(
  732. random.getRequest(provider1, assignedSequenceNumber).provider,
  733. provider1
  734. );
  735. vm.expectRevert(EntropyErrors.InvalidRevealCall.selector);
  736. random.reveal(
  737. provider1,
  738. assignedSequenceNumber,
  739. userRandomNumber,
  740. provider1Proofs[assignedSequenceNumber]
  741. );
  742. vm.stopPrank();
  743. }
  744. function testRequestWithCallbackAndRevealWithCallbackByContract() public {
  745. bytes32 userRandomNumber = bytes32(uint(42));
  746. uint fee = random.getFee(provider1);
  747. EntropyConsumer consumer = new EntropyConsumer(address(random), false);
  748. vm.deal(user1, fee);
  749. vm.prank(user1);
  750. uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
  751. userRandomNumber
  752. );
  753. EntropyStructsV2.Request memory req = random.getRequest(
  754. provider1,
  755. assignedSequenceNumber
  756. );
  757. vm.expectEmit(false, false, false, true, address(random));
  758. emit RevealedWithCallback(
  759. EntropyStructConverter.toV1Request(req),
  760. userRandomNumber,
  761. provider1Proofs[assignedSequenceNumber],
  762. random.combineRandomValues(
  763. userRandomNumber,
  764. provider1Proofs[assignedSequenceNumber],
  765. 0
  766. )
  767. );
  768. vm.prank(user1);
  769. random.revealWithCallback(
  770. provider1,
  771. assignedSequenceNumber,
  772. userRandomNumber,
  773. provider1Proofs[assignedSequenceNumber]
  774. );
  775. assertEq(consumer.sequence(), assignedSequenceNumber);
  776. assertEq(consumer.provider(), provider1);
  777. assertEq(
  778. consumer.randomness(),
  779. random.combineRandomValues(
  780. userRandomNumber,
  781. provider1Proofs[assignedSequenceNumber],
  782. // No blockhash is being used in callback method. As it
  783. // is being depreceated. Passing 0 for it.
  784. 0
  785. )
  786. );
  787. EntropyStructsV2.Request memory reqAfterReveal = random.getRequest(
  788. provider1,
  789. assignedSequenceNumber
  790. );
  791. assertEq(reqAfterReveal.sequenceNumber, 0);
  792. }
  793. function testRequestWithCallbackAndRevealWithCallbackByEoa() public {
  794. bytes32 userRandomNumber = bytes32(uint(42));
  795. uint fee = random.getFee(provider1);
  796. vm.deal(user1, fee);
  797. vm.prank(user1);
  798. uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
  799. provider1,
  800. userRandomNumber
  801. );
  802. EntropyStructsV2.Request memory req = random.getRequest(
  803. provider1,
  804. assignedSequenceNumber
  805. );
  806. vm.expectEmit(false, false, false, true, address(random));
  807. emit RevealedWithCallback(
  808. EntropyStructConverter.toV1Request(req),
  809. userRandomNumber,
  810. provider1Proofs[assignedSequenceNumber],
  811. random.combineRandomValues(
  812. userRandomNumber,
  813. provider1Proofs[assignedSequenceNumber],
  814. 0
  815. )
  816. );
  817. random.revealWithCallback(
  818. provider1,
  819. assignedSequenceNumber,
  820. userRandomNumber,
  821. provider1Proofs[assignedSequenceNumber]
  822. );
  823. EntropyStructsV2.Request memory reqAfterReveal = random.getRequest(
  824. provider1,
  825. assignedSequenceNumber
  826. );
  827. assertEq(reqAfterReveal.sequenceNumber, 0);
  828. }
  829. function testRequestAndRevealWithCallback() public {
  830. uint64 sequenceNumber = request(user2, provider1, 42, false);
  831. assertEq(random.getRequest(provider1, sequenceNumber).requester, user2);
  832. vm.expectRevert(EntropyErrors.InvalidRevealCall.selector);
  833. vm.prank(user2);
  834. random.revealWithCallback(
  835. provider1,
  836. sequenceNumber,
  837. bytes32(uint256(42)),
  838. provider1Proofs[sequenceNumber]
  839. );
  840. }
  841. function testRequestWithCallbackAndRevealWithCallbackFailing() public {
  842. bytes32 userRandomNumber = bytes32(uint(42));
  843. uint fee = random.getFee(provider1);
  844. EntropyConsumer consumer = new EntropyConsumer(address(random), true);
  845. vm.deal(address(consumer), fee);
  846. vm.startPrank(address(consumer));
  847. uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
  848. provider1,
  849. userRandomNumber
  850. );
  851. vm.expectRevert();
  852. random.revealWithCallback(
  853. provider1,
  854. assignedSequenceNumber,
  855. userRandomNumber,
  856. provider1Proofs[assignedSequenceNumber]
  857. );
  858. }
  859. function testRequestWithCallbackGasLimit() public {
  860. uint32 defaultGasLimit = 100000;
  861. vm.prank(provider1);
  862. random.setDefaultGasLimit(defaultGasLimit);
  863. bytes32 userRandomNumber = bytes32(uint(42));
  864. uint fee = random.getFee(provider1);
  865. EntropyConsumer consumer = new EntropyConsumer(address(random), false);
  866. vm.deal(user1, fee);
  867. vm.prank(user1);
  868. uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
  869. userRandomNumber
  870. );
  871. EntropyStructsV2.Request memory req = random.getRequest(
  872. provider1,
  873. assignedSequenceNumber
  874. );
  875. // Verify the gas limit was set correctly
  876. assertEq(req.gasLimit10k, 10);
  877. vm.expectEmit(false, false, false, true, address(random));
  878. emit RevealedWithCallback(
  879. EntropyStructConverter.toV1Request(req),
  880. userRandomNumber,
  881. provider1Proofs[assignedSequenceNumber],
  882. random.combineRandomValues(
  883. userRandomNumber,
  884. provider1Proofs[assignedSequenceNumber],
  885. 0
  886. )
  887. );
  888. random.revealWithCallback(
  889. provider1,
  890. assignedSequenceNumber,
  891. userRandomNumber,
  892. provider1Proofs[assignedSequenceNumber]
  893. );
  894. assertEq(consumer.sequence(), assignedSequenceNumber);
  895. assertEq(consumer.provider(), provider1);
  896. assertEq(
  897. consumer.randomness(),
  898. random.combineRandomValues(
  899. userRandomNumber,
  900. provider1Proofs[assignedSequenceNumber],
  901. 0
  902. )
  903. );
  904. EntropyStructsV2.Request memory reqAfterReveal = random.getRequest(
  905. provider1,
  906. assignedSequenceNumber
  907. );
  908. assertEq(reqAfterReveal.sequenceNumber, 0);
  909. }
  910. function testRequestWithRevertingCallback() public {
  911. uint32 defaultGasLimit = 100000;
  912. vm.prank(provider1);
  913. random.setDefaultGasLimit(defaultGasLimit);
  914. bytes32 userRandomNumber = bytes32(uint(42));
  915. uint fee = random.getFee(provider1);
  916. EntropyConsumer consumer = new EntropyConsumer(address(random), true);
  917. vm.deal(user1, fee);
  918. vm.prank(user1);
  919. uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
  920. userRandomNumber
  921. );
  922. // On the first attempt, the transaction should succeed and emit CallbackFailed event.
  923. bytes memory revertReason = abi.encodeWithSelector(
  924. 0x08c379a0,
  925. "Callback failed"
  926. );
  927. vm.expectEmit(false, false, false, true, address(random));
  928. emit CallbackFailed(
  929. provider1,
  930. address(consumer),
  931. assignedSequenceNumber,
  932. userRandomNumber,
  933. provider1Proofs[assignedSequenceNumber],
  934. random.combineRandomValues(
  935. userRandomNumber,
  936. provider1Proofs[assignedSequenceNumber],
  937. 0
  938. ),
  939. revertReason
  940. );
  941. random.revealWithCallback(
  942. provider1,
  943. assignedSequenceNumber,
  944. userRandomNumber,
  945. provider1Proofs[assignedSequenceNumber]
  946. );
  947. // Verify request is still active after failure
  948. EntropyStructsV2.Request memory reqAfterFailure = random.getRequest(
  949. provider1,
  950. assignedSequenceNumber
  951. );
  952. assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
  953. assertTrue(
  954. reqAfterFailure.callbackStatus ==
  955. EntropyStatusConstants.CALLBACK_FAILED
  956. );
  957. // On the second attempt, the transaction should directly revert
  958. vm.expectRevert();
  959. random.revealWithCallback(
  960. provider1,
  961. assignedSequenceNumber,
  962. userRandomNumber,
  963. provider1Proofs[assignedSequenceNumber]
  964. );
  965. // Again, request stays active after failure
  966. reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber);
  967. assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
  968. assertTrue(
  969. reqAfterFailure.callbackStatus ==
  970. EntropyStatusConstants.CALLBACK_FAILED
  971. );
  972. // If the callback starts succeeding, we can invoke it and it emits the usual RevealedWithCallback event.
  973. consumer.setReverts(false);
  974. vm.expectEmit(false, false, false, true, address(random));
  975. emit RevealedWithCallback(
  976. EntropyStructConverter.toV1Request(reqAfterFailure),
  977. userRandomNumber,
  978. provider1Proofs[assignedSequenceNumber],
  979. random.combineRandomValues(
  980. userRandomNumber,
  981. provider1Proofs[assignedSequenceNumber],
  982. 0
  983. )
  984. );
  985. random.revealWithCallback(
  986. provider1,
  987. assignedSequenceNumber,
  988. userRandomNumber,
  989. provider1Proofs[assignedSequenceNumber]
  990. );
  991. // Verify request is cleared after successful reveal
  992. EntropyStructsV2.Request memory reqAfterReveal = random.getRequest(
  993. provider1,
  994. assignedSequenceNumber
  995. );
  996. assertEq(reqAfterReveal.sequenceNumber, 0);
  997. }
  998. function testRequestWithCallbackUsingTooMuchGas() public {
  999. uint32 defaultGasLimit = 100000;
  1000. vm.prank(provider1);
  1001. random.setDefaultGasLimit(defaultGasLimit);
  1002. bytes32 userRandomNumber = bytes32(uint(42));
  1003. uint fee = random.getFee(provider1);
  1004. EntropyConsumer consumer = new EntropyConsumer(address(random), false);
  1005. // Consumer callback uses ~10% more gas than the provider's default
  1006. consumer.setTargetGasUsage((defaultGasLimit * 110) / 100);
  1007. vm.deal(user1, fee);
  1008. vm.prank(user1);
  1009. uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
  1010. userRandomNumber
  1011. );
  1012. EntropyStructsV2.Request memory req = random.getRequest(
  1013. provider1,
  1014. assignedSequenceNumber
  1015. );
  1016. // Verify the gas limit was set correctly
  1017. assertEq(req.gasLimit10k, 10);
  1018. // The transaction reverts if the provider does not provide enough gas to forward
  1019. // the gasLimit to the callback transaction.
  1020. vm.expectRevert();
  1021. random.revealWithCallback{gas: defaultGasLimit - 10000}(
  1022. provider1,
  1023. assignedSequenceNumber,
  1024. userRandomNumber,
  1025. provider1Proofs[assignedSequenceNumber]
  1026. );
  1027. // If called with enough gas, the transaction should succeed, but the callback should fail because
  1028. // it uses too much gas.
  1029. vm.expectEmit(false, false, false, true, address(random));
  1030. emit CallbackFailed(
  1031. provider1,
  1032. address(consumer),
  1033. assignedSequenceNumber,
  1034. userRandomNumber,
  1035. provider1Proofs[assignedSequenceNumber],
  1036. random.combineRandomValues(
  1037. userRandomNumber,
  1038. provider1Proofs[assignedSequenceNumber],
  1039. 0
  1040. ),
  1041. // out-of-gas reverts have an empty bytes array as the return value.
  1042. ""
  1043. );
  1044. random.revealWithCallback(
  1045. provider1,
  1046. assignedSequenceNumber,
  1047. userRandomNumber,
  1048. provider1Proofs[assignedSequenceNumber]
  1049. );
  1050. // Verify request is still active after failure
  1051. EntropyStructsV2.Request memory reqAfterFailure = random.getRequest(
  1052. provider1,
  1053. assignedSequenceNumber
  1054. );
  1055. assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
  1056. assertEq(
  1057. reqAfterFailure.callbackStatus,
  1058. EntropyStatusConstants.CALLBACK_FAILED
  1059. );
  1060. // A subsequent attempt passing insufficient gas should also revert
  1061. vm.expectRevert();
  1062. random.revealWithCallback{gas: defaultGasLimit - 10000}(
  1063. provider1,
  1064. assignedSequenceNumber,
  1065. userRandomNumber,
  1066. provider1Proofs[assignedSequenceNumber]
  1067. );
  1068. // Again, request stays active after failure
  1069. reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber);
  1070. assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
  1071. assertEq(
  1072. reqAfterFailure.callbackStatus,
  1073. EntropyStatusConstants.CALLBACK_FAILED
  1074. );
  1075. // Calling without a gas limit should succeed
  1076. vm.expectEmit(false, false, false, true, address(random));
  1077. emit RevealedWithCallback(
  1078. EntropyStructConverter.toV1Request(reqAfterFailure),
  1079. userRandomNumber,
  1080. provider1Proofs[assignedSequenceNumber],
  1081. random.combineRandomValues(
  1082. userRandomNumber,
  1083. provider1Proofs[assignedSequenceNumber],
  1084. 0
  1085. )
  1086. );
  1087. random.revealWithCallback(
  1088. provider1,
  1089. assignedSequenceNumber,
  1090. userRandomNumber,
  1091. provider1Proofs[assignedSequenceNumber]
  1092. );
  1093. // Verify request is cleared after successful reveal
  1094. EntropyStructsV2.Request memory reqAfterReveal = random.getRequest(
  1095. provider1,
  1096. assignedSequenceNumber
  1097. );
  1098. assertEq(reqAfterReveal.sequenceNumber, 0);
  1099. }
  1100. // Test the corner case caused by the CALL opcode passing at most 63/64ths of the current gas
  1101. // to the sub-call.
  1102. function testRequestWithCallbackUsingTooMuchGas2() public {
  1103. // With a 64M gas limit, we will pass ~63M gas to the callback (which is insufficient), but still
  1104. // have ~1M gas to execute code within the revealWithCallback method, which should be enough to
  1105. // run all of the logic subsequent to the excessivelySafeCall.
  1106. uint32 defaultGasLimit = 64000000;
  1107. vm.prank(provider1);
  1108. random.setDefaultGasLimit(defaultGasLimit);
  1109. bytes32 userRandomNumber = bytes32(uint(42));
  1110. uint fee = random.getFee(provider1);
  1111. EntropyConsumer consumer = new EntropyConsumer(address(random), false);
  1112. consumer.setTargetGasUsage(defaultGasLimit);
  1113. vm.deal(user1, fee);
  1114. vm.prank(user1);
  1115. uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
  1116. userRandomNumber
  1117. );
  1118. // The transaction reverts if the provider does not provide enough gas to forward
  1119. // the gasLimit to the callback transaction.
  1120. vm.expectRevert(EntropyErrors.InsufficientGas.selector);
  1121. random.revealWithCallback{gas: defaultGasLimit - 10000}(
  1122. provider1,
  1123. assignedSequenceNumber,
  1124. userRandomNumber,
  1125. provider1Proofs[assignedSequenceNumber]
  1126. );
  1127. }
  1128. function testLastRevealedTooOld() public {
  1129. for (uint256 i = 0; i < provider1MaxNumHashes; i++) {
  1130. request(user1, provider1, 42, false);
  1131. }
  1132. assertRequestReverts(
  1133. random.getFee(provider1),
  1134. provider1,
  1135. 42,
  1136. false,
  1137. EntropyErrors.LastRevealedTooOld.selector
  1138. );
  1139. }
  1140. function testAdvanceProviderCommitment(
  1141. uint32 requestCount,
  1142. uint32 updateSeqNumber
  1143. ) public {
  1144. vm.assume(requestCount < provider1MaxNumHashes);
  1145. vm.assume(updateSeqNumber < requestCount);
  1146. vm.assume(0 < updateSeqNumber);
  1147. for (uint256 i = 0; i < requestCount; i++) {
  1148. request(user1, provider1, 42, false);
  1149. }
  1150. assertInvariants();
  1151. EntropyStructsV2.ProviderInfo memory info1 = random.getProviderInfo(
  1152. provider1
  1153. );
  1154. assertEq(info1.currentCommitmentSequenceNumber, 0);
  1155. assertEq(info1.sequenceNumber, requestCount + 1);
  1156. random.advanceProviderCommitment(
  1157. provider1,
  1158. updateSeqNumber,
  1159. provider1Proofs[updateSeqNumber]
  1160. );
  1161. info1 = random.getProviderInfo(provider1);
  1162. assertEq(info1.currentCommitmentSequenceNumber, updateSeqNumber);
  1163. assertEq(info1.currentCommitment, provider1Proofs[updateSeqNumber]);
  1164. assertEq(info1.sequenceNumber, requestCount + 1);
  1165. assertInvariants();
  1166. }
  1167. function testAdvanceProviderCommitmentTooOld(
  1168. uint32 requestCount,
  1169. uint32 updateSeqNumber
  1170. ) public {
  1171. vm.assume(requestCount < provider1MaxNumHashes);
  1172. vm.assume(updateSeqNumber < requestCount);
  1173. vm.assume(0 < updateSeqNumber);
  1174. for (uint256 i = 0; i < requestCount; i++) {
  1175. request(user1, provider1, 42, false);
  1176. }
  1177. assertRevealSucceeds(
  1178. user1,
  1179. provider1,
  1180. requestCount,
  1181. 42,
  1182. provider1Proofs[requestCount],
  1183. ALL_ZEROS
  1184. );
  1185. vm.expectRevert(EntropyErrors.UpdateTooOld.selector);
  1186. random.advanceProviderCommitment(
  1187. provider1,
  1188. updateSeqNumber,
  1189. provider1Proofs[updateSeqNumber]
  1190. );
  1191. }
  1192. function testAdvanceProviderCommitmentIncorrectRevelation(
  1193. uint32 seqNumber,
  1194. uint32 mismatchedProofNumber
  1195. ) public {
  1196. vm.assume(seqNumber < provider1ChainLength);
  1197. vm.assume(mismatchedProofNumber < provider1ChainLength);
  1198. vm.assume(seqNumber != mismatchedProofNumber);
  1199. vm.assume(seqNumber > 0);
  1200. vm.expectRevert(EntropyErrors.IncorrectRevelation.selector);
  1201. random.advanceProviderCommitment(
  1202. provider1,
  1203. seqNumber,
  1204. provider1Proofs[mismatchedProofNumber]
  1205. );
  1206. }
  1207. function testAdvanceProviderCommitmentUpdatesSequenceNumber(
  1208. uint32 seqNumber
  1209. ) public {
  1210. vm.assume(seqNumber < provider1ChainLength);
  1211. vm.assume(seqNumber > 0);
  1212. random.advanceProviderCommitment(
  1213. provider1,
  1214. seqNumber,
  1215. provider1Proofs[seqNumber]
  1216. );
  1217. EntropyStructsV2.ProviderInfo memory info1 = random.getProviderInfo(
  1218. provider1
  1219. );
  1220. assertEq(info1.sequenceNumber, seqNumber + 1);
  1221. }
  1222. function testAdvanceProviderCommitmentHigherThanChainLength(
  1223. uint32 seqNumber
  1224. ) public {
  1225. vm.assume(seqNumber >= provider1ChainLength);
  1226. vm.expectRevert(EntropyErrors.AssertionFailure.selector);
  1227. random.advanceProviderCommitment(
  1228. provider1,
  1229. seqNumber,
  1230. provider1Proofs[0]
  1231. );
  1232. }
  1233. function testSetMaxNumHashes(uint32 maxNumHashes) public {
  1234. vm.prank(provider1);
  1235. random.setMaxNumHashes(maxNumHashes);
  1236. EntropyStructsV2.ProviderInfo memory info1 = random.getProviderInfo(
  1237. provider1
  1238. );
  1239. assertEq(info1.maxNumHashes, maxNumHashes);
  1240. }
  1241. function testSetMaxNumHashesRevertIfNotFromProvider() public {
  1242. vm.expectRevert(EntropyErrors.NoSuchProvider.selector);
  1243. random.setMaxNumHashes(100);
  1244. }
  1245. function testZeroMaxNumHashesDisableChecks() public {
  1246. for (uint256 i = 0; i < provider1MaxNumHashes; i++) {
  1247. request(user1, provider1, 42, false);
  1248. }
  1249. assertRequestReverts(
  1250. random.getFee(provider1),
  1251. provider1,
  1252. 42,
  1253. false,
  1254. EntropyErrors.LastRevealedTooOld.selector
  1255. );
  1256. vm.prank(provider1);
  1257. random.setMaxNumHashes(0);
  1258. request(user1, provider1, 42, false);
  1259. }
  1260. function testFeeManager() public {
  1261. address manager = address(12);
  1262. // Make sure there are some fees for provider1
  1263. request(user1, provider1, 42, false);
  1264. // Manager isn't authorized, so can't withdraw or set fee.
  1265. vm.prank(manager);
  1266. vm.expectRevert();
  1267. random.withdrawAsFeeManager(provider1, provider1FeeInWei);
  1268. vm.prank(manager);
  1269. vm.expectRevert();
  1270. random.setProviderFeeAsFeeManager(provider1, 1000);
  1271. // You can't set a fee manager from an address that isn't a registered provider.
  1272. vm.expectRevert();
  1273. random.setFeeManager(address(manager));
  1274. // Authorizing the fee manager as the provider enables withdrawing and setting fees.
  1275. vm.prank(provider1);
  1276. random.setFeeManager(address(manager));
  1277. // Withdrawing decrements provider's accrued fees and sends balance to the fee manager.
  1278. uint startingBalance = manager.balance;
  1279. vm.prank(manager);
  1280. random.withdrawAsFeeManager(provider1, provider1FeeInWei);
  1281. assertEq(random.getProviderInfo(provider1).accruedFeesInWei, 0);
  1282. assertEq(manager.balance, startingBalance + provider1FeeInWei);
  1283. // Setting provider fee updates the fee in the ProviderInfo.
  1284. vm.prank(manager);
  1285. random.setProviderFeeAsFeeManager(provider1, 10101);
  1286. assertEq(random.getProviderInfo(provider1).feeInWei, 10101);
  1287. // Authorizing a different manager depermissions the previous one.
  1288. address manager2 = address(13);
  1289. vm.prank(provider1);
  1290. random.setFeeManager(address(manager2));
  1291. vm.prank(manager);
  1292. vm.expectRevert();
  1293. random.withdrawAsFeeManager(provider1, provider1FeeInWei);
  1294. vm.prank(manager);
  1295. vm.expectRevert();
  1296. random.setProviderFeeAsFeeManager(provider1, 1000);
  1297. }
  1298. function testSetDefaultGasLimit() public {
  1299. uint32 newGasLimit = 100000;
  1300. vm.prank(provider1);
  1301. vm.expectEmit(false, false, false, true, address(random));
  1302. emit ProviderDefaultGasLimitUpdated(provider1, 0, newGasLimit);
  1303. random.setDefaultGasLimit(newGasLimit);
  1304. EntropyStructsV2.ProviderInfo memory info = random.getProviderInfo(
  1305. provider1
  1306. );
  1307. assertEq(info.defaultGasLimit, newGasLimit);
  1308. // Can reset back to 0.
  1309. vm.prank(provider1);
  1310. random.setDefaultGasLimit(0);
  1311. info = random.getProviderInfo(provider1);
  1312. assertEq(info.defaultGasLimit, 0);
  1313. // Can set to maximum value.
  1314. uint32 maxLimit = random.MAX_GAS_LIMIT();
  1315. vm.prank(provider1);
  1316. random.setDefaultGasLimit(maxLimit);
  1317. info = random.getProviderInfo(provider1);
  1318. assertEq(info.defaultGasLimit, random.MAX_GAS_LIMIT());
  1319. // Reverts if max value is exceeded
  1320. uint32 exceedsGasLimit = random.MAX_GAS_LIMIT() + 1;
  1321. vm.prank(provider1);
  1322. vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
  1323. random.setDefaultGasLimit(exceedsGasLimit);
  1324. }
  1325. function testSetDefaultGasLimitRevertIfNotFromProvider() public {
  1326. vm.expectRevert(EntropyErrors.NoSuchProvider.selector);
  1327. random.setDefaultGasLimit(100000);
  1328. }
  1329. function testRequestWithCallbackUsesDefaultGasLimit() public {
  1330. uint32 defaultGasLimit = 100000;
  1331. vm.prank(provider1);
  1332. random.setDefaultGasLimit(defaultGasLimit);
  1333. bytes32 userRandomNumber = bytes32(uint(42));
  1334. uint fee = random.getFee(provider1);
  1335. vm.deal(user1, fee);
  1336. vm.prank(user1);
  1337. uint64 sequenceNumber = random.requestWithCallback{value: fee}(
  1338. provider1,
  1339. userRandomNumber
  1340. );
  1341. EntropyStructsV2.Request memory req = random.getRequest(
  1342. provider1,
  1343. sequenceNumber
  1344. );
  1345. assertEq(req.gasLimit10k, 10);
  1346. }
  1347. function testGasLimitsAndFeeRounding() public {
  1348. vm.prank(provider1);
  1349. random.setDefaultGasLimit(20000);
  1350. vm.prank(provider1);
  1351. random.setProviderFee(1);
  1352. // Test exact multiples of 10,000
  1353. assertGasLimitAndFee(0, 2, 1);
  1354. assertGasLimitAndFee(10000, 2, 1);
  1355. assertGasLimitAndFee(20000, 2, 1);
  1356. assertGasLimitAndFee(100000, 10, 5);
  1357. // Test values just below multiples of 10,000
  1358. assertGasLimitAndFee(9999, 2, 1);
  1359. assertGasLimitAndFee(19999, 2, 1);
  1360. assertGasLimitAndFee(39999, 4, 2);
  1361. assertGasLimitAndFee(99999, 10, 5);
  1362. // Test values just above multiples of 10,000
  1363. assertGasLimitAndFee(10001, 2, 1);
  1364. assertGasLimitAndFee(20001, 3, 1);
  1365. assertGasLimitAndFee(100001, 11, 5);
  1366. assertGasLimitAndFee(110001, 12, 6);
  1367. // Test middle values
  1368. assertGasLimitAndFee(5000, 2, 1);
  1369. assertGasLimitAndFee(15000, 2, 1);
  1370. assertGasLimitAndFee(25000, 3, 1);
  1371. // Test maximum value
  1372. assertGasLimitAndFee(
  1373. uint32(type(uint16).max) * 10000,
  1374. type(uint16).max,
  1375. uint128(type(uint16).max) / 2
  1376. );
  1377. // Test larger than max value reverts with expected error
  1378. uint32 exceedsGasLimit = uint32(type(uint16).max) * 10000 + 1;
  1379. vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
  1380. random.getFeeForGas(provider1, exceedsGasLimit);
  1381. vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
  1382. random.requestWithCallbackAndGasLimit{value: 10000000000000}(
  1383. provider1,
  1384. bytes32(uint(42)),
  1385. exceedsGasLimit
  1386. );
  1387. // A provider with a 0 gas limit is opted-out of the failure state flow, indicated by
  1388. // a 0 gas limit on all requests.
  1389. vm.prank(provider1);
  1390. random.setDefaultGasLimit(0);
  1391. assertGasLimitAndFee(0, 0, 1);
  1392. assertGasLimitAndFee(10000, 0, 1);
  1393. assertGasLimitAndFee(20000, 0, 1);
  1394. assertGasLimitAndFee(100000, 0, 1);
  1395. }
  1396. // Helper method to create a request with a specific gas limit and check the gasLimit10k / provider fees
  1397. function assertGasLimitAndFee(
  1398. uint32 gasLimit,
  1399. uint16 expectedGasLimit10k,
  1400. uint128 expectedProviderFee
  1401. ) internal {
  1402. // Create a request with callback
  1403. bytes32 userRandomNumber = bytes32(uint(42));
  1404. uint fee = random.getFeeForGas(provider1, gasLimit);
  1405. assertEq(fee - random.getPythFee(), expectedProviderFee);
  1406. // Passing 1 wei less than the expected fee causes a revert.
  1407. vm.deal(user1, fee);
  1408. vm.prank(user1);
  1409. vm.expectRevert(EntropyErrors.InsufficientFee.selector);
  1410. random.requestWithCallbackAndGasLimit{value: fee - 1}(
  1411. provider1,
  1412. userRandomNumber,
  1413. gasLimit
  1414. );
  1415. uint128 startingAccruedProviderFee = random
  1416. .getProviderInfo(provider1)
  1417. .accruedFeesInWei;
  1418. vm.prank(user1);
  1419. uint64 sequenceNumber = random.requestWithCallbackAndGasLimit{
  1420. value: fee
  1421. }(provider1, userRandomNumber, gasLimit);
  1422. assertEq(
  1423. random.getProviderInfo(provider1).accruedFeesInWei -
  1424. startingAccruedProviderFee,
  1425. expectedProviderFee
  1426. );
  1427. // Check the gasLimit10k field in the request
  1428. EntropyStructsV2.Request memory req = random.getRequest(
  1429. provider1,
  1430. sequenceNumber
  1431. );
  1432. assertEq(req.gasLimit10k, expectedGasLimit10k);
  1433. }
  1434. function testCallbackProvidedGas() public {
  1435. vm.prank(provider1);
  1436. random.setDefaultGasLimit(200000);
  1437. assertCallbackResult(0, 190000, true);
  1438. assertCallbackResult(0, 210000, false);
  1439. assertCallbackResult(300000, 290000, true);
  1440. assertCallbackResult(300000, 310000, false);
  1441. // A provider that hasn't upgraded to the callback failure flow
  1442. // can never cause a callback to fail because it runs out of gas.
  1443. vm.prank(provider1);
  1444. random.setDefaultGasLimit(0);
  1445. assertCallbackResult(0, 190000, true);
  1446. assertCallbackResult(0, 210000, true);
  1447. assertCallbackResult(300000, 290000, true);
  1448. assertCallbackResult(300000, 310000, true);
  1449. }
  1450. // Helper method to assert whether a request with a specific gas limit / a callback with a specific gas cost
  1451. // should be successful or not.
  1452. function assertCallbackResult(
  1453. uint32 gasLimit,
  1454. uint32 callbackGasUsage,
  1455. bool expectSuccess
  1456. ) internal {
  1457. // Create a request with callback
  1458. bytes32 userRandomNumber = bytes32(uint(42));
  1459. uint fee = random.getFeeForGas(provider1, gasLimit);
  1460. vm.deal(user1, fee);
  1461. vm.prank(user1);
  1462. EntropyConsumer consumer = new EntropyConsumer(address(random), false);
  1463. uint64 sequenceNumber = consumer.requestEntropyWithGasLimit{value: fee}(
  1464. userRandomNumber,
  1465. gasLimit
  1466. );
  1467. consumer.setTargetGasUsage(callbackGasUsage);
  1468. EntropyStructsV2.Request memory req = random.getRequest(
  1469. provider1,
  1470. sequenceNumber
  1471. );
  1472. if (!expectSuccess) {
  1473. vm.expectEmit(false, false, false, true, address(random));
  1474. emit CallbackFailed(
  1475. provider1,
  1476. address(consumer),
  1477. sequenceNumber,
  1478. userRandomNumber,
  1479. provider1Proofs[sequenceNumber],
  1480. random.combineRandomValues(
  1481. userRandomNumber,
  1482. provider1Proofs[sequenceNumber],
  1483. 0
  1484. ),
  1485. // out-of-gas reverts have an empty bytes array as the return value.
  1486. ""
  1487. );
  1488. random.revealWithCallback(
  1489. provider1,
  1490. sequenceNumber,
  1491. userRandomNumber,
  1492. provider1Proofs[sequenceNumber]
  1493. );
  1494. // Verify request is still active after failure
  1495. EntropyStructsV2.Request memory reqAfterFailure = random.getRequest(
  1496. provider1,
  1497. sequenceNumber
  1498. );
  1499. assertEq(reqAfterFailure.sequenceNumber, sequenceNumber);
  1500. assertEq(
  1501. reqAfterFailure.callbackStatus,
  1502. EntropyStatusConstants.CALLBACK_FAILED
  1503. );
  1504. } else {
  1505. vm.expectEmit(false, false, false, true, address(random));
  1506. emit RevealedWithCallback(
  1507. EntropyStructConverter.toV1Request(req),
  1508. userRandomNumber,
  1509. provider1Proofs[sequenceNumber],
  1510. random.combineRandomValues(
  1511. userRandomNumber,
  1512. provider1Proofs[sequenceNumber],
  1513. 0
  1514. )
  1515. );
  1516. random.revealWithCallback(
  1517. provider1,
  1518. sequenceNumber,
  1519. userRandomNumber,
  1520. provider1Proofs[sequenceNumber]
  1521. );
  1522. // Verify request is cleared after successful callback
  1523. EntropyStructsV2.Request memory reqAfterSuccess = random.getRequest(
  1524. provider1,
  1525. sequenceNumber
  1526. );
  1527. assertEq(reqAfterSuccess.sequenceNumber, 0);
  1528. }
  1529. }
  1530. }
  1531. contract EntropyConsumer is IEntropyConsumer {
  1532. uint64 public sequence;
  1533. bytes32 public randomness;
  1534. address public provider;
  1535. address public entropy;
  1536. bool public reverts;
  1537. uint256 public targetGasUsage;
  1538. constructor(address _entropy, bool _reverts) {
  1539. entropy = _entropy;
  1540. reverts = _reverts;
  1541. targetGasUsage = 0; // Default target
  1542. }
  1543. function requestEntropy(
  1544. bytes32 randomNumber
  1545. ) public payable returns (uint64 sequenceNumber) {
  1546. address _provider = IEntropy(entropy).getDefaultProvider();
  1547. sequenceNumber = IEntropy(entropy).requestWithCallback{
  1548. value: msg.value
  1549. }(_provider, randomNumber);
  1550. }
  1551. function requestEntropyWithGasLimit(
  1552. bytes32 randomNumber,
  1553. uint32 gasLimit
  1554. ) public payable returns (uint64 sequenceNumber) {
  1555. address _provider = IEntropy(entropy).getDefaultProvider();
  1556. sequenceNumber = IEntropy(entropy).requestWithCallbackAndGasLimit{
  1557. value: msg.value
  1558. }(_provider, randomNumber, gasLimit);
  1559. }
  1560. function getEntropy() internal view override returns (address) {
  1561. return entropy;
  1562. }
  1563. function setReverts(bool _reverts) public {
  1564. reverts = _reverts;
  1565. }
  1566. function setTargetGasUsage(uint256 _targetGasUsage) public {
  1567. require(
  1568. _targetGasUsage > 60000,
  1569. "Target gas usage cannot be below 60k (~the cost of storing callback results)"
  1570. );
  1571. targetGasUsage = _targetGasUsage;
  1572. }
  1573. function entropyCallback(
  1574. uint64 _sequence,
  1575. address _provider,
  1576. bytes32 _randomness
  1577. ) internal override {
  1578. uint256 startGas = gasleft();
  1579. // These seemingly innocuous instructions are actually quite expensive
  1580. // (~60k gas) because they're writes to contract storage.
  1581. sequence = _sequence;
  1582. provider = _provider;
  1583. randomness = _randomness;
  1584. // Keep consuming gas until we reach our target
  1585. uint256 currentGasUsed = startGas - gasleft();
  1586. while (currentGasUsed < targetGasUsage) {
  1587. // Consume gas with a hash operation
  1588. keccak256(abi.encodePacked(currentGasUsed, _randomness));
  1589. currentGasUsed = startGas - gasleft();
  1590. }
  1591. if (reverts) {
  1592. revert("Callback failed");
  1593. }
  1594. }
  1595. }