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 all 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
146 changes: 146 additions & 0 deletions backend/pkg/api/data_access/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
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)

GetSlot(ctx context.Context, chainId, block uint64) (*t.BlockSummary, error)
GetSlotOverview(ctx context.Context, chainId, block uint64) (*t.BlockOverview, error)
GetSlotTransactions(ctx context.Context, chainId, block uint64) ([]t.BlockTransactionTableRow, error)
GetSlotVotes(ctx context.Context, chainId, block uint64) ([]t.BlockVoteTableRow, error)
GetSlotAttestations(ctx context.Context, chainId, block uint64) ([]t.BlockAttestationTableRow, error)
GetSlotWithdrawals(ctx context.Context, chainId, block uint64) ([]t.BlockWithdrawalTableRow, error)
GetSlotBlsChanges(ctx context.Context, chainId, block uint64) ([]t.BlockBlsChangeTableRow, error)
GetSlotVoluntaryExits(ctx context.Context, chainId, block uint64) ([]t.BlockVoluntaryExitTableRow, error)
GetSlotBlobs(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)
}

func (d *DataAccessService) GetSlot(ctx context.Context, chainId, slot uint64) (*t.BlockSummary, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlock(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotOverview(ctx context.Context, chainId, slot uint64) (*t.BlockOverview, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockOverview(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotTransactions(ctx context.Context, chainId, slot uint64) ([]t.BlockTransactionTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockTransactions(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotVotes(ctx context.Context, chainId, slot uint64) ([]t.BlockVoteTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockVotes(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotAttestations(ctx context.Context, chainId, slot uint64) ([]t.BlockAttestationTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockAttestations(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotWithdrawals(ctx context.Context, chainId, slot uint64) ([]t.BlockWithdrawalTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockWithdrawals(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotBlsChanges(ctx context.Context, chainId, slot uint64) ([]t.BlockBlsChangeTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockBlsChanges(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotVoluntaryExits(ctx context.Context, chainId, slot uint64) ([]t.BlockVoluntaryExitTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockVoluntaryExits(ctx, chainId, block)
}

func (d *DataAccessService) GetSlotBlobs(ctx context.Context, chainId, slot uint64) ([]t.BlockBlobTableRow, error) {
block, err := d.GetBlockHeightAt(slot)
if err != nil {
return nil, err
}
return d.GetBlockBlobs(ctx, chainId, block)
}
3 changes: 3 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,13 @@ type DataAccessor interface {
UserRepository
NotificationsRepository
AdminRepository
BlockRepository

Close()

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

GetProductSummary(ctx context.Context) (*t.ProductSummary, error)
Expand Down
120 changes: 120 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,18 @@ 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) GetBlockHeightAt(slot uint64) (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 @@ -646,3 +658,111 @@ 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
}

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

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

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

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

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

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

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

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

func (d *DummyService) GetSlotBlobs(ctx context.Context, chainId, block uint64) ([]t.BlockBlobTableRow, error) {
r := []t.BlockBlobTableRow{}
err := commonFakeData(&r)
return r, err
}
10 changes: 10 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,16 @@ 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) GetBlockHeightAt(slot uint64) (uint64, error) {
// @DATA-ACCESS implement; return error if no block at slot
return d.dummy.GetBlockHeightAt(slot)
}

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

Expand Down
39 changes: 32 additions & 7 deletions backend/pkg/api/handlers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/gobitfly/beaconchain/pkg/commons/log"
"github.com/gorilla/mux"
"github.com/invopop/jsonschema"
"github.com/xeipuuv/gojsonschema"

Expand Down Expand Up @@ -359,6 +360,32 @@ 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, paramName string) (uint64, uint64, error) {
var v validationError
var err error
chainId := v.checkNetworkParameter(mux.Vars(r)["network"])
var value uint64
switch paramValue := mux.Vars(r)[paramName]; paramValue {
// possibly add other values like "genesis", "finalized", hardforks etc. later
case "latest":
if paramName == "block" {
value, err = h.dai.GetLatestBlock()
} else if paramName == "slot" {
value, err = h.dai.GetLatestSlot()
}
if err != nil {
return 0, 0, err
}
default:
value = v.checkUint(paramValue, paramName)
}
if v.hasErrors() {
return 0, 0, v
}
return chainId, value, 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 @@ -420,6 +447,10 @@ func (v *validationError) checkAddress(publicId string) string {
return v.checkRegex(reEthereumAddress, publicId, "address")
}

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 @@ -428,13 +459,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
Loading
Loading