From d02911543e8e3051cead2505fe391f2e5fb29445 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Sat, 2 Dec 2023 11:50:56 -0800 Subject: [PATCH] more executor tests --- .../contracts/forge-test/Executor.t.sol | 271 +++++++++++++++++- 1 file changed, 269 insertions(+), 2 deletions(-) diff --git a/target_chains/ethereum/contracts/forge-test/Executor.t.sol b/target_chains/ethereum/contracts/forge-test/Executor.t.sol index 91115fb88e..e2985b3b51 100644 --- a/target_chains/ethereum/contracts/forge-test/Executor.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Executor.t.sol @@ -46,7 +46,6 @@ contract ExecutorTest is Test, WormholeTestUtils { vaa = generateVaa( uint32(block.timestamp), - // TODO: make these arguments so we can do adversarial tests OWNER_CHAIN_ID, OWNER_EMITTER, sequence, @@ -57,7 +56,7 @@ contract ExecutorTest is Test, WormholeTestUtils { executor.execute(vaa); } - function testBasic() public { + function testCallSucceeds() public { callable.reset(); uint32 c = callable.fooCount(); @@ -69,16 +68,275 @@ contract ExecutorTest is Test, WormholeTestUtils { assert(address(executor) != address(this)); } + function testCallWithArgsSucceeds() public { + callable.reset(); + + uint32 c = callable.fooCount(); + assertEq(callable.lastCaller(), address(bytes20(0))); + testExecute( + address(callable), + abi.encodeCall(ICallable.fooWithArgs, (17)), + 1 + ); + assertEq(callable.fooCount(), c + 17); + assertEq(callable.lastCaller(), address(executor)); + // Sanity check to make sure the check above is meaningful. + assert(address(executor) != address(this)); + } + function testCallerAddress() public { uint32 c = callable.fooCount(); testExecute(address(callable), abi.encodeCall(ICallable.foo, ()), 1); assertEq(callable.fooCount(), c + 1); } + + function testIncorrectVaa() public { + string[5] memory forgeItems = [ + "vaaSignature", + "vaaVersion", + "vaaGuardianSetIndex", + "vaaNumSigners+", + "vaaNumSigners-" + ]; + + for (uint i = 0; i < forgeItems.length; i++) { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = forgeVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 1, + payload, + NUM_SIGNERS, + bytes(forgeItems[i]) + ); + + // ExecutorErrors.InvalidWormholeVaa.selector + vm.expectRevert(); + executor.execute(vaa); + } + } + + function testIncorrectOwnerEmitterAddress() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + bytes32(uint256(2)), + 1, + payload, + NUM_SIGNERS + ); + + vm.expectRevert(ExecutorErrors.UnauthorizedEmitter.selector); + executor.execute(vaa); + } + + function testIncorrectOwnerEmitterChainId() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + 8, + OWNER_EMITTER, + 1, + payload, + NUM_SIGNERS + ); + + vm.expectRevert(ExecutorErrors.UnauthorizedEmitter.selector); + executor.execute(vaa); + } + + function testOutOfOrder() public { + testExecute(address(callable), abi.encodeCall(ICallable.foo, ()), 3); + + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 3, + payload, + NUM_SIGNERS + ); + + vm.expectRevert(ExecutorErrors.MessageOutOfOrder.selector); + executor.execute(vaa); + + callable.reset(); + testExecute(address(callable), abi.encodeCall(ICallable.foo, ()), 4); + assertEq(callable.fooCount(), 1); + } + + function testInvalidPayload() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory shortPayload = BytesLib.slice( + payload, + 0, + payload.length - 1 + ); + bytes memory shortVaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 1, + shortPayload, + NUM_SIGNERS + ); + + vm.expectRevert(); + executor.execute(shortVaa); + } + + function testIncorrectTargetChainId() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + uint16(3), + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 1, + payload, + NUM_SIGNERS + ); + + vm.expectRevert(ExecutorErrors.InvalidGovernanceTarget.selector); + executor.execute(vaa); + } + + function testIncorrectTargetAddress() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(0x1), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 1, + payload, + NUM_SIGNERS + ); + + vm.expectRevert(ExecutorErrors.DeserializationError.selector); + executor.execute(vaa); + } + + function testIncorrectAction() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + uint8(17), + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.foo, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 1, + payload, + NUM_SIGNERS + ); + + vm.expectRevert(); + executor.execute(vaa); + } + + function testCallReverts() public { + bytes memory payload = abi.encodePacked( + uint32(0x5054474d), + PythGovernanceInstructions.GovernanceModule.EvmExecutor, + Executor.ExecutorAction.Execute, + CHAIN_ID, + address(executor), + address(callable), + abi.encodeCall(ICallable.reverts, ()) + ); + + bytes memory vaa = generateVaa( + uint32(block.timestamp), + OWNER_CHAIN_ID, + OWNER_EMITTER, + 1, + payload, + NUM_SIGNERS + ); + + vm.expectRevert("call should revert"); + executor.execute(vaa); + } } interface ICallable { function foo() external; + function fooWithArgs(uint32 inc) external; + + function reverts() external; + function reset() external; } @@ -97,4 +355,13 @@ contract TestCallable is ICallable { fooCount += 1; lastCaller = msg.sender; } + + function fooWithArgs(uint32 inc) external override { + fooCount += inc; + lastCaller = msg.sender; + } + + function reverts() external override { + revert("call should revert"); + } }