Skip to content

Commit af5a47f

Browse files
dvushavalonche
authored andcommitted
sim bundles in parallel (new merger) (ethereum#33)
* sim bundles in parallel * add cache for failed bundles too
1 parent 6d4f8a6 commit af5a47f

File tree

2 files changed

+93
-20
lines changed

2 files changed

+93
-20
lines changed

miner/worker.go

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ type worker struct {
253253

254254
bundleCacheMu sync.Mutex
255255
bundleCacheHeaderHash common.Hash
256-
bundleCache map[common.Hash]simulatedBundle
256+
bundleCacheSuccess map[common.Hash]simulatedBundle
257+
bundleCacheFailed map[common.Hash]struct{}
257258

258259
snapshotMu sync.RWMutex // The lock used to protect the snapshots below
259260
snapshotBlock *types.Block
@@ -370,7 +371,8 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
370371
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
371372
coinbase: builderCoinbase,
372373
flashbots: flashbots,
373-
bundleCache: make(map[common.Hash]simulatedBundle),
374+
bundleCacheSuccess: make(map[common.Hash]simulatedBundle),
375+
bundleCacheFailed: make(map[common.Hash]struct{}),
374376
}
375377

376378
// Subscribe NewTxsEvent for tx pool
@@ -1739,38 +1741,61 @@ func (w *worker) simulateBundles(env *environment, bundles []types.MevBundle, pe
17391741
w.bundleCacheMu.Lock()
17401742
defer w.bundleCacheMu.Unlock()
17411743

1742-
simulatedBundles := []simulatedBundle{}
1743-
1744-
var bundleCache map[common.Hash]simulatedBundle
1744+
var cacheSuccess map[common.Hash]simulatedBundle
1745+
var cacheFailed map[common.Hash]struct{}
17451746
if w.bundleCacheHeaderHash == env.header.Hash() {
1746-
bundleCache = w.bundleCache
1747+
cacheSuccess = w.bundleCacheSuccess
1748+
cacheFailed = w.bundleCacheFailed
17471749
} else {
1748-
bundleCache = make(map[common.Hash]simulatedBundle)
1750+
cacheSuccess = make(map[common.Hash]simulatedBundle)
1751+
cacheFailed = make(map[common.Hash]struct{})
17491752
}
17501753

1751-
for _, bundle := range bundles {
1752-
if simmed, ok := bundleCache[bundle.Hash]; ok {
1753-
simulatedBundles = append(simulatedBundles, simmed)
1754+
simResult := make([]*simulatedBundle, len(bundles))
1755+
1756+
var wg sync.WaitGroup
1757+
for i, bundle := range bundles {
1758+
if simmed, ok := cacheSuccess[bundle.Hash]; ok {
1759+
simResult[i] = &simmed
17541760
continue
17551761
}
17561762

1757-
if len(bundle.Txs) == 0 {
1763+
if _, ok := cacheFailed[bundle.Hash]; ok {
17581764
continue
17591765
}
1760-
state := env.state.Copy()
1761-
gasPool := new(core.GasPool).AddGas(env.header.GasLimit)
1762-
simmed, err := w.computeBundleGas(env, bundle, state, gasPool, pendingTxs, 0)
17631766

1764-
if err != nil {
1765-
log.Debug("Error computing gas for a bundle", "error", err)
1766-
continue
1767+
wg.Add(1)
1768+
go func(idx int, bundle types.MevBundle, state *state.StateDB) {
1769+
defer wg.Done()
1770+
if len(bundle.Txs) == 0 {
1771+
return
1772+
}
1773+
gasPool := new(core.GasPool).AddGas(env.header.GasLimit)
1774+
simmed, err := w.computeBundleGas(env, bundle, state, gasPool, pendingTxs, 0)
1775+
1776+
if err != nil {
1777+
log.Debug("Error computing gas for a bundle", "error", err)
1778+
return
1779+
}
1780+
simResult[idx] = &simmed
1781+
}(i, bundle, env.state.Copy())
1782+
}
1783+
1784+
wg.Wait()
1785+
1786+
simulatedBundles := make([]simulatedBundle, 0, len(bundles))
1787+
for i, bundle := range simResult {
1788+
if bundle != nil {
1789+
simulatedBundles = append(simulatedBundles, *bundle)
1790+
cacheSuccess[bundle.OriginalBundle.Hash] = *bundle
1791+
} else {
1792+
cacheFailed[bundles[i].Hash] = struct{}{}
17671793
}
1768-
bundleCache[bundle.Hash] = simmed
1769-
simulatedBundles = append(simulatedBundles, simmed)
17701794
}
17711795

17721796
w.bundleCacheHeaderHash = env.header.Hash()
1773-
w.bundleCache = bundleCache
1797+
w.bundleCacheSuccess = cacheSuccess
1798+
w.bundleCacheFailed = cacheFailed
17741799

17751800
return simulatedBundles, nil
17761801
}

miner/worker_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,3 +669,51 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
669669
}
670670
}
671671
}
672+
673+
func TestSimulateBundles(t *testing.T) {
674+
w, _ := newTestWorker(t, ethashChainConfig, ethash.NewFaker(), rawdb.NewMemoryDatabase(), 0)
675+
defer w.close()
676+
677+
env, err := w.prepareWork(&generateParams{gasLimit: 30000000})
678+
if err != nil {
679+
t.Fatalf("Failed to prepare work: %s", err)
680+
}
681+
682+
signTx := func(nonce uint64) *types.Transaction {
683+
tx, err := types.SignTx(types.NewTransaction(nonce, testUserAddress, big.NewInt(1000), params.TxGas, env.header.BaseFee, nil), types.HomesteadSigner{}, testBankKey)
684+
if err != nil {
685+
t.Fatalf("Failed to sign tx")
686+
}
687+
return tx
688+
}
689+
690+
bundle1 := types.MevBundle{Txs: types.Transactions{signTx(0)}, Hash: common.HexToHash("0x01")}
691+
// this bundle will fail
692+
bundle2 := types.MevBundle{Txs: types.Transactions{signTx(1)}, Hash: common.HexToHash("0x02")}
693+
bundle3 := types.MevBundle{Txs: types.Transactions{signTx(0)}, Hash: common.HexToHash("0x03")}
694+
695+
simBundles, err := w.simulateBundles(env, []types.MevBundle{bundle1, bundle2, bundle3}, nil)
696+
697+
if len(simBundles) != 2 {
698+
t.Fatalf("Incorrect amount of sim bundles")
699+
}
700+
701+
for _, simBundle := range simBundles {
702+
if simBundle.OriginalBundle.Hash == common.HexToHash("0x02") {
703+
t.Fatalf("bundle2 should fail")
704+
}
705+
}
706+
707+
// simulate 2 times to check cache
708+
simBundles, err = w.simulateBundles(env, []types.MevBundle{bundle1, bundle2, bundle3}, nil)
709+
710+
if len(simBundles) != 2 {
711+
t.Fatalf("Incorrect amount of sim bundles(cache)")
712+
}
713+
714+
for _, simBundle := range simBundles {
715+
if simBundle.OriginalBundle.Hash == common.HexToHash("0x02") {
716+
t.Fatalf("bundle2 should fail(cache)")
717+
}
718+
}
719+
}

0 commit comments

Comments
 (0)