[NOD-300] If node has invalid ancestor set the according status in blockindex (#386)

* [NOD-300] If node has invalid ancestor set the according status in blockindex

* [NOD-300] Test that status is also updated for grand child of an invalid block

* [NOD-300] change make(blockSet) to newSet()
This commit is contained in:
Ori Newman 2019-08-28 17:44:33 +03:00 committed by stasatdaglabs
parent b07a118431
commit f0c80905eb
2 changed files with 117 additions and 3 deletions

View File

@ -6,11 +6,18 @@ package blockdag
import (
"fmt"
"github.com/daglabs/btcd/database"
"github.com/daglabs/btcd/util"
)
func (dag *BlockDAG) addNodeToIndexWithInvalidAncestor(block *util.Block) error {
blockHeader := &block.MsgBlock().Header
newNode := newBlockNode(blockHeader, newSet(), dag.dagParams.K)
newNode.status = statusInvalidAncestor
dag.index.AddNode(newNode)
return dag.index.flushToDB()
}
// maybeAcceptBlock potentially accepts a block into the block DAG. It
// performs several validation checks which depend on its position within
// the block DAG before adding it. The block is expected to have already
@ -21,10 +28,14 @@ import (
//
// This function MUST be called with the dagLock held (for writes).
func (dag *BlockDAG) maybeAcceptBlock(block *util.Block, flags BehaviorFlags) error {
// The height of this block is one more than the referenced previous
// block.
parents, err := lookupParentNodes(block, dag)
if err != nil {
if rErr, ok := err.(RuleError); ok && rErr.ErrorCode == ErrInvalidAncestorBlock {
err := dag.addNodeToIndexWithInvalidAncestor(block)
if err != nil {
return err
}
}
return err
}

View File

@ -1281,3 +1281,106 @@ func testFinalizeNodesBelowFinalityPoint(t *testing.T, deleteDiffData bool) {
}
}
}
func TestDAGIndexFailedStatus(t *testing.T) {
params := dagconfig.SimNetParams
dag, teardownFunc, err := DAGSetup("TestDAGIndexFailedStatus", Config{
DAGParams: &params,
})
if err != nil {
t.Fatalf("Failed to setup DAG instance: %v", err)
}
defer teardownFunc()
invalidCbTx := wire.NewSubnetworkMsgTx(wire.TxVersion, []*wire.TxIn{}, []*wire.TxOut{}, subnetworkid.SubnetworkIDCoinbase, 0, []byte{})
txs := []*util.Tx{util.NewTx(invalidCbTx)}
hashMerkleRoot := BuildHashMerkleTreeStore(txs).Root()
invalidMsgBlock := wire.NewMsgBlock(
wire.NewBlockHeader(
1,
[]*daghash.Hash{params.GenesisHash}, hashMerkleRoot,
&daghash.Hash{},
&daghash.Hash{},
dag.genesis.bits,
0),
)
invalidMsgBlock.AddTransaction(invalidCbTx)
invalidBlock := util.NewBlock(invalidMsgBlock)
isOrphan, delay, err := dag.ProcessBlock(invalidBlock, BFNoPoWCheck)
if _, ok := err.(RuleError); !ok {
t.Fatalf("ProcessBlock: expected a rule error but got %s instead", err)
}
if delay != 0 {
t.Fatalf("ProcessBlock: invalidBlock " +
"is too far in the future")
}
if isOrphan {
t.Fatalf("ProcessBlock incorrectly returned invalidBlock " +
"is an orphan\n")
}
invalidBlockNode := dag.index.LookupNode(invalidBlock.Hash())
if invalidBlockNode == nil {
t.Fatalf("invalidBlockNode wasn't added to the block index as expected")
}
if invalidBlockNode.status&statusValidateFailed != statusValidateFailed {
t.Fatalf("invalidBlockNode status to have %b flags raised (got: %b)", statusValidateFailed, invalidBlockNode.status)
}
invalidMsgBlockChild := wire.NewMsgBlock(
wire.NewBlockHeader(1, []*daghash.Hash{
invalidBlock.Hash(),
}, hashMerkleRoot, &daghash.Hash{}, &daghash.Hash{}, dag.genesis.bits, 0),
)
invalidMsgBlockChild.AddTransaction(invalidCbTx)
invalidBlockChild := util.NewBlock(invalidMsgBlockChild)
isOrphan, delay, err = dag.ProcessBlock(invalidBlockChild, BFNoPoWCheck)
if rErr, ok := err.(RuleError); !ok || rErr.ErrorCode != ErrInvalidAncestorBlock {
t.Fatalf("ProcessBlock: expected a rule error but got %s instead", err)
}
if delay != 0 {
t.Fatalf("ProcessBlock: invalidBlockChild " +
"is too far in the future")
}
if isOrphan {
t.Fatalf("ProcessBlock incorrectly returned invalidBlockChild " +
"is an orphan\n")
}
invalidBlockChildNode := dag.index.LookupNode(invalidBlockChild.Hash())
if invalidBlockChildNode == nil {
t.Fatalf("invalidBlockChild wasn't added to the block index as expected")
}
if invalidBlockChildNode.status&statusInvalidAncestor != statusInvalidAncestor {
t.Fatalf("invalidBlockNode status to have %b flags raised (got %b)", statusInvalidAncestor, invalidBlockChildNode.status)
}
invalidMsgBlockGrandChild := wire.NewMsgBlock(
wire.NewBlockHeader(1, []*daghash.Hash{
invalidBlockChild.Hash(),
}, hashMerkleRoot, &daghash.Hash{}, &daghash.Hash{}, dag.genesis.bits, 0),
)
invalidMsgBlockGrandChild.AddTransaction(invalidCbTx)
invalidBlockGrandChild := util.NewBlock(invalidMsgBlockGrandChild)
isOrphan, delay, err = dag.ProcessBlock(invalidBlockGrandChild, BFNoPoWCheck)
if rErr, ok := err.(RuleError); !ok || rErr.ErrorCode != ErrInvalidAncestorBlock {
t.Fatalf("ProcessBlock: expected a rule error but got %s instead", err)
}
if delay != 0 {
t.Fatalf("ProcessBlock: invalidBlockGrandChild " +
"is too far in the future")
}
if isOrphan {
t.Fatalf("ProcessBlock incorrectly returned invalidBlockGrandChild " +
"is an orphan\n")
}
invalidBlockGrandChildNode := dag.index.LookupNode(invalidBlockGrandChild.Hash())
if invalidBlockGrandChildNode == nil {
t.Fatalf("invalidBlockGrandChild wasn't added to the block index as expected")
}
if invalidBlockGrandChildNode.status&statusInvalidAncestor != statusInvalidAncestor {
t.Fatalf("invalidBlockGrandChildNode status to have %b flags raised (got %b)", statusInvalidAncestor, invalidBlockGrandChildNode.status)
}
}