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

171 lines
4.7 KiB
Go

package handler
import (
"context"
"fmt"
"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"
"github.com/ledgerwatch/erigon/cl/utils"
)
func (a *ApiHandler) rootFromStateId(ctx context.Context, tx kv.Tx, stateId *segmentID) (root libcommon.Hash, httpStatusErr int, err error) {
var blockRoot libcommon.Hash
switch {
case stateId.head():
blockRoot, _, err = a.forkchoiceStore.GetHead()
if err != nil {
return libcommon.Hash{}, http.StatusInternalServerError, err
}
case stateId.finalized():
blockRoot = a.forkchoiceStore.FinalizedCheckpoint().BlockRoot()
case stateId.justified():
blockRoot = a.forkchoiceStore.JustifiedCheckpoint().BlockRoot()
case stateId.genesis():
blockRoot, err = beacon_indicies.ReadCanonicalBlockRoot(tx, 0)
if err != nil {
return libcommon.Hash{}, http.StatusInternalServerError, err
}
if blockRoot == (libcommon.Hash{}) {
return libcommon.Hash{}, http.StatusNotFound, fmt.Errorf("genesis block not found")
}
case stateId.getSlot() != nil:
blockRoot, err = beacon_indicies.ReadCanonicalBlockRoot(tx, *stateId.getSlot())
if err != nil {
return libcommon.Hash{}, http.StatusInternalServerError, err
}
if blockRoot == (libcommon.Hash{}) {
return libcommon.Hash{}, http.StatusNotFound, fmt.Errorf("block not found %d", *stateId.getSlot())
}
case stateId.getRoot() != nil:
root = *stateId.getRoot()
return
default:
return libcommon.Hash{}, http.StatusInternalServerError, fmt.Errorf("cannot parse state id")
}
root, err = beacon_indicies.ReadStateRootByBlockRoot(ctx, tx, blockRoot)
if err != nil {
return libcommon.Hash{}, http.StatusInternalServerError, err
}
if root == (libcommon.Hash{}) {
return libcommon.Hash{}, http.StatusNotFound, fmt.Errorf("block not found %d", *stateId.getSlot())
}
return
}
type rootResponse struct {
Root libcommon.Hash `json:"root"`
}
func previousVersion(v clparams.StateVersion) clparams.StateVersion {
if v == clparams.Phase0Version {
return clparams.Phase0Version
}
return v - 1
}
func (a *ApiHandler) getStateFork(r *http.Request) (data any, finalized *bool, version *clparams.StateVersion, httpStatus int, err error) {
var (
tx kv.Tx
blockId *segmentID
root libcommon.Hash
blkHeader *cltypes.SignedBeaconBlockHeader
)
ctx := r.Context()
tx, err = a.indiciesDB.BeginRo(ctx)
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
defer tx.Rollback()
blockId, err = stateIdFromRequest(r)
if err != nil {
httpStatus = http.StatusBadRequest
return
}
root, httpStatus, err = a.rootFromStateId(ctx, tx, blockId)
if err != nil {
return
}
blkHeader, _, err = beacon_indicies.ReadSignedHeaderByStateRoot(ctx, tx, root)
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
if blkHeader == nil {
err = fmt.Errorf("could not read block header: %x", root)
httpStatus = http.StatusNotFound
return
}
slot := blkHeader.Header.Slot
epoch := slot / a.beaconChainCfg.SlotsPerEpoch
stateVersion := a.beaconChainCfg.GetCurrentStateVersion(epoch)
currentVersion := a.beaconChainCfg.GetForkVersionByVersion(stateVersion)
previousVersion := a.beaconChainCfg.GetForkVersionByVersion(previousVersion(stateVersion))
data = &cltypes.Fork{
PreviousVersion: utils.Uint32ToBytes4(previousVersion),
CurrentVersion: utils.Uint32ToBytes4(currentVersion),
Epoch: epoch,
}
httpStatus = http.StatusAccepted
return
}
func (a *ApiHandler) getStateRoot(r *http.Request) (data any, finalized *bool, version *clparams.StateVersion, httpStatus int, err error) {
var (
tx kv.Tx
blockId *segmentID
root libcommon.Hash
blkHeader *cltypes.SignedBeaconBlockHeader
canonical bool
)
ctx := r.Context()
tx, err = a.indiciesDB.BeginRo(ctx)
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
defer tx.Rollback()
blockId, err = stateIdFromRequest(r)
if err != nil {
httpStatus = http.StatusBadRequest
return
}
root, httpStatus, err = a.rootFromStateId(ctx, tx, blockId)
if err != nil {
return
}
blkHeader, canonical, err = beacon_indicies.ReadSignedHeaderByStateRoot(ctx, tx, root)
if err != nil {
httpStatus = http.StatusInternalServerError
return
}
if blkHeader == nil {
err = fmt.Errorf("could not read block header: %x", root)
httpStatus = http.StatusNotFound
return
}
data = rootResponse{Root: blkHeader.Header.Root}
slot := blkHeader.Header.Slot
finalized = new(bool)
*finalized = canonical && slot <= a.forkchoiceStore.FinalizedSlot()
httpStatus = http.StatusAccepted
return
}