Skip to content

Commit

Permalink
Merge pull request #930 from iotaledger/fix/chaineviction
Browse files Browse the repository at this point in the history
Fix: Bug with chain eviction
  • Loading branch information
piotrm50 authored Apr 24, 2024
2 parents 8e76ce9 + 5499679 commit 2fdae82
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 21 deletions.
20 changes: 12 additions & 8 deletions pkg/protocol/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,6 @@ func (c *Chain) initLogger() (shutdown func()) {
// initDerivedProperties initializes the behavior of this chain by setting up the relations between its properties.
func (c *Chain) initDerivedProperties() (shutdown func()) {
return lo.BatchReverse(
c.deriveWarpSyncMode(),

c.shouldEvict.OnTrigger(func() { go c.IsEvicted.Trigger() }),

lo.BatchReverse(
Expand All @@ -245,7 +243,13 @@ func (c *Chain) initDerivedProperties() (shutdown func()) {
}),
),

c.Engine.WithNonEmptyValue(c.deriveOutOfSyncThreshold),
c.Engine.WithNonEmptyValue(func(engine *engine.Engine) (teardown func()) {
return lo.BatchReverse(
c.deriveWarpSyncMode(engine),

c.deriveOutOfSyncThreshold(engine),
)
}),
)
}

Expand All @@ -268,16 +272,16 @@ func (c *Chain) deriveShouldEvict(forkingPoint *Commitment, parentChain *Chain)
}

