github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/consensus/processedblock_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"path/filepath"
     5  	"testing"
     6  
     7  	"github.com/NebulousLabs/Sia/build"
     8  	"github.com/NebulousLabs/Sia/crypto"
     9  	"github.com/NebulousLabs/Sia/modules"
    10  	"github.com/NebulousLabs/Sia/modules/gateway"
    11  	"github.com/NebulousLabs/Sia/modules/miner"
    12  	"github.com/NebulousLabs/Sia/modules/transactionpool"
    13  	"github.com/NebulousLabs/Sia/modules/wallet"
    14  	"github.com/NebulousLabs/Sia/types"
    15  )
    16  
    17  // TestIntegrationMinimumValidChildTimestamp probes the
    18  // MinimumValidChildTimestamp method of the consensus type.
    19  func TestIntegrationMinimumValidChildTimestamp(t *testing.T) {
    20  	if testing.Short() {
    21  		t.SkipNow()
    22  	}
    23  
    24  	// Create a custom consnesus set to control the blocks.
    25  	testdir := build.TempDir(modules.ConsensusDir, "TestIntegrationMinimumValidChildTimestamp")
    26  	g, err := gateway.New("localhost:0", filepath.Join(testdir, modules.GatewayDir))
    27  	if err != nil {
    28  		t.Fatal(err)
    29  	}
    30  	cs, err := New(g, filepath.Join(testdir, modules.ConsensusDir))
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	tp, err := transactionpool.New(cs, g, filepath.Join(testdir, modules.TransactionPoolDir))
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	key, err := crypto.GenerateTwofishKey()
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	_, err = w.Encrypt(key)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	err = w.Unlock(key)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	defer g.Close()
    59  
    60  	// The earliest child timestamp of the genesis block should be the
    61  	// timestamp of the genesis block.
    62  	genesisTime := cs.blockRoot.Block.Timestamp
    63  	earliest, ok := cs.MinimumValidChildTimestamp(cs.blockRoot.Block.ID())
    64  	if !ok || genesisTime != earliest {
    65  		t.Error("genesis block earliest timestamp producing unexpected results")
    66  	}
    67  
    68  	timestampOffsets := []types.Timestamp{1, 3, 2, 5, 4, 6, 7, 8, 9, 10}
    69  	blockIDs := []types.BlockID{cs.blockRoot.Block.ID()}
    70  	for _, offset := range timestampOffsets {
    71  		bfw, target, err := m.BlockForWork()
    72  		if err != nil {
    73  			t.Fatal(err)
    74  		}
    75  		bfw.Timestamp = genesisTime + offset
    76  		solvedBlock, _ := m.SolveBlock(bfw, target)
    77  		err = cs.AcceptBlock(solvedBlock)
    78  		if err != nil {
    79  			t.Fatal(err)
    80  		}
    81  		blockIDs = append(blockIDs, solvedBlock.ID())
    82  	}
    83  
    84  	// Median should be genesisTime for 6th block.
    85  	earliest, ok = cs.MinimumValidChildTimestamp(blockIDs[5])
    86  	if !ok || earliest != genesisTime {
    87  		t.Error("incorrect child timestamp")
    88  	}
    89  	// Median should be genesisTime+1 for 7th block.
    90  	earliest, ok = cs.MinimumValidChildTimestamp(blockIDs[6])
    91  	if !ok || earliest != genesisTime+1 {
    92  		t.Error("incorrect child timestamp")
    93  	}
    94  	// Median should be genesisTime + 5 for pb11.
    95  	earliest, ok = cs.MinimumValidChildTimestamp(blockIDs[10])
    96  	if !ok || earliest != genesisTime+5 {
    97  		t.Error("incorrect child timestamp")
    98  	}
    99  }
   100  
   101  // TestUnitHeavierThan probes the heavierThan method of the processedBlock type.
   102  func TestUnitHeavierThan(t *testing.T) {
   103  	// Create a light node.
   104  	pbLight := new(processedBlock)
   105  	pbLight.Depth[0] = 64
   106  	pbLight.ChildTarget[0] = 200
   107  
   108  	// Create a node that's heavier, but not enough to beat the surpass
   109  	// threshold.
   110  	pbMiddle := new(processedBlock)
   111  	pbMiddle.Depth[0] = 60
   112  	pbMiddle.ChildTarget[0] = 200
   113  
   114  	// Create a node that's heavy enough to break the surpass threshold.
   115  	pbHeavy := new(processedBlock)
   116  	pbHeavy.Depth[0] = 16
   117  	pbHeavy.ChildTarget[0] = 200
   118  
   119  	// pbLight should not be heavier than pbHeavy.
   120  	if pbLight.heavierThan(pbHeavy) {
   121  		t.Error("light heavier than heavy")
   122  	}
   123  	// pbLight should not be heavier than middle.
   124  	if pbLight.heavierThan(pbMiddle) {
   125  		t.Error("light heavier than middle")
   126  	}
   127  	// pbLight should not be heavier than itself.
   128  	if pbLight.heavierThan(pbLight) {
   129  		t.Error("light heavier than itself")
   130  	}
   131  
   132  	// pbMiddle should not be heavier than pbLight.
   133  	if pbMiddle.heavierThan(pbLight) {
   134  		t.Error("middle heaver than light - surpass threshold should not have been broken")
   135  	}
   136  	// pbHeavy should be heaver than pbLight.
   137  	if !pbHeavy.heavierThan(pbLight) {
   138  		t.Error("heavy is not heavier than light")
   139  	}
   140  	// pbHeavy should be heavier than pbMiddle.
   141  	if !pbHeavy.heavierThan(pbMiddle) {
   142  		t.Error("heavy is not heavier than middle")
   143  	}
   144  }
   145  
   146  // TestChildDepth probes the childDeath method of the blockNode type.
   147  func TestChildDepth(t *testing.T) {
   148  	// Try adding to equal weight nodes, result should be half.
   149  	pb := new(processedBlock)
   150  	pb.Depth[0] = 64
   151  	pb.ChildTarget[0] = 64
   152  	childDepth := pb.childDepth()
   153  	if childDepth[0] != 32 {
   154  		t.Error("unexpected child depth")
   155  	}
   156  
   157  	// Try adding nodes of different weights.
   158  	pb.Depth[0] = 24
   159  	pb.ChildTarget[0] = 48
   160  	childDepth = pb.childDepth()
   161  	if childDepth[0] != 16 {
   162  		t.Error("unexpected child depth")
   163  	}
   164  }
   165  
   166  /*
   167  // TestTargetAdjustmentBase probes the targetAdjustmentBase method of the block
   168  // node type.
   169  func TestTargetAdjustmentBase(t *testing.T) {
   170  	cst, err := createConsensusSetTester("TestTargetAdjustmentBase")
   171  	if err != nil {
   172  		t.Fatal(err)
   173  	}
   174  	defer cst.closeCst()
   175  
   176  	// Create a genesis node at timestamp 10,000
   177  	genesisNode := &processedBlock{
   178  		Block: types.Block{Timestamp: 10000},
   179  	}
   180  	cst.cs.db.addBlockMap(genesisNode)
   181  	exactTimeNode := &processedBlock{
   182  		Block: types.Block{
   183  			Nonce:     types.BlockNonce{1, 0, 0, 0, 0, 0, 0, 0},
   184  			Timestamp: types.Timestamp(10000 + types.BlockFrequency),
   185  		},
   186  	}
   187  	exactTimeNode.Parent = genesisNode.Block.ID()
   188  	cst.cs.db.addBlockMap(exactTimeNode)
   189  
   190  	// Base adjustment for the exactTimeNode should be 1.
   191  	adjustment, exact := cst.cs.targetAdjustmentBase(exactTimeNode).Float64()
   192  	if !exact {
   193  		t.Fatal("did not get an exact target adjustment")
   194  	}
   195  	if adjustment != 1 {
   196  		t.Error("block did not adjust itself to the same target")
   197  	}
   198  
   199  	// Create a double-speed node and get the base adjustment.
   200  	doubleSpeedNode := &processedBlock{
   201  		Block: types.Block{Timestamp: types.Timestamp(10000 + types.BlockFrequency)},
   202  	}
   203  	doubleSpeedNode.Parent = exactTimeNode.Block.ID()
   204  	cst.cs.db.addBlockMap(doubleSpeedNode)
   205  	adjustment, exact = cst.cs.targetAdjustmentBase(doubleSpeedNode).Float64()
   206  	if !exact {
   207  		t.Fatal("did not get an exact adjustment")
   208  	}
   209  	if adjustment != 0.5 {
   210  		t.Error("double speed node did not get a base to halve the target")
   211  	}
   212  
   213  	// Create a half-speed node and get the base adjustment.
   214  	halfSpeedNode := &processedBlock{
   215  		Block: types.Block{Timestamp: types.Timestamp(10000 + types.BlockFrequency*6)},
   216  	}
   217  	halfSpeedNode.Parent = doubleSpeedNode.Block.ID()
   218  	cst.cs.db.addBlockMap(halfSpeedNode)
   219  	adjustment, exact = cst.cs.targetAdjustmentBase(halfSpeedNode).Float64()
   220  	if !exact {
   221  		t.Fatal("did not get an exact adjustment")
   222  	}
   223  	if adjustment != 2 {
   224  		t.Error("double speed node did not get a base to halve the target")
   225  	}
   226  
   227  	if testing.Short() {
   228  		t.SkipNow()
   229  	}
   230  	// Create a chain of nodes so that the genesis node is no longer the point
   231  	// of comparison.
   232  	comparisonNode := &processedBlock{
   233  		Block: types.Block{Timestamp: 125000},
   234  	}
   235  	comparisonNode.Parent = halfSpeedNode.Block.ID()
   236  	cst.cs.db.addBlockMap(comparisonNode)
   237  	startingNode := comparisonNode
   238  	for i := types.BlockHeight(0); i < types.TargetWindow; i++ {
   239  		newNode := new(processedBlock)
   240  		newNode.Parent = startingNode.Block.ID()
   241  		newNode.Block.Nonce = types.BlockNonce{byte(i), byte(i / 256), 0, 0, 0, 0, 0, 0}
   242  		cst.cs.db.addBlockMap(newNode)
   243  		startingNode = newNode
   244  	}
   245  	startingNode.Block.Timestamp = types.Timestamp(125000 + types.BlockFrequency*types.TargetWindow)
   246  	adjustment, exact = cst.cs.targetAdjustmentBase(startingNode).Float64()
   247  	if !exact {
   248  		t.Error("failed to get exact result")
   249  	}
   250  	if adjustment != 1 {
   251  		t.Error("got wrong long-range adjustment")
   252  	}
   253  	startingNode.Block.Timestamp = types.Timestamp(125000 + 2*types.BlockFrequency*types.TargetWindow)
   254  	adjustment, exact = cst.cs.targetAdjustmentBase(startingNode).Float64()
   255  	if !exact {
   256  		t.Error("failed to get exact result")
   257  	}
   258  	if adjustment != 2 {
   259  		t.Error("got wrong long-range adjustment")
   260  	}
   261  }
   262  
   263  // TestClampTargetAdjustment probes the clampTargetAdjustment function.
   264  func TestClampTargetAdjustment(t *testing.T) {
   265  	// Check that the MaxAdjustmentUp and MaxAdjustmentDown constants match the
   266  	// test's expectations.
   267  	if types.MaxAdjustmentUp.Cmp(big.NewRat(10001, 10000)) != 0 {
   268  		t.Fatal("MaxAdjustmentUp changed - test now invalid")
   269  	}
   270  	if types.MaxAdjustmentDown.Cmp(big.NewRat(9999, 10000)) != 0 {
   271  		t.Fatal("MaxAdjustmentDown changed - test now invalid")
   272  	}
   273  
   274  	// Check high and low clamping.
   275  	initial := big.NewRat(2, 1)
   276  	clamped := clampTargetAdjustment(initial)
   277  	if clamped.Cmp(big.NewRat(10001, 10000)) != 0 {
   278  		t.Error("clamp not applied to large target adjustment")
   279  	}
   280  	initial = big.NewRat(1, 2)
   281  	clamped = clampTargetAdjustment(initial)
   282  	if clamped.Cmp(big.NewRat(9999, 10000)) != 0 {
   283  		t.Error("clamp not applied to small target adjustment")
   284  	}
   285  
   286  	// Check middle clamping (or lack thereof).
   287  	initial = big.NewRat(10002, 10001)
   288  	clamped = clampTargetAdjustment(initial)
   289  	if clamped.Cmp(initial) != 0 {
   290  		t.Error("clamp applied to safe target adjustment")
   291  	}
   292  	initial = big.NewRat(99999, 100000)
   293  	clamped = clampTargetAdjustment(initial)
   294  	if clamped.Cmp(initial) != 0 {
   295  		t.Error("clamp applied to safe target adjustment")
   296  	}
   297  }
   298  
   299  // TestSetChildTarget probes the setChildTarget method of the block node type.
   300  func TestSetChildTarget(t *testing.T) {
   301  	cst, err := createConsensusSetTester("TestSetChildTarget")
   302  	if err != nil {
   303  		t.Fatal(err)
   304  	}
   305  	defer cst.closeCst()
   306  
   307  	// Create a genesis node and a child that took 2x as long as expected.
   308  	genesisNode := &processedBlock{
   309  		Block: types.Block{Timestamp: 10000},
   310  	}
   311  	genesisNode.ChildTarget[0] = 64
   312  	cst.cs.db.addBlockMap(genesisNode)
   313  	doubleTimeNode := &processedBlock{
   314  		Block: types.Block{Timestamp: types.Timestamp(10000 + types.BlockFrequency*2)},
   315  	}
   316  	doubleTimeNode.Parent = genesisNode.Block.ID()
   317  	cst.cs.db.addBlockMap(doubleTimeNode)
   318  
   319  	// Check the resulting childTarget of the new node and see that the clamp
   320  	// was applied.
   321  	cst.cs.setChildTarget(doubleTimeNode)
   322  	if doubleTimeNode.ChildTarget.Cmp(genesisNode.ChildTarget) <= 0 {
   323  		t.Error("double time node target did not increase")
   324  	}
   325  	fullAdjustment := genesisNode.ChildTarget.MulDifficulty(big.NewRat(1, 2))
   326  	if doubleTimeNode.ChildTarget.Cmp(fullAdjustment) >= 0 {
   327  		t.Error("clamp was not applied when adjusting target")
   328  	}
   329  }
   330  
   331  // TestNewChild probes the newChild method of the block node type.
   332  func TestNewChild(t *testing.T) {
   333  	cst, err := createConsensusSetTester("TestSetChildTarget")
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	defer cst.closeCst()
   338  
   339  	parent := &processedBlock{
   340  		Height: 12,
   341  	}
   342  	parent.Depth[0] = 45
   343  	parent.Block.Timestamp = 100
   344  	parent.ChildTarget[0] = 90
   345  
   346  	cst.cs.db.addBlockMap(parent)
   347  
   348  	child := cst.cs.newChild(parent, types.Block{Timestamp: types.Timestamp(100 + types.BlockFrequency)})
   349  	if child.Parent != parent.Block.ID() {
   350  		t.Error("parent-child relationship incorrect")
   351  	}
   352  	if child.Height != 13 {
   353  		t.Error("child height set incorrectly")
   354  	}
   355  	var expectedDepth types.Target
   356  	expectedDepth[0] = 30
   357  	if child.Depth.Cmp(expectedDepth) != 0 {
   358  		t.Error("child depth did not adjust correctly")
   359  	}
   360  	if child.ChildTarget.Cmp(parent.ChildTarget) != 0 {
   361  		t.Error("child childTarget not adjusted correctly")
   362  	}
   363  }
   364  */