Skip to content

Commit cd802d6

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 b8d301e commit cd802d6

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
@@ -1740,38 +1742,61 @@ func (w *worker) simulateBundles(env *environment, bundles []types.MevBundle, pe
17401742
w.bundleCacheMu.Lock()
17411743
defer w.bundleCacheMu.Unlock()
17421744

1743-
simulatedBundles := []simulatedBundle{}
1744-
1745-
var bundleCache map[common.Hash]simulatedBundle
1745+
var cacheSuccess map[common.Hash]simulatedBundle
1746+
var cacheFailed map[common.Hash]struct{}
17461747
if w.bundleCacheHeaderHash == env.header.Hash() {
1747-
bundleCache = w.bundleCache
1748+
cacheSuccess = w.bundleCacheSuccess
1749+
cacheFailed = w.bundleCacheFailed
17481750
} else {
1749-
bundleCache = make(map[common.Hash]simulatedBundle)
1751+
cacheSuccess = make(map[common.Hash]simulatedBundle)
1752+
cacheFailed = make(map[common.Hash]struct{})
17501753
}
17511754

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

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

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

17731797
w.bundleCacheHeaderHash = env.header.Hash()
1774-
w.bundleCache = bundleCache
1798+
w.bundleCacheSuccess = cacheSuccess
1799+
w.bundleCacheFailed = cacheFailed
17751800

17761801
return simulatedBundles, nil
17771802
}

miner/worker_test.go

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

0 commit comments

Comments
 (0)