-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement EIP7805: Fork-choice enforced Inclusion Lists
- Loading branch information
1 parent
6ce6b86
commit 2671fcf
Showing
66 changed files
with
3,564 additions
and
1,653 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package blockchain | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/prysmaticlabs/prysm/v5/config/params" | ||
"github.com/prysmaticlabs/prysm/v5/time/slots" | ||
) | ||
|
||
const updateInclusionListBlockInterval = time.Second | ||
|
||
// Routine that updates block building with inclusion lists one second before the slot starts. | ||
func (s *Service) updateBlockWithInclusionListRoutine() { | ||
if err := s.waitForSync(); err != nil { | ||
log.WithError(err).Error("Failed to wait for initial sync") | ||
return | ||
} | ||
|
||
interval := time.Second*time.Duration(params.BeaconConfig().SecondsPerSlot) - updateInclusionListBlockInterval | ||
ticker := slots.NewSlotTickerWithIntervals(s.genesisTime, []time.Duration{interval}) | ||
|
||
for { | ||
select { | ||
case <-s.ctx.Done(): | ||
return | ||
case <-ticker.C(): | ||
s.updateBlockWithInclusionList(context.Background()) | ||
} | ||
} | ||
} | ||
|
||
// Updates block building with inclusion lists, the current payload ID, and the new upload ID. | ||
func (s *Service) updateBlockWithInclusionList(ctx context.Context) { | ||
currentSlot := s.CurrentSlot() | ||
|
||
// Skip update if not in or past the FOCIL fork epoch. | ||
if slots.ToEpoch(currentSlot) < params.BeaconConfig().FocilForkEpoch { | ||
return | ||
} | ||
|
||
s.cfg.ForkChoiceStore.RLock() | ||
defer s.cfg.ForkChoiceStore.RUnlock() | ||
|
||
headRoot := s.headRoot() | ||
id, found := s.cfg.PayloadIDCache.PayloadID(currentSlot+1, headRoot) | ||
if !found { | ||
return | ||
} | ||
|
||
txs := s.inclusionListCache.Get(currentSlot) | ||
newID, err := s.cfg.ExecutionEngineCaller.UpdatePayloadWithInclusionList(ctx, id, txs) | ||
if err != nil { | ||
log.WithError(err).Error("Failed to update block with inclusion list") | ||
return | ||
} | ||
|
||
s.cfg.PayloadIDCache.Set(currentSlot+1, headRoot, *newID) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package cache | ||
|
||
import ( | ||
"crypto/sha256" | ||
"sync" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" | ||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" | ||
) | ||
|
||
// InclusionLists maintains a thread-safe map of ValidatorIndex to generic types. | ||
type InclusionLists[T any] struct { | ||
mu sync.Mutex | ||
ils map[primitives.ValidatorIndex]*T | ||
} | ||
|
||
// NewInclusionLists initializes a new InclusionLists instance. | ||
func NewInclusionLists[T any]() *InclusionLists[T] { | ||
return &InclusionLists[T]{ | ||
ils: make(map[primitives.ValidatorIndex]*T), | ||
} | ||
} | ||
|
||
// Add adds or updates an entry in the map with a given InclusionList. | ||
// It tracks if >1 inclusion list is seen for a given validator index by converting the value to a Slot type. | ||
func (c *InclusionLists[T]) Add(il *ethpb.InclusionList) error { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
c.prune(il.Slot) | ||
|
||
if current, exists := c.ils[il.ValidatorIndex]; exists { | ||
if existingIL, ok := any(current).(*ethpb.InclusionList); ok && existingIL.Slot == il.Slot { | ||
if slot, ok := any(il.Slot).(T); ok { | ||
c.ils[il.ValidatorIndex] = &slot | ||
return nil | ||
} | ||
return errors.New("type mismatch: expected Slot type") | ||
} | ||
} | ||
|
||
if value, ok := any(il).(T); ok { | ||
c.ils[il.ValidatorIndex] = &value | ||
return nil | ||
} | ||
return errors.New("type mismatch: expected InclusionList type") | ||
} | ||
|
||
// Get retrieves all unique transactions for the given slot. | ||
func (c *InclusionLists[T]) Get(slot primitives.Slot) [][]byte { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
c.prune(slot) | ||
|
||
seen := make(map[[32]byte]struct{}) | ||
var txs [][]byte | ||
|
||
for _, entry := range c.ils { | ||
if il, ok := any(entry).(*ethpb.InclusionList); ok && il != nil { | ||
for _, tx := range il.Transactions { | ||
hash := sha256.Sum256(tx) | ||
if _, found := seen[hash]; found { | ||
continue | ||
} | ||
seen[hash] = struct{}{} | ||
txs = append(txs, tx) | ||
} | ||
} | ||
} | ||
|
||
return txs | ||
} | ||
|
||
// SeenTwice checks if a validator index is associated with a Slot type value. | ||
func (c *InclusionLists[T]) SeenTwice(idx primitives.ValidatorIndex) bool { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
entry, exists := c.ils[idx] | ||
if !exists { | ||
return false | ||
} | ||
|
||
_, isSlot := any(entry).(primitives.Slot) | ||
return isSlot | ||
} | ||
|
||
// prune removes outdated entries from the map based on the slot. | ||
func (c *InclusionLists[T]) prune(slot primitives.Slot) { | ||
for idx, entry := range c.ils { | ||
switch v := any(entry).(type) { | ||
case *ethpb.InclusionList: | ||
if v != nil && v.Slot+2 <= slot { | ||
delete(c.ils, idx) | ||
} | ||
case primitives.Slot: | ||
if v+2 <= slot { | ||
delete(c.ils, idx) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.