Skip to content

Commit 1d7171c

Browse files
shekhirinRuteri
authored andcommitted
feat(ethash): flashbots_getWork RPC with profit
1 parent 45f1cb1 commit 1d7171c

File tree

12 files changed

+80
-27
lines changed

12 files changed

+80
-27
lines changed

cmd/evm/internal/t8ntool/block.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func (i *bbInput) sealEthash(block *types.Block) (*types.Block, error) {
188188
// If the testmode is used, the sealer will return quickly, and complain
189189
// "Sealing result is not read by miner" if it cannot write the result.
190190
results := make(chan *types.Block, 1)
191-
if err := engine.Seal(nil, block, results, nil); err != nil {
191+
if err := engine.Seal(nil, block, nil, results, nil); err != nil {
192192
panic(fmt.Sprintf("failed to seal block: %v", err))
193193
}
194194
found := <-results

cmd/geth/consolecmd_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
)
3232

3333
const (
34-
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0"
34+
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 flashbots:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0"
3535
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
3636
)
3737

consensus/beacon/consensus.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,9 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
298298
//
299299
// Note, the method returns immediately and will send the result async. More
300300
// than one result may also be returned depending on the consensus algorithm.
301-
func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
301+
func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, profit *big.Int, results chan<- *types.Block, stop <-chan struct{}) error {
302302
if !beacon.IsPoSHeader(block.Header()) {
303-
return beacon.ethone.Seal(chain, block, results, stop)
303+
return beacon.ethone.Seal(chain, block, profit, results, stop)
304304
}
305305
// The seal verification is done by the external consensus engine,
306306
// return directly without pushing any block back. In another word

consensus/clique/clique.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ func (c *Clique) Authorize(signer common.Address, signFn SignerFn) {
589589

590590
// Seal implements consensus.Engine, attempting to create a sealed block using
591591
// the local signing credentials.
592-
func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
592+
func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, profit *big.Int, results chan<- *types.Block, stop <-chan struct{}) error {
593593
header := block.Header()
594594

595595
// Sealing the genesis block is not supported

consensus/consensus.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ type Engine interface {
105105
//
106106
// Note, the method returns immediately and will send the result async. More
107107
// than one result may also be returned depending on the consensus algorithm.
108-
Seal(chain ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error
108+
Seal(chain ChainHeaderReader, block *types.Block, profit *big.Int, results chan<- *types.Block, stop <-chan struct{}) error
109109

110110
// SealHash returns the hash of a block prior to it being sealed.
111111
SealHash(header *types.Header) common.Hash

consensus/ethash/api.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (api *API) GetWork() ([4]string, error) {
4444
}
4545

4646
var (
47-
workCh = make(chan [4]string, 1)
47+
workCh = make(chan [5]string, 1)
4848
errc = make(chan error, 1)
4949
)
5050
select {
@@ -53,7 +53,10 @@ func (api *API) GetWork() ([4]string, error) {
5353
return [4]string{}, errEthashStopped
5454
}
5555
select {
56-
case work := <-workCh:
56+
case fullWork := <-workCh:
57+
var work [4]string
58+
copy(work[:], fullWork[:4])
59+
5760
return work, nil
5861
case err := <-errc:
5962
return [4]string{}, err

consensus/ethash/ethash.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,12 @@ func (ethash *Ethash) APIs(chain consensus.ChainHeaderReader) []rpc.API {
683683
Service: &API{ethash},
684684
Public: true,
685685
},
686+
{
687+
Namespace: "flashbots",
688+
Version: "1.0",
689+
Service: &FlashbotsAPI{ethash},
690+
Public: true,
691+
},
686692
}
687693
}
688694

consensus/ethash/ethash_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestTestMode(t *testing.T) {
3838
defer ethash.Close()
3939

4040
results := make(chan *types.Block)
41-
err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil)
41+
err := ethash.Seal(nil, types.NewBlockWithHeader(header), nil, results, nil)
4242
if err != nil {
4343
t.Fatalf("failed to seal block: %v", err)
4444
}
@@ -111,7 +111,7 @@ func TestRemoteSealer(t *testing.T) {
111111

112112
// Push new work.
113113
results := make(chan *types.Block)
114-
ethash.Seal(nil, block, results, nil)
114+
ethash.Seal(nil, block, nil, results, nil)
115115

116116
var (
117117
work [4]string
@@ -128,7 +128,7 @@ func TestRemoteSealer(t *testing.T) {
128128
header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)}
129129
block = types.NewBlockWithHeader(header)
130130
sealhash = ethash.SealHash(header)
131-
ethash.Seal(nil, block, results, nil)
131+
ethash.Seal(nil, block, nil, results, nil)
132132

133133
if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() {
134134
t.Error("expect to return the latest pushed work")

consensus/ethash/flashbots_api.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package ethash
2+
3+
import "errors"
4+
5+
// FlashbotsAPI exposes Flashbots related methods for the RPC interface.
6+
type FlashbotsAPI struct {
7+
ethash *Ethash
8+
}
9+
10+
// GetWork returns a work package for external miner.
11+
//
12+
// The work package consists of 5 strings:
13+
// result[0] - 32 bytes hex encoded current block header pow-hash
14+
// result[1] - 32 bytes hex encoded seed hash used for DAG
15+
// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
16+
// result[3] - hex encoded block number
17+
// result[4] - hex encoded profit generated from this block
18+
func (api *FlashbotsAPI) GetWork() ([5]string, error) {
19+
if api.ethash.remote == nil {
20+
return [5]string{}, errors.New("not supported")
21+
}
22+
23+
var (
24+
workCh = make(chan [5]string, 1)
25+
errc = make(chan error, 1)
26+
)
27+
select {
28+
case api.ethash.remote.fetchWorkCh <- &sealWork{errc: errc, res: workCh}:
29+
case <-api.ethash.remote.exitCh:
30+
return [5]string{}, errEthashStopped
31+
}
32+
select {
33+
case work := <-workCh:
34+
return work, nil
35+
case err := <-errc:
36+
return [5]string{}, err
37+
}
38+
}

consensus/ethash/sealer.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ var (
4848

4949
// Seal implements consensus.Engine, attempting to find a nonce that satisfies
5050
// the block's difficulty requirements.
51-
func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
51+
func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, profit *big.Int, results chan<- *types.Block, stop <-chan struct{}) error {
5252
// If we're running a fake PoW, simply return a 0 nonce immediately
5353
if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake {
5454
header := block.Header()
@@ -62,7 +62,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block
6262
}
6363
// If we're running a shared PoW, delegate sealing to it
6464
if ethash.shared != nil {
65-
return ethash.shared.Seal(chain, block, results, stop)
65+
return ethash.shared.Seal(chain, block, profit, results, stop)
6666
}
6767
// Create a runner and the multiple search threads it directs
6868
abort := make(chan struct{})
@@ -86,7 +86,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block
8686
}
8787
// Push new work to remote sealer
8888
if ethash.remote != nil {
89-
ethash.remote.workCh <- &sealTask{block: block, results: results}
89+
ethash.remote.workCh <- &sealTask{block: block, profit: profit, results: results}
9090
}
9191
var (
9292
pend sync.WaitGroup
@@ -117,7 +117,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block
117117
case <-ethash.update:
118118
// Thread count was changed on user request, restart
119119
close(abort)
120-
if err := ethash.Seal(chain, block, results, stop); err != nil {
120+
if err := ethash.Seal(chain, block, profit, results, stop); err != nil {
121121
ethash.config.Log.Error("Failed to restart sealing after update", "err", err)
122122
}
123123
}
@@ -194,7 +194,7 @@ type remoteSealer struct {
194194
works map[common.Hash]*types.Block
195195
rates map[common.Hash]hashrate
196196
currentBlock *types.Block
197-
currentWork [4]string
197+
currentWork [5]string
198198
notifyCtx context.Context
199199
cancelNotify context.CancelFunc // cancels all notification requests
200200
reqWG sync.WaitGroup // tracks notification request goroutines
@@ -215,6 +215,7 @@ type remoteSealer struct {
215215
// sealTask wraps a seal block with relative result channel for remote sealer thread.
216216
type sealTask struct {
217217
block *types.Block
218+
profit *big.Int
218219
results chan<- *types.Block
219220
}
220221

@@ -239,7 +240,7 @@ type hashrate struct {
239240
// sealWork wraps a seal work package for remote sealer.
240241
type sealWork struct {
241242
errc chan error
242-
res chan [4]string
243+
res chan [5]string
243244
}
244245

245246
func startRemoteSealer(ethash *Ethash, urls []string, noverify bool) *remoteSealer {
@@ -281,7 +282,7 @@ func (s *remoteSealer) loop() {
281282
// Update current work with new received block.
282283
// Note same work can be past twice, happens when changing CPU threads.
283284
s.results = work.results
284-
s.makeWork(work.block)
285+
s.makeWork(work.block, work.profit)
285286
s.notifyWork()
286287

287288
case work := <-s.fetchWorkCh:
@@ -338,18 +339,23 @@ func (s *remoteSealer) loop() {
338339

339340
// makeWork creates a work package for external miner.
340341
//
341-
// The work package consists of 3 strings:
342+
// The work package consists of 5 strings:
342343
// result[0], 32 bytes hex encoded current block header pow-hash
343344
// result[1], 32 bytes hex encoded seed hash used for DAG
344345
// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
345346
// result[3], hex encoded block number
346-
func (s *remoteSealer) makeWork(block *types.Block) {
347+
// result[4], hex encoded profit generated from this block, if present
348+
func (s *remoteSealer) makeWork(block *types.Block, profit *big.Int) {
347349
hash := s.ethash.SealHash(block.Header())
348350
s.currentWork[0] = hash.Hex()
349351
s.currentWork[1] = common.BytesToHash(SeedHash(block.NumberU64())).Hex()
350352
s.currentWork[2] = common.BytesToHash(new(big.Int).Div(two256, block.Difficulty()).Bytes()).Hex()
351353
s.currentWork[3] = hexutil.EncodeBig(block.Number())
352354

355+
if profit != nil {
356+
s.currentWork[4] = hexutil.EncodeBig(profit)
357+
}
358+
353359
// Trace the seal work fetched by remote sealer.
354360
s.currentBlock = block
355361
s.works[hash] = block
@@ -375,7 +381,7 @@ func (s *remoteSealer) notifyWork() {
375381
}
376382
}
377383

378-
func (s *remoteSealer) sendNotification(ctx context.Context, url string, json []byte, work [4]string) {
384+
func (s *remoteSealer) sendNotification(ctx context.Context, url string, json []byte, work [5]string) {
379385
defer s.reqWG.Done()
380386

381387
req, err := http.NewRequest("POST", url, bytes.NewReader(json))

0 commit comments

Comments
 (0)