diff --git a/pkg/protocol/engine/blocks/block.go b/pkg/protocol/engine/blocks/block.go index 41aa4a27b..b67493b8a 100644 --- a/pkg/protocol/engine/blocks/block.go +++ b/pkg/protocol/engine/blocks/block.go @@ -6,7 +6,6 @@ import ( "github.com/iotaledger/hive.go/ds" "github.com/iotaledger/hive.go/ds/reactive" - "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/syncutils" "github.com/iotaledger/hive.go/stringify" @@ -24,6 +23,7 @@ type Block struct { strongChildren []*Block weakChildren []*Block shallowLikeChildren []*Block + allChildren ds.Set[*Block] // Booker block booked reactive.Variable[bool] @@ -74,15 +74,13 @@ func (r *rootBlock) String() string { return builder.String() } -// NewBlock creates a new Block with the given options. -func NewBlock(modelBlock *model.Block) *Block { +func newEmptyBlock() *Block { return &Block{ witnesses: ds.NewSet[account.SeatIndex](), spenderIDs: ds.NewSet[iotago.TransactionID](), payloadSpenderIDs: ds.NewSet[iotago.TransactionID](), acceptanceRatifiers: ds.NewSet[account.SeatIndex](), confirmationRatifiers: ds.NewSet[account.SeatIndex](), - modelBlock: modelBlock, solid: reactive.NewVariable[bool](), invalid: reactive.NewVariable[bool](), booked: reactive.NewVariable[bool](), @@ -90,55 +88,46 @@ func NewBlock(modelBlock *model.Block) *Block { accepted: reactive.NewVariable[bool](), weightPropagated: reactive.NewVariable[bool](), notarized: reactive.NewEvent(), - workScore: modelBlock.WorkScore(), + allChildren: ds.NewSet[*Block](), } } -func NewRootBlock(blockID iotago.BlockID, commitmentID iotago.CommitmentID, issuingTime time.Time) *Block { - b := &Block{ - witnesses: ds.NewSet[account.SeatIndex](), - spenderIDs: ds.NewSet[iotago.TransactionID](), - payloadSpenderIDs: ds.NewSet[iotago.TransactionID](), - acceptanceRatifiers: ds.NewSet[account.SeatIndex](), - confirmationRatifiers: ds.NewSet[account.SeatIndex](), +// NewBlock creates a new Block with the given options. +func NewBlock(modelBlock *model.Block) *Block { + b := newEmptyBlock() + b.modelBlock = modelBlock + b.workScore = modelBlock.WorkScore() + + return b +} - rootBlock: &rootBlock{ - blockID: blockID, - commitmentID: commitmentID, - issuingTime: issuingTime, - }, - solid: reactive.NewVariable[bool]().Init(true), - invalid: reactive.NewVariable[bool](), - booked: reactive.NewVariable[bool]().Init(true), - preAccepted: reactive.NewVariable[bool]().Init(true), - accepted: reactive.NewVariable[bool]().Init(true), - weightPropagated: reactive.NewVariable[bool]().Init(true), - notarized: reactive.NewEvent(), - scheduled: true, +func NewRootBlock(blockID iotago.BlockID, commitmentID iotago.CommitmentID, issuingTime time.Time) *Block { + b := newEmptyBlock() + b.rootBlock = &rootBlock{ + blockID: blockID, + commitmentID: commitmentID, + issuingTime: issuingTime, } + b.scheduled = true + + // This should be true since we commit and evict on acceptance. + b.solid.Init(true) + b.booked.Init(true) + b.weightPropagated.Init(true) + b.preAccepted.Init(true) + b.accepted.Init(true) b.notarized.Trigger() return b } func NewMissingBlock(blockID iotago.BlockID) *Block { - return &Block{ - missing: true, - missingBlockID: blockID, - witnesses: ds.NewSet[account.SeatIndex](), - spenderIDs: ds.NewSet[iotago.TransactionID](), - payloadSpenderIDs: ds.NewSet[iotago.TransactionID](), - acceptanceRatifiers: ds.NewSet[account.SeatIndex](), - confirmationRatifiers: ds.NewSet[account.SeatIndex](), - solid: reactive.NewVariable[bool](), - invalid: reactive.NewVariable[bool](), - booked: reactive.NewVariable[bool](), - preAccepted: reactive.NewVariable[bool](), - accepted: reactive.NewVariable[bool](), - weightPropagated: reactive.NewVariable[bool](), - notarized: reactive.NewEvent(), - } + b := newEmptyBlock() + b.missing = true + b.missingBlockID = blockID + + return b } func (b *Block) ProtocolBlock() *iotago.Block { @@ -291,25 +280,11 @@ func (b *Block) SetInvalid() (wasUpdated bool) { } // Children returns the children of the Block. -func (b *Block) Children() (children []*Block) { +func (b *Block) Children() ds.ReadableSet[*Block] { b.mutex.RLock() defer b.mutex.RUnlock() - seenBlockIDs := make(map[iotago.BlockID]types.Empty) - for _, parentsByType := range [][]*Block{ - b.strongChildren, - b.weakChildren, - b.shallowLikeChildren, - } { - for _, childMetadata := range parentsByType { - if _, exists := seenBlockIDs[childMetadata.ID()]; !exists { - children = append(children, childMetadata) - seenBlockIDs[childMetadata.ID()] = types.Void - } - } - } - - return children + return b.allChildren } func (b *Block) StrongChildren() []*Block { @@ -345,6 +320,8 @@ func (b *Block) AppendChild(child *Block, childType iotago.ParentsType) { case iotago.ShallowLikeParentType: b.shallowLikeChildren = append(b.shallowLikeChildren, child) } + + b.allChildren.Add(child) } // Update publishes the given Block data to the underlying Block and marks it as no longer missing. @@ -661,6 +638,10 @@ func (b *Block) String() string { builder.AddField(stringify.NewStructField(fmt.Sprintf("shallowLikeChildren%d", index), child.ID().String())) } + for index, child := range b.allChildren.ToSlice() { + builder.AddField(stringify.NewStructField(fmt.Sprintf("allChildren%d", index), child.ID().String())) + } + if b.rootBlock != nil { builder.AddField(stringify.NewStructField("RootBlock", b.rootBlock.String())) } diff --git a/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go b/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go index d2abba0e3..bc37cdfb4 100644 --- a/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go +++ b/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go @@ -709,7 +709,7 @@ func (s *Scheduler) updateChildrenWithLocking(block *blocks.Block) { // updateChildrenWithoutLocking iterates over the direct children of the given blockID and // tries to mark them as ready. func (s *Scheduler) updateChildrenWithoutLocking(block *blocks.Block) { - for _, childBlock := range block.Children() { + block.Children().Range(func(childBlock *blocks.Block) { if _, childBlockExists := s.blockCache.Block(childBlock.ID()); childBlockExists && childBlock.IsEnqueued() { if _, isBasic := childBlock.BasicBlock(); isBasic { s.tryReady(childBlock) @@ -719,7 +719,7 @@ func (s *Scheduler) updateChildrenWithoutLocking(block *blocks.Block) { panic("invalid block type") } } - } + }) } func (s *Scheduler) maxDeficit() Deficit { diff --git a/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go b/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go index 5d497c9ce..b4da4f5ee 100644 --- a/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go +++ b/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go @@ -111,10 +111,16 @@ func (g *Gadget) isCommitteeValidationBlock(block *blocks.Block) (seat account.S } func anyChildInSet(block *blocks.Block, set ds.Set[iotago.BlockID]) bool { - for _, child := range block.Children() { + if err := block.Children().ForEach(func(child *blocks.Block) error { if set.Has(child.ID()) { - return true + return ierrors.New("stop iteration: child in set") } + + // We continue the iteration if the child is not in the set. + return nil + }); err != nil { + // There can only be the stop iteration error -> there's a child in the set. + return true } return false diff --git a/pkg/tests/upgrade_signaling_test.go b/pkg/tests/upgrade_signaling_test.go index 05de3d917..faea67324 100644 --- a/pkg/tests/upgrade_signaling_test.go +++ b/pkg/tests/upgrade_signaling_test.go @@ -400,7 +400,8 @@ func Test_Upgrade_Signaling(t *testing.T) { // Check that issuing still produces the same commitments on the nodes that upgraded. The nodes that did not upgrade // should not be able to issue and process blocks with the new version. ts.IssueBlocksAtSlots("", []iotago.SlotIndex{64, 65}, 4, "63.3", ts.Nodes("nodeB", "nodeC"), false, false) - ts.IssueBlocksAtSlots("", []iotago.SlotIndex{66, 67, 68, 69, 70, 71}, 4, "65.3", ts.Nodes("nodeB", "nodeC"), true, true) + ts.Wait() + ts.IssueBlocksAtSlots("", []iotago.SlotIndex{65, 66, 67, 68, 69, 70, 71}, 4, "65.3", ts.Nodes("nodeB", "nodeC"), true, false) // Nodes that did not set up the new protocol parameters are not able to process blocks with the new version. ts.AssertNodeState(ts.Nodes("nodeA", "nodeD", "nodeF", "nodeG"),