Skip to content

Commit

Permalink
AA-159 prevent recursive call into handleOps (#257)
Browse files Browse the repository at this point in the history
* AA-159 prevent recursive call into handleOps
* added BeforeExecution event
  without this event, all events in validation are attributed to the first UserOperation.
  We can't attribute them to specific UseROp (unless there is exactly one) - but at least not always assign the to the first.
  • Loading branch information
drortirosh authored Apr 9, 2023
1 parent 19918cd commit 9b5f2e4
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 16 deletions.
10 changes: 7 additions & 3 deletions contracts/core/EntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import "./StakeManager.sol";
import "./SenderCreator.sol";
import "./Helpers.sol";
import "./NonceManager.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract EntryPoint is IEntryPoint, StakeManager, NonceManager {
contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard {

using UserOperationLib for UserOperation;

Expand Down Expand Up @@ -88,7 +89,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager {
* @param ops the operations to execute
* @param beneficiary the address to receive the fees
*/
function handleOps(UserOperation[] calldata ops, address payable beneficiary) public {
function handleOps(UserOperation[] calldata ops, address payable beneficiary) public nonReentrant {

This comment has been minimized.

Copy link
@Gooong

Gooong Apr 10, 2023

@drortirosh I think also need to add nonReentrant in simulateHandleOp?


uint256 opslen = ops.length;
UserOpInfo[] memory opInfos = new UserOpInfo[](opslen);
Expand All @@ -101,6 +102,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager {
}

uint256 collected = 0;
emit BeforeExecution();

for (uint256 i = 0; i < opslen; i++) {
collected += _executeUserOp(i, ops[i], opInfos[i]);
Expand All @@ -118,7 +120,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager {
function handleAggregatedOps(
UserOpsPerAggregator[] calldata opsPerAggregator,
address payable beneficiary
) public {
) public nonReentrant {

uint256 opasLen = opsPerAggregator.length;
uint256 totalOps = 0;
Expand All @@ -143,6 +145,8 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager {

UserOpInfo[] memory opInfos = new UserOpInfo[](totalOps);

emit BeforeExecution();

uint256 opIndex = 0;
for (uint256 a = 0; a < opasLen; a++) {
UserOpsPerAggregator calldata opa = opsPerAggregator[a];
Expand Down
6 changes: 6 additions & 0 deletions contracts/interfaces/IEntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ interface IEntryPoint is IStakeManager, INonceManager {
*/
event UserOperationRevertReason(bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason);

/**
* an event emitted by handleOps(), before starting the execution loop.
* any event emitted before this event, is part of the validation.
*/
event BeforeExecution();

/**
* signature aggregator used by the following UserOperationEvents within this bundle.
*/
Expand Down
24 changes: 12 additions & 12 deletions reports/gas-checker.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@
β•‘ β”‚ β”‚ β”‚ (delta for β”‚ (compared to β•‘
β•‘ β”‚ β”‚ β”‚ one UserOp) β”‚ account.exec()) β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple β”‚ 1 β”‚ 78743 β”‚ β”‚ β•‘
β•‘ simple β”‚ 1 β”‚ 81901 β”‚ β”‚ β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple - diff from previous β”‚ 2 β”‚ β”‚ 44162 β”‚ 15148 β•‘
β•‘ simple - diff from previous β”‚ 2 β”‚ β”‚ 44212 β”‚ 15198 β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple β”‚ 10 β”‚ 476282 β”‚ β”‚ β•‘
β•‘ simple β”‚ 10 β”‚ 479854 β”‚ β”‚ β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple - diff from previous β”‚ 11 β”‚ β”‚ 44174 β”‚ 15160 β•‘
β•‘ simple - diff from previous β”‚ 11 β”‚ β”‚ 44236 β”‚ 15222 β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple paymaster β”‚ 1 β”‚ 85002 β”‚ β”‚ β•‘
β•‘ simple paymaster β”‚ 1 β”‚ 88172 β”‚ β”‚ β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple paymaster with diff β”‚ 2 β”‚ β”‚ 43139 β”‚ 14125 β•‘
β•‘ simple paymaster with diff β”‚ 2 β”‚ β”‚ 43165 β”‚ 14151 β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple paymaster β”‚ 10 β”‚ 473554 β”‚ β”‚ β•‘
β•‘ simple paymaster β”‚ 10 β”‚ 476994 β”‚ β”‚ β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ simple paymaster with diff β”‚ 11 β”‚ β”‚ 43150 β”‚ 14136 β•‘
β•‘ simple paymaster with diff β”‚ 11 β”‚ β”‚ 43260 β”‚ 14246 β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ big tx 5k β”‚ 1 β”‚ 179788 β”‚ β”‚ β•‘
β•‘ big tx 5k β”‚ 1 β”‚ 182958 β”‚ β”‚ β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ big tx - diff from previous β”‚ 2 β”‚ β”‚ 144673 β”‚ 19413 β•‘
β•‘ big tx - diff from previous β”‚ 2 β”‚ β”‚ 144723 β”‚ 19463 β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ big tx 5k β”‚ 10 β”‚ 1481914 β”‚ β”‚ β•‘
β•‘ big tx 5k β”‚ 10 β”‚ 1485438 β”‚ β”‚ β•‘
β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•’
β•‘ big tx - diff from previous β”‚ 11 β”‚ β”‚ 144698 β”‚ 19438 β•‘
β•‘ big tx - diff from previous β”‚ 11 β”‚ β”‚ 144712 β”‚ 19452 β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

19 changes: 18 additions & 1 deletion test/entrypoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
simulationResultCatch,
createAccount,
getAggregatedAccountInitCode,
simulationResultWithAggregationCatch
simulationResultWithAggregationCatch, decodeRevertReason
} from './testutils'
import { DefaultsForUserOp, fillAndSign, getUserOpHash } from './UserOp'
import { UserOperation } from './UserOperation'
Expand Down Expand Up @@ -783,6 +783,23 @@ describe('EntryPoint', function () {
await calcGasUsage(rcpt, entryPoint, beneficiaryAddress)
})

it('should fail to call recursively into handleOps', async () => {
const beneficiaryAddress = createAddress()

const callHandleOps = entryPoint.interface.encodeFunctionData('handleOps', [[], beneficiaryAddress])
const execHandlePost = account.interface.encodeFunctionData('execute', [entryPoint.address, 0, callHandleOps])
const op = await fillAndSign({
sender: account.address,
callData: execHandlePost
}, accountOwner, entryPoint)

const rcpt = await entryPoint.handleOps([op], beneficiaryAddress, {
gasLimit: 1e7
}).then(async r => r.wait())

const error = rcpt.events?.find(ev => ev.event === 'UserOperationRevertReason')
expect(decodeRevertReason(error?.args?.revertReason)).to.eql('Error(ReentrancyGuard: reentrant call)', 'execution of handleOps inside a UserOp should revert')
})
it('should report failure on insufficient verificationGas after creation', async () => {
const op0 = await fillAndSign({
sender: account.address,
Expand Down

0 comments on commit 9b5f2e4

Please sign in to comment.