mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-06 14:16:43 +00:00
Add finality check to ResolveVirtual (#2041)
* Add finality check to ResolveVirtual * Warn on finality conflict only if needed
This commit is contained in:
parent
7390651072
commit
c839337425
@ -485,3 +485,136 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
test(consensusConfig.MergeDepth, consensusConfig.GenesisHash, true, true)
|
test(consensusConfig.MergeDepth, consensusConfig.GenesisHash, true, true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFinalityResolveVirtual(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
// Set finalityInterval to 20 blocks, so that test runs quickly
|
||||||
|
consensusConfig.FinalityDuration = 20 * consensusConfig.TargetTimePerBlock
|
||||||
|
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestFinalityResolveVirtual")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
tip := consensusConfig.GenesisHash
|
||||||
|
for {
|
||||||
|
tip, _, err = tc.AddBlock([]*externalapi.DomainHash{tip}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualFinalityPoint, err := tc.FinalityManager().VirtualFinalityPoint(model.NewStagingArea())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !virtualFinalityPoint.Equal(consensusConfig.GenesisHash) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcAttacker, teardownAttacker, err := factory.NewTestConsensus(consensusConfig, "TestFinalityResolveVirtual_attacker")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer teardownAttacker(false)
|
||||||
|
|
||||||
|
virtualSelectedParent, err := tc.GetVirtualSelectedParent()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stagingArea := model.NewStagingArea()
|
||||||
|
virtualSelectedParentGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), stagingArea, virtualSelectedParent, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Selected tip blue score %d", virtualSelectedParentGHOSTDAGData.BlueScore())
|
||||||
|
|
||||||
|
sideChain := make([]*externalapi.DomainBlock, 0)
|
||||||
|
|
||||||
|
for i := uint64(0); ; i++ {
|
||||||
|
tips, err := tcAttacker.Tips()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _, err := tcAttacker.BuildBlockWithParents(tips, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We change the nonce of the first block so its hash won't be similar to any of the
|
||||||
|
// honest DAG blocks. As a result the rest of the side chain should have unique hashes
|
||||||
|
// as well.
|
||||||
|
if i == 0 {
|
||||||
|
mutableHeader := block.Header.ToMutable()
|
||||||
|
mutableHeader.SetNonce(uint64(rand.NewSource(84147).Int63()))
|
||||||
|
block.Header = mutableHeader.ToImmutable()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tcAttacker.ValidateAndInsertBlock(block, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sideChain = append(sideChain, block)
|
||||||
|
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
ghostdagData, err := tcAttacker.GHOSTDAGDataStore().Get(tcAttacker.DatabaseContext(), stagingArea, blockHash, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if virtualSelectedParentGHOSTDAGData.BlueWork().Cmp(ghostdagData.BlueWork()) == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sideChainTipHash := consensushashing.BlockHash(sideChain[len(sideChain)-1])
|
||||||
|
sideChainTipGHOSTDAGData, err := tcAttacker.GHOSTDAGDataStore().Get(tcAttacker.DatabaseContext(), stagingArea, sideChainTipHash, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Side chain tip (%s) blue score %d", sideChainTipHash, sideChainTipGHOSTDAGData.BlueScore())
|
||||||
|
|
||||||
|
for _, block := range sideChain {
|
||||||
|
_, err := tc.ValidateAndInsertBlock(block, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
_, isCompletelyResolved, err := tc.ResolveVirtual()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCompletelyResolved {
|
||||||
|
t.Log("Resolved virtual")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sideChainTipGHOSTDAGData, err = tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), stagingArea, sideChainTipHash, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Side chain tip (%s) blue score %d", sideChainTipHash, sideChainTipGHOSTDAGData.BlueScore())
|
||||||
|
|
||||||
|
newVirtualSelectedParent, err := tc.GetVirtualSelectedParent()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !newVirtualSelectedParent.Equal(virtualSelectedParent) {
|
||||||
|
t.Fatalf("A finality reorg has happened")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -37,6 +37,19 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
|
|||||||
isCompletelyResolved := true
|
isCompletelyResolved := true
|
||||||
for _, tip := range tips {
|
for _, tip := range tips {
|
||||||
log.Debugf("Resolving tip %s", tip)
|
log.Debugf("Resolving tip %s", tip)
|
||||||
|
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(readStagingArea, tip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isViolatingFinality {
|
||||||
|
if shouldNotify {
|
||||||
|
//TODO: Send finality conflict notification
|
||||||
|
log.Warnf("Skipping %s tip resolution because it violates finality", tip)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
resolveStagingArea := model.NewStagingArea()
|
resolveStagingArea := model.NewStagingArea()
|
||||||
unverifiedBlocks, err := csm.getUnverifiedChainBlocks(resolveStagingArea, tip)
|
unverifiedBlocks, err := csm.getUnverifiedChainBlocks(resolveStagingArea, tip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user