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

Commit 1bd51ab

Browse files
authored
Check for codehash changes since first simulation (#99)
1 parent 059f533 commit 1bd51ab

39 files changed

+602
-308
lines changed

abi/entrypoint.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,16 @@
425425
"stateMutability": "view",
426426
"type": "function"
427427
},
428+
{
429+
"inputs": [
430+
{ "internalType": "address", "name": "sender", "type": "address" },
431+
{ "internalType": "address", "name": "paymaster", "type": "address" }
432+
],
433+
"name": "_simulateFindAggregator",
434+
"outputs": [],
435+
"stateMutability": "view",
436+
"type": "function"
437+
},
428438
{
429439
"inputs": [
430440
{ "internalType": "uint32", "name": "_unstakeDelaySec", "type": "uint32" }

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/go-logr/zerologr v1.2.2
1313
github.com/go-playground/validator/v10 v10.11.1
1414
github.com/google/go-cmp v0.5.9
15+
github.com/google/uuid v1.2.0
1516
github.com/metachris/flashbotsrpc v0.5.0
1617
github.com/mitchellh/mapstructure v1.5.0
1718
github.com/rs/zerolog v1.28.0
@@ -45,7 +46,6 @@ require (
4546
github.com/golang/protobuf v1.5.2 // indirect
4647
github.com/golang/snappy v0.0.4 // indirect
4748
github.com/google/flatbuffers v1.12.1 // indirect
48-
github.com/google/uuid v1.2.0 // indirect
4949
github.com/gorilla/websocket v1.4.2 // indirect
5050
github.com/hashicorp/hcl v1.0.0 // indirect
5151
github.com/inconshreveable/mousetrap v1.0.1 // indirect

internal/config/values.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func GetValues() *Values {
5353
// Default variables
5454
viper.SetDefault("erc4337_bundler_port", 4337)
5555
viper.SetDefault("erc4337_bundler_data_directory", "/tmp/stackup_bundler")
56-
viper.SetDefault("erc4337_bundler_supported_entry_points", "0x0F46c65C17AA6b4102046935F33301f0510B163A")
56+
viper.SetDefault("erc4337_bundler_supported_entry_points", "0xCEb7363Cc430D6332D341f5BabBF00dD5f4Ba119")
5757
viper.SetDefault("erc4337_bundler_max_verification_gas", 1500000)
5858
viper.SetDefault("erc4337_bundler_max_ops_for_unstaked_sender", 4)
5959
viper.SetDefault("erc4337_bundler_blocks_in_the_future", 25)

internal/dbutils/utils.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package dbutils
2+
3+
import "strings"
4+
5+
const separator = ":"
6+
7+
func JoinValues(values ...string) string {
8+
return strings.Join(values, separator)
9+
}
10+
11+
func SplitValues(value string) []string {
12+
return strings.Split(value, separator)
13+
}

internal/start/private.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func PrivateMode() {
6262
}
6363

6464
check := checks.New(
65+
db,
6566
rpc,
6667
conf.MaxVerificationGas,
6768
conf.MaxOpsForUnstakedSender,
@@ -88,9 +89,11 @@ func PrivateMode() {
8889
b := bundler.New(mem, chain, conf.SupportedEntryPoints)
8990
b.UseLogger(logr)
9091
b.UseModules(
92+
check.CodeHashes(),
9193
check.PaymasterDeposit(),
9294
relayer.SendUserOperation(),
9395
paymaster.IncOpsIncluded(),
96+
check.Clean(),
9497
)
9598
if err := b.Run(); err != nil {
9699
log.Fatal(err)
@@ -100,6 +103,7 @@ func PrivateMode() {
100103
var d *client.Debug
101104
if conf.DebugMode {
102105
d = client.NewDebug(eoa, eth, mem, b, chain, conf.SupportedEntryPoints[0], beneficiary)
106+
b.SetMaxBatch(1)
103107
relayer.SetBannedThreshold(relay.NoBanThreshold)
104108
}
105109

internal/start/searcher.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func SearcherMode() {
7171
}
7272

7373
check := checks.New(
74+
db,
7475
rpc,
7576
conf.MaxVerificationGas,
7677
conf.MaxOpsForUnstakedSender,
@@ -99,9 +100,11 @@ func SearcherMode() {
99100
b := bundler.New(mem, chain, conf.SupportedEntryPoints)
100101
b.UseLogger(logr)
101102
b.UseModules(
103+
check.CodeHashes(),
102104
check.PaymasterDeposit(),
103105
builder.SendUserOperation(),
104106
paymaster.IncOpsIncluded(),
107+
check.Clean(),
105108
)
106109
if err := b.Run(); err != nil {
107110
log.Fatal(err)
@@ -111,6 +114,7 @@ func SearcherMode() {
111114
var d *client.Debug
112115
if conf.DebugMode {
113116
d = client.NewDebug(eoa, eth, mem, b, chain, conf.SupportedEntryPoints[0], beneficiary)
117+
b.SetMaxBatch(1)
114118
}
115119

116120
// Init HTTP server

pkg/bundler/bundler.go

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type Bundler struct {
2626
stop chan bool
2727
watch chan bool
2828
onStop func()
29+
maxBatch int
2930
}
3031

3132
// New initializes a new EIP-4337 bundler which can be extended with modules for validating batches and
@@ -41,9 +42,15 @@ func New(mempool *mempool.Mempool, chainID *big.Int, supportedEntryPoints []comm
4142
stop: make(chan bool),
4243
watch: make(chan bool),
4344
onStop: func() {},
45+
maxBatch: 0,
4446
}
4547
}
4648

49+
// SetMaxBatch defines the max number of UserOperations per bundle. The default value is 0 (i.e. unlimited).
50+
func (i *Bundler) SetMaxBatch(max int) {
51+
i.maxBatch = max
52+
}
53+
4754
// UseLogger defines the logger object used by the Bundler instance based on the go-logr/logr interface.
4855
func (i *Bundler) UseLogger(logger logr.Logger) {
4956
i.logger = logger.WithName("bundler")
@@ -54,65 +61,75 @@ func (i *Bundler) UseModules(handlers ...modules.BatchHandlerFunc) {
5461
i.batchHandler = modules.ComposeBatchHandlerFunc(handlers...)
5562
}
5663

64+
// Process will create a batch from the mempool and send it through to the EntryPoint.
65+
func (i *Bundler) Process(ep common.Address) (*modules.BatchHandlerCtx, error) {
66+
start := time.Now()
67+
l := i.logger.
68+
WithName("run").
69+
WithValues("entrypoint", ep.String()).
70+
WithValues("chain_id", i.chainID.String())
71+
72+
batch, err := i.mempool.BundleOps(ep)
73+
if err != nil {
74+
l.Error(err, "bundler run error")
75+
return nil, err
76+
}
77+
if len(batch) == 0 {
78+
return nil, nil
79+
}
80+
batch = adjustBatchSize(i.maxBatch, batch)
81+
82+
ctx := modules.NewBatchHandlerContext(batch, ep, i.chainID)
83+
if err := i.batchHandler(ctx); err != nil {
84+
l.Error(err, "bundler run error")
85+
return nil, err
86+
}
87+
88+
rmOps := append([]*userop.UserOperation{}, ctx.Batch...)
89+
rmOps = append(rmOps, ctx.PendingRemoval...)
90+
if err := i.mempool.RemoveOps(ep, rmOps...); err != nil {
91+
l.Error(err, "bundler run error")
92+
return nil, err
93+
}
94+
95+
bat := []string{}
96+
for _, op := range ctx.Batch {
97+
bat = append(bat, op.GetUserOpHash(ep, i.chainID).String())
98+
}
99+
l = l.WithValues("batch_userop_hashes", bat)
100+
101+
drp := []string{}
102+
for _, op := range ctx.PendingRemoval {
103+
drp = append(drp, op.GetUserOpHash(ep, i.chainID).String())
104+
}
105+
l = l.WithValues("dropped_userop_hashes", drp)
106+
107+
for k, v := range ctx.Data {
108+
l = l.WithValues(k, v)
109+
}
110+
l = l.WithValues("duration", time.Since(start))
111+
l.Info("bundler run ok")
112+
return ctx, nil
113+
}
114+
57115
// Run starts a goroutine that will continuously process batches from the mempool.
58116
func (i *Bundler) Run() error {
59117
if i.isRunning {
60118
return nil
61119
}
62120

63121
go func(i *Bundler) {
64-
logger := i.logger.WithName("run")
65-
66122
for {
67123
select {
68124
case <-i.stop:
69125
return
70126
case <-i.watch:
71127
for _, ep := range i.supportedEntryPoints {
72-
start := time.Now()
73-
l := logger.
74-
WithValues("entrypoint", ep.String()).
75-
WithValues("chain_id", i.chainID.String())
76-
77-
batch, err := i.mempool.BundleOps(ep)
128+
_, err := i.Process(ep)
78129
if err != nil {
79-
l.Error(err, "bundler run error")
80-
continue
81-
}
82-
if len(batch) == 0 {
83-
continue
84-
}
85-
86-
ctx := modules.NewBatchHandlerContext(batch, ep, i.chainID)
87-
if err := i.batchHandler(ctx); err != nil {
88-
l.Error(err, "bundler run error")
89-
continue
90-
}
91-
92-
rmOps := append([]*userop.UserOperation{}, ctx.Batch...)
93-
rmOps = append(rmOps, ctx.PendingRemoval...)
94-
if err := i.mempool.RemoveOps(ep, rmOps...); err != nil {
95-
l.Error(err, "bundler run error")
130+
// Already logged.
96131
continue
97132
}
98-
99-
bat := []string{}
100-
for _, op := range ctx.Batch {
101-
bat = append(bat, op.GetUserOpHash(ep, i.chainID).String())
102-
}
103-
l = l.WithValues("batch_userop_hashes", bat)
104-
105-
drp := []string{}
106-
for _, op := range ctx.PendingRemoval {
107-
drp = append(drp, op.GetUserOpHash(ep, i.chainID).String())
108-
}
109-
l = l.WithValues("dropped_userop_hashes", drp)
110-
111-
for k, v := range ctx.Data {
112-
l = l.WithValues(k, v)
113-
}
114-
l = l.WithValues("duration", time.Since(start))
115-
l.Info("bundler run ok")
116133
}
117134
}
118135
}

pkg/bundler/utils.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package bundler
2+
3+
import "github.com/stackup-wallet/stackup-bundler/pkg/userop"
4+
5+
func adjustBatchSize(max int, batch []*userop.UserOperation) []*userop.UserOperation {
6+
if len(batch) > max && max > 0 {
7+
return batch[:max]
8+
}
9+
return batch
10+
}

pkg/client/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/ethereum/go-ethereum/common/hexutil"
1010
"github.com/go-logr/logr"
1111
"github.com/stackup-wallet/stackup-bundler/internal/logger"
12-
"github.com/stackup-wallet/stackup-bundler/pkg/entrypoint"
12+
"github.com/stackup-wallet/stackup-bundler/pkg/entrypoint/filter"
1313
"github.com/stackup-wallet/stackup-bundler/pkg/gas"
1414
"github.com/stackup-wallet/stackup-bundler/pkg/mempool"
1515
"github.com/stackup-wallet/stackup-bundler/pkg/modules"
@@ -193,7 +193,7 @@ func (i *Client) EstimateUserOperationGas(op map[string]any, ep string) (*gas.Ga
193193
// *Client.SendUserOperation.
194194
func (i *Client) GetUserOperationReceipt(
195195
hash string,
196-
) (*entrypoint.UserOperationReceipt, error) {
196+
) (*filter.UserOperationReceipt, error) {
197197
// Init logger
198198
l := i.logger.WithName("eth_getUserOperationReceipt").WithValues("userop_hash", hash)
199199

@@ -209,7 +209,7 @@ func (i *Client) GetUserOperationReceipt(
209209

210210
// GetUserOperationByHash returns a UserOperation based on a given userOpHash returned by
211211
// *Client.SendUserOperation.
212-
func (i *Client) GetUserOperationByHash(hash string) (*entrypoint.HashLookupResult, error) {
212+
func (i *Client) GetUserOperationByHash(hash string) (*filter.HashLookupResult, error) {
213213
// Init logger
214214
l := i.logger.WithName("eth_getUserOperationByHash").WithValues("userop_hash", hash)
215215

pkg/client/debug.go

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/ethereum/go-ethereum/common"
1010
"github.com/ethereum/go-ethereum/ethclient"
1111
"github.com/stackup-wallet/stackup-bundler/pkg/bundler"
12-
"github.com/stackup-wallet/stackup-bundler/pkg/entrypoint"
1312
"github.com/stackup-wallet/stackup-bundler/pkg/mempool"
1413
"github.com/stackup-wallet/stackup-bundler/pkg/signer"
1514
)
@@ -73,48 +72,19 @@ func (d *Debug) DumpMempool(ep string) ([]map[string]any, error) {
7372

7473
// SendBundleNow forces the bundler to build and execute a bundle from the mempool as handleOps() transaction.
7574
func (d *Debug) SendBundleNow() (string, error) {
76-
batch, err := d.mempool.BundleOps(d.entrypoint)
75+
ctx, err := d.bundler.Process(d.entrypoint)
7776
if err != nil {
7877
return "", err
7978
}
80-
if len(batch) > 1 {
81-
batch = batch[:1]
79+
if ctx == nil {
80+
return "", nil
8281
}
8382

84-
est, revert, err := entrypoint.EstimateHandleOpsGas(
85-
d.eoa,
86-
d.eth,
87-
d.chainID,
88-
d.entrypoint,
89-
batch,
90-
d.beneficiary,
91-
)
92-
if err != nil {
93-
return "", err
94-
} else if revert != nil {
95-
return "", errors.New("debug: bad batch during estimate")
96-
}
97-
98-
txn, revert, err := entrypoint.HandleOps(
99-
d.eoa,
100-
d.eth,
101-
d.chainID,
102-
d.entrypoint,
103-
batch,
104-
d.beneficiary,
105-
est,
106-
)
107-
if err != nil {
108-
return "", err
109-
} else if revert != nil {
110-
return "", errors.New("debug: bad batch during call")
83+
hash, ok := ctx.Data["txn_hash"].(string)
84+
if !ok {
85+
return "", errors.New("txn_hash not in ctx Data")
11186
}
112-
113-
if err := d.mempool.RemoveOps(d.entrypoint, batch...); err != nil {
114-
return "", err
115-
}
116-
117-
return txn.Hash().String(), nil
87+
return hash, nil
11888
}
11989

12090
// SetBundlingMode allows the bundler to be stopped so that an explicit call to debug_bundler_sendBundleNow is

0 commit comments

Comments
 (0)