[NOD-616] Remove blockNode.chainHeight (#586)

* [NOD-616] Remove unused methods from BlockDAG.

* [NOD-616] Remove Height from GetRawMempoolVerboseResult and TxDesc.

* [NOD-616] Replaced BlockDAG.ChainHeight with SelectedTipBlueScore.

* [NOD-616] Remove the unused BlockChainHeightByHash.

* [NOD-616] Remove the unused blockChainHeight from checkBlockHeaderContext.

* [NOD-616] Remove chainHeight from util.Block.

* [NOD-616] Remove TestChainHeight.

* [NOD-616] Update unknown rule activation warning to use blueScore.

* [NOD-616] Update thresholdState to use blueScore instead of chainHeight.

* [NOD-616] Update blockLocator to use blueScore instead of chainHeight.

* [NOD-616] Remove blockNode.chainHeight.

* [NOD-616] Fix comments and variable names.

* [NOD-616] Replace a weird for loop with a while loop.

* [NOD-616] Fix a comment.

* [NOD-616] Remove pre-allocation in blockLocator.

* [NOD-616] Coalesce checks that startHash and stopHash are not the same into the same condition.

* [NOD-616] Fix a comment.

* [NOD-616] Remove weird blueScore logic around childHashStrings.

* [NOD-616] Fix hash pointer comparison.

* [NOD-616] Fix a comment.

* [NOD-616] Add ban score to peers misusing GetBlockLocator.

* [NOD-616] Replace adding ban score with disconnecting.

* [NOD-616] Add blueScore to FilteredBlockAddedNtfn.
This commit is contained in:
stasatdaglabs 2020-01-16 13:09:16 +02:00 committed by Svarog
parent 8b8e73feb5
commit 359b16fca9
28 changed files with 136 additions and 626 deletions

View File

@ -80,7 +80,7 @@ func (dag *BlockDAG) maybeAcceptBlock(block *util.Block, flags BehaviorFlags) er
}
}
block.SetChainHeight(newNode.chainHeight)
block.SetBlueScore(newNode.blueScore)
// Connect the passed block to the DAG. This also handles validation of the
// transaction scripts.

View File

