Skip to content

Commit

Permalink
Merge pull request #871 from iotaledger/feat/children-as-set
Browse files Browse the repository at this point in the history
Block children as set
  • Loading branch information
jonastheis authored Mar 25, 2024
2 parents 11c39f7 + 8322ca7 commit 4ddfa64
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 62 deletions.
95 changes: 38 additions & 57 deletions pkg/protocol/engine/blocks/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -24,6 +23,7 @@ type Block struct {
strongChildren []*Block
weakChildren []*Block
shallowLikeChildren []*Block
allChildren ds.Set[*Block]

// Booker block
booked reactive.Variable[bool]
Expand Down Expand Up @@ -74,71 +74,60 @@ 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](),
preAccepted: reactive.NewVariable[bool](),
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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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()))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -719,7 +719,7 @@ func (s *Scheduler) updateChildrenWithoutLocking(block *blocks.Block) {
panic("invalid block type")
}
}
}
})
}

func (s *Scheduler) maxDeficit() Deficit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion pkg/tests/upgrade_signaling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down

0 comments on commit 4ddfa64

Please sign in to comment.