-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Deneb: Produce Block V3 - adding consensus block value #12948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
fa70ca8
d7e6b69
5f420be
c47c1db
8a16eda
4e4173c
951d6d0
0691dcb
2ee830f
26e6d89
62ed6e6
bcbe594
414fbd0
e0d9b7f
70e01d9
3ebc9ea
a9e9a45
bb6f588
fb72677
3e4011f
c956e13
c109cb5
a4586f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package rewards | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "net/http" | ||
|
|
@@ -23,10 +24,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] | ||
|
|
||
|
|
@@ -43,136 +47,134 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) { | |
| http2.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()) | ||
| optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context()) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get state: " + err.Error(), | ||
| Message: "Could not get optimistic mode info: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| blkRoot, err := blk.Block().HashTreeRoot() | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get block root: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| blockRewards, httpError := s.BlockRewardFetcher.GetBlockRewardsData(ctx, blk) | ||
| if httpError != nil { | ||
| http2.WriteError(w, httpError) | ||
| return | ||
| } | ||
| response := &BlockRewardsResponse{ | ||
| Data: blockRewards, | ||
| ExecutionOptimistic: optimistic, | ||
| Finalized: s.FinalizationFetcher.IsFinalized(ctx, blkRoot), | ||
| } | ||
| http2.WriteJson(w, response) | ||
| } | ||
|
|
||
| // 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 { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get proposer's balance: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk) | ||
| st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, blk) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get attestation rewards" + err.Error(), | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get attestation rewards: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| attBalance, err := st.BalanceAtIndex(proposerIndex) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get proposer's balance: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator) | ||
| st, err = coreblocks.ProcessAttesterSlashings(ctx, st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get attester slashing rewards: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get proposer's balance: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator) | ||
| st, err = coreblocks.ProcessProposerSlashings(ctx, st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get proposer slashing rewards" + err.Error(), | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get proposer slashing rewards: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get proposer's balance: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| sa, err := blk.Block().Body().SyncAggregate() | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get sync aggregate: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| var syncCommitteeReward uint64 | ||
| _, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa) | ||
| _, syncCommitteeReward, err = altair.ProcessSyncAggregate(ctx, st, sa) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get sync aggregate rewards: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
|
|
||
| optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context()) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get optimistic mode info: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| blkRoot, err := blk.Block().HashTreeRoot() | ||
| 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 { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get block root: " + err.Error(), | ||
| return nil, &http2.DefaultErrorJson{ | ||
| Message: "Could not get state: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.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), | ||
| } | ||
| http2.WriteJson(w, response) | ||
| return st, nil | ||
| } | ||
|
|
||
| // AttestationRewards retrieves attestation reward info for validators specified by array of public keys or validator index. | ||
|
|
@@ -229,10 +231,12 @@ 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] | ||
|
|
||
| blk, err := s.Blocker.Block(r.Context(), []byte(blockId)) | ||
| blk, err := s.Blocker.Block(ctx, []byte(blockId)) | ||
| if errJson := handleGetBlockError(blk, err); errJson != nil { | ||
| http2.WriteError(w, errJson) | ||
| return | ||
|
|
@@ -245,13 +249,9 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) { | |
| http2.WriteError(w, errJson) | ||
| return | ||
| } | ||
| st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot()) | ||
| if err != nil { | ||
| errJson := &http2.DefaultErrorJson{ | ||
| Message: "Could not get state: " + err.Error(), | ||
| Code: http.StatusInternalServerError, | ||
| } | ||
| http2.WriteError(w, errJson) | ||
| st, httpErr := s.BlockRewardFetcher.GetStateForRewards(ctx, blk) | ||
| if httpErr != nil { | ||
| http2.WriteError(w, httpErr) | ||
| return | ||
| } | ||
| sa, err := blk.Block().Body().SyncAggregate() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,28 @@ | ||
| package rewards | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "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 retrieves the Consensus Payload ( aka block rewards) of the passed in block | ||
|
||
| type BlockRewardsFetcher interface { | ||
| GetBlockRewardsData(context.Context, interfaces.ReadOnlySignedBeaconBlock) (*BlockRewards, *http2.DefaultErrorJson) | ||
| GetStateForRewards(ctx context.Context, blk interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, *http2.DefaultErrorJson) | ||
| } | ||
|
||
|
|
||
| type BlockRewardService struct { | ||
| Replayer stategen.ReplayerBuilder | ||
| } | ||
|
|
||
| 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 { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should place the interface, the service struct and its methods in a new file.