beacon/light: various small changes

This commit is contained in:
Zsolt Felfoldi 2023-05-07 13:15:49 +02:00
parent 7c613fe752
commit f044766bf5
15 changed files with 114 additions and 178 deletions

View file

@ -131,15 +131,15 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
func (api *BeaconLightApi) GetOptimisticHeadUpdate() (types.SignedHead, error) {
func (api *BeaconLightApi) GetOptimisticHeadUpdate() (types.SignedHeader, error) {
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update")
if err != nil {
return types.SignedHead{}, err
return types.SignedHeader{}, err
}
return decodeOptimisticHeadUpdate(resp)
}
func decodeOptimisticHeadUpdate(enc []byte) (types.SignedHead, error) {
func decodeOptimisticHeadUpdate(enc []byte) (types.SignedHeader, error) {
var data struct {
Data struct {
Header types.JsonBeaconHeader `json:"attested_header"`
@ -148,22 +148,22 @@ func decodeOptimisticHeadUpdate(enc []byte) (types.SignedHead, error) {
} `json:"data"`
}
if err := json.Unmarshal(enc, &data); err != nil {
return types.SignedHead{}, err
return types.SignedHeader{}, err
}
if data.Data.Header.Beacon.StateRoot == (common.Hash{}) {
// workaround for different event encoding format in Lodestar
if err := json.Unmarshal(enc, &data.Data); err != nil {
return types.SignedHead{}, err
return types.SignedHeader{}, err
}
}
if len(data.Data.Aggregate.BitMask) != params.SyncCommitteeBitmaskSize {
return types.SignedHead{}, errors.New("invalid sync_committee_bits length")
return types.SignedHeader{}, errors.New("invalid sync_committee_bits length")
}
if len(data.Data.Aggregate.Signature) != params.BlsSignatureSize {
return types.SignedHead{}, errors.New("invalid sync_committee_signature length")
return types.SignedHeader{}, errors.New("invalid sync_committee_signature length")
}
return types.SignedHead{
return types.SignedHeader{
Header: data.Data.Header.Beacon,
SyncAggregate: data.Data.Aggregate,
SignatureSlot: uint64(data.Data.SignatureSlot),
@ -309,7 +309,7 @@ func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) {
// head updates and calls the specified callback functions when they are received.
// The callbacks are also called for the current head and optimistic head at startup.
// They are never called concurrently.
func (api *BeaconLightApi) StartHeadListener(headFn func(slot uint64, blockRoot common.Hash), signedFn func(head types.SignedHead), errFn func(err error)) func() {
func (api *BeaconLightApi) StartHeadListener(headFn func(slot uint64, blockRoot common.Hash), signedFn func(head types.SignedHeader), errFn func(err error)) func() {
closeCh := make(chan struct{}) // initiate closing the stream
closedCh := make(chan struct{}) // stream closed (or failed to create)
stoppedCh := make(chan struct{}) // sync loop stopped

View file

@ -39,7 +39,7 @@ func NewSyncServer(api *BeaconLightApi) *SyncServer {
return &SyncServer{api: api}
}
func (s *SyncServer) SubscribeHeads(newHead func(uint64, common.Hash), newSignedHead func(signedHead types.SignedHead)) {
func (s *SyncServer) SubscribeHeads(newHead func(uint64, common.Hash), newSignedHead func(signedHead types.SignedHeader)) {
s.unsubscribe = s.api.StartHeadListener(newHead, newSignedHead, func(err error) {
log.Warn("Head event stream error", "err", err)
})

View file

@ -421,22 +421,22 @@ func (s *CommitteeChain) getSyncCommittee(period uint64) syncCommittee {
return nil
}
// VerifySignedHead returns true if the given signed head has a valid signature
// VerifySignedHeader returns true if the given signed head has a valid signature
// according to the local committee chain. The caller should ensure that the
// committees advertised by the same source where the signed head came from are
// synced before verifying the signature.
// The age of the header is also returned (the time elapsed since the beginning
// of the given slot, according to the local system clock). If enforceTime is
// true then negative age (future) headers are rejected.
func (s *CommitteeChain) VerifySignedHead(head types.SignedHead) (bool, time.Duration) {
func (s *CommitteeChain) VerifySignedHeader(head types.SignedHeader) (bool, time.Duration) {
s.lock.RLock()
defer s.lock.RUnlock()
return s.verifySignedHead(head)
return s.verifySignedHeader(head)
}
// (rlock required)
func (s *CommitteeChain) verifySignedHead(head types.SignedHead) (bool, time.Duration) {
func (s *CommitteeChain) verifySignedHeader(head types.SignedHeader) (bool, time.Duration) {
var (
slotTime = int64(time.Second) * int64(s.genesisData.GenesisTime+head.Header.Slot*12)
age = time.Duration(s.unixNano() - slotTime)
@ -460,7 +460,7 @@ func (s *CommitteeChain) verifyUpdate(update *types.LightClientUpdate) bool {
// verification. Though in reality SignatureSlot is always bigger than update.Header.Slot,
// setting them as equal here enforces the rule that they have to be in the same sync
// period in order for the light client update proof to be meaningful.
ok, age := s.verifySignedHead(types.SignedHead{Header: update.Header, SyncAggregate: update.SyncAggregate, SignatureSlot: update.Header.Slot})
ok, age := s.verifySignedHeader(update.SignedHeader)
if age < 0 {
log.Warn("Future committee update received", "age", age)
}

View file

@ -287,21 +287,21 @@ func (c *committeeChainTest) insertUpdate(tc *testCommitteeChain, period uint64,
}
}
func (c *committeeChainTest) verifySignedHead(tc *testCommitteeChain, period float64, expOk bool) {
func (c *committeeChainTest) verifySignedHeader(tc *testCommitteeChain, period float64, expOk bool) {
signedHead := tc.makeTestSignedHead(types.Header{Slot: uint64(period * float64(params.SyncPeriodLength))}, 400)
if ok, _ := c.chain.VerifySignedHead(signedHead); ok != expOk {
c.t.Errorf("Incorrect output from VerifySignedHead at period %f (expected %v, got %v)", period, expOk, ok)
if ok, _ := c.chain.VerifySignedHeader(signedHead); ok != expOk {
c.t.Errorf("Incorrect output from VerifySignedHeader at period %f (expected %v, got %v)", period, expOk, ok)
}
}
func (c *committeeChainTest) verifyRange(tc *testCommitteeChain, begin, end uint64) {
if begin > 0 {
c.verifySignedHead(tc, float64(begin)-0.5, false)
c.verifySignedHeader(tc, float64(begin)-0.5, false)
}
for period := begin; period <= end; period++ {
c.verifySignedHead(tc, float64(period)+0.5, true)
c.verifySignedHeader(tc, float64(period)+0.5, true)
}
c.verifySignedHead(tc, float64(end)+1.5, false)
c.verifySignedHeader(tc, float64(end)+1.5, false)
}
func newTestGenesis() GenesisData {
@ -378,9 +378,9 @@ type testCommitteeChain struct {
genesisData GenesisData
}
func (tc *testCommitteeChain) makeTestSignedHead(header types.Header, signerCount int) types.SignedHead {
func (tc *testCommitteeChain) makeTestSignedHead(header types.Header, signerCount int) types.SignedHeader {
bitmask := makeBitmask(signerCount)
return types.SignedHead{
return types.SignedHeader{
Header: header,
SyncAggregate: types.SyncAggregate{
BitMask: bitmask,

View file

@ -38,10 +38,10 @@ func NewHeadValidator(committeeChain *CommitteeChain) *HeadValidator {
type headSub struct {
minSignerCount int
nextSlot uint64
callbacks []func(types.SignedHead)
callbacks []func(types.SignedHeader)
}
func (h *HeadValidator) Subscribe(minSignerCount int, callback func(types.SignedHead)) {
func (h *HeadValidator) Subscribe(minSignerCount int, callback func(types.SignedHeader)) {
h.lock.Lock()
defer h.lock.Unlock()
@ -60,15 +60,15 @@ func (h *HeadValidator) Subscribe(minSignerCount int, callback func(types.Signed
copy(h.subs[insertAt+1:], h.subs[insertAt:len(h.subs)-1])
h.subs[insertAt] = &headSub{
minSignerCount: minSignerCount,
callbacks: []func(types.SignedHead){callback},
callbacks: []func(types.SignedHeader){callback},
}
}
func (h *HeadValidator) Add(head types.SignedHead) error {
func (h *HeadValidator) Add(head types.SignedHeader) error {
h.lock.Lock()
defer h.lock.Unlock()
sigOk, age := h.committeeChain.VerifySignedHead(head)
sigOk, age := h.committeeChain.VerifySignedHeader(head)
if age < 0 {
log.Warn("Future signed head received", "age", age)
}
@ -79,7 +79,7 @@ func (h *HeadValidator) Add(head types.SignedHead) error {
return errors.New("invalid header signature")
}
signerCount := head.SignerCount()
signerCount := head.SyncAggregate.SignerCount()
for _, sub := range h.subs {
if sub.minSignerCount > signerCount {
break

View file

@ -33,7 +33,7 @@ import (
// the trusted engine API while head BLS signatures are validated later as they
// appear, in order to be passed on to other clients.
type HeadTracker struct {
newSignedHead func(server *Server, signedHead types.SignedHead)
newSignedHead func(server *Server, signedHead types.SignedHeader)
validatedLock sync.RWMutex
validatedHead types.Header
@ -54,7 +54,7 @@ type serverHeadInfo struct {
// NewHeadTracker creates a new HeadTracker. The newSignedHead head callback is
// called whenever a signed head is received from any of the connected servers.
func NewHeadTracker(newSignedHead func(server *Server, signedHead types.SignedHead)) *HeadTracker {
func NewHeadTracker(newSignedHead func(server *Server, signedHead types.SignedHeader)) *HeadTracker {
return &HeadTracker{
serverHeads: make(map[*Server]common.Hash),
headInfo: make(map[common.Hash]serverHeadInfo),
@ -101,7 +101,7 @@ func (s *HeadTracker) registerServer(server *Server) {
server.setHead(slot, blockRoot)
s.setServerHead(server, blockRoot)
server.scheduler.triggerServer(server)
}, func(signedHead types.SignedHead) {
}, func(signedHead types.SignedHeader) {
s.newSignedHead(server, signedHead)
})
}

View file

@ -86,7 +86,7 @@ type Scheduler struct {
triggerCh chan struct{} // restarts waiting sync loop
testWaitCh chan struct{} // accepts sends when sync loop is waiting
testTimerCh chan bool // sends true when simulated timer is processed; false when stopped
testTimerResults []bool // true is appended when simulated timer is processed; false when stopped
triggerLock sync.Mutex
waiting, triggered bool
trModules map[Module]struct{}

View file

@ -28,13 +28,13 @@ import (
type testRequestServer struct {
newHead func(uint64, common.Hash)
newSignedHead func(types.SignedHead)
newSignedHead func(types.SignedHeader)
clock *mclock.Simulated
delayUntil mclock.AbsTime
failed bool
}
func (s *testRequestServer) SubscribeHeads(newHead func(uint64, common.Hash), newSignedHead func(types.SignedHead)) {
func (s *testRequestServer) SubscribeHeads(newHead func(uint64, common.Hash), newSignedHead func(types.SignedHeader)) {
s.newHead, s.newSignedHead = newHead, newSignedHead
}
@ -89,7 +89,7 @@ func newSchedulerTest(t *testing.T, clock *mclock.Simulated, serverCount, trigge
st := &schedulerTest{
t: t,
clock: clock,
scheduler: NewScheduler(NewHeadTracker(func(*Server, types.SignedHead) {}), clock),
scheduler: NewScheduler(NewHeadTracker(func(*Server, types.SignedHeader) {}), clock),
modules: make([]*testModule, len(moduleTriggers)),
triggers: make([]*ModuleTrigger, triggerCount),
processCh: make(chan testProcess),
@ -219,7 +219,7 @@ func (r *testRequest) returned() {
func TestServerTrigger(t *testing.T) {
st := newSchedulerTest(t, &mclock.Simulated{}, 3, 2, [][]int{{0}, {}})
st.scheduler.testTimerCh = make(chan bool)
st.scheduler.testTimerResults = []bool{}
req := &testRequest{}
req.reqLock.Trigger = st.triggers[0]
@ -251,9 +251,13 @@ func TestServerTrigger(t *testing.T) {
}
expectTimerFinished := func(exp bool) {
if processed := <-st.scheduler.testTimerCh; processed != exp {
t.Fatalf("Invalid simulated timer result (got processed == %v, expected %v)", processed, exp)
if len(st.scheduler.testTimerResults) == 0 {
t.Fatalf("No timer results found (expected %v)", exp)
}
if st.scheduler.testTimerResults[0] != exp {
t.Fatalf("Invalid simulated timer result (got finished == %v, expected %v)", st.scheduler.testTimerResults[0], exp)
}
st.scheduler.testTimerResults = st.scheduler.testTimerResults[1:]
}
st.servers[2].delayUntil = mclock.AbsTime(time.Second * 5)

View file

@ -29,7 +29,7 @@ import (
// RequestServer is a general server interface that can be extended by modules
// with specific request types.
type RequestServer interface {
SubscribeHeads(newHead func(uint64, common.Hash), newSignedHead func(types.SignedHead))
SubscribeHeads(newHead func(uint64, common.Hash), newSignedHead func(types.SignedHeader))
UnsubscribeHeads()
DelayUntil() mclock.AbsTime // no requests should be sent before this
Fail(string) // report server failure
@ -49,10 +49,10 @@ type Server struct {
moduleData map[Module]*interface{}
lock sync.Mutex
sent map[uint64]chan struct{} // closed when returned; nil when timed out
timeouts map[uint64]mclock.Timer // stopped when request has returned; nil when timed out
timeoutCount int
delayUntil mclock.AbsTime
delayTimer mclock.ChanTimer // if non-nil then expires at delayUntil
delayTimer mclock.Timer // if non-nil then expires at delayUntil
needTrigger bool
lastReqId uint64
stopCh chan struct{}
@ -64,7 +64,7 @@ func (s *Scheduler) newServer(server RequestServer) *Server {
RequestServer: server,
scheduler: s,
moduleData: make(map[Module]*interface{}),
sent: make(map[uint64]chan struct{}),
timeouts: make(map[uint64]mclock.Timer),
stopCh: make(chan struct{}),
}
}
@ -113,48 +113,31 @@ func (s *Server) isDelayed() bool {
if delayUntil == s.delayUntil {
return s.delayTimer != nil
}
s.delayUntil = delayUntil
if s.delayTimer != nil {
if s.delayTimer.Stop() {
if s.scheduler.testTimerCh != nil {
s.scheduler.testTimerCh <- false // simulated timer stopped
}
} else {
s.delayTimer = nil
}
// Note: is stopping the timer is unsuccessful then the resulting AfterFunc
// call will just do nothing
s.stopTimer(s.delayTimer)
s.delayTimer = nil
}
s.delayUntil = delayUntil
delay := time.Duration(delayUntil - s.scheduler.clock.Now())
if delay <= 0 {
s.delayTimer = nil
return false
}
if s.delayTimer == nil {
s.delayTimer = s.scheduler.clock.NewTimer(delay)
} else {
s.delayTimer.Reset(delay)
}
timer := s.delayTimer
go func() {
select {
case <-timer.C():
s.lock.Lock()
if s.delayTimer == timer {
s.delayTimer = nil
if s.needTrigger && s.timeoutCount == 0 {
s.needTrigger = false
s.scheduler.triggerServer(s)
}
}
s.lock.Unlock()
if s.scheduler.testTimerCh != nil {
s.scheduler.testTimerCh <- true // simulated timer processed
}
case <-s.stopCh:
if timer.Stop() && s.scheduler.testTimerCh != nil {
s.scheduler.testTimerCh <- false // simulated timer stopped
s.delayTimer = s.scheduler.clock.AfterFunc(delay, func() {
if s.scheduler.testTimerResults != nil {
s.scheduler.testTimerResults = append(s.scheduler.testTimerResults, true) // simulated timer finished
}
s.lock.Lock()
if s.delayTimer != nil && s.delayUntil == delayUntil { // do nothing if there is a new timer now
s.delayTimer = nil
if s.needTrigger && s.timeoutCount == 0 {
s.needTrigger = false
s.scheduler.triggerServer(s)
}
}
}()
s.lock.Unlock()
})
return true
}
@ -166,44 +149,36 @@ func (s *Server) sendRequest(timeoutTrigger *ModuleTrigger) uint64 {
s.lastReqId++
reqId := s.lastReqId
returnCh := make(chan struct{})
s.sent[reqId] = returnCh
timer := s.scheduler.clock.NewTimer(softRequestTimeout)
go func() {
select {
case <-timer.C():
s.lock.Lock()
if _, ok := s.sent[reqId]; ok {
s.sent[reqId] = nil
s.timeoutCount++
}
s.lock.Unlock()
s.timeouts[reqId] = s.scheduler.clock.AfterFunc(softRequestTimeout, func() {
if s.scheduler.testTimerResults != nil {
s.scheduler.testTimerResults = append(s.scheduler.testTimerResults, true) // simulated timer finished
}
s.lock.Lock()
if s.timeouts[reqId] != nil {
s.timeouts[reqId] = nil
s.timeoutCount++
if timeoutTrigger != nil {
timeoutTrigger.Trigger()
}
if s.scheduler.testTimerCh != nil {
s.scheduler.testTimerCh <- true // simulated timer processed
}
case <-returnCh:
if timer.Stop() && s.scheduler.testTimerCh != nil {
s.scheduler.testTimerCh <- false // simulated timer stopped
}
case <-s.stopCh:
if timer.Stop() && s.scheduler.testTimerCh != nil {
s.scheduler.testTimerCh <- false // simulated timer stopped
}
}
}()
s.lock.Unlock()
})
return reqId
}
func (s *Server) stopTimer(timer mclock.Timer) {
if timer.Stop() && s.scheduler.testTimerResults != nil {
s.scheduler.testTimerResults = append(s.scheduler.testTimerResults, false) // simulated timer stopped
}
}
// hasTimedOut returns true if the given request has timed out.
func (s *Server) hasTimedOut(reqId uint64) bool {
s.lock.Lock()
defer s.lock.Unlock()
ch, ok := s.sent[reqId]
return ok && ch == nil
timer, ok := s.timeouts[reqId]
return ok && timer == nil
}
// returned stops the timeout timer and removes the entry associated with the
@ -213,9 +188,9 @@ func (s *Server) returned(reqId uint64) {
s.lock.Lock()
defer s.lock.Unlock()
if ch, ok := s.sent[reqId]; ok {
if ch != nil {
close(ch)
if timer, ok := s.timeouts[reqId]; ok {
if timer != nil {
s.stopTimer(timer)
} else {
s.timeoutCount--
if s.needTrigger && s.timeoutCount == 0 && !s.isDelayed() {
@ -223,11 +198,18 @@ func (s *Server) returned(reqId uint64) {
s.scheduler.triggerServer(s)
}
}
delete(s.sent, reqId)
delete(s.timeouts, reqId)
}
}
// stop stops all goroutines associated with the server.
func (s *Server) stop() {
close(s.stopCh)
for _, timer := range s.timeouts {
if timer != nil {
s.stopTimer(timer)
}
}
if s.delayTimer != nil {
s.stopTimer(s.delayTimer)
}
}

View file

@ -31,7 +31,7 @@ type HeadUpdater struct {
chain *light.CommitteeChain
lock sync.Mutex
nextSyncPeriod uint64
queuedHeads map[*request.Server][]types.SignedHead
queuedHeads map[*request.Server][]types.SignedHeader
}
func NewHeadUpdater(headValidator *light.HeadValidator, chain *light.CommitteeChain) *HeadUpdater {
@ -39,7 +39,7 @@ func NewHeadUpdater(headValidator *light.HeadValidator, chain *light.CommitteeCh
headValidator: headValidator,
chain: chain,
nextSyncPeriod: math.MaxUint64,
queuedHeads: make(map[*request.Server][]types.SignedHead),
queuedHeads: make(map[*request.Server][]types.SignedHeader),
}
return s
}
@ -49,7 +49,7 @@ func (s *HeadUpdater) SetupModuleTriggers(trigger func(id string, subscribe bool
trigger("newUpdate", true)
}
func (s *HeadUpdater) NewSignedHead(server *request.Server, signedHead types.SignedHead) {
func (s *HeadUpdater) NewSignedHead(server *request.Server, signedHead types.SignedHeader) {
nextPeriod, ok := s.chain.NextSyncPeriod()
if !ok || signedHead.Header.SyncPeriod() > nextPeriod {
s.lock.Lock()

View file

@ -30,6 +30,7 @@ import (
const SerializedCommitteeSize = (params.SyncCommitteeSize + 1) * params.BlsPubkeySize
// SerializedCommittee is the serialized version of a sync committee
type SerializedCommittee [SerializedCommitteeSize]byte
// jsonSyncCommittee is the JSON representation of a sync committee
@ -137,6 +138,8 @@ type SyncCommittee struct {
aggregate *bls.Pubkey
}
// VerifySignature returns true if the given sync aggregate is a valid signature
// or the given hash
func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, aggregate *SyncAggregate) bool {
var (
sig bls.Signature
@ -195,6 +198,7 @@ func (s *SyncAggregate) UnmarshalJSON(input []byte) error {
return nil
}
// SignerCount returns the number of signers in the aggregate signature
func (s *SyncAggregate) SignerCount() int {
var count int
for _, v := range s.BitMask {

View file

@ -32,6 +32,8 @@ import (
"github.com/minio/sha256-simd"
)
const syncCommitteeDomain = 7
// Fork describes a single beacon chain fork and also stores the calculated
// signature domain used after this fork.
type Fork struct {
@ -79,7 +81,7 @@ func computeDomain(forkVersion []byte, genesisValidatorsRoot common.Hash) merkle
hasher.Write(forkVersion32[:])
hasher.Write(genesisValidatorsRoot[:])
hasher.Sum(forkDataRoot[:0])
domain[0] = 7
domain[0] = syncCommitteeDomain
copy(domain[4:], forkDataRoot[:28])
return domain
}

View file

@ -108,53 +108,13 @@ func PeriodOfSlot(slot uint64) uint64 {
return slot >> params.Log2SyncPeriodLength
}
// HeaderWithoutState stores beacon header fields except the state root which can
// be reconstructed from a partial beacon state proof stored alongside the header
type HeaderWithoutState struct {
Slot uint64
ProposerIndex uint64
ParentRoot, BodyRoot common.Hash
}
// Hash calculates the block root of the header
func (bh *HeaderWithoutState) Hash(stateRoot common.Hash) common.Hash {
return bh.Proof(stateRoot).RootHash()
}
// Proof returns a MultiProof of the header
func (bh *HeaderWithoutState) Proof(stateRoot common.Hash) merkle.MultiProof {
var values [8]merkle.Value // values corresponding to indices 8 to 15 of the beacon header tree
binary.LittleEndian.PutUint64(values[params.BhiSlot-8][:8], bh.Slot)
binary.LittleEndian.PutUint64(values[params.BhiProposerIndex-8][:8], bh.ProposerIndex)
values[params.BhiParentRoot-8] = merkle.Value(bh.ParentRoot)
values[params.BhiStateRoot-8] = merkle.Value(stateRoot)
values[params.BhiBodyRoot-8] = merkle.Value(bh.BodyRoot)
return merkle.MultiProof{Format: headerFormat, Values: values[:]}
}
// FullHeader reconstructs a full Header from a HeaderWithoutState and a state root
func (bh *HeaderWithoutState) FullHeader(stateRoot common.Hash) Header {
return Header{
Slot: bh.Slot,
ProposerIndex: bh.ProposerIndex,
ParentRoot: bh.ParentRoot,
StateRoot: stateRoot,
BodyRoot: bh.BodyRoot,
}
}
// SignedHead represents a beacon header signed by a sync committee
// SignedHeader represents a beacon header signed by a sync committee
//
// Note: this structure is created from either an optimistic update or an instant update:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
// https://github.com/zsfelfoldi/beacon-APIs/blob/instant_update/apis/beacon/light_client/instant_update.yaml
type SignedHead struct {
type SignedHeader struct {
Header Header // signed beacon header
SyncAggregate SyncAggregate // sync committee signature aggregate
SignatureSlot uint64 // slot in which the signature has been created (newer than Header.Slot, determines the signing sync committee)
}
// SignerCount returns the number of individual signers in the signature aggregate
func (s *SignedHead) SignerCount() int {
return s.SyncAggregate.SignerCount()
}

View file

@ -26,8 +26,6 @@ import (
"github.com/ethereum/go-ethereum/log"
)
const MaxUpdateScoresLength = 128 // max number of advertised update scores of most recent periods
// LightClientUpdate is a proof of the next sync committee root based on a header
// signed by the sync committee of the given period. Optionally the update can
// prove quasi-finality by the signed header referring to a previous, finalized
@ -37,9 +35,7 @@ const MaxUpdateScoresLength = 128 // max number of advertised update scores of m
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
type LightClientUpdate struct {
Header Header
SyncAggregate SyncAggregate
SignatureSlot uint64
SignedHeader
NextSyncCommitteeRoot common.Hash
NextSyncCommitteeBranch merkle.Values
FinalizedHeader Header
@ -83,7 +79,7 @@ func (u *CommitteeUpdate) MarshalJSON() ([]byte, error) {
Header: JsonBeaconHeader{Beacon: u.Update.Header},
NextSyncCommittee: u.NextSyncCommittee,
NextSyncCommitteeBranch: u.Update.NextSyncCommitteeBranch,
FinalizedHeader: JsonBeaconHeader{Beacon: u.Update.FinalizedHeader}, //TODO should we encode it when not present?
FinalizedHeader: JsonBeaconHeader{Beacon: u.Update.FinalizedHeader},
FinalityBranch: u.Update.FinalityBranch,
SyncAggregate: u.Update.SyncAggregate,
SignatureSlot: common.Decimal(u.Update.SignatureSlot),
@ -100,9 +96,11 @@ func (u *CommitteeUpdate) UnmarshalJSON(input []byte) error {
u.Version = dec.Version
u.NextSyncCommittee = dec.Data.NextSyncCommittee
u.Update = &LightClientUpdate{
Header: dec.Data.Header.Beacon,
SyncAggregate: dec.Data.SyncAggregate,
SignatureSlot: uint64(dec.Data.SignatureSlot),
SignedHeader: SignedHeader{
Header: dec.Data.Header.Beacon,
SyncAggregate: dec.Data.SyncAggregate,
SignatureSlot: uint64(dec.Data.SignatureSlot),
},
NextSyncCommitteeRoot: u.NextSyncCommittee.Root(),
NextSyncCommitteeBranch: dec.Data.NextSyncCommitteeBranch,
FinalizedHeader: dec.Data.FinalizedHeader.Beacon,
@ -196,20 +194,6 @@ type PeriodRange struct {
First, AfterLast uint64
}
/*func (a PeriodRange) Shared(b PeriodRange) PeriodRange {
if b.First > a.First {
a.First = b.First
}
if b.AfterLast < a.AfterLast {
a.AfterLast = b.AfterLast
}
return a
}
func (a PeriodRange) IsValid() bool {
return a.AfterLast >= a.First
}*/
func (a PeriodRange) IsEmpty() bool {
return a.AfterLast == a.First
}

View file

@ -108,7 +108,7 @@ func blsync(ctx *cli.Context) error {
committeeChain.SetGenesisData(chainConfig.GenesisData)
headUpdater := sync.NewHeadUpdater(headValidator, committeeChain)
headTracker := request.NewHeadTracker(headUpdater.NewSignedHead)
headValidator.Subscribe(threshold, func(signedHead types.SignedHead) {
headValidator.Subscribe(threshold, func(signedHead types.SignedHeader) {
headTracker.SetValidatedHead(signedHead.Header)
})