mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-31 16:21:21 +00:00
123 lines
3.9 KiB
Go
123 lines
3.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/ledgerwatch/erigon/cl/beacon/beaconhttp"
|
|
"github.com/ledgerwatch/erigon/cl/persistence/base_encoding"
|
|
state_accessors "github.com/ledgerwatch/erigon/cl/persistence/state"
|
|
shuffling2 "github.com/ledgerwatch/erigon/cl/phase1/core/state/shuffling"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
)
|
|
|
|
type proposerDuties struct {
|
|
Pubkey libcommon.Bytes48 `json:"pubkey"`
|
|
ValidatorIndex uint64 `json:"validator_index,string"`
|
|
Slot uint64 `json:"slot,string"`
|
|
}
|
|
|
|
func (a *ApiHandler) getDutiesProposer(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
|
epoch, err := epochFromRequest(r)
|
|
if err != nil {
|
|
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
|
}
|
|
|
|
if epoch < a.forkchoiceStore.FinalizedCheckpoint().Epoch() {
|
|
tx, err := a.indiciesDB.BeginRo(r.Context())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tx.Rollback()
|
|
key := base_encoding.Encode64ToBytes4(epoch)
|
|
indiciesBytes, err := tx.GetOne(kv.Proposers, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(indiciesBytes) != int(a.beaconChainCfg.SlotsPerEpoch*4) {
|
|
return nil, beaconhttp.NewEndpointError(http.StatusInternalServerError, "proposer duties is corrupted")
|
|
}
|
|
duties := make([]proposerDuties, a.beaconChainCfg.SlotsPerEpoch)
|
|
for i := uint64(0); i < a.beaconChainCfg.SlotsPerEpoch; i++ {
|
|
validatorIndex := binary.BigEndian.Uint32(indiciesBytes[i*4 : i*4+4])
|
|
var pk libcommon.Bytes48
|
|
pk, err := state_accessors.ReadPublicKeyByIndex(tx, uint64(validatorIndex))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
duties[i] = proposerDuties{
|
|
Pubkey: pk,
|
|
ValidatorIndex: uint64(validatorIndex),
|
|
Slot: epoch*a.beaconChainCfg.SlotsPerEpoch + i,
|
|
}
|
|
}
|
|
return newBeaconResponse(duties).withFinalized(true).withVersion(a.beaconChainCfg.GetCurrentStateVersion(epoch)), nil
|
|
}
|
|
|
|
// We need to compute our duties
|
|
state, cancel := a.syncedData.HeadState()
|
|
defer cancel()
|
|
if state == nil {
|
|
return nil, beaconhttp.NewEndpointError(http.StatusServiceUnavailable, "beacon node is syncing")
|
|
|
|
}
|
|
|
|
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 {
|
|
panic(err)
|
|
}
|
|
var pk libcommon.Bytes48
|
|
pk, err = state.ValidatorPublicKey(int(proposerIndex))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
duties[i] = proposerDuties{
|
|
Pubkey: pk,
|
|
ValidatorIndex: proposerIndex,
|
|
Slot: slot,
|
|
}
|
|
}(slot-expectedSlot, slot, indices, seedArray)
|
|
}
|
|
wg.Wait()
|
|
|
|
return newBeaconResponse(duties).withFinalized(false).withVersion(a.beaconChainCfg.GetCurrentStateVersion(epoch)), nil
|
|
}
|