github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/miner/blockmanager_test.go (about) 1 package miner 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/NebulousLabs/Sia/crypto" 8 "github.com/NebulousLabs/Sia/modules" 9 "github.com/NebulousLabs/Sia/types" 10 ) 11 12 // solveHeader takes a block header as input and returns a solved block header 13 // as output. 14 func solveHeader(header types.BlockHeader, target types.Target) types.BlockHeader { 15 // Solve the header. 16 for { 17 // Incrememnt the nonce first to guarantee that a new header is formed 18 // - this helps check for pointer errors. 19 header.Nonce[0]++ 20 id := crypto.HashObject(header) 21 if bytes.Compare(target[:], id[:]) >= 0 { 22 break 23 } 24 } 25 return header 26 } 27 28 // TestIntegrationHeaderForWork checks that header requesting, solving, and 29 // submitting naively works. 30 func TestIntegrationHeaderForWork(t *testing.T) { 31 if testing.Short() { 32 t.SkipNow() 33 } 34 mt, err := createMinerTester("TestIntegreationHeaderForWork") 35 if err != nil { 36 t.Fatal(err) 37 } 38 39 // Get a header and solve it. 40 header, target, err := mt.miner.HeaderForWork() 41 if err != nil { 42 t.Fatal(err) 43 } 44 solvedHeader := solveHeader(header, target) 45 // Sanity check - header and solvedHeader should be different. (within the 46 // testing file, 'header' should always have a nonce of '0' and 47 // solvedHeader should never have a nonce of '0'. 48 if header.Nonce == solvedHeader.Nonce { 49 t.Fatal("nonce memory is not independent") 50 } 51 52 // Submit the header. 53 err = mt.miner.SubmitHeader(solvedHeader) 54 if err != nil { 55 t.Fatal(err) 56 } 57 } 58 59 // TestIntegrationHeaderForWorkUpdates checks that HeaderForWork starts 60 // returning headers on the new block after a block has been submitted to the 61 // consensus set. 62 func TestIntegrationHeaderForWorkUpdates(t *testing.T) { 63 if testing.Short() { 64 t.SkipNow() 65 } 66 mt, err := createMinerTester("TestIntegreationHeaderForWorkUpdates") 67 if err != nil { 68 t.Fatal(err) 69 } 70 71 // Get a header to advance into the header memory. 72 _, _, err = mt.miner.HeaderForWork() 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 // Submit a block, which should trigger a header change. 78 _, err = mt.miner.AddBlock() 79 if err != nil { 80 t.Fatal(err) 81 } 82 83 // Get a header to grind on. 84 header, target, err := mt.miner.HeaderForWork() 85 if err != nil { 86 t.Fatal(err) 87 } 88 solvedHeader := solveHeader(header, target) 89 90 // Submit the header. 91 err = mt.miner.SubmitHeader(solvedHeader) 92 if err != nil { 93 t.Fatal(err) 94 } 95 if !mt.cs.InCurrentPath(types.BlockID(crypto.HashObject(solvedHeader))) { 96 t.Error("header from solved block is not in the current path") 97 } 98 } 99 100 // TestIntegrationManyHeaders checks that requesting a full set of headers a 101 // row results in all unique headers, and that all of them can be reassembled 102 // into valid blocks. 103 func TestIntegrationManyHeaders(t *testing.T) { 104 if testing.Short() { 105 t.SkipNow() 106 } 107 mt, err := createMinerTester("TestIntegrationManyHeaders") 108 if err != nil { 109 t.Fatal(err) 110 } 111 112 // Create a suite of headers for imaginary parallel mining. 113 solvedHeaders := make([]types.BlockHeader, HeaderMemory/BlockMemory*2) 114 for i := range solvedHeaders { 115 header, target, err := mt.miner.HeaderForWork() 116 if err != nil { 117 t.Fatal(err) 118 } 119 solvedHeaders[i] = solveHeader(header, target) 120 } 121 122 // Submit the headers randomly and make sure they are all considered valid. 123 selectionOrder, err := crypto.Perm(len(solvedHeaders)) 124 if err != nil { 125 t.Fatal(err) 126 } 127 for _, selection := range selectionOrder { 128 err = mt.miner.SubmitHeader(solvedHeaders[selection]) 129 if err != nil && err != modules.ErrNonExtendingBlock { 130 t.Error(err) 131 } 132 } 133 } 134 135 // TestIntegrationHeaderBlockOverflow triggers a header overflow by requesting 136 // a block that triggers the overflow. 137 func TestIntegrationHeaderBlockOverflow(t *testing.T) { 138 if testing.Short() { 139 t.SkipNow() 140 } 141 mt, err := createMinerTester("TestIntegrationHeaderBlockOverflow") 142 if err != nil { 143 t.Fatal(err) 144 } 145 146 // Grab a header that will be overwritten. 147 header, target, err := mt.miner.HeaderForWork() 148 if err != nil { 149 t.Fatal(err) 150 } 151 header = solveHeader(header, target) 152 153 // Mine blocks to wrap the memProgress around and wipe the old header. 154 for i := 0; i < BlockMemory; i++ { 155 _, err = mt.miner.AddBlock() 156 if err != nil { 157 t.Fatal(err) 158 } 159 // Grab a header to advance the mempool progress. 160 _, _, err = mt.miner.HeaderForWork() 161 if err != nil { 162 t.Fatal(err) 163 } 164 } 165 166 // Previous header should no longer be in memory. 167 err = mt.miner.SubmitHeader(header) 168 if err != errLateHeader { 169 t.Error(err) 170 } 171 } 172 173 // TestIntegrationHeaderRequestOverflow triggers a header overflow by 174 // requesting a header that triggers overflow. 175 func TestIntegrationHeaderRequestOverflow(t *testing.T) { 176 if testing.Short() { 177 t.SkipNow() 178 } 179 mt, err := createMinerTester("TestIntegrationHeaderRequestOverflow") 180 if err != nil { 181 t.Fatal(err) 182 } 183 184 // Grab a header that will be overwritten. 185 header, target, err := mt.miner.HeaderForWork() 186 if err != nil { 187 t.Fatal(err) 188 } 189 header = solveHeader(header, target) 190 191 // Mine blocks to bring memProgress up to the edge. The number is chosen 192 // specifically so that the overflow happens during the requesting of 200 193 // headers. 194 for i := 0; i < BlockMemory-1; i++ { 195 _, err = mt.miner.AddBlock() 196 if err != nil { 197 t.Fatal(err) 198 } 199 // Grab a header to advance the mempool progress. 200 _, _, err = mt.miner.HeaderForWork() 201 if err != nil { 202 t.Fatal(err) 203 } 204 } 205 206 // Header should still be in memory. 207 err = mt.miner.SubmitHeader(header) 208 if err != modules.ErrNonExtendingBlock { 209 t.Error(err) 210 } 211 212 // Request headers until the overflow is achieved. 213 for i := 0; i < HeaderMemory/BlockMemory; i++ { 214 _, _, err = mt.miner.HeaderForWork() 215 if err != nil { 216 t.Fatal(err) 217 } 218 } 219 220 err = mt.miner.SubmitHeader(header) 221 if err != errLateHeader { 222 t.Error(err) 223 } 224 }