github.com/johnathanhowell/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 */