Executor.t.sol 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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 "../contracts/executor/ExecutorUpgradable.sol";
  6. import "./utils/WormholeTestUtils.t.sol";
  7. import "./utils/InvalidMagic.t.sol";
  8. contract ExecutorTest is Test, WormholeTestUtils {
  9. Wormhole public wormhole;
  10. ExecutorUpgradable public executor;
  11. ExecutorUpgradable public executor2;
  12. TestCallable public callable;
  13. InvalidMagic public executorInvalidMagic;
  14. uint16 OWNER_CHAIN_ID = 7;
  15. bytes32 OWNER_EMITTER = bytes32(uint256(1));
  16. uint8 NUM_SIGNERS = 1;
  17. function setUp() public {
  18. address _wormhole = setUpWormholeReceiver(NUM_SIGNERS);
  19. ExecutorUpgradable _executor = new ExecutorUpgradable();
  20. ERC1967Proxy _proxy = new ERC1967Proxy(address(_executor), "");
  21. executor = ExecutorUpgradable(payable(address(_proxy)));
  22. executor2 = new ExecutorUpgradable();
  23. executorInvalidMagic = new InvalidMagic();
  24. executor.initialize(
  25. _wormhole,
  26. 0,
  27. CHAIN_ID,
  28. OWNER_CHAIN_ID,
  29. OWNER_EMITTER
  30. );
  31. callable = new TestCallable();
  32. }
  33. function testExecute(
  34. address callAddress,
  35. bytes memory callData,
  36. uint64 sequence,
  37. uint value
  38. ) internal returns (bytes memory vaa) {
  39. bytes memory payload = abi.encodePacked(
  40. uint32(0x5054474d),
  41. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  42. Executor.ExecutorAction.Execute,
  43. CHAIN_ID,
  44. address(executor),
  45. callAddress,
  46. value,
  47. callData
  48. );
  49. vaa = generateVaa(
  50. uint32(block.timestamp),
  51. OWNER_CHAIN_ID,
  52. OWNER_EMITTER,
  53. sequence,
  54. payload,
  55. NUM_SIGNERS
  56. );
  57. executor.execute(vaa);
  58. }
  59. function getTestUpgradeVaa(
  60. address newImplementation,
  61. uint value
  62. ) internal view returns (bytes memory vaa) {
  63. bytes memory payload = abi.encodePacked(
  64. uint32(0x5054474d),
  65. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  66. Executor.ExecutorAction.Execute,
  67. CHAIN_ID,
  68. address(executor),
  69. address(executor),
  70. value,
  71. abi.encodeWithSelector(
  72. ExecutorUpgradable.upgradeTo.selector,
  73. newImplementation
  74. )
  75. );
  76. vaa = generateVaa(
  77. uint32(block.timestamp),
  78. OWNER_CHAIN_ID,
  79. OWNER_EMITTER,
  80. 1,
  81. payload,
  82. NUM_SIGNERS
  83. );
  84. }
  85. function testExecutorOwnerChainId() public {
  86. uint chainId = executor.getOwnerChainId();
  87. assertEq(chainId, OWNER_CHAIN_ID);
  88. }
  89. function testExecutorOwnerEmitterAddress() public {
  90. bytes32 ownerEmitterAddress = executor.getOwnerEmitterAddress();
  91. assertEq(ownerEmitterAddress, OWNER_EMITTER);
  92. }
  93. function testExecutorOwner() public {
  94. assertEq(address(executor), executor.owner());
  95. }
  96. function testExternaUpgradeCallFails() public {
  97. vm.expectRevert("Ownable: caller is not the owner");
  98. executor.upgradeTo(address(executor2));
  99. }
  100. function testUpgradeCallSucceedsForContractWithCorrectMagic() public {
  101. bytes memory vaa = getTestUpgradeVaa(address(executor2), 0);
  102. executor.execute(vaa);
  103. }
  104. function testUpgradeCallFailsForNotUUPSContract() public {
  105. bytes memory vaa = getTestUpgradeVaa(address(callable), 0);
  106. vm.expectRevert("ERC1967Upgrade: new implementation is not UUPS");
  107. executor.execute(vaa);
  108. }
  109. function testUpgradeCallFailsForInvalidMagic() public {
  110. bytes memory vaa = getTestUpgradeVaa(address(executorInvalidMagic), 0);
  111. vm.expectRevert(ExecutorErrors.InvalidMagicValue.selector);
  112. executor.execute(vaa);
  113. }
  114. function testLastExecutedSequenceUpdateOnSucceed() public {
  115. callable.reset();
  116. uint32 c = callable.fooCount();
  117. uint oldSequence = executor.getLastExecutedSequence();
  118. uint64 sequence = 1;
  119. assertEq(callable.lastCaller(), address(bytes20(0)));
  120. testExecute(
  121. address(callable),
  122. abi.encodeWithSelector(ICallable.foo.selector),
  123. sequence,
  124. 0
  125. );
  126. uint newSequence = executor.getLastExecutedSequence();
  127. assertGt(newSequence, oldSequence);
  128. assertEq(newSequence, sequence);
  129. assertEq(callable.fooCount(), c + 1);
  130. assertEq(callable.lastCaller(), address(executor));
  131. // Sanity check to make sure the check above is meaningful.
  132. assert(address(executor) != address(this));
  133. }
  134. function testLastExecutedSequenceNoChangeOnFail() public {
  135. uint oldSequence = executor.getLastExecutedSequence();
  136. bytes memory payload = abi.encodePacked(
  137. uint32(0x5054474d),
  138. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  139. Executor.ExecutorAction.Execute,
  140. CHAIN_ID,
  141. address(executor),
  142. address(callable),
  143. uint(0),
  144. abi.encodeWithSelector(ICallable.reverts.selector)
  145. );
  146. bytes memory vaa = generateVaa(
  147. uint32(block.timestamp),
  148. OWNER_CHAIN_ID,
  149. OWNER_EMITTER,
  150. 1,
  151. payload,
  152. NUM_SIGNERS
  153. );
  154. vm.expectRevert("call should revert");
  155. executor.execute(vaa);
  156. uint newSequence = executor.getLastExecutedSequence();
  157. assertEq(newSequence, oldSequence);
  158. }
  159. function testCallSucceeds() public {
  160. callable.reset();
  161. uint32 c = callable.fooCount();
  162. assertEq(callable.lastCaller(), address(bytes20(0)));
  163. testExecute(
  164. address(callable),
  165. abi.encodeWithSelector(ICallable.foo.selector),
  166. 1,
  167. 0
  168. );
  169. assertEq(callable.fooCount(), c + 1);
  170. assertEq(callable.lastCaller(), address(executor));
  171. // Sanity check to make sure the check above is meaningful.
  172. assert(address(executor) != address(this));
  173. }
  174. function testCallWithValueSucceeds() public {
  175. callable.reset();
  176. uint32 c = callable.fooCount();
  177. assertEq(callable.lastCaller(), address(bytes20(0)));
  178. uint value = 1;
  179. vm.deal(address(executor), value);
  180. testExecute(
  181. address(callable),
  182. abi.encodeWithSelector(ICallable.fooPayable.selector),
  183. 1,
  184. value
  185. );
  186. assertEq(callable.fooCount(), c + 1);
  187. assertEq(callable.lastCaller(), address(executor));
  188. assertEq(address(executor).balance, 0);
  189. assertEq(address(callable).balance, value);
  190. // Sanity check to make sure the check above is meaningful.
  191. assert(address(executor) != address(this));
  192. }
  193. function testCallWithValueInsufficientBalance() public {
  194. callable.reset();
  195. assertEq(callable.lastCaller(), address(bytes20(0)));
  196. uint value = 5;
  197. vm.deal(address(executor), 1);
  198. bytes memory payload = abi.encodePacked(
  199. uint32(0x5054474d),
  200. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  201. Executor.ExecutorAction.Execute,
  202. CHAIN_ID,
  203. address(executor),
  204. address(callable),
  205. value,
  206. abi.encodeWithSelector(ICallable.fooPayable.selector)
  207. );
  208. bytes memory vaa = generateVaa(
  209. uint32(block.timestamp),
  210. OWNER_CHAIN_ID,
  211. OWNER_EMITTER,
  212. 1,
  213. payload,
  214. NUM_SIGNERS
  215. );
  216. vm.expectRevert();
  217. executor.execute(vaa);
  218. }
  219. function testCallWithArgsSucceeds() public {
  220. callable.reset();
  221. uint32 c = callable.fooCount();
  222. assertEq(callable.lastCaller(), address(bytes20(0)));
  223. testExecute(
  224. address(callable),
  225. abi.encodeWithSelector(ICallable.fooWithArgs.selector, 17),
  226. 1,
  227. 0
  228. );
  229. assertEq(callable.fooCount(), c + 17);
  230. assertEq(callable.lastCaller(), address(executor));
  231. // Sanity check to make sure the check above is meaningful.
  232. assert(address(executor) != address(this));
  233. }
  234. function testCallWithArgsAndValueSucceeds() public {
  235. callable.reset();
  236. uint32 c = callable.fooCount();
  237. assertEq(callable.lastCaller(), address(bytes20(0)));
  238. uint value = 1;
  239. vm.deal(address(executor), value);
  240. testExecute(
  241. address(callable),
  242. abi.encodeWithSelector(ICallable.fooPayableWithArgs.selector, 17),
  243. 1,
  244. value
  245. );
  246. assertEq(callable.fooCount(), c + 17);
  247. assertEq(callable.lastCaller(), address(executor));
  248. assertEq(address(executor).balance, 0);
  249. assertEq(address(callable).balance, value);
  250. // Sanity check to make sure the check above is meaningful.
  251. assert(address(executor) != address(this));
  252. }
  253. function testCallerAddress() public {
  254. uint32 c = callable.fooCount();
  255. testExecute(
  256. address(callable),
  257. abi.encodeWithSelector(ICallable.foo.selector),
  258. 1,
  259. 0
  260. );
  261. assertEq(callable.fooCount(), c + 1);
  262. }
  263. function testIncorrectVaa() public {
  264. string[5] memory forgeItems = [
  265. "vaaSignature",
  266. "vaaVersion",
  267. "vaaGuardianSetIndex",
  268. "vaaNumSigners+",
  269. "vaaNumSigners-"
  270. ];
  271. for (uint i = 0; i < forgeItems.length; i++) {
  272. bytes memory payload = abi.encodePacked(
  273. uint32(0x5054474d),
  274. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  275. Executor.ExecutorAction.Execute,
  276. CHAIN_ID,
  277. address(executor),
  278. address(callable),
  279. uint(0),
  280. abi.encodeWithSelector(ICallable.foo.selector)
  281. );
  282. bytes memory vaa = forgeVaa(
  283. uint32(block.timestamp),
  284. OWNER_CHAIN_ID,
  285. OWNER_EMITTER,
  286. 1,
  287. payload,
  288. NUM_SIGNERS,
  289. bytes(forgeItems[i])
  290. );
  291. // ExecutorErrors.InvalidWormholeVaa.selector
  292. vm.expectRevert();
  293. executor.execute(vaa);
  294. }
  295. }
  296. function testIncorrectOwnerEmitterAddress() public {
  297. bytes memory payload = abi.encodePacked(
  298. uint32(0x5054474d),
  299. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  300. Executor.ExecutorAction.Execute,
  301. CHAIN_ID,
  302. address(executor),
  303. address(callable),
  304. uint(0),
  305. abi.encodeWithSelector(ICallable.foo.selector)
  306. );
  307. bytes memory vaa = generateVaa(
  308. uint32(block.timestamp),
  309. OWNER_CHAIN_ID,
  310. bytes32(uint256(2)),
  311. 1,
  312. payload,
  313. NUM_SIGNERS
  314. );
  315. vm.expectRevert(ExecutorErrors.UnauthorizedEmitter.selector);
  316. executor.execute(vaa);
  317. }
  318. function testIncorrectOwnerEmitterChainId() public {
  319. bytes memory payload = abi.encodePacked(
  320. uint32(0x5054474d),
  321. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  322. Executor.ExecutorAction.Execute,
  323. CHAIN_ID,
  324. address(executor),
  325. address(callable),
  326. uint(0),
  327. abi.encodeWithSelector(ICallable.foo.selector)
  328. );
  329. bytes memory vaa = generateVaa(
  330. uint32(block.timestamp),
  331. 8,
  332. OWNER_EMITTER,
  333. 1,
  334. payload,
  335. NUM_SIGNERS
  336. );
  337. vm.expectRevert(ExecutorErrors.UnauthorizedEmitter.selector);
  338. executor.execute(vaa);
  339. }
  340. function testOutOfOrder() public {
  341. testExecute(
  342. address(callable),
  343. abi.encodeWithSelector(ICallable.foo.selector),
  344. 3,
  345. 0
  346. );
  347. bytes memory payload = abi.encodePacked(
  348. uint32(0x5054474d),
  349. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  350. Executor.ExecutorAction.Execute,
  351. CHAIN_ID,
  352. address(executor),
  353. address(callable),
  354. uint(0),
  355. abi.encodeWithSelector(ICallable.foo.selector)
  356. );
  357. bytes memory vaa = generateVaa(
  358. uint32(block.timestamp),
  359. OWNER_CHAIN_ID,
  360. OWNER_EMITTER,
  361. 3,
  362. payload,
  363. NUM_SIGNERS
  364. );
  365. vm.expectRevert(ExecutorErrors.MessageOutOfOrder.selector);
  366. executor.execute(vaa);
  367. callable.reset();
  368. testExecute(
  369. address(callable),
  370. abi.encodeWithSelector(ICallable.foo.selector),
  371. 4,
  372. 0
  373. );
  374. assertEq(callable.fooCount(), 1);
  375. }
  376. function testInvalidPayload() public {
  377. bytes memory payload = abi.encodePacked(
  378. uint32(0x5054474d),
  379. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  380. Executor.ExecutorAction.Execute,
  381. CHAIN_ID,
  382. address(executor),
  383. address(callable),
  384. uint(0),
  385. abi.encodeWithSelector(ICallable.foo.selector)
  386. );
  387. bytes memory shortPayload = BytesLib.slice(
  388. payload,
  389. 0,
  390. payload.length - 1
  391. );
  392. bytes memory shortVaa = generateVaa(
  393. uint32(block.timestamp),
  394. OWNER_CHAIN_ID,
  395. OWNER_EMITTER,
  396. 1,
  397. shortPayload,
  398. NUM_SIGNERS
  399. );
  400. vm.expectRevert();
  401. executor.execute(shortVaa);
  402. }
  403. function testIncorrectTargetChainId() public {
  404. bytes memory payload = abi.encodePacked(
  405. uint32(0x5054474d),
  406. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  407. Executor.ExecutorAction.Execute,
  408. uint16(3),
  409. address(executor),
  410. address(callable),
  411. uint(0),
  412. abi.encodeWithSelector(ICallable.foo.selector)
  413. );
  414. bytes memory vaa = generateVaa(
  415. uint32(block.timestamp),
  416. OWNER_CHAIN_ID,
  417. OWNER_EMITTER,
  418. 1,
  419. payload,
  420. NUM_SIGNERS
  421. );
  422. vm.expectRevert(ExecutorErrors.InvalidGovernanceTarget.selector);
  423. executor.execute(vaa);
  424. }
  425. function testIncorrectTargetAddress() public {
  426. bytes memory payload = abi.encodePacked(
  427. uint32(0x5054474d),
  428. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  429. Executor.ExecutorAction.Execute,
  430. CHAIN_ID,
  431. address(0x1),
  432. address(callable),
  433. uint(0),
  434. abi.encodeWithSelector(ICallable.foo.selector)
  435. );
  436. bytes memory vaa = generateVaa(
  437. uint32(block.timestamp),
  438. OWNER_CHAIN_ID,
  439. OWNER_EMITTER,
  440. 1,
  441. payload,
  442. NUM_SIGNERS
  443. );
  444. vm.expectRevert(ExecutorErrors.DeserializationError.selector);
  445. executor.execute(vaa);
  446. }
  447. function testIncorrectAction() public {
  448. bytes memory payload = abi.encodePacked(
  449. uint32(0x5054474d),
  450. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  451. uint8(17),
  452. CHAIN_ID,
  453. address(executor),
  454. address(callable),
  455. uint(0),
  456. abi.encodeWithSelector(ICallable.foo.selector)
  457. );
  458. bytes memory vaa = generateVaa(
  459. uint32(block.timestamp),
  460. OWNER_CHAIN_ID,
  461. OWNER_EMITTER,
  462. 1,
  463. payload,
  464. NUM_SIGNERS
  465. );
  466. vm.expectRevert();
  467. executor.execute(vaa);
  468. }
  469. function testCallReverts() public {
  470. bytes memory payload = abi.encodePacked(
  471. uint32(0x5054474d),
  472. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  473. Executor.ExecutorAction.Execute,
  474. CHAIN_ID,
  475. address(executor),
  476. address(callable),
  477. uint(0),
  478. abi.encodeWithSelector(ICallable.reverts.selector)
  479. );
  480. bytes memory vaa = generateVaa(
  481. uint32(block.timestamp),
  482. OWNER_CHAIN_ID,
  483. OWNER_EMITTER,
  484. 1,
  485. payload,
  486. NUM_SIGNERS
  487. );
  488. vm.expectRevert("call should revert");
  489. executor.execute(vaa);
  490. }
  491. function testCallToEoaReverts() public {
  492. bytes memory payload = abi.encodePacked(
  493. uint32(0x5054474d),
  494. PythGovernanceInstructions.GovernanceModule.EvmExecutor,
  495. Executor.ExecutorAction.Execute,
  496. CHAIN_ID,
  497. address(executor),
  498. address(100),
  499. uint(0),
  500. abi.encodeWithSelector(ICallable.foo.selector)
  501. );
  502. bytes memory vaa = generateVaa(
  503. uint32(block.timestamp),
  504. OWNER_CHAIN_ID,
  505. OWNER_EMITTER,
  506. 1,
  507. payload,
  508. NUM_SIGNERS
  509. );
  510. vm.expectRevert(ExecutorErrors.InvalidContractTarget.selector);
  511. executor.execute(vaa);
  512. }
  513. }
  514. interface ICallable {
  515. function foo() external;
  516. function fooPayable() external payable;
  517. function fooWithArgs(uint32 inc) external;
  518. function fooPayableWithArgs(uint32 inc) external payable;
  519. function reverts() external;
  520. function reset() external;
  521. }
  522. contract TestCallable is ICallable {
  523. uint32 public fooCount = 0;
  524. address public lastCaller = address(bytes20(0));
  525. constructor() {}
  526. function reset() external override {
  527. fooCount = 0;
  528. lastCaller = address(bytes20(0));
  529. }
  530. function foo() external override {
  531. fooCount += 1;
  532. lastCaller = msg.sender;
  533. }
  534. function fooPayable() external payable override {
  535. fooCount += 1;
  536. lastCaller = msg.sender;
  537. }
  538. function fooWithArgs(uint32 inc) external override {
  539. fooCount += inc;
  540. lastCaller = msg.sender;
  541. }
  542. function fooPayableWithArgs(uint32 inc) external payable override {
  543. fooCount += inc;
  544. lastCaller = msg.sender;
  545. }
  546. function reverts() external pure override {
  547. revert("call should revert");
  548. }
  549. }