mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[NOD-648] Add TestProcessDelayedBlocks (#612)
* [NOD-648] Add TestProcessDelayedBlocks * [NOD-648] Add one second to secondsUntilDelayedBlockIsValid to make sure the delayedBlock timestamp will be valid, and add comments * [NOD-648] Remove redundant import * [NOD-648] Use fakeTimeSource instead of time.Sleep * [NOD-648] Rename dag.HaveBlock->dag.IsKnownBlock, dag.BlockExists->dag.IsInDAG * [NOD-648] Add comment * [NOD-641] Rename HaveBlock->IsKnownBlock, BlockExists->IsInDAG
This commit is contained in:
parent
aa74b51e6f
commit
41c8178ad3
@ -153,23 +153,23 @@ type BlockDAG struct {
|
||||
reachabilityStore *reachabilityStore
|
||||
}
|
||||
|
||||
// HaveBlock returns whether or not the DAG instance has the block represented
|
||||
// IsKnownBlock returns whether or not the DAG instance has the block represented
|
||||
// by the passed hash. This includes checking the various places a block can
|
||||
// be in, like part of the DAG or the orphan pool.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (dag *BlockDAG) HaveBlock(hash *daghash.Hash) bool {
|
||||
return dag.BlockExists(hash) || dag.IsKnownOrphan(hash) || dag.isKnownDelayedBlock(hash)
|
||||
func (dag *BlockDAG) IsKnownBlock(hash *daghash.Hash) bool {
|
||||
return dag.IsInDAG(hash) || dag.IsKnownOrphan(hash) || dag.isKnownDelayedBlock(hash)
|
||||
}
|
||||
|
||||
// HaveBlocks returns whether or not the DAG instances has all blocks represented
|
||||
// AreKnownBlocks returns whether or not the DAG instances has all blocks represented
|
||||
// by the passed hashes. This includes checking the various places a block can
|
||||
// be in, like part of the DAG or the orphan pool.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (dag *BlockDAG) HaveBlocks(hashes []*daghash.Hash) bool {
|
||||
func (dag *BlockDAG) AreKnownBlocks(hashes []*daghash.Hash) bool {
|
||||
for _, hash := range hashes {
|
||||
haveBlock := dag.HaveBlock(hash)
|
||||
haveBlock := dag.IsKnownBlock(hash)
|
||||
if !haveBlock {
|
||||
return false
|
||||
}
|
||||
@ -234,7 +234,7 @@ func (dag *BlockDAG) GetOrphanMissingAncestorHashes(orphanHash *daghash.Hash) ([
|
||||
queue = append(queue, parentHash)
|
||||
}
|
||||
} else {
|
||||
if !dag.BlockExists(current) && current != orphanHash {
|
||||
if !dag.IsInDAG(current) && current != orphanHash {
|
||||
missingAncestorsHashes = append(missingAncestorsHashes, current)
|
||||
}
|
||||
}
|
||||
@ -1501,7 +1501,7 @@ func (dag *BlockDAG) SelectedParentChain(blockHash *daghash.Hash) ([]*daghash.Ha
|
||||
if blockHash == nil {
|
||||
blockHash = dag.genesis.hash
|
||||
}
|
||||
if !dag.BlockExists(blockHash) {
|
||||
if !dag.IsInDAG(blockHash) {
|
||||
return nil, nil, errors.Errorf("blockHash %s does not exist in the DAG", blockHash)
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ func TestBlockCount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHaveBlock tests the HaveBlock API to ensure proper functionality.
|
||||
func TestHaveBlock(t *testing.T) {
|
||||
// TestIsKnownBlock tests the IsKnownBlock API to ensure proper functionality.
|
||||
func TestIsKnownBlock(t *testing.T) {
|
||||
// Load up blocks such that there is a fork in the DAG.
|
||||
// (genesis block) -> 1 -> 2 -> 3 -> 4
|
||||
// \-> 3b
|
||||
@ -217,9 +217,9 @@ func TestHaveBlock(t *testing.T) {
|
||||
t.Fatalf("NewHashFromStr: %v", err)
|
||||
}
|
||||
|
||||
result := dag.HaveBlock(hash)
|
||||
result := dag.IsKnownBlock(hash)
|
||||
if result != test.want {
|
||||
t.Fatalf("HaveBlock #%d got %v want %v", i, result,
|
||||
t.Fatalf("IsKnownBlock #%d got %v want %v", i, result,
|
||||
test.want)
|
||||
}
|
||||
}
|
||||
|
@ -873,7 +873,7 @@ func (dag *BlockDAG) BlockHashesFrom(lowHash *daghash.Hash, limit int) ([]*dagha
|
||||
// genesis hash in the result
|
||||
blockHashes = append(blockHashes, dag.genesis.hash)
|
||||
}
|
||||
if !dag.BlockExists(lowHash) {
|
||||
if !dag.IsInDAG(lowHash) {
|
||||
return nil, errors.Errorf("block %s not found", lowHash)
|
||||
}
|
||||
blueScore, err := dag.BlueScoreByBlockHash(lowHash)
|
||||
|
@ -48,11 +48,11 @@ const (
|
||||
BFNone BehaviorFlags = 0
|
||||
)
|
||||
|
||||
// BlockExists determines whether a block with the given hash exists in
|
||||
// IsInDAG determines whether a block with the given hash exists in
|
||||
// the DAG.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (dag *BlockDAG) BlockExists(hash *daghash.Hash) bool {
|
||||
func (dag *BlockDAG) IsInDAG(hash *daghash.Hash) bool {
|
||||
return dag.index.HaveBlock(hash)
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ func (dag *BlockDAG) processBlockNoLock(block *util.Block, flags BehaviorFlags)
|
||||
log.Tracef("Processing block %s", blockHash)
|
||||
|
||||
// The block must not already exist in the DAG.
|
||||
if dag.BlockExists(blockHash) && !wasBlockStored {
|
||||
if dag.IsInDAG(blockHash) && !wasBlockStored {
|
||||
str := fmt.Sprintf("already have block %s", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
@ -183,7 +183,7 @@ func (dag *BlockDAG) processBlockNoLock(block *util.Block, flags BehaviorFlags)
|
||||
|
||||
var missingParents []*daghash.Hash
|
||||
for _, parentHash := range block.MsgBlock().Header.ParentHashes {
|
||||
if !dag.BlockExists(parentHash) {
|
||||
if !dag.IsInDAG(parentHash) {
|
||||
missingParents = append(missingParents, parentHash)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@ -69,3 +71,168 @@ func TestProcessOrphans(t *testing.T) {
|
||||
t.Fatalf("TestProcessOrphans: child block erroneously not marked as invalid")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeTimeSource struct {
|
||||
time time.Time
|
||||
}
|
||||
|
||||
func (fts *fakeTimeSource) AdjustedTime() time.Time {
|
||||
return fts.time
|
||||
}
|
||||
|
||||
func (fts *fakeTimeSource) AddTimeSample(_ string, _ time.Time) {
|
||||
}
|
||||
|
||||
func (fts *fakeTimeSource) Offset() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
||||
func TestProcessDelayedBlocks(t *testing.T) {
|
||||
// We use dag1 so we can build the test blocks with the proper
|
||||
// block header (UTXO commitment, acceptedIDMerkleroot, etc), and
|
||||
// then we use dag2 for the actual test.
|
||||
dag1, teardownFunc, err := DAGSetup("TestProcessDelayedBlocks1", Config{
|
||||
DAGParams: &dagconfig.SimnetParams,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup DAG instance: %v", err)
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
initialTime := dag1.dagParams.GenesisBlock.Header.Timestamp
|
||||
// Here we use a fake time source that returns a timestamp
|
||||
// one hour into the future to make delayedBlock artificially
|
||||
// valid.
|
||||
dag1.timeSource = &fakeTimeSource{initialTime.Add(time.Hour)}
|
||||
|
||||
delayedBlock, err := PrepareBlockForTest(dag1, []*daghash.Hash{dag1.dagParams.GenesisBlock.BlockHash()}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error in PrepareBlockForTest: %s", err)
|
||||
}
|
||||
|
||||
blockDelay := time.Duration(dag1.dagParams.TimestampDeviationTolerance+5) * time.Second
|
||||
delayedBlock.Header.Timestamp = initialTime.Add(blockDelay)
|
||||
|
||||
isOrphan, isDelayed, err := dag1.ProcessBlock(util.NewBlock(delayedBlock), BFNoPoWCheck)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessBlock returned unexpected error: %s\n", err)
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("ProcessBlock incorrectly returned delayedBlock " +
|
||||
"is an orphan\n")
|
||||
}
|
||||
if isDelayed {
|
||||
t.Fatalf("ProcessBlock incorrectly returned delayedBlock " +
|
||||
"is delayed\n")
|
||||
}
|
||||
|
||||
delayedBlockChild, err := PrepareBlockForTest(dag1, []*daghash.Hash{delayedBlock.BlockHash()}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error in PrepareBlockForTest: %s", err)
|
||||
}
|
||||
|
||||
// Here the actual test begins. We add a delayed block and
|
||||
// its child and check that they are not added to the DAG,
|
||||
// and check that they're added only if we add a new block
|
||||
// after the delayed block timestamp is valid.
|
||||
dag2, teardownFunc2, err := DAGSetup("TestProcessDelayedBlocks2", Config{
|
||||
DAGParams: &dagconfig.SimnetParams,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup DAG instance: %v", err)
|
||||
}
|
||||
defer teardownFunc2()
|
||||
dag2.timeSource = &fakeTimeSource{initialTime}
|
||||
|
||||
isOrphan, isDelayed, err = dag2.ProcessBlock(util.NewBlock(delayedBlock), BFNoPoWCheck)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessBlock returned unexpected error: %s\n", err)
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("ProcessBlock incorrectly returned delayedBlock " +
|
||||
"is an orphan\n")
|
||||
}
|
||||
if !isDelayed {
|
||||
t.Fatalf("ProcessBlock incorrectly returned delayedBlock " +
|
||||
"is not delayed\n")
|
||||
}
|
||||
|
||||
if dag2.IsInDAG(delayedBlock.BlockHash()) {
|
||||
t.Errorf("dag.IsInDAG should return false for a delayed block")
|
||||
}
|
||||
if !dag2.IsKnownBlock(delayedBlock.BlockHash()) {
|
||||
t.Errorf("dag.IsKnownBlock should return true for a a delayed block")
|
||||
}
|
||||
|
||||
isOrphan, isDelayed, err = dag2.ProcessBlock(util.NewBlock(delayedBlockChild), BFNoPoWCheck)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessBlock returned unexpected error: %s\n", err)
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("ProcessBlock incorrectly returned delayedBlockChild " +
|
||||
"is an orphan\n")
|
||||
}
|
||||
if !isDelayed {
|
||||
t.Fatalf("ProcessBlock incorrectly returned delayedBlockChild " +
|
||||
"is not delayed\n")
|
||||
}
|
||||
|
||||
if dag2.IsInDAG(delayedBlockChild.BlockHash()) {
|
||||
t.Errorf("dag.IsInDAG should return false for a child of a delayed block")
|
||||
}
|
||||
if !dag2.IsKnownBlock(delayedBlockChild.BlockHash()) {
|
||||
t.Errorf("dag.IsKnownBlock should return true for a child of a delayed block")
|
||||
}
|
||||
|
||||
blockBeforeDelay, err := PrepareBlockForTest(dag2, []*daghash.Hash{dag2.dagParams.GenesisBlock.BlockHash()}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error in PrepareBlockForTest: %s", err)
|
||||
}
|
||||
isOrphan, isDelayed, err = dag2.ProcessBlock(util.NewBlock(blockBeforeDelay), BFNoPoWCheck)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessBlock returned unexpected error: %s\n", err)
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("ProcessBlock incorrectly returned blockBeforeDelay " +
|
||||
"is an orphan\n")
|
||||
}
|
||||
if isDelayed {
|
||||
t.Fatalf("ProcessBlock incorrectly returned blockBeforeDelay " +
|
||||
"is delayed\n")
|
||||
}
|
||||
|
||||
if dag2.IsInDAG(delayedBlock.BlockHash()) {
|
||||
t.Errorf("delayedBlock shouldn't be added to the DAG because its time hasn't reached yet")
|
||||
}
|
||||
if dag2.IsInDAG(delayedBlockChild.BlockHash()) {
|
||||
t.Errorf("delayedBlockChild shouldn't be added to the DAG because its parent is not in the DAG")
|
||||
}
|
||||
|
||||
// We advance the clock to the point where delayedBlock timestamp is valid.
|
||||
secondsUntilDelayedBlockIsValid := delayedBlock.Header.Timestamp.Unix() - int64(dag2.TimestampDeviationTolerance) - dag2.AdjustedTime().Unix() + 1
|
||||
dag2.timeSource = &fakeTimeSource{initialTime.Add(time.Duration(secondsUntilDelayedBlockIsValid) * time.Second)}
|
||||
|
||||
blockAfterDelay, err := PrepareBlockForTest(dag2, []*daghash.Hash{dag2.dagParams.GenesisBlock.BlockHash()}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error in PrepareBlockForTest: %s", err)
|
||||
}
|
||||
isOrphan, isDelayed, err = dag2.ProcessBlock(util.NewBlock(blockAfterDelay), BFNoPoWCheck)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessBlock returned unexpected error: %s\n", err)
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("ProcessBlock incorrectly returned blockBeforeDelay " +
|
||||
"is an orphan\n")
|
||||
}
|
||||
if isDelayed {
|
||||
t.Fatalf("ProcessBlock incorrectly returned blockBeforeDelay " +
|
||||
"is not delayed\n")
|
||||
}
|
||||
|
||||
if !dag2.IsInDAG(delayedBlock.BlockHash()) {
|
||||
t.Fatalf("delayedBlock should be added to the DAG because its time has been reached")
|
||||
}
|
||||
if !dag2.IsInDAG(delayedBlockChild.BlockHash()) {
|
||||
t.Errorf("delayedBlockChild shouldn't be added to the DAG because its parent has been added to the DAG")
|
||||
}
|
||||
}
|
||||
|
@ -101,14 +101,14 @@ func (bi *blockImporter) processBlock(serializedBlock []byte) (bool, error) {
|
||||
|
||||
// Skip blocks that already exist.
|
||||
blockHash := block.Hash()
|
||||
if bi.dag.HaveBlock(blockHash) {
|
||||
if bi.dag.IsKnownBlock(blockHash) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Don't bother trying to process orphans.
|
||||
parentHashes := block.MsgBlock().Header.ParentHashes
|
||||
if len(parentHashes) > 0 {
|
||||
if !bi.dag.HaveBlocks(parentHashes) {
|
||||
if !bi.dag.AreKnownBlocks(parentHashes) {
|
||||
return false, errors.Errorf("import file contains block "+
|
||||
"%v which does not link to the available "+
|
||||
"block DAG", parentHashes)
|
||||
|
@ -591,7 +591,7 @@ func (sm *SyncManager) haveInventory(invVect *wire.InvVect) (bool, error) {
|
||||
fallthrough
|
||||
case wire.InvTypeBlock:
|
||||
// Ask DAG if the block is known to it in any form (in DAG or as an orphan).
|
||||
return sm.dag.HaveBlock(invVect.Hash), nil
|
||||
return sm.dag.IsKnownBlock(invVect.Hash), nil
|
||||
|
||||
case wire.InvTypeTx:
|
||||
// Ask the transaction memory pool if the transaction is known
|
||||
|
@ -198,9 +198,9 @@ type Config struct {
|
||||
// to the peer as needed.
|
||||
SelectedTipHash func() *daghash.Hash
|
||||
|
||||
// BlockExists determines whether a block with the given hash exists in
|
||||
// IsInDAG determines whether a block with the given hash exists in
|
||||
// the DAG.
|
||||
BlockExists func(*daghash.Hash) bool
|
||||
IsInDAG func(*daghash.Hash) bool
|
||||
|
||||
// HostToNetAddress returns the netaddress for the given host. This can be
|
||||
// nil in which case the host will be parsed as an IP address.
|
||||
@ -662,7 +662,7 @@ func (p *Peer) SetSelectedTipHash(selectedTipHash *daghash.Hash) {
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (p *Peer) IsSelectedTipKnown() bool {
|
||||
return !p.cfg.BlockExists(p.selectedTipHash)
|
||||
return !p.cfg.IsInDAG(p.selectedTipHash)
|
||||
}
|
||||
|
||||
// LastSend returns the last send time of the peer.
|
||||
|
@ -21,7 +21,7 @@ func (sp *Peer) OnBlockLocator(_ *peer.Peer, msg *wire.MsgBlockLocator) {
|
||||
// If the first hash of the block locator is known, it means we found
|
||||
// the highest shared block.
|
||||
highHash := msg.BlockLocatorHashes[0]
|
||||
if dag.BlockExists(highHash) {
|
||||
if dag.IsInDAG(highHash) {
|
||||
if dag.IsKnownFinalizedBlock(highHash) {
|
||||
peerLog.Debugf("Cannot sync with peer %s because the highest"+
|
||||
" shared chain block (%s) is below the finality point", sp, highHash)
|
||||
|
@ -304,7 +304,7 @@ func (sp *Peer) selectedTipHash() *daghash.Hash {
|
||||
// blockExists determines whether a block with the given hash exists in
|
||||
// the DAG.
|
||||
func (sp *Peer) blockExists(hash *daghash.Hash) bool {
|
||||
return sp.server.DAG.BlockExists(hash)
|
||||
return sp.server.DAG.IsInDAG(hash)
|
||||
}
|
||||
|
||||
// addKnownAddresses adds the given addresses to the set of known addresses to
|
||||
@ -1052,7 +1052,7 @@ func newPeerConfig(sp *Peer) *peer.Config {
|
||||
OnWrite: sp.OnWrite,
|
||||
},
|
||||
SelectedTipHash: sp.selectedTipHash,
|
||||
BlockExists: sp.blockExists,
|
||||
IsInDAG: sp.blockExists,
|
||||
HostToNetAddress: sp.server.addrManager.HostToNetAddress,
|
||||
Proxy: config.ActiveConfig().Proxy,
|
||||
UserAgentName: userAgentName,
|
||||
|
@ -29,7 +29,7 @@ func handleGetBlocks(s *Server, cmd interface{}, closeChan <-chan struct{}) (int
|
||||
defer s.cfg.DAG.RUnlock()
|
||||
|
||||
// If lowHash is not in the DAG, there's nothing to do; return an error.
|
||||
if lowHash != nil && !s.cfg.DAG.HaveBlock(lowHash) {
|
||||
if lowHash != nil && !s.cfg.DAG.IsKnownBlock(lowHash) {
|
||||
return nil, &rpcmodel.RPCError{
|
||||
Code: rpcmodel.ErrRPCBlockNotFound,
|
||||
Message: "Block not found",
|
||||
|
@ -38,7 +38,7 @@ func handleGetChainFromBlock(s *Server, cmd interface{}, closeChan <-chan struct
|
||||
|
||||
// If startHash is not in the selected parent chain, there's nothing
|
||||
// to do; return an error.
|
||||
if startHash != nil && !s.cfg.DAG.BlockExists(startHash) {
|
||||
if startHash != nil && !s.cfg.DAG.IsInDAG(startHash) {
|
||||
return nil, &rpcmodel.RPCError{
|
||||
Code: rpcmodel.ErrRPCBlockNotFound,
|
||||
Message: "Block not found in the DAG",
|
||||
|
Loading…
x
Reference in New Issue
Block a user