ipld-eth-beacon-indexer/pkg/beaconclient/processslot.go

139 lines
5.0 KiB
Go
Raw Normal View History

// This file will keep track of all the code needed to process a slot.
// To process a slot, it should have all the necessary data needed to write it to the DB.
// But not actually write it.
package beaconclient
import (
"encoding/hex"
"fmt"
"github.com/ferranbt/fastssz/spectests"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
)
var (
SlotUnmarshalError = "Unable to properly unmarshal the Slot field in the SignedBeaconBlock."
ParentRootUnmarshalError = "Unable to properly unmarshal the ParentRoot field in the SignedBeaconBlock."
MissingIdentifiedError = "Can't Query state without a set slot or block_root"
)
type ProcessSlot struct {
Slot string // The slot number.
BlockRoot string // The hex encoded string of the BlockRoot.
StateRoot string // The hex encoded string of the StateRoot.
ParentBlockRoot string // The hex encoded string of the parent block.
SszSignedBeaconBlock []byte // The entire SSZ encoded SignedBeaconBlock
SszBeaconState []byte // The entire SSZ encoded BeaconState
FullBeaconState *spectests.BeaconState // The unmarshaled BeaconState object, the unmarshalling could have errors.
FullSignedBeaconBlock *spectests.SignedBeaconBlock // The unmarshaled BeaconState object, the unmarshalling could have errors.
}
// This function will do all the work to process the slot at head.
func processHeadSlot(baseEndpoint string, slot string, blockRoot string, stateRoot string, parentBlockRoot string, previousSlot uint64, previousBlockRoot string) error {
pc := &ProcessSlot{
Slot: slot,
BlockRoot: blockRoot,
StateRoot: stateRoot,
ParentBlockRoot: parentBlockRoot,
}
err := pc.getSignedBeaconBlock(baseEndpoint)
if err != nil {
return err
}
err = pc.getBeaconState(baseEndpoint)
if err != nil {
return err
}
// Handle any reorgs or skipped slots.
if previousSlot != 0 && previousBlockRoot != "" {
pc.checkPreviousSlot(previousSlot, previousBlockRoot)
}
// Get this object ready to write
// Write the object to the DB.
return nil
}
// Update the SszSignedBeaconBlock and FullSignedBeaconBlock object with their respective values.
func (ps *ProcessSlot) getSignedBeaconBlock(baseEndpoint string) error {
var blockIdentifier string // Used to query the block
if ps.BlockRoot != "" {
blockIdentifier = ps.BlockRoot
} else if ps.Slot != "" {
blockIdentifier = ps.Slot
} else {
log.Error(MissingIdentifiedError)
return fmt.Errorf(MissingIdentifiedError)
}
blockEndpoint := baseEndpoint + blockIdentifier
ps.SszSignedBeaconBlock, _ = querySsz(blockEndpoint, ps.Slot)
ps.FullSignedBeaconBlock = new(spectests.SignedBeaconBlock)
err := ps.FullSignedBeaconBlock.UnmarshalSSZ(ps.SszSignedBeaconBlock)
if err != nil {
if ps.FullSignedBeaconBlock.Block.Slot == 0 {
loghelper.LogSlotError(ps.Slot, err).Error(SlotUnmarshalError)
return fmt.Errorf(SlotUnmarshalError)
} else if ps.FullSignedBeaconBlock.Block.ParentRoot == nil {
loghelper.LogSlotError(ps.Slot, err).Error(ParentRootUnmarshalError)
return fmt.Errorf(ParentRootUnmarshalError)
}
}
return nil
}
// Update the SszBeaconState and FullBeaconState object with their respective values.
func (ps *ProcessSlot) getBeaconState(baseEndpoint string) error {
var stateIdentifier string // Used to query the state
if ps.StateRoot != "" {
stateIdentifier = ps.BlockRoot
} else if ps.Slot != "" {
stateIdentifier = ps.Slot
} else {
log.Error(MissingIdentifiedError)
return fmt.Errorf(MissingIdentifiedError)
}
stateEndpoint := baseEndpoint + stateIdentifier
ps.SszBeaconState, _ = querySsz(stateEndpoint, ps.Slot)
ps.FullBeaconState = new(spectests.BeaconState)
err := ps.FullSignedBeaconBlock.UnmarshalSSZ(ps.SszBeaconState)
if err != nil {
if ps.FullBeaconState.Slot == 0 {
loghelper.LogSlotError(ps.Slot, err).Error(SlotUnmarshalError)
return fmt.Errorf(SlotUnmarshalError)
}
}
return nil
}
func (ps *ProcessSlot) checkPreviousSlot(previousSlot uint64, previousBlockRoot string) {
if previousSlot == ps.FullBeaconState.Slot {
log.WithFields(log.Fields{
"slot": ps.FullBeaconState.Slot,
"fork": true,
}).Warn("A fork occurred! The previous slot and current slot match.")
// Handle Forks
} else if previousSlot-1 != ps.FullBeaconState.Slot {
log.WithFields(log.Fields{
"previousSlot": previousSlot,
"currentSlot": ps.FullBeaconState.Slot,
}).Error("We skipped a few slots.")
// Call our batch processing function.
} else if previousBlockRoot != "0x"+hex.EncodeToString(ps.FullSignedBeaconBlock.Block.ParentRoot) {
log.WithFields(log.Fields{
"previousBlockRoot": previousBlockRoot,
"currentBlockParent": ps.FullSignedBeaconBlock.Block.ParentRoot,
}).Error("The previousBlockRoot does not match the current blocks parent, an unprocessed fork might have occurred.")
// Handle Forks
}
}