erigon-pulse/cl/beacon/handler/headers.go
2023-10-18 23:10:53 +02:00

130 lines
3.5 KiB
Go

package handler
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/persistence/beacon_indicies"
)
func (a *ApiHandler) getHeaders(r *http.Request) (data any, finalized *bool, version *clparams.StateVersion, httpStatus int, err error) {
ctx := r.Context()
req := &getHeadersRequest{}
finalized = new(bool)
*finalized = true
// Try to decode the request body into the struct. If there is an error,
// respond to the client with the error message and a 400 status code.
err = json.NewDecoder(r.Body).Decode(&req)
if errors.Is(err, io.EOF) {
req = nil
} else if err != nil {
err = fmt.Errorf("error while decoding json: %s", err)
httpStatus = http.StatusBadRequest
return
}
var tx kv.Tx
tx, err = a.indiciesDB.BeginRo(ctx)
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
defer tx.Rollback()
var headersList []*cltypes.SignedBeaconBlockHeader
var canonicals []bool
// 4 Cases empty request, only slot, only parent_root, both.
if req == nil || (req.ParentRoot == nil && req.Slot == nil) { // case 1 empty request
var headSlot uint64
_, headSlot, err = a.forkchoiceStore.GetHead()
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
headersList, canonicals, err = beacon_indicies.ReadSignedHeadersBySlot(ctx, tx, headSlot)
} else if req.Slot != nil {
headersList, canonicals, err = beacon_indicies.ReadSignedHeadersBySlot(ctx, tx, *req.Slot)
} else if req.ParentRoot != nil {
headersList, canonicals, err = beacon_indicies.ReadSignedHeadersByParentRoot(ctx, tx, *req.ParentRoot)
}
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
if len(headersList) == 0 {
*finalized = false
}
resp := []*headerResponse{}
for idx, header := range headersList {
var headerRoot libcommon.Hash
headerRoot, err = header.HashSSZ()
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
if !canonicals[idx] || header.Header.Slot > a.forkchoiceStore.FinalizedSlot() {
*finalized = false
}
resp = append(resp, &headerResponse{
Root: headerRoot,
Canonical: canonicals[idx],
Header: header,
})
}
httpStatus = http.StatusAccepted
data = resp
return
}
func (a *ApiHandler) getHeader(r *http.Request) (data any, finalized *bool, version *clparams.StateVersion, httpStatus int, err error) {
ctx := r.Context()
tx, err2 := a.indiciesDB.BeginRo(ctx)
if err2 != nil {
httpStatus = http.StatusInternalServerError
err = err2
return
}
defer tx.Rollback()
blockId, err2 := blockIdFromRequest(r)
if err2 != nil {
httpStatus = http.StatusBadRequest
err = err2
return
}
root, httpStatus2, err2 := a.rootFromBlockId(ctx, tx, blockId)
if err2 != nil {
httpStatus = httpStatus2
err = err2
return
}
signedHeader, isCanonical, err2 := beacon_indicies.ReadSignedHeaderByBlockRoot(ctx, tx, root)
if err2 != nil {
httpStatus = http.StatusInternalServerError
err = err2
return
}
if signedHeader == nil {
httpStatus = http.StatusNotFound
err = fmt.Errorf("could not read block header: %x", root)
return
}
data = &headerResponse{
Root: root,
Canonical: isCanonical,
Header: signedHeader,
}
finalized = new(bool)
*finalized = isCanonical && signedHeader.Header.Slot <= a.forkchoiceStore.FinalizedSlot()
httpStatus = http.StatusAccepted
return
}