eth/catalyst, miner: deduplicate work + show payload id (#26115)

This PR now also includes a fix to the problem of mult-routines building blocks on the same input. This PR works as before with regards to stopping the work, but it just will not spin up a second routine if one is already building. So if the CL does N calls to FCU+buildblock, and N calls to GetPayload, only the first of each will do something, the other calls will be mostly no-ops.

This PR also adds printout of the payload id into the logs.
This commit is contained in:
Martin Holst Swende
2022-11-07 15:30:54 +01:00
committed by GitHub
parent 111ed1af1b
commit ca948b8579
4 changed files with 53 additions and 21 deletions
+25 -4
View File
@@ -17,6 +17,8 @@
package miner
import (
"crypto/sha256"
"encoding/binary"
"math/big"
"sync"
"time"
@@ -38,12 +40,26 @@ type BuildPayloadArgs struct {
Random common.Hash // The provided randomness value
}
// Id computes an 8-byte identifier by hashing the components of the payload arguments.
func (args *BuildPayloadArgs) Id() beacon.PayloadID {
// Hash
hasher := sha256.New()
hasher.Write(args.Parent[:])
binary.Write(hasher, binary.BigEndian, args.Timestamp)
hasher.Write(args.Random[:])
hasher.Write(args.FeeRecipient[:])
var out beacon.PayloadID
copy(out[:], hasher.Sum(nil)[:8])
return out
}
// Payload wraps the built payload(block waiting for sealing). According to the
// engine-api specification, EL should build the initial version of the payload
// which has an empty transaction set and then keep update it in order to maximize
// the revenue. Therefore, the empty-block here is always available and full-block
// will be set/updated afterwards.
type Payload struct {
id beacon.PayloadID
empty *types.Block
full *types.Block
fullFees *big.Int
@@ -53,11 +69,13 @@ type Payload struct {
}
// newPayload initializes the payload object.
func newPayload(empty *types.Block) *Payload {
func newPayload(empty *types.Block, id beacon.PayloadID) *Payload {
payload := &Payload{
id: id,
empty: empty,
stop: make(chan struct{}),
}
log.Info("Starting work on payload", "id", payload.id)
payload.cond = sync.NewCond(&payload.lock)
return payload
}
@@ -80,8 +98,9 @@ func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.D
payload.fullFees = fees
feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether))
log.Info("Updated payload", "number", block.NumberU64(), "hash", block.Hash(),
"txs", len(block.Transactions()), "gas", block.GasUsed(), "fees", feesInEther, "elapsed", common.PrettyDuration(elapsed))
log.Info("Updated payload", "id", payload.id, "number", block.NumberU64(), "hash", block.Hash(),
"txs", len(block.Transactions()), "gas", block.GasUsed(), "fees", feesInEther,
"root", block.Root(), "elapsed", common.PrettyDuration(elapsed))
}
payload.cond.Broadcast() // fire signal for notifying full block
}
@@ -139,7 +158,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) {
return nil, err
}
// Construct a payload object for return.
payload := newPayload(empty)
payload := newPayload(empty, args.Id())
// Spin up a routine for updating the payload in background. This strategy
// can maximum the revenue for including transactions with highest fee.
@@ -164,8 +183,10 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) {
}
timer.Reset(w.recommit)
case <-payload.stop:
log.Info("Stopping work on payload", "id", payload.id, "reason", "delivery")
return
case <-endTimer.C:
log.Info("Stopping work on payload", "id", payload.id, "reason", "timeout")
return
}
}