@ -19,7 +19,7 @@ func TestAncestorErrors(t *testing.T) {
defer teardownFunc()
node := newTestNode(dag, newSet(), int32(0x10000000), 0, time.Unix(0, 0))
node.chainHeight = 2
node.blueScore = 2
ancestor := node.SelectedAncestor(3)
if ancestor != nil {
t.Errorf("TestAncestorErrors: Ancestor() unexpectedly returned a node. Expected: <nil>")

View File

@ -1,8 +1,8 @@
package blockdag
import (
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/daghash"
"github.com/pkg/errors"
)
// BlockLocator is used to help locate a specific block. The algorithm for
@ -29,7 +29,7 @@ type BlockLocator []*daghash.Hash
// known.
//
// This function is safe for concurrent access.
func (dag *BlockDAG) BlockLocatorFromHashes(startHash, stopHash *daghash.Hash) BlockLocator {
func (dag *BlockDAG) BlockLocatorFromHashes(startHash, stopHash *daghash.Hash) (BlockLocator, error) {
dag.dagLock.RLock()
defer dag.dagLock.RUnlock()
startNode := dag.index.LookupNode(startHash)
@ -40,15 +40,6 @@ func (dag *BlockDAG) BlockLocatorFromHashes(startHash, stopHash *daghash.Hash) B
return dag.blockLocator(startNode, stopNode)
}
// LatestBlockLocator returns a block locator for the current tips of the DAG.
//
// This function is safe for concurrent access.
func (dag *BlockDAG) LatestBlockLocator() BlockLocator {
dag.dagLock.RLock()
defer dag.dagLock.RUnlock()
return dag.blockLocator(nil, nil)
}
// blockLocator returns a block locator for the passed start and stop nodes.
// The default value for the start node is the selected tip, and the default
// values of the stop node is the genesis block.
@ -56,7 +47,7 @@ func (dag *BlockDAG) LatestBlockLocator() BlockLocator {
// See the BlockLocator type comments for more details.
//
// This function MUST be called with the DAG state lock held (for reads).
func (dag *BlockDAG) blockLocator(startNode, stopNode *blockNode) BlockLocator {
func (dag *BlockDAG) blockLocator(startNode, stopNode *blockNode) (BlockLocator, error) {
// Use the selected tip if requested.
if startNode == nil {
startNode = dag.virtual.selectedParent
@ -70,51 +61,36 @@ func (dag *BlockDAG) blockLocator(startNode, stopNode *blockNode) BlockLocator {
// block locator won't contain the start node.
startNode = startNode.selectedParent
// If the start node or the stop node are not in the
// virtual's selected parent chain, we replace them with their
// closest selected parent that is part of the virtual's
// selected parent chain.
for !dag.IsInSelectedParentChain(stopNode.hash) {
stopNode = stopNode.selectedParent
}
for !dag.IsInSelectedParentChain(startNode.hash) {
startNode = startNode.selectedParent
}
// Calculate the max number of entries that will ultimately be in the
// block locator. See the description of the algorithm for how these
// numbers are derived.
// startNode.hash + stopNode.hash.
// Then floor(log2(startNode.chainHeight-stopNode.chainHeight)) entries for the skip portion.
maxEntries := 2 + util.FastLog2Floor(startNode.chainHeight-stopNode.chainHeight)
locator := make(BlockLocator, 0, maxEntries)
node := startNode
step := uint64(1)
for node := startNode; node != nil; {
locator := make(BlockLocator, 0)
for node != nil {
locator = append(locator, node.hash)
// Nothing more to add once the stop node has been added.
if node.chainHeight == stopNode.chainHeight {
if node.blueScore <= stopNode.blueScore {
if node != stopNode {
return nil, errors.Errorf("startNode and stopNode are " +
"not in the same selected parent chain.")
}
break
}
// Calculate chainHeight of previous node to include ensuring the
// Calculate blueScore of previous node to include ensuring the
// final node is stopNode.
nextChainHeight := node.chainHeight - step
if nextChainHeight < stopNode.chainHeight {
nextChainHeight = stopNode.chainHeight
nextBlueScore := node.blueScore - step
if nextBlueScore < stopNode.blueScore {
nextBlueScore = stopNode.blueScore
}
// walk backwards through the nodes to the correct ancestor.
node = node.SelectedAncestor(nextChainHeight)
node = node.SelectedAncestor(nextBlueScore)
// Double the distance between included hashes.
step *= 2
}
return locator
return locator, nil
}
// FindNextLocatorBoundaries returns the lowest unknown block locator, hash

View File

@ -83,9 +83,6 @@ type blockNode struct {
// hash is the double sha 256 of the block.
hash *daghash.Hash
// chainHeight is the number of hops you need to go down the selected parent chain in order to get to the genesis block.
chainHeight uint64
// Some fields from block headers to aid in reconstructing headers
// from memory. These must be treated as immutable and are intentionally
// ordered to avoid padding on 64-bit platforms.
@ -107,13 +104,6 @@ type blockNode struct {
isFinalized bool
}
func calculateChainHeight(node *blockNode) uint64 {
if node.isGenesis() {
return 0
}
return node.selectedParent.chainHeight + 1
}
// newBlockNode returns a new block node for the given block header and parents, and the
// anticone of its selected parent (parent with highest blue score).
// selectedParentAnticone is used to update reachability data we store for future reachability queries.
@ -146,7 +136,6 @@ func (dag *BlockDAG) newBlockNode(blockHeader *wire.BlockHeader, parents blockSe
if err != nil {
panic(errors.Wrap(err, "unexpected error in GHOSTDAG"))
}
node.chainHeight = calculateChainHeight(node)
}
return node, selectedParentAnticone
}
@ -183,31 +172,31 @@ func (node *blockNode) Header() *wire.BlockHeader {
}
}
// SelectedAncestor returns the ancestor block node at the provided chain-height by following
// SelectedAncestor returns the ancestor block node at the provided blue score by following
// the selected-parents chain backwards from this node. The returned block will be nil when a
// height is requested that is after the height of the passed node.
// blue score is requested that is higher than the blue score of the passed node.
//
// This function is safe for concurrent access.
func (node *blockNode) SelectedAncestor(chainHeight uint64) *blockNode {
if chainHeight < 0 || chainHeight > node.chainHeight {
func (node *blockNode) SelectedAncestor(blueScore uint64) *blockNode {
if blueScore < 0 || blueScore > node.blueScore {
return nil
}
n := node
for ; n != nil && n.chainHeight != chainHeight; n = n.selectedParent {
// Intentionally left blank
for n != nil && n.blueScore > blueScore {
n = n.selectedParent
}
return n
}
// RelativeAncestor returns the ancestor block node a relative 'distance' of
// chain-blocks before this node. This is equivalent to calling Ancestor with
// the node's chain-height minus provided distance.
// blue blocks before this node. This is equivalent to calling Ancestor with
// the node's blue score minus provided distance.
//
// This function is safe for concurrent access.
func (node *blockNode) RelativeAncestor(distance uint64) *blockNode {
return node.SelectedAncestor(node.chainHeight - distance)
return node.SelectedAncestor(node.blueScore - distance)
}
// CalcPastMedianTime returns the median time of the previous few blocks

View File

@ -1,97 +0,0 @@
package blockdag
import (
"github.com/kaspanet/kaspad/dagconfig"
"github.com/kaspanet/kaspad/wire"
"testing"
)
func TestChainHeight(t *testing.T) {
// Create a new database and DAG instance to run tests against.
params := dagconfig.SimnetParams
params.K = 2
dag, teardownFunc, err := DAGSetup("TestChainHeight", Config{
DAGParams: &params,
})
if err != nil {
t.Fatalf("TestChainHeight: Failed to setup DAG instance: %s", err)
}
defer teardownFunc()
block0 := dag.dagParams.GenesisBlock
block1 := prepareAndProcessBlock(t, dag, block0)
block2 := prepareAndProcessBlock(t, dag, block0)
block3 := prepareAndProcessBlock(t, dag, block0)
block4 := prepareAndProcessBlock(t, dag, block1, block2, block3)
block5 := prepareAndProcessBlock(t, dag, block1, block2, block3)
block6 := prepareAndProcessBlock(t, dag, block1, block2, block3)
block7 := prepareAndProcessBlock(t, dag, block0)
block8 := prepareAndProcessBlock(t, dag, block7)
block9 := prepareAndProcessBlock(t, dag, block8)
block10 := prepareAndProcessBlock(t, dag, block9, block6)
// Because nodes 7 & 8 were mined secretly, block10's selected
// parent will be block6, although block9 is higher. So in this
// case, block10.height and block10.chainHeight will be different
tests := []struct {
block *wire.MsgBlock
expectedChainHeight uint64
}{
{
block: block0,
expectedChainHeight: 0,
},
{
block: block1,
expectedChainHeight: 1,
},
{
block: block2,
expectedChainHeight: 1,
},
{
block: block3,
expectedChainHeight: 1,
},
{
block: block4,
expectedChainHeight: 2,
},
{
block: block5,
expectedChainHeight: 2,
},
{
block: block6,
expectedChainHeight: 2,
},
{
block: block7,
expectedChainHeight: 1,
},
{
block: block8,
expectedChainHeight: 2,
},
{
block: block9,
expectedChainHeight: 3,
},
{
block: block10,
expectedChainHeight: 3,
},
}
for _, test := range tests {
node := dag.index.LookupNode(test.block.BlockHash())
if node.chainHeight != test.expectedChainHeight {
t.Errorf("block %s expected chain height %v but got %v", node, test.expectedChainHeight, node.chainHeight)
}
if calculateChainHeight(node) != test.expectedChainHeight {
t.Errorf("block %s expected calculated chain height %v but got %v", node, test.expectedChainHeight, node.chainHeight)
}
}
}

View File

@ -1516,10 +1516,9 @@ func (dag *BlockDAG) SelectedParentChain(startHash *daghash.Hash) ([]*daghash.Ha
return removedChainHashes, addedChainHashes, nil
}
// ChainHeight return the chain-height of the selected tip. In other words - it returns
// the length of the dag's selected-parent chain
func (dag *BlockDAG) ChainHeight() uint64 {
return dag.selectedTip().chainHeight
// SelectedTipBlueScore returns the blue score of the selected tip.
func (dag *BlockDAG) SelectedTipBlueScore() uint64 {
return dag.selectedTip().blueScore
}
// VirtualBlueScore returns the blue score of the current virtual block
@ -1561,20 +1560,6 @@ func (dag *BlockDAG) HeaderByHash(hash *daghash.Hash) (*wire.BlockHeader, error)
return node.Header(), nil
}
// BlockChainHeightByHash returns the chain height of the block with the given
// hash in the DAG.
//
// This function is safe for concurrent access.
func (dag *BlockDAG) BlockChainHeightByHash(hash *daghash.Hash) (uint64, error) {
node := dag.index.LookupNode(hash)
if node == nil {
str := fmt.Sprintf("block %s is not in the DAG", hash)
return 0, errNotInDAG(str)
}
return node.chainHeight, nil
}
// ChildHashesByHash returns the child hashes of the block with the given hash in the
// DAG.
//
@ -1608,81 +1593,6 @@ func (dag *BlockDAG) SelectedParentHash(blockHash *daghash.Hash) (*daghash.Hash,
return node.selectedParent.hash, nil
}
// ChainHeightToHashRange returns a range of block hashes for the given start chain
// height and end hash, inclusive on both ends. The hashes are for all blocks that
// are ancestors of endHash with height greater than or equal to startChainHeight.
// The end hash must belong to a block that is known to be valid.
//
// This function is safe for concurrent access.
func (dag *BlockDAG) ChainHeightToHashRange(startChainHeight uint64,
endHash *daghash.Hash, maxResults int) ([]*daghash.Hash, error) {
endNode := dag.index.LookupNode(endHash)
if endNode == nil {
return nil, errors.Errorf("no known block header with hash %s", endHash)
}
if !dag.index.NodeStatus(endNode).KnownValid() {
return nil, errors.Errorf("block %s is not yet validated", endHash)
}
endChainHeight := endNode.chainHeight
if startChainHeight < 0 {
return nil, errors.Errorf("start chain height (%d) is below 0", startChainHeight)
}
if startChainHeight > endChainHeight {
return nil, errors.Errorf("start chain height (%d) is past end chain height (%d)",
startChainHeight, endChainHeight)
}
resultsLength := int(endChainHeight - startChainHeight + 1)
if resultsLength > maxResults {
return nil, errors.Errorf("number of results (%d) would exceed max (%d)",
resultsLength, maxResults)
}
// Walk backwards from endChainHeight to startChainHeight, collecting block hashes.
node := endNode
hashes := make([]*daghash.Hash, resultsLength)
for i := resultsLength - 1; i >= 0; i-- {
hashes[i] = node.hash
node = node.selectedParent
}
return hashes, nil
}
// IntervalBlockHashes returns hashes for all blocks that are ancestors of
// endHash where the block height is a positive multiple of interval.
//
// This function is safe for concurrent access.
func (dag *BlockDAG) IntervalBlockHashes(endHash *daghash.Hash, interval uint64,
) ([]*daghash.Hash, error) {
endNode := dag.index.LookupNode(endHash)
if endNode == nil {
return nil, errors.Errorf("no known block header with hash %s", endHash)
}
if !dag.index.NodeStatus(endNode).KnownValid() {
return nil, errors.Errorf("block %s is not yet validated", endHash)
}
endChainHeight := endNode.chainHeight
resultsLength := endChainHeight / interval
hashes := make([]*daghash.Hash, resultsLength)
dag.virtual.mtx.Lock()
defer dag.virtual.mtx.Unlock()
blockNode := endNode
for index := endChainHeight / interval; index > 0; index-- {
blockHeight := index * interval
blockNode = blockNode.SelectedAncestor(blockHeight)
hashes[index-1] = blockNode.hash
}
return hashes, nil
}
// getBlueBlocksHashesBetween returns the hashes of the blocks after the provided
// start hash until the provided stop hash is reached, or up to the
// provided max number of block hashes.
@ -2055,8 +1965,8 @@ func New(config *Config) (*BlockDAG, error) {
}
selectedTip := dag.selectedTip()
log.Infof("DAG state (chain height %d, hash %s)",
selectedTip.chainHeight, selectedTip.hash)
log.Infof("DAG state (blue score %d, hash %s)",
selectedTip.blueScore, selectedTip.hash)
return dag, nil
}

View File

@ -8,12 +8,9 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
"time"
"math/rand"
"github.com/kaspanet/kaspad/dagconfig"
"github.com/kaspanet/kaspad/database"
"github.com/kaspanet/kaspad/txscript"
@ -271,7 +268,7 @@ func TestCalcSequenceLock(t *testing.T) {
TxID: *targetTx.ID(),
Index: 0,
}
prevUtxoChainHeight := uint64(numBlocksToGenerate) - 4
prevUtxoBlueScore := uint64(numBlocksToGenerate) - 4
// Obtain the past median time from the PoV of the input created above.
// The past median time for the input is the past median time from the PoV
@ -283,7 +280,7 @@ func TestCalcSequenceLock(t *testing.T) {
// the MTP will be calculated from the PoV of the yet-to-be-mined
// block.
nextMedianTime := node.PastMedianTime(dag).Unix()
nextBlockChainHeight := int32(numBlocksToGenerate) + 1
nextBlockBlueScore := int32(numBlocksToGenerate) + 1
// Add an additional transaction which will serve as our unconfirmed
// output.
@ -369,7 +366,7 @@ func TestCalcSequenceLock(t *testing.T) {
utxoSet: utxoSet,
want: &SequenceLock{
Seconds: medianTime + (5 << wire.SequenceLockTimeGranularity) - 1,
BlockBlueScore: int64(prevUtxoChainHeight) + 3,
BlockBlueScore: int64(prevUtxoBlueScore) + 3,
},
},
// Transaction with a single input. The input's sequence number
@ -382,7 +379,7 @@ func TestCalcSequenceLock(t *testing.T) {
utxoSet: utxoSet,
want: &SequenceLock{
Seconds: -1,
BlockBlueScore: int64(prevUtxoChainHeight) + 2,
BlockBlueScore: int64(prevUtxoBlueScore) + 2,
},
},
// A transaction with two inputs with lock times expressed in
@ -421,7 +418,7 @@ func TestCalcSequenceLock(t *testing.T) {
utxoSet: utxoSet,
want: &SequenceLock{
Seconds: -1,
BlockBlueScore: int64(prevUtxoChainHeight) + 10,
BlockBlueScore: int64(prevUtxoBlueScore) + 10,
},
},
// A transaction with multiple inputs. Two inputs are time
@ -447,7 +444,7 @@ func TestCalcSequenceLock(t *testing.T) {
utxoSet: utxoSet,
want: &SequenceLock{
Seconds: medianTime + (13 << wire.SequenceLockTimeGranularity) - 1,
BlockBlueScore: int64(prevUtxoChainHeight) + 8,
BlockBlueScore: int64(prevUtxoBlueScore) + 8,
},
},
// A transaction with a single unconfirmed input. As the input
@ -463,7 +460,7 @@ func TestCalcSequenceLock(t *testing.T) {
mempool: true,
want: &SequenceLock{
Seconds: -1,
BlockBlueScore: int64(nextBlockChainHeight) + 1,
BlockBlueScore: int64(nextBlockBlueScore) + 1,
},
},
// A transaction with a single unconfirmed input. The input has
@ -544,214 +541,6 @@ func TestCalcPastMedianTime(t *testing.T) {
t.Errorf("TestCalcPastMedianTime: expected past median time of block %v to be %v seconds from genesis but got %v", test.blockNumber, test.expectedSecondsSinceGenesis, secondsSinceGenesis)
}
}
}
// nodeHashes is a convenience function that returns the hashes for all of the
// passed indexes of the provided nodes. It is used to construct expected hash
// slices in the tests.
func nodeHashes(nodes []*blockNode, indexes ...int) []*daghash.Hash {
hashes := make([]*daghash.Hash, 0, len(indexes))
for _, idx := range indexes {
hashes = append(hashes, nodes[idx].hash)
}
return hashes
}
// testNoncePrng provides a deterministic prng for the nonce in generated fake
// nodes. The ensures that the node have unique hashes.
var testNoncePrng = rand.New(rand.NewSource(0))
// chainedNodes returns the specified number of nodes constructed such that each
// subsequent node points to the previous one to create a chain. The first node
// will point to the passed parent which can be nil if desired.
func chainedNodes(dag *BlockDAG, parents blockSet, numNodes int) []*blockNode {
nodes := make([]*blockNode, numNodes)
tips := parents
for i := 0; i < numNodes; i++ {
// This is invalid, but all that is needed is enough to get the
// synthetic tests to work.
header := wire.BlockHeader{
Nonce: testNoncePrng.Uint64(),
HashMerkleRoot: &daghash.ZeroHash,
AcceptedIDMerkleRoot: &daghash.ZeroHash,
UTXOCommitment: &daghash.ZeroHash,
}
header.ParentHashes = tips.hashes()
nodes[i], _ = dag.newBlockNode(&header, tips)
tips = setFromSlice(nodes[i])
}
return nodes
}
// testTip is a convenience function to grab the tip of a chain of block nodes
// created via chainedNodes.
func testTip(nodes []*blockNode) *blockNode {
return nodes[len(nodes)-1]
}
// TestChainHeightToHashRange ensures that fetching a range of block hashes by start
// chain height and end hash works as expected.
func TestChainHeightToHashRange(t *testing.T) {
// Construct a synthetic block DAG with a block index consisting of
// the following structure.
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a -> 18a (unvalidated)
tip := testTip
dag := newTestDAG(&dagconfig.SimnetParams)
branch0Nodes := chainedNodes(dag, setFromSlice(dag.genesis), 18)
branch1Nodes := chainedNodes(dag, setFromSlice(branch0Nodes[14]), 3)
for _, node := range branch0Nodes {
dag.index.SetStatusFlags(node, statusValid)
dag.index.AddNode(node)
}
for _, node := range branch1Nodes {
if node.chainHeight < 18 {
dag.index.SetStatusFlags(node, statusValid)
}
dag.index.AddNode(node)
}
dag.virtual.SetTips(setFromSlice(tip(branch0Nodes)))
tests := []struct {
name string
startChainHeight uint64 // locator for requested inventory
endHash *daghash.Hash // stop hash for locator
maxResults int // max to locate, 0 = wire const
hashes []*daghash.Hash // expected located hashes
expectError bool
}{
{
name: "blocks below tip",
startChainHeight: 11,
endHash: branch0Nodes[14].hash,
maxResults: 10,
hashes: nodeHashes(branch0Nodes, 10, 11, 12, 13, 14),
},
{
name: "blocks on main chain",
startChainHeight: 15,
endHash: branch0Nodes[17].hash,
maxResults: 10,
hashes: nodeHashes(branch0Nodes, 14, 15, 16, 17),
},
{
name: "blocks on stale chain",
startChainHeight: 15,
endHash: branch1Nodes[1].hash,
maxResults: 10,
hashes: append(nodeHashes(branch0Nodes, 14),
nodeHashes(branch1Nodes, 0, 1)...),
},
{
name: "invalid start chain height",
startChainHeight: 19,
endHash: branch0Nodes[17].hash,
maxResults: 10,
expectError: true,
},
{
name: "too many results",
startChainHeight: 1,
endHash: branch0Nodes[17].hash,
maxResults: 10,
expectError: true,
},
{
name: "unvalidated block",
startChainHeight: 15,
endHash: branch1Nodes[2].hash,
maxResults: 10,
expectError: true,
},
}
for _, test := range tests {
hashes, err := dag.ChainHeightToHashRange(test.startChainHeight, test.endHash,
test.maxResults)
if err != nil {
if !test.expectError {
t.Errorf("%s: unexpected error: %v", test.name, err)
}
continue
}
if !reflect.DeepEqual(hashes, test.hashes) {
t.Errorf("%s: unxpected hashes -- got %v, want %v",
test.name, hashes, test.hashes)
}
}
}
// TestIntervalBlockHashes ensures that fetching block hashes at specified
// intervals by end hash works as expected.
func TestIntervalBlockHashes(t *testing.T) {
// Construct a synthetic block DAG with a block index consisting of
// the following structure.
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a -> 18a (unvalidated)
tip := testTip
dag := newTestDAG(&dagconfig.SimnetParams)
branch0Nodes := chainedNodes(dag, setFromSlice(dag.genesis), 18)
branch1Nodes := chainedNodes(dag, setFromSlice(branch0Nodes[14]), 3)
for _, node := range branch0Nodes {
dag.index.SetStatusFlags(node, statusValid)
dag.index.AddNode(node)
}
for _, node := range branch1Nodes {
if node.chainHeight < 18 {
dag.index.SetStatusFlags(node, statusValid)
}
dag.index.AddNode(node)
}
dag.virtual.SetTips(setFromSlice(tip(branch0Nodes)))
tests := []struct {
name string
endHash *daghash.Hash
interval uint64
hashes []*daghash.Hash
expectError bool
}{
{
name: "blocks on main chain",
endHash: branch0Nodes[17].hash,
interval: 8,
hashes: nodeHashes(branch0Nodes, 7, 15),
},
{
name: "blocks on stale chain",
endHash: branch1Nodes[1].hash,
interval: 8,
hashes: append(nodeHashes(branch0Nodes, 7),
nodeHashes(branch1Nodes, 0)...),
},
{
name: "no results",
endHash: branch0Nodes[17].hash,
interval: 20,
hashes: []*daghash.Hash{},
},
{
name: "unvalidated block",
endHash: branch1Nodes[2].hash,
interval: 8,
expectError: true,
},
}
for _, test := range tests {
hashes, err := dag.IntervalBlockHashes(test.endHash, test.interval)
if err != nil {
if !test.expectError {
t.Errorf("%s: unexpected error: %v", test.name, err)
}
continue
}
if !reflect.DeepEqual(hashes, test.hashes) {
t.Errorf("%s: unxpected hashes -- got %v, want %v",
test.name, hashes, test.hashes)
}
}
}
func TestNew(t *testing.T) {

View File

@ -717,8 +717,6 @@ func (dag *BlockDAG) deserializeBlockNode(blockRow []byte) (*blockNode, error) {
}
}
node.chainHeight = calculateChainHeight(node)
return node, nil
}

View File

@ -130,15 +130,15 @@ func (dag *BlockDAG) thresholdState(prevNode *blockNode, checker thresholdCondit
// The threshold state for the window that contains the genesis block is
// defined by definition.
confirmationWindow := checker.MinerConfirmationWindow()
if prevNode == nil || (prevNode.chainHeight+1) < confirmationWindow {
if prevNode == nil || (prevNode.blueScore+1) < confirmationWindow {
return ThresholdDefined, nil
}
// Get the ancestor that is the last block of the previous confirmation
// window in order to get its threshold state. This can be done because
// the state is the same for all blocks within a given window.
prevNode = prevNode.SelectedAncestor(prevNode.chainHeight -
(prevNode.chainHeight+1)%confirmationWindow)
prevNode = prevNode.SelectedAncestor(prevNode.blueScore -
(prevNode.blueScore+1)%confirmationWindow)
// Iterate backwards through each of the previous confirmation windows
// to find the most recently cached threshold state.

View File

@ -555,7 +555,7 @@ func (dag *BlockDAG) checkBlockSanity(block *util.Block, flags BehaviorFlags) (t
// - BFFastAdd: No checks are performed.
//
// This function MUST be called with the dag state lock held (for writes).
func (dag *BlockDAG) checkBlockHeaderContext(header *wire.BlockHeader, bluestParent *blockNode, blockChainHeight uint64, fastAdd bool) error {
func (dag *BlockDAG) checkBlockHeaderContext(header *wire.BlockHeader, bluestParent *blockNode, fastAdd bool) error {
if !fastAdd {
if err := dag.validateDifficulty(header, bluestParent); err != nil {
return err
@ -661,7 +661,7 @@ func (dag *BlockDAG) checkBlockContext(block *util.Block, parents blockSet, flag
// Perform all block header related validation checks.
header := &block.MsgBlock().Header
if err = dag.checkBlockHeaderContext(header, bluestParent, block.ChainHeight(), fastAdd); err != nil {
if err = dag.checkBlockHeaderContext(header, bluestParent, fastAdd); err != nil {
return err
}

View File

@ -28,35 +28,35 @@ func TestSequenceLocksActive(t *testing.T) {
}
tests := []struct {
seqLock *SequenceLock
blockChainHeight uint64
mtp time.Time
seqLock *SequenceLock
blockBlueScore uint64
mtp time.Time
want bool
}{
// Block based sequence lock with equal block height.
{seqLock: seqLock(1000, -1), blockChainHeight: 1001, mtp: time.Unix(9, 0), want: true},
// Block based sequence lock with equal block blue score.
{seqLock: seqLock(1000, -1), blockBlueScore: 1001, mtp: time.Unix(9, 0), want: true},
// Time based sequence lock with mtp past the absolute time.
{seqLock: seqLock(-1, 30), blockChainHeight: 2, mtp: time.Unix(31, 0), want: true},
{seqLock: seqLock(-1, 30), blockBlueScore: 2, mtp: time.Unix(31, 0), want: true},
// Block based sequence lock with current height below seq lock block height.
{seqLock: seqLock(1000, -1), blockChainHeight: 90, mtp: time.Unix(9, 0), want: false},
// Block based sequence lock with current blue score below seq lock block blue score.
{seqLock: seqLock(1000, -1), blockBlueScore: 90, mtp: time.Unix(9, 0), want: false},
// Time based sequence lock with current time before lock time.
{seqLock: seqLock(-1, 30), blockChainHeight: 2, mtp: time.Unix(29, 0), want: false},
{seqLock: seqLock(-1, 30), blockBlueScore: 2, mtp: time.Unix(29, 0), want: false},
// Block based sequence lock at the same height, so shouldn't yet be active.
{seqLock: seqLock(1000, -1), blockChainHeight: 1000, mtp: time.Unix(9, 0), want: false},
// Block based sequence lock at the same blue score, so shouldn't yet be active.
{seqLock: seqLock(1000, -1), blockBlueScore: 1000, mtp: time.Unix(9, 0), want: false},
// Time based sequence lock with current time equal to lock time, so shouldn't yet be active.
{seqLock: seqLock(-1, 30), blockChainHeight: 2, mtp: time.Unix(30, 0), want: false},
{seqLock: seqLock(-1, 30), blockBlueScore: 2, mtp: time.Unix(30, 0), want: false},
}
t.Logf("Running %d sequence locks tests", len(tests))
for i, test := range tests {
got := SequenceLockActive(test.seqLock,
test.blockChainHeight, test.mtp)
test.blockBlueScore, test.mtp)
if got != test.want {
t.Fatalf("SequenceLockActive #%d got %v want %v", i,
got, test.want)
@ -515,42 +515,39 @@ func TestPastMedianTime(t *testing.T) {
}
// Checks that a block is valid if it has timestamp equals to past median time
chainHeight := tip.chainHeight + 1
node := newTestNode(dag, setFromSlice(tip),
blockVersion,
dag.powMaxBits,
tip.PastMedianTime(dag))
header := node.Header()
err := dag.checkBlockHeaderContext(header, node.parents.bluest(), chainHeight, false)
err := dag.checkBlockHeaderContext(header, node.parents.bluest(), false)
if err != nil {
t.Errorf("TestPastMedianTime: unexpected error from checkBlockHeaderContext: %v"+
"(a block with timestamp equals to past median time should be valid)", err)
}
// Checks that a block is valid if its timestamp is after past median time
chainHeight = tip.chainHeight + 1
node = newTestNode(dag, setFromSlice(tip),
blockVersion,
dag.powMaxBits,
tip.PastMedianTime(dag).Add(time.Second))
header = node.Header()
err = dag.checkBlockHeaderContext(header, node.parents.bluest(), chainHeight, false)
err = dag.checkBlockHeaderContext(header, node.parents.bluest(), false)
if err != nil {
t.Errorf("TestPastMedianTime: unexpected error from checkBlockHeaderContext: %v"+
"(a block with timestamp bigger than past median time should be valid)", err)
}
// Checks that a block is invalid if its timestamp is before past median time
chainHeight = tip.chainHeight + 1
node = newTestNode(dag, setFromSlice(tip),
blockVersion,
0,
tip.PastMedianTime(dag).Add(-time.Second))
header = node.Header()
err = dag.checkBlockHeaderContext(header, node.parents.bluest(), chainHeight, false)
err = dag.checkBlockHeaderContext(header, node.parents.bluest(), false)
if err == nil {
t.Errorf("TestPastMedianTime: unexpected success: block should be invalid if its timestamp is before past median time")
}

View File

@ -250,9 +250,9 @@ func (dag *BlockDAG) warnUnknownRuleActivations(node *blockNode) error {
case ThresholdLockedIn:
window := checker.MinerConfirmationWindow()
activationChainHeight := window - (node.chainHeight % window)
activationBlueScore := window - (node.blueScore % window)
log.Warnf("Unknown new rules are about to activate in "+
"%d blocks (bit %d)", activationChainHeight, bit)
"%d blueScore (bit %d)", activationBlueScore, bit)
}
}

View File

@ -87,14 +87,14 @@ func solveBlock(header *wire.BlockHeader, targetDifficulty *big.Int) bool {
// standardCoinbaseScript returns a standard script suitable for use as the
// signature script of the coinbase transaction of a new block. In particular,
// it starts with the block height that is required by version 2 blocks.
func standardCoinbaseScript(nextBlockHeight uint64, extraNonce uint64) ([]byte, error) {
return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).
// it starts with the block blue score.
func standardCoinbaseScript(nextBlueScore uint64, extraNonce uint64) ([]byte, error) {
return txscript.NewScriptBuilder().AddInt64(int64(nextBlueScore)).
AddInt64(int64(extraNonce)).Script()
}
// createCoinbaseTx returns a coinbase transaction paying an appropriate
// subsidy based on the passed block height to the provided address.
// subsidy based on the passed block blue score to the provided address.
func createCoinbaseTx(coinbaseScript []byte, nextBlueScore uint64,
addr util.Address, mineTo []wire.TxOut,
net *dagconfig.Params) (*util.Tx, error) {
@ -133,27 +133,27 @@ func createCoinbaseTx(coinbaseScript []byte, nextBlueScore uint64,
// initialized), then the timestamp of the previous block will be used plus 1
// second is used. Passing nil for the previous block results in a block that
// builds off of the genesis block for the specified chain.
func CreateBlock(parentBlock *util.Block, inclusionTxs []*util.Tx,
blockVersion int32, blockTime time.Time, miningAddr util.Address,
mineTo []wire.TxOut, net *dagconfig.Params, powMaxBits uint32) (*util.Block, error) {
func CreateBlock(parentBlock *util.Block, parentBlueScore uint64,
inclusionTxs []*util.Tx, blockVersion int32, blockTime time.Time,
miningAddr util.Address, mineTo []wire.TxOut, net *dagconfig.Params,
powMaxBits uint32) (*util.Block, error) {
var (
parentHash *daghash.Hash
blockChainHeight uint64
parentBlockTime time.Time
parentHash *daghash.Hash
blockBlueScore uint64
parentBlockTime time.Time
)
// If the parent block isn't specified, then we'll construct a block
// that builds off of the genesis block for the chain.
if parentBlock == nil {
parentHash = net.GenesisHash
blockChainHeight = 1
parentBlockTime = net.GenesisBlock.Header.Timestamp.Add(time.Minute)
} else {
parentHash = parentBlock.Hash()
blockChainHeight = parentBlock.ChainHeight() + 1
parentBlockTime = parentBlock.MsgBlock().Header.Timestamp
}
blockBlueScore = parentBlueScore + 1
// If a target block time was specified, then use that as the header's
// timestamp. Otherwise, add one second to the parent block unless
@ -167,11 +167,11 @@ func CreateBlock(parentBlock *util.Block, inclusionTxs []*util.Tx,
}
extraNonce := uint64(0)
coinbaseScript, err := standardCoinbaseScript(blockChainHeight, extraNonce)
coinbaseScript, err := standardCoinbaseScript(blockBlueScore, extraNonce)
if err != nil {
return nil, err
}
coinbaseTx, err := createCoinbaseTx(coinbaseScript, blockChainHeight,
coinbaseTx, err := createCoinbaseTx(coinbaseScript, blockBlueScore,
miningAddr, mineTo, net)
if err != nil {
return nil, err

View File

@ -440,17 +440,14 @@ func (h *Harness) GenerateAndSubmitBlockWithCustomCoinbaseOutputs(
return nil, err
}
selectedTipBlueScore := selectedTip.BlueScore
mBlock, err := h.Node.GetBlock(selectedTipHash, nil)
if err != nil {
return nil, err
}
parentBlock := util.NewBlock(mBlock)
parentBlock.SetChainHeight(selectedTipBlueScore)
// Create a new block including the specified transactions
newBlock, err := CreateBlock(parentBlock, txns, blockVersion,
newBlock, err := CreateBlock(parentBlock, selectedTip.BlueScore, txns, blockVersion,
blockTime, h.wallet.coinbaseAddr, mineTo, h.ActiveNet, h.powMaxBits)
if err != nil {
return nil, err

View File

@ -58,10 +58,6 @@ type Config struct {
// associated with.
DAGParams *dagconfig.Params
// DAGChainHeight defines the function to use to access the chain
// height of the DAG
DAGChainHeight func() uint64
// MedianTimePast defines the function to use in order to access the
// median time past calculated from the point-of-view of the current
// selected tip.
@ -683,14 +679,13 @@ func (mp *TxPool) RemoveDoubleSpends(tx *util.Tx) {
// helper for maybeAcceptTransaction.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *TxPool) addTransaction(tx *util.Tx, height uint64, blueScore uint64, fee uint64, parentsInPool []*wire.Outpoint) (*TxDesc, error) {
func (mp *TxPool) addTransaction(tx *util.Tx, fee uint64, parentsInPool []*wire.Outpoint) (*TxDesc, error) {
// Add the transaction to the pool and mark the referenced outpoints
// as spent by the pool.
txD := &TxDesc{
TxDesc: mining.TxDesc{
Tx: tx,
Added: time.Now(),
Height: height,
Fee: fee,
FeePerKB: fee * 1000 / uint64(tx.MsgTx().SerializeSize()),
},
@ -789,7 +784,7 @@ func (mp *TxPool) FetchTransaction(txID *daghash.TxID) (*util.Tx, error) {
// more details.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rejectDupOrphans bool) ([]*daghash.TxID, *TxDesc, error) {
func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, rejectDupOrphans bool) ([]*daghash.TxID, *TxDesc, error) {
txID := tx.ID()
// Don't accept the transaction if it already exists in the pool. This
@ -1018,8 +1013,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rejectDupOrphans bo
}
// Add to transaction pool.
bestHeight := mp.cfg.DAGChainHeight()
txD, err := mp.addTransaction(tx, bestHeight, nextBlockBlueScore, txFee, parentsInPool)
txD, err := mp.addTransaction(tx, txFee, parentsInPool)
if err != nil {
return nil, nil, err
}
@ -1047,7 +1041,7 @@ func (mp *TxPool) MaybeAcceptTransaction(tx *util.Tx, isNew bool) ([]*daghash.Tx
defer mp.cfg.DAG.RUnlock()
mp.mtx.Lock()
defer mp.mtx.Unlock()
hashes, txD, err := mp.maybeAcceptTransaction(tx, isNew, true)
hashes, txD, err := mp.maybeAcceptTransaction(tx, true)
return hashes, txD, err
}
@ -1089,7 +1083,7 @@ func (mp *TxPool) processOrphans(acceptedTx *util.Tx) []*TxDesc {
// Potentially accept an orphan into the tx pool.
for _, tx := range orphans {
missing, txD, err := mp.maybeAcceptTransaction(
tx, true, false)
tx, false)
if err != nil {
// The orphan is now invalid, so there
// is no way any other orphans which
@ -1176,7 +1170,7 @@ func (mp *TxPool) ProcessTransaction(tx *util.Tx, allowOrphan bool, tag Tag) ([]
defer mp.mtx.Unlock()
// Potentially accept the transaction to the memory pool.
missingParents, txD, err := mp.maybeAcceptTransaction(tx, true, true)
missingParents, txD, err := mp.maybeAcceptTransaction(tx, true)
if err != nil {
return nil, err
}
@ -1315,7 +1309,6 @@ func (mp *TxPool) RawMempoolVerbose() map[string]*rpcmodel.GetRawMempoolVerboseR
Size: int32(tx.MsgTx().SerializeSize()),
Fee: util.Amount(desc.Fee).ToKAS(),
Time: desc.Added.Unix(),
Height: desc.Height,
Depends: make([]string, 0),
}
for _, txIn := range tx.MsgTx().TxIn {

View File

@ -349,7 +349,6 @@ func newPoolHarness(t *testing.T, dagParams *dagconfig.Params, numOutputs uint32
MaxTxVersion: 1,
},
DAGParams: &params,
DAGChainHeight: fDAG.BlueScore,
MedianTimePast: fDAG.MedianTimePast,
CalcSequenceLockNoLock: calcSequenceLock,
SigCache: nil,
@ -542,8 +541,8 @@ func TestProcessTransaction(t *testing.T) {
}
//Checks that a coinbase transaction cannot be added to the mempool
curHeight := harness.dag.BlueScore()
coinbase, err := harness.CreateCoinbaseTx(curHeight+1, 1)
currentBlueScore := harness.dag.BlueScore()
coinbase, err := harness.CreateCoinbaseTx(currentBlueScore+1, 1)
if err != nil {
t.Errorf("CreateCoinbaseTx: %v", err)
}
@ -638,7 +637,7 @@ func TestProcessTransaction(t *testing.T) {
t.Fatalf("PayToAddrScript: unexpected error: %v", err)
}
p2shTx := util.NewTx(wire.NewNativeMsgTx(1, nil, []*wire.TxOut{{Value: 5000000000, ScriptPubKey: p2shScriptPubKey}}))
if isAccepted, err := harness.txPool.mpUTXOSet.AddTx(p2shTx.MsgTx(), curHeight+1); err != nil {
if isAccepted, err := harness.txPool.mpUTXOSet.AddTx(p2shTx.MsgTx(), currentBlueScore+1); err != nil {
t.Fatalf("AddTx unexpectedly failed. Error: %s", err)
} else if !isAccepted {
t.Fatalf("AddTx unexpectedly didn't add tx %s", p2shTx.ID())

View File

@ -32,10 +32,6 @@ type TxDesc struct {
// Added is the time when the entry was added to the source pool.
Added time.Time
// Height is the block height when the entry was added to the the source
// pool.
Height uint64
// Fee is the total fee the transaction associated with the entry pays.
Fee uint64

View File

@ -12,7 +12,6 @@ import "encoding/json"
type GetBlockHeaderVerboseResult struct {
Hash string `json:"hash"`
Confirmations uint64 `json:"confirmations"`
Height uint64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
HashMerkleRoot string `json:"hashMerkleRoot"`
@ -33,7 +32,6 @@ type GetBlockVerboseResult struct {
Hash string `json:"hash"`
Confirmations uint64 `json:"confirmations"`
Size int32 `json:"size"`
Height uint64 `json:"height"`
BlueScore uint64 `json:"blueScore"`
IsChainBlock bool `json:"isChainBlock"`
Version int32 `json:"version"`
@ -265,7 +263,6 @@ type GetRawMempoolVerboseResult struct {
Size int32 `json:"size"`
Fee float64 `json:"fee"`
Time int64 `json:"time"`
Height uint64 `json:"height"`
Depends []string `json:"depends"`
}

View File

@ -37,16 +37,16 @@ const (
// FilteredBlockAddedNtfn defines the filteredBlockAdded JSON-RPC
// notification.
type FilteredBlockAddedNtfn struct {
ChainHeight uint64
BlueScore uint64
Header string
SubscribedTxs []string
}
// NewFilteredBlockAddedNtfn returns a new instance which can be used to
// issue a filteredBlockAdded JSON-RPC notification.
func NewFilteredBlockAddedNtfn(chainHeight uint64, header string, subscribedTxs []string) *FilteredBlockAddedNtfn {
func NewFilteredBlockAddedNtfn(blueScore uint64, header string, subscribedTxs []string) *FilteredBlockAddedNtfn {
return &FilteredBlockAddedNtfn{
ChainHeight: chainHeight,
BlueScore: blueScore,
Header: header,
SubscribedTxs: subscribedTxs,
}

View File

@ -35,14 +35,14 @@ func TestRPCServerWebsocketNotifications(t *testing.T) {
{
name: "filteredBlockAdded",
newNtfn: func() (interface{}, error) {
return rpcmodel.NewCommand("filteredBlockAdded", 100000, "header", []string{"tx0", "tx1"})
return rpcmodel.NewCommand("filteredBlockAdded", 100, "header", []string{"tx0", "tx1"})
},
staticNtfn: func() interface{} {
return rpcmodel.NewFilteredBlockAddedNtfn(100000, "header", []string{"tx0", "tx1"})
return rpcmodel.NewFilteredBlockAddedNtfn(100, "header", []string{"tx0", "tx1"})
},
marshalled: `{"jsonrpc":"1.0","method":"filteredBlockAdded","params":[100000,"header",["tx0","tx1"]],"id":null}`,
marshalled: `{"jsonrpc":"1.0","method":"filteredBlockAdded","params":[100,"header",["tx0","tx1"]],"id":null}`,
unmarshalled: &rpcmodel.FilteredBlockAddedNtfn{
ChainHeight: 100000,
BlueScore: 100,
Header: "header",
SubscribedTxs: []string{"tx0", "tx1"},
},

View File

@ -1,6 +1,7 @@
package p2p
import (
"fmt"
"github.com/kaspanet/kaspad/peer"
"github.com/kaspanet/kaspad/wire"
)
@ -8,15 +9,19 @@ import (
// OnGetBlockLocator is invoked when a peer receives a getlocator kaspa
// message.
func (sp *Peer) OnGetBlockLocator(_ *peer.Peer, msg *wire.MsgGetBlockLocator) {
locator := sp.server.DAG.BlockLocatorFromHashes(msg.StartHash, msg.StopHash)
if len(locator) == 0 {
peerLog.Infof("Couldn't build a block locator between blocks %s and %s"+
" that was requested from peer %s",
sp)
locator, err := sp.server.DAG.BlockLocatorFromHashes(msg.StartHash, msg.StopHash)
if err != nil || len(locator) == 0 {
warning := fmt.Sprintf("Couldn't build a block locator between blocks "+
"%s and %s that was requested from peer %s", msg.StartHash, msg.StopHash, sp)
if err != nil {
warning = fmt.Sprintf("%s: %s", warning, err)
}
peerLog.Warnf(warning)
sp.Disconnect()
return
}
err := sp.PushBlockLocatorMsg(locator)
err = sp.PushBlockLocatorMsg(locator)
if err != nil {
peerLog.Errorf("Failed to send block locator message to peer %s: %s",
sp, err)

View File

@ -1662,7 +1662,6 @@ func NewServer(listenAddrs []string, db database.DB, dagParams *dagconfig.Params
MaxTxVersion: 1,
},
DAGParams: dagParams,
DAGChainHeight: func() uint64 { return s.DAG.ChainHeight() },
MedianTimePast: func() time.Time { return s.DAG.CalcPastMedianTime() },
CalcSequenceLockNoLock: func(tx *util.Tx, utxoSet blockdag.UTXOSet) (*blockdag.SequenceLock, error) {
return s.DAG.CalcSequenceLockNoLock(tx, utxoSet, true)

View File

@ -210,23 +210,19 @@ func buildGetBlockVerboseResult(s *Server, block *util.Block, isVerboseTx bool)
params := s.cfg.DAGParams
blockHeader := block.MsgBlock().Header
// Get the block chain height.
blockChainHeight, err := s.cfg.DAG.BlockChainHeightByHash(hash)
blockBlueScore, err := s.cfg.DAG.BlueScoreByBlockHash(hash)
if err != nil {
context := "Failed to obtain block height"
context := "Could not get block blue score"
return nil, internalRPCError(err.Error(), context)
}
// Get the hashes for the next blocks unless there are none.
var nextHashStrings []string
if blockChainHeight < s.cfg.DAG.ChainHeight() { //TODO: (Ori) This is probably wrong. Done only for compilation
childHashes, err := s.cfg.DAG.ChildHashesByHash(hash)
if err != nil {
context := "No next block"
return nil, internalRPCError(err.Error(), context)
}
nextHashStrings = daghash.Strings(childHashes)
childHashes, err := s.cfg.DAG.ChildHashesByHash(hash)
if err != nil {
context := "No next block"
return nil, internalRPCError(err.Error(), context)
}
childHashStrings := daghash.Strings(childHashes)
blockConfirmations, err := s.cfg.DAG.BlockConfirmationsByHashNoLock(hash)
if err != nil {
@ -234,12 +230,6 @@ func buildGetBlockVerboseResult(s *Server, block *util.Block, isVerboseTx bool)
return nil, internalRPCError(err.Error(), context)
}
blockBlueScore, err := s.cfg.DAG.BlueScoreByBlockHash(hash)
if err != nil {
context := "Could not get block blue score"
return nil, internalRPCError(err.Error(), context)
}
selectedParentHash, err := s.cfg.DAG.SelectedParentHash(hash)
if err != nil {
context := "Could not get block selected parent"
@ -264,13 +254,12 @@ func buildGetBlockVerboseResult(s *Server, block *util.Block, isVerboseTx bool)
Nonce: blockHeader.Nonce,
Time: blockHeader.Timestamp.Unix(),
Confirmations: blockConfirmations,
Height: blockChainHeight,
BlueScore: blockBlueScore,
IsChainBlock: isChainBlock,
Size: int32(block.MsgBlock().SerializeSize()),
Bits: strconv.FormatInt(int64(blockHeader.Bits), 16),
Difficulty: getDifficultyRatio(blockHeader.Bits, params),
NextHashes: nextHashStrings,
NextHashes: childHashStrings,
}
if isVerboseTx {

View File

@ -40,23 +40,13 @@ func handleGetBlockHeader(s *Server, cmd interface{}, closeChan <-chan struct{})
// The verbose flag is set, so generate the JSON object and return it.
// Get the block chain height from chain.
blockChainHeight, err := s.cfg.DAG.BlockChainHeightByHash(hash)
// Get the hashes for the next blocks unless there are none.
childHashes, err := s.cfg.DAG.ChildHashesByHash(hash)
if err != nil {
context := "Failed to obtain block height"
context := "No next block"
return nil, internalRPCError(err.Error(), context)
}
// Get the hashes for the next blocks unless there are none.
var nextHashStrings []string
if blockChainHeight < s.cfg.DAG.ChainHeight() { //TODO: (Ori) This is probably wrong. Done only for compilation
childHashes, err := s.cfg.DAG.ChildHashesByHash(hash)
if err != nil {
context := "No next block"
return nil, internalRPCError(err.Error(), context)
}
nextHashStrings = daghash.Strings(childHashes)
}
childHashStrings := daghash.Strings(childHashes)
blockConfirmations, err := s.cfg.DAG.BlockConfirmationsByHash(hash)
if err != nil {
@ -74,12 +64,11 @@ func handleGetBlockHeader(s *Server, cmd interface{}, closeChan <-chan struct{})
blockHeaderReply := rpcmodel.GetBlockHeaderVerboseResult{
Hash: c.Hash,
Confirmations: blockConfirmations,
Height: blockChainHeight,
Version: blockHeader.Version,
VersionHex: fmt.Sprintf("%08x", blockHeader.Version),
HashMerkleRoot: blockHeader.HashMerkleRoot.String(),
AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot.String(),
NextHashes: nextHashStrings,
NextHashes: childHashStrings,
ParentHashes: daghash.Strings(blockHeader.ParentHashes),
SelectedParentHash: selectedParentHash.String(),
Nonce: blockHeader.Nonce,

View File

@ -106,11 +106,11 @@ func handleGetBlockTemplate(s *Server, cmd interface{}, closeChan <-chan struct{
// No point in generating templates or processing proposals before
// the DAG is synced. Note that we make a special check for when
// we have nothing besides the genesis block (chainHeight == 0),
// we have nothing besides the genesis block (blueScore == 0),
// because in that state IsCurrent may still return true.
currentChainHeight := s.cfg.DAG.ChainHeight()
if (currentChainHeight != 0 && !s.cfg.SyncMgr.IsCurrent()) ||
(currentChainHeight == 0 && !s.cfg.CPUMiner.ShouldMineOnGenesis()) {
currentBlueScore := s.cfg.DAG.SelectedTipBlueScore()
if (currentBlueScore != 0 && !s.cfg.SyncMgr.IsCurrent()) ||
(currentBlueScore == 0 && !s.cfg.CPUMiner.ShouldMineOnGenesis()) {
return nil, &rpcmodel.RPCError{
Code: rpcmodel.ErrRPCClientInInitialDownload,
Message: "Kaspa is downloading blocks...",

View File

@ -665,8 +665,7 @@ func (m *wsNotificationManager) notifyFilteredBlockAdded(clients map[chan struct
"added notification: %s", err)
return
}
ntfn := rpcmodel.NewFilteredBlockAddedNtfn(block.ChainHeight(),
hex.EncodeToString(w.Bytes()), nil)
ntfn := rpcmodel.NewFilteredBlockAddedNtfn(block.BlueScore(), hex.EncodeToString(w.Bytes()), nil)
// Search for relevant transactions for each client and save them
// serialized in hex encoding for the notification.

View File

@ -8,7 +8,6 @@ import (
"bytes"
"fmt"
"io"
"math"
"time"
"github.com/kaspanet/kaspad/util/daghash"
@ -20,10 +19,6 @@ import (
type OutOfRangeError string
const (
// BlockHeightUnknown is the value returned for a block height that is unknown.
// This is typically because the block has not been inserted into the DAG yet.
BlockHeightUnknown = math.MaxUint64
// CoinbaseTransactionIndex is the index of the coinbase transaction in every block
CoinbaseTransactionIndex = 0
)
@ -41,9 +36,9 @@ type Block struct {
msgBlock *wire.MsgBlock // Underlying MsgBlock
serializedBlock []byte // Serialized bytes for the block
blockHash *daghash.Hash // Cached block hash
chainHeight uint64 // Selected-chain height
transactions []*Tx // Transactions
txnsGenerated bool // ALL wrapped transactions generated
blueScore uint64 // Blue score
}
// MsgBlock returns the underlying wire.MsgBlock for the Block.
@ -189,17 +184,6 @@ func (b *Block) TxLoc() ([]wire.TxLoc, error) {
return txLocs, err
}
// ChainHeight returns the saved chan height of the block . This value
// will be BlockHeightUnknown if it hasn't already explicitly been set.
func (b *Block) ChainHeight() uint64 {
return b.chainHeight
}
// SetChainHeight sets the chain height of the block.
func (b *Block) SetChainHeight(chainHeight uint64) {
b.chainHeight = chainHeight
}
// IsGenesis returns whether or not this block is the genesis block.
func (b *Block) IsGenesis() bool {
return b.MsgBlock().Header.IsGenesis()
@ -215,12 +199,21 @@ func (b *Block) Timestamp() time.Time {
return b.msgBlock.Header.Timestamp
}
// BlueScore returns this block's blue score.
func (b *Block) BlueScore() uint64 {
return b.blueScore
}
// SetBlueScore sets the blue score of the block.
func (b *Block) SetBlueScore(blueScore uint64) {
b.blueScore = blueScore
}
// NewBlock returns a new instance of a kaspa block given an underlying
// wire.MsgBlock. See Block.
func NewBlock(msgBlock *wire.MsgBlock) *Block {
return &Block{
msgBlock: msgBlock,
chainHeight: BlockHeightUnknown,
msgBlock: msgBlock,
}
}

View File

@ -29,14 +29,6 @@ func TestBlock(t *testing.T) {
spew.Sdump(msgBlock), spew.Sdump(&Block100000))
}
// Ensure block chain height set and get work properly.
wantChainHeight := uint64(100000)
b.SetChainHeight(wantChainHeight)
if gotChainHeight := b.ChainHeight(); gotChainHeight != wantChainHeight {
t.Errorf("ChainHeight: mismatched chain height - got %v, want %v",
gotChainHeight, wantChainHeight)
}
// Hash for block 100,000.
wantHashStr := "839a8e072e6d402128f6f9a32ffc012e471e071e8ef8405552b1e58ef7b681f0"
wantHash, err := daghash.NewHashFromStr(wantHashStr)