mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-965] Make dag.index.LookupNode return false if node is not found * [NOD-965] Rename blockDAG->dag * [NOD-965] Remove irrelevant test * [NOD-965] Use bi.index's ok in LookupNode
137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
// Copyright (c) 2015-2017 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package blockdag
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/dbaccess"
|
|
"sync"
|
|
|
|
"github.com/kaspanet/kaspad/dagconfig"
|
|
"github.com/kaspanet/kaspad/util/daghash"
|
|
)
|
|
|
|
// blockIndex provides facilities for keeping track of an in-memory index of the
|
|
// block DAG.
|
|
type blockIndex struct {
|
|
// The following fields are set when the instance is created and can't
|
|
// be changed afterwards, so there is no need to protect them with a
|
|
// separate mutex.
|
|
dagParams *dagconfig.Params
|
|
|
|
sync.RWMutex
|
|
index map[daghash.Hash]*blockNode
|
|
dirty map[*blockNode]struct{}
|
|
}
|
|
|
|
// newBlockIndex returns a new empty instance of a block index. The index will
|
|
// be dynamically populated as block nodes are loaded from the database and
|
|
// manually added.
|
|
func newBlockIndex(dagParams *dagconfig.Params) *blockIndex {
|
|
return &blockIndex{
|
|
dagParams: dagParams,
|
|
index: make(map[daghash.Hash]*blockNode),
|
|
dirty: make(map[*blockNode]struct{}),
|
|
}
|
|
}
|
|
|
|
// HaveBlock returns whether or not the block index contains the provided hash.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (bi *blockIndex) HaveBlock(hash *daghash.Hash) bool {
|
|
bi.RLock()
|
|
defer bi.RUnlock()
|
|
_, hasBlock := bi.index[*hash]
|
|
return hasBlock
|
|
}
|
|
|
|
// LookupNode returns the block node identified by the provided hash. It will
|
|
// return nil if there is no entry for the hash.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (bi *blockIndex) LookupNode(hash *daghash.Hash) (*blockNode, bool) {
|
|
bi.RLock()
|
|
defer bi.RUnlock()
|
|
node, ok := bi.index[*hash]
|
|
return node, ok
|
|
}
|
|
|
|
// AddNode adds the provided node to the block index and marks it as dirty.
|
|
// Duplicate entries are not checked so it is up to caller to avoid adding them.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (bi *blockIndex) AddNode(node *blockNode) {
|
|
bi.Lock()
|
|
defer bi.Unlock()
|
|
bi.addNode(node)
|
|
bi.dirty[node] = struct{}{}
|
|
}
|
|
|
|
// addNode adds the provided node to the block index, but does not mark it as
|
|
// dirty. This can be used while initializing the block index.
|
|
//
|
|
// This function is NOT safe for concurrent access.
|
|
func (bi *blockIndex) addNode(node *blockNode) {
|
|
bi.index[*node.hash] = node
|
|
}
|
|
|
|
// NodeStatus provides concurrent-safe access to the status field of a node.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus {
|
|
bi.RLock()
|
|
defer bi.RUnlock()
|
|
status := node.status
|
|
return status
|
|
}
|
|
|
|
// SetStatusFlags flips the provided status flags on the block node to on,
|
|
// regardless of whether they were on or off previously. This does not unset any
|
|
// flags currently on.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) {
|
|
bi.Lock()
|
|
defer bi.Unlock()
|
|
node.status |= flags
|
|
bi.dirty[node] = struct{}{}
|
|
}
|
|
|
|
// UnsetStatusFlags flips the provided status flags on the block node to off,
|
|
// regardless of whether they were on or off previously.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) {
|
|
bi.Lock()
|
|
defer bi.Unlock()
|
|
node.status &^= flags
|
|
bi.dirty[node] = struct{}{}
|
|
}
|
|
|
|
// flushToDB writes all dirty block nodes to the database.
|
|
func (bi *blockIndex) flushToDB(dbContext *dbaccess.TxContext) error {
|
|
bi.Lock()
|
|
defer bi.Unlock()
|
|
if len(bi.dirty) == 0 {
|
|
return nil
|
|
}
|
|
|
|
for node := range bi.dirty {
|
|
serializedBlockNode, err := serializeBlockNode(node)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
key := blockIndexKey(node.hash, node.blueScore)
|
|
err = dbaccess.StoreIndexBlock(dbContext, key, serializedBlockNode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (bi *blockIndex) clearDirtyEntries() {
|
|
bi.dirty = make(map[*blockNode]struct{})
|
|
}
|