mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-10 04:51:20 +00:00
121 lines
3.3 KiB
Go
121 lines
3.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/ledgerwatch/erigon/cl/phase1/core/state/lru"
|
|
shuffling2 "github.com/ledgerwatch/erigon/cl/phase1/core/state/shuffling"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon/cl/clparams"
|
|
)
|
|
|
|
type proposerDuties struct {
|
|
Pubkey libcommon.Bytes48 `json:"pubkey"`
|
|
ValidatorIndex uint64 `json:"validator_index"`
|
|
Slot uint64 `json:"slot"`
|
|
}
|
|
|
|
// The proposer knight respects its duties and hands over which proposer should be proposing in which slot.
|
|
type proposerKnight struct {
|
|
// The proposer knight's duties.
|
|
dutiesCache *lru.Cache[uint64, []proposerDuties]
|
|
}
|
|
|
|
func (a *ApiHandler) getDutiesProposer(r *http.Request) (data any, finalized *bool, version *clparams.StateVersion, httpStatus int, err error) {
|
|
if a.dutiesCache == nil {
|
|
a.dutiesCache, err = lru.New[uint64, []proposerDuties]("proposerKnight", 32)
|
|
}
|
|
if err != nil {
|
|
httpStatus = http.StatusInternalServerError
|
|
return
|
|
}
|
|
var epoch uint64
|
|
|
|
epoch, err = epochFromRequest(r)
|
|
if err != nil {
|
|
httpStatus = http.StatusBadRequest
|
|
return
|
|
}
|
|
|
|
if epoch < a.forkchoiceStore.FinalizedCheckpoint().Epoch() {
|
|
err = fmt.Errorf("invalid epoch")
|
|
httpStatus = http.StatusBadRequest
|
|
return
|
|
}
|
|
|
|
// We need to compute our duties
|
|
state, cancel := a.syncedData.HeadState()
|
|
defer cancel()
|
|
if state == nil {
|
|
err = fmt.Errorf("node is syncing")
|
|
httpStatus = http.StatusInternalServerError
|
|
return
|
|
}
|
|
|
|
expectedSlot := epoch * a.beaconChainCfg.SlotsPerEpoch
|
|
|
|
duties := make([]proposerDuties, a.beaconChainCfg.SlotsPerEpoch)
|
|
wg := sync.WaitGroup{}
|
|
|
|
for slot := expectedSlot; slot < expectedSlot+a.beaconChainCfg.SlotsPerEpoch; slot++ {
|
|
var proposerIndex uint64
|
|
// Lets do proposer index computation
|
|
mixPosition := (epoch + a.beaconChainCfg.EpochsPerHistoricalVector - a.beaconChainCfg.MinSeedLookahead - 1) %
|
|
a.beaconChainCfg.EpochsPerHistoricalVector
|
|
// Input for the seed hash.
|
|
mix := state.GetRandaoMix(int(mixPosition))
|
|
input := shuffling2.GetSeed(a.beaconChainCfg, mix, epoch, a.beaconChainCfg.DomainBeaconProposer)
|
|
slotByteArray := make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(slotByteArray, slot)
|
|
|
|
// Add slot to the end of the input.
|
|
inputWithSlot := append(input[:], slotByteArray...)
|
|
hash := sha256.New()
|
|
|
|
// Calculate the hash.
|
|
hash.Write(inputWithSlot)
|
|
seed := hash.Sum(nil)
|
|
|
|
indices := state.GetActiveValidatorsIndices(epoch)
|
|
|
|
// Write the seed to an array.
|
|
seedArray := [32]byte{}
|
|
copy(seedArray[:], seed)
|
|
wg.Add(1)
|
|
|
|
// Do it in parallel
|
|
go func(i, slot uint64, indicies []uint64, seedArray [32]byte) {
|
|
defer wg.Done()
|
|
proposerIndex, err = shuffling2.ComputeProposerIndex(state.BeaconState, indices, seedArray)
|
|
if err != nil {
|
|
httpStatus = http.StatusInternalServerError
|
|
return
|
|
}
|
|
var pk libcommon.Bytes48
|
|
pk, err = state.ValidatorPublicKey(int(proposerIndex))
|
|
if err != nil {
|
|
httpStatus = http.StatusInternalServerError
|
|
return
|
|
}
|
|
duties[i] = proposerDuties{
|
|
Pubkey: pk,
|
|
ValidatorIndex: proposerIndex,
|
|
Slot: slot,
|
|
}
|
|
}(slot-expectedSlot, slot, indices, seedArray)
|
|
}
|
|
wg.Wait()
|
|
a.dutiesCache.Add(epoch, duties)
|
|
data = duties
|
|
finalized = new(bool)
|
|
*finalized = false
|
|
httpStatus = http.StatusAccepted
|
|
return
|
|
|
|
}
|