forked from cerc-io/plugeth
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:
+6
-16
@@ -18,8 +18,6 @@
|
||||
package catalyst
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
@@ -288,12 +286,17 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
||||
FeeRecipient: payloadAttributes.SuggestedFeeRecipient,
|
||||
Random: payloadAttributes.Random,
|
||||
}
|
||||
id := args.Id()
|
||||
// If we already are busy generating this work, then we do not need
|
||||
// to start a second process.
|
||||
if api.localBlocks.has(id) {
|
||||
return valid(&id), nil
|
||||
}
|
||||
payload, err := api.eth.Miner().BuildPayload(args)
|
||||
if err != nil {
|
||||
log.Error("Failed to build payload", "err", err)
|
||||
return valid(nil), beacon.InvalidPayloadAttributes.With(err)
|
||||
}
|
||||
id := computePayloadId(update.HeadBlockHash, payloadAttributes)
|
||||
api.localBlocks.put(id, payload)
|
||||
return valid(&id), nil
|
||||
}
|
||||
@@ -443,19 +446,6 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa
|
||||
return beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &hash}, nil
|
||||
}
|
||||
|
||||
// computePayloadId computes a pseudo-random payloadid, based on the parameters.
|
||||
func computePayloadId(headBlockHash common.Hash, params *beacon.PayloadAttributesV1) beacon.PayloadID {
|
||||
// Hash
|
||||
hasher := sha256.New()
|
||||
hasher.Write(headBlockHash[:])
|
||||
binary.Write(hasher, binary.BigEndian, params.Timestamp)
|
||||
hasher.Write(params.Random[:])
|
||||
hasher.Write(params.SuggestedFeeRecipient[:])
|
||||
var out beacon.PayloadID
|
||||
copy(out[:], hasher.Sum(nil)[:8])
|
||||
return out
|
||||
}
|
||||
|
||||
// delayPayloadImport stashes the given block away for import at a later time,
|
||||
// either via a forkchoice update or a sync extension. This method is meant to
|
||||
// be called by the newpayload command when the block seems to be ok, but some
|
||||
|
||||
@@ -184,7 +184,12 @@ func TestEth2PrepareAndGetPayload(t *testing.T) {
|
||||
}
|
||||
// give the payload some time to be built
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams)
|
||||
payloadID := (&miner.BuildPayloadArgs{
|
||||
Parent: fcState.HeadBlockHash,
|
||||
Timestamp: blockParams.Timestamp,
|
||||
FeeRecipient: blockParams.SuggestedFeeRecipient,
|
||||
Random: blockParams.Random,
|
||||
}).Id()
|
||||
execData, err := api.GetPayloadV1(payloadID)
|
||||
if err != nil {
|
||||
t.Fatalf("error getting payload, err=%v", err)
|
||||
|
||||
@@ -85,6 +85,22 @@ func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// has checks if a particular payload is already tracked.
|
||||
func (q *payloadQueue) has(id beacon.PayloadID) bool {
|
||||
q.lock.RLock()
|
||||
defer q.lock.RUnlock()
|
||||
|
||||
for _, item := range q.payloads {
|
||||
if item == nil {
|
||||
return false
|
||||
}
|
||||
if item.id == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// headerQueueItem represents an hash->header tuple to store until it's retrieved
|
||||
// or evicted.
|
||||
type headerQueueItem struct {
|
||||
|
||||
Reference in New Issue
Block a user