@@ -14,44 +14,28 @@ import (
14
14
"github.com/ethereum/go-ethereum/crypto"
15
15
"github.com/ethereum/go-ethereum/ethclient"
16
16
"github.com/ethereum/go-ethereum/rpc"
17
+ "github.com/stackup-wallet/stackup-bundler/pkg/tracer"
17
18
"github.com/stackup-wallet/stackup-bundler/pkg/userop"
18
19
)
19
20
20
21
var (
21
22
// A dummy private key used to build *bind.TransactOpts for simulation.
22
23
dummyPk , _ = crypto .GenerateKey ()
23
24
24
- // A marker to delimit between account and paymaster simulation .
25
- markerOpCode = "NUMBER "
25
+ // Pre number marker represents account validation .
26
+ accountNumberLevel = "0 "
26
27
27
- // Pre-marker represents account validation.
28
- preMarker = "account"
29
-
30
- // Post-marker represents paymaster validation.
31
- postMarker = "paymaster"
32
-
33
- // All opcodes executed at this depth are from the EntryPoint and allowed.
34
- allowedDepth = float64 (1 )
35
-
36
- // The gas opcode is only allowed if followed immediately by callOpcodes.
37
- gasOpCode = "GAS"
28
+ // Post number marker represents paymaster validation.
29
+ paymasterNumberLevel = "1"
38
30
39
31
// Only one create2 opcode is allowed if these two conditions are met:
40
32
// 1. op.initcode.length != 0
41
33
// 2. During account simulation (i.e. before markerOpCode)
42
34
create2OpCode = "CREATE2"
43
35
44
- // List of opcodes related to CALL.
45
- callOpcodes = mapset .NewSet (
46
- "CALL" ,
47
- "DELEGATECALL" ,
48
- "CALLCODE" ,
49
- "STATICCALL" ,
50
- )
51
-
52
- // List of opcodes not allowed during simulation for depth > allowedDepth (i.e. account, paymaster, or
53
- // contracts called by them).
54
- baseForbiddenOpCodes = mapset .NewSet (
36
+ // List of opcodes not allowed during simulation for depth > 1 (i.e. account, paymaster, or contracts
37
+ // called by them).
38
+ bannedOpCodes = mapset .NewSet (
55
39
"GASPRICE" ,
56
40
"GASLIMIT" ,
57
41
"DIFFICULTY" ,
62
46
"SELFBALANCE" ,
63
47
"BALANCE" ,
64
48
"ORIGIN" ,
49
+ "GAS" ,
65
50
"CREATE" ,
66
51
"COINBASE" ,
67
52
)
@@ -94,36 +79,25 @@ func SimulateValidation(rpc *rpc.Client, entryPoint common.Address, op *userop.U
94
79
return sim , nil
95
80
}
96
81
97
- type structLog struct {
98
- Depth float64 `json:"depth"`
99
- Gas float64 `json:"gas"`
100
- GasCost float64 `json:"gasCost"`
101
- Op string `json:"op"`
102
- Pc float64 `json:"pc"`
103
- Stack []string `json:"stack"`
104
- }
105
-
106
- type traceCallRes struct {
107
- Failed bool `json:"failed"`
108
- Gas float64 `json:"gas"`
109
- ReturnValue []byte `json:"returnValue"`
110
- StructLogs []structLog `json:"structLogs"`
111
- }
112
-
113
82
type traceCallReq struct {
114
83
From common.Address `json:"from"`
115
84
To common.Address `json:"to"`
116
85
Data hexutil.Bytes `json:"data"`
117
86
}
118
87
119
88
type traceCallOpts struct {
120
- DisableStorage bool `json:"disableStorage"`
121
- DisableMemory bool `json:"disableMemory"`
89
+ Tracer string `json:"tracer"`
122
90
}
123
91
124
92
// TraceSimulateValidation makes a debug_traceCall to Entrypoint.simulateValidation(userop) and returns the
125
93
// results without any state changes.
126
- func TraceSimulateValidation (rpc * rpc.Client , entryPoint common.Address , op * userop.UserOperation , chainID * big.Int ) error {
94
+ func TraceSimulateValidation (
95
+ rpc * rpc.Client ,
96
+ entryPoint common.Address ,
97
+ op * userop.UserOperation ,
98
+ chainID * big.Int ,
99
+ customTracer string ,
100
+ ) error {
127
101
ep , err := NewEntrypoint (entryPoint , ethclient .NewClient (rpc ))
128
102
if err != nil {
129
103
return err
@@ -139,48 +113,51 @@ func TraceSimulateValidation(rpc *rpc.Client, entryPoint common.Address, op *use
139
113
return err
140
114
}
141
115
142
- var res traceCallRes
143
116
req := traceCallReq {
144
117
From : common .HexToAddress ("0x" ),
145
118
To : entryPoint ,
146
119
Data : tx .Data (),
147
120
}
121
+
122
+ var res tracer.BundlerCollectorReturn
148
123
opts := traceCallOpts {
149
- DisableStorage : false ,
150
- DisableMemory : false ,
124
+ Tracer : customTracer ,
151
125
}
152
126
if err := rpc .CallContext (context .Background (), & res , "debug_traceCall" , & req , "latest" , & opts ); err != nil {
153
127
return err
154
128
}
155
129
156
- var prev structLog
157
- create2count := 0
158
- simFor := preMarker
159
- for _ , sl := range res . StructLogs {
160
- if sl . Depth == allowedDepth {
161
- if sl . Op == markerOpCode {
162
- simFor = postMarker
163
- }
164
- continue
165
- }
130
+ var accountOpCodes , paymasterOpCodes tracer. Counts
131
+ if len ( res . NumberLevels ) == 1 {
132
+ accountOpCodes = res . NumberLevels [ accountNumberLevel ]. Opcodes
133
+ paymasterOpCodes = make (tracer. Counts )
134
+ } else if len ( res . NumberLevels ) == 2 {
135
+ accountOpCodes = res . NumberLevels [ accountNumberLevel ]. Opcodes
136
+ paymasterOpCodes = res . NumberLevels [ paymasterNumberLevel ]. Opcodes
137
+ } else {
138
+ return fmt . Errorf ( "unexpected tracing result for op: %s" , op . GetUserOpHash ( entryPoint , chainID ))
139
+ }
166
140
167
- if prev .Op == gasOpCode && ! callOpcodes .Contains (sl .Op ) {
168
- return fmt .Errorf ("%s: uses opcode %s incorrectly" , simFor , gasOpCode )
141
+ for key := range accountOpCodes {
142
+ if bannedOpCodes .Contains (key ) {
143
+ return fmt .Errorf ("account contains banned opcode: %s" , key )
169
144
}
145
+ }
170
146
171
- if sl .Op == create2OpCode {
172
- create2count ++
173
-
174
- if create2count > 1 || len (op .InitCode ) == 0 || simFor != preMarker {
175
- return fmt .Errorf ("%s: uses opcode %s incorrectly" , simFor , sl .Op )
176
- }
147
+ for key := range paymasterOpCodes {
148
+ if bannedOpCodes .Contains (key ) {
149
+ return fmt .Errorf ("paymaster contains banned opcode: %s" , key )
177
150
}
151
+ }
178
152
179
- if baseForbiddenOpCodes .Contains (sl .Op ) {
180
- return fmt .Errorf ("%s: uses forbidden opcode %s" , simFor , sl .Op )
181
- }
153
+ create2Count , ok := accountOpCodes [create2OpCode ]
154
+ if ok && (create2Count > 1 || len (op .InitCode ) == 0 ) {
155
+ return fmt .Errorf ("account with too many %s" , create2OpCode )
156
+ }
182
157
183
- prev = sl
158
+ _ , ok = paymasterOpCodes [create2OpCode ]
159
+ if ok {
160
+ return fmt .Errorf ("paymaster uses banned %s opcode: %s" , create2OpCode , op .GetPaymaster ())
184
161
}
185
162
186
163
return nil
0 commit comments