mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-10 19:51:20 +00:00
98949d8075
Co-authored-by: terencechain <terence@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
190 lines
6.4 KiB
Go
190 lines
6.4 KiB
Go
package rewards
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair"
|
|
coreblocks "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/validators"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
|
|
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
|
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
|
"github.com/prysmaticlabs/prysm/v4/network"
|
|
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
|
)
|
|
|
|
// BlockRewards is an HTTP handler for Beacon API getBlockRewards.
|
|
func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
|
|
segments := strings.Split(r.URL.Path, "/")
|
|
blockId := segments[len(segments)-1]
|
|
|
|
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
|
|
if errJson := handleGetBlockError(blk, err); errJson != nil {
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
if blk.Version() == version.Phase0 {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: "block rewards are not supported for Phase 0 blocks",
|
|
Code: http.StatusBadRequest,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
|
|
// We want to run several block processing functions that update the proposer's balance.
|
|
// This will allow us to calculate proposer rewards for each operation (atts, slashings etc).
|
|
// To do this, we replay the state up to the block's slot, but before processing the block.
|
|
st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot())
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get state").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
|
|
proposerIndex := blk.Block().ProposerIndex()
|
|
initBalance, err := st.BalanceAtIndex(proposerIndex)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get attestation rewards").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
attBalance, err := st.BalanceAtIndex(proposerIndex)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get attester slashing rewards").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get proposer slashing rewards").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
sa, err := blk.Block().Body().SyncAggregate()
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get sync aggregate").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
var syncCommitteeReward uint64
|
|
_, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa)
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get sync aggregate rewards").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
|
|
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get optimistic mode info").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
blkRoot, err := blk.Block().HashTreeRoot()
|
|
if err != nil {
|
|
errJson := &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get block root").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
network.WriteError(w, errJson)
|
|
return
|
|
}
|
|
|
|
response := &BlockRewardsResponse{
|
|
Data: &BlockRewards{
|
|
ProposerIndex: strconv.FormatUint(uint64(proposerIndex), 10),
|
|
Total: strconv.FormatUint(proposerSlashingsBalance-initBalance+syncCommitteeReward, 10),
|
|
Attestations: strconv.FormatUint(attBalance-initBalance, 10),
|
|
SyncAggregate: strconv.FormatUint(syncCommitteeReward, 10),
|
|
ProposerSlashings: strconv.FormatUint(proposerSlashingsBalance-attSlashingsBalance, 10),
|
|
AttesterSlashings: strconv.FormatUint(attSlashingsBalance-attBalance, 10),
|
|
},
|
|
ExecutionOptimistic: optimistic,
|
|
Finalized: s.FinalizationFetcher.IsFinalized(r.Context(), blkRoot),
|
|
}
|
|
network.WriteJson(w, response)
|
|
}
|
|
|
|
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) *network.DefaultErrorJson {
|
|
if errors.Is(err, lookup.BlockIdParseError{}) {
|
|
return &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "invalid block ID").Error(),
|
|
Code: http.StatusBadRequest,
|
|
}
|
|
}
|
|
if err != nil {
|
|
return &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not get block from block ID").Error(),
|
|
Code: http.StatusInternalServerError,
|
|
}
|
|
}
|
|
if err := blocks.BeaconBlockIsNil(blk); err != nil {
|
|
return &network.DefaultErrorJson{
|
|
Message: errors.Wrapf(err, "could not find requested block").Error(),
|
|
Code: http.StatusNotFound,
|
|
}
|
|
}
|
|
return nil
|
|
}
|