diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 2f683b688..08010e623 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" ) +// AddOrphan adds the block to the orphan set func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphansMutex.Lock() defer f.orphansMutex.Unlock() @@ -14,6 +15,7 @@ func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphans[*orphanHash] = orphanBlock } +// UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore. func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*externalapi.DomainBlock, error) { f.orphansMutex.Lock() defer f.orphansMutex.Unlock() diff --git a/domain/consensus/database/serialization/blues_anticone_sizes.go b/domain/consensus/database/serialization/blues_anticone_sizes.go index 1b2359b61..19f526e02 100644 --- a/domain/consensus/database/serialization/blues_anticone_sizes.go +++ b/domain/consensus/database/serialization/blues_anticone_sizes.go @@ -10,8 +10,9 @@ func bluesAnticoneSizesToDBBluesAnticoneSizes(bluesAnticoneSizes map[externalapi dbBluesAnticoneSizes := make([]*DbBluesAnticoneSizes, len(bluesAnticoneSizes)) i := 0 for hash, anticoneSize := range bluesAnticoneSizes { + hashCopy := hash dbBluesAnticoneSizes[i] = &DbBluesAnticoneSizes{ - BlueHash: DomainHashToDbHash(&hash), + BlueHash: DomainHashToDbHash(&hashCopy), AnticoneSize: uint32(anticoneSize), } i++ diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index 550a0fc67..e3df498ce 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // DAGTraversalManager exposes methods for traversing blocks // in the DAG type DAGTraversalManager interface { - HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) + BlockAtDepth(highHash *externalapi.DomainHash, depth uint64) (*externalapi.DomainHash, error) LowestChainBlockAboveOrEqualToBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) SelectedParentIterator(highHash *externalapi.DomainHash) BlockIterator SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 57204c2d7..7b9236160 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -99,12 +99,7 @@ func (bb *testBlockBuilder) buildBlockWithParents( return nil, err } - selectedParentStatus, err := bb.testConsensus.BlockStatusStore().Get(bb.databaseContext, ghostdagData.SelectedParent) - if err != nil { - return nil, err - } - - selectedParentStatus, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 7cbef09cb..417468732 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -159,6 +159,9 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap } isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore) + if !isAccepted { + return false, accumulatedMassBefore, nil + } } err = utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore) diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go index c63bd449a..f568733de 100644 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ b/domain/consensus/processes/consensusstatemanager/finality.go @@ -28,20 +28,8 @@ func (csm *consensusStateManager) checkFinalityViolation( func (csm *consensusStateManager) virtualFinalityPoint() ( *externalapi.DomainHash, error) { - virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - - finalityPointBlueScore := virtualGHOSTDAGData.BlueScore - csm.finalityDepth - if virtualGHOSTDAGData.BlueScore < csm.finalityDepth { - // if there's no `csm.finalityDepth` blocks in the DAG - // practically - returns the genesis - finalityPointBlueScore = 0 - } - - return csm.dagTraversalManager.HighestChainBlockBelowBlueScore( - model.VirtualBlockHash, finalityPointBlueScore) + return csm.dagTraversalManager.BlockAtDepth( + model.VirtualBlockHash, csm.finalityDepth) } func (csm *consensusStateManager) isViolatingFinality( diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 74926f69d..59a65a9ab 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -156,14 +156,5 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH } defer csm.ghostdagDataStore.Discard() - virtualHeaderGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, virtualHeaderHash) - if err != nil { - return nil, err - } - - blueScore := virtualHeaderGHOSTDAGData.BlueScore - csm.pruningDepth - if csm.pruningDepth > virtualHeaderGHOSTDAGData.BlueScore { - blueScore = 0 - } - return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(virtualHeaderHash, blueScore) + return csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth) } diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 1379c8263..bc157f78d 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -64,17 +64,21 @@ func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.Dom } } -// HighestChainBlockBelowBlueScore returns the hash of the -// highest block with a blue score lower than the given -// blueScore in the selected-parent-chain of the block -// with the given highHash's selected parent chain -func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, requiredBlueScore uint64) (*externalapi.DomainHash, error) { +// BlockAtDepth returns the hash of the highest block with a blue score +// lower than (highHash.blueSore - depth) in the selected-parent-chain +// of the block with the given highHash's selected parent chain. +func (dtm *dagTraversalManager) BlockAtDepth(highHash *externalapi.DomainHash, depth uint64) (*externalapi.DomainHash, error) { currentBlockHash := highHash highBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash) if err != nil { return nil, err } + requiredBlueScore := uint64(0) + if highBlockGHOSTDAGData.BlueScore > depth { + requiredBlueScore = highBlockGHOSTDAGData.BlueScore - depth + } + currentBlockGHOSTDAGData := highBlockGHOSTDAGData // If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore for currentBlockGHOSTDAGData.BlueScore >= requiredBlueScore { diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 3c3ba65c1..6a13f01be 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -12,25 +12,156 @@ import ( ) func TestBlueBlockWindow(t *testing.T) { - testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestBlueBlockWindow") - if err != nil { - t.Fatalf("NewTestConsensus: %s", err) - } - defer tearDown() - - windowSize := uint64(10) - blockByIDMap := make(map[string]*externalapi.DomainHash) - idByBlockMap := make(map[externalapi.DomainHash]string) - blockByIDMap["A"] = params.GenesisHash - idByBlockMap[*params.GenesisHash] = "A" - - blocksData := []*struct { - parents []string - id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash - expectedWindowWithGenesisPadding []string - }{ + tests := map[string][]*struct { + parents []string + id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash + expectedWindowWithGenesisPadding []string + }{ + "kaspa-mainnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + }, + }, + "kaspa-testnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + }, + }, + "kaspa-devnet": { { parents: []string{"A"}, id: "B", @@ -101,7 +232,96 @@ func TestBlueBlockWindow(t *testing.T) { id: "O", expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, }, + }, + "kaspa-simnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + }, + }, + } + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.K = 1 + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestBlueBlockWindow") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) } + defer tearDown() + + windowSize := uint64(10) + blockByIDMap := make(map[string]*externalapi.DomainHash) + idByBlockMap := make(map[externalapi.DomainHash]string) + blockByIDMap["A"] = params.GenesisHash + idByBlockMap[*params.GenesisHash] = "A" + + blocksData := tests[params.Name] for _, blockData := range blocksData { parents := hashset.New() @@ -112,7 +332,7 @@ func TestBlueBlockWindow(t *testing.T) { block, err := tc.AddBlock(parents.ToSlice(), nil, nil) if err != nil { - t.Fatalf("AddBlock: %s", err) + t.Fatalf("AddBlock: %+v", err) } blockByIDMap[blockData.id] = block diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index 41419ade6..cbf29f331 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -50,7 +50,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma return nil } - finalityPoint, err := mdm.finalityPoint(ghostdagData) + finalityPoint, err := mdm.finalityPoint(blockHash) if err != nil { return err } @@ -88,7 +88,7 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues)) for _, blue := range ghostdagData.MergeSetBlues { - notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(ghostdagData, blue) + notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(blockHash, blue) if err != nil { return nil, err } @@ -101,8 +101,8 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter return nonBoundedMergeDepthViolatingBlues, nil } -func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(ghostdagData *model.BlockGHOSTDAGData, other *externalapi.DomainHash) (bool, error) { - finalityPoint, err := mdm.finalityPoint(ghostdagData) +func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(this, other *externalapi.DomainHash) (bool, error) { + finalityPoint, err := mdm.finalityPoint(this) if err != nil { return false, err } @@ -110,6 +110,6 @@ func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(ghostdagData return mdm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint, other) } -func (mdm *mergeDepthManager) finalityPoint(ghostdagData *model.BlockGHOSTDAGData) (*externalapi.DomainHash, error) { - return mdm.dagTraversalManager.HighestChainBlockBelowBlueScore(ghostdagData.SelectedParent, ghostdagData.BlueScore-mdm.finalityDepth) +func (mdm *mergeDepthManager) finalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + return mdm.dagTraversalManager.BlockAtDepth(blockHash, mdm.finalityDepth) } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index edc9766e7..36c397dc2 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -98,7 +98,7 @@ func (pm *pruningManager) FindNextPruningPoint() error { } // get Virtual(pruningDepth) - candidatePHash, err := pm.dagTraversalManager.HighestChainBlockBelowBlueScore(model.VirtualBlockHash, pm.pruningDepth) + candidatePHash, err := pm.dagTraversalManager.BlockAtDepth(model.VirtualBlockHash, pm.pruningDepth) if err != nil { return err } diff --git a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go index d0036b8bb..255780fe0 100644 --- a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go +++ b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go @@ -152,6 +152,9 @@ func (mna *MinimalNetAdapter) handleHandshake(routes *Routes, ourID *id.ID) erro err = routes.OutgoingRoute.Enqueue(&appmessage.MsgAddresses{ AddressList: []*appmessage.NetAddress{}, }) + if err != nil { + return err + } err = routes.OutgoingRoute.Enqueue(&appmessage.MsgRequestAddresses{ IncludeAllSubnetworks: true,