mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-05 13:46:42 +00:00
199 lines
5.9 KiB
Go
199 lines
5.9 KiB
Go
// Copyright (c) 2014-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/dagconfig"
|
|
"github.com/kaspanet/kaspad/util/daghash"
|
|
"github.com/kaspanet/kaspad/wire"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kaspanet/kaspad/util"
|
|
)
|
|
|
|
// TestBigToCompact ensures BigToCompact converts big integers to the expected
|
|
// compact representation.
|
|
func TestBigToCompact(t *testing.T) {
|
|
tests := []struct {
|
|
in int64
|
|
out uint32
|
|
}{
|
|
{0, 0},
|
|
{-1, 25231360},
|
|
}
|
|
|
|
for x, test := range tests {
|
|
n := big.NewInt(test.in)
|
|
r := util.BigToCompact(n)
|
|
if r != test.out {
|
|
t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n",
|
|
x, r, test.out)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCompactToBig ensures CompactToBig converts numbers using the compact
|
|
// representation to the expected big intergers.
|
|
func TestCompactToBig(t *testing.T) {
|
|
tests := []struct {
|
|
in uint32
|
|
out int64
|
|
}{
|
|
{10000000, 0},
|
|
}
|
|
|
|
for x, test := range tests {
|
|
n := util.CompactToBig(test.in)
|
|
want := big.NewInt(test.out)
|
|
if n.Cmp(want) != 0 {
|
|
t.Errorf("TestCompactToBig test #%d failed: got %d want %d\n",
|
|
x, n.Int64(), want.Int64())
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCalcWork ensures CalcWork calculates the expected work value from values
|
|
// in compact representation.
|
|
func TestCalcWork(t *testing.T) {
|
|
tests := []struct {
|
|
in uint32
|
|
out int64
|
|
}{
|
|
{10000000, 0},
|
|
}
|
|
|
|
for x, test := range tests {
|
|
bits := uint32(test.in)
|
|
|
|
r := util.CalcWork(bits)
|
|
if r.Int64() != test.out {
|
|
t.Errorf("TestCalcWork test #%d failed: got %v want %d\n",
|
|
x, r.Int64(), test.out)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifficulty(t *testing.T) {
|
|
params := dagconfig.SimNetParams
|
|
params.K = 1
|
|
dag := newTestDAG(¶ms)
|
|
nonce := uint64(0)
|
|
zeroTime := time.Unix(0, 0)
|
|
addNode := func(parents blockSet, blockTime time.Time) *blockNode {
|
|
bluestParent := parents.bluest()
|
|
if blockTime == zeroTime {
|
|
blockTime = time.Unix(bluestParent.timestamp+1, 0)
|
|
}
|
|
header := &wire.BlockHeader{
|
|
ParentHashes: parents.hashes(),
|
|
Bits: dag.requiredDifficulty(bluestParent, blockTime),
|
|
Nonce: nonce,
|
|
Timestamp: blockTime,
|
|
HashMerkleRoot: &daghash.ZeroHash,
|
|
AcceptedIDMerkleRoot: &daghash.ZeroHash,
|
|
UTXOCommitment: &daghash.ZeroHash,
|
|
}
|
|
node := newBlockNode(header, parents, dag.dagParams.K)
|
|
node.updateParentsChildren()
|
|
nonce++
|
|
return node
|
|
}
|
|
tip := dag.genesis
|
|
for i := uint64(0); i < dag.difficultyAdjustmentWindowSize; i++ {
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if tip.bits != dag.genesis.bits {
|
|
t.Fatalf("As long as the bluest parent's blue score is less then the difficulty adjustment window size, the difficulty should be the same as genesis'")
|
|
}
|
|
}
|
|
for i := uint64(0); i < dag.difficultyAdjustmentWindowSize+1000; i++ {
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if tip.bits != dag.genesis.bits {
|
|
t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change")
|
|
}
|
|
}
|
|
nodeInThePast := addNode(setFromSlice(tip), tip.PastMedianTime(dag))
|
|
if nodeInThePast.bits != tip.bits {
|
|
t.Fatalf("The difficulty should only change when nodeInThePast is in the past of a block bluest parent")
|
|
}
|
|
tip = nodeInThePast
|
|
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if tip.bits != nodeInThePast.bits {
|
|
t.Fatalf("The difficulty should only change when nodeInThePast is in the past of a block bluest parent")
|
|
}
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if compareBits(tip.bits, nodeInThePast.bits) >= 0 {
|
|
t.Fatalf("tip.bits should be smaller than nodeInThePast.bits because nodeInThePast increased the block rate, so the difficulty should increase as well")
|
|
}
|
|
expectedBits := uint32(0x207ff395)
|
|
if tip.bits != expectedBits {
|
|
t.Errorf("tip.bits was expected to be %x but got %x", expectedBits, tip.bits)
|
|
}
|
|
|
|
// Increase block rate to increase difficulty
|
|
for i := uint64(0); i < dag.difficultyAdjustmentWindowSize; i++ {
|
|
tip = addNode(setFromSlice(tip), tip.PastMedianTime(dag))
|
|
if compareBits(tip.bits, tip.parents.bluest().bits) > 0 {
|
|
t.Fatalf("Because we're increasing the block rate, the difficulty can't decrease")
|
|
}
|
|
}
|
|
|
|
// Add blocks until difficulty stabilizes
|
|
lastBits := tip.bits
|
|
sameBitsCount := uint64(0)
|
|
for sameBitsCount < dag.difficultyAdjustmentWindowSize+1 {
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if tip.bits == lastBits {
|
|
sameBitsCount++
|
|
} else {
|
|
lastBits = tip.bits
|
|
sameBitsCount = 0
|
|
}
|
|
}
|
|
slowNode := addNode(setFromSlice(tip), time.Unix(tip.timestamp+2, 0))
|
|
if slowNode.bits != tip.bits {
|
|
t.Fatalf("The difficulty should only change when slowNode is in the past of a block bluest parent")
|
|
}
|
|
|
|
tip = slowNode
|
|
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if tip.bits != slowNode.bits {
|
|
t.Fatalf("The difficulty should only change when slowNode is in the past of a block bluest parent")
|
|
}
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
if compareBits(tip.bits, slowNode.bits) <= 0 {
|
|
t.Fatalf("tip.bits should be smaller than slowNode.bits because slowNode decreased the block rate, so the difficulty should decrease as well")
|
|
}
|
|
|
|
splitNode := addNode(setFromSlice(tip), zeroTime)
|
|
tip = splitNode
|
|
for i := 0; i < 100; i++ {
|
|
tip = addNode(setFromSlice(tip), zeroTime)
|
|
}
|
|
blueTip := tip
|
|
|
|
redChainTip := splitNode
|
|
for i := 0; i < 10; i++ {
|
|
redChainTip = addNode(setFromSlice(redChainTip), redChainTip.PastMedianTime(dag))
|
|
}
|
|
tipWithRedPast := addNode(setFromSlice(redChainTip, blueTip), zeroTime)
|
|
tipWithoutRedPast := addNode(setFromSlice(blueTip), zeroTime)
|
|
if tipWithoutRedPast.bits != tipWithRedPast.bits {
|
|
t.Fatalf("tipWithoutRedPast.bits should be the same as tipWithRedPast.bits because red blocks shouldn't affect the difficulty")
|
|
}
|
|
}
|
|
|
|
func compareBits(a uint32, b uint32) int {
|
|
aTarget := util.CompactToBig(a)
|
|
bTarget := util.CompactToBig(b)
|
|
return aTarget.Cmp(bTarget)
|
|
}
|