-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adaptive heaviest branch tipsel (#567)
* Move transaction root index funcs to dag package * Add new coordinator config options * Show checkpoints as milestones in the visualizer * First working draft of the adaptive heaviest branch tipselection * Feed the dog * Coordinator code cleanup * Fixed race condition in Coordinator * Add checks if URTS plugin is enabled * Fix nextMilestoneSignal getting lost sometimes * Add itemList struct * Replace enforceTips with minRequiredTips * Removed maxTipsCount criteria * Code cleanup * Simplify below max depth check * Move context.WithDeadline to SelectTips * Inline randomTip * Add config option for heaviestBranchSelectionDeadline * Change default values * Remove latestTip * - Fix whiteflag address mutations not correctly mutating if a balance changes multiple times inside the same confirmation Co-authored-by: Alexander Sporn <[email protected]>
- Loading branch information
Showing
18 changed files
with
711 additions
and
480 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package dag | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
|
||
"github.com/gohornet/hornet/pkg/model/hornet" | ||
"github.com/gohornet/hornet/pkg/model/milestone" | ||
"github.com/gohornet/hornet/pkg/model/tangle" | ||
) | ||
|
||
// UpdateOutdatedRootSnapshotIndexes updates the transaction root snapshot indexes of the given transactions. | ||
// the "outdatedTransactions" should be ordered from latest to oldest to avoid recursion. | ||
func UpdateOutdatedRootSnapshotIndexes(outdatedTransactions hornet.Hashes, lsmi milestone.Index) { | ||
for i := len(outdatedTransactions) - 1; i >= 0; i-- { | ||
outdatedTxHash := outdatedTransactions[i] | ||
|
||
cachedTx := tangle.GetCachedTransactionOrNil(outdatedTxHash) | ||
if cachedTx == nil { | ||
panic(tangle.ErrTransactionNotFound) | ||
} | ||
GetTransactionRootSnapshotIndexes(cachedTx, lsmi) | ||
} | ||
} | ||
|
||
// GetTransactionRootSnapshotIndexes searches the transaction root snapshot indexes for a given transaction. | ||
func GetTransactionRootSnapshotIndexes(cachedTx *tangle.CachedTransaction, lsmi milestone.Index) (youngestTxRootSnapshotIndex milestone.Index, oldestTxRootSnapshotIndex milestone.Index) { | ||
defer cachedTx.Release(true) // tx -1 | ||
|
||
// if the tx already contains recent (calculation index matches LSMI) | ||
// information about yrtsi and ortsi, return that info | ||
yrtsi, ortsi, rtsci := cachedTx.GetMetadata().GetRootSnapshotIndexes() | ||
if rtsci == lsmi { | ||
return yrtsi, ortsi | ||
} | ||
|
||
snapshotInfo := tangle.GetSnapshotInfo() | ||
|
||
youngestTxRootSnapshotIndex = 0 | ||
oldestTxRootSnapshotIndex = 0 | ||
|
||
updateIndexes := func(yrtsi milestone.Index, ortsi milestone.Index) { | ||
if (youngestTxRootSnapshotIndex == 0) || (youngestTxRootSnapshotIndex < yrtsi) { | ||
youngestTxRootSnapshotIndex = yrtsi | ||
} | ||
if (oldestTxRootSnapshotIndex == 0) || (oldestTxRootSnapshotIndex > ortsi) { | ||
oldestTxRootSnapshotIndex = ortsi | ||
} | ||
} | ||
|
||
// collect all approvees in the cone that are not confirmed, | ||
// are no solid entry points and have no recent calculation index | ||
var outdatedTransactions hornet.Hashes | ||
|
||
startTxHash := cachedTx.GetMetadata().GetTxHash() | ||
|
||
// traverse the approvees of this transaction to calculate the root snapshot indexes for this transaction. | ||
// this walk will also collect all outdated transactions in the same cone, to update them afterwards. | ||
if err := TraverseApprovees(cachedTx.GetMetadata().GetTxHash(), | ||
// traversal stops if no more transactions pass the given condition | ||
func(cachedTx *tangle.CachedTransaction) (bool, error) { // tx +1 | ||
defer cachedTx.Release(true) // tx -1 | ||
|
||
// first check if the tx was confirmed => update yrtsi and ortsi with the confirmation index | ||
if confirmed, at := cachedTx.GetMetadata().GetConfirmed(); confirmed { | ||
updateIndexes(at, at) | ||
return false, nil | ||
} | ||
|
||
if bytes.Equal(startTxHash, cachedTx.GetTransaction().GetTxHash()) { | ||
// skip the start transaction, so it doesn't get added to the outdatedTransactions | ||
return true, nil | ||
} | ||
|
||
// if the tx was not confirmed yet, but already contains recent (calculation index matches LSMI) information | ||
// about yrtsi and ortsi, propagate that info | ||
yrtsi, ortsi, rtsci := cachedTx.GetMetadata().GetRootSnapshotIndexes() | ||
if rtsci == lsmi { | ||
updateIndexes(yrtsi, ortsi) | ||
return false, nil | ||
} | ||
|
||
outdatedTransactions = append(outdatedTransactions, cachedTx.GetTransaction().GetTxHash()) | ||
|
||
return true, nil | ||
}, | ||
// consumer | ||
func(cachedTx *tangle.CachedTransaction) error { // tx +1 | ||
defer cachedTx.Release(true) // tx -1 | ||
return nil | ||
}, | ||
// called on missing approvees | ||
func(approveeHash hornet.Hash) error { | ||
return fmt.Errorf("missing approvee %v", approveeHash.Trytes()) | ||
}, | ||
// called on solid entry points | ||
func(txHash hornet.Hash) { | ||
updateIndexes(snapshotInfo.EntryPointIndex, snapshotInfo.EntryPointIndex) | ||
}, true, false, nil); err != nil { | ||
panic(err) | ||
} | ||
|
||
// update the outdated root snapshot indexes of all transactions in the cone in order from oldest txs to latest. | ||
// this is an efficient way to update the whole cone, because updating from oldest to latest will not be recursive. | ||
UpdateOutdatedRootSnapshotIndexes(outdatedTransactions, lsmi) | ||
|
||
// set the new transaction root snapshot indexes in the metadata of the transaction | ||
cachedTx.GetMetadata().SetRootSnapshotIndexes(youngestTxRootSnapshotIndex, oldestTxRootSnapshotIndex, lsmi) | ||
|
||
return youngestTxRootSnapshotIndex, oldestTxRootSnapshotIndex | ||
} | ||
|
||
// UpdateTransactionRootSnapshotIndexes updates the transaction root snapshot | ||
// indexes of the future cone of all given transactions. | ||
// all the transactions of the newly confirmed cone already have updated transaction root snapshot indexes. | ||
// we have to walk the future cone, and update the past cone of all transactions that reference an old cone. | ||
// as a special property, invocations of the yielded function share the same 'already traversed' set to circumvent | ||
// walking the future cone of the same transactions multiple times. | ||
func UpdateTransactionRootSnapshotIndexes(txHashes hornet.Hashes, lsmi milestone.Index) { | ||
traversed := map[string]struct{}{} | ||
|
||
// we update all transactions in order from oldest to latest | ||
for _, txHash := range txHashes { | ||
|
||
if err := TraverseApprovers(txHash, | ||
// traversal stops if no more transactions pass the given condition | ||
func(cachedTx *tangle.CachedTransaction) (bool, error) { // tx +1 | ||
defer cachedTx.Release(true) // tx -1 | ||
_, previouslyTraversed := traversed[string(cachedTx.GetTransaction().GetTxHash())] | ||
return !previouslyTraversed, nil | ||
}, | ||
// consumer | ||
func(cachedTx *tangle.CachedTransaction) error { // tx +1 | ||
defer cachedTx.Release(true) // tx -1 | ||
traversed[string(cachedTx.GetTransaction().GetTxHash())] = struct{}{} | ||
|
||
// updates the transaction root snapshot indexes of the outdated past cone for this transaction | ||
GetTransactionRootSnapshotIndexes(cachedTx.Retain(), lsmi) // tx pass +1 | ||
|
||
return nil | ||
}, true, nil); err != nil { | ||
panic(err) | ||
} | ||
} | ||
} |
Oops, something went wrong.