[NOD-1557] Cover the consensusStateManager package in trace logs (#1135)

* [NOD-1557] Add trace logs in add_block_to_virtual.go.

* [NOD-1557] Add trace logs in resolve_block_status.go.

* [NOD-1557] Add trace logs in calculate_past_utxo.go.

* [NOD-1557] Add trace logs in finality.go.

* [NOD-1557] Add trace logs in multisets.go.

* [NOD-1557] Fix compilation errors.

* [NOD-1557] Add trace logs to verify_and_build_utxo.go.

* [NOD-1557] Add trace logs to update_virtual.go.

* [NOD-1557] Add trace logs to set_pruning_utxo_set.go.

* [NOD-1557] Add trace logs to populate_tx_with_utxo_entries.go.

* [NOD-1557] Add trace logs to pick_virtual_parents.go.

* [NOD-1557] Make go vet happy.

* [NOD-1557] Clarify that some logic in AddBlockToVirtual is there for the sake of logging alone.

* [NOD-1557] Call blockStatusStore directly in AddBlockToVirtual when refetching the block status.
This commit is contained in:
Mike Zak 2020-11-23 13:08:10 +02:00
parent fafe1d534f
commit 5211727206
10 changed files with 385 additions and 25 deletions

View File

@ -9,33 +9,53 @@ import (
// current virtual. This process may result in a new virtual block
// getting created
func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.DomainHash) error {
log.Tracef("AddBlockToVirtual start for block %s", blockHash)
defer log.Tracef("AddBlockToVirtual end for block %s", blockHash)
log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash)
isNextVirtualSelectedParent, err := csm.isNextVirtualSelectedParent(blockHash)
if err != nil {
return err
}
if isNextVirtualSelectedParent {
log.Tracef("Block %s is the new virtual. Resolving its block status", blockHash)
blockStatus, err := csm.resolveBlockStatus(blockHash)
if err != nil {
return err
}
if blockStatus == externalapi.StatusValid {
log.Tracef("Block %s is tentatively valid. Resolving whether it violates finality", blockHash)
err = csm.checkFinalityViolation(blockHash)
if err != nil {
return err
}
// Re-fetch the block status for logging purposes
// because it could've been changed in
// checkFinalityViolation
blockStatus, err = csm.blockStatusStore.Get(csm.databaseContext, blockHash)
if err != nil {
return err
}
}
log.Debugf("Block %s is the next virtual selected parent. "+
"Its resolved status is `%s`", blockHash, blockStatus)
} else {
log.Debugf("Block %s is not next virtual selected parent. Therefore leaving him with status `%s`",
blockHash, externalapi.StatusUTXOPendingVerification)
log.Debugf("Block %s is not the next virtual selected parent, "+
"therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification)
}
log.Tracef("Adding block %s to the DAG tips", blockHash)
newTips, err := csm.addTip(blockHash)
if err != nil {
return err
}
log.Tracef("After adding %s, the new tips are %s", blockHash, newTips)
log.Tracef("Updating the virtual with the new tips")
err = csm.updateVirtual(blockHash, newTips)
if err != nil {
return err
@ -45,7 +65,12 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai
}
func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
log.Tracef("isNextVirtualSelectedParent start for block %s", blockHash)
defer log.Tracef("isNextVirtualSelectedParent end for block %s", blockHash)
if *blockHash == *csm.genesisHash {
log.Tracef("Block %s is the genesis block, therefore it is "+
"the selected parent by definition", blockHash)
return true, nil
}
@ -54,30 +79,43 @@ func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externa
return false, err
}
log.Tracef("Selecting the next selected parent between "+
"the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent)
nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent, blockHash)
if err != nil {
return false, err
}
log.Tracef("The next selected parent is: %s", nextVirtualSelectedParent)
return *blockHash == *nextVirtualSelectedParent, nil
}
func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (newTips []*externalapi.DomainHash, err error) {
log.Tracef("addTip start for new tip %s", newTipHash)
defer log.Tracef("addTip end for new tip %s", newTipHash)
log.Tracef("Calculating the new tips for new tip %s", newTipHash)
newTips, err = csm.calculateNewTips(newTipHash)
if err != nil {
return nil, err
}
log.Tracef("The new tips are: %s", newTips)
err = csm.consensusStateStore.StageTips(newTips)
if err != nil {
return nil, err
}
log.Tracef("Staged the new tips %s", newTips)
return newTips, nil
}
func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
log.Tracef("calculateNewTips start for new tip %s", newTipHash)
defer log.Tracef("calculateNewTips end for new tip %s", newTipHash)
if *newTipHash == *csm.genesisHash {
log.Tracef("The new tip is the genesis block, therefore it is the only tip by definition")
return []*externalapi.DomainHash{newTipHash}, nil
}
@ -85,11 +123,13 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai
if err != nil {
return nil, err
}
log.Tracef("The current tips are: %s", currentTips)
newTipParents, err := csm.dagTopologyManager.Parents(newTipHash)
if err != nil {
return nil, err
}
log.Tracef("The parents of the new tip are: %s", newTipParents)
newTips := []*externalapi.DomainHash{newTipHash}
@ -105,6 +145,7 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai
newTips = append(newTips, currentTip)
}
}
log.Tracef("The calculated new tips are: %s", newTips)
return newTips, nil
}

View File

