Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 62 additions & 14 deletions pkg/miner/endorsementpool/endorsement_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,42 @@ type EndorsementPool struct {
maxEndorsements int
}

func sameRound(a, b *proto.EndorseBlock) bool {
if a == nil || b == nil {
return false
}
return a.EndorsedBlockID == b.EndorsedBlockID &&
a.FinalizedBlockID == b.FinalizedBlockID &&
a.FinalizedBlockHeight == b.FinalizedBlockHeight
}

// ShouldIgnoreEndorsement checks if the endorsement must be ignored and not added to pool/conflicts.
func (p *EndorsementPool) ShouldIgnoreEndorsement(
e *proto.EndorseBlock,
pk bls.PublicKey,
lastFinalizedHeight proto.Height,
parentBlockID proto.BlockID,
) bool {
if e == nil {
return true
}
if proto.Height(e.FinalizedBlockHeight) > lastFinalizedHeight {
return true
}
msg, err := e.EndorsementMessage()
if err != nil {
return true
}
ok, err := bls.Verify(pk, msg, e.Signature)
if err != nil || !ok {
return true
}
if parentBlockID != e.EndorsedBlockID {
return true
}
return false
}

func NewEndorsementPool(maxGenerators int) (*EndorsementPool, error) {
if maxGenerators <= 0 {
return nil, errors.New("the max number of endorsements must be more than 0")
Expand All @@ -83,26 +119,38 @@ func NewEndorsementPool(maxGenerators int) (*EndorsementPool, error) {

// Add inserts an endorsement into the heap with priority based on balance desc, seq asc.
func (p *EndorsementPool) Add(e *proto.EndorseBlock, pk bls.PublicKey,
lastFinalizedHeight proto.Height, lastFinalizedBlockID proto.BlockID, balance uint64) error {
if e == nil {
return errors.New("invalid endorsement")
}

lastFinalizedHeight proto.Height, lastFinalizedBlockID proto.BlockID, balance uint64,
parentBlockID proto.BlockID) (bool, error) {
k := makeKey(e.EndorsedBlockID, e.EndorserIndex)

p.mu.Lock()
defer p.mu.Unlock()
if _, exists := p.byKey[k]; exists {
p.conflicts = append(p.conflicts, *e)
slog.Debug("endorsement is conflicting because it already exists in the endorsement pool", "index", e.EndorserIndex)
return nil
}

if proto.Height(e.FinalizedBlockHeight) <= lastFinalizedHeight &&
e.FinalizedBlockID != lastFinalizedBlockID {
p.conflicts = append(p.conflicts, *e)
slog.Debug("endorsement is conflicting because the block finalized IDs don't match", "index",
e.EndorserIndex)
return nil
return false, nil
}

if p.ShouldIgnoreEndorsement(e, pk, lastFinalizedHeight, parentBlockID) {
return false, nil
}

// Endorsements are valid only within one finalization round.
// If round changed, old endorsements must be dropped, otherwise stale signatures can
// survive (especially with equal balances) and break aggregated signature verification.
if len(p.h) > 0 && !sameRound(p.h[0].eb, e) {
p.byKey = make(map[key]*heapItemEndorsement)
p.h = nil
p.conflicts = nil
}

if _, exists := p.byKey[k]; exists {
p.conflicts = append(p.conflicts, *e)
slog.Debug("endorsement is conflicting because it already exists in the endorsement pool", "index", e.EndorserIndex)
return false, nil
}

p.seq++
Expand All @@ -117,14 +165,14 @@ func (p *EndorsementPool) Add(e *proto.EndorseBlock, pk bls.PublicKey,
if len(p.h) < p.maxEndorsements {
heap.Push(&p.h, item)
p.byKey[k] = item
return nil
return true, nil
}

// If heap is full — check min (root).
minItem := p.h[0]
// If priority is lower or equal the min, throw the new one away.
if balance < minItem.balance || (balance == minItem.balance && item.seq > minItem.seq) {
return nil
return false, nil
}

// Otherwise remove min and insert the new one.
Expand All @@ -134,7 +182,7 @@ func (p *EndorsementPool) Add(e *proto.EndorseBlock, pk bls.PublicKey,

heap.Push(&p.h, item)
p.byKey[k] = item
return nil
return true, nil
}

func (p *EndorsementPool) GetAll() []proto.EndorseBlock {
Expand Down
Loading
Loading