Skip to content
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

(BIDS 3226) API: Block Details v2 (Internal) #637

Merged
merged 7 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions backend/pkg/api/data_access/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package dataaccess

import (
"context"

t "github.com/gobitfly/beaconchain/pkg/api/types"
)

type BlockRepository interface {
GetBlock(ctx context.Context, chainId, block uint64) (*t.BlockSummary, error)
GetBlockOverview(ctx context.Context, chainId, block uint64) (*t.BlockOverview, error)
GetBlockTransactions(ctx context.Context, chainId, block uint64) ([]t.BlockTransactionTableRow, error)
GetBlockVotes(ctx context.Context, chainId, block uint64) ([]t.BlockVoteTableRow, error)
GetBlockAttestations(ctx context.Context, chainId, block uint64) ([]t.BlockAttestationTableRow, error)
GetBlockWithdrawals(ctx context.Context, chainId, block uint64) ([]t.BlockWithdrawalTableRow, error)
GetBlockBlsChanges(ctx context.Context, chainId, block uint64) ([]t.BlockBlsChangeTableRow, error)
GetBlockVoluntaryExits(ctx context.Context, chainId, block uint64) ([]t.BlockVoluntaryExitTableRow, error)
GetBlockBlobs(ctx context.Context, chainId, block uint64) ([]t.BlockBlobTableRow, error)
}