@ -1,6 +1,7 @@
package consensusstatemanager
import (
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
"github.com/pkg/errors"
@ -15,8 +16,12 @@ import (
func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (
*model.UTXODiff, model.AcceptanceData, model.Multiset, error) {
// The genesis block has an empty UTXO diff, empty acceptance data, and a blank multiset
log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash)
defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash)
if *blockHash == *csm.genesisHash {
log.Tracef("Block %s is the genesis. By definition, "+
"it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash)
return &model.UTXODiff{}, model.AcceptanceData{}, multiset.New(), nil
}
@ -24,40 +29,56 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *
if err != nil {
return nil, nil, nil, err
}
log.Tracef("Restoring the past UTXO of block %s with selectedParent %s",
blockHash, blockGHOSTDAGData.SelectedParent)
selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent)
if err != nil {
return nil, nil, nil, err
}
log.Tracef("Applying blue blocks to the selected parent past UTXO of block %s", blockHash)
acceptanceData, utxoDiff, err := csm.applyBlueBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData)
if err != nil {
return nil, nil, nil, err
}
log.Tracef("Calculating the multiset of %s", blockHash)
multiset, err := csm.calculateMultiset(acceptanceData, blockGHOSTDAGData)
if err != nil {
return nil, nil, nil, err
}
log.Tracef("The multiset of block %s resolved to: %s", blockHash, multiset.Hash())
return utxoDiff, acceptanceData, multiset, nil
}
func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainHash) (*model.UTXODiff, error) {
log.Tracef("restorePastUTXO start for block %s", blockHash)
defer log.Tracef("restorePastUTXO end for block %s", blockHash)
var err error
// collect the UTXO diffs
log.Tracef("Collecting UTXO diffs for block %s", blockHash)
var utxoDiffs []*model.UTXODiff
nextBlockHash := blockHash
for {
log.Tracef("Collecting UTXO diff for block %s", nextBlockHash)
utxoDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, nextBlockHash)
if err != nil {
return nil, err
}
utxoDiffs = append(utxoDiffs, utxoDiff)
log.Tracef("Collected UTXO diff for block %s: %s", nextBlockHash, utxoDiff)
exists, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, nextBlockHash)
if err != nil {
return nil, err
}
if !exists {
log.Tracef("Block %s does not have a UTXO diff child, "+
"meaning we reached the virtual. Returning the collected "+
"UTXO diffs: %s", nextBlockHash, utxoDiffs)
break
}
@ -66,11 +87,15 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
return nil, err
}
if nextBlockHash == nil {
log.Tracef("Block %s does not have a UTXO diff child, "+
"meaning we reached the virtual. Returning the collected "+
"UTXO diffs: %s", nextBlockHash, utxoDiffs)
break
}
}
// apply the diffs in reverse order
log.Tracef("Applying the collected UTXO diffs for block %s in reverse order", blockHash)
accumulatedDiff := model.NewUTXODiff()
for i := len(utxoDiffs) - 1; i >= 0; i-- {
accumulatedDiff, err = utxoalgebra.WithDiff(accumulatedDiff, utxoDiffs[i])
@ -78,6 +103,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
return nil, err
}
}
log.Tracef("The accumulated diff for block %s is: %s", blockHash, accumulatedDiff)
return accumulatedDiff, nil
}
@ -86,6 +112,9 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
selectedParentPastUTXODiff *model.UTXODiff, ghostdagData *model.BlockGHOSTDAGData) (
model.AcceptanceData, *model.UTXODiff, error) {
log.Tracef("applyBlueBlocks start for block %s", blockHash)
defer log.Tracef("applyBlueBlocks end for block %s", blockHash)
blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues)
if err != nil {
return nil, nil, err
@ -95,30 +124,39 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
if err != nil {
return nil, nil, err
}
log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime)
multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks))
accumulatedUTXODiff := utxoalgebra.DiffClone(selectedParentPastUTXODiff)
accumulatedMass := uint64(0)
for i, blueBlock := range blueBlocks {
blueBlockHash := consensusserialization.BlockHash(blueBlock)
log.Tracef("Applying blue block %s", blueBlockHash)
blockAcceptanceData := &model.BlockAcceptanceData{
TransactionAcceptanceData: make([]*model.TransactionAcceptanceData, len(blueBlock.Transactions)),
}
isSelectedParent := i == 0
log.Tracef("Is blue block %s the selected parent: %t", blueBlockHash, isSelectedParent)
for j, transaction := range blueBlock.Transactions {
var isAccepted bool
var fee uint64
transactionID := consensusserialization.TransactionID(transaction)
log.Tracef("Attempting to accept transaction %s in block %s",
transactionID, blueBlockHash)
isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent,
accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore)
if err != nil {
return nil, nil, err
}
log.Tracef("Transaction %s in block %s isAccepted: %t, fee: %d",
transactionID, blueBlockHash, isAccepted, transaction.Fee)
blockAcceptanceData.TransactionAcceptanceData[j] = &model.TransactionAcceptanceData{
Transaction: transaction,
Fee: fee,
Fee: transaction.Fee,
IsAccepted: isAccepted,
}
}
@ -133,6 +171,11 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap
accumulatedMassBefore uint64, selectedParentPastMedianTime int64, blockBlueScore uint64) (
isAccepted bool, accumulatedMassAfter uint64, err error) {
transactionID := consensusserialization.TransactionID(transaction)
log.Tracef("maybeAcceptTransaction start for transaction %s in block %s", transactionID, blockHash)
defer log.Tracef("maybeAcceptTransaction end for transaction %s in block %s", transactionID, blockHash)
log.Tracef("Populating transaction %s with UTXO entries", transactionID)
err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, accumulatedUTXODiff)
if err != nil {
if !errors.As(err, &(ruleerrors.RuleError{})) {
@ -145,9 +188,14 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap
// Coinbase transaction outputs are added to the UTXO-set only if they are in the selected parent chain.
if transactionhelper.IsCoinBase(transaction) {
if !isSelectedParent {
log.Tracef("Transaction %s is the coinbase of block %s "+
"but said block is not in the selected parent chain. "+
"As such, it is not accepted", transactionID, blockHash)
return false, accumulatedMassBefore, nil
}
log.Tracef("Transaction %s is the coinbase of block %s", transactionID, blockHash)
} else {
log.Tracef("Validating transaction %s in block %s", transactionID, blockHash)
err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee(
transaction, blockHash, selectedParentPastMedianTime)
if err != nil {
@ -155,15 +203,22 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap
return false, 0, err
}
log.Tracef("Validation failed for transaction %s "+
"in block %s: %s", transactionID, blockHash, err)
return false, accumulatedMassBefore, nil
}
log.Tracef("Validation passed for transaction %s in block %s", transactionID, blockHash)
log.Tracef("Check mass for transaction %s in block %s", transactionID, blockHash)
isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore)
if !isAccepted {
log.Tracef("Transaction %s in block %s has too much mass, "+
"and cannot be accepted", transactionID, blockHash)
return false, accumulatedMassBefore, nil
}
}
log.Tracef("Adding transaction %s in block %s to the accumulated diff", transactionID, blockHash)
err = utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore)
if err != nil {
return false, 0, err
@ -176,7 +231,14 @@ func (csm *consensusStateManager) checkTransactionMass(
transaction *externalapi.DomainTransaction, accumulatedMassBefore uint64) (
isAccepted bool, accumulatedMassAfter uint64) {
transactionID := consensusserialization.TransactionID(transaction)
log.Tracef("checkTransactionMass start for transaction %s", transactionID)
defer log.Tracef("checkTransactionMass end for transaction %s", transactionID)
log.Tracef("Adding transaction %s with mass %d to the "+
"so-far accumulated mass of %d", transactionID, transaction.Mass, accumulatedMassBefore)
accumulatedMassAfter = accumulatedMassBefore + transaction.Mass
log.Tracef("Accumulated mass including transaction %s: %d", transactionID, accumulatedMassAfter)
// We could potentially overflow the accumulator so check for
// overflow as well.
@ -187,7 +249,13 @@ func (csm *consensusStateManager) checkTransactionMass(
return true, accumulatedMassAfter
}
func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (model.ReadOnlyUTXOSetIterator, error) {
func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (
model.ReadOnlyUTXOSetIterator, error) {
log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash)
defer log.Tracef("RestorePastUTXOSetIterator end for block %s", blockHash)
log.Tracef("Calculating UTXO diff for block %s", blockHash)
blockDiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash)
if err != nil {
return nil, err

View File

@ -8,7 +8,12 @@ import (
func (csm *consensusStateManager) checkFinalityViolation(
blockHash *externalapi.DomainHash) error {
log.Tracef("checkFinalityViolation start for block %s", blockHash)
defer log.Tracef("checkFinalityViolation end for block %s", blockHash)
if *blockHash == *csm.genesisHash {
log.Tracef("Block %s is the genesis block, "+
"and does not violate finality by definition", blockHash)
return nil
}
@ -20,7 +25,9 @@ func (csm *consensusStateManager) checkFinalityViolation(
if isViolatingFinality {
csm.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
return nil
}
log.Tracef("Block %s does not violate finality", blockHash)
return nil
}
@ -28,21 +35,37 @@ func (csm *consensusStateManager) checkFinalityViolation(
func (csm *consensusStateManager) virtualFinalityPoint() (
*externalapi.DomainHash, error) {
return csm.dagTraversalManager.BlockAtDepth(
log.Tracef("virtualFinalityPoint start")
defer log.Tracef("virtualFinalityPoint end")
virtualFinalityPoint, err := csm.dagTraversalManager.BlockAtDepth(
model.VirtualBlockHash, csm.finalityDepth)
if err != nil {
return nil, err
}
log.Tracef("The current virtual finality block is: %s", virtualFinalityPoint)
return virtualFinalityPoint, nil
}
func (csm *consensusStateManager) isViolatingFinality(
blockHash *externalapi.DomainHash) (bool, error) {
log.Tracef("isViolatingFinality start for block %s", blockHash)
defer log.Tracef("isViolatingFinality end for block %s", blockHash)
virtualFinalityPoint, err := csm.virtualFinalityPoint()
if err != nil {
return false, err
}
log.Tracef("The virtual finality point is: %s", virtualFinalityPoint)
isInSelectedParentChain, err := csm.dagTopologyManager.IsInSelectedParentChainOf(virtualFinalityPoint, blockHash)
if err != nil {
return false, err
}
log.Tracef("Is the virtual finality point %s "+
"in the selected parent chain of %s: %t", virtualFinalityPoint, blockHash, isInSelectedParentChain)
return !isInSelectedParentChain, nil
}

View File

@ -11,7 +11,12 @@ import (
func (csm *consensusStateManager) calculateMultiset(
acceptanceData model.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) {
log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent)
defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent)
if blockGHOSTDAGData.SelectedParent == nil {
log.Tracef("Selected parent is nil, which could only happen for the genesis. " +
"The genesis, by definition, has an empty multiset")
return multiset.New(), nil
}
@ -19,21 +24,26 @@ func (csm *consensusStateManager) calculateMultiset(
if err != nil {
return nil, err
}
log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent, ms.Hash())
for _, blockAcceptanceData := range acceptanceData {
for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
transaction := transactionAcceptanceData.Transaction
transactionID := consensusserialization.TransactionID(transaction)
if !transactionAcceptanceData.IsAccepted {
log.Tracef("Skipping transaction %s because it was not accepted", transactionID)
continue
}
transaction := transactionAcceptanceData.Transaction
isCoinbase := i == 0
log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase)
var err error
err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore, isCoinbase)
if err != nil {
return nil, err
}
log.Tracef("Added transaction %s to the multiset", transactionID)
}
}
@ -43,7 +53,13 @@ func (csm *consensusStateManager) calculateMultiset(
func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.DomainTransaction,
blockBlueScore uint64, isCoinbase bool) error {
transactionID := consensusserialization.TransactionID(transaction)
log.Tracef("addTransactionToMultiset start for transaction %s", transactionID)
defer log.Tracef("addTransactionToMultiset end for transaction %s", transactionID)
for _, input := range transaction.Inputs {
log.Tracef("Removing input %s at index %d from the multiset",
input.PreviousOutpoint.TransactionID, input.PreviousOutpoint.Index)
err := removeUTXOFromMultiset(multiset, input.UTXOEntry, &input.PreviousOutpoint)
if err != nil {
return err
@ -52,7 +68,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.
for i, output := range transaction.Outputs {
outpoint := &externalapi.DomainOutpoint{
TransactionID: *consensusserialization.TransactionID(transaction),
TransactionID: *transactionID,
Index: uint32(i),
}
utxoEntry := &externalapi.UTXOEntry{
@ -61,6 +77,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.
BlockBlueScore: blockBlueScore,
IsCoinbase: isCoinbase,
}
log.Tracef("Adding input %s at index %d from the multiset", transactionID, i)
err := addUTXOToMultiset(multiset, utxoEntry, outpoint)
if err != nil {
return err

View File

@ -10,6 +10,10 @@ import (
)
func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
log.Tracef("pickVirtualParents start for tips: %s", tips)
defer log.Tracef("pickVirtualParents end for tips: %s", tips)
log.Tracef("Pushing all tips into a DownHeap")
candidatesHeap := csm.dagTraversalManager.NewDownHeap()
for _, tip := range tips {
err := candidatesHeap.Push(tip)
@ -26,6 +30,7 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH
if err != nil {
return nil, err
}
log.Tracef("The selected parent of the virtual is: %s", virtualSelectedParent)
selectedVirtualParents := hashset.NewFromSlice(virtualSelectedParent)
@ -33,28 +38,44 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH
for candidatesHeap.Len() > 0 && len(selectedVirtualParents) < constants.MaxBlockParents {
candidate := candidatesHeap.Pop()
log.Tracef("Attempting to add %s to the virtual parents", candidate)
log.Tracef("The current merge set size is %d", mergeSetSize)
mergeSetIncrease, err := csm.mergeSetIncrease(candidate, selectedVirtualParents)
if err != nil {
return nil, err
}
log.Tracef("The merge set would increase by %d with block %s", mergeSetIncrease, candidate)
if mergeSetSize+mergeSetIncrease > constants.MergeSetSizeLimit {
log.Tracef("Cannot add block %s since that would violate the merge set size limit", candidate)
continue
}
selectedVirtualParents.Add(candidate)
mergeSetSize += mergeSetIncrease
log.Tracef("Added block %s to the virtual parents set", candidate)
}
boundedMergeBreakingParents, err := csm.boundedMergeBreakingParents(selectedVirtualParents.ToSlice())
if err != nil {
return nil, err
}
log.Tracef("The following parents are omitted for "+
"breaking the bounded merge set: %s", boundedMergeBreakingParents)
return selectedVirtualParents.Subtract(boundedMergeBreakingParents).ToSlice(), nil
virtualParents := selectedVirtualParents.Subtract(boundedMergeBreakingParents).ToSlice()
log.Tracef("The virtual parents resolved to be: %s", virtualParents)
return virtualParents, nil
}
func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap model.BlockHeap) (*externalapi.DomainHash, error) {
func (csm *consensusStateManager) selectVirtualSelectedParent(
candidatesHeap model.BlockHeap) (*externalapi.DomainHash, error) {
log.Tracef("selectVirtualSelectedParent start")
defer log.Tracef("selectVirtualSelectedParent end")
disqualifiedCandidates := hashset.New()
for {
@ -63,20 +84,24 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod
}
selectedParentCandidate := candidatesHeap.Pop()
log.Tracef("Checking block %s for selected parent eligibility", selectedParentCandidate)
selectedParentCandidateStatus, err := csm.blockStatusStore.Get(csm.databaseContext, selectedParentCandidate)
if err != nil {
return nil, err
}
if selectedParentCandidateStatus == externalapi.StatusValid {
log.Tracef("Block %s is valid. Returning it as the selected parent", selectedParentCandidate)
return selectedParentCandidate, nil
}
log.Tracef("Block %s is not valid. Adding it to the disqualified set", selectedParentCandidate)
disqualifiedCandidates.Add(selectedParentCandidate)
candidateParents, err := csm.dagTopologyManager.Parents(selectedParentCandidate)
if err != nil {
return nil, err
}
log.Tracef("The parents of block %s are: %s", selectedParentCandidate, candidateParents)
for _, parent := range candidateParents {
parentChildren, err := csm.dagTopologyManager.Children(parent)
if err != nil {
@ -90,8 +115,11 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod
break
}
}
log.Tracef("The children of block %s are: %s", parent, parentChildren)
if disqualifiedCandidates.ContainsAllInSlice(parentChildren) {
log.Tracef("The disqualified set contains all the "+
"children of %s. Adding it to the candidate heap", parentChildren)
err := candidatesHeap.Push(parent)
if err != nil {
return nil, err
@ -104,6 +132,9 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod
func (csm *consensusStateManager) mergeSetIncrease(
candidate *externalapi.DomainHash, selectedVirtualParents hashset.HashSet) (int, error) {
log.Tracef("mergeSetIncrease start")
defer log.Tracef("mergeSetIncrease end")
visited := hashset.New()
queue := csm.dagTraversalManager.NewDownHeap()
err := queue.Push(candidate)
@ -114,15 +145,20 @@ func (csm *consensusStateManager) mergeSetIncrease(
for queue.Len() > 0 {
current := queue.Pop()
log.Tracef("Attempting to increment the merge set size increase for block %s", current)
isInPastOfSelectedVirtualParents, err := csm.dagTopologyManager.IsAncestorOfAny(
current, selectedVirtualParents.ToSlice())
if err != nil {
return 0, err
}
if isInPastOfSelectedVirtualParents {
log.Tracef("Skipping block %s because it's in the past of one "+
"(or more) of the selected virtual parents", current)
continue
}
log.Tracef("Incrementing the merge set size increase")
mergeSetIncrease++
parents, err := csm.dagTopologyManager.Parents(current)
@ -139,12 +175,18 @@ func (csm *consensusStateManager) mergeSetIncrease(
}
}
}
log.Tracef("The resolved merge set size increase is: %d", mergeSetIncrease)
return mergeSetIncrease, nil
}
func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externalapi.DomainHash) (hashset.HashSet, error) {
// Temporarily set virtual to all parents, so that we can run ghostdag on it
func (csm *consensusStateManager) boundedMergeBreakingParents(
parents []*externalapi.DomainHash) (hashset.HashSet, error) {
log.Tracef("boundedMergeBreakingParents start for parents: %s", parents)
defer log.Tracef("boundedMergeBreakingParents end for parents: %s", parents)
log.Tracef("Temporarily setting virtual to all parents, so that we can run ghostdag on it")
err := csm.dagTopologyManager.SetParents(model.VirtualBlockHash, parents)
if err != nil {
return nil, err
@ -159,24 +201,29 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa
if err != nil {
return nil, err
}
log.Tracef("The potentially kosherizing blocks are: %s", potentiallyKosherizingBlocks)
virtualFinalityPoint, err := csm.virtualFinalityPoint()
if err != nil {
return nil, err
}
log.Tracef("The finality point of the virtual is: %s", virtualFinalityPoint)
badReds := []*externalapi.DomainHash{}
var badReds []*externalapi.DomainHash
virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
for _, redBlock := range virtualGHOSTDAGData.MergeSetReds {
log.Tracef("Check whether red block %s is kosherized", redBlock)
isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock)
if err != nil {
return nil, err
}
if isFinalityPointInPast {
log.Tracef("Skipping red block %s because it has the virtual's"+
" finality point in its past", redBlock)
continue
}
@ -186,17 +233,21 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa
if err != nil {
return nil, err
}
log.Tracef("Red block %s is an ancestor of potentially kosherizing "+
"block %s, therefore the red block is kosher", redBlock, potentiallyKosherizingBlock)
if isKosherized {
break
}
}
if !isKosherized {
log.Tracef("Red block %s is not kosher. Adding it to the bad reds set", redBlock)
badReds = append(badReds, redBlock)
}
}
boundedMergeBreakingParents := hashset.New()
for _, parent := range parents {
log.Tracef("Checking whether parent %s breaks the bounded merge set", parent)
isBadRedInPast := false
for _, badRedBlock := range badReds {
isBadRedInPast, err = csm.dagTopologyManager.IsAncestorOf(parent, badRedBlock)
@ -204,10 +255,12 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa
return nil, err
}
if isBadRedInPast {
log.Tracef("Parent %s is an ancestor of bad red %s", parent, badRedBlock)
break
}
}
if isBadRedInPast {
log.Tracef("Adding parent %s to the bounded merge breaking parents set", parent)
boundedMergeBreakingParents.Add(parent)
}
}

View File

@ -5,6 +5,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
)
// PopulateTransactionWithUTXOEntries populates the transaction UTXO entries with data from the virtual's UTXO set.
@ -18,22 +19,31 @@ func (csm *consensusStateManager) PopulateTransactionWithUTXOEntries(transaction
func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualOrDiff(
transaction *externalapi.DomainTransaction, utxoDiff *model.UTXODiff) error {
missingOutpoints := []*externalapi.DomainOutpoint{}
transactionID := consensusserialization.TransactionID(transaction)
log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff start for transaction %s", transactionID)
defer log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff end for transaction %s", transactionID)
var missingOutpoints []*externalapi.DomainOutpoint
for _, transactionInput := range transaction.Inputs {
// skip all inputs that have a pre-filled utxo entry
if transactionInput.UTXOEntry != nil {
log.Tracef("Skipping outpoint %s:%d because it is already populated",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
continue
}
// check if utxoDiff says anything about the input's outpoint
if utxoDiff != nil {
if utxoEntry, ok := utxoalgebra.CollectionGet(utxoDiff.ToAdd, &transactionInput.PreviousOutpoint); ok {
log.Tracef("Populating outpoint %s:%d from the given utxoDiff",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
transactionInput.UTXOEntry = utxoEntry
continue
}
if utxoalgebra.CollectionContains(utxoDiff.ToRemove, &transactionInput.PreviousOutpoint) {
log.Tracef("Outpoint %s:%d is missing in the given utxoDiff",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint)
continue
}
@ -45,10 +55,14 @@ func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualO
return err
}
if !hasUTXOEntry {
log.Tracef("Outpoint %s:%d is missing in the database",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint)
continue
}
log.Tracef("Populating outpoint %s:%d from the database",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
utxoEntry, err := csm.consensusStateStore.UTXOByOutpoint(csm.databaseContext, &transactionInput.PreviousOutpoint)
if err != nil {
return err

View File

@ -9,25 +9,40 @@ import (
)
func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
// get list of all blocks in the selected parent chain that have not yet resolved their status
log.Tracef("resolveBlockStatus start for block %s", blockHash)
defer log.Tracef("resolveBlockStatus end for block %s", blockHash)
log.Tracef("Getting a list of all blocks in the selected "+
"parent chain of %s that have no yet resolved their status", blockHash)
unverifiedBlocks, err := csm.getUnverifiedChainBlocks(blockHash)
if err != nil {
return 0, err
}
log.Tracef("Got %d unverified blocks in the selected parent "+
"chain of %s: %s", len(unverifiedBlocks), blockHash, unverifiedBlocks)
// If there's no unverified blocks in the given block's chain - this means the given block already has a
// UTXO-verified status, and therefore it should be retrieved from the store and returned
if len(unverifiedBlocks) == 0 {
return csm.blockStatusStore.Get(csm.databaseContext, blockHash)
log.Tracef("There are not unverified blocks in %s's selected parent chain. "+
"This means that the block already has a UTXO-verified status.", blockHash)
status, err := csm.blockStatusStore.Get(csm.databaseContext, blockHash)
if err != nil {
return 0, err
}
log.Tracef("Block %s's status resolved to: %s", blockHash, status)
return status, nil
}
log.Tracef("Finding the status of the selected parent of %s", blockHash)
selectedParentStatus, err := csm.findSelectedParentStatus(unverifiedBlocks)
if err != nil {
return 0, err
}
log.Tracef("The status of the selected parent of %s is: %s", blockHash, selectedParentStatus)
log.Tracef("Resolving the unverified blocks' status in reverse order (past to present)")
var blockStatus externalapi.BlockStatus
// resolve the unverified blocks' statuses in opposite order
for i := len(unverifiedBlocks) - 1; i >= 0; i-- {
unverifiedBlockHash := unverifiedBlocks[i]
@ -51,8 +66,14 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma
// findSelectedParentStatus returns the status of the selectedParent of the last block in the unverifiedBlocks chain
func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*externalapi.DomainHash) (
externalapi.BlockStatus, error) {
log.Tracef("findSelectedParentStatus start")
defer log.Tracef("findSelectedParentStatus end")
lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1]
if *lastUnverifiedBlock == *csm.genesisHash {
log.Tracef("the most recent unverified block is the genesis block, "+
"which by definition has status: %s", externalapi.StatusValid)
return externalapi.StatusValid, nil
}
lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, lastUnverifiedBlock)
@ -65,17 +86,24 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e
func (csm *consensusStateManager) getUnverifiedChainBlocks(
blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
unverifiedBlocks := []*externalapi.DomainHash{}
log.Tracef("getUnverifiedChainBlocks start for block %s", blockHash)
defer log.Tracef("getUnverifiedChainBlocks end for block %s", blockHash)
var unverifiedBlocks []*externalapi.DomainHash
currentHash := blockHash
for {
log.Tracef("Getting status for block %s", currentHash)
currentBlockStatus, err := csm.blockStatusStore.Get(csm.databaseContext, currentHash)
if err != nil {
return nil, err
}
if currentBlockStatus != externalapi.StatusUTXOPendingVerification {
log.Tracef("Block %s has status %s. Returning all the "+
"unverified blocks prior to it: %s", currentHash, currentBlockStatus, unverifiedBlocks)
return unverifiedBlocks, nil
}
log.Tracef("Block %s is unverified. Adding it to the unverified block collection", currentHash)
unverifiedBlocks = append(unverifiedBlocks, currentHash)
currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, currentHash)
@ -84,7 +112,9 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks(
}
if currentBlockGHOSTDAGData.SelectedParent == nil {
return unverifiedBlocks, nil // this means we reached genesis
log.Tracef("Genesis block reached. Returning all the "+
"unverified blocks prior to it: %s", unverifiedBlocks)
return unverifiedBlocks, nil
}
currentHash = currentBlockGHOSTDAGData.SelectedParent
@ -92,11 +122,16 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks(
}
func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
log.Tracef("resolveSingleBlockStatus start for block %s", blockHash)
defer log.Tracef("resolveSingleBlockStatus end for block %s", blockHash)
log.Tracef("Calculating pastUTXO and acceptance data and multiset for block %s", blockHash)
pastUTXODiff, acceptanceData, multiset, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash)
if err != nil {
return 0, err
}
log.Tracef("Staging the calculated acceptance data of block %s", blockHash)
err = csm.acceptanceDataStore.Stage(blockHash, acceptanceData)
if err != nil {
return 0, err
@ -107,20 +142,27 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap
return 0, err
}
log.Tracef("verifying the UTXO of block %s", blockHash)
err = csm.verifyUTXO(block, blockHash, pastUTXODiff, acceptanceData, multiset)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
log.Debugf("UTXO verification for block %s failed: %s", blockHash, err)
return externalapi.StatusDisqualifiedFromChain, nil
}
return 0, err
}
log.Debugf("UTXO verification for block %s passed", blockHash)
log.Tracef("Staging the multiset of block %s", blockHash)
csm.multisetStore.Stage(blockHash, multiset)
log.Tracef("Staging the utxoDiff of block %s", blockHash)
err = csm.utxoDiffStore.Stage(blockHash, pastUTXODiff, nil)
if err != nil {
return 0, err
}
log.Tracef("Updating the parent utxoDiffs of block %s", blockHash)
err = csm.updateParentDiffs(blockHash, pastUTXODiff)
if err != nil {
return 0, err
@ -130,10 +172,15 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap
}
func (csm *consensusStateManager) updateParentDiffs(
blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error {
log.Tracef("updateParentDiffs start for block %s", blockHash)
defer log.Tracef("updateParentDiffs end for block %s", blockHash)
parentHashes, err := csm.dagTopologyManager.Parents(blockHash)
if err != nil {
return err
}
log.Tracef("Parent hashes for block %s are: %s", blockHash, parentHashes)
for _, parentHash := range parentHashes {
// skip all parents that already have a utxo-diff child
parentHasUTXODiffChild, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, parentHash)
@ -141,6 +188,8 @@ func (csm *consensusStateManager) updateParentDiffs(
return err
}
if parentHasUTXODiffChild {
log.Tracef("Skipping parent %s of block %s because it "+
"already has a UTXO diff-child", parentHash, blockHash)
continue
}
@ -149,11 +198,14 @@ func (csm *consensusStateManager) updateParentDiffs(
return err
}
if parentStatus != externalapi.StatusValid {
log.Tracef("Skipping parent %s of block %s because it "+
"has a non-valid status %s", parentHash, blockHash, parentStatus)
continue
}
// parents that till now didn't have a utxo-diff child - were actually virtual's diffParents.
// parents that didn't have a utxo-diff child until now were actually virtual's diffParents.
// Update them to have the new block as their utxo-diff child
log.Tracef("Resolving new UTXO diff of parent %s", parentHash)
parentCurrentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, parentHash)
if err != nil {
return err
@ -162,7 +214,9 @@ func (csm *consensusStateManager) updateParentDiffs(
if err != nil {
return err
}
log.Tracef("The new UTXO diff parent %s resolved to: %s", parentHash, parentNewDiff)
log.Tracef("Staging the new UTXO diff and diff child for parent %s", parentHash)
err = csm.utxoDiffStore.Stage(parentHash, parentNewDiff, blockHash)
if err != nil {
return err

View File

@ -32,10 +32,14 @@ func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byt
}
func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byte) error {
log.Tracef("setPruningPointUTXOSet start")
defer log.Tracef("setPruningPointUTXOSet end")
headerTipsPruningPoint, err := csm.HeaderTipsPruningPoint()
if err != nil {
return err
}
log.Tracef("The pruning point of the header tips is: %s", headerTipsPruningPoint)
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
@ -47,27 +51,34 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
if err != nil {
return err
}
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
headerTipsPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, headerTipsPruningPoint)
if err != nil {
return err
}
log.Tracef("The multiset in the header of the header tip pruning point: %s",
headerTipsPruningPointHeader.UTXOCommitment)
if headerTipsPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+
"point UTXO set is %s but got %s", headerTipsPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
}
log.Tracef("Header tip pruning point multiset validation passed")
log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips")
err = csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes)
if err != nil {
return err
}
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes)
if err != nil {
return err
}
log.Tracef("Staging the virtual UTXO set")
err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet))
if err != nil {
return err
@ -78,11 +89,13 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
return err
}
log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff")
err = csm.updateVirtualDiffParents(headerTipsPruningPoint, model.NewUTXODiff())
if err != nil {
return err
}
log.Tracef("Staging the status of the header tips pruning point as %s", externalapi.StatusValid)
csm.blockStatusStore.Stage(headerTipsPruningPoint, externalapi.StatusValid)
return nil
}
@ -136,18 +149,22 @@ func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.Proto
}
func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) {
log.Tracef("HeaderTipsPruningPoint start")
defer log.Tracef("HeaderTipsPruningPoint end")
headerTips, err := csm.headerTipsStore.Tips(csm.databaseContext)
if err != nil {
return nil, err
}
log.Tracef("The current header tips are: %s", headerTips)
log.Tracef("Temporarily staging the parents of the virtual header to be the header tips: %s", headerTips)
err = csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{
Parents: headerTips,
})
if err != nil {
return nil, err
}
defer csm.blockRelationStore.Discard()
err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash)
@ -156,5 +173,10 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH
}
defer csm.ghostdagDataStore.Discard()
return csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth)
pruningPoint, err := csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth)
if err != nil {
return nil, err
}
log.Tracef("The block at depth %d from %s is: %s", csm.pruningDepth, virtualHeaderHash, pruningPoint)
return pruningPoint, nil
}

View File

@ -8,38 +8,49 @@ import (
)
func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error {
log.Tracef("updateVirtual start for block %s", newBlockHash)
defer log.Tracef("updateVirtual end for block %s", newBlockHash)
log.Tracef("Picking virtual parents from the tips: %s", tips)
virtualParents, err := csm.pickVirtualParents(tips)
if err != nil {
return err
}
log.Tracef("Picked virtual parents: %s", virtualParents)
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, virtualParents)
if err != nil {
return err
}
log.Tracef("Set new parents for the virtual block hash")
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
if err != nil {
return err
}
log.Tracef("Calculating past UTXO, acceptance data, and multiset for the new virtual block")
virtualUTXODiff, virtualAcceptanceData, virtualMultiset, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash)
if err != nil {
return err
}
log.Tracef("Staging new acceptance data for the virtual block")
err = csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData)
if err != nil {
return err
}
log.Tracef("Staging new multiset for the virtual block")
csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset)
log.Tracef("Staging new UTXO diff for the virtual block")
err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff)
if err != nil {
return err
}
log.Tracef("Updating the virtual diff parents after adding %s to the DAG", newBlockHash)
err = csm.updateVirtualDiffParents(newBlockHash, virtualUTXODiff)
if err != nil {
return err
@ -51,14 +62,20 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain
func (csm *consensusStateManager) updateVirtualDiffParents(
newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error {
log.Tracef("updateVirtualDiffParents start for block %s", newBlockHash)
defer log.Tracef("updateVirtualDiffParents end for block %s", newBlockHash)
var newVirtualDiffParents []*externalapi.DomainHash
if *newBlockHash == *csm.genesisHash {
log.Tracef("Block %s is the genesis, so by definition "+
"it is the only member of the new virtual diff parents set", newBlockHash)
newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash}
} else {
oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext)
if err != nil {
return err
}
log.Tracef("The old virtual's diff parents are: %s", oldVirtualDiffParents)
// If the status of the new block is not `Valid` - virtualDiffParents didn't change
status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash)
@ -66,8 +83,11 @@ func (csm *consensusStateManager) updateVirtualDiffParents(
return err
}
if status != externalapi.StatusValid {
log.Tracef("The status of the new block %s is non-valid. "+
"As such, don't change the diff parents of the virtual", newBlockHash)
newVirtualDiffParents = oldVirtualDiffParents
} else {
log.Tracef("Block %s is valid. Updating the virtual diff parents", newBlockHash)
newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash)
if err != nil {
return err
@ -82,8 +102,10 @@ func (csm *consensusStateManager) updateVirtualDiffParents(
}
}
}
log.Tracef("The new virtual diff parents are: %s", newVirtualDiffParents)
for _, virtualDiffParent := range newVirtualDiffParents {
log.Tracef("Calculating new UTXO diff for virtual diff parent %s", virtualDiffParent)
virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent)
if err != nil {
return err
@ -92,11 +114,13 @@ func (csm *consensusStateManager) updateVirtualDiffParents(
if err != nil {
return err
}
log.Tracef("Staging new UTXO diff for virtual diff parent %s: %s", virtualDiffParent, newDiff)
err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil)
if err != nil {
return err
}
}
log.Tracef("Staging the new virtual UTXO diff parents")
return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents)
}

