Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite ConflictDAG #2606

Draft
wants to merge 141 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
141 commits
Select commit Hold shift + click to select a range
7c2cb28
Feat: Initial Brainstorm un multi-tiered conflictdag
hmoog Mar 10, 2023
10b10a0
Feat: more brainstorming
hmoog Mar 10, 2023
37109ba
Feat: started implementing ordering
hmoog Mar 11, 2023
83d251e
Feat: WIP WIP
hmoog Mar 14, 2023
bb26ad8
Feat: added unit tests
hmoog Mar 15, 2023
0021cfd
Feat: added more stuff
hmoog Mar 15, 2023
3e34f51
Feat: WIP WIP it works
hmoog Mar 16, 2023
71b62f6
Feat: started finalizing and commenting sub packages
hmoog Mar 16, 2023
5513fe5
Feat: refactored more code
hmoog Mar 16, 2023
9d2bc1a
Feat: more cleanup
hmoog Mar 16, 2023
9094a6e
Refactor: removed unnecessary code
hmoog Mar 16, 2023
9bfceea
Refactor: fixed some outputs in the String methods
hmoog Mar 16, 2023
8ced0b0
Merge branch 'develop' of https://github.com/iotaledger/goshimmer int…
hmoog Mar 17, 2023
3394cbc
Fix: updated constructor of AdvancedSet
hmoog Mar 17, 2023
643d928
Refactor: removed unused code
hmoog Mar 17, 2023
c933c52
Feat: implemented some preferred instead stuff
hmoog Mar 17, 2023
5740e1c
Feat: Added PreferredInstead functionalitz
hmoog Mar 17, 2023
80aeece
Refactor: started cleaning up
hmoog Mar 17, 2023
e042aef
Refactor: cleaned up more code
hmoog Mar 17, 2023
eb04c9c
Refactor: cleaned up code
hmoog Mar 17, 2023
6b80c04
Refactor: started cleanup SortedSet
hmoog Mar 17, 2023
55496d3
Refactor: cleaned up SortedSet
hmoog Mar 18, 2023
3aad4ed
Feat: hooked PreferredInsteadUpdated
hmoog Mar 18, 2023
bbab455
Test new Conflicts WIP
piotrm50 Mar 20, 2023
6b96cf1
Create a worker for updating conflict preference
piotrm50 Mar 21, 2023
222a962
Sorted conflicts somewhat work
piotrm50 Mar 21, 2023
ba18dd0
Test WIP
piotrm50 Mar 21, 2023
fc1aa60
Feat: added shared pendingTasksCounter
hmoog Mar 21, 2023
d7d7813
Feat: fixed bugs?
hmoog Mar 22, 2023
e82ff02
Add event log for debugging
piotrm50 Mar 22, 2023
c315e24
Fix: fixed some bugs
hmoog Mar 22, 2023
1dcc458
Improve unit tests
piotrm50 Mar 22, 2023
6e3148e
Improve test assertion
piotrm50 Mar 22, 2023
608bb25
Fix: fixed linter issue
hmoog Mar 22, 2023
14445bc
Refactor: refactored code
hmoog Mar 22, 2023
cc6980a
Fix: fixed race condition
hmoog Mar 22, 2023
c66b60c
Add parentsPreferredConflicts property
piotrm50 Mar 23, 2023
8f7fcca
Feat: started adding likeInstead references
hmoog Mar 24, 2023
484a33e
Feat: started adding tests for LikedInstead
hmoog Mar 24, 2023
56a4551
Feat: likedinstead seems to work
hmoog Mar 24, 2023
d5e1181
Refactor: refactored code
hmoog Mar 24, 2023
101870c
Fix: fixed linter errors
hmoog Mar 24, 2023
6dbff41
Refactor: fixed linter error
hmoog Mar 24, 2023
03b4b7a
Refactor: cleaned up code
hmoog Mar 25, 2023
13a3b23
Feat: started tying things together in the ConflictDAG
hmoog Mar 25, 2023
195a7a9
Merge branch 'develop' of github.com:iotaledger/goshimmer into feat/r…
hmoog Mar 29, 2023
12437c1
Feat: started adding conflictdag tests
hmoog Mar 29, 2023
0ef7a4c
Feat: extended tests
hmoog Mar 29, 2023
63e66d1
Fix: fixed bug
hmoog Mar 29, 2023
20e2aba
Fix: fixed bug
hmoog Mar 29, 2023
0254d06
Feat: added more tests
hmoog Mar 30, 2023
77785eb
Feat: upgraded hive.go
hmoog Apr 4, 2023
1fadcaf
Feat: cleaned up API
hmoog Apr 4, 2023
a2dad39
Feat: simplified API
hmoog Apr 4, 2023
21ca0f9
Feat: cleaned up API
hmoog Apr 5, 2023
f7af16c
Feat: simplified api
hmoog Apr 5, 2023
65e5c26
Feat: added method to join a conflict to new conflictSets
hmoog Apr 5, 2023
cf5fe5b
Feat: uploaded some changes
hmoog Apr 5, 2023
e85c8c8
Feat: cleaned up types
hmoog Apr 5, 2023
c90601c
Feat: added voting primitives
hmoog Apr 5, 2023
d02da12
Feat: cleaned up code
hmoog Apr 5, 2023
a107dbb
Refactor: cleaned up more code
hmoog Apr 5, 2023
1fffdd5
Feat: cleaned up code
hmoog Apr 6, 2023
bbee28a
Feat: merged more funcs
hmoog Apr 6, 2023
c6dbe6e
Feat: more cleanup
hmoog Apr 6, 2023
87f34c9
Refactor: started restructuring code
hmoog Apr 6, 2023
908cb0b
Refactor: added comments in respect to locking
hmoog Apr 7, 2023
7496958
Refactor: removed unnecessary variable
hmoog Apr 7, 2023
e02482a
Merge branch 'develop' into feat/rewrite-conflictdag-with-voting
hmoog Apr 7, 2023
cce86b2
Feat: go mod tidy
hmoog Apr 7, 2023
f378894
Fix: fixed data race
hmoog Apr 7, 2023
88b6ad5
Feat: cleaned up code
hmoog Apr 10, 2023
9d82204
Feat: started adding vote logic
hmoog Apr 10, 2023
bac12e8
Refactor: refactored walkers and removed utils
hmoog Apr 10, 2023
0d8a269
Feat: WIP (almost done)
hmoog Apr 11, 2023
44a821d
Feat: added tests for acceptance
hmoog Apr 11, 2023
dd73c3f
Feat: extended tests
hmoog Apr 11, 2023
5e223a1
Evaluate results of a test
piotrm50 Apr 11, 2023
e70660d
Feat: cleaned up code
hmoog Apr 12, 2023
8d32368
Clean up stuff
piotrm50 Apr 12, 2023
bc8b174
Move things from conflict package to conflictdag package and improve …
piotrm50 Apr 12, 2023
eb5ad7c
Fix: reverted accidental change from previous commit
hmoog Apr 12, 2023
5a1046e
Implement Dispose methods for Conflict and SortedConflicts
piotrm50 Apr 12, 2023
a311ac3
Feat: started tracking conflictsets in conflicts
hmoog Apr 13, 2023
b51e5ae
Implement eviction of the new ConflictDAG
piotrm50 Apr 13, 2023
80eeda0
Fix tests after refactoring
piotrm50 Apr 13, 2023
6b660de
Feat: started fixing tests
hmoog Apr 13, 2023
af2d817
Merge branch 'feat/rewrite-conflictdag-with-voting' of https://github…
hmoog Apr 13, 2023
b42d725
Fix: fixed tests#
hmoog Apr 13, 2023
8e6222e
Refactor: introduced utility method for getting conflictsets
hmoog Apr 13, 2023
750f35b
Feat: continued work ok eviction
hmoog Apr 14, 2023
6c2cc1d
Fix: fixed bug
hmoog Apr 14, 2023
5806b69
Feat: cleaned up eviction
hmoog Apr 14, 2023
bb9aa0f
Ledger uses new conflict DAG
piotrm50 Apr 14, 2023
1f0ed9b
Refactor: added comment
hmoog Apr 14, 2023
bd3dd69
Merge branch 'feat/rewrite-conflictdag-with-voting' of https://github…
hmoog Apr 14, 2023
b6961e3
Get rid of VirtualVoting component. Make markerbooker use new Conflic…
piotrm50 Apr 14, 2023
d3c2da5
Integrate the new conflictdag with the rest of the components
piotrm50 Apr 14, 2023
1412314
Start fixing compile errors
piotrm50 Apr 14, 2023
e1779ee
Refactor: reverted accidental rename
hmoog Apr 14, 2023
0cf3e83
Refactor: fix more rename bugs
hmoog Apr 14, 2023
e5c8078
Feat: more cleanup
hmoog Apr 14, 2023
bf717e9
Refactor: minimized changes
hmoog Apr 14, 2023
b0d3508
Feat: further minimized diff
hmoog Apr 14, 2023
d86df62
Fix: fixed some bugs
hmoog Apr 14, 2023
66ff2d4
Fix: fixed ReferenceProvider
hmoog Apr 14, 2023
cc057b7
Refactor: refactored code
hmoog Apr 15, 2023
53ec43b
Refactor: refactored code
hmoog Apr 15, 2023
fd9b2b0
Refactor: refactor
hmoog Apr 15, 2023
a2c126a
Refactor: minimized diff
hmoog Apr 15, 2023
eb09e99
Refactor: reverted erroneous rename
hmoog Apr 15, 2023
d0e8a14
Feat: switched ConflictDAG API to use AdvancedSets
hmoog Apr 17, 2023
9a80012
Feat: optimized code to use AdvancedSet everywhere
hmoog Apr 17, 2023
2462094
Feat: fixed interfaces
hmoog Apr 17, 2023
8a34c1d
Continue integrating new conflictdag with the codebase
piotrm50 Apr 17, 2023
6307ff4
Fix last problems
piotrm50 Apr 17, 2023
8d064cf
Fix tips conflicts tracker
piotrm50 Apr 17, 2023
26bdd21
Fix some problems with double spend resolution
piotrm50 Apr 17, 2023
d0e9ccd
Merge branch 'debug/race-conditions' into feat/rewrite-conflictdag-wi…
piotrm50 Apr 17, 2023
9537e80
Merge remote-tracking branch 'origin/debug/race-conditions' into feat…
piotrm50 Apr 17, 2023
162034f
Continue fixing problems after integrating the new conflictdag
piotrm50 Apr 17, 2023
2d8b6a4
Fix some more problems with double spend and guava spam.
piotrm50 Apr 17, 2023
ed31879
Feat: added some missing comments
hmoog Apr 17, 2023
3c9f913
Fix: fixed tests
hmoog Apr 17, 2023
9920479
Feat: Created ConflictDAG interface package
hmoog Apr 18, 2023
fa1d97a
Only remove strong parents when adding a new tip to tip pool
piotrm50 Apr 18, 2023
1cbee1c
Fix casting votes when propagating conflict after fork.
piotrm50 Apr 18, 2023
6ecdf48
Revert accidental change
piotrm50 Apr 18, 2023
2503e80
Feat: implemented generic test framework for conflictdag
hmoog Apr 19, 2023
27312ab
Merge remote-tracking branch 'origin/develop' into feat/rewrite-confl…
piotrm50 Apr 20, 2023
d026284
Fix post merge errors
piotrm50 Apr 20, 2023
aed80c5
Merge remote-tracking branch 'origin/develop' into feat/rewrite-confl…
piotrm50 Apr 20, 2023
d745f0a
Remove some unused metrics that caused problems
piotrm50 Apr 20, 2023
9846cee
Fix nil pointer in the metrics plugin
piotrm50 Apr 26, 2023
db1714c
Always create conflictsets
piotrm50 Apr 27, 2023
c7866a2
Get rid of implicit self-like
piotrm50 Apr 27, 2023
151a66e
Add a parent block back to the tip pool after removing old one.
piotrm50 Apr 27, 2023
7258ae8
Remove printlns for subjectively invalid blocks
piotrm50 Apr 27, 2023
4e167db
Fix imports
piotrm50 Apr 28, 2023
8574b8e
Add non-conflicting conflict to ConflictDAG test suite
karimodm May 11, 2023
749aa3e
Merge branch 'feat/rewrite-conflictdag-with-voting' of github.com:iot…
karimodm May 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/evilwallet/connector.go
Expand Up @@ -183,7 +183,7 @@ type Client interface {
GetUnspentOutputForAddress(addr devnetvm.Address) *jsonmodels.WalletOutput
// GetAddressUnspentOutputs gets the unspent outputs of an address.
GetAddressUnspentOutputs(address string) (outputIDs []utxo.OutputID, err error)
// GetTransactionConfirmationState returns the ConfirmationState of a given transaction ID.
// GetTransactionConfirmationState returns the AcceptanceState of a given transaction ID.
GetTransactionConfirmationState(txID string) confirmation.State
// GetOutput gets the output of a given outputID.
GetOutput(outputID utxo.OutputID) devnetvm.Output
Expand Down Expand Up @@ -338,7 +338,7 @@ func (c *WebClient) GetOutput(outputID utxo.OutputID) devnetvm.Output {
return output
}

// GetTransactionConfirmationState returns the ConfirmationState of a given transaction ID.
// GetTransactionConfirmationState returns the AcceptanceState of a given transaction ID.
func (c *WebClient) GetTransactionConfirmationState(txID string) confirmation.State {
resp, err := c.api.GetTransactionMetadata(txID)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion client/wallet/webconnector.go
Expand Up @@ -118,7 +118,7 @@ func (webConnector WebConnector) SendTransaction(tx *devnetvm.Transaction) (err
return
}

// GetTransactionConfirmationState fetches the ConfirmationState of the transaction.
// GetTransactionConfirmationState fetches the AcceptanceState of the transaction.
func (webConnector WebConnector) GetTransactionConfirmationState(txID utxo.TransactionID) (confirmationState confirmation.State, err error) {
txmeta, err := webConnector.client.GetTransactionMetadata(txID.Base58())
if err != nil {
Expand Down
169 changes: 86 additions & 83 deletions packages/app/blockissuer/blockfactory/referenceprovider.go
@@ -1,17 +1,20 @@
package blockfactory

import (
"fmt"
"time"

"github.com/pkg/errors"
"golang.org/x/xerrors"

"github.com/iotaledger/goshimmer/packages/protocol"
"github.com/iotaledger/goshimmer/packages/protocol/engine/ledger/mempool/conflictdag"
"github.com/iotaledger/goshimmer/packages/protocol/engine/ledger/utxo"
"github.com/iotaledger/goshimmer/packages/protocol/engine/tangle/booker"
"github.com/iotaledger/goshimmer/packages/protocol/models"
"github.com/iotaledger/goshimmer/packages/protocol/models/payload"
"github.com/iotaledger/hive.go/core/slot"
"github.com/iotaledger/hive.go/ds/advancedset"
"github.com/iotaledger/hive.go/lo"
)

// region ReferenceProvider ////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -39,58 +42,59 @@ func (r *ReferenceProvider) References(payload payload.Payload, strongParents mo

excludedConflictIDs := utxo.NewTransactionIDs()

r.protocol.Engine().Ledger.MemPool().ConflictDAG().WeightsMutex.Lock()
defer r.protocol.Engine().Ledger.MemPool().ConflictDAG().WeightsMutex.Unlock()
err = r.protocol.Engine().Ledger.MemPool().ConflictDAG().ReadConsistent(func(conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) error {
for strongParent := range strongParents {
excludedConflictIDsCopy := excludedConflictIDs.Clone()
referencesToAdd, validStrongParent := r.addedReferencesForBlock(strongParent, excludedConflictIDsCopy, conflictDAG)
if !validStrongParent {
if !r.payloadLiked(strongParent, conflictDAG) {
continue
}

for strongParent := range strongParents {
excludedConflictIDsCopy := excludedConflictIDs.Clone()
referencesToAdd, validStrongParent := r.addedReferencesForBlock(strongParent, excludedConflictIDsCopy)
if !validStrongParent {
if !r.payloadLiked(strongParent) {
continue
referencesToAdd = models.NewParentBlockIDs().Add(models.WeakParentType, strongParent)
} else {
referencesToAdd.AddStrong(strongParent)
}

referencesToAdd = models.NewParentBlockIDs().Add(models.WeakParentType, strongParent)
} else {
referencesToAdd.AddStrong(strongParent)
if combinedReferences, success := r.tryExtendReferences(references, referencesToAdd); success {
references = combinedReferences
excludedConflictIDs = excludedConflictIDsCopy
}
}

if combinedReferences, success := r.tryExtendReferences(references, referencesToAdd); success {
references = combinedReferences
excludedConflictIDs = excludedConflictIDsCopy
if len(references[models.StrongParentType]) == 0 {
return errors.Errorf("none of the provided strong parents can be referenced. Strong parents provided: %+v.", strongParents)
}
}

if len(references[models.StrongParentType]) == 0 {
return nil, errors.Errorf("none of the provided strong parents can be referenced. Strong parents provided: %+v.", strongParents)
}
// This should be liked anyway, or at least it should be corrected by shallow like if we spend.
// If a node spends something it doesn't like, then the payload is invalid as well.
weakReferences, likeInsteadReferences, err := r.referencesFromUnacceptedInputs(payload, excludedConflictIDs, conflictDAG)
if err != nil {
return errors.Wrapf(err, "failed to create references for unnaccepted inputs")
}

// This should be liked anyway, or at least it should be corrected by shallow like if we spend.
// If a node spends something it doesn't like, then the payload is invalid as well.
weakReferences, likeInsteadReferences, err := r.referencesFromUnacceptedInputs(payload, excludedConflictIDs)
if err != nil {
return nil, errors.Wrapf(err, "failed to create references for unnaccepted inputs")
}
references.AddAll(models.WeakParentType, weakReferences)
references.AddAll(models.ShallowLikeParentType, likeInsteadReferences)

references.AddAll(models.WeakParentType, weakReferences)
references.AddAll(models.ShallowLikeParentType, likeInsteadReferences)
// Include censored, pending conflicts if there are free weak parent spots.
references.AddAll(models.WeakParentType, r.referencesToMissingConflicts(models.MaxParentsCount-len(references[models.WeakParentType]), conflictDAG))

// Include censored, pending conflicts if there are free weak parent spots.
references.AddAll(models.WeakParentType, r.referencesToMissingConflicts(models.MaxParentsCount-len(references[models.WeakParentType])))
// Make sure that there's no duplicate between strong and weak parents.
references.CleanupReferences()

// Make sure that there's no duplicate between strong and weak parents.
references.CleanupReferences()
return nil
})

return references, nil
return references, err
}

func (r *ReferenceProvider) referencesToMissingConflicts(amount int) (blockIDs models.BlockIDs) {
func (r *ReferenceProvider) referencesToMissingConflicts(amount int, conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) (blockIDs models.BlockIDs) {
blockIDs = models.NewBlockIDs()
if amount == 0 {
return blockIDs
}

for it := r.protocol.TipManager.TipsConflictTracker.MissingConflicts(amount).Iterator(); it.HasNext(); {
for it := r.protocol.TipManager.TipsConflictTracker.MissingConflicts(amount, conflictDAG).Iterator(); it.HasNext(); {
conflictID := it.Next()

// TODO: make sure that timestamp monotonicity is not broken
Expand All @@ -113,7 +117,7 @@ func (r *ReferenceProvider) referencesToMissingConflicts(amount int) (blockIDs m
return blockIDs
}

func (r *ReferenceProvider) referencesFromUnacceptedInputs(payload payload.Payload, excludedConflictIDs utxo.TransactionIDs) (weakParents models.BlockIDs, likeInsteadParents models.BlockIDs, err error) {
func (r *ReferenceProvider) referencesFromUnacceptedInputs(payload payload.Payload, excludedConflictIDs utxo.TransactionIDs, conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) (weakParents models.BlockIDs, likeInsteadParents models.BlockIDs, err error) {
weakParents = models.NewBlockIDs()
likeInsteadParents = models.NewBlockIDs()

Expand Down Expand Up @@ -155,7 +159,7 @@ func (r *ReferenceProvider) referencesFromUnacceptedInputs(payload payload.Paylo
continue
}

if adjust, referencedBlk, referenceErr := r.adjustOpinion(transactionConflictID, excludedConflictIDs); referenceErr != nil {
if adjust, referencedBlk, referenceErr := r.adjustOpinion(transactionConflictID, excludedConflictIDs, conflictDAG); referenceErr != nil {
return nil, nil, errors.Wrapf(referenceErr, "failed to correct opinion for weak parent with unaccepted output %s", referencedTransactionID)
} else if adjust {
if referencedBlk != models.EmptyBlockID {
Expand All @@ -174,7 +178,7 @@ func (r *ReferenceProvider) referencesFromUnacceptedInputs(payload payload.Paylo
}

// addedReferenceForBlock returns the reference that is necessary to correct our opinion on the given block.
func (r *ReferenceProvider) addedReferencesForBlock(blockID models.BlockID, excludedConflictIDs utxo.TransactionIDs) (addedReferences models.ParentBlockIDs, success bool) {
func (r *ReferenceProvider) addedReferencesForBlock(blockID models.BlockID, excludedConflictIDs utxo.TransactionIDs, conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) (addedReferences models.ParentBlockIDs, success bool) {
engineInstance := r.protocol.Engine()

block, exists := engineInstance.Tangle.Booker().Block(blockID)
Expand All @@ -189,27 +193,27 @@ func (r *ReferenceProvider) addedReferencesForBlock(blockID models.BlockID, excl
}

var err error
if addedReferences, err = r.addedReferencesForConflicts(blockConflicts, excludedConflictIDs); err != nil {
if addedReferences, err = r.addedReferencesForConflicts(blockConflicts, excludedConflictIDs, conflictDAG); err != nil {
// Delete the tip if we could not pick it up.
if schedulerBlock, schedulerBlockExists := r.protocol.CongestionControl.Scheduler().Block(blockID); schedulerBlockExists {
r.protocol.TipManager.DeleteTip(schedulerBlock)
r.protocol.TipManager.InvalidateTip(schedulerBlock)
}
return nil, false
}

// We could not refer to any block to fix the opinion, so we add the tips' strong parents to the tip pool.
if addedReferences == nil {
if block, exists := r.protocol.Engine().Tangle.Booker().Block(blockID); exists {
block.ForEachParentByType(models.StrongParentType, func(parentBlockID models.BlockID) bool {
if schedulerBlock, schedulerBlockExists := r.protocol.CongestionControl.Scheduler().Block(parentBlockID); schedulerBlockExists {
r.protocol.TipManager.AddTipNonMonotonic(schedulerBlock)
}
return true
})
}
fmt.Println(">> could not fix opinion", blockID)
return nil, false
}
//// We could not refer to any block to fix the opinion, so we add the tips' strong parents to the tip pool.
//if addedReferences == nil {
// if block, exists := r.protocol.Engine().Tangle.Booker().Block(blockID); exists {
// block.ForEachParentByType(models.StrongParentType, func(parentBlockID models.BlockID) bool {
// if schedulerBlock, schedulerBlockExists := r.protocol.CongestionControl.Scheduler().Block(parentBlockID); schedulerBlockExists {
// r.protocol.TipManager.AddTipNonMonotonic(schedulerBlock)
// }
// return true
// })
// }
// fmt.Println(">> could not fix opinion", blockID)
// return nil, false
//}

// A block might introduce too many references and cannot be picked up as a strong parent.
if _, success = r.tryExtendReferences(models.NewParentBlockIDs(), addedReferences); !success {
Expand All @@ -220,7 +224,7 @@ func (r *ReferenceProvider) addedReferencesForBlock(blockID models.BlockID, excl
}

// addedReferencesForConflicts returns the references that are necessary to correct our opinion on the given conflicts.
func (r *ReferenceProvider) addedReferencesForConflicts(conflictIDs utxo.TransactionIDs, excludedConflictIDs utxo.TransactionIDs) (referencesToAdd models.ParentBlockIDs, err error) {
func (r *ReferenceProvider) addedReferencesForConflicts(conflictIDs utxo.TransactionIDs, excludedConflictIDs utxo.TransactionIDs, conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) (referencesToAdd models.ParentBlockIDs, err error) {
referencesToAdd = models.NewParentBlockIDs()

for it := conflictIDs.Iterator(); it.HasNext(); {
Expand All @@ -231,45 +235,49 @@ func (r *ReferenceProvider) addedReferencesForConflicts(conflictIDs utxo.Transac
continue
}

if adjust, referencedBlk, referenceErr := r.adjustOpinion(conflictID, excludedConflictIDs); referenceErr != nil {
adjust, referencedBlk, referenceErr := r.adjustOpinion(conflictID, excludedConflictIDs, conflictDAG)
if referenceErr != nil {
return nil, errors.Wrapf(referenceErr, "failed to create reference for %s", conflictID)
} else if adjust {
if referencedBlk != models.EmptyBlockID {
referencesToAdd.Add(models.ShallowLikeParentType, referencedBlk)
} else {
// We could not find a block that we could reference to fix this strong parent, but we don't want to delete the tip.
return nil, nil
}
}

if adjust {
referencesToAdd.Add(models.ShallowLikeParentType, referencedBlk)
}
}

return referencesToAdd, nil
}

// adjustOpinion returns the reference that is necessary to correct our opinion on the given conflict.
func (r *ReferenceProvider) adjustOpinion(conflictID utxo.TransactionID, excludedConflictIDs utxo.TransactionIDs) (adjust bool, attachmentID models.BlockID, err error) {
func (r *ReferenceProvider) adjustOpinion(conflictID utxo.TransactionID, excludedConflictIDs utxo.TransactionIDs, conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) (adjust bool, attachmentID models.BlockID, err error) {
engineInstance := r.protocol.Engine()

likedConflictID, dislikedConflictIDs := engineInstance.Consensus.ConflictResolver().AdjustOpinion(conflictID)

likedConflictID := conflictDAG.LikedInstead(advancedset.New(conflictID))
// if likedConflictID is empty, then conflictID is liked and doesn't need to be corrected
if likedConflictID.IsEmpty() {
// TODO: make conflictset and conflict creation atomic to always prevent this.
return false, models.EmptyBlockID, errors.Errorf("likedConflictID empty when trying to adjust opinion for %s", conflictID)
}

if likedConflictID == conflictID {
return false, models.EmptyBlockID, nil
}

attachment, err := r.latestValidAttachment(likedConflictID)
// TODO: make sure that timestamp monotonicity is held
if err != nil {
if err = likedConflictID.ForEach(func(likedConflictID utxo.TransactionID) (err error) {
attachment, err := r.latestValidAttachment(likedConflictID)
// TODO: make sure that timestamp monotonicity is held
if err != nil {
return err
}

attachmentID = attachment.ID()

excludedConflictIDs.AddAll(engineInstance.Ledger.MemPool().Utils().ConflictIDsInFutureCone(lo.Return1(conflictDAG.ConflictingConflicts(likedConflictID))))

return nil
}); err != nil {
return false, models.EmptyBlockID, err
}

excludedConflictIDs.AddAll(engineInstance.Ledger.MemPool().Utils().ConflictIDsInFutureCone(dislikedConflictIDs))

return true, attachment.ID(), nil
if attachmentID == models.EmptyBlockID {
return false, attachmentID, xerrors.Errorf("could not find attachment to fix conflict %s", conflictID)
}
return true, attachmentID, nil
}

// latestValidAttachment returns the first valid attachment of the given transaction.
Expand All @@ -291,21 +299,16 @@ func (r *ReferenceProvider) latestValidAttachment(txID utxo.TransactionID) (bloc
}

// payloadLiked checks if the payload of a Block is liked.
func (r *ReferenceProvider) payloadLiked(blockID models.BlockID) (liked bool) {
func (r *ReferenceProvider) payloadLiked(blockID models.BlockID, conflictDAG conflictdag.ReadLockedConflictDAG[utxo.TransactionID, utxo.OutputID, models.BlockVotePower]) (liked bool) {
engineInstance := r.protocol.Engine()

block, exists := engineInstance.Tangle.Booker().Block(blockID)
if !exists {
return false
}
conflictIDs := engineInstance.Tangle.Booker().TransactionConflictIDs(block)

for it := conflictIDs.Iterator(); it.HasNext(); {
conflict, exists := engineInstance.Ledger.MemPool().ConflictDAG().Conflict(it.Next())
if !exists {
continue
}
if !engineInstance.Consensus.ConflictResolver().ConflictLiked(conflict) {
for conflicts := engineInstance.Tangle.Booker().TransactionConflictIDs(block).Iterator(); conflicts.HasNext(); {
if !conflictDAG.LikedInstead(advancedset.New(conflicts.Next())).IsEmpty() {
return false
}
}
Expand Down
16 changes: 8 additions & 8 deletions packages/app/jsonmodels/ledgerstate.go
Expand Up @@ -2,14 +2,14 @@

import (
"encoding/json"
"github.com/iotaledger/hive.go/ds/advancedset"

Check failure on line 5 in packages/app/jsonmodels/ledgerstate.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] packages/app/jsonmodels/ledgerstate.go#L5

File is not `goimports`-ed with -local github.com/iotaledger (goimports)
Raw output
packages/app/jsonmodels/ledgerstate.go:5: File is not `goimports`-ed with -local github.com/iotaledger (goimports)
	"github.com/iotaledger/hive.go/ds/advancedset"
"time"

"github.com/mr-tron/base58"
"github.com/pkg/errors"

"github.com/iotaledger/goshimmer/packages/core/confirmation"
"github.com/iotaledger/goshimmer/packages/protocol/engine/ledger/mempool"
"github.com/iotaledger/goshimmer/packages/protocol/engine/ledger/mempool/conflictdag"
"github.com/iotaledger/goshimmer/packages/protocol/engine/ledger/utxo"
"github.com/iotaledger/goshimmer/packages/protocol/engine/ledger/vm/devnetvm"
"github.com/iotaledger/goshimmer/packages/typeutils"
Expand Down Expand Up @@ -531,21 +531,21 @@
}

// NewConflictWeight returns a Conflict from the given ledger.Conflict.
func NewConflictWeight(conflict *conflictdag.Conflict[utxo.TransactionID, utxo.OutputID], confirmationState confirmation.State, aw int64) ConflictWeight {
func NewConflictWeight(conflictID utxo.TransactionID, conflictParentsIDs *advancedset.AdvancedSet[utxo.TransactionID], conflictSets *advancedset.AdvancedSet[utxo.OutputID], confirmationState confirmation.State, aw int64) ConflictWeight {
return ConflictWeight{
ID: conflict.ID().Base58(),
ID: conflictID.Base58(),
Parents: func() []string {
parents := make([]string, 0)
for it := conflict.Parents().Iterator(); it.HasNext(); {
for it := conflictParentsIDs.Iterator(); it.HasNext(); {
parents = append(parents, it.Next().Base58())
}

return parents
}(),
ConflictIDs: func() []string {
conflictIDs := make([]string, 0)
for it := conflict.ConflictSets().Iterator(); it.HasNext(); {
conflictIDs = append(conflictIDs, it.Next().ID().Base58())
for it := conflictSets.Iterator(); it.HasNext(); {
conflictIDs = append(conflictIDs, it.Next().Base58())
}

return conflictIDs
Expand All @@ -563,9 +563,9 @@
}

// NewChildConflict returns a ChildConflict from the given ledger.ChildConflict.
func NewChildConflict(childConflict *conflictdag.Conflict[utxo.TransactionID, utxo.OutputID]) *ChildConflict {
func NewChildConflict(childConflictID utxo.TransactionID) *ChildConflict {
return &ChildConflict{
ConflictID: childConflict.ID().Base58(),
ConflictID: childConflictID.Base58(),
}
}

Expand Down