From 6572c5f98f197323bc95546cb836716e2f4a93b5 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:52:11 +0100 Subject: [PATCH 01/49] Fix: Memleak in Protocol --- pkg/tests/protocol_eviction_test.go | 185 ++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 pkg/tests/protocol_eviction_test.go diff --git a/pkg/tests/protocol_eviction_test.go b/pkg/tests/protocol_eviction_test.go new file mode 100644 index 000000000..57375d6da --- /dev/null +++ b/pkg/tests/protocol_eviction_test.go @@ -0,0 +1,185 @@ +package tests + +import ( + "fmt" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/iotaledger/hive.go/core/eventticker" + "github.com/iotaledger/hive.go/ds" + "github.com/iotaledger/hive.go/runtime/memanalyzer" + "github.com/iotaledger/hive.go/runtime/module" + "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/protocol" + "github.com/iotaledger/iota-core/pkg/protocol/engine" + "github.com/iotaledger/iota-core/pkg/protocol/engine/blocks" + "github.com/iotaledger/iota-core/pkg/protocol/engine/syncmanager/trivialsyncmanager" + "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/seatmanager" + mock2 "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/seatmanager/mock" + "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/sybilprotectionv1" + "github.com/iotaledger/iota-core/pkg/storage" + "github.com/iotaledger/iota-core/pkg/testsuite" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" + iotago "github.com/iotaledger/iota.go/v4" +) + +func TestProtocol_Eviction(t *testing.T) { + var ( + genesisSlot iotago.SlotIndex = 0 + minCommittableAge iotago.SlotIndex = 2 + maxCommittableAge iotago.SlotIndex = 4 + ) + + ts := testsuite.NewTestSuite(t, + testsuite.WithProtocolParametersOptions( + iotago.WithTimeProviderOptions( + genesisSlot, + testsuite.GenesisTimeWithOffsetBySlots(1000, testsuite.DefaultSlotDurationInSeconds), + testsuite.DefaultSlotDurationInSeconds, + 3, + ), + iotago.WithLivenessOptions( + 10, + 10, + minCommittableAge, + maxCommittableAge, + 5, + ), + ), + + testsuite.WithWaitFor(15*time.Second), + ) + defer ts.Shutdown() + + node := ts.AddValidatorNode("node0") + + ts.Run(false, map[string][]options.Option[protocol.Protocol]{ + "node0": []options.Option[protocol.Protocol]{ + protocol.WithSybilProtectionProvider( + sybilprotectionv1.NewProvider( + sybilprotectionv1.WithSeatManagerProvider(module.Provide(func(e *engine.Engine) seatmanager.SeatManager { + poa := mock2.NewManualPOAProvider()(e).(*mock2.ManualPOA) + poa.AddAccount(node.Validator.AccountID, node.Name) + + onlineValidators := ds.NewSet[string]() + + e.Constructed.OnTrigger(func() { + e.Events.BlockDAG.BlockAttached.Hook(func(block *blocks.Block) { + if block.ModelBlock().ProtocolBlock().Header.IssuerID == node.Validator.AccountID && onlineValidators.Add(node.Name) { + e.LogError("node online", "name", node.Name) + poa.SetOnline(onlineValidators.ToSlice()...) + } + }) + }) + + return poa + })), + ), + ), + + protocol.WithEngineOptions( + engine.WithBlockRequesterOptions( + eventticker.RetryInterval[iotago.SlotIndex, iotago.BlockID](1*time.Second), + eventticker.RetryJitter[iotago.SlotIndex, iotago.BlockID](500*time.Millisecond), + ), + ), + + protocol.WithSyncManagerProvider( + trivialsyncmanager.NewProvider( + trivialsyncmanager.WithBootstrappedFunc(func(e *engine.Engine) bool { + return e.Notarization.IsBootstrapped() + }), + ), + ), + + protocol.WithStorageOptions( + storage.WithPruningDelay(20), + ), + }, + }) + + node.Protocol.Engines.Main.Get().SybilProtection.SeatManager().(*mock2.ManualPOA).SetOnline("node0") + + // Verify that nodes have the expected states. + { + genesisCommitment := iotago.NewEmptyCommitment(ts.API) + genesisCommitment.ReferenceManaCost = ts.API.ProtocolParameters().CongestionControlParameters().MinReferenceManaCost + ts.AssertNodeState(ts.Nodes(), + testsuite.WithSnapshotImported(true), + testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), + testsuite.WithLatestCommitment(genesisCommitment), + testsuite.WithLatestFinalizedSlot(0), + testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), + + testsuite.WithSybilProtectionCommittee(0, []iotago.AccountID{node.Validator.AccountID}), + testsuite.WithEvictedSlot(0), + testsuite.WithActiveRootBlocks(ts.Blocks("Genesis")), + testsuite.WithStorageRootBlocks(ts.Blocks("Genesis")), + ) + } + + issueBlocks := func(slots []iotago.SlotIndex) { + parentSlot := slots[0] - 1 + lastIssuedSlot := slots[len(slots)-1] + lastCommittedSlot := lastIssuedSlot - minCommittableAge + + initialParentsPrefix := "P0:" + strconv.Itoa(int(parentSlot)) + ".3" + if parentSlot == genesisSlot { + initialParentsPrefix = "Genesis" + } + + ts.IssueBlocksAtSlots("P0:", slots, 4, initialParentsPrefix, []*mock.Node{node}, true, true) + + cumulativeAttestations := uint64(0) + for slot := genesisSlot + maxCommittableAge; slot <= lastCommittedSlot; slot++ { + var attestationBlocks Blocks + attestationBlocks.Add(ts, node, 0, slot) + + cumulativeAttestations++ + + ts.AssertAttestationsForSlot(slot, attestationBlocks, node) + } + + ts.AssertNodeState([]*mock.Node{node}, + testsuite.WithLatestFinalizedSlot(lastCommittedSlot-1), + testsuite.WithLatestCommitmentSlotIndex(lastCommittedSlot), + testsuite.WithEqualStoredCommitmentAtIndex(lastCommittedSlot), + testsuite.WithLatestCommitmentCumulativeWeight(cumulativeAttestations), + testsuite.WithSybilProtectionCommittee(ts.API.TimeProvider().EpochFromSlot(lastCommittedSlot), []iotago.AccountID{node.Validator.AccountID}), + testsuite.WithEvictedSlot(lastCommittedSlot), + ) + + var tipBlocks Blocks + tipBlocks.Add(ts, node, 0, lastIssuedSlot) + + ts.AssertStrongTips(tipBlocks, node) + } + + // issue blocks until we evict the first slot + issueBlocks([]iotago.SlotIndex{1, 2, 3, 4, 5, 6, 7, 8}) + + memConsumptionStart := memConsumption(node) + fmt.Println(memConsumptionStart) + + // issue more blocks + issueBlocks([]iotago.SlotIndex{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}) + + memConsumptionEnd := memConsumption(node) + fmt.Println(memConsumptionEnd) + + // make sure the memory does not grow by more than 5% + for key, memStart := range memConsumptionStart { + require.Less(t, float64(memConsumptionEnd[key]), 1.05*float64(memStart), key+" should not grow by more than 5%") + } +} + +func memConsumption(node *mock.Node) map[string]uintptr { + return map[string]uintptr{ + "Engine": memanalyzer.MemSize(node.Protocol.Engines.Main.Get()), + "Protocol": memanalyzer.MemSize(node.Protocol), + } +} From b2a5f7872ac018faf015cdbb505e01d61ea7ab76 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Fri, 16 Feb 2024 02:58:53 +0100 Subject: [PATCH 02/49] Fix: memleak fixed + added tooling for manual traversal --- pkg/core/traversed/object.go | 94 +++++++++++++++++++++++++++++ pkg/protocol/chain.go | 20 ++++++ pkg/protocol/chains.go | 12 ++++ pkg/protocol/commitment.go | 15 +++++ pkg/protocol/commitments.go | 27 +++++++++ pkg/protocol/protocol.go | 8 +++ pkg/tests/protocol_eviction_test.go | 40 ++++++------ 7 files changed, 198 insertions(+), 18 deletions(-) create mode 100644 pkg/core/traversed/object.go diff --git a/pkg/core/traversed/object.go b/pkg/core/traversed/object.go new file mode 100644 index 000000000..027d1c191 --- /dev/null +++ b/pkg/core/traversed/object.go @@ -0,0 +1,94 @@ +package traversed + +import ( + "strings" + + "github.com/iotaledger/hive.go/ds/orderedmap" + "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/hive.go/stringify" +) + +type Object struct { + typeName string + instanceID string + childObjects *orderedmap.OrderedMap[string, *Object] + visitedObjects SeenElements + visited bool +} + +func NewObject(typeName string, instanceID string, traverse func(*Object), seenElements ...SeenElements) *Object { + o := &Object{ + typeName: typeName, + instanceID: instanceID, + visitedObjects: lo.First(seenElements, make(SeenElements)), + childObjects: orderedmap.New[string, *Object](), + } + + if o.visitedObjects[instanceID] { + o.visited = true + } else { + o.visitedObjects[instanceID] = true + + traverse(o) + } + + return o +} + +func (m *Object) AddTraversable(key string, object Traversable) { + if stringify.IsInterfaceNil(object) { + m.childObjects.Set(key, nil) + } else { + m.childObjects.Set(key, object.Traverse(m.visitedObjects)) + } +} + +func (m *Object) AddNewObject(key string, typeName string, instanceIdentifier string, setup func(set *Object)) { + m.childObjects.Set(key, NewObject(typeName, instanceIdentifier, setup, m.visitedObjects)) +} + +func (m *Object) String() string { + return m.string(0) +} + +func (m *Object) string(indent int) string { + if m == nil { + return "nil" + } + + var typeString string + if m.typeName == m.instanceID { + typeString = m.typeName + } else { + typeString = m.typeName + "(" + m.instanceID + ")" + } + + if m.visited { + return typeString + " {...}" + } + + childOutputs := make([]string, 0) + m.childObjects.ForEach(func(key string, value *Object) bool { + if value != nil && value.typeName == key { + childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentSize)+value.string(indent+1)) + } else { + childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentSize)+key+": "+value.string(indent+1)) + } + + return true + }) + + if len(childOutputs) == 0 { + return typeString + " {}" + } + + return typeString + " {\n" + strings.Join(childOutputs, ",\n") + "\n" + strings.Repeat(" ", (indent)*indentSize) + "}" +} + +type Traversable interface { + Traverse(seenElements ...SeenElements) *Object +} + +type SeenElements map[any]bool + +const indentSize = 2 diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 366f138a1..a03cf2074 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -1,12 +1,15 @@ package protocol import ( + "fmt" + "github.com/libp2p/go-libp2p/core/peer" "github.com/iotaledger/hive.go/ds/reactive" "github.com/iotaledger/hive.go/ds/shrinkingmap" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/log" + "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -165,6 +168,19 @@ func (c *Chain) LatestEngine() *engine.Engine { return currentEngine } +func (c *Chain) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { + return traversed.NewObject("Chain", c.LogName(), func(chain *traversed.Object) { + chain.AddTraversable("ForkingPoint", c.ForkingPoint.Get()) + chain.AddTraversable("ParentChain", c.ParentChain.Get()) + + chain.AddNewObject("ChildChains", "Set", fmt.Sprintf("%p", c.ChildChains), func(childChains *traversed.Object) { + c.ChildChains.Range(func(childChain *Chain) { + childChains.AddTraversable(childChain.LogName(), childChain) + }) + }) + }, seenObjects...) +} + // initLogger initializes the Logger of this chain. func (c *Chain) initLogger() (shutdown func()) { c.Logger = c.chains.NewChildLogger("", true) @@ -261,6 +277,10 @@ func (c *Chain) addCommitment(newCommitment *Commitment) (shutdown func()) { newCommitment.IsAttested.OnTrigger(func() { c.LatestAttestedCommitment.Set(newCommitment) }), newCommitment.IsVerified.OnTrigger(func() { c.LatestProducedCommitment.Set(newCommitment) }), newCommitment.IsSynced.OnTrigger(func() { c.LatestSyncedSlot.Set(newCommitment.Slot()) }), + + func() { + c.commitments.Delete(newCommitment.Slot()) + }, ) } diff --git a/pkg/protocol/chains.go b/pkg/protocol/chains.go index 6bb8cc277..528bb77f2 100644 --- a/pkg/protocol/chains.go +++ b/pkg/protocol/chains.go @@ -2,6 +2,7 @@ package protocol import ( "cmp" + "fmt" "github.com/libp2p/go-libp2p/core/peer" @@ -9,6 +10,7 @@ import ( "github.com/iotaledger/hive.go/ds/shrinkingmap" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/log" + "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -81,6 +83,16 @@ func (c *Chains) WithInitializedEngines(callback func(chain *Chain, engine *engi }) } +func (c *Chains) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { + return traversed.NewObject("Chains", c.LogName(), func(o *traversed.Object) { + o.AddNewObject("Set", "Set", fmt.Sprintf("%p", c.Set), func(set *traversed.Object) { + c.Range(func(chain *Chain) { + set.AddTraversable(chain.LogName(), chain) + }) + }) + }, seenObjects...) +} + // initLogger initializes the logger for this component. func (c *Chains) initLogger(logger log.Logger) (shutdown func()) { c.Logger = logger diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index d6455ef92..b0e2d57d6 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -8,6 +8,7 @@ import ( "github.com/iotaledger/hive.go/ds/reactive" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/log" + "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -137,6 +138,20 @@ func (c *Commitment) TargetEngine() *engine.Engine { return nil } +func (c *Commitment) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { + return traversed.NewObject("Commitment", c.LogName(), func(o *traversed.Object) { + o.AddTraversable("Parent", c.Parent.Get()) + o.AddTraversable("MainChild", c.MainChild.Get()) + o.AddTraversable("Chain", c.Chain.Get()) + + o.AddNewObject("Children", "Set", fmt.Sprintf("%p", c.Children), func(children *traversed.Object) { + c.Children.Range(func(child *Commitment) { + children.AddTraversable(child.LogName(), child) + }) + }) + }, seenObjects...) +} + // Less is a function that is used to break ties between two Commitments that have the same cumulative weight by using // the ID of their divergence points (the first commitment that is different between their chains). func (c *Commitment) Less(other *Commitment) bool { diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 28ccb27a4..f3b25c73c 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -1,6 +1,8 @@ package protocol import ( + "fmt" + "github.com/libp2p/go-libp2p/core/peer" "github.com/iotaledger/hive.go/core/eventticker" @@ -11,6 +13,7 @@ import ( "github.com/iotaledger/hive.go/log" "github.com/iotaledger/hive.go/runtime/workerpool" "github.com/iotaledger/iota-core/pkg/core/promise" + "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -97,6 +100,26 @@ func (c *Commitments) API(commitmentID iotago.CommitmentID) (commitmentAPI *engi return commitment.TargetEngine().CommitmentAPI(commitmentID) } +func (c *Commitments) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { + return traversed.NewObject("Commitments", c.LogName(), func(o *traversed.Object) { + o.AddNewObject("Set", "Set", fmt.Sprintf("%p", c.Set), func(set *traversed.Object) { + c.Range(func(commitment *Commitment) { + set.AddTraversable(commitment.LogName(), commitment) + }) + }) + + o.AddNewObject("cachedRequests", "ShrinkingMap", "ShrinkingMap", func(cachedRequests *traversed.Object) { + c.cachedRequests.ForEach(func(commitmentID iotago.CommitmentID, cachedRequest *promise.Promise[*Commitment]) bool { + if commitment := cachedRequest.Result(); commitment != nil { + cachedRequests.AddTraversable(commitmentID.String(), commitment) + } + + return true + }) + }) + }, seenObjects...) +} + // initLogger initializes the logger for this component. func (c *Commitments) initLogger() (shutdown func()) { c.Logger = c.protocol.NewChildLogger("Commitments") @@ -273,6 +296,10 @@ func (c *Commitments) initCommitment(commitment *Commitment, slotEvicted reactiv // solidify the parent of the commitment c.cachedRequest(commitment.PreviousCommitmentID(), true).OnSuccess(func(parent *Commitment) { commitment.Parent.Set(parent) + + parent.IsEvicted.OnTrigger(func() { + commitment.Parent.Set(nil) + }) }) // add commitment to the set diff --git a/pkg/protocol/protocol.go b/pkg/protocol/protocol.go index d836bb772..227edfc18 100644 --- a/pkg/protocol/protocol.go +++ b/pkg/protocol/protocol.go @@ -14,6 +14,7 @@ import ( "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/hive.go/runtime/workerpool" + "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/network" "github.com/iotaledger/iota-core/pkg/network/protocols/core" @@ -142,6 +143,13 @@ func (p *Protocol) LatestAPI() iotago.API { return p.Engines.Main.Get().LatestAPI() } +func (p *Protocol) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { + return traversed.NewObject("Protocol", p.LogName(), func(o *traversed.Object) { + o.AddTraversable("Commitments", p.Commitments) + o.AddTraversable("Chains", p.Chains) + }, seenObjects...) +} + // initSubcomponents initializes the subcomponents of the protocol and returns a function that shuts them down. func (p *Protocol) initSubcomponents(networkEndpoint network.Endpoint) (shutdown func()) { p.Network = core.NewProtocol(networkEndpoint, p.Workers.CreatePool("NetworkProtocol"), p) diff --git a/pkg/tests/protocol_eviction_test.go b/pkg/tests/protocol_eviction_test.go index 57375d6da..ad0769b78 100644 --- a/pkg/tests/protocol_eviction_test.go +++ b/pkg/tests/protocol_eviction_test.go @@ -6,11 +6,12 @@ import ( "testing" "time" + "github.com/fjl/memsize" "github.com/stretchr/testify/require" "github.com/iotaledger/hive.go/core/eventticker" "github.com/iotaledger/hive.go/ds" - "github.com/iotaledger/hive.go/runtime/memanalyzer" + "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/protocol" @@ -159,27 +160,30 @@ func TestProtocol_Eviction(t *testing.T) { ts.AssertStrongTips(tipBlocks, node) } + lastIssuedSlot := iotago.SlotIndex(0) + + issueBlocksTill := func(slot iotago.SlotIndex) { + slotsToIssue := make([]iotago.SlotIndex, slot-lastIssuedSlot) + for currentSlot := lastIssuedSlot + 1; currentSlot <= slot; currentSlot++ { + slotsToIssue[currentSlot-lastIssuedSlot-1] = currentSlot + } + + issueBlocks(slotsToIssue) + + lastIssuedSlot = slot + } + // issue blocks until we evict the first slot - issueBlocks([]iotago.SlotIndex{1, 2, 3, 4, 5, 6, 7, 8}) + issueBlocksTill(8) - memConsumptionStart := memConsumption(node) - fmt.Println(memConsumptionStart) + memConsumptionStart := memsize.Scan(node.Protocol).Total + fmt.Println(node.Protocol.Traverse()) // issue more blocks - issueBlocks([]iotago.SlotIndex{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}) + issueBlocksTill(100) - memConsumptionEnd := memConsumption(node) - fmt.Println(memConsumptionEnd) + memConsumptionEnd := memsize.Scan(node.Protocol).Total + fmt.Println(node.Protocol.Traverse()) - // make sure the memory does not grow by more than 5% - for key, memStart := range memConsumptionStart { - require.Less(t, float64(memConsumptionEnd[key]), 1.05*float64(memStart), key+" should not grow by more than 5%") - } -} - -func memConsumption(node *mock.Node) map[string]uintptr { - return map[string]uintptr{ - "Engine": memanalyzer.MemSize(node.Protocol.Engines.Main.Get()), - "Protocol": memanalyzer.MemSize(node.Protocol), - } + require.Less(t, float64(lo.Return1(memConsumptionEnd)), 1.05*float64(memConsumptionStart), "memory consumption should not grow by more than 5%") } From b592c2a9ce2a885f751e56c240cea775d551ca6d Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:07:56 +0100 Subject: [PATCH 03/49] Skip eviction test with -race flag --- pkg/tests/protocol_eviction_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/tests/protocol_eviction_test.go b/pkg/tests/protocol_eviction_test.go index ad0769b78..583f480f0 100644 --- a/pkg/tests/protocol_eviction_test.go +++ b/pkg/tests/protocol_eviction_test.go @@ -28,6 +28,10 @@ import ( ) func TestProtocol_Eviction(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in -race mode.") + } + var ( genesisSlot iotago.SlotIndex = 0 minCommittableAge iotago.SlotIndex = 2 From ba425fa8b5005d4f1502ff9f7cf69c052ac9f64f Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:35:27 +0100 Subject: [PATCH 04/49] Fix commitment eviction --- pkg/protocol/commitment.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index b0e2d57d6..acb53e102 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -316,13 +316,24 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) // deriveChain derives the Chain of this Commitment which is either inherited from the parent if we are the main child // or a newly created chain. func (c *Commitment) deriveChain(parent *Commitment) func() { - return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable3(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain) *Chain { + return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable4(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain, isParentEvicted bool) *Chain { // do not adjust the chain of the root commitment (it is set from the outside) if isRoot { return currentChain } - // if we are not the main child of our parent, we spawn a new chain + // If the parent commitment is evicted and the current commitment is not the root, + // that means that the chain is an orphaned fork, and we should not spawn a new chain. + // Eventually, the commitments on the orphaned chain in a given slot will be evicted once the finalized slot advances. + if isParentEvicted { + if currentChain != nil { + currentChain.IsEvicted.Trigger() + } + + return nil + } + + // if we are not the main child of our parent, we spawn a new chain (new fork) if c != mainChild { if currentChain == nil { currentChain = c.commitments.protocol.Chains.newChain() @@ -337,10 +348,12 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { // main child) if currentChain != nil && currentChain != parentChain { currentChain.IsEvicted.Trigger() + + return nil } return parentChain - }, c.IsRoot, parent.MainChild, parent.Chain, c.Chain.Get())) + }, c.IsRoot, parent.MainChild, parent.Chain, parent.IsEvicted, c.Chain.Get())) } // deriveCumulativeAttestedWeight derives the CumulativeAttestedWeight of this Commitment which is the sum of the From 441e4673b0594f15e32086d1a24a27b8b4a3442f Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:50:45 +0100 Subject: [PATCH 05/49] Fix: erroneous refactor --- pkg/protocol/chain.go | 17 ++++++++++++++++- pkg/protocol/commitment.go | 19 +++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index a03cf2074..612a60faf 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -207,7 +207,12 @@ func (c *Chain) initDerivedProperties() (shutdown func()) { return lo.Batch( c.deriveWarpSyncMode(), - c.ForkingPoint.WithValue(c.deriveParentChain), + c.ForkingPoint.WithValue(func(forkingPoint *Commitment) (teardown func()) { + return lo.Batch( + c.deriveParentChain(forkingPoint), + c.deriveIsEvicted(forkingPoint), + ) + }), c.ParentChain.WithNonEmptyValue(lo.Bind(c, (*Chain).deriveChildChains)), c.Engine.WithNonEmptyValue(c.deriveOutOfSyncThreshold), ) @@ -255,6 +260,16 @@ func (c *Chain) deriveParentChain(forkingPoint *Commitment) (shutdown func()) { return nil } +func (c *Chain) deriveIsEvicted(forkingPoint *Commitment) (shutdown func()) { + if forkingPoint == nil { + return + } + + return forkingPoint.IsEvicted.OnTrigger(func() { + c.IsEvicted.Trigger() + }) +} + // deriveOutOfSyncThreshold defines how a chain determines its "out of sync" threshold (the latest seen slot minus 2 // times the max committable age or 0 if this would cause an overflow to the negative numbers). func (c *Chain) deriveOutOfSyncThreshold(engineInstance *engine.Engine) func() { diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index acb53e102..b0e2d57d6 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -316,24 +316,13 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) // deriveChain derives the Chain of this Commitment which is either inherited from the parent if we are the main child // or a newly created chain. func (c *Commitment) deriveChain(parent *Commitment) func() { - return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable4(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain, isParentEvicted bool) *Chain { + return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable3(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain) *Chain { // do not adjust the chain of the root commitment (it is set from the outside) if isRoot { return currentChain } - // If the parent commitment is evicted and the current commitment is not the root, - // that means that the chain is an orphaned fork, and we should not spawn a new chain. - // Eventually, the commitments on the orphaned chain in a given slot will be evicted once the finalized slot advances. - if isParentEvicted { - if currentChain != nil { - currentChain.IsEvicted.Trigger() - } - - return nil - } - - // if we are not the main child of our parent, we spawn a new chain (new fork) + // if we are not the main child of our parent, we spawn a new chain if c != mainChild { if currentChain == nil { currentChain = c.commitments.protocol.Chains.newChain() @@ -348,12 +337,10 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { // main child) if currentChain != nil && currentChain != parentChain { currentChain.IsEvicted.Trigger() - - return nil } return parentChain - }, c.IsRoot, parent.MainChild, parent.Chain, parent.IsEvicted, c.Chain.Get())) + }, c.IsRoot, parent.MainChild, parent.Chain, c.Chain.Get())) } // deriveCumulativeAttestedWeight derives the CumulativeAttestedWeight of this Commitment which is the sum of the From adf99f6c22c6bd886b86a355385e83faea595027 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 20 Feb 2024 02:12:12 +0100 Subject: [PATCH 06/49] Fix: fixed more bugs --- pkg/protocol/chain.go | 7 ++++++- pkg/protocol/commitments.go | 3 +-- pkg/tests/protocol_engine_switching_test.go | 4 +++- pkg/tests/protocol_startup_test.go | 6 ++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 612a60faf..caf24d561 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -233,6 +233,10 @@ func (c *Chain) deriveWarpSyncMode() func() { // deriveChildChains defines how a chain determines its ChildChains (by adding each child to the set). func (c *Chain) deriveChildChains(child *Chain) func() { + if child == c { + return nil + } + c.ChildChains.Add(child) return func() { @@ -266,7 +270,8 @@ func (c *Chain) deriveIsEvicted(forkingPoint *Commitment) (shutdown func()) { } return forkingPoint.IsEvicted.OnTrigger(func() { - c.IsEvicted.Trigger() + // TODO: MOVE TO DEDICATED WORKER + go c.IsEvicted.Trigger() }) } diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index f3b25c73c..3286474a0 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -176,8 +176,7 @@ func (c *Commitments) publishRootCommitment(mainChain *Chain, mainEngine *engine publishedCommitment.Chain.Set(mainChain) } - // TODO: USE SET HERE (debug eviction issues) - mainChain.ForkingPoint.DefaultTo(publishedCommitment) + mainChain.ForkingPoint.Set(publishedCommitment) c.Root.Set(publishedCommitment) }) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 71168d92d..65b7dfa08 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -373,7 +373,9 @@ func TestProtocol_EngineSwitching(t *testing.T) { // This is to make sure that the storage was copied correctly during engine switching. ts.AssertBlocksExist(ts.BlocksWithPrefix("P0"), true, ts.Nodes()...) ts.AssertBlocksExist(ts.BlocksWithPrefix("P1"), true, ts.Nodes()...) - ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, ts.Nodes()...) + + // old blocks can exist (we route everything by default to the main chain) but are unsolid + //ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, ts.Nodes()...) ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) } diff --git a/pkg/tests/protocol_startup_test.go b/pkg/tests/protocol_startup_test.go index c9e86a652..1a98bc3a8 100644 --- a/pkg/tests/protocol_startup_test.go +++ b/pkg/tests/protocol_startup_test.go @@ -102,7 +102,8 @@ func Test_BookInCommittedSlot(t *testing.T) { ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithChainID(genesisCommitment.MustID()), + // TODO: remove this? the forking gets updated now on eviction + //testsuite.WithChainID(genesisCommitment.MustID()), testsuite.WithLatestCommitmentSlotIndex(5), testsuite.WithEvictedSlot(5), testsuite.WithActiveRootBlocks(expectedActiveRootBlocks), @@ -270,7 +271,8 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithChainID(genesisCommitment.MustID()), + // TODO: remove this? the forking gets updated now on eviction + //testsuite.WithChainID(genesisCommitment.MustID()), testsuite.WithLatestFinalizedSlot(11), testsuite.WithLatestCommitmentSlotIndex(11), testsuite.WithEqualStoredCommitmentAtIndex(11), From c61292f0be410637d1b2c27fffc063ca369a1aa5 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Tue, 20 Feb 2024 16:11:54 +0100 Subject: [PATCH 07/49] Improve chain management and add logs --- pkg/protocol/blocks.go | 8 +- pkg/protocol/chain.go | 2 + pkg/protocol/commitment.go | 52 +++++++- pkg/tests/protocol_engine_switching_test.go | 19 ++- pkg/testsuite/chainmanager.go | 28 ----- pkg/testsuite/chains.go | 129 ++++++++++++++++++++ pkg/testsuite/node_state.go | 2 +- 7 files changed, 202 insertions(+), 38 deletions(-) delete mode 100644 pkg/testsuite/chainmanager.go create mode 100644 pkg/testsuite/chains.go diff --git a/pkg/protocol/blocks.go b/pkg/protocol/blocks.go index 479033628..9ab6f5cd6 100644 --- a/pkg/protocol/blocks.go +++ b/pkg/protocol/blocks.go @@ -95,8 +95,14 @@ func (b *Blocks) ProcessResponse(block *model.Block, from peer.ID) { return } + if commitment != nil && commitment.IsOrphaned.Get() { + b.LogTrace("discard block from an orphaned chain", "commitmentID", block.ProtocolBlock().Header.SlotCommitmentID, "blockID", block.ID()) + + return + } + // add the block to the dropped blocks buffer if we could not dispatch it to the chain - if commitment == nil || !commitment.Chain.Get().DispatchBlock(block, from) { + if commitment == nil || commitment.IsOrphaned.Get() || !commitment.Chain.Get().DispatchBlock(block, from) { if !b.droppedBlocksBuffer.Add(block.ProtocolBlock().Header.SlotCommitmentID, types.NewTuple(block, from)) { b.LogError("failed to add dropped block referencing unsolid commitment to dropped blocks buffer", "commitmentID", block.ProtocolBlock().Header.SlotCommitmentID, "blockID", block.ID()) } else { diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index caf24d561..84cddc7f3 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -299,6 +299,8 @@ func (c *Chain) addCommitment(newCommitment *Commitment) (shutdown func()) { newCommitment.IsSynced.OnTrigger(func() { c.LatestSyncedSlot.Set(newCommitment.Slot()) }), func() { + // TODO: this should not be done here, because it might cause problems upon chain switching. + // A chain should manage this field by itself. c.commitments.Delete(newCommitment.Slot()) }, ) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index b0e2d57d6..2ac236701 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -85,6 +85,13 @@ type Commitment struct { // IsEvicted contains a flag indicating if this Commitment was evicted from the Protocol. IsEvicted reactive.Event + // IsOrphaned contains a flag indicating if this Commitment is part of an orphaned chain. + // An orphaned chain has its forking point below RootCommitment of the main chain. + // Orphaned commitments are eventually evicted just like other commitments. + // We don't dispatch blocks of orphaned commitments. + // We keep them around to not have to request them every time a block with such a commitment is received. + IsOrphaned reactive.Event + // commitments contains a reference to the Commitments instance that this Commitment belongs to. commitments *Commitments @@ -116,6 +123,7 @@ func newCommitment(commitments *Commitments, model *model.Commitment) *Commitmen IsAboveLatestVerifiedCommitment: reactive.NewVariable[bool](), ReplayDroppedBlocks: reactive.NewVariable[bool](), IsEvicted: reactive.NewEvent(), + IsOrphaned: reactive.NewEvent(), commitments: commitments, } @@ -239,6 +247,7 @@ func (c *Commitment) initLogger() (shutdown func()) { c.IsVerified.LogUpdates(c, log.LevelTrace, "IsVerified"), c.ReplayDroppedBlocks.LogUpdates(c, log.LevelTrace, "ReplayDroppedBlocks"), c.IsEvicted.LogUpdates(c, log.LevelTrace, "IsEvicted"), + c.IsOrphaned.LogUpdates(c, log.LevelDebug, "IsOrphaned"), // TODO: change the log level to trace c.Logger.UnsubscribeFromParentLogger, ) @@ -265,6 +274,7 @@ func (c *Commitment) initDerivedProperties() (shutdown func()) { return lo.Batch( parent.deriveChildren(c), + c.deriveOrphaned(parent), c.deriveChain(parent), c.deriveCumulativeAttestedWeight(parent), c.deriveIsAboveLatestVerifiedCommitment(parent), @@ -316,31 +326,63 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) // deriveChain derives the Chain of this Commitment which is either inherited from the parent if we are the main child // or a newly created chain. func (c *Commitment) deriveChain(parent *Commitment) func() { - return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable3(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain) *Chain { + return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable4(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain, parentOrphaned bool) *Chain { // do not adjust the chain of the root commitment (it is set from the outside) if isRoot { return currentChain } + // If the parent commitment is orphaned, + // that means that the chain is an orphaned fork, and we should not spawn a new chain. + // Eventually, the orphaned commitments will be evicted once the finalized slot advances. + if parentOrphaned { + return nil + } + // if we are not the main child of our parent, we spawn a new chain if c != mainChild { if currentChain == nil { currentChain = c.commitments.protocol.Chains.newChain() currentChain.ForkingPoint.Set(c) + + return currentChain + } + + if parentChain == currentChain { + return nil } return currentChain + } // if we are the main child of our parent, and our chain is not the parent chain (that we are supposed to // inherit), then we evict our current chain (we will spawn a new one if we ever change back to not being the // main child) - if currentChain != nil && currentChain != parentChain { - currentChain.IsEvicted.Trigger() - } + //if currentChain != nil && currentChain != parentChain { + // currentChain.IsEvicted.Trigger() + //} return parentChain - }, c.IsRoot, parent.MainChild, parent.Chain, c.Chain.Get())) + }, c.IsRoot, parent.MainChild, parent.Chain, parent.IsOrphaned, c.Chain.Get())) +} + +func (c *Commitment) deriveOrphaned(parent *Commitment) func() { + return c.IsOrphaned.DeriveValueFrom(reactive.NewDerivedVariable3(func(isOrphaned bool, isParentOrphaned bool, parentCommitment *Commitment, isRoot bool) bool { + c.LogDebug("derive orphaned", "isOrphaned", isOrphaned, "isParentOrphaned", isParentOrphaned, "parentCommitment", parentCommitment, "isRoot", isRoot) + // if the commitment is orphaned, we exit early + if isOrphaned { + return true + } + + // If the parent was evicted and the current commitment is not root, it is marked as orphaned. + if parentCommitment == nil && !isRoot { + return true + } + + // As a last resort, inherit the orphaned flag from the parent. + return isParentOrphaned + }, parent.IsOrphaned, c.Parent, c.IsRoot)) } // deriveCumulativeAttestedWeight derives the CumulativeAttestedWeight of this Commitment which is the sum of the diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 65b7dfa08..b82203ea1 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -12,6 +12,7 @@ import ( "github.com/iotaledger/hive.go/core/eventticker" "github.com/iotaledger/hive.go/ds" "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/hive.go/log" "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/core/account" @@ -113,6 +114,8 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.Run(false, nodeOptions) + node6.Protocol.SetLogLevel(log.LevelTrace) + expectedCommittee := []iotago.AccountID{ node0.Validator.AccountID, node1.Validator.AccountID, @@ -260,6 +263,12 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertAttestationsForSlot(slot, attestationBlocks, nodesP1...) } + ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) + ts.AssertUniqueCommitmentChain(nodesP1...) + //ts.AssertCommitmentsOnChain(commitments, chain, nodes...) + + //ts.AssertCommitmentsOrphaned(commitments, bool, nodes...) + // Make sure the tips are properly set. var tipBlocks []*blocks.Block for _, node := range nodesP1[:len(nodesP1)-1] { @@ -282,6 +291,9 @@ func TestProtocol_EngineSwitching(t *testing.T) { testsuite.WithEvictedSlot(18), ) + ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) + ts.AssertUniqueCommitmentChain(nodesP2...) + for _, slot := range []iotago.SlotIndex{12, 13, 14, 15} { var attestationBlocks []*blocks.Block for _, node := range nodesP2 { @@ -368,14 +380,15 @@ func TestProtocol_EngineSwitching(t *testing.T) { wg.Wait() } + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. // Those nodes should also have all the blocks from the target fork P1 and should not have blocks from P2. // This is to make sure that the storage was copied correctly during engine switching. ts.AssertBlocksExist(ts.BlocksWithPrefix("P0"), true, ts.Nodes()...) ts.AssertBlocksExist(ts.BlocksWithPrefix("P1"), true, ts.Nodes()...) - - // old blocks can exist (we route everything by default to the main chain) but are unsolid - //ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, ts.Nodes()...) + ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, ts.Nodes()...) ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) } diff --git a/pkg/testsuite/chainmanager.go b/pkg/testsuite/chainmanager.go deleted file mode 100644 index 18d54946a..000000000 --- a/pkg/testsuite/chainmanager.go +++ /dev/null @@ -1,28 +0,0 @@ -package testsuite - -import ( - "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/iota-core/pkg/testsuite/mock" -) - -func (t *TestSuite) AssertChainManagerIsSolid(nodes ...*mock.Node) { - mustNodes(nodes) - - for _, node := range nodes { - t.Eventually(func() error { - chain := node.Protocol.Chains.Main.Get() - if chain == nil { - return ierrors.Errorf("AssertChainManagerIsSolid: %s: chain is nil", node.Name) - } - - latestChainCommitment := chain.LatestCommitment.Get() - latestCommitment := node.Protocol.Engines.Main.Get().SyncManager.LatestCommitment() - - if latestCommitment.ID() != latestChainCommitment.ID() { - return ierrors.Errorf("AssertChainManagerIsSolid: %s: latest commitment is not equal, expected %s, got %s", node.Name, latestCommitment.ID(), latestChainCommitment.ID()) - } - - return nil - }) - } -} diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go new file mode 100644 index 000000000..59eb77a6a --- /dev/null +++ b/pkg/testsuite/chains.go @@ -0,0 +1,129 @@ +package testsuite + +import ( + "github.com/iotaledger/hive.go/ds/shrinkingmap" + "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/iota-core/pkg/protocol" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" + iotago "github.com/iotaledger/iota.go/v4" +) + +func (t *TestSuite) AssertLatestEngineCommitmentOnMainChain(nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + chain := node.Protocol.Chains.Main.Get() + if chain == nil { + return ierrors.Errorf("AssertLatestEngineCommitmentOnMainChain: %s: chain is nil", node.Name) + } + + latestChainCommitment := chain.LatestCommitment.Get() + latestCommitment := node.Protocol.Engines.Main.Get().SyncManager.LatestCommitment() + + if latestCommitment.ID() != latestChainCommitment.ID() { + return ierrors.Errorf("AssertLatestEngineCommitmentOnMainChain: %s: latest commitment is not equal, expected %s, got %s", node.Name, latestCommitment.ID(), latestChainCommitment.ID()) + } + + return nil + }) + } +} + +func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []iotago.CommitmentID, chainID iotago.CommitmentID, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + var selectedChain *protocol.Chain + _ = node.Protocol.Chains.Set.ForEach(func(chain *protocol.Chain) error { + if chain.ForkingPoint.Get().ID() == chainID { + selectedChain = chain + } + + return nil + }) + + if selectedChain == nil { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: chain with forking point %s not found", node.Name, chainID) + } + + for _, expectedCommitmentID := range expectedCommitments { + // Check that passed commitments have the correct chain assigned. + { + expectedCommitment, err := node.Protocol.Commitments.Get(expectedCommitmentID, false) + if err != nil { + return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitmentID, chainID) + } + + if expectedCommitment.Chain.Get() != selectedChain { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s, got %s", node.Name, expectedCommitmentID, chainID, expectedCommitment.Chain.Get().ForkingPoint.Get().ID()) + } + } + + // Check that the chain has correct commitments assigned in its metadata. + { + commitment, exists := selectedChain.Commitment(expectedCommitmentID.Slot()) + if !exists { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment for slot %d does not exist on the selected chain %s", node.Name, expectedCommitmentID.Slot(), chainID) + } + + if expectedCommitmentID != commitment.ID() { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment on chain does not match, expected %s, got %s", node.Name, expectedCommitmentID, commitment.ID()) + } + } + } + + return nil + }) + } +} + +func (t *TestSuite) AssertUniqueCommitmentChain(nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + commitmentCountPerChain := shrinkingmap.New[*protocol.Chain, *shrinkingmap.ShrinkingMap[iotago.SlotIndex, []iotago.CommitmentID]]() + _ = node.Protocol.Commitments.ForEach(func(commitment *protocol.Commitment) error { + commitmentCountForChain, _ := commitmentCountPerChain.GetOrCreate(commitment.Chain.Get(), func() *shrinkingmap.ShrinkingMap[iotago.SlotIndex, []iotago.CommitmentID] { + return shrinkingmap.New[iotago.SlotIndex, []iotago.CommitmentID]() + }) + + commitmentCountForChain.Compute(commitment.Slot(), func(currentValue []iotago.CommitmentID, _ bool) []iotago.CommitmentID { + return append(currentValue, commitment.ID()) + }) + + return nil + }) + + incorrectCommitments := make(map[iotago.CommitmentID][]iotago.CommitmentID) + commitmentCountPerChain.ForEach(func(chain *protocol.Chain, commitmentCountForChain *shrinkingmap.ShrinkingMap[iotago.SlotIndex, []iotago.CommitmentID]) bool { + for _, commitments := range commitmentCountForChain.Values() { + if len(commitments) > 1 { + incorrectCommitments[chain.ForkingPoint.Get().ID()] = append(incorrectCommitments[chain.ForkingPoint.Get().ID()], commitments...) + } + } + + return true + }) + + if len(incorrectCommitments) > 0 { + return ierrors.Errorf("AssertUniqueCommitmentChain: %s: multiple commitments for a slot use the same chain, %s", node.Name, incorrectCommitments) + } + + return nil + }) + } +} + +//func (t *TestSuite) AssertCommitmentsOrphaned(commitments []iotago.CommitmentID, expectedOrphaned bool, nodes ...*mock.Node) { +// mustNodes(nodes) +// +// for _, node := range nodes { +// t.Eventually(func() error { +// +// return nil +// }) +// } +//} diff --git a/pkg/testsuite/node_state.go b/pkg/testsuite/node_state.go index aef18d144..c52e15242 100644 --- a/pkg/testsuite/node_state.go +++ b/pkg/testsuite/node_state.go @@ -57,7 +57,7 @@ func (t *TestSuite) AssertNodeState(nodes []*mock.Node, opts ...options.Option[N t.AssertEvictedSlot(*state.evictedSlot, nodes...) } if state.chainManagerSolid != nil && *state.chainManagerSolid { - t.AssertChainManagerIsSolid(nodes...) + t.AssertLatestEngineCommitmentOnMainChain(nodes...) } } From 6d994ba0bc4772ecbef6166ad6a8a15f8793890e Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 21 Feb 2024 09:19:45 +0100 Subject: [PATCH 08/49] Add CommitmentsOfMainEngine to testsuite --- pkg/testsuite/testsuite.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/testsuite/testsuite.go b/pkg/testsuite/testsuite.go index 4ac75400e..4a9f4aaac 100644 --- a/pkg/testsuite/testsuite.go +++ b/pkg/testsuite/testsuite.go @@ -17,6 +17,7 @@ import ( "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/hive.go/runtime/syncutils" "github.com/iotaledger/iota-core/pkg/core/account" + "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol" "github.com/iotaledger/iota-core/pkg/protocol/engine/blocks" "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" @@ -99,7 +100,7 @@ func NewTestSuite(testingT *testing.T, opts ...options.Option[TestSuite]) *TestS optsTick: durationFromEnvOrDefault(2*time.Millisecond, "CI_UNIT_TESTS_TICK"), optsLogger: loggerFromEnvOrDefault("CI_UNIT_TESTS_NO_LOG", "CI_UNIT_TESTS_LOG_LEVEL"), }, opts, func(t *TestSuite) { - //fmt.Println("Setup TestSuite -", testingT.Name(), " @ ", time.Now()) + // fmt.Println("Setup TestSuite -", testingT.Name(), " @ ", time.Now()) t.ProtocolParameterOptions = append(t.ProtocolParameterOptions, iotago.WithNetworkOptions(testingT.Name(), iotago.PrefixTestnet)) t.API = iotago.V3API(iotago.NewV3SnapshotProtocolParameters(t.ProtocolParameterOptions...)) @@ -393,6 +394,19 @@ func (t *TestSuite) AddGenesisAccount(accountDetails snapshotcreator.AccountDeta t.optsAccounts = append(t.optsAccounts, accountDetails) } +func (t *TestSuite) CommitmentsOfMainEngine(node *mock.Node, start, end iotago.SlotIndex) []*model.Commitment { + var commitments []*model.Commitment + + for i := start; i <= end; i++ { + commitment, err := node.Protocol.Engines.Main.Get().Storage.Commitments().Load(i) + require.NoErrorf(t.Testing, err, "node %s: commitment for slot %d not found", node.Name, i) + + commitments = append(commitments, commitment) + } + + return commitments +} + // AddGenesisWallet adds a wallet to the test suite with a block issuer in the genesis snapshot and access to the genesis seed. // If no block issuance credits are provided, the wallet will be assigned half of the maximum block issuance credits. func (t *TestSuite) AddGenesisWallet(name string, node *mock.Node, walletOpts ...options.Option[WalletOptions]) *mock.Wallet { From 1830638ecc8ae4f9177b17d2efca607374250259 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 21 Feb 2024 09:21:12 +0100 Subject: [PATCH 09/49] Remove superfluous orphaned check --- pkg/protocol/blocks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/protocol/blocks.go b/pkg/protocol/blocks.go index 9ab6f5cd6..639cb9d32 100644 --- a/pkg/protocol/blocks.go +++ b/pkg/protocol/blocks.go @@ -102,7 +102,7 @@ func (b *Blocks) ProcessResponse(block *model.Block, from peer.ID) { } // add the block to the dropped blocks buffer if we could not dispatch it to the chain - if commitment == nil || commitment.IsOrphaned.Get() || !commitment.Chain.Get().DispatchBlock(block, from) { + if commitment == nil || !commitment.Chain.Get().DispatchBlock(block, from) { if !b.droppedBlocksBuffer.Add(block.ProtocolBlock().Header.SlotCommitmentID, types.NewTuple(block, from)) { b.LogError("failed to add dropped block referencing unsolid commitment to dropped blocks buffer", "commitmentID", block.ProtocolBlock().Header.SlotCommitmentID, "blockID", block.ID()) } else { From ada36ce7e118040ad08eb83c276b574a2bb28769 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 21 Feb 2024 09:50:47 +0100 Subject: [PATCH 10/49] Add AssertCommitmentsOrphaned to testsuite --- pkg/testsuite/chains.go | 49 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index 59eb77a6a..bae1b0656 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -3,6 +3,7 @@ package testsuite import ( "github.com/iotaledger/hive.go/ds/shrinkingmap" "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol" "github.com/iotaledger/iota-core/pkg/testsuite/mock" iotago "github.com/iotaledger/iota.go/v4" @@ -30,7 +31,7 @@ func (t *TestSuite) AssertLatestEngineCommitmentOnMainChain(nodes ...*mock.Node) } } -func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []iotago.CommitmentID, chainID iotago.CommitmentID, nodes ...*mock.Node) { +func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commitment, chainID iotago.CommitmentID, nodes ...*mock.Node) { mustNodes(nodes) for _, node := range nodes { @@ -48,28 +49,28 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []iotago.Commit return ierrors.Errorf("AssertCommitmentsOnChain: %s: chain with forking point %s not found", node.Name, chainID) } - for _, expectedCommitmentID := range expectedCommitments { + for _, expectedCommitment := range expectedCommitments { // Check that passed commitments have the correct chain assigned. { - expectedCommitment, err := node.Protocol.Commitments.Get(expectedCommitmentID, false) + expectedCommitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) if err != nil { - return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitmentID, chainID) + return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitment, chainID) } if expectedCommitment.Chain.Get() != selectedChain { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s, got %s", node.Name, expectedCommitmentID, chainID, expectedCommitment.Chain.Get().ForkingPoint.Get().ID()) + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s, got %s", node.Name, expectedCommitment, chainID, expectedCommitment.Chain.Get().ForkingPoint.Get().ID()) } } // Check that the chain has correct commitments assigned in its metadata. { - commitment, exists := selectedChain.Commitment(expectedCommitmentID.Slot()) + commitment, exists := selectedChain.Commitment(expectedCommitment.Slot()) if !exists { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment for slot %d does not exist on the selected chain %s", node.Name, expectedCommitmentID.Slot(), chainID) + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment for slot %d does not exist on the selected chain %s", node.Name, expectedCommitment.Slot(), chainID) } - if expectedCommitmentID != commitment.ID() { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment on chain does not match, expected %s, got %s", node.Name, expectedCommitmentID, commitment.ID()) + if expectedCommitment.ID() != commitment.ID() { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment on chain does not match, expected %s, got %s", node.Name, expectedCommitment, commitment.ID()) } } } @@ -117,13 +118,23 @@ func (t *TestSuite) AssertUniqueCommitmentChain(nodes ...*mock.Node) { } } -//func (t *TestSuite) AssertCommitmentsOrphaned(commitments []iotago.CommitmentID, expectedOrphaned bool, nodes ...*mock.Node) { -// mustNodes(nodes) -// -// for _, node := range nodes { -// t.Eventually(func() error { -// -// return nil -// }) -// } -//} +func (t *TestSuite) AssertCommitmentsOrphaned(expectedCommitments []*model.Commitment, expectedOrphaned bool, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + for _, expectedCommitment := range expectedCommitments { + commitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) + if err != nil { + return ierrors.Wrapf(err, "AssertCommitmentsOrphaned: %s: expected commitment %s not found", node.Name, expectedCommitment.ID()) + } + + if expectedOrphaned != commitment.IsOrphaned.Get() { + return ierrors.Errorf("AssertCommitmentsOrphaned: %s: expected commitment %s to be orphaned %t, got %t", node.Name, expectedCommitment.ID(), expectedOrphaned, commitment.IsOrphaned.Get()) + } + } + + return nil + }) + } +} From 4ec47d4924790464c5df6bf606d623d0adbdadf1 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:11:51 +0100 Subject: [PATCH 11/49] Partial fix of the chain management. --- pkg/protocol/commitment.go | 10 +++++----- pkg/testsuite/chains.go | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 2ac236701..846818c59 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -318,7 +318,8 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) return mainChild } - return lo.Return1(c.Children.Any()) + // When removing the commitment, we need to set the main child back to nil when cleaning up children to avoid inconsistent state with MainChild being set to a random value, which then triggers other reactive events. + return nil }) } } @@ -368,21 +369,20 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { } func (c *Commitment) deriveOrphaned(parent *Commitment) func() { - return c.IsOrphaned.DeriveValueFrom(reactive.NewDerivedVariable3(func(isOrphaned bool, isParentOrphaned bool, parentCommitment *Commitment, isRoot bool) bool { - c.LogDebug("derive orphaned", "isOrphaned", isOrphaned, "isParentOrphaned", isParentOrphaned, "parentCommitment", parentCommitment, "isRoot", isRoot) + return c.IsOrphaned.DeriveValueFrom(reactive.NewDerivedVariable3(func(isOrphaned bool, isParentOrphaned bool, isParentEvicted bool, isRoot bool) bool { // if the commitment is orphaned, we exit early if isOrphaned { return true } // If the parent was evicted and the current commitment is not root, it is marked as orphaned. - if parentCommitment == nil && !isRoot { + if isParentEvicted && !isRoot { return true } // As a last resort, inherit the orphaned flag from the parent. return isParentOrphaned - }, parent.IsOrphaned, c.Parent, c.IsRoot)) + }, parent.IsOrphaned, parent.IsEvicted, c.IsRoot)) } // deriveCumulativeAttestedWeight derives the CumulativeAttestedWeight of this Commitment which is the sum of the diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index bae1b0656..2f1a6075e 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -87,6 +87,11 @@ func (t *TestSuite) AssertUniqueCommitmentChain(nodes ...*mock.Node) { t.Eventually(func() error { commitmentCountPerChain := shrinkingmap.New[*protocol.Chain, *shrinkingmap.ShrinkingMap[iotago.SlotIndex, []iotago.CommitmentID]]() _ = node.Protocol.Commitments.ForEach(func(commitment *protocol.Commitment) error { + // Orphaned commitments have chain set to nil, we want to ignore them in this check. + if commitment.Chain.Get() == nil { + return nil + } + commitmentCountForChain, _ := commitmentCountPerChain.GetOrCreate(commitment.Chain.Get(), func() *shrinkingmap.ShrinkingMap[iotago.SlotIndex, []iotago.CommitmentID] { return shrinkingmap.New[iotago.SlotIndex, []iotago.CommitmentID]() }) From f9f457a8062b2f3885399a73f23b343771aad91c Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:04:52 +0100 Subject: [PATCH 12/49] Fix engine switching test --- pkg/protocol/commitment.go | 10 ++++--- pkg/tests/protocol_engine_switching_test.go | 33 ++++++++++++++++----- pkg/testsuite/chains.go | 4 +-- pkg/testsuite/testsuite.go | 12 +++++--- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 846818c59..0bb2778d7 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -275,7 +275,9 @@ func (c *Commitment) initDerivedProperties() (shutdown func()) { parent.deriveChildren(c), c.deriveOrphaned(parent), + c.deriveChain(parent), + c.deriveCumulativeAttestedWeight(parent), c.deriveIsAboveLatestVerifiedCommitment(parent), @@ -349,7 +351,7 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { return currentChain } - if parentChain == currentChain { + if parentChain == currentChain || mainChild == nil { return nil } @@ -369,20 +371,20 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { } func (c *Commitment) deriveOrphaned(parent *Commitment) func() { - return c.IsOrphaned.DeriveValueFrom(reactive.NewDerivedVariable3(func(isOrphaned bool, isParentOrphaned bool, isParentEvicted bool, isRoot bool) bool { + return c.IsOrphaned.DeriveValueFrom(reactive.NewDerivedVariable4(func(isOrphaned bool, isParentOrphaned bool, isParentEvicted bool, isRoot bool, rootCommitment *Commitment) bool { // if the commitment is orphaned, we exit early if isOrphaned { return true } // If the parent was evicted and the current commitment is not root, it is marked as orphaned. - if isParentEvicted && !isRoot { + if isParentEvicted && !isRoot && rootCommitment.Slot() <= c.Slot() { return true } // As a last resort, inherit the orphaned flag from the parent. return isParentOrphaned - }, parent.IsOrphaned, parent.IsEvicted, c.IsRoot)) + }, parent.IsOrphaned, parent.IsEvicted, c.IsRoot, c.commitments.Root)) } // deriveCumulativeAttestedWeight derives the CumulativeAttestedWeight of this Commitment which is the sum of the diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index b82203ea1..df37d309d 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -12,10 +12,10 @@ import ( "github.com/iotaledger/hive.go/core/eventticker" "github.com/iotaledger/hive.go/ds" "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/log" "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/core/account" + "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol" "github.com/iotaledger/iota-core/pkg/protocol/engine" "github.com/iotaledger/iota-core/pkg/protocol/engine/blocks" @@ -114,8 +114,6 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.Run(false, nodeOptions) - node6.Protocol.SetLogLevel(log.LevelTrace) - expectedCommittee := []iotago.AccountID{ node0.Validator.AccountID, node1.Validator.AccountID, @@ -265,9 +263,8 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) - //ts.AssertCommitmentsOnChain(commitments, chain, nodes...) - - //ts.AssertCommitmentsOrphaned(commitments, bool, nodes...) + ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(node0, 13, 18), ts.CommitmentOfMainEngine(node0, 13).ID(), nodesP1...) + ts.AssertCommitmentsOrphaned(ts.CommitmentsOfMainEngine(node0, 13, 18), false, nodesP1...) // Make sure the tips are properly set. var tipBlocks []*blocks.Block @@ -277,6 +274,8 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertStrongTips(tipBlocks, nodesP1...) } + var engineCommitmentsP2 []*model.Commitment + // Issue blocks in partition 2. { ts.IssueBlocksAtSlots("P2:", []iotago.SlotIndex{14, 15, 16, 17, 18, 19, 20}, 4, "P0:13.3", nodesP2[:len(nodesP2)-1], true, false) @@ -291,8 +290,11 @@ func TestProtocol_EngineSwitching(t *testing.T) { testsuite.WithEvictedSlot(18), ) + engineCommitmentsP2 = ts.CommitmentsOfMainEngine(node6, 6, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) + ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 6).ID(), nodesP2...) + ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) for _, slot := range []iotago.SlotIndex{12, 13, 14, 15} { var attestationBlocks []*blocks.Block @@ -380,8 +382,10 @@ func TestProtocol_EngineSwitching(t *testing.T) { wg.Wait() } - ts.AssertUniqueCommitmentChain(ts.Nodes()...) - ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + lastFinalizedSlot := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 + ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() >= lastFinalizedSlot + }) // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. // Those nodes should also have all the blocks from the target fork P1 and should not have blocks from P2. @@ -391,6 +395,19 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, ts.Nodes()...) ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) + + commitmentsMainChain := ts.CommitmentsOfMainEngine(node0, node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot()-4, expectedCommittedSlotAfterPartitionMerge) + + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(node0, lastFinalizedSlot).ID(), ts.Nodes()...) + // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + + // TODO: assert chain count + // TODO: assert that Protocol only contains commitments from above the eviction point. } func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index 2f1a6075e..830a04cee 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -45,7 +45,7 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit return nil }) - if selectedChain == nil { + if chainID != iotago.EmptyCommitmentID && selectedChain == nil { return ierrors.Errorf("AssertCommitmentsOnChain: %s: chain with forking point %s not found", node.Name, chainID) } @@ -63,7 +63,7 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit } // Check that the chain has correct commitments assigned in its metadata. - { + if selectedChain != nil { commitment, exists := selectedChain.Commitment(expectedCommitment.Slot()) if !exists { return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment for slot %d does not exist on the selected chain %s", node.Name, expectedCommitment.Slot(), chainID) diff --git a/pkg/testsuite/testsuite.go b/pkg/testsuite/testsuite.go index 4a9f4aaac..df0c31cfc 100644 --- a/pkg/testsuite/testsuite.go +++ b/pkg/testsuite/testsuite.go @@ -398,15 +398,19 @@ func (t *TestSuite) CommitmentsOfMainEngine(node *mock.Node, start, end iotago.S var commitments []*model.Commitment for i := start; i <= end; i++ { - commitment, err := node.Protocol.Engines.Main.Get().Storage.Commitments().Load(i) - require.NoErrorf(t.Testing, err, "node %s: commitment for slot %d not found", node.Name, i) - - commitments = append(commitments, commitment) + commitments = append(commitments, t.CommitmentOfMainEngine(node, i)) } return commitments } +func (t *TestSuite) CommitmentOfMainEngine(node *mock.Node, slot iotago.SlotIndex) *model.Commitment { + commitment, err := node.Protocol.Engines.Main.Get().Storage.Commitments().Load(slot) + require.NoErrorf(t.Testing, err, "node %s: commitment for slot %d not found", node.Name, slot) + + return commitment +} + // AddGenesisWallet adds a wallet to the test suite with a block issuer in the genesis snapshot and access to the genesis seed. // If no block issuance credits are provided, the wallet will be assigned half of the maximum block issuance credits. func (t *TestSuite) AddGenesisWallet(name string, node *mock.Node, walletOpts ...options.Option[WalletOptions]) *mock.Wallet { From e3bf1dc4bb9f250f5797e593803c47fac99f653c Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:59:31 +0100 Subject: [PATCH 13/49] Add AssertCommitmentsEvicted to testsuite --- pkg/testsuite/chains.go | 58 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index 2f1a6075e..1233f6dca 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -52,13 +52,13 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit for _, expectedCommitment := range expectedCommitments { // Check that passed commitments have the correct chain assigned. { - expectedCommitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) + protocolCommitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) if err != nil { - return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitment, chainID) + return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, protocolCommitment, chainID) } - if expectedCommitment.Chain.Get() != selectedChain { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s, got %s", node.Name, expectedCommitment, chainID, expectedCommitment.Chain.Get().ForkingPoint.Get().ID()) + if protocolCommitment.Chain.Get() != selectedChain { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s, got %s", node.Name, protocolCommitment, chainID, protocolCommitment.Chain.Get().ForkingPoint.Get().ID()) } } @@ -123,6 +123,56 @@ func (t *TestSuite) AssertUniqueCommitmentChain(nodes ...*mock.Node) { } } +func (t *TestSuite) AssertCommitmentsEvicted(expectedEvictedSlot iotago.SlotIndex, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + + seenChains := make(map[*protocol.Chain]struct{}) + if err := node.Protocol.Commitments.ForEach(func(commitment *protocol.Commitment) error { + if commitment.Chain.Get() != nil { // the chain of orphaned commitments is nil. + seenChains[commitment.Chain.Get()] = struct{}{} + } + + if expectedEvictedSlot >= commitment.Slot() { + return ierrors.Errorf("AssertCommitmentsEvicted: %s: commitment %s not evicted", node.Name, commitment.ID()) + } + + return nil + }); err != nil { + return err + } + + if err := node.Protocol.Chains.ForEach(func(chain *protocol.Chain) error { + for i := iotago.SlotIndex(0); i <= expectedEvictedSlot; i++ { + commitment, exists := chain.Commitment(expectedEvictedSlot) + if exists { + return ierrors.Errorf("AssertCommitmentsEvicted: %s: commitment %s on chain %s not evicted", node.Name, commitment.ID(), chain.ForkingPoint.Get().ID()) + } + } + + return nil + }); err != nil { + return err + } + + // Make sure that we don't have dangling chains. + if err := node.Protocol.Chains.Set.ForEach(func(chain *protocol.Chain) error { + if _, exists := seenChains[chain]; !exists { + return ierrors.Errorf("AssertCommitmentsEvicted: %s: chain %s not evicted", node.Name, chain.ForkingPoint.Get().ID()) + } + + return nil + }); err != nil { + return err + } + + return nil + }) + } +} + func (t *TestSuite) AssertCommitmentsOrphaned(expectedCommitments []*model.Commitment, expectedOrphaned bool, nodes ...*mock.Node) { mustNodes(nodes) From 08bed6a1287421710bd7b9ca194dd273801181c1 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:04:06 +0100 Subject: [PATCH 14/49] WIP: add checks to other engine switching tests --- pkg/tests/protocol_engine_switching_test.go | 65 +++++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index df37d309d..3755bee45 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -263,8 +263,8 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) - ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(node0, 13, 18), ts.CommitmentOfMainEngine(node0, 13).ID(), nodesP1...) - ts.AssertCommitmentsOrphaned(ts.CommitmentsOfMainEngine(node0, 13, 18), false, nodesP1...) + ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), ts.CommitmentOfMainEngine(nodesP1[0], 13).ID(), nodesP1...) + ts.AssertCommitmentsOrphaned(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), false, nodesP1...) // Make sure the tips are properly set. var tipBlocks []*blocks.Block @@ -290,10 +290,10 @@ func TestProtocol_EngineSwitching(t *testing.T) { testsuite.WithEvictedSlot(18), ) - engineCommitmentsP2 = ts.CommitmentsOfMainEngine(node6, 6, 18) + engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 6, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) - ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 6).ID(), nodesP2...) + ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(nodesP1[0], 6).ID(), nodesP2...) ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) for _, slot := range []iotago.SlotIndex{12, 13, 14, 15} { @@ -382,11 +382,6 @@ func TestProtocol_EngineSwitching(t *testing.T) { wg.Wait() } - lastFinalizedSlot := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 - ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { - return commitment.Slot() >= lastFinalizedSlot - }) - // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. // Those nodes should also have all the blocks from the target fork P1 and should not have blocks from P2. // This is to make sure that the storage was copied correctly during engine switching. @@ -396,13 +391,18 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) - commitmentsMainChain := ts.CommitmentsOfMainEngine(node0, node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot()-4, expectedCommittedSlotAfterPartitionMerge) + lastFinalizedSlot := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 + ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() >= lastFinalizedSlot + }) + + commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], lastFinalizedSlot-4, expectedCommittedSlotAfterPartitionMerge) ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(node0, lastFinalizedSlot).ID(), ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], lastFinalizedSlot).ID(), ts.Nodes()...) // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) @@ -571,6 +571,8 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertBlocksExist(ts.BlocksWithPrefix("P1"), false, nodesP2...) } + var engineCommitmentsP2 []*model.Commitment + // Issue blocks in partition 2. { ts.IssueBlocksAtSlots("P2:", []iotago.SlotIndex{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 4, "P0:7.3", nodesP2, true, false) @@ -610,6 +612,26 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), true, nodesP2...) ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, nodesP1...) + + lastFinalizedSlot := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 + commitmentsMainChain := ts.CommitmentsOfMainEngine(node0, lastFinalizedSlot-4, expectedCommittedSlotAfterPartitionMerge) + ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() >= lastFinalizedSlot + }) + + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(node0, lastFinalizedSlot).ID(), ts.Nodes()...) + // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + + engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 6, 18) + ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) + ts.AssertUniqueCommitmentChain(nodesP2...) + ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 6).ID(), nodesP2...) + ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) } // Merge the partitions @@ -993,6 +1015,27 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { wg.Wait() ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) + + lastFinalizedSlot := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 + commitmentsMainChain := ts.CommitmentsOfMainEngine(ts.Node("node0"), lastFinalizedSlot-4, expectedCommittedSlotAfterPartitionMerge) + ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() >= lastFinalizedSlot + }) + ultimateCommitmentsP3 := lo.Filter(engineCommitmentsP3, func(commitment *model.Commitment) bool { + return commitment.Slot() >= lastFinalizedSlot + }) + + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, true, ts.Nodes()...) + + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], lastFinalizedSlot).ID(), ts.Nodes()...) + // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, iotago.EmptyCommitmentID, ts.Nodes()...) } type Blocks []*blocks.Block From 6cbe73b2d0261882e225ecc3634ea183f79448d9 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:44:41 +0100 Subject: [PATCH 15/49] Improve engine switching tests --- pkg/tests/protocol_engine_switching_test.go | 87 +++++++++++++-------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 3755bee45..1d32ca4a0 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -12,6 +12,7 @@ import ( "github.com/iotaledger/hive.go/core/eventticker" "github.com/iotaledger/hive.go/ds" "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/hive.go/log" "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/core/account" @@ -32,10 +33,16 @@ import ( ) func TestProtocol_EngineSwitching(t *testing.T) { + var ( + genesisSlot iotago.SlotIndex = 0 + minCommittableAge iotago.SlotIndex = 2 + maxCommittableAge iotago.SlotIndex = 4 + ) + ts := testsuite.NewTestSuite(t, testsuite.WithProtocolParametersOptions( iotago.WithTimeProviderOptions( - 0, + genesisSlot, testsuite.GenesisTimeWithOffsetBySlots(1000, testsuite.DefaultSlotDurationInSeconds), testsuite.DefaultSlotDurationInSeconds, 3, @@ -43,8 +50,8 @@ func TestProtocol_EngineSwitching(t *testing.T) { iotago.WithLivenessOptions( 10, 10, - 2, - 4, + minCommittableAge, + maxCommittableAge, 5, ), ), @@ -391,18 +398,18 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) - lastFinalizedSlot := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 + oldestNonEvictedCommitment := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { - return commitment.Slot() >= lastFinalizedSlot + return commitment.Slot() >= oldestNonEvictedCommitment }) - commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], lastFinalizedSlot-4, expectedCommittedSlotAfterPartitionMerge) + commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], lastFinalizedSlot).ID(), ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) @@ -411,12 +418,18 @@ func TestProtocol_EngineSwitching(t *testing.T) { } func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { + var ( + genesisSlot iotago.SlotIndex = 0 + minCommittableAge iotago.SlotIndex = 2 + maxCommittableAge iotago.SlotIndex = 5 + ) + ts := testsuite.NewTestSuite(t, testsuite.WithWaitFor(15*time.Second), testsuite.WithProtocolParametersOptions( iotago.WithTimeProviderOptions( - 0, + genesisSlot, testsuite.GenesisTimeWithOffsetBySlots(1000, testsuite.DefaultSlotDurationInSeconds), testsuite.DefaultSlotDurationInSeconds, 4, // 16 slots per epoch @@ -424,8 +437,8 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { iotago.WithLivenessOptions( 10, 10, - 2, - 5, + minCommittableAge, + maxCommittableAge, 10, ), ), @@ -471,6 +484,10 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { "node3": nodeOpts, }) + ts.Node("node0").Protocol.SetLogLevel(log.LevelTrace) + ts.Node("node0").Protocol.Engines.Main.Get().SetLogLevel(log.LevelDebug) + ts.Node("node0").Protocol.Blocks.SetLogLevel(log.LevelDebug) + // Verify that nodes have the expected states after startup. { genesisCommitment := iotago.NewEmptyCommitment(ts.API) @@ -613,24 +630,10 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), true, nodesP2...) ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, nodesP1...) - lastFinalizedSlot := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 - commitmentsMainChain := ts.CommitmentsOfMainEngine(node0, lastFinalizedSlot-4, expectedCommittedSlotAfterPartitionMerge) - ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { - return commitment.Slot() >= lastFinalizedSlot - }) - - ts.AssertUniqueCommitmentChain(ts.Nodes()...) - ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(node0, lastFinalizedSlot).ID(), ts.Nodes()...) - // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) - - engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 6, 18) + engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 0, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) - ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 6).ID(), nodesP2...) + ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 0).ID(), nodesP2...) ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) } @@ -704,6 +707,22 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertAttestationsForSlot(17, ts.Blocks("P1:15.3-node0", "P1:17.3-node1", "P1:17.3-node2"), nodesP1...) // Committee in epoch 2 is only node1, node2. Block(P1:15.3-node0) commits to Slot12. ts.AssertAttestationsForSlot(18, ts.Blocks("P1:18.3-node1", "P1:18.3-node2"), nodesP1...) // Committee in epoch 2 is only node1, node2. Block(P1:15.3-node0) commits to Slot12, that's why it is not carried to 18. ts.AssertAttestationsForSlot(19, ts.Blocks("P1:19.3-node1", "P1:19.3-node2"), ts.Nodes()...) // Committee in epoch 2 is only node1, node2 + + oldestNonEvictedCommitment := nodesP1[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + commitmentsMainChain := ts.CommitmentsOfMainEngine(node0, oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) + ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() >= oldestNonEvictedCommitment + }) + + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) + // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + // TODO: assert chain count + // TODO: assert that Protocol only contains commitments from above the eviction point. } func TestProtocol_EngineSwitching_Tie(t *testing.T) { @@ -978,6 +997,11 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { otherPartitions = []*mock.Node{nodes[0], nodes[1]} } + oldestNonEvictedCommitmentBeforeMerge := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + + engineCommitmentsP2 := ts.CommitmentsOfMainEngine(otherPartitions[0], oldestNonEvictedCommitmentBeforeMerge, 18) + engineCommitmentsP3 := ts.CommitmentsOfMainEngine(otherPartitions[0], oldestNonEvictedCommitmentBeforeMerge, 18) + // Merge the partitions { fmt.Println("") @@ -1016,13 +1040,13 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) - lastFinalizedSlot := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - 4 - commitmentsMainChain := ts.CommitmentsOfMainEngine(ts.Node("node0"), lastFinalizedSlot-4, expectedCommittedSlotAfterPartitionMerge) + oldestNonEvictedCommitment := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + commitmentsMainChain := ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { - return commitment.Slot() >= lastFinalizedSlot + return commitment.Slot() >= oldestNonEvictedCommitment }) ultimateCommitmentsP3 := lo.Filter(engineCommitmentsP3, func(commitment *model.Commitment) bool { - return commitment.Slot() >= lastFinalizedSlot + return commitment.Slot() >= oldestNonEvictedCommitment }) ts.AssertUniqueCommitmentChain(ts.Nodes()...) @@ -1031,11 +1055,12 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, true, ts.Nodes()...) ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], lastFinalizedSlot).ID(), ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, iotago.EmptyCommitmentID, ts.Nodes()...) + } type Blocks []*blocks.Block From 1e310923f87ed61eb2f82e2af3ab7966613af4bb Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:40:42 +0100 Subject: [PATCH 16/49] Fix error where commitment with EmptyCommitmentID is attempted to be solidified (as a parent of the genesis commitment) --- pkg/protocol/attestations.go | 2 +- pkg/protocol/commitments.go | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/pkg/protocol/attestations.go b/pkg/protocol/attestations.go index 49ad57d5d..4b9eb0e26 100644 --- a/pkg/protocol/attestations.go +++ b/pkg/protocol/attestations.go @@ -158,7 +158,7 @@ func (a *Attestations) sendRequest(commitmentID iotago.CommitmentID) { // processResponse processes the given attestation response. func (a *Attestations) processResponse(commitment *model.Commitment, attestations []*iotago.Attestation, merkleProof *merklehasher.Proof[iotago.Identifier], from peer.ID) { a.workerPool.Submit(func() { - publishedCommitment, _, err := a.protocol.Commitments.publishCommitment(commitment) + publishedCommitment, _, err := a.protocol.Commitments.publishCommitment(commitment, false) if err != nil { a.LogDebug("failed to publish commitment when processing attestations", "commitmentID", commitment.ID(), "peer", from, "error", err) diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 3286474a0..24544783e 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -164,7 +164,7 @@ func (c *Commitments) initRequester() (shutdown func()) { // publishRootCommitment publishes the root commitment of the main engine. func (c *Commitments) publishRootCommitment(mainChain *Chain, mainEngine *engine.Engine) func() { return mainEngine.RootCommitment.OnUpdate(func(_ *model.Commitment, rootCommitment *model.Commitment) { - publishedCommitment, published, err := c.publishCommitment(rootCommitment) + publishedCommitment, published, err := c.publishCommitment(rootCommitment, false) if err != nil { c.LogError("failed to publish new root commitment", "id", rootCommitment.ID(), "error", err) @@ -206,7 +206,7 @@ func (c *Commitments) publishEngineCommitments(chain *Chain, engine *engine.Engi } // publish the commitment - publishedCommitment, _, err := c.publishCommitment(commitment) + publishedCommitment, _, err := c.publishCommitment(commitment, true) if err != nil { c.LogError("failed to publish commitment from engine", "engine", engine.LogName(), "commitment", commitment, "err", err) @@ -225,9 +225,9 @@ func (c *Commitments) publishEngineCommitments(chain *Chain, engine *engine.Engi // publishCommitment publishes the given commitment and returns the singleton Commitment instance that is used to // represent it in our data structure (together with a boolean that indicates if we were the first goroutine to publish // the commitment). -func (c *Commitments) publishCommitment(commitment *model.Commitment) (publishedCommitment *Commitment, published bool, err error) { +func (c *Commitments) publishCommitment(commitment *model.Commitment, solidify bool) (publishedCommitment *Commitment, published bool, err error) { // retrieve promise and abort if it was already rejected - cachedRequest := c.cachedRequest(commitment.ID()) + cachedRequest := c.cachedRequest(commitment.ID(), solidify) if cachedRequest.WasRejected() { return nil, false, ierrors.Wrapf(cachedRequest.Err(), "failed to request commitment %s", commitment.ID()) } @@ -246,7 +246,7 @@ func (c *Commitments) publishCommitment(commitment *model.Commitment) (published // cachedRequest returns a singleton Promise for the given commitmentID. If the Promise does not exist yet, it will be // created and optionally requested from the network if missing. Once the promise is resolved, the Commitment is // initialized and provided to the consumers. -func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, requestIfMissing ...bool) *promise.Promise[*Commitment] { +func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, solidify bool, requestIfMissing ...bool) *promise.Promise[*Commitment] { // handle evicted slots slotEvicted := c.protocol.EvictionEvent(commitmentID.Index()) if slotEvicted.WasTriggered() && c.protocol.LastEvictedSlot().Get() != 0 { @@ -270,7 +270,7 @@ func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, requestIfM // handle successful resolutions cachedRequest.OnSuccess(func(commitment *Commitment) { - c.initCommitment(commitment, slotEvicted) + c.initCommitment(commitment, solidify, slotEvicted) }) // handle failed resolutions @@ -289,17 +289,19 @@ func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, requestIfM } // initCommitment initializes the given commitment in the protocol. -func (c *Commitments) initCommitment(commitment *Commitment, slotEvicted reactive.Event) { +func (c *Commitments) initCommitment(commitment *Commitment, solidify bool, slotEvicted reactive.Event) { commitment.LogDebug("created", "id", commitment.ID()) // solidify the parent of the commitment - c.cachedRequest(commitment.PreviousCommitmentID(), true).OnSuccess(func(parent *Commitment) { - commitment.Parent.Set(parent) + if solidify { + c.cachedRequest(commitment.PreviousCommitmentID(), true).OnSuccess(func(parent *Commitment) { + commitment.Parent.Set(parent) - parent.IsEvicted.OnTrigger(func() { - commitment.Parent.Set(nil) + parent.IsEvicted.OnTrigger(func() { + commitment.Parent.Set(nil) + }) }) - }) + } // add commitment to the set c.Add(commitment) @@ -368,7 +370,7 @@ func (c *Commitments) processResponse(commitment *model.Commitment, from peer.ID return } - if publishedCommitment, published, err := c.protocol.Commitments.publishCommitment(commitment); err != nil { + if publishedCommitment, published, err := c.protocol.Commitments.publishCommitment(commitment, false); err != nil { c.LogError("failed to process commitment", "fromPeer", from, "err", err) } else if published { c.LogTrace("received response", "commitment", publishedCommitment.LogName(), "fromPeer", from) From cd2afeefbe3b0e72fafd2461725627fb6a393e6a Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:41:08 +0100 Subject: [PATCH 17/49] Add AssertCommitmentsEvicted to EngineSwitchingTest --- pkg/tests/protocol_engine_switching_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 1d32ca4a0..83e99fa16 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -121,6 +121,10 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.Run(false, nodeOptions) + node0.Protocol.SetLogLevel(log.LevelDebug) + node0.Protocol.Chains.SetLogLevel(log.LevelTrace) + node0.Protocol.Commitments.SetLogLevel(log.LevelTrace) + expectedCommittee := []iotago.AccountID{ node0.Validator.AccountID, node1.Validator.AccountID, @@ -272,6 +276,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertUniqueCommitmentChain(nodesP1...) ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), ts.CommitmentOfMainEngine(nodesP1[0], 13).ID(), nodesP1...) ts.AssertCommitmentsOrphaned(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), false, nodesP1...) + ts.AssertCommitmentsEvicted(12, nodesP1...) // Make sure the tips are properly set. var tipBlocks []*blocks.Block @@ -302,6 +307,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertUniqueCommitmentChain(nodesP2...) ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(nodesP1[0], 6).ID(), nodesP2...) ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) + ts.AssertCommitmentsEvicted(5, nodesP2...) for _, slot := range []iotago.SlotIndex{12, 13, 14, 15} { var attestationBlocks []*blocks.Block @@ -412,7 +418,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) - + ts.AssertCommitmentsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) // TODO: assert chain count // TODO: assert that Protocol only contains commitments from above the eviction point. } From 2fea35cdc3004b5b1691099ddee230b178abafa5 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 22 Feb 2024 05:30:50 +0100 Subject: [PATCH 18/49] Fix solidification of commitments --- pkg/protocol/commitments.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 24544783e..063a55b63 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -73,7 +73,7 @@ func newCommitments(protocol *Protocol) *Commitments { func (c *Commitments) Get(commitmentID iotago.CommitmentID, requestIfMissing ...bool) (commitment *Commitment, err error) { cachedRequest, exists := c.cachedRequests.Get(commitmentID) if !exists && lo.First(requestIfMissing) { - if cachedRequest = c.cachedRequest(commitmentID, true); cachedRequest.WasRejected() { + if cachedRequest = c.cachedRequest(commitmentID, true, true); cachedRequest.WasRejected() { return nil, ierrors.Wrapf(cachedRequest.Err(), "failed to request commitment %s", commitmentID) } } @@ -294,7 +294,7 @@ func (c *Commitments) initCommitment(commitment *Commitment, solidify bool, slot // solidify the parent of the commitment if solidify { - c.cachedRequest(commitment.PreviousCommitmentID(), true).OnSuccess(func(parent *Commitment) { + c.cachedRequest(commitment.PreviousCommitmentID(), true, true).OnSuccess(func(parent *Commitment) { commitment.Parent.Set(parent) parent.IsEvicted.OnTrigger(func() { From e84b4434a8a5442230c4cfdab971fdba28ea0582 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 22 Feb 2024 06:08:44 +0100 Subject: [PATCH 19/49] Evict chain when forking point becomes orphaned --- pkg/protocol/chain.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 84cddc7f3..6776cce2a 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -269,10 +269,24 @@ func (c *Chain) deriveIsEvicted(forkingPoint *Commitment) (shutdown func()) { return } - return forkingPoint.IsEvicted.OnTrigger(func() { - // TODO: MOVE TO DEDICATED WORKER - go c.IsEvicted.Trigger() - }) + // TODO: this might be cleaner but deadlocks + // return c.IsEvicted.DeriveValueFrom(reactive.NewDerivedVariable2(func(currentValue bool, forkingPointIsOrphaned bool, forkingPointIsEvicted bool) bool { + // if currentValue { + // return true + // } + // + // return forkingPointIsOrphaned || forkingPointIsEvicted + // }, forkingPoint.IsOrphaned, forkingPoint.IsEvicted)) + + return lo.Batch( + forkingPoint.IsEvicted.OnTrigger(func() { + // TODO: MOVE TO DEDICATED WORKER + go c.IsEvicted.Trigger() + }), + forkingPoint.IsOrphaned.OnTrigger(func() { + go c.IsEvicted.Trigger() + }), + ) } // deriveOutOfSyncThreshold defines how a chain determines its "out of sync" threshold (the latest seen slot minus 2 From 0b6579c68ffe9a22b45397783d1cd93c6f08eb1c Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 22 Feb 2024 06:32:18 +0100 Subject: [PATCH 20/49] Derive commitment's chain from its own orphaned flag (instead of its parent's) since we compute it before deriving the chain. This fixes the edge case where the chain is created its forking point is already orphaned --- pkg/protocol/commitment.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 0bb2778d7..2d0ad97f5 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -329,16 +329,16 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) // deriveChain derives the Chain of this Commitment which is either inherited from the parent if we are the main child // or a newly created chain. func (c *Commitment) deriveChain(parent *Commitment) func() { - return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable4(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain, parentOrphaned bool) *Chain { + return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable4(func(currentChain *Chain, isRoot bool, isOrphaned bool, mainChild *Commitment, parentChain *Chain) *Chain { // do not adjust the chain of the root commitment (it is set from the outside) if isRoot { return currentChain } - // If the parent commitment is orphaned, + // If the commitment is orphaned, // that means that the chain is an orphaned fork, and we should not spawn a new chain. // Eventually, the orphaned commitments will be evicted once the finalized slot advances. - if parentOrphaned { + if isOrphaned { return nil } @@ -362,12 +362,12 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { // if we are the main child of our parent, and our chain is not the parent chain (that we are supposed to // inherit), then we evict our current chain (we will spawn a new one if we ever change back to not being the // main child) - //if currentChain != nil && currentChain != parentChain { + // if currentChain != nil && currentChain != parentChain { // currentChain.IsEvicted.Trigger() - //} + // } return parentChain - }, c.IsRoot, parent.MainChild, parent.Chain, parent.IsOrphaned, c.Chain.Get())) + }, c.IsRoot, c.IsOrphaned, parent.MainChild, parent.Chain, c.Chain.Get())) } func (c *Commitment) deriveOrphaned(parent *Commitment) func() { From 2f465a35d2992f7b0317d3d52bc214f63dbdf84e Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 22 Feb 2024 07:58:28 +0100 Subject: [PATCH 21/49] Add assertions for Protocol.Chains and Protocol.Commitments to engine switching tests --- pkg/tests/protocol_engine_switching_test.go | 119 ++++++++++++-------- pkg/testsuite/chains.go | 16 ++- 2 files changed, 84 insertions(+), 51 deletions(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 83e99fa16..97fb0522b 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -121,10 +121,6 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.Run(false, nodeOptions) - node0.Protocol.SetLogLevel(log.LevelDebug) - node0.Protocol.Chains.SetLogLevel(log.LevelTrace) - node0.Protocol.Commitments.SetLogLevel(log.LevelTrace) - expectedCommittee := []iotago.AccountID{ node0.Validator.AccountID, node1.Validator.AccountID, @@ -272,11 +268,12 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertAttestationsForSlot(slot, attestationBlocks, nodesP1...) } + // Assert Protocol.Chains and Protocol.Commitments state. ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), ts.CommitmentOfMainEngine(nodesP1[0], 13).ID(), nodesP1...) ts.AssertCommitmentsOrphaned(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), false, nodesP1...) - ts.AssertCommitmentsEvicted(12, nodesP1...) + ts.AssertCommitmentsAndChainsEvicted(12, nodesP1...) // Make sure the tips are properly set. var tipBlocks []*blocks.Block @@ -302,12 +299,13 @@ func TestProtocol_EngineSwitching(t *testing.T) { testsuite.WithEvictedSlot(18), ) + // Assert Protocol.Chains and Protocol.Commitments state. engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 6, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(nodesP1[0], 6).ID(), nodesP2...) ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) - ts.AssertCommitmentsEvicted(5, nodesP2...) + ts.AssertCommitmentsAndChainsEvicted(5, nodesP2...) for _, slot := range []iotago.SlotIndex{12, 13, 14, 15} { var attestationBlocks []*blocks.Block @@ -404,23 +402,24 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) - oldestNonEvictedCommitment := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge - ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { - return commitment.Slot() >= oldestNonEvictedCommitment - }) + // Assert Protocol.Chains and Protocol.Commitments state. + { + oldestNonEvictedCommitment := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() >= oldestNonEvictedCommitment + }) - commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) + commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) - ts.AssertUniqueCommitmentChain(ts.Nodes()...) - ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) - ts.AssertCommitmentsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) - // TODO: assert chain count - // TODO: assert that Protocol only contains commitments from above the eviction point. + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) + // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + ts.AssertCommitmentsAndChainsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) + } } func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { @@ -592,6 +591,14 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertBlocksExist(ts.BlocksWithPrefix("P1"), true, nodesP1...) ts.AssertBlocksExist(ts.BlocksWithPrefix("P1"), false, nodesP2...) + + // Assert Protocol.Chains and Protocol.Commitments state. + engineCommitmentsP1 := ts.CommitmentsOfMainEngine(nodesP1[0], 12, 18) + ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) + ts.AssertUniqueCommitmentChain(nodesP1...) + ts.AssertCommitmentsOnChain(engineCommitmentsP1, ts.CommitmentOfMainEngine(node0, 12).ID(), nodesP1...) + ts.AssertCommitmentsOrphaned(engineCommitmentsP1, false, nodesP1...) + ts.AssertCommitmentsAndChainsEvicted(11, nodesP1...) } var engineCommitmentsP2 []*model.Commitment @@ -636,11 +643,13 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), true, nodesP2...) ts.AssertBlocksExist(ts.BlocksWithPrefix("P2"), false, nodesP1...) + // Assert Protocol.Chains and Protocol.Commitments state. engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 0, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 0).ID(), nodesP2...) ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) + // We only finalized until slot 4, and maxCommittableAge=5. Thus, we don't expect any evictions on chains/commmitments yet. } // Merge the partitions @@ -720,15 +729,18 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { return commitment.Slot() >= oldestNonEvictedCommitment }) - ts.AssertUniqueCommitmentChain(ts.Nodes()...) - ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) - // TODO: assert chain count - // TODO: assert that Protocol only contains commitments from above the eviction point. + // Assert Protocol.Chains and Protocol.Commitments state. + { + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) + // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + + ts.AssertCommitmentsAndChainsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) + } } func TestProtocol_EngineSwitching_Tie(t *testing.T) { @@ -827,6 +839,8 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.Run(false, nodesOptions) + nodes[0].Protocol.SetLogLevel(log.LevelTrace) + expectedCommittee := []iotago.AccountID{nodes[0].Validator.AccountID, nodes[1].Validator.AccountID, nodes[2].Validator.AccountID} seatIndexes := []account.SeatIndex{ @@ -951,6 +965,9 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { } ts.AssertStrongTips(tipBlocks, targetNodes...) + + // Assert Protocol.Chains and Protocol.Commitments state. + // TODO: assert here } issueBlocks(0, []iotago.SlotIndex{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}) @@ -985,9 +1002,9 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { issueBlocks(2, []iotago.SlotIndex{14, 15, 16, 17, 18, 19, 20}) issueBlocks(3, []iotago.SlotIndex{14, 15, 16, 17, 18, 19, 20}) - commitment140, _ := nodes[0].Protocol.Chains.Main.Get().Commitment(14) - commitment141, _ := nodes[1].Protocol.Chains.Main.Get().Commitment(14) - commitment142, _ := nodes[2].Protocol.Chains.Main.Get().Commitment(14) + commitment140 := ts.CommitmentOfMainEngine(nodes[0], 14) + commitment141 := ts.CommitmentOfMainEngine(nodes[1], 14) + commitment142 := ts.CommitmentOfMainEngine(nodes[2], 14) var mainPartition []*mock.Node var otherPartitions []*mock.Node @@ -1003,10 +1020,8 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { otherPartitions = []*mock.Node{nodes[0], nodes[1]} } - oldestNonEvictedCommitmentBeforeMerge := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge - - engineCommitmentsP2 := ts.CommitmentsOfMainEngine(otherPartitions[0], oldestNonEvictedCommitmentBeforeMerge, 18) - engineCommitmentsP3 := ts.CommitmentsOfMainEngine(otherPartitions[0], oldestNonEvictedCommitmentBeforeMerge, 18) + engineCommitmentsP2 := ts.CommitmentsOfMainEngine(otherPartitions[0], lastCommonSlot+1, 18) + engineCommitmentsP3 := ts.CommitmentsOfMainEngine(otherPartitions[1], lastCommonSlot+1, 18) // Merge the partitions { @@ -1047,6 +1062,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) oldestNonEvictedCommitment := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + fmt.Println("Oldest non-evicted commitment: ", oldestNonEvictedCommitment) commitmentsMainChain := ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { return commitment.Slot() >= oldestNonEvictedCommitment @@ -1055,18 +1071,31 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { return commitment.Slot() >= oldestNonEvictedCommitment }) + // TODO: remove prints + fmt.Println("Commitments on main chain: ", lo.Map(commitmentsMainChain, func(c *model.Commitment) iotago.CommitmentID { + return c.ID() + })) + fmt.Println("Ultimate commitments P2: ", lo.Map(ultimateCommitmentsP2, func(c *model.Commitment) iotago.CommitmentID { + return c.ID() + })) + fmt.Println("Ultimate commitments P3: ", lo.Map(ultimateCommitmentsP3, func(c *model.Commitment) iotago.CommitmentID { + return c.ID() + })) + ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. + // We have not evicted the slot below the forking point, so chains are not yet orphaned. + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), ts.Nodes()...) - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, iotago.EmptyCommitmentID, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) + + // TODO: ts.AssertCommitmentsAndChainsEvicted(11, ts.Nodes()...) } type Blocks []*blocks.Block @@ -1083,8 +1112,8 @@ func slotPrefix(partition int, slot iotago.SlotIndex) string { return "P" + strconv.Itoa(partition) + ":" } -func commitmentWithLargestID(commitments ...*protocol.Commitment) *protocol.Commitment { - var largestCommitment *protocol.Commitment +func commitmentWithLargestID(commitments ...*model.Commitment) *model.Commitment { + var largestCommitment *model.Commitment for _, commitment := range commitments { if largestCommitment == nil || bytes.Compare(lo.PanicOnErr(commitment.ID().Bytes()), lo.PanicOnErr(largestCommitment.ID().Bytes())) > 0 { largestCommitment = commitment diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index 37d4e8108..e1c0ab717 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -54,11 +54,15 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit { protocolCommitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) if err != nil { - return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, protocolCommitment, chainID) + return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitment.ID(), chainID) } if protocolCommitment.Chain.Get() != selectedChain { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s, got %s", node.Name, protocolCommitment, chainID, protocolCommitment.Chain.Get().ForkingPoint.Get().ID()) + if selectedChain == nil { + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected nil, got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) + } + + return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s (pointer: %p, name: %s), got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), chainID, selectedChain, selectedChain.LogName(), protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) } } @@ -123,7 +127,7 @@ func (t *TestSuite) AssertUniqueCommitmentChain(nodes ...*mock.Node) { } } -func (t *TestSuite) AssertCommitmentsEvicted(expectedEvictedSlot iotago.SlotIndex, nodes ...*mock.Node) { +func (t *TestSuite) AssertCommitmentsAndChainsEvicted(expectedEvictedSlot iotago.SlotIndex, nodes ...*mock.Node) { mustNodes(nodes) for _, node := range nodes { @@ -136,7 +140,7 @@ func (t *TestSuite) AssertCommitmentsEvicted(expectedEvictedSlot iotago.SlotInde } if expectedEvictedSlot >= commitment.Slot() { - return ierrors.Errorf("AssertCommitmentsEvicted: %s: commitment %s not evicted", node.Name, commitment.ID()) + return ierrors.Errorf("AssertCommitmentsAndChainsEvicted: %s: commitment %s not evicted", node.Name, commitment.ID()) } return nil @@ -148,7 +152,7 @@ func (t *TestSuite) AssertCommitmentsEvicted(expectedEvictedSlot iotago.SlotInde for i := iotago.SlotIndex(0); i <= expectedEvictedSlot; i++ { commitment, exists := chain.Commitment(expectedEvictedSlot) if exists { - return ierrors.Errorf("AssertCommitmentsEvicted: %s: commitment %s on chain %s not evicted", node.Name, commitment.ID(), chain.ForkingPoint.Get().ID()) + return ierrors.Errorf("AssertCommitmentsAndChainsEvicted: %s: commitment %s on chain %s not evicted", node.Name, commitment.ID(), chain.ForkingPoint.Get().ID()) } } @@ -160,7 +164,7 @@ func (t *TestSuite) AssertCommitmentsEvicted(expectedEvictedSlot iotago.SlotInde // Make sure that we don't have dangling chains. if err := node.Protocol.Chains.Set.ForEach(func(chain *protocol.Chain) error { if _, exists := seenChains[chain]; !exists { - return ierrors.Errorf("AssertCommitmentsEvicted: %s: chain %s not evicted", node.Name, chain.ForkingPoint.Get().ID()) + return ierrors.Errorf("AssertCommitmentsAndChainsEvicted: %s: chain %s not evicted, total count of chains (from commitments)=%d, actual (in Protocol.Chains)=%d", node.Name, chain.ForkingPoint.Get().ID(), len(seenChains), node.Protocol.Chains.Set.Size()) } return nil From a144417737122290a9963b1eb0a5aec85f570bfd Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:11:51 +0100 Subject: [PATCH 22/49] Fix deriveChain method --- pkg/protocol/commitment.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 2d0ad97f5..91b5c4fd7 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -342,6 +342,11 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { return nil } + // if mainChild is nil that means that the parent has been evicted, so we should stay on the currentChain + if mainChild == nil { + return currentChain + } + // if we are not the main child of our parent, we spawn a new chain if c != mainChild { if currentChain == nil { @@ -356,7 +361,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 (that we are supposed to From 2596646e8381dd33ec4921b326bf185ef1db5bf4 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:41:03 +0100 Subject: [PATCH 23/49] Fix and extend EngineSwitching_Tie test --- pkg/protocol/commitments.go | 11 +++- pkg/tests/protocol_engine_switching_test.go | 71 +++++++++++++-------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 063a55b63..27e01cf8f 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -176,7 +176,16 @@ func (c *Commitments) publishRootCommitment(mainChain *Chain, mainEngine *engine publishedCommitment.Chain.Set(mainChain) } - mainChain.ForkingPoint.Set(publishedCommitment) + // Update the forking point of a chain only if the root is empty or root belongs to the main chain + // to avoid updating ForkingPoint of the new mainChain into the past. + if c.Root.Get() == nil { + mainChain.LogDebug("set forking point", "publishedCommitment", publishedCommitment.LogName(), "mainChain", mainChain.LogName(), "Root", "nil", "published", published) + + mainChain.ForkingPoint.Set(publishedCommitment) + } else if c.Root.Get().Chain.Get() == mainChain { + mainChain.LogDebug("set forking point", "publishedCommitment", publishedCommitment.LogName(), "mainChain", mainChain.LogName(), "Root", c.Root.Get().LogName(), "published", published) + mainChain.ForkingPoint.Set(publishedCommitment) + } c.Root.Set(publishedCommitment) }) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 97fb0522b..96cecef60 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -120,7 +120,9 @@ func TestProtocol_EngineSwitching(t *testing.T) { } ts.Run(false, nodeOptions) - + ts.Node("node6").Protocol.SetLogLevel(log.LevelTrace) + ts.Node("node6").Protocol.Engines.Main.Get().SetLogLevel(log.LevelDebug) + ts.Node("node6").Protocol.Blocks.SetLogLevel(log.LevelDebug) expectedCommittee := []iotago.AccountID{ node0.Validator.AccountID, node1.Validator.AccountID, @@ -786,6 +788,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AddDefaultWallet(nodes[0]) const expectedCommittedSlotAfterPartitionMerge = 18 + const forkingSlot = 14 nodeOptions := []options.Option[protocol.Protocol]{ protocol.WithSybilProtectionProvider( @@ -965,13 +968,18 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { } ts.AssertStrongTips(tipBlocks, targetNodes...) - - // Assert Protocol.Chains and Protocol.Commitments state. - // TODO: assert here } issueBlocks(0, []iotago.SlotIndex{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}) + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + + commitmentsMainChain := ts.CommitmentsOfMainEngine(nodes[0], 6, 11) + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, commitmentsMainChain[0].ID(), ts.Nodes()...) + ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) + // Split into partitions P1, P2 and P3. ts.SplitIntoPartitions(map[string][]*mock.Node{ "P1": {nodes[0]}, @@ -1002,6 +1010,9 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { issueBlocks(2, []iotago.SlotIndex{14, 15, 16, 17, 18, 19, 20}) issueBlocks(3, []iotago.SlotIndex{14, 15, 16, 17, 18, 19, 20}) + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + commitment140 := ts.CommitmentOfMainEngine(nodes[0], 14) commitment141 := ts.CommitmentOfMainEngine(nodes[1], 14) commitment142 := ts.CommitmentOfMainEngine(nodes[2], 14) @@ -1062,40 +1073,48 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) oldestNonEvictedCommitment := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge - fmt.Println("Oldest non-evicted commitment: ", oldestNonEvictedCommitment) - commitmentsMainChain := ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) + + commitmentsMainChain = ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { - return commitment.Slot() >= oldestNonEvictedCommitment + return commitment.Slot() >= forkingSlot }) ultimateCommitmentsP3 := lo.Filter(engineCommitmentsP3, func(commitment *model.Commitment) bool { - return commitment.Slot() >= oldestNonEvictedCommitment + return commitment.Slot() >= forkingSlot }) - // TODO: remove prints - fmt.Println("Commitments on main chain: ", lo.Map(commitmentsMainChain, func(c *model.Commitment) iotago.CommitmentID { - return c.ID() - })) - fmt.Println("Ultimate commitments P2: ", lo.Map(ultimateCommitmentsP2, func(c *model.Commitment) iotago.CommitmentID { - return c.ID() - })) - fmt.Println("Ultimate commitments P3: ", lo.Map(ultimateCommitmentsP3, func(c *model.Commitment) iotago.CommitmentID { - return c.ID() - })) - ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) // We have not evicted the slot below the forking point, so chains are not yet orphaned. + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, iotago.EmptyCommitmentID, ts.Nodes()...) - - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // TODO: ts.AssertCommitmentsAndChainsEvicted(11, ts.Nodes()...) + // The Main partition should have all commitments on the old chain, because it did not switch chains. + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) + // Pre-fork commitments should be on the old chains on other partitions. + ts.AssertCommitmentsOnChain(commitmentsMainChain[:8], ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions...) + // Post-fork winning commitments should be on the new chains on other partitions. This chain is the new main one. + ts.AssertCommitmentsOnChain(commitmentsMainChain[8:], ts.CommitmentOfMainEngine(otherPartitions[0], forkingSlot).ID(), otherPartitions...) + + // P2 commitments on the main partition should be on its own chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), mainPartition...) + + // P2 commitments on P2 node should be on the old chain, that is not the main chain anymore. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) + // P2 commitments on P3 node should be on separate chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[1]) + + // P3 commitments on the main partition should be on its own chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), mainPartition...) + // P3 commitments on P3 node should be on the old chain, that is not the main chain anymore. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) + // P3 commitments on P2 node should be on separate chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[0]) + + // TODO: + // Extend the test and make sure that after eviction everything is intact. + // ts.AssertCommitmentsAndChainsEvicted(11, ts.Nodes()...) } type Blocks []*blocks.Block From 532f36da97ef1af0b9cd5d4caac194d2dd1d27f9 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:41:25 +0100 Subject: [PATCH 24/49] Update hive.go --- go.mod | 28 ++++++++++++------------ go.sum | 52 ++++++++++++++++++++++----------------------- tools/gendoc/go.mod | 26 +++++++++++------------ tools/gendoc/go.sum | 52 ++++++++++++++++++++++----------------------- 4 files changed, 79 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index c30e0bb02..18733ff38 100644 --- a/go.mod +++ b/go.mod @@ -5,24 +5,25 @@ go 1.22 replace github.com/goccy/go-graphviz => github.com/alexsporn/go-graphviz v0.0.0-20231011102718-04f10f0a9b59 require ( + github.com/fjl/memsize v0.0.2 github.com/goccy/go-graphviz v0.1.2 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/iotaledger/hive.go/ads v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/app v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/kvstore v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/log v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a + github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7 @@ -65,7 +66,6 @@ require ( github.com/ethereum/go-ethereum v1.13.12 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect - github.com/fjl/memsize v0.0.2 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/fogleman/gg v1.3.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect diff --git a/go.sum b/go.sum index 201ee1bba..bcaea351e 100644 --- a/go.sum +++ b/go.sum @@ -277,32 +277,32 @@ github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJ github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 h1:dTrD7X2PTNgli6EbS4tV9qu3QAm/kBU3XaYZV2xdzys= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7/go.mod h1:ZRdPu684P0fQ1z8sXz4dj9H5LWHhz4a9oCtvjunkSrw= -github.com/iotaledger/hive.go/ads v0.0.0-20240216135101-261e99d9d84a h1:lfHr3XqlJbScsEgj62LX1SRypjTuSPOJfMcUUInypno= -github.com/iotaledger/hive.go/ads v0.0.0-20240216135101-261e99d9d84a/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= -github.com/iotaledger/hive.go/app v0.0.0-20240216135101-261e99d9d84a h1:o5viyYlzi6kgClLNgUW5Pay0tXMylc0FPivYgSlAc4g= -github.com/iotaledger/hive.go/app v0.0.0-20240216135101-261e99d9d84a/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= -github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a h1:9xeffzciYdw9L/ebAOPg/39Bqn3p5iyOROQhQHaAEUs= -github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a h1:+l3NjL4v700Iv+ZF7KjPALkygFOxzkByoRIoSK9bOzc= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= -github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a h1:ux81+J6mcxYw6usZpEPLZjE6J+TNs3RaRcTHa9+5ERM= -github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= -github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a h1:7M1+k0H53jahg2ZDN10SociepCB+jymIZoiYaSenpbQ= -github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a h1:ugcQ43xbMZo5XYTfanIHOxQGKNpxhcatcz9ZXcX6W1o= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240216135101-261e99d9d84a h1:Lszz1ySzHxYKb/QB3+/Ug4WklVgVKCA84u4PB0XK6TM= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240216135101-261e99d9d84a/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= -github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a h1:eUAtyEIYRlAPeZ2qhlEA+7T8DVoYK2h9eotlst/84SU= -github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= -github.com/iotaledger/hive.go/log v0.0.0-20240216135101-261e99d9d84a h1:XzIuUsWPtDP7h9UbQPFW5/bjeqVjodcSCMRuF7zP5jk= -github.com/iotaledger/hive.go/log v0.0.0-20240216135101-261e99d9d84a/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= -github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a h1:qmfoYLK2XyPOXfldG21qHyCrbIf0sl7iJoFirvTrnO0= -github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a h1:ahUFo0X9Th+8/aE6KSWiy7Eap5p0YFL6CDapP1o8dLo= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= -github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a h1:xLreq/rXeSPdb86RnZNEPH3PUIWt56BQxK1+11+hM4I= -github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= +github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e h1:h195tDK+cZBfM0OJ5ZSYPzjSPhfg2utrHHXaYAtXQkY= +github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= +github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e h1:xOe/ax4r8F8vgpmTbc0V9/Cl6JQ2JiObOWeDQq//u3s= +github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e h1:9tUYS4l7f3U2XTGe/rFXdNQn0AyROhU2DZJBeFAQFoI= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e h1:AxbYz87RFRbnALhxRREap5fWYwF8xkHq8KmEHM3kaN8= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e h1:2EpgyJ0IgWK93+1gd+nPV/Wbx8rGNsSmW+XzySGDRTg= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= +github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e h1:9J3QsVCMeMQycImBTYeD/XyJgvX5Yv0AwtimMJ7SuZg= +github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e h1:SRT3fEbDVM+uZtH+lqN1o5e3VZvJJv2KspbhuSa1lTM= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e h1:EtklyRHUac1tVYTp2SAWGZkl/2igjwTXq+YtqzEHA4E= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= +github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e h1:j9ELM/rqMbupr6YiNuttfRpEJCkDb8q0EMlfV0qJnrI= +github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= +github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e h1:g03c/P+yXscbY+K42F1pon4x0KK/+1q/0g3bpy3akJc= +github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e h1:NLuBZrIWe3ScuTHWv0zZF9UnViLC2/C4KrvlxhxCKQg= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e h1:Y1dM+4Uym0z2qGdhHWar//aJwhfWIQoFXHEsIO6rInA= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e h1:fWpuNla2LzjuK68fapZuyR11/yFnQJgBxBAn3SIaQe0= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e h1:I6KnVRg96X7mL1k/h3xovdJL3I31q8C6wPiUJanvOdY= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e/go.mod h1:rCLE9iv2S0qiL4s7TPj/2ieTLhV2m0Nor3g2JJHhu6M= github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 h1:ebh2IKHPVG/qMjTk56hIBG9DcZ0XN02pP8UJ+vB2IpM= diff --git a/tools/gendoc/go.mod b/tools/gendoc/go.mod index f5fd4b460..1c3cccfd3 100644 --- a/tools/gendoc/go.mod +++ b/tools/gendoc/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/iotaledger/iota-core => ../../ require ( - github.com/iotaledger/hive.go/app v0.0.0-20240216135101-261e99d9d84a + github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3 github.com/iotaledger/iota-core v0.0.0-00010101000000-000000000000 ) @@ -56,18 +56,18 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 // indirect - github.com/iotaledger/hive.go/ads v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/kvstore v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/log v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a // indirect - github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a // indirect + github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e // indirect github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e // indirect github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 // indirect github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7 // indirect diff --git a/tools/gendoc/go.sum b/tools/gendoc/go.sum index 8d9fbf916..329011610 100644 --- a/tools/gendoc/go.sum +++ b/tools/gendoc/go.sum @@ -279,34 +279,34 @@ github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJ github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 h1:dTrD7X2PTNgli6EbS4tV9qu3QAm/kBU3XaYZV2xdzys= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7/go.mod h1:ZRdPu684P0fQ1z8sXz4dj9H5LWHhz4a9oCtvjunkSrw= -github.com/iotaledger/hive.go/ads v0.0.0-20240216135101-261e99d9d84a h1:lfHr3XqlJbScsEgj62LX1SRypjTuSPOJfMcUUInypno= -github.com/iotaledger/hive.go/ads v0.0.0-20240216135101-261e99d9d84a/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= -github.com/iotaledger/hive.go/app v0.0.0-20240216135101-261e99d9d84a h1:o5viyYlzi6kgClLNgUW5Pay0tXMylc0FPivYgSlAc4g= -github.com/iotaledger/hive.go/app v0.0.0-20240216135101-261e99d9d84a/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= +github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e h1:h195tDK+cZBfM0OJ5ZSYPzjSPhfg2utrHHXaYAtXQkY= +github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= +github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e h1:xOe/ax4r8F8vgpmTbc0V9/Cl6JQ2JiObOWeDQq//u3s= +github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3 h1:4aVJTc0KS77uEw0Tny4r0n1ORwcbAQDECaCclgf/6lE= github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3/go.mod h1:TZeAqieDu+xDOZp2e9+S+8pZp1PrfgcwLUnxmd8IgLU= -github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a h1:9xeffzciYdw9L/ebAOPg/39Bqn3p5iyOROQhQHaAEUs= -github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a h1:+l3NjL4v700Iv+ZF7KjPALkygFOxzkByoRIoSK9bOzc= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= -github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a h1:ux81+J6mcxYw6usZpEPLZjE6J+TNs3RaRcTHa9+5ERM= -github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= -github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a h1:7M1+k0H53jahg2ZDN10SociepCB+jymIZoiYaSenpbQ= -github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a h1:ugcQ43xbMZo5XYTfanIHOxQGKNpxhcatcz9ZXcX6W1o= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240216135101-261e99d9d84a h1:Lszz1ySzHxYKb/QB3+/Ug4WklVgVKCA84u4PB0XK6TM= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240216135101-261e99d9d84a/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= -github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a h1:eUAtyEIYRlAPeZ2qhlEA+7T8DVoYK2h9eotlst/84SU= -github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= -github.com/iotaledger/hive.go/log v0.0.0-20240216135101-261e99d9d84a h1:XzIuUsWPtDP7h9UbQPFW5/bjeqVjodcSCMRuF7zP5jk= -github.com/iotaledger/hive.go/log v0.0.0-20240216135101-261e99d9d84a/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= -github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a h1:qmfoYLK2XyPOXfldG21qHyCrbIf0sl7iJoFirvTrnO0= -github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a h1:ahUFo0X9Th+8/aE6KSWiy7Eap5p0YFL6CDapP1o8dLo= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= -github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a h1:xLreq/rXeSPdb86RnZNEPH3PUIWt56BQxK1+11+hM4I= -github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e h1:9tUYS4l7f3U2XTGe/rFXdNQn0AyROhU2DZJBeFAQFoI= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e h1:AxbYz87RFRbnALhxRREap5fWYwF8xkHq8KmEHM3kaN8= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e h1:2EpgyJ0IgWK93+1gd+nPV/Wbx8rGNsSmW+XzySGDRTg= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= +github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e h1:9J3QsVCMeMQycImBTYeD/XyJgvX5Yv0AwtimMJ7SuZg= +github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e h1:SRT3fEbDVM+uZtH+lqN1o5e3VZvJJv2KspbhuSa1lTM= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e h1:EtklyRHUac1tVYTp2SAWGZkl/2igjwTXq+YtqzEHA4E= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= +github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e h1:j9ELM/rqMbupr6YiNuttfRpEJCkDb8q0EMlfV0qJnrI= +github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= +github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e h1:g03c/P+yXscbY+K42F1pon4x0KK/+1q/0g3bpy3akJc= +github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e h1:NLuBZrIWe3ScuTHWv0zZF9UnViLC2/C4KrvlxhxCKQg= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e h1:Y1dM+4Uym0z2qGdhHWar//aJwhfWIQoFXHEsIO6rInA= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e h1:fWpuNla2LzjuK68fapZuyR11/yFnQJgBxBAn3SIaQe0= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e h1:I6KnVRg96X7mL1k/h3xovdJL3I31q8C6wPiUJanvOdY= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e/go.mod h1:rCLE9iv2S0qiL4s7TPj/2ieTLhV2m0Nor3g2JJHhu6M= github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 h1:ebh2IKHPVG/qMjTk56hIBG9DcZ0XN02pP8UJ+vB2IpM= From cbfd240157be10686f558e0ceb41f8fd557cdfd4 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 22 Feb 2024 17:32:24 +0100 Subject: [PATCH 25/49] Update hive.go and adjust to changes --- go.mod | 26 +++++++++---------- go.sum | 52 ++++++++++++++++++------------------- pkg/protocol/commitments.go | 2 +- tools/gendoc/go.mod | 26 +++++++++---------- tools/gendoc/go.sum | 52 ++++++++++++++++++------------------- 5 files changed, 79 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index 18733ff38..55036cdeb 100644 --- a/go.mod +++ b/go.mod @@ -11,19 +11,19 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e - github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/ads v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/app v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/constraints v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222160526-683e413d0020 + github.com/iotaledger/hive.go/crypto v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/ds v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/ierrors v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/kvstore v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/lo v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/log v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/runtime v0.0.0-20240222160526-683e413d0020 + github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222160526-683e413d0020 + github.com/iotaledger/hive.go/stringify v0.0.0-20240222160526-683e413d0020 github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7 diff --git a/go.sum b/go.sum index bcaea351e..59b8d9b8c 100644 --- a/go.sum +++ b/go.sum @@ -277,32 +277,32 @@ github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJ github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 h1:dTrD7X2PTNgli6EbS4tV9qu3QAm/kBU3XaYZV2xdzys= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7/go.mod h1:ZRdPu684P0fQ1z8sXz4dj9H5LWHhz4a9oCtvjunkSrw= -github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e h1:h195tDK+cZBfM0OJ5ZSYPzjSPhfg2utrHHXaYAtXQkY= -github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= -github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e h1:xOe/ax4r8F8vgpmTbc0V9/Cl6JQ2JiObOWeDQq//u3s= -github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= -github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e h1:9tUYS4l7f3U2XTGe/rFXdNQn0AyROhU2DZJBeFAQFoI= -github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e h1:AxbYz87RFRbnALhxRREap5fWYwF8xkHq8KmEHM3kaN8= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= -github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e h1:2EpgyJ0IgWK93+1gd+nPV/Wbx8rGNsSmW+XzySGDRTg= -github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= -github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e h1:9J3QsVCMeMQycImBTYeD/XyJgvX5Yv0AwtimMJ7SuZg= -github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e h1:SRT3fEbDVM+uZtH+lqN1o5e3VZvJJv2KspbhuSa1lTM= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e h1:EtklyRHUac1tVYTp2SAWGZkl/2igjwTXq+YtqzEHA4E= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= -github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e h1:j9ELM/rqMbupr6YiNuttfRpEJCkDb8q0EMlfV0qJnrI= -github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= -github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e h1:g03c/P+yXscbY+K42F1pon4x0KK/+1q/0g3bpy3akJc= -github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= -github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e h1:NLuBZrIWe3ScuTHWv0zZF9UnViLC2/C4KrvlxhxCKQg= -github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e h1:Y1dM+4Uym0z2qGdhHWar//aJwhfWIQoFXHEsIO6rInA= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= -github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e h1:fWpuNla2LzjuK68fapZuyR11/yFnQJgBxBAn3SIaQe0= -github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= +github.com/iotaledger/hive.go/ads v0.0.0-20240222160526-683e413d0020 h1:FJHw2V/cnJLSeB+XdgelBT4C8jUI99JuMbaNypdpkpI= +github.com/iotaledger/hive.go/ads v0.0.0-20240222160526-683e413d0020/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= +github.com/iotaledger/hive.go/app v0.0.0-20240222160526-683e413d0020 h1:+VO7E3Nn9+C8cda0KI/+zVYNWFA/QLBu8ARpt2Xfatk= +github.com/iotaledger/hive.go/app v0.0.0-20240222160526-683e413d0020/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222160526-683e413d0020 h1:l9Fc+Bw9otBTRCpTF+XNDBKfBwgccdng2uuzaR0tBHo= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222160526-683e413d0020/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222160526-683e413d0020 h1:U3euqRCLdnKHJqqsX95RKyDDLmGFwgXew2NMW6vgTBE= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222160526-683e413d0020/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222160526-683e413d0020 h1:Qj27ibHcawZ+5TPogsYLBjt1IfFMnwx1a4CwxCLzJQE= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222160526-683e413d0020/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= +github.com/iotaledger/hive.go/ds v0.0.0-20240222160526-683e413d0020 h1:aCWG7orkg5SgRma8aJjULQLquxDgcrSKfhOxn3u1Nm8= +github.com/iotaledger/hive.go/ds v0.0.0-20240222160526-683e413d0020/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222160526-683e413d0020 h1:kYm+HU4J9m4S6bnPGbP0GfPAaCXqYJEoYRJ0ryhVQog= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222160526-683e413d0020/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222160526-683e413d0020 h1:96r3eh/Gudp8bP16GVCxd7BAAU3NIWAhT7W1Di7kzfs= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222160526-683e413d0020/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= +github.com/iotaledger/hive.go/lo v0.0.0-20240222160526-683e413d0020 h1:hlpnGdbzT7Ny91guSWCBSv3j8Wv6nYDNfd2SUCK78jE= +github.com/iotaledger/hive.go/lo v0.0.0-20240222160526-683e413d0020/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= +github.com/iotaledger/hive.go/log v0.0.0-20240222160526-683e413d0020 h1:28wvZcHCC47h5Mq3c18RhQTBHZQOwGTJzQ7tQlfa9sU= +github.com/iotaledger/hive.go/log v0.0.0-20240222160526-683e413d0020/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222160526-683e413d0020 h1:xExV8jV5tBKiZCiEJMGtzlY1wWJ5aOBUO/Tm5+6DLiA= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222160526-683e413d0020/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222160526-683e413d0020 h1:7f6uZo+QPPIQxHaTyNWhl2GSY3rwlaUjiSkPAp7nGBA= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222160526-683e413d0020/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222160526-683e413d0020 h1:i4dMbwwmc613mShMAqCxEET+IZa7sBt6rSEMi+lUeAs= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222160526-683e413d0020/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e h1:I6KnVRg96X7mL1k/h3xovdJL3I31q8C6wPiUJanvOdY= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e/go.mod h1:rCLE9iv2S0qiL4s7TPj/2ieTLhV2m0Nor3g2JJHhu6M= github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 h1:ebh2IKHPVG/qMjTk56hIBG9DcZ0XN02pP8UJ+vB2IpM= diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 27e01cf8f..c24162f56 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -258,7 +258,7 @@ func (c *Commitments) publishCommitment(commitment *model.Commitment, solidify b func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, solidify bool, requestIfMissing ...bool) *promise.Promise[*Commitment] { // handle evicted slots slotEvicted := c.protocol.EvictionEvent(commitmentID.Index()) - if slotEvicted.WasTriggered() && c.protocol.LastEvictedSlot().Get() != 0 { + if slotEvicted.WasTriggered() { return promise.New[*Commitment]().Reject(ErrorSlotEvicted) } diff --git a/tools/gendoc/go.mod b/tools/gendoc/go.mod index 1c3cccfd3..7c70b7ff0 100644 --- a/tools/gendoc/go.mod +++ b/tools/gendoc/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/iotaledger/iota-core => ../../ require ( - github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e + github.com/iotaledger/hive.go/app v0.0.0-20240222160526-683e413d0020 github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3 github.com/iotaledger/iota-core v0.0.0-00010101000000-000000000000 ) @@ -56,18 +56,18 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 // indirect - github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e // indirect - github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e // indirect + github.com/iotaledger/hive.go/ads v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/constraints v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/crypto v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/ds v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/ierrors v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/kvstore v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/lo v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/log v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/runtime v0.0.0-20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222160526-683e413d0020 // indirect + github.com/iotaledger/hive.go/stringify v0.0.0-20240222160526-683e413d0020 // indirect github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e // indirect github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 // indirect github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7 // indirect diff --git a/tools/gendoc/go.sum b/tools/gendoc/go.sum index 329011610..1977116bd 100644 --- a/tools/gendoc/go.sum +++ b/tools/gendoc/go.sum @@ -279,34 +279,34 @@ github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJ github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 h1:dTrD7X2PTNgli6EbS4tV9qu3QAm/kBU3XaYZV2xdzys= github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7/go.mod h1:ZRdPu684P0fQ1z8sXz4dj9H5LWHhz4a9oCtvjunkSrw= -github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e h1:h195tDK+cZBfM0OJ5ZSYPzjSPhfg2utrHHXaYAtXQkY= -github.com/iotaledger/hive.go/ads v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= -github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e h1:xOe/ax4r8F8vgpmTbc0V9/Cl6JQ2JiObOWeDQq//u3s= -github.com/iotaledger/hive.go/app v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= +github.com/iotaledger/hive.go/ads v0.0.0-20240222160526-683e413d0020 h1:FJHw2V/cnJLSeB+XdgelBT4C8jUI99JuMbaNypdpkpI= +github.com/iotaledger/hive.go/ads v0.0.0-20240222160526-683e413d0020/go.mod h1:4bUdqpUden+8RL2WZGzDJqYjOO6JrYZ2L1isp/2lVss= +github.com/iotaledger/hive.go/app v0.0.0-20240222160526-683e413d0020 h1:+VO7E3Nn9+C8cda0KI/+zVYNWFA/QLBu8ARpt2Xfatk= +github.com/iotaledger/hive.go/app v0.0.0-20240222160526-683e413d0020/go.mod h1:O9agBfrnt1ykrDOzF6GXZf4ivcw+SxM9c9C86YtbxLU= github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3 h1:4aVJTc0KS77uEw0Tny4r0n1ORwcbAQDECaCclgf/6lE= github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3/go.mod h1:TZeAqieDu+xDOZp2e9+S+8pZp1PrfgcwLUnxmd8IgLU= -github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e h1:9tUYS4l7f3U2XTGe/rFXdNQn0AyROhU2DZJBeFAQFoI= -github.com/iotaledger/hive.go/constraints v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e h1:AxbYz87RFRbnALhxRREap5fWYwF8xkHq8KmEHM3kaN8= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222083732-602e8e1b2f7e/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= -github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e h1:2EpgyJ0IgWK93+1gd+nPV/Wbx8rGNsSmW+XzySGDRTg= -github.com/iotaledger/hive.go/crypto v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= -github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e h1:9J3QsVCMeMQycImBTYeD/XyJgvX5Yv0AwtimMJ7SuZg= -github.com/iotaledger/hive.go/ds v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e h1:SRT3fEbDVM+uZtH+lqN1o5e3VZvJJv2KspbhuSa1lTM= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e h1:EtklyRHUac1tVYTp2SAWGZkl/2igjwTXq+YtqzEHA4E= -github.com/iotaledger/hive.go/kvstore v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= -github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e h1:j9ELM/rqMbupr6YiNuttfRpEJCkDb8q0EMlfV0qJnrI= -github.com/iotaledger/hive.go/lo v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= -github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e h1:g03c/P+yXscbY+K42F1pon4x0KK/+1q/0g3bpy3akJc= -github.com/iotaledger/hive.go/log v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= -github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e h1:NLuBZrIWe3ScuTHWv0zZF9UnViLC2/C4KrvlxhxCKQg= -github.com/iotaledger/hive.go/runtime v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e h1:Y1dM+4Uym0z2qGdhHWar//aJwhfWIQoFXHEsIO6rInA= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222083732-602e8e1b2f7e/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= -github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e h1:fWpuNla2LzjuK68fapZuyR11/yFnQJgBxBAn3SIaQe0= -github.com/iotaledger/hive.go/stringify v0.0.0-20240222083732-602e8e1b2f7e/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222160526-683e413d0020 h1:l9Fc+Bw9otBTRCpTF+XNDBKfBwgccdng2uuzaR0tBHo= +github.com/iotaledger/hive.go/constraints v0.0.0-20240222160526-683e413d0020/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222160526-683e413d0020 h1:U3euqRCLdnKHJqqsX95RKyDDLmGFwgXew2NMW6vgTBE= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240222160526-683e413d0020/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222160526-683e413d0020 h1:Qj27ibHcawZ+5TPogsYLBjt1IfFMnwx1a4CwxCLzJQE= +github.com/iotaledger/hive.go/crypto v0.0.0-20240222160526-683e413d0020/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= +github.com/iotaledger/hive.go/ds v0.0.0-20240222160526-683e413d0020 h1:aCWG7orkg5SgRma8aJjULQLquxDgcrSKfhOxn3u1Nm8= +github.com/iotaledger/hive.go/ds v0.0.0-20240222160526-683e413d0020/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222160526-683e413d0020 h1:kYm+HU4J9m4S6bnPGbP0GfPAaCXqYJEoYRJ0ryhVQog= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240222160526-683e413d0020/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222160526-683e413d0020 h1:96r3eh/Gudp8bP16GVCxd7BAAU3NIWAhT7W1Di7kzfs= +github.com/iotaledger/hive.go/kvstore v0.0.0-20240222160526-683e413d0020/go.mod h1:vgJh/0OelY+SHdWsdo0kXOYciHu8UA9OAi2FbJgVQsc= +github.com/iotaledger/hive.go/lo v0.0.0-20240222160526-683e413d0020 h1:hlpnGdbzT7Ny91guSWCBSv3j8Wv6nYDNfd2SUCK78jE= +github.com/iotaledger/hive.go/lo v0.0.0-20240222160526-683e413d0020/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= +github.com/iotaledger/hive.go/log v0.0.0-20240222160526-683e413d0020 h1:28wvZcHCC47h5Mq3c18RhQTBHZQOwGTJzQ7tQlfa9sU= +github.com/iotaledger/hive.go/log v0.0.0-20240222160526-683e413d0020/go.mod h1:JCv/LVVTAMoCPLzou534RoIif7CAezcWZlGYabrHsck= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222160526-683e413d0020 h1:xExV8jV5tBKiZCiEJMGtzlY1wWJ5aOBUO/Tm5+6DLiA= +github.com/iotaledger/hive.go/runtime v0.0.0-20240222160526-683e413d0020/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222160526-683e413d0020 h1:7f6uZo+QPPIQxHaTyNWhl2GSY3rwlaUjiSkPAp7nGBA= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240222160526-683e413d0020/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222160526-683e413d0020 h1:i4dMbwwmc613mShMAqCxEET+IZa7sBt6rSEMi+lUeAs= +github.com/iotaledger/hive.go/stringify v0.0.0-20240222160526-683e413d0020/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e h1:I6KnVRg96X7mL1k/h3xovdJL3I31q8C6wPiUJanvOdY= github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240216141618-d7dfe94bdc1e/go.mod h1:rCLE9iv2S0qiL4s7TPj/2ieTLhV2m0Nor3g2JJHhu6M= github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240216141023-6d5f4ef12ac5 h1:ebh2IKHPVG/qMjTk56hIBG9DcZ0XN02pP8UJ+vB2IpM= From d289573635e4657d30f493891690217a428d72c6 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:46:37 +0100 Subject: [PATCH 26/49] Fix unit tests --- pkg/protocol/commitment.go | 2 +- pkg/protocol/commitments.go | 9 ++------- pkg/tests/protocol_engine_switching_test.go | 3 ++- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 91b5c4fd7..af7094085 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -356,7 +356,7 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { return currentChain } - if parentChain == currentChain || mainChild == nil { + if parentChain == currentChain { return nil } diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index c24162f56..3a925ed26 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -176,14 +176,9 @@ func (c *Commitments) publishRootCommitment(mainChain *Chain, mainEngine *engine publishedCommitment.Chain.Set(mainChain) } - // Update the forking point of a chain only if the root is empty or root belongs to the main chain + // Update the forking point of a chain only if the root is empty or root belongs to the main chain or the published commitment is on the main chain. // to avoid updating ForkingPoint of the new mainChain into the past. - if c.Root.Get() == nil { - mainChain.LogDebug("set forking point", "publishedCommitment", publishedCommitment.LogName(), "mainChain", mainChain.LogName(), "Root", "nil", "published", published) - - mainChain.ForkingPoint.Set(publishedCommitment) - } else if c.Root.Get().Chain.Get() == mainChain { - mainChain.LogDebug("set forking point", "publishedCommitment", publishedCommitment.LogName(), "mainChain", mainChain.LogName(), "Root", c.Root.Get().LogName(), "published", published) + if c.Root.Get() == nil || c.Root.Get().Chain.Get() == mainChain || publishedCommitment.Chain.Get() == mainChain { mainChain.ForkingPoint.Set(publishedCommitment) } diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 96cecef60..dbb9e6a0d 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -1112,9 +1112,10 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { // P3 commitments on P2 node should be on separate chain. ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[0]) + //ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) + // TODO: // Extend the test and make sure that after eviction everything is intact. - // ts.AssertCommitmentsAndChainsEvicted(11, ts.Nodes()...) } type Blocks []*blocks.Block From 15cf9c800c1a8394ba35b489b9ae1e327967fa17 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:36:59 +0100 Subject: [PATCH 27/49] Account for slow CI test execution --- pkg/tests/protocol_engine_switching_test.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index dbb9e6a0d..e64fdb2fe 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -411,12 +411,23 @@ func TestProtocol_EngineSwitching(t *testing.T) { return commitment.Slot() >= oldestNonEvictedCommitment }) + ts.AssertNodeState(ts.Nodes(), + testsuite.WithLatestFinalizedSlot(node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot()), + ) + commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + + // When the test is slow on the CI the eviction of a commitment might be delayed, so here we account for that. + if oldestNonEvictedCommitment >= 14 { + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + } else { + ts.AssertCommitmentsOrphaned(commitmentsMainChain, true, ts.Nodes()...) + } + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) From 851f434a7baff58d31e50b4e776204f3194cd0f9 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Sat, 24 Feb 2024 00:35:31 +0100 Subject: [PATCH 28/49] Feat: started simplifying code --- pkg/protocol/commitment.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index af7094085..18b2b9205 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -271,7 +271,7 @@ func (c *Commitment) initDerivedProperties() (shutdown func()) { c.CumulativeWeight.Set(c.Commitment.CumulativeWeight()) } - return lo.Batch( + return lo.BatchReverse( parent.deriveChildren(c), c.deriveOrphaned(parent), @@ -342,11 +342,6 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { return nil } - // if mainChild is nil that means that the parent has been evicted, so we should stay on the currentChain - if mainChild == nil { - return currentChain - } - // if we are not the main child of our parent, we spawn a new chain if c != mainChild { if currentChain == nil { From d92b2f2f8ede3c82741197e423d44eb4aab23eff Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:13:59 +0100 Subject: [PATCH 29/49] Feat: Cleanup MemLeak PR --- pkg/protocol/attestations.go | 2 +- pkg/protocol/commitments.go | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/protocol/attestations.go b/pkg/protocol/attestations.go index 4b9eb0e26..49ad57d5d 100644 --- a/pkg/protocol/attestations.go +++ b/pkg/protocol/attestations.go @@ -158,7 +158,7 @@ func (a *Attestations) sendRequest(commitmentID iotago.CommitmentID) { // processResponse processes the given attestation response. func (a *Attestations) processResponse(commitment *model.Commitment, attestations []*iotago.Attestation, merkleProof *merklehasher.Proof[iotago.Identifier], from peer.ID) { a.workerPool.Submit(func() { - publishedCommitment, _, err := a.protocol.Commitments.publishCommitment(commitment, false) + publishedCommitment, _, err := a.protocol.Commitments.publishCommitment(commitment) if err != nil { a.LogDebug("failed to publish commitment when processing attestations", "commitmentID", commitment.ID(), "peer", from, "error", err) diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 3a925ed26..59d67cfb1 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -73,7 +73,7 @@ func newCommitments(protocol *Protocol) *Commitments { func (c *Commitments) Get(commitmentID iotago.CommitmentID, requestIfMissing ...bool) (commitment *Commitment, err error) { cachedRequest, exists := c.cachedRequests.Get(commitmentID) if !exists && lo.First(requestIfMissing) { - if cachedRequest = c.cachedRequest(commitmentID, true, true); cachedRequest.WasRejected() { + if cachedRequest = c.cachedRequest(commitmentID, true); cachedRequest.WasRejected() { return nil, ierrors.Wrapf(cachedRequest.Err(), "failed to request commitment %s", commitmentID) } } @@ -164,7 +164,7 @@ func (c *Commitments) initRequester() (shutdown func()) { // publishRootCommitment publishes the root commitment of the main engine. func (c *Commitments) publishRootCommitment(mainChain *Chain, mainEngine *engine.Engine) func() { return mainEngine.RootCommitment.OnUpdate(func(_ *model.Commitment, rootCommitment *model.Commitment) { - publishedCommitment, published, err := c.publishCommitment(rootCommitment, false) + publishedCommitment, published, err := c.publishCommitment(rootCommitment) if err != nil { c.LogError("failed to publish new root commitment", "id", rootCommitment.ID(), "error", err) @@ -210,7 +210,7 @@ func (c *Commitments) publishEngineCommitments(chain *Chain, engine *engine.Engi } // publish the commitment - publishedCommitment, _, err := c.publishCommitment(commitment, true) + publishedCommitment, _, err := c.publishCommitment(commitment) if err != nil { c.LogError("failed to publish commitment from engine", "engine", engine.LogName(), "commitment", commitment, "err", err) @@ -229,9 +229,9 @@ func (c *Commitments) publishEngineCommitments(chain *Chain, engine *engine.Engi // publishCommitment publishes the given commitment and returns the singleton Commitment instance that is used to // represent it in our data structure (together with a boolean that indicates if we were the first goroutine to publish // the commitment). -func (c *Commitments) publishCommitment(commitment *model.Commitment, solidify bool) (publishedCommitment *Commitment, published bool, err error) { +func (c *Commitments) publishCommitment(commitment *model.Commitment) (publishedCommitment *Commitment, published bool, err error) { // retrieve promise and abort if it was already rejected - cachedRequest := c.cachedRequest(commitment.ID(), solidify) + cachedRequest := c.cachedRequest(commitment.ID()) if cachedRequest.WasRejected() { return nil, false, ierrors.Wrapf(cachedRequest.Err(), "failed to request commitment %s", commitment.ID()) } @@ -250,7 +250,7 @@ func (c *Commitments) publishCommitment(commitment *model.Commitment, solidify b // cachedRequest returns a singleton Promise for the given commitmentID. If the Promise does not exist yet, it will be // created and optionally requested from the network if missing. Once the promise is resolved, the Commitment is // initialized and provided to the consumers. -func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, solidify bool, requestIfMissing ...bool) *promise.Promise[*Commitment] { +func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, requestIfMissing ...bool) *promise.Promise[*Commitment] { // handle evicted slots slotEvicted := c.protocol.EvictionEvent(commitmentID.Index()) if slotEvicted.WasTriggered() { @@ -274,7 +274,7 @@ func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, solidify b // handle successful resolutions cachedRequest.OnSuccess(func(commitment *Commitment) { - c.initCommitment(commitment, solidify, slotEvicted) + c.initCommitment(commitment, slotEvicted) }) // handle failed resolutions @@ -293,12 +293,12 @@ func (c *Commitments) cachedRequest(commitmentID iotago.CommitmentID, solidify b } // initCommitment initializes the given commitment in the protocol. -func (c *Commitments) initCommitment(commitment *Commitment, solidify bool, slotEvicted reactive.Event) { +func (c *Commitments) initCommitment(commitment *Commitment, slotEvicted reactive.Event) { commitment.LogDebug("created", "id", commitment.ID()) // solidify the parent of the commitment - if solidify { - c.cachedRequest(commitment.PreviousCommitmentID(), true, true).OnSuccess(func(parent *Commitment) { + if root := c.Root.Get(); root != nil && commitment.Slot() > root.Slot() { + c.cachedRequest(commitment.PreviousCommitmentID(), true).OnSuccess(func(parent *Commitment) { commitment.Parent.Set(parent) parent.IsEvicted.OnTrigger(func() { @@ -374,7 +374,7 @@ func (c *Commitments) processResponse(commitment *model.Commitment, from peer.ID return } - if publishedCommitment, published, err := c.protocol.Commitments.publishCommitment(commitment, false); err != nil { + if publishedCommitment, published, err := c.protocol.Commitments.publishCommitment(commitment); err != nil { c.LogError("failed to process commitment", "fromPeer", from, "err", err) } else if published { c.LogTrace("received response", "commitment", publishedCommitment.LogName(), "fromPeer", from) From 49bd804a15d80cc890ece37016a04cc592460f60 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Mon, 26 Feb 2024 08:49:40 +0100 Subject: [PATCH 30/49] Fix Chain eviction assertion --- pkg/protocol/chain.go | 2 +- pkg/tests/protocol_engine_switching_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 6776cce2a..08607afc4 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -149,7 +149,7 @@ func (c *Chain) Commitment(slot iotago.SlotIndex) (commitment *Commitment, exist case slot > forkingPoint.Slot(): return currentChain.commitments.Get(slot) default: - currentChain = c.ParentChain.Get() + currentChain = currentChain.ParentChain.Get() } } diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index e64fdb2fe..f24b6d1af 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -421,7 +421,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - // When the test is slow on the CI the eviction of a commitment might be delayed, so here we account for that. + // When the test is slow on the CI, the eviction of a commitment might be delayed, so here we account for that. if oldestNonEvictedCommitment >= 14 { ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) } else { @@ -1123,7 +1123,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { // P3 commitments on P2 node should be on separate chain. ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[0]) - //ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) + ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) // TODO: // Extend the test and make sure that after eviction everything is intact. From 2ee35663cc4e1d08805e2a8edeb565dc514e146c Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:35:17 +0100 Subject: [PATCH 31/49] Extend the engine switching tie test. --- pkg/protocol/chain.go | 2 - pkg/tests/protocol_engine_switching_test.go | 143 +++++++++++++------- pkg/testsuite/storage_settings.go | 19 +++ 3 files changed, 110 insertions(+), 54 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 08607afc4..66fa7272e 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -313,8 +313,6 @@ func (c *Chain) addCommitment(newCommitment *Commitment) (shutdown func()) { newCommitment.IsSynced.OnTrigger(func() { c.LatestSyncedSlot.Set(newCommitment.Slot()) }), func() { - // TODO: this should not be done here, because it might cause problems upon chain switching. - // A chain should manage this field by itself. c.commitments.Delete(newCommitment.Slot()) }, ) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index f24b6d1af..48d7c1be4 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -411,9 +411,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { return commitment.Slot() >= oldestNonEvictedCommitment }) - ts.AssertNodeState(ts.Nodes(), - testsuite.WithLatestFinalizedSlot(node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot()), - ) + ts.AssertFinalizedCommitmentAtLeastSlotIndex(14+maxCommittableAge, ts.Nodes()...) commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) @@ -780,7 +778,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ), ), - testsuite.WithWaitFor(15*time.Second), + testsuite.WithWaitFor(60*time.Second), ) defer ts.Shutdown() @@ -854,6 +852,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.Run(false, nodesOptions) nodes[0].Protocol.SetLogLevel(log.LevelTrace) + nodes[1].Protocol.SetLogLevel(log.LevelTrace) expectedCommittee := []iotago.AccountID{nodes[0].Validator.AccountID, nodes[1].Validator.AccountID, nodes[2].Validator.AccountID} @@ -1059,29 +1058,32 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.MergePartitionsToMain() } - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() + // Make sure the nodes switch their engines. + { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() - ctxP1, ctxP1Cancel := context.WithCancel(ctx) - ctxP2, ctxP2Cancel := context.WithCancel(ctx) - ctxP3, ctxP3Cancel := context.WithCancel(ctx) + ctxP1, ctxP1Cancel := context.WithCancel(ctx) + ctxP2, ctxP2Cancel := context.WithCancel(ctx) + ctxP3, ctxP3Cancel := context.WithCancel(ctx) - wg := &sync.WaitGroup{} + wg := &sync.WaitGroup{} - // Issue blocks on both partitions after merging the networks. - nodes[0].Validator.IssueActivity(ctxP1, wg, 21, nodes[0]) - nodes[1].Validator.IssueActivity(ctxP2, wg, 21, nodes[1]) - nodes[2].Validator.IssueActivity(ctxP3, wg, 21, nodes[2]) + // Issue blocks on all partitions after merging the networks. + nodes[0].Validator.IssueActivity(ctxP1, wg, 21, nodes[0]) + nodes[1].Validator.IssueActivity(ctxP2, wg, 21, nodes[1]) + nodes[2].Validator.IssueActivity(ctxP3, wg, 21, nodes[2]) - ts.AssertMainEngineSwitchedCount(0, mainPartition...) - ts.AssertMainEngineSwitchedCount(1, otherPartitions...) + ts.AssertMainEngineSwitchedCount(0, mainPartition...) + ts.AssertMainEngineSwitchedCount(1, otherPartitions...) - ctxP1Cancel() - ctxP2Cancel() - ctxP3Cancel() - wg.Wait() + ctxP1Cancel() + ctxP2Cancel() + ctxP3Cancel() + wg.Wait() - ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) + ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) + } oldestNonEvictedCommitment := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge @@ -1093,40 +1095,77 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { return commitment.Slot() >= forkingSlot }) - ts.AssertUniqueCommitmentChain(ts.Nodes()...) - ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + { + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - // We have not evicted the slot below the forking point, so chains are not yet orphaned. - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, false, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, false, ts.Nodes()...) - - // The Main partition should have all commitments on the old chain, because it did not switch chains. - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) - // Pre-fork commitments should be on the old chains on other partitions. - ts.AssertCommitmentsOnChain(commitmentsMainChain[:8], ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions...) - // Post-fork winning commitments should be on the new chains on other partitions. This chain is the new main one. - ts.AssertCommitmentsOnChain(commitmentsMainChain[8:], ts.CommitmentOfMainEngine(otherPartitions[0], forkingSlot).ID(), otherPartitions...) - - // P2 commitments on the main partition should be on its own chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), mainPartition...) - - // P2 commitments on P2 node should be on the old chain, that is not the main chain anymore. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) - // P2 commitments on P3 node should be on separate chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[1]) - - // P3 commitments on the main partition should be on its own chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), mainPartition...) - // P3 commitments on P3 node should be on the old chain, that is not the main chain anymore. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) - // P3 commitments on P2 node should be on separate chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[0]) + // We have not evicted the slot below the forking point, so chains are not yet orphaned. + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, false, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, false, ts.Nodes()...) + + // The Main partition should have all commitments on the old chain, because it did not switch chains. + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) + // Pre-fork commitments should be on the old chains on other partitions. + ts.AssertCommitmentsOnChain(commitmentsMainChain[:8], ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions...) + // Post-fork winning commitments should be on the new chains on other partitions. This chain is the new main one. + ts.AssertCommitmentsOnChain(commitmentsMainChain[8:], ts.CommitmentOfMainEngine(otherPartitions[0], forkingSlot).ID(), otherPartitions...) + + // P2 commitments on the main partition should be on its own chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), mainPartition...) + + // P2 commitments on P2 node should be on the old chain, that is not the main chain anymore. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) + // P2 commitments on P3 node should be on separate chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[1]) + + // P3 commitments on the main partition should be on its own chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), mainPartition...) + // P3 commitments on P3 node should be on the old chain, that is not the main chain anymore. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) + // P3 commitments on P2 node should be on separate chain. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[0]) + + ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) + } - ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) + // Finalize further slot and make sure the nodes have the same state of chains. + { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + ctxP1, ctxP1Cancel := context.WithCancel(ctx) + ctxP2, ctxP2Cancel := context.WithCancel(ctx) + ctxP3, ctxP3Cancel := context.WithCancel(ctx) + + wg := &sync.WaitGroup{} + + // Issue blocks on all partitions after merging the networks. + nodes[0].Validator.IssueActivity(ctxP1, wg, nodes[0].Protocol.Engines.Main.Get().Storage.Settings().LatestStoredSlot()+1, nodes[0]) + nodes[1].Validator.IssueActivity(ctxP2, wg, nodes[1].Protocol.Engines.Main.Get().Storage.Settings().LatestStoredSlot()+1, nodes[1]) + nodes[2].Validator.IssueActivity(ctxP3, wg, nodes[2].Protocol.Engines.Main.Get().Storage.Settings().LatestStoredSlot()+1, nodes[2]) + + ts.AssertFinalizedCommitmentAtLeastSlotIndex(forkingSlot+maxCommittableAge+1, ts.Nodes()...) - // TODO: - // Extend the test and make sure that after eviction everything is intact. + ctxP1Cancel() + ctxP2Cancel() + ctxP3Cancel() + wg.Wait() + + oldestNonEvictedCommitment = mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + commitmentsMainChain = ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestCommitment().Slot()) + + ts.AssertUniqueCommitmentChain(ts.Nodes()...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) + ts.AssertCommitmentsAndChainsEvicted(forkingSlot+1, ts.Nodes()...) + + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) + + // The oldest commitment is in the slices are should already be evicted, so we only need to check the newer ones. + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2[2:], true, ts.Nodes()...) + ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3[2:], true, ts.Nodes()...) + } } type Blocks []*blocks.Block diff --git a/pkg/testsuite/storage_settings.go b/pkg/testsuite/storage_settings.go index 230a85bc1..4459e71d2 100644 --- a/pkg/testsuite/storage_settings.go +++ b/pkg/testsuite/storage_settings.go @@ -95,6 +95,25 @@ func (t *TestSuite) AssertLatestCommitmentSlotIndex(slot iotago.SlotIndex, nodes } } +func (t *TestSuite) AssertFinalizedCommitmentAtLeastSlotIndex(slot iotago.SlotIndex, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + latestFinalizedSlotSettings := node.Protocol.Engines.Main.Get().Storage.Settings().LatestFinalizedSlot() + if slot > latestFinalizedSlotSettings { + return ierrors.Errorf("AssertFinalizedCommitmentAtLeastSlotIndex: %s: expected at least %v, got %v in settings", node.Name, slot, latestFinalizedSlotSettings) + } + latestFinalizedSlotSyncManager := node.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() + if slot > latestFinalizedSlotSyncManager { + return ierrors.Errorf("AssertFinalizedCommitmentAtLeastSlotIndex: %s: expected at least %v, got %v in sync manager", node.Name, slot, latestFinalizedSlotSyncManager) + } + + return nil + }) + } +} + func (t *TestSuite) AssertLatestCommitmentCumulativeWeight(cw uint64, nodes ...*mock.Node) { mustNodes(nodes) From 412aded18b6eac659a28e29ce7dad56afecc0475 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:29:57 +0100 Subject: [PATCH 32/49] Refactor: cleanup --- pkg/core/inspection/inspected_object.go | 133 ++++++++++++++++++++++++ pkg/core/inspection/session.go | 15 +++ pkg/core/traversed/object.go | 94 ----------------- pkg/protocol/chain.go | 16 --- pkg/protocol/chains.go | 12 --- pkg/protocol/commitment.go | 15 --- pkg/protocol/commitments.go | 23 ---- pkg/protocol/inspection.go | 70 +++++++++++++ pkg/protocol/protocol.go | 8 -- pkg/tests/protocol_eviction_test.go | 4 +- 10 files changed, 220 insertions(+), 170 deletions(-) create mode 100644 pkg/core/inspection/inspected_object.go create mode 100644 pkg/core/inspection/session.go delete mode 100644 pkg/core/traversed/object.go create mode 100644 pkg/protocol/inspection.go diff --git a/pkg/core/inspection/inspected_object.go b/pkg/core/inspection/inspected_object.go new file mode 100644 index 000000000..710d5c64f --- /dev/null +++ b/pkg/core/inspection/inspected_object.go @@ -0,0 +1,133 @@ +package inspection + +import ( + "fmt" + "regexp" + "strings" + "unicode" + + "github.com/iotaledger/hive.go/ds/orderedmap" + "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/hive.go/stringify" +) + +// InspectedObject is an interface that is used to represent an object that has been inspected. +type InspectedObject interface { + // Type returns the type of the object. + Type() string + + // InstanceID returns the instance identifier of the object. + InstanceID() string + + // AddChild adds a child object to the inspected object. + AddChild(name string, instance any, inspectManually ...func(object InspectedObject)) + + // String returns a string representation of the inspected object. + String() string +} + +// NewInspectedObject creates a new inspected object from the given instance and inspect function. +func NewInspectedObject(instance any, inspect func(InspectedObject), session ...Session) InspectedObject { + o := &inspectedObject{ + instance: instance, + childObjects: orderedmap.New[string, InspectedObject](), + session: lo.First(session, make(Session)), + } + + if o.inspected = o.session.FirstOccurrence(instance); o.inspected { + inspect(o) + } + + return o +} + +// inspectedObject is an implementation of the InspectedObject interface. +type inspectedObject struct { + instance any + childObjects *orderedmap.OrderedMap[string, InspectedObject] + session Session + inspected bool +} + +// Type returns the type of the object. +func (i *inspectedObject) Type() string { + runes := []rune(regexp.MustCompile(`[^.]+\.([^[]+).*`).ReplaceAllString(fmt.Sprintf("%T", i.instance), "${1}")) + runes[0] = unicode.ToUpper(runes[0]) + + return string(runes) +} + +// InstanceID returns the instance identifier of the object. +func (i *inspectedObject) InstanceID() string { + type named interface { + LogName() string + } + + if namedInstance, isNamed := i.instance.(named); isNamed { + return namedInstance.LogName() + } + + return fmt.Sprintf("%p", i.instance) +} + +// AddChild adds a child object to the inspected object. +func (i *inspectedObject) AddChild(name string, instance any, inspectManually ...func(object InspectedObject)) { + type inspectable interface { + Inspect(session ...Session) InspectedObject + } + + if stringify.IsInterfaceNil(instance) { + i.childObjects.Set(name, nil) + } else if len(inspectManually) >= 1 { + i.childObjects.Set(name, NewInspectedObject(instance, inspectManually[0], i.session)) + } else { + i.childObjects.Set(name, instance.(inspectable).Inspect(i.session)) + } +} + +// String returns a string representation of the inspected object. +func (i *inspectedObject) String() string { + return i.indentedString(0) +} + +// indentedString returns a string representation of the inspected object with the given indentation. +func (i *inspectedObject) indentedString(indent int) string { + if i == nil { + return "nil" + } + + var typeString string + if instanceID, typeName := i.InstanceID(), i.Type(); typeName == instanceID { + typeString = typeName + } else { + typeString = typeName + "(" + instanceID + ")" + } + + if !i.inspected { + return typeString + " {...}" + } + + childOutputs := make([]string, 0) + i.childObjects.ForEach(func(key string, value InspectedObject) bool { + if value == nil { + childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentationSize)+key+": nil") + } else if objectValue, ok := value.(*inspectedObject); !ok { + panic("this should never happen but linter requires type cast check") + } else if value.Type() == key || value.InstanceID() == key { + childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentationSize)+objectValue.indentedString(indent+1)) + } else { + childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentationSize)+key+": "+objectValue.indentedString(indent+1)) + } + + return true + }) + + if len(childOutputs) == 0 { + return typeString + " {}" + } + + return typeString + " {\n" + strings.Join(childOutputs, ",\n") + "\n" + strings.Repeat(" ", (indent)*indentationSize) + "}" +} + +// indentationSize defines the size of the indentation. +const indentationSize = 2 diff --git a/pkg/core/inspection/session.go b/pkg/core/inspection/session.go new file mode 100644 index 000000000..be03ae4f8 --- /dev/null +++ b/pkg/core/inspection/session.go @@ -0,0 +1,15 @@ +package inspection + +// Session is used to track instances of objects that have already been inspected. +type Session map[any]bool + +// FirstOccurrence checks if the given instance has already been inspected. +func (s Session) FirstOccurrence(instance any) bool { + if s[instance] { + return false + } + + s[instance] = true + + return true +} diff --git a/pkg/core/traversed/object.go b/pkg/core/traversed/object.go deleted file mode 100644 index 027d1c191..000000000 --- a/pkg/core/traversed/object.go +++ /dev/null @@ -1,94 +0,0 @@ -package traversed - -import ( - "strings" - - "github.com/iotaledger/hive.go/ds/orderedmap" - "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/stringify" -) - -type Object struct { - typeName string - instanceID string - childObjects *orderedmap.OrderedMap[string, *Object] - visitedObjects SeenElements - visited bool -} - -func NewObject(typeName string, instanceID string, traverse func(*Object), seenElements ...SeenElements) *Object { - o := &Object{ - typeName: typeName, - instanceID: instanceID, - visitedObjects: lo.First(seenElements, make(SeenElements)), - childObjects: orderedmap.New[string, *Object](), - } - - if o.visitedObjects[instanceID] { - o.visited = true - } else { - o.visitedObjects[instanceID] = true - - traverse(o) - } - - return o -} - -func (m *Object) AddTraversable(key string, object Traversable) { - if stringify.IsInterfaceNil(object) { - m.childObjects.Set(key, nil) - } else { - m.childObjects.Set(key, object.Traverse(m.visitedObjects)) - } -} - -func (m *Object) AddNewObject(key string, typeName string, instanceIdentifier string, setup func(set *Object)) { - m.childObjects.Set(key, NewObject(typeName, instanceIdentifier, setup, m.visitedObjects)) -} - -func (m *Object) String() string { - return m.string(0) -} - -func (m *Object) string(indent int) string { - if m == nil { - return "nil" - } - - var typeString string - if m.typeName == m.instanceID { - typeString = m.typeName - } else { - typeString = m.typeName + "(" + m.instanceID + ")" - } - - if m.visited { - return typeString + " {...}" - } - - childOutputs := make([]string, 0) - m.childObjects.ForEach(func(key string, value *Object) bool { - if value != nil && value.typeName == key { - childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentSize)+value.string(indent+1)) - } else { - childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentSize)+key+": "+value.string(indent+1)) - } - - return true - }) - - if len(childOutputs) == 0 { - return typeString + " {}" - } - - return typeString + " {\n" + strings.Join(childOutputs, ",\n") + "\n" + strings.Repeat(" ", (indent)*indentSize) + "}" -} - -type Traversable interface { - Traverse(seenElements ...SeenElements) *Object -} - -type SeenElements map[any]bool - -const indentSize = 2 diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 6776cce2a..4d7eaa992 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -1,15 +1,12 @@ package protocol import ( - "fmt" - "github.com/libp2p/go-libp2p/core/peer" "github.com/iotaledger/hive.go/ds/reactive" "github.com/iotaledger/hive.go/ds/shrinkingmap" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/log" - "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -168,19 +165,6 @@ func (c *Chain) LatestEngine() *engine.Engine { return currentEngine } -func (c *Chain) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { - return traversed.NewObject("Chain", c.LogName(), func(chain *traversed.Object) { - chain.AddTraversable("ForkingPoint", c.ForkingPoint.Get()) - chain.AddTraversable("ParentChain", c.ParentChain.Get()) - - chain.AddNewObject("ChildChains", "Set", fmt.Sprintf("%p", c.ChildChains), func(childChains *traversed.Object) { - c.ChildChains.Range(func(childChain *Chain) { - childChains.AddTraversable(childChain.LogName(), childChain) - }) - }) - }, seenObjects...) -} - // initLogger initializes the Logger of this chain. func (c *Chain) initLogger() (shutdown func()) { c.Logger = c.chains.NewChildLogger("", true) diff --git a/pkg/protocol/chains.go b/pkg/protocol/chains.go index bc0f44bb6..e169eda4e 100644 --- a/pkg/protocol/chains.go +++ b/pkg/protocol/chains.go @@ -2,7 +2,6 @@ package protocol import ( "cmp" - "fmt" "time" "github.com/libp2p/go-libp2p/core/peer" @@ -12,7 +11,6 @@ import ( "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/log" "github.com/iotaledger/iota-core/pkg/core/account" - "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" "github.com/iotaledger/iota-core/pkg/protocol/engine/blocks" @@ -298,16 +296,6 @@ func (c *Chains) WithInitializedEngines(callback func(chain *Chain, engine *engi }) } -func (c *Chains) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { - return traversed.NewObject("Chains", c.LogName(), func(o *traversed.Object) { - o.AddNewObject("Set", "Set", fmt.Sprintf("%p", c.Set), func(set *traversed.Object) { - c.Range(func(chain *Chain) { - set.AddTraversable(chain.LogName(), chain) - }) - }) - }, seenObjects...) -} - // initLogger initializes the logger for this component. func (c *Chains) initLogger(logger log.Logger) (shutdown func()) { c.Logger = logger diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 18b2b9205..6919a2c92 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -8,7 +8,6 @@ import ( "github.com/iotaledger/hive.go/ds/reactive" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/log" - "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -146,20 +145,6 @@ func (c *Commitment) TargetEngine() *engine.Engine { return nil } -func (c *Commitment) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { - return traversed.NewObject("Commitment", c.LogName(), func(o *traversed.Object) { - o.AddTraversable("Parent", c.Parent.Get()) - o.AddTraversable("MainChild", c.MainChild.Get()) - o.AddTraversable("Chain", c.Chain.Get()) - - o.AddNewObject("Children", "Set", fmt.Sprintf("%p", c.Children), func(children *traversed.Object) { - c.Children.Range(func(child *Commitment) { - children.AddTraversable(child.LogName(), child) - }) - }) - }, seenObjects...) -} - // Less is a function that is used to break ties between two Commitments that have the same cumulative weight by using // the ID of their divergence points (the first commitment that is different between their chains). func (c *Commitment) Less(other *Commitment) bool { diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index 59d67cfb1..e1945f87a 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -1,8 +1,6 @@ package protocol import ( - "fmt" - "github.com/libp2p/go-libp2p/core/peer" "github.com/iotaledger/hive.go/core/eventticker" @@ -13,7 +11,6 @@ import ( "github.com/iotaledger/hive.go/log" "github.com/iotaledger/hive.go/runtime/workerpool" "github.com/iotaledger/iota-core/pkg/core/promise" - "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/protocol/engine" iotago "github.com/iotaledger/iota.go/v4" @@ -100,26 +97,6 @@ func (c *Commitments) API(commitmentID iotago.CommitmentID) (commitmentAPI *engi return commitment.TargetEngine().CommitmentAPI(commitmentID) } -func (c *Commitments) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { - return traversed.NewObject("Commitments", c.LogName(), func(o *traversed.Object) { - o.AddNewObject("Set", "Set", fmt.Sprintf("%p", c.Set), func(set *traversed.Object) { - c.Range(func(commitment *Commitment) { - set.AddTraversable(commitment.LogName(), commitment) - }) - }) - - o.AddNewObject("cachedRequests", "ShrinkingMap", "ShrinkingMap", func(cachedRequests *traversed.Object) { - c.cachedRequests.ForEach(func(commitmentID iotago.CommitmentID, cachedRequest *promise.Promise[*Commitment]) bool { - if commitment := cachedRequest.Result(); commitment != nil { - cachedRequests.AddTraversable(commitmentID.String(), commitment) - } - - return true - }) - }) - }, seenObjects...) -} - // initLogger initializes the logger for this component. func (c *Commitments) initLogger() (shutdown func()) { c.Logger = c.protocol.NewChildLogger("Commitments") diff --git a/pkg/protocol/inspection.go b/pkg/protocol/inspection.go new file mode 100644 index 000000000..f2eb6787b --- /dev/null +++ b/pkg/protocol/inspection.go @@ -0,0 +1,70 @@ +package protocol + +import ( + "github.com/iotaledger/iota-core/pkg/core/inspection" + "github.com/iotaledger/iota-core/pkg/core/promise" + iotago "github.com/iotaledger/iota.go/v4" +) + +func (p *Protocol) Inspect(session ...inspection.Session) inspection.InspectedObject { + return inspection.NewInspectedObject(p, func(o inspection.InspectedObject) { + o.AddChild("Commitments", p.Commitments) + o.AddChild("Chains", p.Chains) + }, session...) +} + +func (c *Commitments) Inspect(session ...inspection.Session) inspection.InspectedObject { + return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { + o.AddChild("Set", c.Set, func(set inspection.InspectedObject) { + c.Range(func(commitment *Commitment) { + set.AddChild(commitment.LogName(), commitment) + }) + }) + + o.AddChild("cachedRequests", c.cachedRequests, func(cachedRequests inspection.InspectedObject) { + c.cachedRequests.ForEach(func(commitmentID iotago.CommitmentID, cachedRequest *promise.Promise[*Commitment]) bool { + if commitment := cachedRequest.Result(); commitment != nil { + cachedRequests.AddChild(commitmentID.String(), commitment) + } + + return true + }) + }) + }, session...) +} + +func (c *Commitment) Inspect(session ...inspection.Session) inspection.InspectedObject { + return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { + o.AddChild("Parent", c.Parent.Get()) + o.AddChild("MainChild", c.MainChild.Get()) + o.AddChild("Chain", c.Chain.Get()) + + o.AddChild("Children", c.Children, func(children inspection.InspectedObject) { + c.Children.Range(func(child *Commitment) { + children.AddChild(child.LogName(), child) + }) + }) + }, session...) +} + +func (c *Chains) Inspect(session ...inspection.Session) inspection.InspectedObject { + return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { + o.AddChild("Set", c.Set, func(set inspection.InspectedObject) { + c.Range(func(chain *Chain) { + set.AddChild(chain.LogName(), chain) + }) + }) + }, session...) +} + +func (c *Chain) Inspect(session ...inspection.Session) inspection.InspectedObject { + return inspection.NewInspectedObject(c, func(chain inspection.InspectedObject) { + chain.AddChild("ForkingPoint", c.ForkingPoint.Get()) + chain.AddChild("ParentChain", c.ParentChain.Get()) + chain.AddChild("ChildChains", c.ChildChains, func(childChains inspection.InspectedObject) { + c.ChildChains.Range(func(childChain *Chain) { + childChains.AddChild(childChain.LogName(), childChain) + }) + }) + }, session...) +} diff --git a/pkg/protocol/protocol.go b/pkg/protocol/protocol.go index 227edfc18..d836bb772 100644 --- a/pkg/protocol/protocol.go +++ b/pkg/protocol/protocol.go @@ -14,7 +14,6 @@ import ( "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/hive.go/runtime/workerpool" - "github.com/iotaledger/iota-core/pkg/core/traversed" "github.com/iotaledger/iota-core/pkg/model" "github.com/iotaledger/iota-core/pkg/network" "github.com/iotaledger/iota-core/pkg/network/protocols/core" @@ -143,13 +142,6 @@ func (p *Protocol) LatestAPI() iotago.API { return p.Engines.Main.Get().LatestAPI() } -func (p *Protocol) Traverse(seenObjects ...traversed.SeenElements) *traversed.Object { - return traversed.NewObject("Protocol", p.LogName(), func(o *traversed.Object) { - o.AddTraversable("Commitments", p.Commitments) - o.AddTraversable("Chains", p.Chains) - }, seenObjects...) -} - // initSubcomponents initializes the subcomponents of the protocol and returns a function that shuts them down. func (p *Protocol) initSubcomponents(networkEndpoint network.Endpoint) (shutdown func()) { p.Network = core.NewProtocol(networkEndpoint, p.Workers.CreatePool("NetworkProtocol"), p) diff --git a/pkg/tests/protocol_eviction_test.go b/pkg/tests/protocol_eviction_test.go index 583f480f0..7cfcc10ea 100644 --- a/pkg/tests/protocol_eviction_test.go +++ b/pkg/tests/protocol_eviction_test.go @@ -181,13 +181,13 @@ func TestProtocol_Eviction(t *testing.T) { issueBlocksTill(8) memConsumptionStart := memsize.Scan(node.Protocol).Total - fmt.Println(node.Protocol.Traverse()) + fmt.Println(node.Protocol.Inspect()) // issue more blocks issueBlocksTill(100) memConsumptionEnd := memsize.Scan(node.Protocol).Total - fmt.Println(node.Protocol.Traverse()) + fmt.Println(node.Protocol.Inspect()) require.Less(t, float64(lo.Return1(memConsumptionEnd)), 1.05*float64(memConsumptionStart), "memory consumption should not grow by more than 5%") } From e18cb1fd5a19e7ebe44db08b9c421e67a0922268 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Mon, 26 Feb 2024 21:19:13 +0100 Subject: [PATCH 33/49] Feat: address linter error --- pkg/core/inspection/inspected_object.go | 4 +- pkg/protocol/inspection.go | 52 +++++++++++++++---------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/pkg/core/inspection/inspected_object.go b/pkg/core/inspection/inspected_object.go index 710d5c64f..959ede39a 100644 --- a/pkg/core/inspection/inspected_object.go +++ b/pkg/core/inspection/inspected_object.go @@ -80,8 +80,10 @@ func (i *inspectedObject) AddChild(name string, instance any, inspectManually .. i.childObjects.Set(name, nil) } else if len(inspectManually) >= 1 { i.childObjects.Set(name, NewInspectedObject(instance, inspectManually[0], i.session)) + } else if inspectableInstance, isInspectable := instance.(inspectable); isInspectable { + i.childObjects.Set(name, inspectableInstance.Inspect(i.session)) } else { - i.childObjects.Set(name, instance.(inspectable).Inspect(i.session)) + panic("added object does not have an 'Inspect(session ...Session) InspectedObject' method - please provide a manual inspection function") } } diff --git a/pkg/protocol/inspection.go b/pkg/protocol/inspection.go index f2eb6787b..f5f3c4924 100644 --- a/pkg/protocol/inspection.go +++ b/pkg/protocol/inspection.go @@ -14,14 +14,14 @@ func (p *Protocol) Inspect(session ...inspection.Session) inspection.InspectedOb } func (c *Commitments) Inspect(session ...inspection.Session) inspection.InspectedObject { - return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { - o.AddChild("Set", c.Set, func(set inspection.InspectedObject) { + var ( + inspectSet = func(set inspection.InspectedObject) { c.Range(func(commitment *Commitment) { set.AddChild(commitment.LogName(), commitment) }) - }) + } - o.AddChild("cachedRequests", c.cachedRequests, func(cachedRequests inspection.InspectedObject) { + inspectCachedRequests = func(cachedRequests inspection.InspectedObject) { c.cachedRequests.ForEach(func(commitmentID iotago.CommitmentID, cachedRequest *promise.Promise[*Commitment]) bool { if commitment := cachedRequest.Result(); commitment != nil { cachedRequests.AddChild(commitmentID.String(), commitment) @@ -29,42 +29,52 @@ func (c *Commitments) Inspect(session ...inspection.Session) inspection.Inspecte return true }) - }) + } + ) + + return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { + o.AddChild("Set", c.Set, inspectSet) + o.AddChild("cachedRequests", c.cachedRequests, inspectCachedRequests) }, session...) } func (c *Commitment) Inspect(session ...inspection.Session) inspection.InspectedObject { + inspectChildren := func(children inspection.InspectedObject) { + c.Children.Range(func(child *Commitment) { + children.AddChild(child.LogName(), child) + }) + } + return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { o.AddChild("Parent", c.Parent.Get()) o.AddChild("MainChild", c.MainChild.Get()) o.AddChild("Chain", c.Chain.Get()) - - o.AddChild("Children", c.Children, func(children inspection.InspectedObject) { - c.Children.Range(func(child *Commitment) { - children.AddChild(child.LogName(), child) - }) - }) + o.AddChild("Children", c.Children, inspectChildren) }, session...) } func (c *Chains) Inspect(session ...inspection.Session) inspection.InspectedObject { - return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { - o.AddChild("Set", c.Set, func(set inspection.InspectedObject) { - c.Range(func(chain *Chain) { - set.AddChild(chain.LogName(), chain) - }) + inspectSet := func(set inspection.InspectedObject) { + c.Set.Range(func(chain *Chain) { + set.AddChild(chain.LogName(), chain) }) + } + + return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { + o.AddChild("Set", c.Set, inspectSet) }, session...) } func (c *Chain) Inspect(session ...inspection.Session) inspection.InspectedObject { + inspectChildChains := func(childChains inspection.InspectedObject) { + c.ChildChains.Range(func(childChain *Chain) { + childChains.AddChild(childChain.LogName(), childChain) + }) + } + return inspection.NewInspectedObject(c, func(chain inspection.InspectedObject) { chain.AddChild("ForkingPoint", c.ForkingPoint.Get()) chain.AddChild("ParentChain", c.ParentChain.Get()) - chain.AddChild("ChildChains", c.ChildChains, func(childChains inspection.InspectedObject) { - c.ChildChains.Range(func(childChain *Chain) { - childChains.AddChild(childChain.LogName(), childChain) - }) - }) + chain.AddChild("ChildChains", c.ChildChains, inspectChildChains) }, session...) } From ce7d96622a2645d19151b86b59f2b246e13693bb Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:50:54 +0100 Subject: [PATCH 34/49] Refactor: removed orphaned --- pkg/protocol/blocks.go | 6 --- pkg/protocol/chain.go | 17 ++++--- pkg/protocol/commitment.go | 53 +++------------------ pkg/protocol/inspection.go | 4 +- pkg/tests/protocol_engine_switching_test.go | 8 ++-- pkg/testsuite/chains.go | 4 +- 6 files changed, 21 insertions(+), 71 deletions(-) diff --git a/pkg/protocol/blocks.go b/pkg/protocol/blocks.go index 639cb9d32..479033628 100644 --- a/pkg/protocol/blocks.go +++ b/pkg/protocol/blocks.go @@ -95,12 +95,6 @@ func (b *Blocks) ProcessResponse(block *model.Block, from peer.ID) { return } - if commitment != nil && commitment.IsOrphaned.Get() { - b.LogTrace("discard block from an orphaned chain", "commitmentID", block.ProtocolBlock().Header.SlotCommitmentID, "blockID", block.ID()) - - return - } - // add the block to the dropped blocks buffer if we could not dispatch it to the chain if commitment == nil || !commitment.Chain.Get().DispatchBlock(block, from) { if !b.droppedBlocksBuffer.Add(block.ProtocolBlock().Header.SlotCommitmentID, types.NewTuple(block, from)) { diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index 4d7eaa992..d21fdd7da 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -126,6 +126,10 @@ func (c *Chain) LastCommonSlot() iotago.SlotIndex { func (c *Chain) DispatchBlock(block *model.Block, src peer.ID) (dispatched bool) { if c == nil { return false + } else if c.IsEvicted.Get() { + c.LogTrace("discard for evicted chain", "commitmentID", block.ProtocolBlock().Header.SlotCommitmentID, "blockID", block.ID()) + + return true } dispatched = c.dispatchBlockToSpawnedEngine(block, src) @@ -262,15 +266,10 @@ func (c *Chain) deriveIsEvicted(forkingPoint *Commitment) (shutdown func()) { // return forkingPointIsOrphaned || forkingPointIsEvicted // }, forkingPoint.IsOrphaned, forkingPoint.IsEvicted)) - return lo.Batch( - forkingPoint.IsEvicted.OnTrigger(func() { - // TODO: MOVE TO DEDICATED WORKER - go c.IsEvicted.Trigger() - }), - forkingPoint.IsOrphaned.OnTrigger(func() { - go c.IsEvicted.Trigger() - }), - ) + return forkingPoint.IsEvicted.OnTrigger(func() { + // TODO: MOVE TO DEDICATED WORKER + go c.IsEvicted.Trigger() + }) } // deriveOutOfSyncThreshold defines how a chain determines its "out of sync" threshold (the latest seen slot minus 2 diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 6919a2c92..151255225 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -84,13 +84,6 @@ type Commitment struct { // IsEvicted contains a flag indicating if this Commitment was evicted from the Protocol. IsEvicted reactive.Event - // IsOrphaned contains a flag indicating if this Commitment is part of an orphaned chain. - // An orphaned chain has its forking point below RootCommitment of the main chain. - // Orphaned commitments are eventually evicted just like other commitments. - // We don't dispatch blocks of orphaned commitments. - // We keep them around to not have to request them every time a block with such a commitment is received. - IsOrphaned reactive.Event - // commitments contains a reference to the Commitments instance that this Commitment belongs to. commitments *Commitments @@ -122,7 +115,6 @@ func newCommitment(commitments *Commitments, model *model.Commitment) *Commitmen IsAboveLatestVerifiedCommitment: reactive.NewVariable[bool](), ReplayDroppedBlocks: reactive.NewVariable[bool](), IsEvicted: reactive.NewEvent(), - IsOrphaned: reactive.NewEvent(), commitments: commitments, } @@ -232,7 +224,6 @@ func (c *Commitment) initLogger() (shutdown func()) { c.IsVerified.LogUpdates(c, log.LevelTrace, "IsVerified"), c.ReplayDroppedBlocks.LogUpdates(c, log.LevelTrace, "ReplayDroppedBlocks"), c.IsEvicted.LogUpdates(c, log.LevelTrace, "IsEvicted"), - c.IsOrphaned.LogUpdates(c, log.LevelDebug, "IsOrphaned"), // TODO: change the log level to trace c.Logger.UnsubscribeFromParentLogger, ) @@ -259,8 +250,6 @@ func (c *Commitment) initDerivedProperties() (shutdown func()) { return lo.BatchReverse( parent.deriveChildren(c), - c.deriveOrphaned(parent), - c.deriveChain(parent), c.deriveCumulativeAttestedWeight(parent), @@ -314,30 +303,17 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) // deriveChain derives the Chain of this Commitment which is either inherited from the parent if we are the main child // or a newly created chain. func (c *Commitment) deriveChain(parent *Commitment) func() { - return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable4(func(currentChain *Chain, isRoot bool, isOrphaned bool, mainChild *Commitment, parentChain *Chain) *Chain { + return c.Chain.DeriveValueFrom(reactive.NewDerivedVariable3(func(currentChain *Chain, isRoot bool, mainChild *Commitment, parentChain *Chain) *Chain { // do not adjust the chain of the root commitment (it is set from the outside) if isRoot { return currentChain } - // If the commitment is orphaned, - // that means that the chain is an orphaned fork, and we should not spawn a new chain. - // Eventually, the orphaned commitments will be evicted once the finalized slot advances. - if isOrphaned { - return nil - } - // if we are not the main child of our parent, we spawn a new chain if c != mainChild { - if currentChain == nil { + if currentChain == nil || currentChain == parentChain { currentChain = c.commitments.protocol.Chains.newChain() currentChain.ForkingPoint.Set(c) - - return currentChain - } - - if parentChain == currentChain { - return nil } return currentChain @@ -346,29 +322,12 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { // if we are the main child of our parent, and our chain is not the parent chain (that we are supposed to // inherit), then we evict our current chain (we will spawn a new one if we ever change back to not being the // main child) - // if currentChain != nil && currentChain != parentChain { - // currentChain.IsEvicted.Trigger() - // } - - return parentChain - }, c.IsRoot, c.IsOrphaned, parent.MainChild, parent.Chain, c.Chain.Get())) -} - -func (c *Commitment) deriveOrphaned(parent *Commitment) func() { - return c.IsOrphaned.DeriveValueFrom(reactive.NewDerivedVariable4(func(isOrphaned bool, isParentOrphaned bool, isParentEvicted bool, isRoot bool, rootCommitment *Commitment) bool { - // if the commitment is orphaned, we exit early - if isOrphaned { - return true + if currentChain != nil && currentChain != parentChain { + currentChain.IsEvicted.Trigger() } - // If the parent was evicted and the current commitment is not root, it is marked as orphaned. - if isParentEvicted && !isRoot && rootCommitment.Slot() <= c.Slot() { - return true - } - - // As a last resort, inherit the orphaned flag from the parent. - return isParentOrphaned - }, parent.IsOrphaned, parent.IsEvicted, c.IsRoot, c.commitments.Root)) + return parentChain + }, c.IsRoot, parent.MainChild, parent.Chain, c.Chain.Get())) } // deriveCumulativeAttestedWeight derives the CumulativeAttestedWeight of this Commitment which is the sum of the diff --git a/pkg/protocol/inspection.go b/pkg/protocol/inspection.go index f5f3c4924..109054315 100644 --- a/pkg/protocol/inspection.go +++ b/pkg/protocol/inspection.go @@ -23,9 +23,7 @@ func (c *Commitments) Inspect(session ...inspection.Session) inspection.Inspecte inspectCachedRequests = func(cachedRequests inspection.InspectedObject) { c.cachedRequests.ForEach(func(commitmentID iotago.CommitmentID, cachedRequest *promise.Promise[*Commitment]) bool { - if commitment := cachedRequest.Result(); commitment != nil { - cachedRequests.AddChild(commitmentID.String(), commitment) - } + cachedRequests.AddChild(commitmentID.String(), cachedRequest.Result()) return true }) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index e64fdb2fe..97b885e6e 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -429,8 +429,8 @@ func TestProtocol_EngineSwitching(t *testing.T) { } ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + // TODO: check that its not on the main chain + // ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) ts.AssertCommitmentsAndChainsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) } } @@ -749,8 +749,8 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + // TODO: check that its not on the main chain + // ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) ts.AssertCommitmentsAndChainsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) } diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index e1c0ab717..ad3810aa4 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -188,8 +188,8 @@ func (t *TestSuite) AssertCommitmentsOrphaned(expectedCommitments []*model.Commi return ierrors.Wrapf(err, "AssertCommitmentsOrphaned: %s: expected commitment %s not found", node.Name, expectedCommitment.ID()) } - if expectedOrphaned != commitment.IsOrphaned.Get() { - return ierrors.Errorf("AssertCommitmentsOrphaned: %s: expected commitment %s to be orphaned %t, got %t", node.Name, expectedCommitment.ID(), expectedOrphaned, commitment.IsOrphaned.Get()) + if chain := commitment.Chain.Get(); expectedOrphaned != (chain == nil || chain.IsEvicted.Get()) { + return ierrors.Errorf("AssertCommitmentsOrphaned: %s: expected commitment %s to be orphaned %t, got %t", node.Name, expectedCommitment.ID(), expectedOrphaned, chain == nil || chain.IsEvicted.Get()) } } From e73715c67a0d80f999faf3d7db99b74e44fc8b5a Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:42:22 +0100 Subject: [PATCH 35/49] Improve engine switching tests. --- pkg/tests/protocol_engine_switching_test.go | 162 +++++++------------- pkg/testsuite/chains.go | 16 ++ pkg/testsuite/fork.go | 16 ++ 3 files changed, 84 insertions(+), 110 deletions(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 48d7c1be4..39cc6ead5 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -2,17 +2,16 @@ package tests import ( "bytes" - "context" "fmt" + "slices" "strconv" - "sync" "testing" "time" "github.com/iotaledger/hive.go/core/eventticker" "github.com/iotaledger/hive.go/ds" + "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/log" "github.com/iotaledger/hive.go/runtime/module" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/core/account" @@ -71,7 +70,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { node8 := ts.AddNode("node8") ts.AddDefaultWallet(node0) - const expectedCommittedSlotAfterPartitionMerge = 18 + const expectedCommittedSlotAfterPartitionMerge = 19 nodesP1 := []*mock.Node{node0, node1, node2, node3, node4, node5} nodesP2 := []*mock.Node{node6, node7, node8} @@ -120,9 +119,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { } ts.Run(false, nodeOptions) - ts.Node("node6").Protocol.SetLogLevel(log.LevelTrace) - ts.Node("node6").Protocol.Engines.Main.Get().SetLogLevel(log.LevelDebug) - ts.Node("node6").Protocol.Blocks.SetLogLevel(log.LevelDebug) + expectedCommittee := []iotago.AccountID{ node0.Validator.AccountID, node1.Validator.AccountID, @@ -349,40 +346,25 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertStrongTips(tipBlocks, nodesP2...) } - for _, node := range ts.Nodes() { - manualPOA := node.Protocol.Engines.Main.Get().SybilProtection.SeatManager().(*mock2.ManualPOA) - manualPOA.SetOnline("node0", "node1", "node2", "node3", "node4", "node6", "node7") - } // Merge the partitions { ts.MergePartitionsToMain() fmt.Println("\n=========================\nMerged network partitions\n=========================") - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - ctxP1, ctxP1Cancel := context.WithCancel(ctx) - ctxP2, ctxP2Cancel := context.WithCancel(ctx) - - wg := &sync.WaitGroup{} - // Issue blocks on both partitions after merging the networks. - node0.Validator.IssueActivity(ctxP1, wg, 21, node0) - node1.Validator.IssueActivity(ctxP1, wg, 21, node1) - node2.Validator.IssueActivity(ctxP1, wg, 21, node2) - node3.Validator.IssueActivity(ctxP1, wg, 21, node3) - node4.Validator.IssueActivity(ctxP1, wg, 21, node4) - // node5.Validator.IssueActivity(ctxP1, wg, 21, node5) - - node6.Validator.IssueActivity(ctxP2, wg, 21, node6) - node7.Validator.IssueActivity(ctxP2, wg, 21, node7) - // node8.Validator.IssueActivity(ctxP2, wg, 21, node8) + ts.IssueBlocksAtSlots("P2-merge:", []iotago.SlotIndex{20, 21}, 4, "P2:20.3", nodesP2[:len(nodesP2)-1], true, true) // P1 finalized until slot 18. We do not expect any forks here because our CW is higher than the other partition's. ts.AssertForkDetectedCount(0, nodesP1...) // P1's chain is heavier, they should not consider switching the chain. ts.AssertCandidateEngineActivatedCount(0, nodesP1...) - ctxP2Cancel() // we can stop issuing on P2. + + for _, node := range ts.Nodes() { + manualPOA := node.Protocol.Engines.Main.Get().SybilProtection.SeatManager().(*mock2.ManualPOA) + manualPOA.SetOnline("node0", "node1", "node2", "node3", "node4", "node6", "node7") + } + + ts.IssueBlocksAtSlots("P1-merge:", []iotago.SlotIndex{20, 21, 22}, 4, "P1:20.3", nodesP1[:len(nodesP1)-1], true, true) // Nodes from P2 should switch the chain. ts.AssertForkDetectedCount(1, nodesP2...) @@ -390,9 +372,6 @@ func TestProtocol_EngineSwitching(t *testing.T) { // Here we need to let enough time pass for the nodes to sync up the candidate engines and switch them ts.AssertMainEngineSwitchedCount(1, nodesP2...) - - ctxP1Cancel() - wg.Wait() } // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. @@ -406,25 +385,21 @@ func TestProtocol_EngineSwitching(t *testing.T) { // Assert Protocol.Chains and Protocol.Commitments state. { - oldestNonEvictedCommitment := node0.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + oldestNonEvictedCommitment := iotago.SlotIndex(15) ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { return commitment.Slot() >= oldestNonEvictedCommitment }) - ts.AssertFinalizedCommitmentAtLeastSlotIndex(14+maxCommittableAge, ts.Nodes()...) + ts.AssertLatestFinalizedSlot(19, ts.Nodes()...) commitmentsMainChain := ts.CommitmentsOfMainEngine(nodesP1[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) + ts.AssertMainChain(ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - // When the test is slow on the CI, the eviction of a commitment might be delayed, so here we account for that. - if oldestNonEvictedCommitment >= 14 { - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - } else { - ts.AssertCommitmentsOrphaned(commitmentsMainChain, true, ts.Nodes()...) - } + ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // EmptyCommitmentID as ChainID means that the chain on those commitments should be set to nil. @@ -466,7 +441,7 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { node2 := ts.AddValidatorNode("node2") node3 := ts.AddValidatorNode("node3") - const expectedCommittedSlotAfterPartitionMerge = 18 + const expectedCommittedSlotAfterPartitionMerge = 19 nodesP1 := []*mock.Node{node0, node1, node2} nodesP2 := []*mock.Node{node3} @@ -500,10 +475,6 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { "node3": nodeOpts, }) - ts.Node("node0").Protocol.SetLogLevel(log.LevelTrace) - ts.Node("node0").Protocol.Engines.Main.Get().SetLogLevel(log.LevelDebug) - ts.Node("node0").Protocol.Blocks.SetLogLevel(log.LevelDebug) - // Verify that nodes have the expected states after startup. { genesisCommitment := iotago.NewEmptyCommitment(ts.API) @@ -668,26 +639,14 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.MergePartitionsToMain() fmt.Println("\n=========================\nMerged network partitions\n=========================") - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - ctxP1, ctxP1Cancel := context.WithCancel(ctx) - ctxP2, ctxP2Cancel := context.WithCancel(ctx) - - wg := &sync.WaitGroup{} - - // Issue blocks on both partitions after merging the networks. - node0.Validator.IssueActivity(ctxP1, wg, 21, node0) - node1.Validator.IssueActivity(ctxP1, wg, 21, node1) - node2.Validator.IssueActivity(ctxP1, wg, 21, node2) - - node3.Validator.IssueActivity(ctxP2, wg, 21, node3) + ts.IssueBlocksAtSlots("P2-merge:", []iotago.SlotIndex{20, 21}, 4, "P2:20.3", nodesP2, true, true) // P1 finalized until slot 16. We do not expect any forks here because our CW is higher than the other partition's. ts.AssertForkDetectedCount(0, nodesP1...) // P1's chain is heavier, they should not consider switching the chain. ts.AssertCandidateEngineActivatedCount(0, nodesP1...) - ctxP2Cancel() // we can stop issuing on P2. + + ts.IssueBlocksAtSlots("P1-merge:", []iotago.SlotIndex{20, 21, 22}, 4, "P1:20.3", nodesP1, true, true) // Nodes from P2 should switch the chain. ts.AssertForkDetectedCount(1, nodesP2...) @@ -697,10 +656,10 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertMainEngineSwitchedCount(1, nodesP2...) // Make sure that enough activity messages are issued so that a block in slot 21 gets accepted and triggers commitment of slot 18. - time.Sleep(3 * time.Second) + //time.Sleep(3 * time.Second) - ctxP1Cancel() - wg.Wait() + //ctxP1Cancel() + //wg.Wait() } // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. @@ -778,7 +737,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ), ), - testsuite.WithWaitFor(60*time.Second), + testsuite.WithWaitFor(15*time.Second), ) defer ts.Shutdown() @@ -851,9 +810,6 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.Run(false, nodesOptions) - nodes[0].Protocol.SetLogLevel(log.LevelTrace) - nodes[1].Protocol.SetLogLevel(log.LevelTrace) - expectedCommittee := []iotago.AccountID{nodes[0].Validator.AccountID, nodes[1].Validator.AccountID, nodes[2].Validator.AccountID} seatIndexes := []account.SeatIndex{ @@ -1029,6 +985,13 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { var mainPartition []*mock.Node var otherPartitions []*mock.Node + + partitionsInOrder := []*types.Tuple[int, *model.Commitment]{types.NewTuple(1, commitment140), types.NewTuple(2, commitment141), types.NewTuple(3, commitment142)} + slices.SortFunc(partitionsInOrder, func(a, b *types.Tuple[int, *model.Commitment]) int { + return bytes.Compare(lo.PanicOnErr(a.B.ID().Bytes()), lo.PanicOnErr(b.B.ID().Bytes())) + }) + fmt.Println(partitionsInOrder) + switch commitmentWithLargestID(commitment140, commitment141, commitment142) { case commitment140: mainPartition = nodes[0:1] @@ -1060,32 +1023,19 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { // Make sure the nodes switch their engines. { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - ctxP1, ctxP1Cancel := context.WithCancel(ctx) - ctxP2, ctxP2Cancel := context.WithCancel(ctx) - ctxP3, ctxP3Cancel := context.WithCancel(ctx) - - wg := &sync.WaitGroup{} - - // Issue blocks on all partitions after merging the networks. - nodes[0].Validator.IssueActivity(ctxP1, wg, 21, nodes[0]) - nodes[1].Validator.IssueActivity(ctxP2, wg, 21, nodes[1]) - nodes[2].Validator.IssueActivity(ctxP3, wg, 21, nodes[2]) + // We need to issue in order, so that after merging the network we issue from the lowest partition, + // to make sure that the two losing nodes don't switch engines before they learn about the partition that should win in the end. + for _, partition := range partitionsInOrder { + // Tuple contains partition index. + ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partition.A), []iotago.SlotIndex{20}, 1, slotPrefix(partition.A, 20)+strconv.Itoa(20)+".3", nodes[partition.A-1:partition.A], false, true) + } ts.AssertMainEngineSwitchedCount(0, mainPartition...) - ts.AssertMainEngineSwitchedCount(1, otherPartitions...) - - ctxP1Cancel() - ctxP2Cancel() - ctxP3Cancel() - wg.Wait() - + ts.AssertMainEngineSwitchedCountGreaterEqualThan(1, otherPartitions...) ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) } - oldestNonEvictedCommitment := mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + oldestNonEvictedCommitment := iotago.SlotIndex(6) commitmentsMainChain = ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { @@ -1097,6 +1047,10 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { { ts.AssertUniqueCommitmentChain(ts.Nodes()...) + + ts.AssertMainChain(ts.CommitmentOfMainEngine(mainPartition[0], 6).ID(), mainPartition...) + ts.AssertMainChain(ts.CommitmentOfMainEngine(mainPartition[0], forkingSlot).ID(), otherPartitions...) + ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) // We have not evicted the slot below the forking point, so chains are not yet orphaned. @@ -1129,38 +1083,26 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) } + fmt.Println("---------------------") // Finalize further slot and make sure the nodes have the same state of chains. { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - ctxP1, ctxP1Cancel := context.WithCancel(ctx) - ctxP2, ctxP2Cancel := context.WithCancel(ctx) - ctxP3, ctxP3Cancel := context.WithCancel(ctx) + //ts.CommitUntilSlot(forkingSlot+maxCommittableAge+2, ts.BlockIDsWithPrefix(fmt.Sprintf("P%d-merge:", mainPartitionIndex))...) - wg := &sync.WaitGroup{} + ts.IssueBlocksAtSlots("P0-merge:", []iotago.SlotIndex{20, 21, 22}, 3, slotPrefix(partitionsInOrder[len(partitionsInOrder)-1].A, 20)+strconv.Itoa(20)+".2", ts.Nodes(), true, true) - // Issue blocks on all partitions after merging the networks. - nodes[0].Validator.IssueActivity(ctxP1, wg, nodes[0].Protocol.Engines.Main.Get().Storage.Settings().LatestStoredSlot()+1, nodes[0]) - nodes[1].Validator.IssueActivity(ctxP2, wg, nodes[1].Protocol.Engines.Main.Get().Storage.Settings().LatestStoredSlot()+1, nodes[1]) - nodes[2].Validator.IssueActivity(ctxP3, wg, nodes[2].Protocol.Engines.Main.Get().Storage.Settings().LatestStoredSlot()+1, nodes[2]) + oldestNonEvictedCommitment = 19 - maxCommittableAge + commitmentsMainChain = ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, 20) - ts.AssertFinalizedCommitmentAtLeastSlotIndex(forkingSlot+maxCommittableAge+1, ts.Nodes()...) + ts.AssertLatestFinalizedSlot(19, ts.Nodes()...) - ctxP1Cancel() - ctxP2Cancel() - ctxP3Cancel() - wg.Wait() - - oldestNonEvictedCommitment = mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge - commitmentsMainChain = ts.CommitmentsOfMainEngine(mainPartition[0], oldestNonEvictedCommitment, mainPartition[0].Protocol.Engines.Main.Get().SyncManager.LatestCommitment().Slot()) + ts.AssertMainChain(ts.CommitmentOfMainEngine(mainPartition[0], forkingSlot+1).ID(), ts.Nodes()...) ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsAndChainsEvicted(forkingSlot+1, ts.Nodes()...) + ts.AssertCommitmentsAndChainsEvicted(forkingSlot, ts.Nodes()...) ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) + ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[len(mainPartition)-1], oldestNonEvictedCommitment).ID(), mainPartition...) // The oldest commitment is in the slices are should already be evicted, so we only need to check the newer ones. ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2[2:], true, ts.Nodes()...) diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index e1c0ab717..cc1680273 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -197,3 +197,19 @@ func (t *TestSuite) AssertCommitmentsOrphaned(expectedCommitments []*model.Commi }) } } + +func (t *TestSuite) AssertMainChain(expectedChainID iotago.CommitmentID, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + mainChainID := node.Protocol.Chains.Main.Get().ForkingPoint.Get().ID() + + if mainChainID != expectedChainID { + return ierrors.Errorf("AssertMainChain: %s: expected main chain to be %s, got %s", node.Name, expectedChainID, mainChainID) + } + + return nil + }) + } +} diff --git a/pkg/testsuite/fork.go b/pkg/testsuite/fork.go index 74d134a42..1fb4f55d7 100644 --- a/pkg/testsuite/fork.go +++ b/pkg/testsuite/fork.go @@ -52,3 +52,19 @@ func (t *TestSuite) AssertMainEngineSwitchedCount(expectedCount int, nodes ...*m }) } } + +func (t *TestSuite) AssertMainEngineSwitchedCountGreaterEqualThan(expectedCount int, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + + actualCount := node.MainEngineSwitchedCount() + if expectedCount <= actualCount { + return ierrors.Errorf("AssertMainEngineSwitchedCountGreaterEqualThan: %s: expected at least %v, got %v", node.Name, expectedCount, actualCount) + } + + return nil + }) + } +} From a7a9d329dff003f4bb95d49236c0fd8ecb289cea Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:39:12 +0100 Subject: [PATCH 36/49] Feat: evict child chains --- pkg/protocol/chain.go | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index d21fdd7da..8cbdee250 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -192,16 +192,35 @@ 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()) { + markChainEvicted := func() { + // TODO: MOVE TO DEDICATED WORKER + go c.IsEvicted.Trigger() + } + return lo.Batch( c.deriveWarpSyncMode(), c.ForkingPoint.WithValue(func(forkingPoint *Commitment) (teardown func()) { return lo.Batch( + func() (teardown func()) { + if forkingPoint == nil { + return + } + + return forkingPoint.IsEvicted.OnTrigger(markChainEvicted) + }(), + c.deriveParentChain(forkingPoint), - c.deriveIsEvicted(forkingPoint), ) }), - c.ParentChain.WithNonEmptyValue(lo.Bind(c, (*Chain).deriveChildChains)), + + c.ParentChain.WithNonEmptyValue(func(parent *Chain) (teardown func()) { + return lo.Batch( + parent.IsEvicted.OnTrigger(markChainEvicted), + + parent.deriveChildChains(c), + ) + }), c.Engine.WithNonEmptyValue(c.deriveOutOfSyncThreshold), ) } @@ -252,26 +271,6 @@ func (c *Chain) deriveParentChain(forkingPoint *Commitment) (shutdown func()) { return nil } -func (c *Chain) deriveIsEvicted(forkingPoint *Commitment) (shutdown func()) { - if forkingPoint == nil { - return - } - - // TODO: this might be cleaner but deadlocks - // return c.IsEvicted.DeriveValueFrom(reactive.NewDerivedVariable2(func(currentValue bool, forkingPointIsOrphaned bool, forkingPointIsEvicted bool) bool { - // if currentValue { - // return true - // } - // - // return forkingPointIsOrphaned || forkingPointIsEvicted - // }, forkingPoint.IsOrphaned, forkingPoint.IsEvicted)) - - return forkingPoint.IsEvicted.OnTrigger(func() { - // TODO: MOVE TO DEDICATED WORKER - go c.IsEvicted.Trigger() - }) -} - // deriveOutOfSyncThreshold defines how a chain determines its "out of sync" threshold (the latest seen slot minus 2 // times the max committable age or 0 if this would cause an overflow to the negative numbers). func (c *Chain) deriveOutOfSyncThreshold(engineInstance *engine.Engine) func() { From e3d016b8234c5ef5aad29589613c7b3e807f8b21 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:49:48 +0100 Subject: [PATCH 37/49] Make tie test predictable. --- pkg/tests/protocol_engine_switching_test.go | 50 ++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 39cc6ead5..a320b47ba 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -990,22 +990,12 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { slices.SortFunc(partitionsInOrder, func(a, b *types.Tuple[int, *model.Commitment]) int { return bytes.Compare(lo.PanicOnErr(a.B.ID().Bytes()), lo.PanicOnErr(b.B.ID().Bytes())) }) - fmt.Println(partitionsInOrder) - - switch commitmentWithLargestID(commitment140, commitment141, commitment142) { - case commitment140: - mainPartition = nodes[0:1] - otherPartitions = []*mock.Node{nodes[1], nodes[2]} - case commitment141: - mainPartition = nodes[1:2] - otherPartitions = []*mock.Node{nodes[0], nodes[2]} - case commitment142: - mainPartition = nodes[2:3] - otherPartitions = []*mock.Node{nodes[0], nodes[1]} - } - engineCommitmentsP2 := ts.CommitmentsOfMainEngine(otherPartitions[0], lastCommonSlot+1, 18) - engineCommitmentsP3 := ts.CommitmentsOfMainEngine(otherPartitions[1], lastCommonSlot+1, 18) + mainPartition = nodes[partitionsInOrder[2].A-1 : partitionsInOrder[2].A] + otherPartitions = []*mock.Node{nodes[partitionsInOrder[0].A-1], nodes[partitionsInOrder[1].A-1]} + + engineCommitmentsP2 := ts.CommitmentsOfMainEngine(otherPartitions[1], lastCommonSlot+1, 18) + engineCommitmentsP3 := ts.CommitmentsOfMainEngine(otherPartitions[0], lastCommonSlot+1, 18) // Merge the partitions { @@ -1023,15 +1013,23 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { // Make sure the nodes switch their engines. { - // We need to issue in order, so that after merging the network we issue from the lowest partition, - // to make sure that the two losing nodes don't switch engines before they learn about the partition that should win in the end. - for _, partition := range partitionsInOrder { - // Tuple contains partition index. - ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partition.A), []iotago.SlotIndex{20}, 1, slotPrefix(partition.A, 20)+strconv.Itoa(20)+".3", nodes[partition.A-1:partition.A], false, true) - } + ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partitionsInOrder[0].A), []iotago.SlotIndex{20}, 1, slotPrefix(partitionsInOrder[0].A, 20)+strconv.Itoa(20)+".3", nodes[partitionsInOrder[0].A-1:partitionsInOrder[0].A], true, true) + ts.AssertCommitmentsOnChain(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) + + ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partitionsInOrder[1].A), []iotago.SlotIndex{20}, 1, slotPrefix(partitionsInOrder[1].A, 20)+strconv.Itoa(20)+".3", nodes[partitionsInOrder[1].A-1:partitionsInOrder[1].A], true, true) + ts.AssertMainEngineSwitchedCount(1, otherPartitions[0]) + ts.AssertCommitmentsOnChain(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) + ts.AssertCommitmentsOnChain(engineCommitmentsP2, engineCommitmentsP2[0].ID(), mainPartition[0], otherPartitions[0]) + + ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partitionsInOrder[2].A), []iotago.SlotIndex{20}, 1, slotPrefix(partitionsInOrder[2].A, 20)+strconv.Itoa(20)+".3", nodes[partitionsInOrder[2].A-1:partitionsInOrder[2].A], true, true) + ts.AssertCommitmentsOnChain(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) + ts.AssertCommitmentsOnChain(engineCommitmentsP2, engineCommitmentsP2[0].ID(), mainPartition[0], otherPartitions[0]) + ts.AssertCommitmentsOnChain(commitmentsMainChain, commitmentsMainChain[0].ID(), otherPartitions...) ts.AssertMainEngineSwitchedCount(0, mainPartition...) - ts.AssertMainEngineSwitchedCountGreaterEqualThan(1, otherPartitions...) + ts.AssertMainEngineSwitchedCount(2, otherPartitions[0]) + ts.AssertMainEngineSwitchedCount(1, otherPartitions[1]) + ts.AssertEqualStoredCommitmentAtIndex(expectedCommittedSlotAfterPartitionMerge, ts.Nodes()...) } @@ -1069,16 +1067,16 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), mainPartition...) // P2 commitments on P2 node should be on the old chain, that is not the main chain anymore. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) // P2 commitments on P3 node should be on separate chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[1]) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[0]) // P3 commitments on the main partition should be on its own chain. ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), mainPartition...) // P3 commitments on P3 node should be on the old chain, that is not the main chain anymore. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) // P3 commitments on P2 node should be on separate chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[0]) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[1]) ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) } From 1a11f10a69e933208417520137caa410f6683443 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:07:48 +0100 Subject: [PATCH 38/49] Fix: commented out recursive chain eviction --- pkg/protocol/chain.go | 2 +- pkg/protocol/inspection.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index edcf485e6..c54383789 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -216,7 +216,7 @@ func (c *Chain) initDerivedProperties() (shutdown func()) { c.ParentChain.WithNonEmptyValue(func(parent *Chain) (teardown func()) { return lo.Batch( - parent.IsEvicted.OnTrigger(markChainEvicted), + //parent.IsEvicted.OnTrigger(markChainEvicted), parent.deriveChildChains(c), ) diff --git a/pkg/protocol/inspection.go b/pkg/protocol/inspection.go index 109054315..9b656b20a 100644 --- a/pkg/protocol/inspection.go +++ b/pkg/protocol/inspection.go @@ -60,6 +60,10 @@ func (c *Chains) Inspect(session ...inspection.Session) inspection.InspectedObje return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { o.AddChild("Set", c.Set, inspectSet) + o.AddChild("Main", c.Main.Get()) + o.AddChild("HeaviestClaimedCandidate", c.HeaviestClaimedCandidate.Get()) + o.AddChild("HeaviestAttestedCandidate", c.HeaviestAttestedCandidate.Get()) + o.AddChild("HeaviestAttestedCandidate", c.HeaviestAttestedCandidate.Get()) }, session...) } From 381be38aa86ee0936f038f974437c4b03bc71bae Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:39:17 +0100 Subject: [PATCH 39/49] Feat: changed order of inspected elements --- pkg/protocol/inspection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/protocol/inspection.go b/pkg/protocol/inspection.go index 9b656b20a..a273fa36f 100644 --- a/pkg/protocol/inspection.go +++ b/pkg/protocol/inspection.go @@ -59,11 +59,11 @@ func (c *Chains) Inspect(session ...inspection.Session) inspection.InspectedObje } return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { - o.AddChild("Set", c.Set, inspectSet) o.AddChild("Main", c.Main.Get()) o.AddChild("HeaviestClaimedCandidate", c.HeaviestClaimedCandidate.Get()) o.AddChild("HeaviestAttestedCandidate", c.HeaviestAttestedCandidate.Get()) o.AddChild("HeaviestAttestedCandidate", c.HeaviestAttestedCandidate.Get()) + o.AddChild("Set", c.Set, inspectSet) }, session...) } From e2126a5a96be0844de879f3ae2583a5c9a16da17 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:02:15 +0100 Subject: [PATCH 40/49] Fix: fixed bug --- pkg/testsuite/chains.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index dac6b9154..27ce806fb 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -38,7 +38,7 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit t.Eventually(func() error { var selectedChain *protocol.Chain _ = node.Protocol.Chains.Set.ForEach(func(chain *protocol.Chain) error { - if chain.ForkingPoint.Get().ID() == chainID { + if forkingPoint := chain.ForkingPoint.Get(); forkingPoint != nil && forkingPoint.ID() == chainID { selectedChain = chain } From 9d4d8d3fdf15a8a872f96d39a6b0e252716da89a Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 23:17:41 +0100 Subject: [PATCH 41/49] Feat: simplified child management --- pkg/protocol/commitment.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 151255225..733b9f55a 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -247,9 +247,9 @@ func (c *Commitment) initDerivedProperties() (shutdown func()) { c.CumulativeWeight.Set(c.Commitment.CumulativeWeight()) } - return lo.BatchReverse( - parent.deriveChildren(c), + parent.registerChild(c) + return lo.BatchReverse( c.deriveChain(parent), c.deriveCumulativeAttestedWeight(parent), @@ -278,8 +278,9 @@ func (c *Commitment) initDerivedProperties() (shutdown func()) { ) } -// deriveChildren derives the children of this Commitment by adding the given child to the Children set. -func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) { +// registerChild adds the given Commitment as a child of this Commitment and sets it as the main child if it is the +// first child of this Commitment. +func (c *Commitment) registerChild(child *Commitment) { c.MainChild.Compute(func(mainChild *Commitment) *Commitment { if !c.Children.Add(child) || mainChild != nil { return mainChild @@ -287,17 +288,6 @@ func (c *Commitment) deriveChildren(child *Commitment) (unregisterChild func()) return child }) - - return func() { - c.MainChild.Compute(func(mainChild *Commitment) *Commitment { - if !c.Children.Delete(child) || child != mainChild { - return mainChild - } - - // When removing the commitment, we need to set the main child back to nil when cleaning up children to avoid inconsistent state with MainChild being set to a random value, which then triggers other reactive events. - return nil - }) - } } // deriveChain derives the Chain of this Commitment which is either inherited from the parent if we are the main child From 317f63a76573d52680ac26f99602a84a0d090a65 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Tue, 27 Feb 2024 23:32:15 +0100 Subject: [PATCH 42/49] Refactor: removed unused code --- pkg/protocol/commitments.go | 6 +----- pkg/testsuite/fork.go | 16 ---------------- pkg/testsuite/storage_settings.go | 19 ------------------- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/pkg/protocol/commitments.go b/pkg/protocol/commitments.go index e1945f87a..a9d0c1763 100644 --- a/pkg/protocol/commitments.go +++ b/pkg/protocol/commitments.go @@ -276,11 +276,7 @@ func (c *Commitments) initCommitment(commitment *Commitment, slotEvicted reactiv // solidify the parent of the commitment if root := c.Root.Get(); root != nil && commitment.Slot() > root.Slot() { c.cachedRequest(commitment.PreviousCommitmentID(), true).OnSuccess(func(parent *Commitment) { - commitment.Parent.Set(parent) - - parent.IsEvicted.OnTrigger(func() { - commitment.Parent.Set(nil) - }) + parent.IsEvicted.OnTrigger(commitment.Parent.ToggleValue(parent)) }) } diff --git a/pkg/testsuite/fork.go b/pkg/testsuite/fork.go index 1fb4f55d7..74d134a42 100644 --- a/pkg/testsuite/fork.go +++ b/pkg/testsuite/fork.go @@ -52,19 +52,3 @@ func (t *TestSuite) AssertMainEngineSwitchedCount(expectedCount int, nodes ...*m }) } } - -func (t *TestSuite) AssertMainEngineSwitchedCountGreaterEqualThan(expectedCount int, nodes ...*mock.Node) { - mustNodes(nodes) - - for _, node := range nodes { - t.Eventually(func() error { - - actualCount := node.MainEngineSwitchedCount() - if expectedCount <= actualCount { - return ierrors.Errorf("AssertMainEngineSwitchedCountGreaterEqualThan: %s: expected at least %v, got %v", node.Name, expectedCount, actualCount) - } - - return nil - }) - } -} diff --git a/pkg/testsuite/storage_settings.go b/pkg/testsuite/storage_settings.go index 4459e71d2..230a85bc1 100644 --- a/pkg/testsuite/storage_settings.go +++ b/pkg/testsuite/storage_settings.go @@ -95,25 +95,6 @@ func (t *TestSuite) AssertLatestCommitmentSlotIndex(slot iotago.SlotIndex, nodes } } -func (t *TestSuite) AssertFinalizedCommitmentAtLeastSlotIndex(slot iotago.SlotIndex, nodes ...*mock.Node) { - mustNodes(nodes) - - for _, node := range nodes { - t.Eventually(func() error { - latestFinalizedSlotSettings := node.Protocol.Engines.Main.Get().Storage.Settings().LatestFinalizedSlot() - if slot > latestFinalizedSlotSettings { - return ierrors.Errorf("AssertFinalizedCommitmentAtLeastSlotIndex: %s: expected at least %v, got %v in settings", node.Name, slot, latestFinalizedSlotSettings) - } - latestFinalizedSlotSyncManager := node.Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - if slot > latestFinalizedSlotSyncManager { - return ierrors.Errorf("AssertFinalizedCommitmentAtLeastSlotIndex: %s: expected at least %v, got %v in sync manager", node.Name, slot, latestFinalizedSlotSyncManager) - } - - return nil - }) - } -} - func (t *TestSuite) AssertLatestCommitmentCumulativeWeight(cw uint64, nodes ...*mock.Node) { mustNodes(nodes) From 6000f06f58acf1703217499db9d22c31a20265a7 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:16:46 +0100 Subject: [PATCH 43/49] Feat: more cleanup --- pkg/protocol/chain.go | 16 +++++------ pkg/tests/protocol_engine_switching_test.go | 30 ++++++++++----------- pkg/testsuite/chains.go | 6 ++--- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index c54383789..c62e0adb6 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -239,16 +239,16 @@ func (c *Chain) deriveWarpSyncMode() func() { } // deriveChildChains defines how a chain determines its ChildChains (by adding each child to the set). -func (c *Chain) deriveChildChains(child *Chain) func() { - if child == c { - return nil - } - - c.ChildChains.Add(child) +func (c *Chain) deriveChildChains(child *Chain) (teardown func()) { + if child != c { + c.ChildChains.Add(child) - return func() { - c.ChildChains.Delete(child) + teardown = func() { + c.ChildChains.Delete(child) + } } + + return } // deriveParentChain defines how a chain determines its parent chain from its forking point (it inherits the Chain from diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index dece191ce..d58039dc9 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -271,7 +271,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), ts.CommitmentOfMainEngine(nodesP1[0], 13).ID(), nodesP1...) - ts.AssertCommitmentsOrphaned(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), false, nodesP1...) + ts.AssertCommitmentsOnEvictedChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), false, nodesP1...) ts.AssertCommitmentsAndChainsEvicted(12, nodesP1...) // Make sure the tips are properly set. @@ -303,7 +303,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(nodesP1[0], 6).ID(), nodesP2...) - ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) + ts.AssertCommitmentsOnEvictedChain(engineCommitmentsP2, false, nodesP2...) ts.AssertCommitmentsAndChainsEvicted(5, nodesP2...) for _, slot := range []iotago.SlotIndex{12, 13, 14, 15} { @@ -397,9 +397,9 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertMainChain(ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // TODO: check that its not on the main chain @@ -579,7 +579,7 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) ts.AssertCommitmentsOnChain(engineCommitmentsP1, ts.CommitmentOfMainEngine(node0, 12).ID(), nodesP1...) - ts.AssertCommitmentsOrphaned(engineCommitmentsP1, false, nodesP1...) + ts.AssertCommitmentsOnEvictedChain(engineCommitmentsP1, false, nodesP1...) ts.AssertCommitmentsAndChainsEvicted(11, nodesP1...) } @@ -630,7 +630,7 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 0).ID(), nodesP2...) - ts.AssertCommitmentsOrphaned(engineCommitmentsP2, false, nodesP2...) + ts.AssertCommitmentsOnEvictedChain(engineCommitmentsP2, false, nodesP2...) // We only finalized until slot 4, and maxCommittableAge=5. Thus, we don't expect any evictions on chains/commmitments yet. } @@ -703,8 +703,8 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { { ts.AssertUniqueCommitmentChain(ts.Nodes()...) ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP2, true, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) // TODO: check that its not on the main chain // ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) @@ -942,7 +942,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) commitmentsMainChain := ts.CommitmentsOfMainEngine(nodes[0], 6, 11) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(commitmentsMainChain, commitmentsMainChain[0].ID(), ts.Nodes()...) ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) @@ -1052,9 +1052,9 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) // We have not evicted the slot below the forking point, so chains are not yet orphaned. - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2, false, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP2, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP3, false, ts.Nodes()...) // The Main partition should have all commitments on the old chain, because it did not switch chains. ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) @@ -1099,12 +1099,12 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsAndChainsEvicted(forkingSlot, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(commitmentsMainChain, false, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[len(mainPartition)-1], oldestNonEvictedCommitment).ID(), mainPartition...) // The oldest commitment is in the slices are should already be evicted, so we only need to check the newer ones. - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP2[2:], true, ts.Nodes()...) - ts.AssertCommitmentsOrphaned(ultimateCommitmentsP3[2:], true, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP2[2:], true, ts.Nodes()...) + ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP3[2:], true, ts.Nodes()...) } } diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index 27ce806fb..7ab82e198 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -177,7 +177,7 @@ func (t *TestSuite) AssertCommitmentsAndChainsEvicted(expectedEvictedSlot iotago } } -func (t *TestSuite) AssertCommitmentsOrphaned(expectedCommitments []*model.Commitment, expectedOrphaned bool, nodes ...*mock.Node) { +func (t *TestSuite) AssertCommitmentsOnEvictedChain(expectedCommitments []*model.Commitment, expectedOrphaned bool, nodes ...*mock.Node) { mustNodes(nodes) for _, node := range nodes { @@ -185,11 +185,11 @@ func (t *TestSuite) AssertCommitmentsOrphaned(expectedCommitments []*model.Commi for _, expectedCommitment := range expectedCommitments { commitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) if err != nil { - return ierrors.Wrapf(err, "AssertCommitmentsOrphaned: %s: expected commitment %s not found", node.Name, expectedCommitment.ID()) + return ierrors.Wrapf(err, "AssertCommitmentsOnEvictedChain: %s: expected commitment %s not found", node.Name, expectedCommitment.ID()) } if chain := commitment.Chain.Get(); expectedOrphaned != (chain == nil || chain.IsEvicted.Get()) { - return ierrors.Errorf("AssertCommitmentsOrphaned: %s: expected commitment %s to be orphaned %t, got %t", node.Name, expectedCommitment.ID(), expectedOrphaned, chain == nil || chain.IsEvicted.Get()) + return ierrors.Errorf("AssertCommitmentsOnEvictedChain: %s: expected commitment %s to be on evicted chain %t, got %t", node.Name, expectedCommitment.ID(), expectedOrphaned, chain == nil || chain.IsEvicted.Get()) } } From 89b2499e24961097db8ee915c7f37682ca3ac1d3 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:44:13 +0100 Subject: [PATCH 44/49] Feat: clean up more --- pkg/core/inspection/inspected_object.go | 135 ------------------------ pkg/core/inspection/session.go | 15 --- pkg/protocol/inspection.go | 82 -------------- pkg/tests/protocol_eviction_test.go | 3 - 4 files changed, 235 deletions(-) delete mode 100644 pkg/core/inspection/inspected_object.go delete mode 100644 pkg/core/inspection/session.go delete mode 100644 pkg/protocol/inspection.go diff --git a/pkg/core/inspection/inspected_object.go b/pkg/core/inspection/inspected_object.go deleted file mode 100644 index 959ede39a..000000000 --- a/pkg/core/inspection/inspected_object.go +++ /dev/null @@ -1,135 +0,0 @@ -package inspection - -import ( - "fmt" - "regexp" - "strings" - "unicode" - - "github.com/iotaledger/hive.go/ds/orderedmap" - "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/stringify" -) - -// InspectedObject is an interface that is used to represent an object that has been inspected. -type InspectedObject interface { - // Type returns the type of the object. - Type() string - - // InstanceID returns the instance identifier of the object. - InstanceID() string - - // AddChild adds a child object to the inspected object. - AddChild(name string, instance any, inspectManually ...func(object InspectedObject)) - - // String returns a string representation of the inspected object. - String() string -} - -// NewInspectedObject creates a new inspected object from the given instance and inspect function. -func NewInspectedObject(instance any, inspect func(InspectedObject), session ...Session) InspectedObject { - o := &inspectedObject{ - instance: instance, - childObjects: orderedmap.New[string, InspectedObject](), - session: lo.First(session, make(Session)), - } - - if o.inspected = o.session.FirstOccurrence(instance); o.inspected { - inspect(o) - } - - return o -} - -// inspectedObject is an implementation of the InspectedObject interface. -type inspectedObject struct { - instance any - childObjects *orderedmap.OrderedMap[string, InspectedObject] - session Session - inspected bool -} - -// Type returns the type of the object. -func (i *inspectedObject) Type() string { - runes := []rune(regexp.MustCompile(`[^.]+\.([^[]+).*`).ReplaceAllString(fmt.Sprintf("%T", i.instance), "${1}")) - runes[0] = unicode.ToUpper(runes[0]) - - return string(runes) -} - -// InstanceID returns the instance identifier of the object. -func (i *inspectedObject) InstanceID() string { - type named interface { - LogName() string - } - - if namedInstance, isNamed := i.instance.(named); isNamed { - return namedInstance.LogName() - } - - return fmt.Sprintf("%p", i.instance) -} - -// AddChild adds a child object to the inspected object. -func (i *inspectedObject) AddChild(name string, instance any, inspectManually ...func(object InspectedObject)) { - type inspectable interface { - Inspect(session ...Session) InspectedObject - } - - if stringify.IsInterfaceNil(instance) { - i.childObjects.Set(name, nil) - } else if len(inspectManually) >= 1 { - i.childObjects.Set(name, NewInspectedObject(instance, inspectManually[0], i.session)) - } else if inspectableInstance, isInspectable := instance.(inspectable); isInspectable { - i.childObjects.Set(name, inspectableInstance.Inspect(i.session)) - } else { - panic("added object does not have an 'Inspect(session ...Session) InspectedObject' method - please provide a manual inspection function") - } -} - -// String returns a string representation of the inspected object. -func (i *inspectedObject) String() string { - return i.indentedString(0) -} - -// indentedString returns a string representation of the inspected object with the given indentation. -func (i *inspectedObject) indentedString(indent int) string { - if i == nil { - return "nil" - } - - var typeString string - if instanceID, typeName := i.InstanceID(), i.Type(); typeName == instanceID { - typeString = typeName - } else { - typeString = typeName + "(" + instanceID + ")" - } - - if !i.inspected { - return typeString + " {...}" - } - - childOutputs := make([]string, 0) - i.childObjects.ForEach(func(key string, value InspectedObject) bool { - if value == nil { - childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentationSize)+key+": nil") - } else if objectValue, ok := value.(*inspectedObject); !ok { - panic("this should never happen but linter requires type cast check") - } else if value.Type() == key || value.InstanceID() == key { - childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentationSize)+objectValue.indentedString(indent+1)) - } else { - childOutputs = append(childOutputs, strings.Repeat(" ", (indent+1)*indentationSize)+key+": "+objectValue.indentedString(indent+1)) - } - - return true - }) - - if len(childOutputs) == 0 { - return typeString + " {}" - } - - return typeString + " {\n" + strings.Join(childOutputs, ",\n") + "\n" + strings.Repeat(" ", (indent)*indentationSize) + "}" -} - -// indentationSize defines the size of the indentation. -const indentationSize = 2 diff --git a/pkg/core/inspection/session.go b/pkg/core/inspection/session.go deleted file mode 100644 index be03ae4f8..000000000 --- a/pkg/core/inspection/session.go +++ /dev/null @@ -1,15 +0,0 @@ -package inspection - -// Session is used to track instances of objects that have already been inspected. -type Session map[any]bool - -// FirstOccurrence checks if the given instance has already been inspected. -func (s Session) FirstOccurrence(instance any) bool { - if s[instance] { - return false - } - - s[instance] = true - - return true -} diff --git a/pkg/protocol/inspection.go b/pkg/protocol/inspection.go deleted file mode 100644 index a273fa36f..000000000 --- a/pkg/protocol/inspection.go +++ /dev/null @@ -1,82 +0,0 @@ -package protocol - -import ( - "github.com/iotaledger/iota-core/pkg/core/inspection" - "github.com/iotaledger/iota-core/pkg/core/promise" - iotago "github.com/iotaledger/iota.go/v4" -) - -func (p *Protocol) Inspect(session ...inspection.Session) inspection.InspectedObject { - return inspection.NewInspectedObject(p, func(o inspection.InspectedObject) { - o.AddChild("Commitments", p.Commitments) - o.AddChild("Chains", p.Chains) - }, session...) -} - -func (c *Commitments) Inspect(session ...inspection.Session) inspection.InspectedObject { - var ( - inspectSet = func(set inspection.InspectedObject) { - c.Range(func(commitment *Commitment) { - set.AddChild(commitment.LogName(), commitment) - }) - } - - inspectCachedRequests = func(cachedRequests inspection.InspectedObject) { - c.cachedRequests.ForEach(func(commitmentID iotago.CommitmentID, cachedRequest *promise.Promise[*Commitment]) bool { - cachedRequests.AddChild(commitmentID.String(), cachedRequest.Result()) - - return true - }) - } - ) - - return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { - o.AddChild("Set", c.Set, inspectSet) - o.AddChild("cachedRequests", c.cachedRequests, inspectCachedRequests) - }, session...) -} - -func (c *Commitment) Inspect(session ...inspection.Session) inspection.InspectedObject { - inspectChildren := func(children inspection.InspectedObject) { - c.Children.Range(func(child *Commitment) { - children.AddChild(child.LogName(), child) - }) - } - - return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { - o.AddChild("Parent", c.Parent.Get()) - o.AddChild("MainChild", c.MainChild.Get()) - o.AddChild("Chain", c.Chain.Get()) - o.AddChild("Children", c.Children, inspectChildren) - }, session...) -} - -func (c *Chains) Inspect(session ...inspection.Session) inspection.InspectedObject { - inspectSet := func(set inspection.InspectedObject) { - c.Set.Range(func(chain *Chain) { - set.AddChild(chain.LogName(), chain) - }) - } - - return inspection.NewInspectedObject(c, func(o inspection.InspectedObject) { - o.AddChild("Main", c.Main.Get()) - o.AddChild("HeaviestClaimedCandidate", c.HeaviestClaimedCandidate.Get()) - o.AddChild("HeaviestAttestedCandidate", c.HeaviestAttestedCandidate.Get()) - o.AddChild("HeaviestAttestedCandidate", c.HeaviestAttestedCandidate.Get()) - o.AddChild("Set", c.Set, inspectSet) - }, session...) -} - -func (c *Chain) Inspect(session ...inspection.Session) inspection.InspectedObject { - inspectChildChains := func(childChains inspection.InspectedObject) { - c.ChildChains.Range(func(childChain *Chain) { - childChains.AddChild(childChain.LogName(), childChain) - }) - } - - return inspection.NewInspectedObject(c, func(chain inspection.InspectedObject) { - chain.AddChild("ForkingPoint", c.ForkingPoint.Get()) - chain.AddChild("ParentChain", c.ParentChain.Get()) - chain.AddChild("ChildChains", c.ChildChains, inspectChildChains) - }, session...) -} diff --git a/pkg/tests/protocol_eviction_test.go b/pkg/tests/protocol_eviction_test.go index 7cfcc10ea..05cee7a73 100644 --- a/pkg/tests/protocol_eviction_test.go +++ b/pkg/tests/protocol_eviction_test.go @@ -1,7 +1,6 @@ package tests import ( - "fmt" "strconv" "testing" "time" @@ -181,13 +180,11 @@ func TestProtocol_Eviction(t *testing.T) { issueBlocksTill(8) memConsumptionStart := memsize.Scan(node.Protocol).Total - fmt.Println(node.Protocol.Inspect()) // issue more blocks issueBlocksTill(100) memConsumptionEnd := memsize.Scan(node.Protocol).Total - fmt.Println(node.Protocol.Inspect()) require.Less(t, float64(lo.Return1(memConsumptionEnd)), 1.05*float64(memConsumptionStart), "memory consumption should not grow by more than 5%") } From 2670f2b5e2ec012365ca864f92a6c8c54ad9d3ba Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:39:14 +0800 Subject: [PATCH 45/49] Rename AssertChainID to AssertMainChain and use corresponding method --- pkg/tests/confirmation_state_test.go | 2 +- pkg/tests/protocol_engine_rollback_test.go | 8 ++++---- pkg/tests/protocol_engine_switching_test.go | 14 +++++++------- pkg/tests/protocol_eviction_test.go | 2 +- pkg/testsuite/node_state.go | 10 +++++----- pkg/testsuite/storage_settings.go | 16 ---------------- 6 files changed, 18 insertions(+), 34 deletions(-) diff --git a/pkg/tests/confirmation_state_test.go b/pkg/tests/confirmation_state_test.go index 05e47eaa8..82bbb0e6d 100644 --- a/pkg/tests/confirmation_state_test.go +++ b/pkg/tests/confirmation_state_test.go @@ -79,7 +79,7 @@ func TestConfirmationFlags(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), testsuite.WithSybilProtectionOnlineCommittee(lo.Return1(lo.Return1(nodeA.Protocol.Engines.Main.Get().SybilProtection.SeatManager().CommitteeInSlot(1)).GetSeat(nodeA.Validator.AccountID))), diff --git a/pkg/tests/protocol_engine_rollback_test.go b/pkg/tests/protocol_engine_rollback_test.go index f3a3b1118..06daaa127 100644 --- a/pkg/tests/protocol_engine_rollback_test.go +++ b/pkg/tests/protocol_engine_rollback_test.go @@ -116,7 +116,7 @@ func TestProtocol_EngineRollbackFinalization(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), @@ -303,7 +303,7 @@ func TestProtocol_EngineRollbackNoFinalization(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), @@ -497,7 +497,7 @@ func TestProtocol_EngineRollbackNoFinalizationLastSlot(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), @@ -691,7 +691,7 @@ func TestProtocol_EngineRollbackNoFinalizationBeforePointOfNoReturn(t *testing.T testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index d58039dc9..395bde276 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -155,7 +155,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), @@ -484,7 +484,7 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, ts.AccountsOfNodes("node0", "node1", "node2", "node3")), @@ -656,10 +656,10 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertMainEngineSwitchedCount(1, nodesP2...) // Make sure that enough activity messages are issued so that a block in slot 21 gets accepted and triggers commitment of slot 18. - //time.Sleep(3 * time.Second) + // time.Sleep(3 * time.Second) - //ctxP1Cancel() - //wg.Wait() + // ctxP1Cancel() + // wg.Wait() } // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. @@ -831,7 +831,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), @@ -1084,7 +1084,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { fmt.Println("---------------------") // Finalize further slot and make sure the nodes have the same state of chains. { - //ts.CommitUntilSlot(forkingSlot+maxCommittableAge+2, ts.BlockIDsWithPrefix(fmt.Sprintf("P%d-merge:", mainPartitionIndex))...) + // ts.CommitUntilSlot(forkingSlot+maxCommittableAge+2, ts.BlockIDsWithPrefix(fmt.Sprintf("P%d-merge:", mainPartitionIndex))...) ts.IssueBlocksAtSlots("P0-merge:", []iotago.SlotIndex{20, 21, 22}, 3, slotPrefix(partitionsInOrder[len(partitionsInOrder)-1].A, 20)+strconv.Itoa(20)+".2", ts.Nodes(), true, true) diff --git a/pkg/tests/protocol_eviction_test.go b/pkg/tests/protocol_eviction_test.go index 05cee7a73..a5f0aac51 100644 --- a/pkg/tests/protocol_eviction_test.go +++ b/pkg/tests/protocol_eviction_test.go @@ -116,7 +116,7 @@ func TestProtocol_Eviction(t *testing.T) { testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestCommitment(genesisCommitment), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(genesisCommitment.MustID()), testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), testsuite.WithSybilProtectionCommittee(0, []iotago.AccountID{node.Validator.AccountID}), diff --git a/pkg/testsuite/node_state.go b/pkg/testsuite/node_state.go index c52e15242..4350d40e0 100644 --- a/pkg/testsuite/node_state.go +++ b/pkg/testsuite/node_state.go @@ -29,8 +29,8 @@ func (t *TestSuite) AssertNodeState(nodes []*mock.Node, opts ...options.Option[N if state.latestFinalizedSlot != nil { t.AssertLatestFinalizedSlot(*state.latestFinalizedSlot, nodes...) } - if state.chainID != nil { - t.AssertChainID(*state.chainID, nodes...) + if state.mainChainID != nil { + t.AssertMainChain(*state.mainChainID, nodes...) } if state.sybilProtectionCommitteeEpoch != nil && state.sybilProtectionCommittee != nil { t.AssertSybilProtectionCommittee(*state.sybilProtectionCommitteeEpoch, *state.sybilProtectionCommittee, nodes...) @@ -68,7 +68,7 @@ type NodeState struct { latestCommitmentSlot *iotago.SlotIndex latestCommitmentCumulativeWeight *uint64 latestFinalizedSlot *iotago.SlotIndex - chainID *iotago.CommitmentID + mainChainID *iotago.CommitmentID sybilProtectionCommitteeEpoch *iotago.EpochIndex sybilProtectionCommittee *[]iotago.AccountID @@ -129,9 +129,9 @@ func WithLatestFinalizedSlot(slot iotago.SlotIndex) options.Option[NodeState] { } } -func WithChainID(chainID iotago.CommitmentID) options.Option[NodeState] { +func WithMainChainID(chainID iotago.CommitmentID) options.Option[NodeState] { return func(state *NodeState) { - state.chainID = &chainID + state.mainChainID = &chainID } } diff --git a/pkg/testsuite/storage_settings.go b/pkg/testsuite/storage_settings.go index 230a85bc1..800933da9 100644 --- a/pkg/testsuite/storage_settings.go +++ b/pkg/testsuite/storage_settings.go @@ -126,19 +126,3 @@ func (t *TestSuite) AssertLatestFinalizedSlot(slot iotago.SlotIndex, nodes ...*m }) } } - -func (t *TestSuite) AssertChainID(expectedChainID iotago.CommitmentID, nodes ...*mock.Node) { - mustNodes(nodes) - - for _, node := range nodes { - t.Eventually(func() error { - actualChainID := node.Protocol.Chains.Main.Get().ForkingPoint.Get().ID() - - if expectedChainID != actualChainID { - return ierrors.Errorf("AssertChainID: %s: expected %s (index: %d), got %s (index: %d)", node.Name, expectedChainID, expectedChainID.Slot(), actualChainID, actualChainID.Slot()) - } - - return nil - }) - } -} From 6349eba83426baf07459957ddd1df8544c82eb21 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:40:18 +0800 Subject: [PATCH 46/49] Remove TODOs from Test_StartNodeFromSnapshotAndDisk --- pkg/tests/protocol_startup_test.go | 48 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/pkg/tests/protocol_startup_test.go b/pkg/tests/protocol_startup_test.go index 1a98bc3a8..346452614 100644 --- a/pkg/tests/protocol_startup_test.go +++ b/pkg/tests/protocol_startup_test.go @@ -22,10 +22,13 @@ import ( ) func Test_BookInCommittedSlot(t *testing.T) { + const maxCommittableAge = iotago.SlotIndex(4) + const genesisSlot = iotago.SlotIndex(0) + ts := testsuite.NewTestSuite(t, testsuite.WithProtocolParametersOptions( iotago.WithTimeProviderOptions( - 0, + genesisSlot, testsuite.GenesisTimeWithOffsetBySlots(1000, testsuite.DefaultSlotDurationInSeconds), testsuite.DefaultSlotDurationInSeconds, 3, @@ -34,7 +37,7 @@ func Test_BookInCommittedSlot(t *testing.T) { 10, 10, 2, - 4, + maxCommittableAge, 5, ), ), @@ -64,15 +67,14 @@ func Test_BookInCommittedSlot(t *testing.T) { } // Verify that nodes have the expected states. - genesisCommitment := iotago.NewEmptyCommitment(ts.API) - genesisCommitment.ReferenceManaCost = ts.API.ProtocolParameters().CongestionControlParameters().MinReferenceManaCost + genesisCommitment := ts.CommitmentOfMainEngine(nodeA, genesisSlot) ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithLatestCommitment(genesisCommitment), + testsuite.WithLatestCommitment(genesisCommitment.Commitment()), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), - testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), + testsuite.WithMainChainID(genesisCommitment.ID()), + testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment.Commitment()}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), testsuite.WithSybilProtectionOnlineCommittee(expectedOnlineCommittee...), testsuite.WithEvictedSlot(0), @@ -84,7 +86,7 @@ func Test_BookInCommittedSlot(t *testing.T) { // Epoch 0: issue 4 rows per slot. { - ts.IssueBlocksAtEpoch("", 0, 4, "Genesis", ts.Nodes(), true, false) + ts.IssueBlocksAtEpoch("", 0, 4, "Genesis", ts.Nodes(), true, true) ts.AssertBlocksExist(ts.BlocksWithPrefixes("1", "2", "3", "4", "5", "6", "7"), true, ts.Nodes()...) @@ -102,8 +104,8 @@ func Test_BookInCommittedSlot(t *testing.T) { ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - // TODO: remove this? the forking gets updated now on eviction - //testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithLatestFinalizedSlot(4), + testsuite.WithMainChainID(ts.CommitmentOfMainEngine(nodeA, 4-maxCommittableAge).ID()), testsuite.WithLatestCommitmentSlotIndex(5), testsuite.WithEvictedSlot(5), testsuite.WithActiveRootBlocks(expectedActiveRootBlocks), @@ -125,10 +127,13 @@ func Test_BookInCommittedSlot(t *testing.T) { } func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { + const maxCommittableAge = iotago.SlotIndex(4) + const genesisSlot = iotago.SlotIndex(0) + ts := testsuite.NewTestSuite(t, testsuite.WithProtocolParametersOptions( iotago.WithTimeProviderOptions( - 0, + genesisSlot, testsuite.GenesisTimeWithOffsetBySlots(1000, testsuite.DefaultSlotDurationInSeconds), testsuite.DefaultSlotDurationInSeconds, 3, @@ -137,7 +142,7 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { 10, 10, 2, - 4, + maxCommittableAge, 5, ), ), @@ -179,15 +184,14 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { } // Verify that nodes have the expected states. - genesisCommitment := iotago.NewEmptyCommitment(ts.API) - genesisCommitment.ReferenceManaCost = ts.API.ProtocolParameters().CongestionControlParameters().MinReferenceManaCost + genesisCommitment := ts.CommitmentOfMainEngine(nodeA, genesisSlot) ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithLatestCommitment(genesisCommitment), + testsuite.WithLatestCommitment(genesisCommitment.Commitment()), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithChainID(genesisCommitment.MustID()), - testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), + testsuite.WithMainChainID(genesisCommitment.ID()), + testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment.Commitment()}), testsuite.WithSybilProtectionCommittee(0, expectedCommittee), testsuite.WithSybilProtectionOnlineCommittee(expectedOnlineCommittee...), testsuite.WithEvictedSlot(0), @@ -223,7 +227,7 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(ts.CommitmentOfMainEngine(nodeA, 4-maxCommittableAge).ID()), testsuite.WithLatestFinalizedSlot(4), testsuite.WithLatestCommitmentSlotIndex(5), testsuite.WithEqualStoredCommitmentAtIndex(5), @@ -271,8 +275,7 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - // TODO: remove this? the forking gets updated now on eviction - //testsuite.WithChainID(genesisCommitment.MustID()), + testsuite.WithMainChainID(ts.CommitmentOfMainEngine(nodeA, 11-maxCommittableAge).ID()), testsuite.WithLatestFinalizedSlot(11), testsuite.WithLatestCommitmentSlotIndex(11), testsuite.WithEqualStoredCommitmentAtIndex(11), @@ -351,12 +354,10 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { ts.AssertStorageRootBlocks(expectedStorageRootBlocksFrom9, ts.Nodes("nodeD")...) } - slot7Commitment := lo.PanicOnErr(nodeA.Protocol.Engines.Main.Get().Storage.Commitments().Load(7)) - ts.AssertNodeState(ts.Nodes("nodeC-restarted", "nodeD"), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithChainID(slot7Commitment.ID()), + testsuite.WithMainChainID(ts.CommitmentOfMainEngine(nodeA, 11-maxCommittableAge).ID()), testsuite.WithLatestFinalizedSlot(11), testsuite.WithLatestCommitmentSlotIndex(11), testsuite.WithEqualStoredCommitmentAtIndex(11), @@ -414,6 +415,7 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), testsuite.WithLatestFinalizedSlot(36), + testsuite.WithMainChainID(ts.CommitmentOfMainEngine(nodeA, 36-maxCommittableAge).ID()), testsuite.WithLatestCommitmentSlotIndex(37), testsuite.WithEqualStoredCommitmentAtIndex(37), testsuite.WithLatestCommitmentCumulativeWeight(68), // 2 for each slot starting from 4 From c6b6b8024e976c0e76dd2b0fd722ec6a8949d718 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:17:07 +0800 Subject: [PATCH 47/49] AssertCommitmentsOnChain in TestProtocol_EngineSwitching and TestProtocol_EngineSwitching_CommitteeRotation --- pkg/tests/protocol_engine_switching_test.go | 91 +++++++++++---------- pkg/testsuite/chains.go | 44 ++++++++-- 2 files changed, 86 insertions(+), 49 deletions(-) diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index 395bde276..b5b3dcd40 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -270,7 +270,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { // Assert Protocol.Chains and Protocol.Commitments state. ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) - ts.AssertCommitmentsOnChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), ts.CommitmentOfMainEngine(nodesP1[0], 13).ID(), nodesP1...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), ts.CommitmentOfMainEngine(nodesP1[0], 13).ID(), nodesP1...) ts.AssertCommitmentsOnEvictedChain(ts.CommitmentsOfMainEngine(nodesP1[0], 13, 18), false, nodesP1...) ts.AssertCommitmentsAndChainsEvicted(12, nodesP1...) @@ -302,7 +302,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 6, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) - ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(nodesP1[0], 6).ID(), nodesP2...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP2, ts.CommitmentOfMainEngine(nodesP1[0], 6).ID(), nodesP2...) ts.AssertCommitmentsOnEvictedChain(engineCommitmentsP2, false, nodesP2...) ts.AssertCommitmentsAndChainsEvicted(5, nodesP2...) @@ -401,9 +401,18 @@ func TestProtocol_EngineSwitching(t *testing.T) { ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // TODO: check that its not on the main chain - // ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) + + // Since we diverge in slot 14 the forking point of the chain is at slot 14. + commitment14P2 := lo.First(lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { + return commitment.Slot() == 14 + })) + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, commitment14P2.ID(), nodesP1...) + + // Before the merge we finalize until slot 10 (root commitment=6), so the forking point of the then main chain + // is at slot 6. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(nodesP2[0], 6).ID(), nodesP2...) + ts.AssertCommitmentsAndChainsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) } } @@ -477,15 +486,14 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { // Verify that nodes have the expected states after startup. { - genesisCommitment := iotago.NewEmptyCommitment(ts.API) - genesisCommitment.ReferenceManaCost = ts.API.ProtocolParameters().CongestionControlParameters().MinReferenceManaCost + genesisCommitment := ts.CommitmentOfMainEngine(node0, 0) ts.AssertNodeState(ts.Nodes(), testsuite.WithSnapshotImported(true), testsuite.WithProtocolParameters(ts.API.ProtocolParameters()), - testsuite.WithLatestCommitment(genesisCommitment), + testsuite.WithLatestCommitment(genesisCommitment.Commitment()), testsuite.WithLatestFinalizedSlot(0), - testsuite.WithMainChainID(genesisCommitment.MustID()), - testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment}), + testsuite.WithMainChainID(genesisCommitment.ID()), + testsuite.WithStorageCommitments([]*iotago.Commitment{genesisCommitment.Commitment()}), testsuite.WithSybilProtectionCommittee(0, ts.AccountsOfNodes("node0", "node1", "node2", "node3")), testsuite.WithSybilProtectionOnlineCommittee(ts.SeatOfNodes(0, "node0", "node1", "node2", "node3")...), @@ -578,7 +586,7 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { engineCommitmentsP1 := ts.CommitmentsOfMainEngine(nodesP1[0], 12, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP1...) ts.AssertUniqueCommitmentChain(nodesP1...) - ts.AssertCommitmentsOnChain(engineCommitmentsP1, ts.CommitmentOfMainEngine(node0, 12).ID(), nodesP1...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP1, ts.CommitmentOfMainEngine(node0, 12).ID(), nodesP1...) ts.AssertCommitmentsOnEvictedChain(engineCommitmentsP1, false, nodesP1...) ts.AssertCommitmentsAndChainsEvicted(11, nodesP1...) } @@ -629,7 +637,7 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { engineCommitmentsP2 = ts.CommitmentsOfMainEngine(nodesP2[0], 0, 18) ts.AssertLatestEngineCommitmentOnMainChain(nodesP2...) ts.AssertUniqueCommitmentChain(nodesP2...) - ts.AssertCommitmentsOnChain(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 0).ID(), nodesP2...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP2, ts.CommitmentOfMainEngine(node0, 0).ID(), nodesP2...) ts.AssertCommitmentsOnEvictedChain(engineCommitmentsP2, false, nodesP2...) // We only finalized until slot 4, and maxCommittableAge=5. Thus, we don't expect any evictions on chains/commmitments yet. } @@ -654,12 +662,6 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { // Here we need to let enough time pass for the nodes to sync up the candidate engines and switch them ts.AssertMainEngineSwitchedCount(1, nodesP2...) - - // Make sure that enough activity messages are issued so that a block in slot 21 gets accepted and triggers commitment of slot 18. - // time.Sleep(3 * time.Second) - - // ctxP1Cancel() - // wg.Wait() } // Make sure that nodes that switched their engine still have blocks with prefix P0 from before the fork. @@ -693,7 +695,9 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertAttestationsForSlot(18, ts.Blocks("P1:18.3-node1", "P1:18.3-node2"), nodesP1...) // Committee in epoch 2 is only node1, node2. Block(P1:15.3-node0) commits to Slot12, that's why it is not carried to 18. ts.AssertAttestationsForSlot(19, ts.Blocks("P1:19.3-node1", "P1:19.3-node2"), ts.Nodes()...) // Committee in epoch 2 is only node1, node2 - oldestNonEvictedCommitment := nodesP1[0].Protocol.Engines.Main.Get().SyncManager.LatestFinalizedSlot() - maxCommittableAge + ts.AssertLatestFinalizedSlot(19, ts.Nodes()...) + + oldestNonEvictedCommitment := 19 - maxCommittableAge commitmentsMainChain := ts.CommitmentsOfMainEngine(node0, oldestNonEvictedCommitment, expectedCommittedSlotAfterPartitionMerge) ultimateCommitmentsP2 := lo.Filter(engineCommitmentsP2, func(commitment *model.Commitment) bool { return commitment.Slot() >= oldestNonEvictedCommitment @@ -705,9 +709,15 @@ func TestProtocol_EngineSwitching_CommitteeRotation(t *testing.T) { ts.AssertLatestEngineCommitmentOnMainChain(ts.Nodes()...) ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP2, true, ts.Nodes()...) ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) - // TODO: check that its not on the main chain - // ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, ts.Nodes()...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain, ts.CommitmentOfMainEngine(nodesP1[0], oldestNonEvictedCommitment).ID(), ts.Nodes()...) + + // Since we diverge in slot 8 and P1 finalized until slot 17 (root commitment=12) before the merge, + // the chain is not solidifiable and there will never be a chain created for nodes on P1. + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, iotago.EmptyCommitmentID, nodesP1...) + + // After the merge we finalize until slot 19 (root commitment=14), so the chain is evicted (we check this above) + // and therefore i + ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(node3, 0).ID(), nodesP2...) ts.AssertCommitmentsAndChainsEvicted(oldestNonEvictedCommitment-1, ts.Nodes()...) } @@ -943,7 +953,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { commitmentsMainChain := ts.CommitmentsOfMainEngine(nodes[0], 6, 11) ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, commitmentsMainChain[0].ID(), ts.Nodes()...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain, commitmentsMainChain[0].ID(), ts.Nodes()...) ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) // Split into partitions P1, P2 and P3. @@ -1014,17 +1024,17 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { // Make sure the nodes switch their engines. { ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partitionsInOrder[0].A), []iotago.SlotIndex{20}, 1, slotPrefix(partitionsInOrder[0].A, 20)+strconv.Itoa(20)+".3", nodes[partitionsInOrder[0].A-1:partitionsInOrder[0].A], true, true) - ts.AssertCommitmentsOnChain(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partitionsInOrder[1].A), []iotago.SlotIndex{20}, 1, slotPrefix(partitionsInOrder[1].A, 20)+strconv.Itoa(20)+".3", nodes[partitionsInOrder[1].A-1:partitionsInOrder[1].A], true, true) ts.AssertMainEngineSwitchedCount(1, otherPartitions[0]) - ts.AssertCommitmentsOnChain(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) - ts.AssertCommitmentsOnChain(engineCommitmentsP2, engineCommitmentsP2[0].ID(), mainPartition[0], otherPartitions[0]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP2, engineCommitmentsP2[0].ID(), mainPartition[0], otherPartitions[0]) ts.IssueBlocksAtSlots(fmt.Sprintf("P%d-merge:", partitionsInOrder[2].A), []iotago.SlotIndex{20}, 1, slotPrefix(partitionsInOrder[2].A, 20)+strconv.Itoa(20)+".3", nodes[partitionsInOrder[2].A-1:partitionsInOrder[2].A], true, true) - ts.AssertCommitmentsOnChain(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) - ts.AssertCommitmentsOnChain(engineCommitmentsP2, engineCommitmentsP2[0].ID(), mainPartition[0], otherPartitions[0]) - ts.AssertCommitmentsOnChain(commitmentsMainChain, commitmentsMainChain[0].ID(), otherPartitions...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP3, engineCommitmentsP3[0].ID(), mainPartition[0], otherPartitions[1]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(engineCommitmentsP2, engineCommitmentsP2[0].ID(), mainPartition[0], otherPartitions[0]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain, commitmentsMainChain[0].ID(), otherPartitions...) ts.AssertMainEngineSwitchedCount(0, mainPartition...) ts.AssertMainEngineSwitchedCount(2, otherPartitions[0]) @@ -1057,35 +1067,32 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP3, false, ts.Nodes()...) // The Main partition should have all commitments on the old chain, because it did not switch chains. - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[0], oldestNonEvictedCommitment).ID(), mainPartition...) // Pre-fork commitments should be on the old chains on other partitions. - ts.AssertCommitmentsOnChain(commitmentsMainChain[:8], ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain[:8], ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions...) // Post-fork winning commitments should be on the new chains on other partitions. This chain is the new main one. - ts.AssertCommitmentsOnChain(commitmentsMainChain[8:], ts.CommitmentOfMainEngine(otherPartitions[0], forkingSlot).ID(), otherPartitions...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain[8:], ts.CommitmentOfMainEngine(otherPartitions[0], forkingSlot).ID(), otherPartitions...) // P2 commitments on the main partition should be on its own chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), mainPartition...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), mainPartition...) // P2 commitments on P2 node should be on the old chain, that is not the main chain anymore. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ultimateCommitmentsP2, ts.CommitmentOfMainEngine(otherPartitions[1], oldestNonEvictedCommitment).ID(), otherPartitions[1]) // P2 commitments on P3 node should be on separate chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[0]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ultimateCommitmentsP2, ultimateCommitmentsP2[0].ID(), otherPartitions[0]) // P3 commitments on the main partition should be on its own chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), mainPartition...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), mainPartition...) // P3 commitments on P3 node should be on the old chain, that is not the main chain anymore. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ultimateCommitmentsP3, ts.CommitmentOfMainEngine(otherPartitions[0], oldestNonEvictedCommitment).ID(), otherPartitions[0]) // P3 commitments on P2 node should be on separate chain. - ts.AssertCommitmentsOnChain(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[1]) + ts.AssertCommitmentsOnChainAndChainHasCommitments(ultimateCommitmentsP3, ultimateCommitmentsP3[0].ID(), otherPartitions[1]) ts.AssertCommitmentsAndChainsEvicted(5, ts.Nodes()...) } - fmt.Println("---------------------") // Finalize further slot and make sure the nodes have the same state of chains. { - // ts.CommitUntilSlot(forkingSlot+maxCommittableAge+2, ts.BlockIDsWithPrefix(fmt.Sprintf("P%d-merge:", mainPartitionIndex))...) - ts.IssueBlocksAtSlots("P0-merge:", []iotago.SlotIndex{20, 21, 22}, 3, slotPrefix(partitionsInOrder[len(partitionsInOrder)-1].A, 20)+strconv.Itoa(20)+".2", ts.Nodes(), true, true) oldestNonEvictedCommitment = 19 - maxCommittableAge @@ -1100,7 +1107,7 @@ func TestProtocol_EngineSwitching_Tie(t *testing.T) { ts.AssertCommitmentsAndChainsEvicted(forkingSlot, ts.Nodes()...) ts.AssertCommitmentsOnEvictedChain(commitmentsMainChain, false, ts.Nodes()...) - ts.AssertCommitmentsOnChain(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[len(mainPartition)-1], oldestNonEvictedCommitment).ID(), mainPartition...) + ts.AssertCommitmentsOnChainAndChainHasCommitments(commitmentsMainChain, ts.CommitmentOfMainEngine(mainPartition[len(mainPartition)-1], oldestNonEvictedCommitment).ID(), mainPartition...) // The oldest commitment is in the slices are should already be evicted, so we only need to check the newer ones. ts.AssertCommitmentsOnEvictedChain(ultimateCommitmentsP2[2:], true, ts.Nodes()...) diff --git a/pkg/testsuite/chains.go b/pkg/testsuite/chains.go index 7ab82e198..ace98cba5 100644 --- a/pkg/testsuite/chains.go +++ b/pkg/testsuite/chains.go @@ -31,7 +31,7 @@ func (t *TestSuite) AssertLatestEngineCommitmentOnMainChain(nodes ...*mock.Node) } } -func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commitment, chainID iotago.CommitmentID, nodes ...*mock.Node) { +func (t *TestSuite) AssertCommitmentsOnChainAndChainHasCommitments(expectedCommitments []*model.Commitment, chainID iotago.CommitmentID, nodes ...*mock.Node) { mustNodes(nodes) for _, node := range nodes { @@ -46,7 +46,7 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit }) if chainID != iotago.EmptyCommitmentID && selectedChain == nil { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: chain with forking point %s not found", node.Name, chainID) + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: chain with forking point %s not found", node.Name, chainID) } for _, expectedCommitment := range expectedCommitments { @@ -54,15 +54,15 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit { protocolCommitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) if err != nil { - return ierrors.Wrapf(err, "AssertCommitmentsOnChain: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitment.ID(), chainID) + return ierrors.Wrapf(err, "AssertCommitmentsOnChainAndChainHasCommitments: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitment.ID(), chainID) } if protocolCommitment.Chain.Get() != selectedChain { if selectedChain == nil { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected nil, got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: commitment %s not on correct chain, expected nil, got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) } - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment %s not on correct chain, expected %s (pointer: %p, name: %s), got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), chainID, selectedChain, selectedChain.LogName(), protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: commitment %s not on correct chain, expected %s (pointer: %p, name: %s), got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), chainID, selectedChain, selectedChain.LogName(), protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) } } @@ -70,11 +70,41 @@ func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commit if selectedChain != nil { commitment, exists := selectedChain.Commitment(expectedCommitment.Slot()) if !exists { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment for slot %d does not exist on the selected chain %s", node.Name, expectedCommitment.Slot(), chainID) + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: commitment for slot %d does not exist on the selected chain %s", node.Name, expectedCommitment.Slot(), chainID) } if expectedCommitment.ID() != commitment.ID() { - return ierrors.Errorf("AssertCommitmentsOnChain: %s: commitment on chain does not match, expected %s, got %s", node.Name, expectedCommitment, commitment.ID()) + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: commitment on chain does not match, expected %s, got %s", node.Name, expectedCommitment, commitment.ID()) + } + } + } + + return nil + }) + } +} + +func (t *TestSuite) AssertCommitmentsOnChain(expectedCommitments []*model.Commitment, expectedChainID iotago.CommitmentID, nodes ...*mock.Node) { + mustNodes(nodes) + + for _, node := range nodes { + t.Eventually(func() error { + for _, expectedCommitment := range expectedCommitments { + // Check that passed commitments have the correct chain assigned. + { + protocolCommitment, err := node.Protocol.Commitments.Get(expectedCommitment.ID(), false) + if err != nil { + return ierrors.Wrapf(err, "AssertCommitmentsOnChainAndChainHasCommitments: %s: expected commitment %s on chain %s not found", node.Name, expectedCommitment.ID(), expectedChainID) + } + + if protocolCommitment.Chain.Get() == nil { + if expectedChainID != iotago.EmptyCommitmentID { + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: commitment %s (name: %s) not on correct chain, expected %s, got nil", node.Name, expectedCommitment.ID(), protocolCommitment.LogName(), expectedChainID) + } + } else { + if expectedChainID != protocolCommitment.Chain.Get().ForkingPoint.Get().ID() { + return ierrors.Errorf("AssertCommitmentsOnChainAndChainHasCommitments: %s: commitment %s not on correct chain, expected %s, got %s (pointer: %p, name: %s)", node.Name, expectedCommitment.ID(), expectedChainID, protocolCommitment.Chain.Get().ForkingPoint.Get().ID(), protocolCommitment.Chain.Get(), protocolCommitment.Chain.Get().LogName()) + } } } } From 636ded4aa0851c0a73480181289dce310f47b697 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:40:31 +0800 Subject: [PATCH 48/49] Add comments --- pkg/protocol/commitment.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/protocol/commitment.go b/pkg/protocol/commitment.go index 733b9f55a..83b8bed12 100644 --- a/pkg/protocol/commitment.go +++ b/pkg/protocol/commitment.go @@ -299,7 +299,8 @@ func (c *Commitment) deriveChain(parent *Commitment) func() { return currentChain } - // if we are not the main child of our parent, we spawn a new chain + // If we are not the main child of our parent, we spawn a new chain. + // Here we basically move commitments to a new chain if there's a fork. if c != mainChild { if currentChain == nil || currentChain == parentChain { currentChain = c.commitments.protocol.Chains.newChain() @@ -309,9 +310,10 @@ 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 (that we are supposed to - // inherit), then we evict our current chain (we will spawn a new one if we ever change back to not being the - // main child) + // 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 { currentChain.IsEvicted.Trigger() } From cf3b65d001073e579bda846af24581dab477fc75 Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:18:04 +0100 Subject: [PATCH 49/49] Feat: added shouldEvict --- pkg/protocol/chain.go | 63 ++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/pkg/protocol/chain.go b/pkg/protocol/chain.go index c62e0adb6..31c634c35 100644 --- a/pkg/protocol/chain.go +++ b/pkg/protocol/chain.go @@ -57,6 +57,9 @@ type Chain struct { // IsEvicted contains a flag that indicates whether this chain was evicted. IsEvicted reactive.Event + // shouldEvict contains a flag that indicates whether this chain should be evicted. + shouldEvict reactive.Event + // chains contains a reference to the Chains instance that this chain belongs to. chains *Chains @@ -83,6 +86,7 @@ func newChain(chains *Chains) *Chain { StartEngine: reactive.NewVariable[bool](), Engine: reactive.NewVariable[*engine.Engine](), IsEvicted: reactive.NewEvent(), + shouldEvict: reactive.NewEvent(), chains: chains, commitments: shrinkingmap.New[iotago.SlotIndex, *Commitment](), @@ -185,6 +189,7 @@ func (c *Chain) initLogger() (shutdown func()) { c.StartEngine.LogUpdates(c, log.LevelDebug, "StartEngine"), c.Engine.LogUpdates(c, log.LevelTrace, "Engine", (*engine.Engine).LogName), c.IsEvicted.LogUpdates(c, log.LevelTrace, "IsEvicted"), + c.shouldEvict.LogUpdates(c, log.LevelTrace, "shouldEvict"), c.Logger.UnsubscribeFromParentLogger, ) @@ -192,39 +197,49 @@ 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()) { - markChainEvicted := func() { - // TODO: MOVE TO DEDICATED WORKER - go c.IsEvicted.Trigger() - } - - return lo.Batch( + return lo.BatchReverse( c.deriveWarpSyncMode(), - c.ForkingPoint.WithValue(func(forkingPoint *Commitment) (teardown func()) { - return lo.Batch( - func() (teardown func()) { - if forkingPoint == nil { - return - } + c.shouldEvict.OnTrigger(func() { go c.IsEvicted.Trigger() }), - return forkingPoint.IsEvicted.OnTrigger(markChainEvicted) - }(), + lo.BatchReverse( + c.ForkingPoint.WithNonEmptyValue(func(forkingPoint *Commitment) (teardown func()) { + return lo.BatchReverse( + c.deriveParentChain(forkingPoint), - c.deriveParentChain(forkingPoint), - ) - }), + c.ParentChain.WithValue(func(parentChain *Chain) (teardown func()) { + return lo.BatchReverse( + parentChain.deriveChildChains(c), - c.ParentChain.WithNonEmptyValue(func(parent *Chain) (teardown func()) { - return lo.Batch( - //parent.IsEvicted.OnTrigger(markChainEvicted), + c.deriveShouldEvict(forkingPoint, parentChain), + ) + }), + ) + }), + ), - parent.deriveChildChains(c), - ) - }), c.Engine.WithNonEmptyValue(c.deriveOutOfSyncThreshold), ) } +// deriveShouldEvict defines how a chain determines whether it should be evicted (if it is not the main chain and either +// its forking point or its parent chain is evicted). +func (c *Chain) deriveShouldEvict(forkingPoint *Commitment, parentChain *Chain) (shutdown func()) { + if forkingPoint != nil && parentChain != nil { + return c.shouldEvict.DeriveValueFrom(reactive.NewDerivedVariable2(func(_, forkingPointIsEvicted bool, parentChainIsEvicted bool) bool { + return c.chains.Main.Get() != c && (forkingPointIsEvicted || parentChainIsEvicted) + }, forkingPoint.IsEvicted, parentChain.IsEvicted)) + } + + if forkingPoint != nil { + return c.shouldEvict.DeriveValueFrom(reactive.NewDerivedVariable(func(_, forkingPointIsEvicted bool) bool { + return c.chains.Main.Get() != c && forkingPointIsEvicted + }, forkingPoint.IsEvicted)) + } + + return +} + // 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 { @@ -240,7 +255,7 @@ func (c *Chain) deriveWarpSyncMode() func() { // deriveChildChains defines how a chain determines its ChildChains (by adding each child to the set). func (c *Chain) deriveChildChains(child *Chain) (teardown func()) { - if child != c { + if c != nil && c != child { c.ChildChains.Add(child) teardown = func() {