Thomas E Lackey
27fa54c6dc
1. Updates or replaces outdated dependencies (eg, replacing a version of the Prysm client with the latest zrnt). 2. Add support for parsing Bellatrix-era BeaconState and BeaconBlocks 3. Adds flags for toggling the processing of BeaconBlocks and BeaconState. This is particularly important because processing and storing the BeaconState at this time would be too expensive to really do (see: Temporarily disable BeaconState indexing #75 and [Feature] Reduce the Amount of DB Space the Beacon Chain Needs #71) 4. Fixes flaky event handling. The previous code would not reconnect in the case of errors with the SSE connection. This enables automatic reconnection in the case of error (default in the updated v2 SSE library dependency), and also adds a timeout so that if no event is received in 2.5x the block time, the SSE connection is closed and re-established. 5. Other refactoring and cleanup (eg, changing the type of slot from int to Slot (uint64)).
442 lines
8.8 KiB
Go
442 lines
8.8 KiB
Go
package beaconclient
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"github.com/protolambda/zrnt/eth2/beacon/altair"
|
|
"github.com/protolambda/zrnt/eth2/beacon/bellatrix"
|
|
"github.com/protolambda/zrnt/eth2/beacon/common"
|
|
"github.com/protolambda/zrnt/eth2/beacon/phase0"
|
|
"github.com/protolambda/zrnt/eth2/configs"
|
|
"github.com/protolambda/ztyp/codec"
|
|
"github.com/protolambda/ztyp/tree"
|
|
log "github.com/sirupsen/logrus"
|
|
"strconv"
|
|
)
|
|
|
|
type Eth1Data common.Eth1Data
|
|
type Root common.Root
|
|
type Signature common.BLSSignature
|
|
type Slot uint64
|
|
type Epoch uint64
|
|
type ExecutionPayloadHeader common.ExecutionPayloadHeader
|
|
|
|
func ParseSlot(v string) (Slot, error) {
|
|
slotNum, err := strconv.ParseUint(v, 10, 64)
|
|
return Slot(slotNum), err
|
|
}
|
|
|
|
func (s *Slot) Format() string {
|
|
return strconv.FormatUint(uint64(*s), 10)
|
|
}
|
|
|
|
func (s *Slot) Number() uint64 {
|
|
return uint64(*s)
|
|
}
|
|
|
|
func (s *Slot) Plus(v uint64) Slot {
|
|
return Slot(v + s.Number())
|
|
}
|
|
|
|
func (s *Slot) PlusInt(v int) Slot {
|
|
return s.Plus(uint64(v))
|
|
}
|
|
|
|
func (e *Epoch) Format() string {
|
|
return strconv.FormatUint(uint64(*e), 10)
|
|
}
|
|
|
|
type BeaconBlock struct {
|
|
spec *common.Spec
|
|
bellatrix *bellatrix.BeaconBlock
|
|
altair *altair.BeaconBlock
|
|
phase0 *phase0.BeaconBlock
|
|
}
|
|
|
|
type BeaconBlockBody struct {
|
|
spec *common.Spec
|
|
bellatrix *bellatrix.BeaconBlockBody
|
|
altair *altair.BeaconBlockBody
|
|
phase0 *phase0.BeaconBlockBody
|
|
}
|
|
|
|
type BeaconState struct {
|
|
spec *common.Spec
|
|
bellatrix *bellatrix.BeaconState
|
|
altair *altair.BeaconState
|
|
phase0 *phase0.BeaconState
|
|
}
|
|
|
|
type SignedBeaconBlock struct {
|
|
spec *common.Spec
|
|
bellatrix *bellatrix.SignedBeaconBlock
|
|
altair *altair.SignedBeaconBlock
|
|
phase0 *phase0.SignedBeaconBlock
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) UnmarshalSSZ(ssz []byte) error {
|
|
spec := chooseSpec(s.spec)
|
|
|
|
var bellatrix bellatrix.SignedBeaconBlock
|
|
err := bellatrix.Deserialize(spec, makeDecodingReader(ssz))
|
|
if nil == err {
|
|
s.bellatrix = &bellatrix
|
|
s.altair = nil
|
|
s.phase0 = nil
|
|
log.Info("Unmarshalled Bellatrix SignedBeaconBlock")
|
|
return nil
|
|
}
|
|
|
|
var altair altair.SignedBeaconBlock
|
|
err = altair.Deserialize(spec, makeDecodingReader(ssz))
|
|
if nil == err {
|
|
s.bellatrix = nil
|
|
s.altair = &altair
|
|
s.phase0 = nil
|
|
log.Info("Unmarshalled Altair SignedBeaconBlock")
|
|
return nil
|
|
}
|
|
|
|
var phase0 phase0.SignedBeaconBlock
|
|
err = phase0.Deserialize(spec, makeDecodingReader(ssz))
|
|
if nil == err {
|
|
s.bellatrix = nil
|
|
s.altair = nil
|
|
s.phase0 = &phase0
|
|
log.Info("Unmarshalled Phase0 SignedBeaconBlock")
|
|
return nil
|
|
}
|
|
|
|
s.bellatrix = nil
|
|
s.altair = nil
|
|
s.phase0 = nil
|
|
|
|
log.Warning("Unable to unmarshal SignedBeaconBlock")
|
|
return err
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) MarshalSSZ() ([]byte, error) {
|
|
spec := chooseSpec(s.spec)
|
|
var err error
|
|
var buf bytes.Buffer
|
|
encodingWriter := codec.NewEncodingWriter(&buf)
|
|
|
|
if s.IsBellatrix() {
|
|
err = s.bellatrix.Serialize(spec, encodingWriter)
|
|
}
|
|
if s.IsAltair() {
|
|
err = s.altair.Serialize(spec, encodingWriter)
|
|
}
|
|
if s.IsPhase0() {
|
|
err = s.phase0.Serialize(spec, encodingWriter)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), err
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) IsBellatrix() bool {
|
|
return s.bellatrix != nil
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) IsAltair() bool {
|
|
return s.altair != nil
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) IsPhase0() bool {
|
|
return s.phase0 != nil
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) GetBellatrix() *bellatrix.SignedBeaconBlock {
|
|
return s.bellatrix
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) GetAltair() *altair.SignedBeaconBlock {
|
|
return s.altair
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) GetPhase0() *phase0.SignedBeaconBlock {
|
|
return s.phase0
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) Signature() Signature {
|
|
if s.IsBellatrix() {
|
|
return Signature(s.bellatrix.Signature)
|
|
}
|
|
|
|
if s.IsAltair() {
|
|
return Signature(s.altair.Signature)
|
|
}
|
|
|
|
if s.IsPhase0() {
|
|
return Signature(s.phase0.Signature)
|
|
}
|
|
|
|
return Signature{}
|
|
}
|
|
|
|
func (s *SignedBeaconBlock) Block() *BeaconBlock {
|
|
if s.IsBellatrix() {
|
|
return &BeaconBlock{bellatrix: &s.bellatrix.Message, spec: s.spec}
|
|
}
|
|
|
|
if s.IsAltair() {
|
|
return &BeaconBlock{altair: &s.altair.Message, spec: s.spec}
|
|
}
|
|
|
|
if s.IsPhase0() {
|
|
return &BeaconBlock{phase0: &s.phase0.Message, spec: s.spec}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BeaconBlock) IsBellatrix() bool {
|
|
return b.bellatrix != nil
|
|
}
|
|
|
|
func (b *BeaconBlock) IsAltair() bool {
|
|
return b.altair != nil
|
|
}
|
|
|
|
func (b *BeaconBlock) IsPhase0() bool {
|
|
return b.phase0 != nil
|
|
}
|
|
|
|
func (s *BeaconBlock) GetBellatrix() *bellatrix.BeaconBlock {
|
|
return s.bellatrix
|
|
}
|
|
|
|
func (s *BeaconBlock) GetAltair() *altair.BeaconBlock {
|
|
return s.altair
|
|
}
|
|
|
|
func (s *BeaconBlock) GetPhase0() *phase0.BeaconBlock {
|
|
return s.phase0
|
|
}
|
|
|
|
func (b *BeaconBlock) ParentRoot() Root {
|
|
if b.IsBellatrix() {
|
|
return Root(b.bellatrix.ParentRoot)
|
|
}
|
|
|
|
if b.IsAltair() {
|
|
return Root(b.altair.ParentRoot)
|
|
}
|
|
|
|
if b.IsPhase0() {
|
|
return Root(b.phase0.ParentRoot)
|
|
}
|
|
|
|
return Root{}
|
|
}
|
|
|
|
func (b *BeaconBlock) StateRoot() Root {
|
|
if b.IsBellatrix() {
|
|
return Root(b.bellatrix.StateRoot)
|
|
}
|
|
|
|
if b.IsAltair() {
|
|
return Root(b.altair.StateRoot)
|
|
}
|
|
|
|
if b.IsPhase0() {
|
|
return Root(b.phase0.StateRoot)
|
|
}
|
|
|
|
return Root{}
|
|
}
|
|
|
|
func (b *BeaconBlock) Body() *BeaconBlockBody {
|
|
if b.IsBellatrix() {
|
|
return &BeaconBlockBody{bellatrix: &b.bellatrix.Body, spec: b.spec}
|
|
}
|
|
|
|
if b.IsAltair() {
|
|
return &BeaconBlockBody{altair: &b.altair.Body, spec: b.spec}
|
|
}
|
|
|
|
if b.IsPhase0() {
|
|
return &BeaconBlockBody{phase0: &b.phase0.Body, spec: b.spec}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BeaconBlockBody) IsBellatrix() bool {
|
|
return b.bellatrix != nil
|
|
}
|
|
|
|
func (b *BeaconBlockBody) IsAltair() bool {
|
|
return b.altair != nil
|
|
}
|
|
|
|
func (b *BeaconBlockBody) IsPhase0() bool {
|
|
return b.phase0 != nil
|
|
}
|
|
|
|
func (b *BeaconBlockBody) Eth1Data() Eth1Data {
|
|
if b.IsBellatrix() {
|
|
return Eth1Data(b.bellatrix.Eth1Data)
|
|
}
|
|
|
|
if b.IsAltair() {
|
|
return Eth1Data(b.altair.Eth1Data)
|
|
}
|
|
|
|
if b.IsPhase0() {
|
|
return Eth1Data(b.phase0.Eth1Data)
|
|
}
|
|
|
|
return Eth1Data{}
|
|
}
|
|
|
|
func (b *BeaconBlockBody) ExecutionPayloadHeader() *ExecutionPayloadHeader {
|
|
if b.IsBellatrix() {
|
|
payloadHeader := b.bellatrix.ExecutionPayload.Header(chooseSpec(b.spec))
|
|
return (*ExecutionPayloadHeader)(payloadHeader)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BeaconBlock) HashTreeRoot() Root {
|
|
spec := chooseSpec(b.spec)
|
|
hashFn := tree.GetHashFn()
|
|
|
|
if b.IsBellatrix() {
|
|
return Root(b.bellatrix.HashTreeRoot(spec, hashFn))
|
|
}
|
|
|
|
if b.IsAltair() {
|
|
return Root(b.altair.HashTreeRoot(spec, hashFn))
|
|
}
|
|
|
|
if b.IsPhase0() {
|
|
return Root(b.phase0.HashTreeRoot(spec, hashFn))
|
|
}
|
|
|
|
return Root{}
|
|
}
|
|
|
|
func (s *BeaconState) UnmarshalSSZ(ssz []byte) error {
|
|
spec := chooseSpec(s.spec)
|
|
|
|
var bellatrix bellatrix.BeaconState
|
|
err := bellatrix.Deserialize(spec, makeDecodingReader(ssz))
|
|
if nil == err {
|
|
s.bellatrix = &bellatrix
|
|
s.altair = nil
|
|
s.phase0 = nil
|
|
log.Info("Unmarshalled Bellatrix BeaconState")
|
|
return nil
|
|
}
|
|
|
|
var altair altair.BeaconState
|
|
err = altair.Deserialize(spec, makeDecodingReader(ssz))
|
|
if nil == err {
|
|
s.bellatrix = nil
|
|
s.altair = &altair
|
|
s.phase0 = nil
|
|
log.Info("Unmarshalled Altair BeaconState")
|
|
return nil
|
|
}
|
|
|
|
var phase0 phase0.BeaconState
|
|
err = phase0.Deserialize(spec, makeDecodingReader(ssz))
|
|
if nil == err {
|
|
s.bellatrix = nil
|
|
s.altair = nil
|
|
s.phase0 = &phase0
|
|
log.Info("Unmarshalled Phase0 BeaconState")
|
|
return nil
|
|
}
|
|
|
|
s.bellatrix = nil
|
|
s.altair = nil
|
|
s.phase0 = nil
|
|
|
|
log.Warning("Unable to unmarshal BeaconState")
|
|
return err
|
|
}
|
|
|
|
func (s *BeaconState) MarshalSSZ() ([]byte, error) {
|
|
spec := chooseSpec(s.spec)
|
|
var err error
|
|
var buf bytes.Buffer
|
|
encodingWriter := codec.NewEncodingWriter(&buf)
|
|
|
|
if s.IsBellatrix() {
|
|
err = s.bellatrix.Serialize(spec, encodingWriter)
|
|
} else if s.IsAltair() {
|
|
err = s.altair.Serialize(spec, encodingWriter)
|
|
} else if s.IsPhase0() {
|
|
err = s.phase0.Serialize(spec, encodingWriter)
|
|
} else {
|
|
err = errors.New("BeaconState not set")
|
|
}
|
|
|
|
if nil != err {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func (s *BeaconState) IsBellatrix() bool {
|
|
return s.bellatrix != nil
|
|
}
|
|
|
|
func (s *BeaconState) IsAltair() bool {
|
|
return s.altair != nil
|
|
}
|
|
|
|
func (s *BeaconState) IsPhase0() bool {
|
|
return s.phase0 != nil
|
|
}
|
|
|
|
func (s *BeaconState) HashTreeRoot() Root {
|
|
spec := chooseSpec(s.spec)
|
|
hashFn := tree.GetHashFn()
|
|
|
|
if s.IsBellatrix() {
|
|
return Root(s.bellatrix.HashTreeRoot(spec, hashFn))
|
|
}
|
|
|
|
if s.IsAltair() {
|
|
return Root(s.altair.HashTreeRoot(spec, hashFn))
|
|
}
|
|
|
|
if s.IsPhase0() {
|
|
return Root(s.phase0.HashTreeRoot(spec, hashFn))
|
|
}
|
|
|
|
return Root{}
|
|
}
|
|
|
|
func (s *BeaconState) GetBellatrix() *bellatrix.BeaconState {
|
|
return s.bellatrix
|
|
}
|
|
|
|
func (s *BeaconState) GetAltair() *altair.BeaconState {
|
|
return s.altair
|
|
}
|
|
|
|
func (s *BeaconState) GetPhase0() *phase0.BeaconState {
|
|
return s.phase0
|
|
}
|
|
|
|
func chooseSpec(spec *common.Spec) *common.Spec {
|
|
if nil == spec {
|
|
return configs.Mainnet
|
|
}
|
|
return spec
|
|
}
|
|
|
|
func makeDecodingReader(ssz []byte) *codec.DecodingReader {
|
|
return codec.NewDecodingReader(bytes.NewReader(ssz), uint64(len(ssz)))
|
|
}
|