Deneb: Produce Block V3 - adding consensus block value (#12948)

* adding in block rewards to represent consensus payload

* Update beacon-chain/rpc/eth/validator/handlers_block.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* radek's comments

* more review changes

* adding more tests for forks

* gaz

* updating names

* gaz

* fixing imports

* fixing variable name

* gaz

* fixing test

* renaming variables to match data

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
james-prysm
2023-10-10 10:12:20 -05:00
committed by GitHub
parent 8eb82dd378
commit af70677778
17 changed files with 547 additions and 158 deletions

View File

@@ -4,6 +4,7 @@ const (
VersionHeader = "Eth-Consensus-Version"
ExecutionPayloadBlindedHeader = "Eth-Execution-Payload-Blinded"
ExecutionPayloadValueHeader = "Eth-Execution-Payload-Value"
ConsensusBlockValueHeader = "Eth-Consensus-Block-Value"
JsonMediaType = "application/json"
OctetStreamMediaType = "application/octet-stream"
)

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [
"handlers.go",
"server.go",
"service.go",
"structs.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards",
@@ -21,11 +22,13 @@ go_library(
"//beacon-chain/state/stategen:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//network/http:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_wealdtech_go_bytesutil//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)
@@ -54,6 +57,7 @@ go_test(
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
],
)

View File

@@ -8,9 +8,7 @@ import (
"strings"
"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/epoch/precompute"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/validators"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
@@ -20,10 +18,13 @@ import (
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"github.com/wealdtech/go-bytesutil"
"go.opencensus.io/trace"
)
// BlockRewards is an HTTP handler for Beacon API getBlockRewards.
func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.BlockRewards")
defer span.End()
segments := strings.Split(r.URL.Path, "/")
blockId := segments[len(segments)-1]
@@ -36,63 +37,6 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
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 {
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
return
}
proposerIndex := blk.Block().ProposerIndex()
initBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk)
if err != nil {
http2.HandleError(w, "Could not get attestation rewards"+err.Error(), http.StatusInternalServerError)
return
}
attBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator)
if err != nil {
http2.HandleError(w, "Could not get attester slashing rewards: "+err.Error(), http.StatusInternalServerError)
return
}
attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator)
if err != nil {
http2.HandleError(w, "Could not get proposer slashing rewards"+err.Error(), http.StatusInternalServerError)
return
}
proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
sa, err := blk.Block().Body().SyncAggregate()
if err != nil {
http2.HandleError(w, "Could not get sync aggregate: "+err.Error(), http.StatusInternalServerError)
return
}
var syncCommitteeReward uint64
_, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa)
if err != nil {
http2.HandleError(w, "Could not get sync aggregate rewards: "+err.Error(), http.StatusInternalServerError)
return
}
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
if err != nil {
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
@@ -103,18 +47,15 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
return
}
blockRewards, httpError := s.BlockRewardFetcher.GetBlockRewardsData(ctx, blk)
if httpError != nil {
http2.WriteError(w, httpError)
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),
},
Data: blockRewards,
ExecutionOptimistic: optimistic,
Finalized: s.FinalizationFetcher.IsFinalized(r.Context(), blkRoot),
Finalized: s.FinalizationFetcher.IsFinalized(ctx, blkRoot),
}
http2.WriteJson(w, response)
}
@@ -165,6 +106,8 @@ func (s *Server) AttestationRewards(w http.ResponseWriter, r *http.Request) {
// SyncCommitteeRewards retrieves rewards info for sync committee members specified by array of public keys or validator index.
// If no array is provided, return reward info for every committee member.
func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.SyncCommitteeRewards")
defer span.End()
segments := strings.Split(r.URL.Path, "/")
blockId := segments[len(segments)-1]
@@ -176,9 +119,10 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
http2.HandleError(w, "Sync committee rewards are not supported for Phase 0", http.StatusBadRequest)
return
}
st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot())
if err != nil {
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
st, httpErr := s.BlockRewardFetcher.GetStateForRewards(ctx, blk)
if httpErr != nil {
http2.WriteError(w, httpErr)
return
}
sa, err := blk.Block().Body().SyncAggregate()

View File

@@ -11,6 +11,7 @@ import (
"strings"
"testing"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair"
@@ -34,12 +35,42 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/util"
)
func TestBlockRewards(t *testing.T) {
func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, interfaces.SignedBeaconBlock, error) {
helpers.ClearCache()
var sbb interfaces.SignedBeaconBlock
var st state.BeaconState
var err error
switch forkName {
case "phase0":
return nil, nil, errors.New("phase0 not supported")
case "altair":
st, err = util.NewBeaconStateAltair()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockAltair(util.NewBeaconBlockAltair())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case "bellatrix":
st, err = util.NewBeaconStateBellatrix()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockBellatrix(util.NewBeaconBlockBellatrix())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case "capella":
st, err = util.NewBeaconStateCapella()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockCapella(util.NewBeaconBlockCapella())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case "deneb":
st, err = util.NewBeaconStateDeneb()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockDeneb(util.NewBeaconBlockDeneb())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
default:
return nil, nil, errors.New("fork is not supported")
}
valCount := 64
st, err := util.NewBeaconStateCapella()
require.NoError(t, st.SetSlot(1))
require.NoError(t, err)
validators := make([]*eth.Validator, 0, valCount)
@@ -68,11 +99,10 @@ func TestBlockRewards(t *testing.T) {
bRoots[0] = slot0bRoot
require.NoError(t, st.SetBlockRoots(bRoots))
b := util.HydrateSignedBeaconBlockCapella(util.NewBeaconBlockCapella())
b.Block.Slot = 2
sbb.SetSlot(2)
// we have to set the proposer index to the value that will be randomly chosen (fortunately it's deterministic)
b.Block.ProposerIndex = 12
b.Block.Body.Attestations = []*eth.Attestation{
sbb.SetProposerIndex(12)
sbb.SetAttestations([]*eth.Attestation{
{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
@@ -83,7 +113,8 @@ func TestBlockRewards(t *testing.T) {
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
}
})
attData1 := util.HydrateAttestationData(&eth.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32)})
attData2 := util.HydrateAttestationData(&eth.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32)})
domain, err := signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorsRoot())
@@ -92,7 +123,7 @@ func TestBlockRewards(t *testing.T) {
require.NoError(t, err)
sigRoot2, err := signing.ComputeSigningRoot(attData2, domain)
require.NoError(t, err)
b.Block.Body.AttesterSlashings = []*eth.AttesterSlashing{
sbb.SetAttesterSlashings([]*eth.AttesterSlashing{
{
Attestation_1: &eth.IndexedAttestation{
AttestingIndices: []uint64{0},
@@ -105,7 +136,7 @@ func TestBlockRewards(t *testing.T) {
Signature: secretKeys[0].Sign(sigRoot2[:]).Marshal(),
},
},
}
})
header1 := &eth.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 1,
@@ -126,7 +157,7 @@ func TestBlockRewards(t *testing.T) {
require.NoError(t, err)
sigRoot2, err = signing.ComputeSigningRoot(header2, domain)
require.NoError(t, err)
b.Block.Body.ProposerSlashings = []*eth.ProposerSlashing{
sbb.SetProposerSlashings([]*eth.ProposerSlashing{
{
Header_1: &eth.SignedBeaconBlockHeader{
Header: header1,
@@ -137,7 +168,7 @@ func TestBlockRewards(t *testing.T) {
Signature: secretKeys[1].Sign(sigRoot2[:]).Marshal(),
},
},
}
})
scBits := bitfield.NewBitvector512()
scBits.SetBitAt(10, true)
scBits.SetBitAt(100, true)
@@ -153,24 +184,51 @@ func TestBlockRewards(t *testing.T) {
sig2, err := blst.SignatureFromBytes(secretKeys[19].Sign(r[:]).Marshal())
require.NoError(t, err)
aggSig := bls.AggregateSignatures([]bls.Signature{sig1, sig2}).Marshal()
b.Block.Body.SyncAggregate = &eth.SyncAggregate{SyncCommitteeBits: scBits, SyncCommitteeSignature: aggSig}
sbb, err := blocks.NewSignedBeaconBlock(b)
err = sbb.SetSyncAggregate(&eth.SyncAggregate{SyncCommitteeBits: scBits, SyncCommitteeSignature: aggSig})
require.NoError(t, err)
return st, sbb, nil
}
func TestBlockRewards(t *testing.T) {
phase0block, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ReplayerBuilder: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st)),
}
t.Run("phase 0", func(t *testing.T) {
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
}
url := "http://only.the.slot.number.at.the.end.is.important/0"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, "Block rewards are not supported for Phase 0 blocks", e.Message)
})
t.Run("altair", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "altair")
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st))},
}
t.Run("ok", func(t *testing.T) {
url := "http://only.the.slot.number.at.the.end.is.important/2"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
@@ -189,18 +247,104 @@ func TestBlockRewards(t *testing.T) {
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
t.Run("phase 0", func(t *testing.T) {
url := "http://only.the.slot.number.at.the.end.is.important/0"
t.Run("bellatrix", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "bellatrix")
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st))},
}
url := "http://only.the.slot.number.at.the.end.is.important/2"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, "Block rewards are not supported for Phase 0 blocks", e.Message)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
assert.Equal(t, "125089490", resp.Data.Total)
assert.Equal(t, "89442", resp.Data.Attestations)
assert.Equal(t, "48", resp.Data.SyncAggregate)
assert.Equal(t, "62500000", resp.Data.AttesterSlashings)
assert.Equal(t, "62500000", resp.Data.ProposerSlashings)
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
t.Run("capella", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "capella")
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st))},
}
url := "http://only.the.slot.number.at.the.end.is.important/2"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
assert.Equal(t, "125089490", resp.Data.Total)
assert.Equal(t, "89442", resp.Data.Attestations)
assert.Equal(t, "48", resp.Data.SyncAggregate)
assert.Equal(t, "62500000", resp.Data.AttesterSlashings)
assert.Equal(t, "62500000", resp.Data.ProposerSlashings)
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
t.Run("deneb", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "deneb")
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st))},
}
url := "http://only.the.slot.number.at.the.end.is.important/2"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
assert.Equal(t, "125089490", resp.Data.Total)
assert.Equal(t, "89442", resp.Data.Attestations)
assert.Equal(t, "48", resp.Data.SyncAggregate)
assert.Equal(t, "62500000", resp.Data.AttesterSlashings)
assert.Equal(t, "62500000", resp.Data.ProposerSlashings)
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
}
@@ -560,7 +704,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ReplayerBuilder: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st)),
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st))},
}
t.Run("ok - filtered vals", func(t *testing.T) {

View File

@@ -3,15 +3,14 @@ package rewards
import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
)
type Server struct {
Blocker lookup.Blocker
OptimisticModeFetcher blockchain.OptimisticModeFetcher
FinalizationFetcher blockchain.FinalizationFetcher
ReplayerBuilder stategen.ReplayerBuilder
TimeFetcher blockchain.TimeFetcher
Stater lookup.Stater
HeadFetcher blockchain.HeadFetcher
BlockRewardFetcher BlockRewardsFetcher
}

View File

@@ -0,0 +1,124 @@
package rewards
import (
"context"
"net/http"
"strconv"
"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/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
)
// BlockRewardsFetcher is a interface that provides access to reward related responses
type BlockRewardsFetcher interface {
GetBlockRewardsData(context.Context, interfaces.ReadOnlySignedBeaconBlock) (*BlockRewards, *http2.DefaultErrorJson)
GetStateForRewards(context.Context, interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, *http2.DefaultErrorJson)
}
// BlockRewardService implements BlockRewardsFetcher and can be declared to access the underlying functions
type BlockRewardService struct {
Replayer stategen.ReplayerBuilder
}
// GetBlockRewardsData returns the BlockRewards Object which is used for the BlockRewardsResponse and ProduceBlockV3
func (rs *BlockRewardService) GetBlockRewardsData(ctx context.Context, blk interfaces.ReadOnlySignedBeaconBlock) (*BlockRewards, *http2.DefaultErrorJson) {
st, httpErr := rs.GetStateForRewards(ctx, blk)
if httpErr != nil {
return nil, httpErr
}
proposerIndex := blk.Block().ProposerIndex()
initBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, blk)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get attestation rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
attBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
st, err = coreblocks.ProcessAttesterSlashings(ctx, st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get attester slashing rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
st, err = coreblocks.ProcessProposerSlashings(ctx, st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get proposer slashing rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
sa, err := blk.Block().Body().SyncAggregate()
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get sync aggregate: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
var syncCommitteeReward uint64
_, syncCommitteeReward, err = altair.ProcessSyncAggregate(ctx, st, sa)
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get sync aggregate rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
return &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),
}, nil
}
// GetStateForRewards returns the state replayed up to the block's slot
func (rs *BlockRewardService) GetStateForRewards(ctx context.Context, blk interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, *http2.DefaultErrorJson) {
// 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 := rs.Replayer.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(ctx, blk.Block().Slot())
if err != nil {
return nil, &http2.DefaultErrorJson{
Message: "Could not get state: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
return st, nil
}

View File

@@ -1,9 +1,9 @@
package rewards
type BlockRewardsResponse struct {
Data BlockRewards `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
Data *BlockRewards `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}
type BlockRewards struct {

View File

@@ -0,0 +1,14 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["mock.go"],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards/testing",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/rpc/eth/rewards:go_default_library",
"//beacon-chain/state:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//network/http:go_default_library",
],
)

View File

@@ -0,0 +1,30 @@
package testing
import (
"context"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
)
type MockBlockRewardFetcher struct {
Rewards *rewards.BlockRewards
Error *http2.DefaultErrorJson
State state.BeaconState
}
func (m *MockBlockRewardFetcher) GetBlockRewardsData(_ context.Context, _ interfaces.ReadOnlySignedBeaconBlock) (*rewards.BlockRewards, *http2.DefaultErrorJson) {
if m.Error != nil {
return nil, m.Error
}
return m.Rewards, nil
}
func (m *MockBlockRewardFetcher) GetStateForRewards(_ context.Context, _ interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, *http2.DefaultErrorJson) {
if m.Error != nil {
return nil, m.Error
}
return m.State, nil
}

View File

@@ -162,7 +162,7 @@ const (
}`
AltairBlock = `{
"message": {
"slot": "1",
"slot": "2",
"proposer_index": "1",
"parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
@@ -204,7 +204,7 @@ const (
"attesting_indices": [
"1"
],
"signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"signature": "0xabb0124c7574f281a293f4185cad3cb22681d520917ce46665243eacb051000d8bacf75e1451870ca6b3b9e6c9d41a7b02ead2685a84188a4fafd3825daf6a989625d719ccd2d83a40101f4a453fca62878c890eca622363f9ddb8f367a91e84",
"data": {
"slot": "1",
"index": "1",
@@ -223,18 +223,18 @@ const (
"attesting_indices": [
"1"
],
"signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"signature": "0xabb0124c7574f281a293f4185cad3cb22681d520917ce46665243eacb051000d8bacf75e1451870ca6b3b9e6c9d41a7b02ead2685a84188a4fafd3825daf6a989625d719ccd2d83a40101f4a453fca62878c890eca622363f9ddb8f367a91e84",
"data": {
"slot": "1",
"index": "1",
"beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"source": {
"epoch": "1",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f3"
},
"target": {
"epoch": "1",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f3"
}
}
}
@@ -242,18 +242,18 @@ const (
],
"attestations": [
{
"aggregation_bits": "0xffffffffffffffffffffffffffffffffff3f",
"signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"aggregation_bits": "0x07",
"signature": "0xabb0124c7574f281a293f4185cad3cb22681d520917ce46665243eacb051000d8bacf75e1451870ca6b3b9e6c9d41a7b02ead2685a84188a4fafd3825daf6a989625d719ccd2d83a40101f4a453fca62878c890eca622363f9ddb8f367a91e84",
"data": {
"slot": "1",
"index": "1",
"slot": "0",
"index": "0",
"beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"source": {
"epoch": "1",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
},
"target": {
"epoch": "1",
"epoch": "0",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
}
}

View File

@@ -26,6 +26,7 @@ go_library(
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/rpc/core:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/eth/rewards:go_default_library",
"//beacon-chain/rpc/eth/shared:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/state:go_default_library",
@@ -33,6 +34,8 @@ go_library(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
@@ -75,6 +78,8 @@ go_test(
"//beacon-chain/operations/synccommittee:go_default_library",
"//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/rpc/core:go_default_library",
"//beacon-chain/rpc/eth/rewards:go_default_library",
"//beacon-chain/rpc/eth/rewards/testing:go_default_library",
"//beacon-chain/rpc/eth/shared:go_default_library",
"//beacon-chain/rpc/eth/shared/testing:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",

View File

@@ -9,8 +9,11 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/api"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -84,16 +87,26 @@ func (s *Server) produceBlockV3(ctx context.Context, w http.ResponseWriter, r *h
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
consensusBlockValue, httpError := getConsensusBlockValue(ctx, s.BlockRewardFetcher, v1alpha1resp.Block)
if httpError != nil {
http2.WriteError(w, httpError)
return
}
w.Header().Set(api.ExecutionPayloadBlindedHeader, fmt.Sprintf("%v", v1alpha1resp.IsBlinded))
w.Header().Set(api.ExecutionPayloadValueHeader, fmt.Sprintf("%d", v1alpha1resp.PayloadValue))
w.Header().Set(api.ConsensusBlockValueHeader, consensusBlockValue)
phase0Block, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Phase0)
if ok {
// rewards aren't used in phase 0
handleProducePhase0V3(ctx, w, isSSZ, phase0Block, v1alpha1resp.PayloadValue)
return
}
altairBlock, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Altair)
if ok {
handleProduceAltairV3(ctx, w, isSSZ, altairBlock, v1alpha1resp.PayloadValue)
handleProduceAltairV3(ctx, w, isSSZ, altairBlock, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(ctx)
@@ -107,36 +120,82 @@ func (s *Server) produceBlockV3(ctx context.Context, w http.ResponseWriter, r *h
}
blindedBellatrixBlock, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_BlindedBellatrix)
if ok {
handleProduceBlindedBellatrixV3(ctx, w, isSSZ, blindedBellatrixBlock, v1alpha1resp.PayloadValue)
handleProduceBlindedBellatrixV3(ctx, w, isSSZ, blindedBellatrixBlock, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
bellatrixBlock, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Bellatrix)
if ok {
handleProduceBellatrixV3(ctx, w, isSSZ, bellatrixBlock, v1alpha1resp.PayloadValue)
handleProduceBellatrixV3(ctx, w, isSSZ, bellatrixBlock, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
blindedCapellaBlock, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_BlindedCapella)
if ok {
handleProduceBlindedCapellaV3(ctx, w, isSSZ, blindedCapellaBlock, v1alpha1resp.PayloadValue)
handleProduceBlindedCapellaV3(ctx, w, isSSZ, blindedCapellaBlock, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
capellaBlock, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Capella)
if ok {
handleProduceCapellaV3(ctx, w, isSSZ, capellaBlock, v1alpha1resp.PayloadValue)
handleProduceCapellaV3(ctx, w, isSSZ, capellaBlock, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
blindedDenebBlockContents, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_BlindedDeneb)
if ok {
handleProduceBlindedDenebV3(ctx, w, isSSZ, blindedDenebBlockContents, v1alpha1resp.PayloadValue)
handleProduceBlindedDenebV3(ctx, w, isSSZ, blindedDenebBlockContents, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
denebBlockContents, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Deneb)
if ok {
handleProduceDenebV3(ctx, w, isSSZ, denebBlockContents, v1alpha1resp.PayloadValue)
handleProduceDenebV3(ctx, w, isSSZ, denebBlockContents, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
}
func getConsensusBlockValue(ctx context.Context, blockRewardsFetcher rewards.BlockRewardsFetcher, i interface{} /* block as argument */) (string, *http2.DefaultErrorJson) {
var wrapper interfaces.ReadOnlySignedBeaconBlock
var err error
// TODO: we should not require this fake signed wrapper and fix associated functions in the future.
switch b := i.(type) {
case *eth.GenericBeaconBlock_Phase0:
//ignore for phase0
return "", nil
case *eth.GenericBeaconBlock_Altair:
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_Altair{Altair: &eth.SignedBeaconBlockAltair{Block: b.Altair}})
case *eth.GenericBeaconBlock_Bellatrix:
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_Bellatrix{Bellatrix: &eth.SignedBeaconBlockBellatrix{Block: b.Bellatrix}})
case *eth.GenericBeaconBlock_BlindedBellatrix:
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_BlindedBellatrix{BlindedBellatrix: &eth.SignedBlindedBeaconBlockBellatrix{Block: b.BlindedBellatrix}})
case *eth.GenericBeaconBlock_Capella:
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_Capella{Capella: &eth.SignedBeaconBlockCapella{Block: b.Capella}})
case *eth.GenericBeaconBlock_BlindedCapella:
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_BlindedCapella{BlindedCapella: &eth.SignedBlindedBeaconBlockCapella{Block: b.BlindedCapella}})
case *eth.GenericBeaconBlock_Deneb:
// no need for sidecar
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_Deneb{Deneb: &eth.SignedBeaconBlockAndBlobsDeneb{Block: &eth.SignedBeaconBlockDeneb{Block: b.Deneb.Block}}})
case *eth.GenericBeaconBlock_BlindedDeneb:
// no need for sidecar
wrapper, err = blocks.NewSignedBeaconBlock(&eth.GenericSignedBeaconBlock_BlindedDeneb{BlindedDeneb: &eth.SignedBlindedBeaconBlockAndBlobsDeneb{SignedBlindedBlock: &eth.SignedBlindedBeaconBlockDeneb{Message: b.BlindedDeneb.Block}}})
default:
return "", &http2.DefaultErrorJson{
Message: fmt.Errorf("type %T is not supported", b).Error(),
Code: http.StatusInternalServerError,
}
}
if err != nil {
return "", &http2.DefaultErrorJson{
Message: err.Error(),
Code: http.StatusInternalServerError,
}
}
//get consensus payload value which is the same as the total from the block rewards api
blockRewards, httpError := blockRewardsFetcher.GetBlockRewardsData(ctx, wrapper)
if httpError != nil {
return "", httpError
}
return blockRewards.Total, nil
}
func handleProducePhase0V3(
ctx context.Context,
w http.ResponseWriter,
@@ -169,6 +228,7 @@ func handleProducePhase0V3(
Version: version.String(version.Phase0),
ExecutionPayloadBlinded: false,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue), // mev not available at this point
ConsensusBlockValue: "", // rewards not applicable before altair
Data: jsonBytes,
})
}
@@ -178,10 +238,12 @@ func handleProduceAltairV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_Altair,
payloadValue uint64,
executionPayloadValue uint64,
consensusPayloadValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceAltairV3")
defer span.End()
if isSSZ {
sszResp, err := blk.Altair.MarshalSSZ()
if err != nil {
@@ -204,7 +266,8 @@ func handleProduceAltairV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Altair),
ExecutionPayloadBlinded: false,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue), // mev not available at this point
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue), // mev not available at this point
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
@@ -214,7 +277,8 @@ func handleProduceBellatrixV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_Bellatrix,
payloadValue uint64,
executionPayloadValue uint64,
consensusPayloadValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceBellatrixV3")
defer span.End()
@@ -240,7 +304,8 @@ func handleProduceBellatrixV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Bellatrix),
ExecutionPayloadBlinded: false,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue), // mev not available at this point
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue), // mev not available at this point
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
@@ -250,7 +315,8 @@ func handleProduceBlindedBellatrixV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_BlindedBellatrix,
payloadValue uint64,
executionPayloadValue uint64,
consensusPayloadValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceBlindedBellatrixV3")
defer span.End()
@@ -276,7 +342,8 @@ func handleProduceBlindedBellatrixV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Bellatrix),
ExecutionPayloadBlinded: true,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue),
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue),
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
@@ -286,7 +353,8 @@ func handleProduceBlindedCapellaV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_BlindedCapella,
payloadValue uint64,
executionPayloadValue uint64,
consensusPayloadValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceBlindedCapellaV3")
defer span.End()
@@ -312,7 +380,8 @@ func handleProduceBlindedCapellaV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Capella),
ExecutionPayloadBlinded: true,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue),
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue),
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
@@ -322,7 +391,8 @@ func handleProduceCapellaV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_Capella,
payloadValue uint64,
executionPayloadValue uint64,
consensusPayloadValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceCapellaV3")
defer span.End()
@@ -348,7 +418,8 @@ func handleProduceCapellaV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Capella),
ExecutionPayloadBlinded: false,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue), // mev not available at this point
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue), // mev not available at this point
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
@@ -358,7 +429,8 @@ func handleProduceBlindedDenebV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_BlindedDeneb,
payloadValue uint64,
executionPayloadValue uint64,
consensusPayloadValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceBlindedDenebV3")
defer span.End()
@@ -384,7 +456,8 @@ func handleProduceBlindedDenebV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Deneb),
ExecutionPayloadBlinded: true,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue),
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue),
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
@@ -394,7 +467,8 @@ func handleProduceDenebV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_Deneb,
payloadValue uint64,
executionPayloadValue uint64,
consensusBlockValue string,
) {
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV3.internal.handleProduceDenebV3")
defer span.End()
@@ -420,7 +494,8 @@ func handleProduceDenebV3(
http2.WriteJson(w, &ProduceBlockV3Response{
Version: version.String(version.Deneb),
ExecutionPayloadBlinded: false,
ExecutionPayloadValue: fmt.Sprintf("%d", payloadValue), // mev not available at this point
ExecutionPayloadValue: fmt.Sprintf("%d", executionPayloadValue), // mev not available at this point
ConsensusBlockValue: consensusBlockValue,
Data: jsonBytes,
})
}

View File

@@ -12,6 +12,8 @@ import (
"github.com/golang/mock/gomock"
"github.com/prysmaticlabs/prysm/v4/api"
blockchainTesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards"
rewardtesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
rpctesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared/testing"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
@@ -46,26 +48,31 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"phase0","execution_payload_blinded":false,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"phase0","execution_payload_blinded":false,"execution_payload_value":"0","consensus_block_value":"","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "", true)
})
t.Run("Altair", func(t *testing.T) {
var block *shared.SignedBeaconBlockAltair
err := json.Unmarshal([]byte(rpctesting.AltairBlock), &block)
require.NoError(t, err)
jsonBytes, err := json.Marshal(block.Message)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), gomock.Any()).Return(
func() (*eth.GenericBeaconBlock, error) {
return block.Message.ToGeneric()
}())
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -74,11 +81,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"altair","execution_payload_blinded":false,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"altair","execution_payload_blinded":false,"execution_payload_value":"0","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Bellatrix", func(t *testing.T) {
var block *shared.SignedBeaconBlockBellatrix
@@ -92,10 +100,12 @@ func TestProduceBlockV3(t *testing.T) {
return block.Message.ToGeneric()
}())
mockChainService := &blockchainTesting.ChainService{}
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -104,11 +114,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"bellatrix","execution_payload_blinded":false,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"bellatrix","execution_payload_blinded":false,"execution_payload_value":"0","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("BlindedBellatrix", func(t *testing.T) {
var block *shared.SignedBlindedBeaconBlockBellatrix
@@ -122,10 +133,12 @@ func TestProduceBlockV3(t *testing.T) {
return block.Message.ToGeneric()
}())
mockChainService := &blockchainTesting.ChainService{}
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -134,11 +147,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"bellatrix","execution_payload_blinded":true,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"bellatrix","execution_payload_blinded":true,"execution_payload_value":"0","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "true", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Capella", func(t *testing.T) {
var block *shared.SignedBeaconBlockCapella
@@ -152,10 +166,12 @@ func TestProduceBlockV3(t *testing.T) {
return block.Message.ToGeneric()
}())
mockChainService := &blockchainTesting.ChainService{}
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -164,11 +180,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"capella","execution_payload_blinded":false,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"capella","execution_payload_blinded":false,"execution_payload_value":"0","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Blinded Capella", func(t *testing.T) {
var block *shared.SignedBlindedBeaconBlockCapella
@@ -185,10 +202,12 @@ func TestProduceBlockV3(t *testing.T) {
return g, err
}())
mockChainService := &blockchainTesting.ChainService{}
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -197,11 +216,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"capella","execution_payload_blinded":true,"execution_payload_value":"2000","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"capella","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "true", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "2000", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Deneb", func(t *testing.T) {
var block *shared.SignedBeaconBlockContentsDeneb
@@ -215,10 +235,12 @@ func TestProduceBlockV3(t *testing.T) {
return block.ToUnsigned().ToGeneric()
}())
mockChainService := &blockchainTesting.ChainService{}
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -227,11 +249,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"deneb","execution_payload_blinded":false,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"deneb","execution_payload_blinded":false,"execution_payload_value":"0","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Blinded Deneb", func(t *testing.T) {
var block *shared.SignedBlindedBeaconBlockContentsDeneb
@@ -245,10 +268,12 @@ func TestProduceBlockV3(t *testing.T) {
return block.ToUnsigned().ToGeneric()
}())
mockChainService := &blockchainTesting.ChainService{}
mockRewards := &rewards.BlockRewards{Total: "10"}
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -257,11 +282,12 @@ func TestProduceBlockV3(t *testing.T) {
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"deneb","execution_payload_blinded":true,"execution_payload_value":"0","data":%s}`, string(jsonBytes))
want := fmt.Sprintf(`{"version":"deneb","execution_payload_blinded":true,"execution_payload_value":"0","consensus_block_value":"10","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "true", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("invalid query parameter slot empty", func(t *testing.T) {
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
@@ -321,6 +347,7 @@ func TestProduceBlockV3(t *testing.T) {
func TestProduceBlockV3SSZ(t *testing.T) {
ctrl := gomock.NewController(t)
mockRewards := &rewards.BlockRewards{Total: "10"}
t.Run("Phase 0", func(t *testing.T) {
var block *shared.SignedBeaconBlock
err := json.Unmarshal([]byte(rpctesting.Phase0Block), &block)
@@ -351,6 +378,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "", true)
})
t.Run("Altair", func(t *testing.T) {
var block *shared.SignedBeaconBlockAltair
@@ -361,9 +389,11 @@ func TestProduceBlockV3SSZ(t *testing.T) {
func() (*eth.GenericBeaconBlock, error) {
return block.Message.ToGeneric()
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -382,6 +412,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Bellatrix", func(t *testing.T) {
var block *shared.SignedBeaconBlockBellatrix
@@ -397,6 +428,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -415,6 +447,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("BlindedBellatrix", func(t *testing.T) {
var block *shared.SignedBlindedBeaconBlockBellatrix
@@ -430,6 +463,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -448,6 +482,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "true", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Capella", func(t *testing.T) {
var block *shared.SignedBeaconBlockCapella
@@ -463,6 +498,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -481,6 +517,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Blinded Capella", func(t *testing.T) {
var block *shared.SignedBlindedBeaconBlockCapella
@@ -499,6 +536,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -517,6 +555,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "true", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "2000", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Deneb", func(t *testing.T) {
var block *shared.SignedBeaconBlockContentsDeneb
@@ -532,6 +571,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -550,6 +590,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "false", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
t.Run("Blinded Deneb", func(t *testing.T) {
var block *shared.SignedBlindedBeaconBlockContentsDeneb
@@ -565,6 +606,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
V1Alpha1Server: v1alpha1Server,
SyncChecker: &mockSync.Sync{IsSyncing: false},
OptimisticModeFetcher: mockChainService,
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: mockRewards},
}
rr := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +
"&graffiti=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
@@ -583,5 +625,6 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, writer.Header().Get(api.ExecutionPayloadBlindedHeader) == "true", true)
require.Equal(t, writer.Header().Get(api.ExecutionPayloadValueHeader) == "0", true)
require.Equal(t, writer.Header().Get(api.ConsensusBlockValueHeader) == "10", true)
})
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/core"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -34,4 +35,5 @@ type Server struct {
BlockBuilder builder.BlockBuilder
OperationNotifier operation.Notifier
CoreService *core.Service
BlockRewardFetcher rewards.BlockRewardsFetcher
}

View File

@@ -78,6 +78,7 @@ type ProduceBlockV3Response struct {
Version string `json:"version"`
ExecutionPayloadBlinded bool `json:"execution_payload_blinded"`
ExecutionPayloadValue string `json:"execution_payload_value"`
ConsensusBlockValue string `json:"consensus_block_value"`
Data json.RawMessage `json:"data"` // represents the block values based on the version
}

View File

@@ -211,15 +211,15 @@ func (s *Service) Start() {
BeaconDB: s.cfg.BeaconDB,
ChainInfoFetcher: s.cfg.ChainInfoFetcher,
}
rewardFetcher := &rewards.BlockRewardService{Replayer: ch}
rewardsServer := &rewards.Server{
Blocker: blocker,
OptimisticModeFetcher: s.cfg.OptimisticModeFetcher,
FinalizationFetcher: s.cfg.FinalizationFetcher,
ReplayerBuilder: ch,
TimeFetcher: s.cfg.GenesisTimeFetcher,
Stater: stater,
HeadFetcher: s.cfg.HeadFetcher,
BlockRewardFetcher: rewardFetcher,
}
s.cfg.Router.HandleFunc("/eth/v1/beacon/rewards/blocks/{block_id}", rewardsServer.BlockRewards).Methods(http.MethodGet)
@@ -304,6 +304,7 @@ func (s *Service) Start() {
BlockBuilder: s.cfg.BlockBuilder,
OperationNotifier: s.cfg.OperationNotifier,
CoreService: coreService,
BlockRewardFetcher: rewardFetcher,
}
s.cfg.Router.HandleFunc("/eth/v1/validator/aggregate_attestation", validatorServerV1.GetAggregateAttestation).Methods(http.MethodGet)

View File

@@ -73,7 +73,8 @@ func AttestingIndices(bf bitfield.Bitfield, committee []primitives.ValidatorInde
return nil, fmt.Errorf("bitfield length %d is not equal to committee length %d", bf.Len(), len(committee))
}
indices := make([]uint64, 0, bf.Count())
for _, idx := range bf.BitIndices() {
p := bf.BitIndices()
for _, idx := range p {
if idx < len(committee) {
indices = append(indices, uint64(committee[idx]))
}
@@ -104,6 +105,7 @@ func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedA
ctx, span := trace.StartSpan(ctx, "attestationutil.VerifyIndexedAttestationSig")
defer span.End()
indices := indexedAtt.AttestingIndices
messageHash, err := signing.ComputeSigningRoot(indexedAtt.Data, domain)
if err != nil {
return errors.Wrap(err, "could not get signing root of object")