// deriveWarpSyncMode defines how a chain determines whether it is in warp sync mode or not.
func (c *Chain) deriveWarpSyncMode() func() {
return c.WarpSyncMode.DeriveValueFrom(reactive.NewDerivedVariable3(func(warpSyncMode bool, latestSyncedSlot iotago.SlotIndex, latestSeenSlot iotago.SlotIndex, outOfSyncThreshold iotago.SlotIndex) bool {
func (c *Chain) deriveWarpSyncMode(engine *engine.Engine) func() {
return c.WarpSyncMode.DeriveValueFrom(reactive.NewDerivedVariable4(func(warpSyncMode bool, engineInitialized bool, latestSyncedSlot iotago.SlotIndex, latestSeenSlot iotago.SlotIndex, outOfSyncThreshold iotago.SlotIndex) bool {
// if warp sync mode is enabled, keep it enabled until we have synced all slots
if warpSyncMode {
return latestSyncedSlot < latestSeenSlot
return engineInitialized && latestSyncedSlot < latestSeenSlot
}

// if warp sync mode is disabled, enable it only if we fall below the out of sync threshold
return latestSyncedSlot < outOfSyncThreshold
}, c.LatestSyncedSlot, c.chains.LatestSeenSlot, c.OutOfSyncThreshold, c.WarpSyncMode.Get()))
return engineInitialized && latestSyncedSlot < outOfSyncThreshold
}, engine.InitializedEvent(), c.LatestSyncedSlot, c.chains.LatestSeenSlot, c.OutOfSyncThreshold, c.WarpSyncMode.Get()))
}

// deriveChildChains defines how a chain determines its ChildChains (by adding each child to the set).
Expand Down
13 changes: 2 additions & 11 deletions pkg/protocol/commitment.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,15 +324,6 @@ func (c *Commitment) deriveChain(parent *Commitment) func() {
return currentChain
}

// If we are the main child of our parent, and our chain is not the parent chain,
// then we inherit the parent chain and evict the current one.
// We will spawn a new one if we ever change back to not being the main child.
// Here we basically move commitments to the parent chain.
if currentChain != nil && currentChain != parentChain {
// TODO: refactor it to use a dedicated WorkerPool
go currentChain.IsEvicted.Trigger()
}

return parentChain
}, c.IsRoot, parent.MainChild, parent.Chain, c.Chain.Get()))
}
Expand Down Expand Up @@ -368,8 +359,8 @@ func (c *Commitment) deriveIsAboveLatestVerifiedCommitment(parent *Commitment) f
// deriveRequestAttestations derives the RequestAttestations flag of this Commitment which is true if our Chain is
// requesting attestations (while not having an engine), and we are the directly above the latest attested Commitment.
func (c *Commitment) deriveRequestAttestations(chain *Chain, parent *Commitment) func() {
return c.RequestAttestations.DeriveValueFrom(reactive.NewDerivedVariable4(func(_ bool, startEngine bool, verifyAttestations bool, parentIsAttested bool, isAttested bool) bool {
return !startEngine && verifyAttestations && parentIsAttested && !isAttested
return c.RequestAttestations.DeriveValueFrom(reactive.NewDerivedVariable4(func(_ bool, startEngine bool, requestAttestations bool, parentIsAttested bool, isAttested bool) bool {
return !startEngine && requestAttestations && parentIsAttested && !isAttested
}, chain.StartEngine, chain.RequestAttestations, parent.IsAttested, c.IsAttested))
}

Expand Down
17 changes: 15 additions & 2 deletions pkg/protocol/sybilprotection/sybilprotectionv1/sybilprotection.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (o *SybilProtection) CommitSlot(slot iotago.SlotIndex) (committeeRoot iotag
// If the committed slot is `maxCommittableAge` away from the end of the epoch, then register (reuse)
// a committee for the next epoch if it hasn't been selected yet.
if slot+maxCommittableAge == currentEpochEndSlot {
if _, committeeExists := o.seatManager.CommitteeInEpoch(nextEpoch); !committeeExists {
if committee, committeeExists := o.seatManager.CommitteeInEpoch(nextEpoch); !committeeExists {
// If the committee for the epoch wasn't set before due to finalization of a slot,
// we promote the current committee to also serve in the next epoch.
committeeAccounts, err := o.reuseCommittee(currentEpoch, nextEpoch)
Expand All @@ -169,6 +169,9 @@ func (o *SybilProtection) CommitSlot(slot iotago.SlotIndex) (committeeRoot iotag
}

o.events.CommitteeSelected.Trigger(committeeAccounts, nextEpoch)
o.LogDebug("reusing committee", "nextEpoch", nextEpoch, "committeeIDs", committeeAccounts.IDs())
} else {
o.LogDebug("not reusing committee", "nextEpoch", nextEpoch, "committeeIDs", committee.IDs())
}
}

Expand Down Expand Up @@ -230,7 +233,11 @@ func (o *SybilProtection) committeeRoot(targetCommitteeEpoch iotago.EpochIndex)
iotago.AccountIDFromBytes,
)

for _, accountID := range committee.IDs() {
committeeIDs := committee.IDs()

o.LogDebug("generating committee root", "committeeIDs", committeeIDs, "epoch", targetCommitteeEpoch)

for _, accountID := range committeeIDs {
if err = committeeTree.Add(accountID); err != nil {
return iotago.Identifier{}, ierrors.Wrapf(err, "failed to add account %s to committee tree", accountID)
}
Expand Down Expand Up @@ -411,13 +418,17 @@ func (o *SybilProtection) selectNewCommittee(slot iotago.SlotIndex) (*account.Se
return nil, ierrors.Wrapf(err, "failed to retrieve candidates for epoch %d", nextEpoch)
}

o.LogDebug("selecting new committee", "candidates", candidates.ToSlice(), "slot", slot)

// If there's no candidate, reuse the current committee.
if candidates.Size() == 0 {
committee, err := o.reuseCommittee(currentEpoch, nextEpoch)
if err != nil {
return nil, ierrors.Wrapf(err, "failed to reuse committee (due to no candidates) for epoch %d", nextEpoch)
}

o.LogDebug("candidates empty, reusing committee", "candidates", committee.IDs(), "slot", slot)

return committee, nil
}

Expand Down Expand Up @@ -445,6 +456,8 @@ func (o *SybilProtection) selectNewCommittee(slot iotago.SlotIndex) (*account.Se

o.performanceTracker.ClearCandidates()

o.LogDebug("rotating committee", "candidates", newCommittee.IDs(), "slot", slot)

return newCommittee, nil
}

Expand Down

0 comments on commit 2fdae82

Please sign in to comment.