View File

@ -21,26 +21,38 @@ import (
func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash,
pastUTXODiff *model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error {
log.Tracef("verifyUTXO start for block %s", blockHash)
defer log.Tracef("verifyUTXO end for block %s", blockHash)
log.Tracef("Validating UTXO commitment for block %s", blockHash)
err := csm.validateUTXOCommitment(block, blockHash, multiset)
if err != nil {
return err
}
log.Tracef("UTXO commitment validation passed for block %s", blockHash)
log.Tracef("Validating acceptedIDMerkleRoot for block %s", blockHash)
err = csm.validateAcceptedIDMerkleRoot(block, blockHash, acceptanceData)
if err != nil {
return err
}
log.Tracef("AcceptedIDMerkleRoot validation passed for block %s", blockHash)
coinbaseTransaction := block.Transactions[0]
log.Tracef("Validating coinbase transaction %s for block %s",
consensusserialization.TransactionID(coinbaseTransaction), blockHash)
err = csm.validateCoinbaseTransaction(blockHash, coinbaseTransaction)
if err != nil {
return err
}
log.Tracef("Coinbase transaction validation passed for block %s", blockHash)
log.Tracef("Validating transactions against past UTXO for block %s", blockHash)
err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff, err)
if err != nil {
return err
}
log.Tracef("Transactions against past UTXO validation passed for block %s", blockHash)
return nil
}
@ -48,25 +60,38 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock,
blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, err error) error {
log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash)
defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash)
selectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(blockHash)
if err != nil {
return err
}
log.Tracef("The past median time of %s is %d", blockHash, selectedParentMedianTime)
for i, transaction := range block.Transactions {
transactionID := consensusserialization.TransactionID(transaction)
log.Tracef("Validating transaction %s in block %s against "+
"the block's past UTXO", transactionID, blockHash)
if i == transactionhelper.CoinbaseTransactionIndex {
log.Tracef("Skipping transaction %s because it is the coinbase", transactionID)
continue
}
log.Tracef("Populating transaction %s with UTXO entries", transactionID)
err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, pastUTXODiff)
if err != nil {
return err
}
log.Tracef("Validating transaction %s and populating it with mass and fee", transactionID)
err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee(
transaction, blockHash, selectedParentMedianTime)
if err != nil {
return err
}
log.Tracef("Validation against the block's past UTXO "+
"passed for transaction %s in block %s", transactionID, blockHash)
}
return nil
}
@ -74,6 +99,9 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block
func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalapi.DomainBlock,
blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error {
log.Tracef("validateAcceptedIDMerkleRoot start for block %s", blockHash)
defer log.Tracef("validateAcceptedIDMerkleRoot end for block %s", blockHash)
calculatedAcceptedIDMerkleRoot := calculateAcceptedIDMerkleRoot(acceptanceData)
if block.Header.AcceptedIDMerkleRoot != *calculatedAcceptedIDMerkleRoot {
return errors.Wrapf(ruleerrors.ErrBadMerkleRoot, "block %s accepted ID merkle root is invalid - block "+
@ -87,6 +115,9 @@ func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalap
func (csm *consensusStateManager) validateUTXOCommitment(
block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, multiset model.Multiset) error {
log.Tracef("validateUTXOCommitment start for block %s", blockHash)
defer log.Tracef("validateUTXOCommitment end for block %s", blockHash)
multisetHash := multiset.Hash()
if block.Header.UTXOCommitment != *multisetHash {
return errors.Wrapf(ruleerrors.ErrBadUTXOCommitment, "block %s UTXO commitment is invalid - block "+
@ -97,6 +128,9 @@ func (csm *consensusStateManager) validateUTXOCommitment(
}
func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData) *externalapi.DomainHash {
log.Tracef("calculateAcceptedIDMerkleRoot start")
defer log.Tracef("calculateAcceptedIDMerkleRoot end")
var acceptedTransactions []*externalapi.DomainTransaction
for _, blockAcceptanceData := range multiblockAcceptanceData {
@ -117,11 +151,18 @@ func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData
}
func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externalapi.DomainHash,
coinbaseTransaction *externalapi.DomainTransaction) error {
log.Tracef("validateCoinbaseTransaction start for block %s", blockHash)
defer log.Tracef("validateCoinbaseTransaction end for block %s", blockHash)
log.Tracef("Extracting coinbase data for coinbase transaction %s in block %s",
consensusserialization.TransactionID(coinbaseTransaction), blockHash)
_, coinbaseData, err := coinbase.ExtractCoinbaseDataAndBlueScore(coinbaseTransaction)
if err != nil {
return err
}
log.Tracef("Calculating the expected coinbase transaction for the given coinbase data and block %s", blockHash)
expectedCoinbaseTransaction, err := csm.coinbaseManager.ExpectedCoinbaseTransaction(blockHash, coinbaseData)
if err != nil {
return err
@ -129,6 +170,9 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa
coinbaseTransactionHash := consensusserialization.TransactionHash(coinbaseTransaction)
expectedCoinbaseTransactionHash := consensusserialization.TransactionHash(expectedCoinbaseTransaction)
log.Tracef("given coinbase hash: %s, expected coinbase hash: %s",
coinbaseTransactionHash, expectedCoinbaseTransactionHash)
if *coinbaseTransactionHash != *expectedCoinbaseTransactionHash {
return errors.Wrap(ruleerrors.ErrBadCoinbaseTransaction, "coinbase transaction is not built as expected")
}