Skip to content
This repository was archived by the owner on Oct 20, 2024. It is now read-only.

Commit f268ce1

Browse files
authored
Fine tune fallback binary search for reliability (#261)
1 parent 0698fc4 commit f268ce1

File tree

5 files changed

+79
-27
lines changed

5 files changed

+79
-27
lines changed

e2e/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const config: IConfig = {
1414
bundlerUrl: "http://localhost:4337",
1515
testERC20Token: "0x3870419Ba2BBf0127060bCB37f69A1b1C090992B",
1616
// https://github.com/stackup-wallet/contracts/blob/main/contracts/test/TestGas.sol
17-
testGas: "0xdea3d7b717F3A6E634876092470efc281f9b3de7",
17+
testGas: "0xc2e76Ee793a194Dd930C18c4cDeC93E7C75d567C",
1818
};
1919

2020
export default config;

e2e/test/withoutPaymaster.test.ts

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -207,28 +207,33 @@ describe("Without Paymaster", () => {
207207
});
208208
});
209209

210-
describe("With gas discount", () => {
211-
const depth = 3;
212-
[15000, 20000, 25000, 30000, 35000].forEach((discount) => {
213-
test(`Sender can make contract interactions with ${discount} gas discount to recursive calls`, async () => {
214-
const response = await client.sendUserOperation(
215-
acc.execute(
216-
config.testGas,
217-
0,
218-
testGas.interface.encodeFunctionData("recursiveCall", [
219-
depth,
220-
0,
221-
discount,
222-
depth,
223-
])
224-
),
225-
opChecks(provider)
226-
);
227-
const event = await response.wait();
210+
describe("With random gas discount", () => {
211+
[1, 2, 3].forEach((depth) =>
212+
describe(`At depth equal to ${depth}`, () => {
213+
Array.from({ length: 5 }, () =>
214+
Math.floor(Math.random() * 100000)
215+
).forEach((discount) => {
216+
test(`Sender can make contract interactions with ${discount} gas discount to recursive calls`, async () => {
217+
const response = await client.sendUserOperation(
218+
acc.execute(
219+
config.testGas,
220+
0,
221+
testGas.interface.encodeFunctionData("recursiveCall", [
222+
depth,
223+
0,
224+
discount,
225+
depth,
226+
])
227+
),
228+
opChecks(provider)
229+
);
230+
const event = await response.wait();
228231

229-
expect(event?.args.success).toBe(true);
230-
});
231-
});
232+
expect(event?.args.success).toBe(true);
233+
});
234+
});
235+
})
236+
);
232237
});
233238

234239
describe("With multiple stacks per depth", () => {

pkg/entrypoint/execution/trace.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,18 @@ func TraceSimulateHandleOp(in *TraceInput) (*TraceOutput, error) {
128128
return out, errors.NewRPCError(errors.EXECUTION_REVERTED, "execution reverted", nil)
129129
}
130130

131-
reason, err := errors.DecodeRevert(data)
132-
if err != nil {
133-
return out, err
131+
reason, revErr := errors.DecodeRevert(data)
132+
if revErr != nil {
133+
code, panErr := errors.DecodePanic(data)
134+
if panErr != nil {
135+
return nil, fmt.Errorf("%s, %s", revErr, panErr)
136+
}
137+
138+
return out, errors.NewRPCError(
139+
errors.EXECUTION_REVERTED,
140+
fmt.Sprintf("panic encountered: %s", code),
141+
code,
142+
)
134143
}
135144
return out, errors.NewRPCError(errors.EXECUTION_REVERTED, reason, reason)
136145
}

pkg/errors/panic.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package errors
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"math/big"
7+
8+
"github.com/ethereum/go-ethereum/accounts/abi"
9+
"github.com/ethereum/go-ethereum/common/hexutil"
10+
)
11+
12+
func panicError() abi.Error {
13+
code, _ := abi.NewType("uint256", "uint256", nil)
14+
return abi.NewError("Panic", abi.Arguments{
15+
{Name: "code", Type: code},
16+
})
17+
}
18+
19+
func DecodePanic(data []byte) (string, error) {
20+
abi := panicError()
21+
panic, err := abi.Unpack(data)
22+
if err != nil {
23+
return "", fmt.Errorf("panic: %s", err)
24+
}
25+
26+
args, ok := panic.([]any)
27+
if !ok {
28+
return "", errors.New("panic: cannot assert type: args is not of type []any")
29+
}
30+
if len(args) != 1 {
31+
return "", fmt.Errorf("panic: invalid args length: expected 1, got %d", len(args))
32+
}
33+
34+
return hexutil.EncodeBig(args[0].(*big.Int)), nil
35+
}

pkg/gas/estimate.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,9 @@ func EstimateGas(in *EstimateInput) (verificationGas uint64, callGas uint64, err
156156
// Execution is successful but one shot tracing has failed. Fallback to binary search with an
157157
// efficient range. Hitting this point could mean a contract is passing manual gas limits with a
158158
// static discount, e.g. sub(gas(), STATIC_DISCOUNT). This is not yet accounted for in the tracer.
159-
if isExecutionOOG(err) {
159+
if isExecutionOOG(err) || isExecutionReverted(err) {
160160
l := cgl.Int64()
161-
r := (l * 150) / 100 // Set upper bound to +50%
161+
r := in.MaxGasLimit.Int64()
162162
f := int64(0)
163163
simErr := err
164164
for r-l >= fallBackBinarySearchCutoff {
@@ -180,6 +180,9 @@ func EstimateGas(in *EstimateInput) (verificationGas uint64, callGas uint64, err
180180
// CGL too low, go higher.
181181
l = m + 1
182182
continue
183+
} else if err != nil && isPrefundNotPaid(err) {
184+
// CGL too high, go lower.
185+
r = m - 1
183186
} else if err == nil {
184187
// CGL too high, go lower.
185188
r = m - 1

0 commit comments

Comments
 (0)