Add TestFinality back (#1129)

* Add VirtualFinalityPoint to TestConsensusStateManager

* Add TestFinality back
This commit is contained in:
Elichai Turkel 2020-11-22 12:30:27 +02:00 committed by GitHub
parent 950dd0cc8d
commit b3a3121725
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 174 additions and 0 deletions

View File

@ -0,0 +1,169 @@
package consensus
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/dagconfig"
"testing"
)
func TestFinality(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
// Set finalityInterval to 50 blocks, so that test runs quickly
params.FinalityDuration = 50 * params.TargetTimePerBlock
factory := NewFactory()
consensus, teardown, err := factory.NewTestConsensus(params, "TestFinality")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
buildAndInsertBlock := func(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) {
block, err := consensus.BuildBlockWithParents(parentHashes, nil, nil)
if err != nil {
return nil, err
}
err = consensus.ValidateAndInsertBlock(block)
if err != nil {
return nil, err
}
return block, nil
}
// Build a chain of `finalityInterval - 1` blocks
finalityInterval := params.FinalityDepth()
var mainChainTip *externalapi.DomainBlock
mainChainTipHash := params.GenesisHash
for i := uint64(0); i < finalityInterval-1; i++ {
mainChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{mainChainTipHash})
if err != nil {
t.Fatalf("TestFinality: Failed to process Block #%d: %v", i, err)
}
mainChainTipHash = consensusserialization.BlockHash(mainChainTip)
blockInfo, err := consensus.GetBlockInfo(mainChainTipHash)
if err != nil {
t.Fatalf("TestFinality: Block #%d failed to get info: %v", i, err)
}
if blockInfo.BlockStatus != externalapi.StatusValid {
t.Fatalf("Block #%d in main chain expected to have status '%s', but got '%s'",
i, externalapi.StatusValid, blockInfo.BlockStatus)
}
}
// Mine another chain of `finality-Interval - 2` blocks
var sideChainTip *externalapi.DomainBlock
sideChainTipHash := params.GenesisHash
for i := uint64(0); i < finalityInterval-2; i++ {
sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash})
if err != nil {
t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err)
}
sideChainTipHash = consensusserialization.BlockHash(sideChainTip)
blockInfo, err := consensus.GetBlockInfo(sideChainTipHash)
if err != nil {
t.Fatalf("TestFinality: Block #%d failed to get info: %v", i, err)
} else if !blockInfo.Exists {
t.Fatalf("TestFinality: Failed getting block info, doesn't exists")
}
if blockInfo.BlockStatus != externalapi.StatusUTXOPendingVerification {
t.Fatalf("Block #%d in side chain expected to have status '%s', but got '%s'",
i, externalapi.StatusUTXOPendingVerification, blockInfo.BlockStatus)
}
}
// Add two more blocks in the side-chain until it becomes the selected chain
for i := uint64(0); i < 2; i++ {
sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash})
if err != nil {
t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err)
}
sideChainTipHash = consensusserialization.BlockHash(sideChainTip)
}
// Make sure that now the sideChainTip is valid and selectedTip
blockInfo, err := consensus.GetBlockInfo(sideChainTipHash)
if err != nil {
t.Fatalf("TestFinality: Failed to get block info: %v", err)
} else if !blockInfo.Exists {
t.Fatalf("TestFinality: Failed getting block info, doesn't exists")
}
if blockInfo.BlockStatus != externalapi.StatusValid {
t.Fatalf("TestFinality: Overtaking block in side-chain expected to have status '%s', but got '%s'",
externalapi.StatusValid, blockInfo.BlockStatus)
}
selectedTip, err := consensus.GetVirtualSelectedParent()
if err != nil {
t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err)
}
if *consensusserialization.BlockHash(selectedTip) != *sideChainTipHash {
t.Fatalf("Overtaking block in side-chain is not selectedTip")
}
// Add two more blocks to main chain, to move finality point to first non-genesis block in mainChain
for i := uint64(0); i < 2; i++ {
mainChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{mainChainTipHash})
if err != nil {
t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err)
}
mainChainTipHash = consensusserialization.BlockHash(mainChainTip)
}
virtualFinality, err := consensus.ConsensusStateManager().VirtualFinalityPoint()
if err != nil {
t.Fatalf("TestFinality: Failed getting the virtual's finality point: %v", err)
}
if *virtualFinality == *params.GenesisHash {
t.Fatalf("virtual's finalityPoint is still genesis after adding finalityInterval + 1 blocks to the main chain")
}
// TODO: Make sure that a finality conflict notification is sent
// Add two more blocks to the side chain, so that it violates finality and gets status UTXOPendingVerification even
// though it is the block with the highest blue score.
for i := uint64(0); i < 2; i++ {
sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash})
if err != nil {
t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err)
}
sideChainTipHash = consensusserialization.BlockHash(sideChainTip)
}
// Check that sideChainTip hash higher blue score than the selected parent
selectedTip, err = consensus.GetVirtualSelectedParent()
if err != nil {
t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err)
}
selectedTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), consensusserialization.BlockHash(selectedTip))
if err != nil {
t.Fatalf("TestFinality: Failed getting the ghost dag data of the selected tip: %v", err)
}
sideChainTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), sideChainTipHash)
if err != nil {
t.Fatalf("TestFinality: Failed getting the ghost dag data of the sidechain tip: %v", err)
}
if selectedTipGhostDagData.BlueScore > sideChainTipGhostDagData.BlueScore {
t.Fatalf("sideChainTip is not the bluest tip when it is expected to be")
}
// Blocks violating finality should have a UTXOPendingVerification status
blockInfo, err = consensus.GetBlockInfo(sideChainTipHash)
if err != nil {
t.Fatalf("TestFinality: Failed to get block info: %v", err)
} else if !blockInfo.Exists {
t.Fatalf("TestFinality: Failed getting block info, doesn't exists")
}
if blockInfo.BlockStatus != externalapi.StatusUTXOPendingVerification {
t.Fatalf("TestFinality: Finality violating block expected to have status '%s', but got '%s'",
externalapi.StatusUTXOPendingVerification, blockInfo.BlockStatus)
}
})
}

View File

@ -18,4 +18,5 @@ type TestConsensusStateManager interface {
AddUTXOToMultiset(multiset Multiset, entry *externalapi.UTXOEntry,
outpoint *externalapi.DomainOutpoint) error
ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error)
VirtualFinalityPoint() (*externalapi.DomainHash, error)
}

View File

@ -23,3 +23,7 @@ func (csm testConsensusStateManager) AddUTXOToMultiset(
func (csm testConsensusStateManager) ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
return csm.resolveBlockStatus(blockHash)
}
func (csm testConsensusStateManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) {
return csm.virtualFinalityPoint()
}