func (d *DataAccessService) GetBlock(ctx context.Context, chainId, block uint64) (*t.BlockSummary, error) {
// @DATA-ACCESS
return d.dummy.GetBlock(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockOverview(ctx context.Context, chainId, block uint64) (*t.BlockOverview, error) {
// @DATA-ACCESS
return d.dummy.GetBlockOverview(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockTransactions(ctx context.Context, chainId, block uint64) ([]t.BlockTransactionTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockTransactions(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockVotes(ctx context.Context, chainId, block uint64) ([]t.BlockVoteTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockVotes(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockAttestations(ctx context.Context, chainId, block uint64) ([]t.BlockAttestationTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockAttestations(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockWithdrawals(ctx context.Context, chainId, block uint64) ([]t.BlockWithdrawalTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockWithdrawals(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockBlsChanges(ctx context.Context, chainId, block uint64) ([]t.BlockBlsChangeTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockBlsChanges(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockVoluntaryExits(ctx context.Context, chainId, block uint64) ([]t.BlockVoluntaryExitTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockVoluntaryExits(ctx, chainId, block)
}

func (d *DataAccessService) GetBlockBlobs(ctx context.Context, chainId, block uint64) ([]t.BlockBlobTableRow, error) {
// @DATA-ACCESS
return d.dummy.GetBlockBlobs(ctx, chainId, block)
}
2 changes: 2 additions & 0 deletions backend/pkg/api/data_access/data_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ type DataAccessor interface {
UserRepository
NotificationsRepository
AdminRepository
BlockRepository

Close()

GetLatestSlot() (uint64, error)
GetLatestBlock() (uint64, error)
GetLatestExchangeRates() ([]t.EthConversionRate, error)

GetProductSummary(ctx context.Context) (*t.ProductSummary, error)
Expand Down
60 changes: 60 additions & 0 deletions backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ func (d *DummyService) GetLatestSlot() (uint64, error) {
return r, err
}

func (d *DummyService) GetLatestBlock() (uint64, error) {
r := uint64(0)
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetLatestExchangeRates() ([]t.EthConversionRate, error) {
r := []t.EthConversionRate{}
err := commonFakeData(&r)
Expand Down Expand Up @@ -618,3 +624,57 @@ func (d *DummyService) UpdateAdConfiguration(ctx context.Context, key, jquerySel
func (d *DummyService) RemoveAdConfiguration(ctx context.Context, key string) error {
return nil
}

func (d *DummyService) GetBlock(ctx context.Context, chainId, block uint64) (*t.BlockSummary, error) {
r := t.BlockSummary{}
err := commonFakeData(&r)
return &r, err
}

func (d *DummyService) GetBlockOverview(ctx context.Context, chainId, block uint64) (*t.BlockOverview, error) {
r := t.BlockOverview{}
err := commonFakeData(&r)
return &r, err
}

func (d *DummyService) GetBlockTransactions(ctx context.Context, chainId, block uint64) ([]t.BlockTransactionTableRow, error) {
r := []t.BlockTransactionTableRow{}
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetBlockVotes(ctx context.Context, chainId, block uint64) ([]t.BlockVoteTableRow, error) {
r := []t.BlockVoteTableRow{}
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetBlockAttestations(ctx context.Context, chainId, block uint64) ([]t.BlockAttestationTableRow, error) {
r := []t.BlockAttestationTableRow{}
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetBlockWithdrawals(ctx context.Context, chainId, block uint64) ([]t.BlockWithdrawalTableRow, error) {
r := []t.BlockWithdrawalTableRow{}
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetBlockBlsChanges(ctx context.Context, chainId, block uint64) ([]t.BlockBlsChangeTableRow, error) {
r := []t.BlockBlsChangeTableRow{}
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetBlockVoluntaryExits(ctx context.Context, chainId, block uint64) ([]t.BlockVoluntaryExitTableRow, error) {
r := []t.BlockVoluntaryExitTableRow{}
err := commonFakeData(&r)
return r, err
}

func (d *DummyService) GetBlockBlobs(ctx context.Context, chainId, block uint64) ([]t.BlockBlobTableRow, error) {
r := []t.BlockBlobTableRow{}
err := commonFakeData(&r)
return r, err
}
5 changes: 5 additions & 0 deletions backend/pkg/api/data_access/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ func (d *DataAccessService) GetLatestSlot() (uint64, error) {
return latestSlot, nil
}

func (d *DataAccessService) GetLatestBlock() (uint64, error) {
// @DATA-ACCESS implement
return d.dummy.GetLatestBlock()
}

func (d *DataAccessService) GetLatestExchangeRates() ([]t.EthConversionRate, error) {
result := []t.EthConversionRate{}

Expand Down
37 changes: 30 additions & 7 deletions backend/pkg/api/handlers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,31 @@ func (h *HandlerService) getDashboardPremiumPerks(ctx context.Context, id types.
return &userInfo.PremiumPerks, nil
}

// helper function to unify handling of block detail request validation
func (h *HandlerService) validateBlockRequest(r *http.Request) (uint64, uint64, error) {
var v validationError
req := struct {
Network intOrString `json:"network"`
Block string `json:"block"`
}{}
if err := v.checkBody(&req, r); err != nil {
return 0, 0, err
}
chainId := v.checkNetwork(req.Network)
LuccaBitfly marked this conversation as resolved.
Show resolved Hide resolved
block, err := h.dai.GetLatestBlock()
if err != nil {
return 0, 0, err
}
if req.Block != "latest" {
block = v.checkUintMinMax(req.Block, 0, block, "block")
}
LuccaBitfly marked this conversation as resolved.
Show resolved Hide resolved
if v.hasErrors() {
return 0, 0, v
}

return chainId, block, nil
}

// checkGroupId validates the given group id and returns it as an int64.
// If the given group id is empty and allowEmpty is true, it returns -1 (all groups).
func (v *validationError) checkGroupId(param string, allowEmpty bool) int64 {
Expand Down Expand Up @@ -416,6 +441,10 @@ func checkMinMax[T number](v *validationError, param T, min T, max T, paramName
return param
}

func (v *validationError) checkUintMinMax(param string, min uint64, max uint64, paramName string) uint64 {
return checkMinMax(v, v.checkUint(param, paramName), min, max, paramName)
}

func (v *validationError) checkPagingParams(q url.Values) Paging {
paging := Paging{
cursor: q.Get("cursor"),
Expand All @@ -424,13 +453,7 @@ func (v *validationError) checkPagingParams(q url.Values) Paging {
}

if limitStr := q.Get("limit"); limitStr != "" {
limit, err := strconv.ParseUint(limitStr, 10, 64)
if err != nil {
v.add("limit", fmt.Sprintf("given value '%s' is not a valid positive integer", limitStr))
return paging
}
checkMinMax(v, limit, 1, maxQueryLimit, "limit")
paging.limit = limit
paging.limit = v.checkUintMinMax(limitStr, 1, maxQueryLimit, "limit")
}

if paging.cursor != "" {
Expand Down
173 changes: 173 additions & 0 deletions backend/pkg/api/handlers/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1898,3 +1898,176 @@ func (h *HandlerService) InternalPostUserNotificationsTestWebhook(w http.Respons
// TODO
returnOk(w, nil)
}

// --------------------------------------
// Blocks

func (h *HandlerService) InternalGetBlock(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlock(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockResponse{
Data: *data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockOverview(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockOverview(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}
response := types.InternalGetBlockOverviewResponse{
Data: *data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockTransactions(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockTransactions(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockTransactionsResponse{
Data: data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockVotes(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockVotes(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockVotesResponse{
Data: data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockAttestations(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockAttestations(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockAttestationsResponse{
Data: data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockWithdrawals(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockWithdrawals(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockWtihdrawalsResponse{
Data: data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockBlsChanges(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockBlsChanges(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockBlsChangesResponse{
Data: data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockVoluntaryExits(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockVoluntaryExits(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockVoluntaryExitsResponse{
Data: data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalGetBlockBlobs(w http.ResponseWriter, r *http.Request) {
chainId, block, err := h.validateBlockRequest(r)
if err != nil {
handleErr(w, err)
return
}

data, err := h.dai.GetBlockBlobs(r.Context(), chainId, block)
if err != nil {
handleErr(w, err)
return
}

response := types.InternalGetBlockBlobsResponse{
Data: data,
}
returnOk(w, response)
}
Loading
Loading