OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / blockchain / chain_test.go
1 // Copyright (c) 2013-2017 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4
5 package blockchain
6
7 import (
8         "reflect"
9         "testing"
10         "time"
11
12         "github.com/btcsuite/btcd/chaincfg"
13         "github.com/btcsuite/btcd/chaincfg/chainhash"
14         "github.com/btcsuite/btcd/wire"
15         "github.com/btcsuite/btcutil"
16 )
17
18 // TestHaveBlock tests the HaveBlock API to ensure proper functionality.
19 func TestHaveBlock(t *testing.T) {
20         // Load up blocks such that there is a side chain.
21         // (genesis block) -> 1 -> 2 -> 3 -> 4
22         //                          \-> 3a
23         testFiles := []string{
24                 "blk_0_to_4.dat.bz2",
25                 "blk_3A.dat.bz2",
26         }
27
28         var blocks []*btcutil.Block
29         for _, file := range testFiles {
30                 blockTmp, err := loadBlocks(file)
31                 if err != nil {
32                         t.Errorf("Error loading file: %v\n", err)
33                         return
34                 }
35                 blocks = append(blocks, blockTmp...)
36         }
37
38         // Create a new database and chain instance to run tests against.
39         chain, teardownFunc, err := chainSetup("haveblock",
40                 &chaincfg.MainNetParams)
41         if err != nil {
42                 t.Errorf("Failed to setup chain instance: %v", err)
43                 return
44         }
45         defer teardownFunc()
46
47         // Since we're not dealing with the real block chain, set the coinbase
48         // maturity to 1.
49         chain.TstSetCoinbaseMaturity(1)
50
51         for i := 1; i < len(blocks); i++ {
52                 _, isOrphan, err := chain.ProcessBlock(blocks[i], BFNone)
53                 if err != nil {
54                         t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
55                         return
56                 }
57                 if isOrphan {
58                         t.Errorf("ProcessBlock incorrectly returned block %v "+
59                                 "is an orphan\n", i)
60                         return
61                 }
62         }
63
64         // Insert an orphan block.
65         _, isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000),
66                 BFNone)
67         if err != nil {
68                 t.Errorf("Unable to process block: %v", err)
69                 return
70         }
71         if !isOrphan {
72                 t.Errorf("ProcessBlock indicated block is an not orphan when " +
73                         "it should be\n")
74                 return
75         }
76
77         tests := []struct {
78                 hash string
79                 want bool
80         }{
81                 // Genesis block should be present (in the main chain).
82                 {hash: chaincfg.MainNetParams.GenesisHash.String(), want: true},
83
84                 // Block 3a should be present (on a side chain).
85                 {hash: "00000000474284d20067a4d33f6a02284e6ef70764a3a26d6a5b9df52ef663dd", want: true},
86
87                 // Block 100000 should be present (as an orphan).
88                 {hash: "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506", want: true},
89
90                 // Random hashes should not be available.
91                 {hash: "123", want: false},
92         }
93
94         for i, test := range tests {
95                 hash, err := chainhash.NewHashFromStr(test.hash)
96                 if err != nil {
97                         t.Errorf("NewHashFromStr: %v", err)
98                         continue
99                 }
100
101                 result, err := chain.HaveBlock(hash)
102                 if err != nil {
103                         t.Errorf("HaveBlock #%d unexpected error: %v", i, err)
104                         return
105                 }
106                 if result != test.want {
107                         t.Errorf("HaveBlock #%d got %v want %v", i, result,
108                                 test.want)
109                         continue
110                 }
111         }
112 }
113
114 // TestCalcSequenceLock tests the LockTimeToSequence function, and the
115 // CalcSequenceLock method of a Chain instance. The tests exercise several
116 // combinations of inputs to the CalcSequenceLock function in order to ensure
117 // the returned SequenceLocks are correct for each test instance.
118 func TestCalcSequenceLock(t *testing.T) {
119         netParams := &chaincfg.SimNetParams
120
121         // We need to activate CSV in order to test the processing logic, so
122         // manually craft the block version that's used to signal the soft-fork
123         // activation.
124         csvBit := netParams.Deployments[chaincfg.DeploymentCSV].BitNumber
125         blockVersion := int32(0x20000000 | (uint32(1) << csvBit))
126
127         // Generate enough synthetic blocks to activate CSV.
128         chain := newFakeChain(netParams)
129         node := chain.bestChain.Tip()
130         blockTime := node.Header().Timestamp
131         numBlocksToActivate := (netParams.MinerConfirmationWindow * 3)
132         for i := uint32(0); i < numBlocksToActivate; i++ {
133                 blockTime = blockTime.Add(time.Second)
134                 node = newFakeNode(node, blockVersion, 0, blockTime)
135                 chain.index.AddNode(node)
136                 chain.bestChain.SetTip(node)
137         }
138
139         // Create a utxo view with a fake utxo for the inputs used in the
140         // transactions created below.  This utxo is added such that it has an
141         // age of 4 blocks.
142         targetTx := btcutil.NewTx(&wire.MsgTx{
143                 TxOut: []*wire.TxOut{{
144                         PkScript: nil,
145                         Value:    10,
146                 }},
147         })
148         utxoView := NewUtxoViewpoint()
149         utxoView.AddTxOuts(targetTx, int32(numBlocksToActivate)-4)
150         utxoView.SetBestHash(&node.hash)
151
152         // Create a utxo that spends the fake utxo created above for use in the
153         // transactions created in the tests.  It has an age of 4 blocks.  Note
154         // that the sequence lock heights are always calculated from the same
155         // point of view that they were originally calculated from for a given
156         // utxo.  That is to say, the height prior to it.
157         utxo := wire.OutPoint{
158                 Hash:  *targetTx.Hash(),
159                 Index: 0,
160         }
161         prevUtxoHeight := int32(numBlocksToActivate) - 4
162
163         // Obtain the median time past from the PoV of the input created above.
164         // The MTP for the input is the MTP from the PoV of the block *prior*
165         // to the one that included it.
166         medianTime := node.RelativeAncestor(5).CalcPastMedianTime().Unix()
167
168         // The median time calculated from the PoV of the best block in the
169         // test chain.  For unconfirmed inputs, this value will be used since
170         // the MTP will be calculated from the PoV of the yet-to-be-mined
171         // block.
172         nextMedianTime := node.CalcPastMedianTime().Unix()
173         nextBlockHeight := int32(numBlocksToActivate) + 1
174
175         // Add an additional transaction which will serve as our unconfirmed
176         // output.
177         unConfTx := &wire.MsgTx{
178                 TxOut: []*wire.TxOut{{
179                         PkScript: nil,
180                         Value:    5,
181                 }},
182         }
183         unConfUtxo := wire.OutPoint{
184                 Hash:  unConfTx.TxHash(),
185                 Index: 0,
186         }
187
188         // Adding a utxo with a height of 0x7fffffff indicates that the output
189         // is currently unmined.
190         utxoView.AddTxOuts(btcutil.NewTx(unConfTx), 0x7fffffff)
191
192         tests := []struct {
193                 tx      *wire.MsgTx
194                 view    *UtxoViewpoint
195                 mempool bool
196                 want    *SequenceLock
197         }{
198                 // A transaction of version one should disable sequence locks
199                 // as the new sequence number semantics only apply to
200                 // transactions version 2 or higher.
201                 {
202                         tx: &wire.MsgTx{
203                                 Version: 1,
204                                 TxIn: []*wire.TxIn{{
205                                         PreviousOutPoint: utxo,
206                                         Sequence:         LockTimeToSequence(false, 3),
207                                 }},
208                         },
209                         view: utxoView,
210                         want: &SequenceLock{
211                                 Seconds:     -1,
212                                 BlockHeight: -1,
213                         },
214                 },
215                 // A transaction with a single input with max sequence number.
216                 // This sequence number has the high bit set, so sequence locks
217                 // should be disabled.
218                 {
219                         tx: &wire.MsgTx{
220                                 Version: 2,
221                                 TxIn: []*wire.TxIn{{
222                                         PreviousOutPoint: utxo,
223                                         Sequence:         wire.MaxTxInSequenceNum,
224                                 }},
225                         },
226                         view: utxoView,
227                         want: &SequenceLock{
228                                 Seconds:     -1,
229                                 BlockHeight: -1,
230                         },
231                 },
232                 // A transaction with a single input whose lock time is
233                 // expressed in seconds.  However, the specified lock time is
234                 // below the required floor for time based lock times since
235                 // they have time granularity of 512 seconds.  As a result, the
236                 // seconds lock-time should be just before the median time of
237                 // the targeted block.
238                 {
239                         tx: &wire.MsgTx{
240                                 Version: 2,
241                                 TxIn: []*wire.TxIn{{
242                                         PreviousOutPoint: utxo,
243                                         Sequence:         LockTimeToSequence(true, 2),
244                                 }},
245                         },
246                         view: utxoView,
247                         want: &SequenceLock{
248                                 Seconds:     medianTime - 1,
249                                 BlockHeight: -1,
250                         },
251                 },
252                 // A transaction with a single input whose lock time is
253                 // expressed in seconds.  The number of seconds should be 1023
254                 // seconds after the median past time of the last block in the
255                 // chain.
256                 {
257                         tx: &wire.MsgTx{
258                                 Version: 2,
259                                 TxIn: []*wire.TxIn{{
260                                         PreviousOutPoint: utxo,
261                                         Sequence:         LockTimeToSequence(true, 1024),
262                                 }},
263                         },
264                         view: utxoView,
265                         want: &SequenceLock{
266                                 Seconds:     medianTime + 1023,
267                                 BlockHeight: -1,
268                         },
269                 },
270                 // A transaction with multiple inputs.  The first input has a
271                 // lock time expressed in seconds.  The second input has a
272                 // sequence lock in blocks with a value of 4.  The last input
273                 // has a sequence number with a value of 5, but has the disable
274                 // bit set.  So the first lock should be selected as it's the
275                 // latest lock that isn't disabled.
276                 {
277                         tx: &wire.MsgTx{
278                                 Version: 2,
279                                 TxIn: []*wire.TxIn{{
280                                         PreviousOutPoint: utxo,
281                                         Sequence:         LockTimeToSequence(true, 2560),
282                                 }, {
283                                         PreviousOutPoint: utxo,
284                                         Sequence:         LockTimeToSequence(false, 4),
285                                 }, {
286                                         PreviousOutPoint: utxo,
287                                         Sequence: LockTimeToSequence(false, 5) |
288                                                 wire.SequenceLockTimeDisabled,
289                                 }},
290                         },
291                         view: utxoView,
292                         want: &SequenceLock{
293                                 Seconds:     medianTime + (5 << wire.SequenceLockTimeGranularity) - 1,
294                                 BlockHeight: prevUtxoHeight + 3,
295                         },
296                 },
297                 // Transaction with a single input.  The input's sequence number
298                 // encodes a relative lock-time in blocks (3 blocks).  The
299                 // sequence lock should  have a value of -1 for seconds, but a
300                 // height of 2 meaning it can be included at height 3.
301                 {
302                         tx: &wire.MsgTx{
303                                 Version: 2,
304                                 TxIn: []*wire.TxIn{{
305                                         PreviousOutPoint: utxo,
306                                         Sequence:         LockTimeToSequence(false, 3),
307                                 }},
308                         },
309                         view: utxoView,
310                         want: &SequenceLock{
311                                 Seconds:     -1,
312                                 BlockHeight: prevUtxoHeight + 2,
313                         },
314                 },
315                 // A transaction with two inputs with lock times expressed in
316                 // seconds.  The selected sequence lock value for seconds should
317                 // be the time further in the future.
318                 {
319                         tx: &wire.MsgTx{
320                                 Version: 2,
321                                 TxIn: []*wire.TxIn{{
322                                         PreviousOutPoint: utxo,
323                                         Sequence:         LockTimeToSequence(true, 5120),
324                                 }, {
325                                         PreviousOutPoint: utxo,
326                                         Sequence:         LockTimeToSequence(true, 2560),
327                                 }},
328                         },
329                         view: utxoView,
330                         want: &SequenceLock{
331                                 Seconds:     medianTime + (10 << wire.SequenceLockTimeGranularity) - 1,
332                                 BlockHeight: -1,
333                         },
334                 },
335                 // A transaction with two inputs with lock times expressed in
336                 // blocks.  The selected sequence lock value for blocks should
337                 // be the height further in the future, so a height of 10
338                 // indicating it can be included at height 11.
339                 {
340                         tx: &wire.MsgTx{
341                                 Version: 2,
342                                 TxIn: []*wire.TxIn{{
343                                         PreviousOutPoint: utxo,
344                                         Sequence:         LockTimeToSequence(false, 1),
345                                 }, {
346                                         PreviousOutPoint: utxo,
347                                         Sequence:         LockTimeToSequence(false, 11),
348                                 }},
349                         },
350                         view: utxoView,
351                         want: &SequenceLock{
352                                 Seconds:     -1,
353                                 BlockHeight: prevUtxoHeight + 10,
354                         },
355                 },
356                 // A transaction with multiple inputs.  Two inputs are time
357                 // based, and the other two are block based. The lock lying
358                 // further into the future for both inputs should be chosen.
359                 {
360                         tx: &wire.MsgTx{
361                                 Version: 2,
362                                 TxIn: []*wire.TxIn{{
363                                         PreviousOutPoint: utxo,
364                                         Sequence:         LockTimeToSequence(true, 2560),
365                                 }, {
366                                         PreviousOutPoint: utxo,
367                                         Sequence:         LockTimeToSequence(true, 6656),
368                                 }, {
369                                         PreviousOutPoint: utxo,
370                                         Sequence:         LockTimeToSequence(false, 3),
371                                 }, {
372                                         PreviousOutPoint: utxo,
373                                         Sequence:         LockTimeToSequence(false, 9),
374                                 }},
375                         },
376                         view: utxoView,
377                         want: &SequenceLock{
378                                 Seconds:     medianTime + (13 << wire.SequenceLockTimeGranularity) - 1,
379                                 BlockHeight: prevUtxoHeight + 8,
380                         },
381                 },
382                 // A transaction with a single unconfirmed input.  As the input
383                 // is confirmed, the height of the input should be interpreted
384                 // as the height of the *next* block.  So, a 2 block relative
385                 // lock means the sequence lock should be for 1 block after the
386                 // *next* block height, indicating it can be included 2 blocks
387                 // after that.
388                 {
389                         tx: &wire.MsgTx{
390                                 Version: 2,
391                                 TxIn: []*wire.TxIn{{
392                                         PreviousOutPoint: unConfUtxo,
393                                         Sequence:         LockTimeToSequence(false, 2),
394                                 }},
395                         },
396                         view:    utxoView,
397                         mempool: true,
398                         want: &SequenceLock{
399                                 Seconds:     -1,
400                                 BlockHeight: nextBlockHeight + 1,
401                         },
402                 },
403                 // A transaction with a single unconfirmed input.  The input has
404                 // a time based lock, so the lock time should be based off the
405                 // MTP of the *next* block.
406                 {
407                         tx: &wire.MsgTx{
408                                 Version: 2,
409                                 TxIn: []*wire.TxIn{{
410                                         PreviousOutPoint: unConfUtxo,
411                                         Sequence:         LockTimeToSequence(true, 1024),
412                                 }},
413                         },
414                         view:    utxoView,
415                         mempool: true,
416                         want: &SequenceLock{
417                                 Seconds:     nextMedianTime + 1023,
418                                 BlockHeight: -1,
419                         },
420                 },
421         }
422
423         t.Logf("Running %v SequenceLock tests", len(tests))
424         for i, test := range tests {
425                 utilTx := btcutil.NewTx(test.tx)
426                 seqLock, err := chain.CalcSequenceLock(utilTx, test.view, test.mempool)
427                 if err != nil {
428                         t.Fatalf("test #%d, unable to calc sequence lock: %v", i, err)
429                 }
430
431                 if seqLock.Seconds != test.want.Seconds {
432                         t.Fatalf("test #%d got %v seconds want %v seconds",
433                                 i, seqLock.Seconds, test.want.Seconds)
434                 }
435                 if seqLock.BlockHeight != test.want.BlockHeight {
436                         t.Fatalf("test #%d got height of %v want height of %v ",
437                                 i, seqLock.BlockHeight, test.want.BlockHeight)
438                 }
439         }
440 }
441
442 // nodeHashes is a convenience function that returns the hashes for all of the
443 // passed indexes of the provided nodes.  It is used to construct expected hash
444 // slices in the tests.
445 func nodeHashes(nodes []*blockNode, indexes ...int) []chainhash.Hash {
446         hashes := make([]chainhash.Hash, 0, len(indexes))
447         for _, idx := range indexes {
448                 hashes = append(hashes, nodes[idx].hash)
449         }
450         return hashes
451 }
452
453 // nodeHeaders is a convenience function that returns the headers for all of
454 // the passed indexes of the provided nodes.  It is used to construct expected
455 // located headers in the tests.
456 func nodeHeaders(nodes []*blockNode, indexes ...int) []wire.BlockHeader {
457         headers := make([]wire.BlockHeader, 0, len(indexes))
458         for _, idx := range indexes {
459                 headers = append(headers, nodes[idx].Header())
460         }
461         return headers
462 }
463
464 // TestLocateInventory ensures that locating inventory via the LocateHeaders and
465 // LocateBlocks functions behaves as expected.
466 func TestLocateInventory(t *testing.T) {
467         // Construct a synthetic block chain with a block index consisting of
468         // the following structure.
469         //      genesis -> 1 -> 2 -> ... -> 15 -> 16  -> 17  -> 18
470         //                                    \-> 16a -> 17a
471         tip := tstTip
472         chain := newFakeChain(&chaincfg.MainNetParams)
473         branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
474         branch1Nodes := chainedNodes(branch0Nodes[14], 2)
475         for _, node := range branch0Nodes {
476                 chain.index.AddNode(node)
477         }
478         for _, node := range branch1Nodes {
479                 chain.index.AddNode(node)
480         }
481         chain.bestChain.SetTip(tip(branch0Nodes))
482
483         // Create chain views for different branches of the overall chain to
484         // simulate a local and remote node on different parts of the chain.
485         localView := newChainView(tip(branch0Nodes))
486         remoteView := newChainView(tip(branch1Nodes))
487
488         // Create a chain view for a completely unrelated block chain to
489         // simulate a remote node on a totally different chain.
490         unrelatedBranchNodes := chainedNodes(nil, 5)
491         unrelatedView := newChainView(tip(unrelatedBranchNodes))
492
493         tests := []struct {
494                 name       string
495                 locator    BlockLocator       // locator for requested inventory
496                 hashStop   chainhash.Hash     // stop hash for locator
497                 maxAllowed uint32             // max to locate, 0 = wire const
498                 headers    []wire.BlockHeader // expected located headers
499                 hashes     []chainhash.Hash   // expected located hashes
500         }{
501                 {
502                         // Empty block locators and unknown stop hash.  No
503                         // inventory should be located.
504                         name:     "no locators, no stop",
505                         locator:  nil,
506                         hashStop: chainhash.Hash{},
507                         headers:  nil,
508                         hashes:   nil,
509                 },
510                 {
511                         // Empty block locators and stop hash in side chain.
512                         // The expected result is the requested block.
513                         name:     "no locators, stop in side",
514                         locator:  nil,
515                         hashStop: tip(branch1Nodes).hash,
516                         headers:  nodeHeaders(branch1Nodes, 1),
517                         hashes:   nodeHashes(branch1Nodes, 1),
518                 },
519                 {
520                         // Empty block locators and stop hash in main chain.
521                         // The expected result is the requested block.
522                         name:     "no locators, stop in main",
523                         locator:  nil,
524                         hashStop: branch0Nodes[12].hash,
525                         headers:  nodeHeaders(branch0Nodes, 12),
526                         hashes:   nodeHashes(branch0Nodes, 12),
527                 },
528                 {
529                         // Locators based on remote being on side chain and a
530                         // stop hash local node doesn't know about.  The
531                         // expected result is the blocks after the fork point in
532                         // the main chain and the stop hash has no effect.
533                         name:     "remote side chain, unknown stop",
534                         locator:  remoteView.BlockLocator(nil),
535                         hashStop: chainhash.Hash{0x01},
536                         headers:  nodeHeaders(branch0Nodes, 15, 16, 17),
537                         hashes:   nodeHashes(branch0Nodes, 15, 16, 17),
538                 },
539                 {
540                         // Locators based on remote being on side chain and a
541                         // stop hash in side chain.  The expected result is the
542                         // blocks after the fork point in the main chain and the
543                         // stop hash has no effect.
544                         name:     "remote side chain, stop in side",
545                         locator:  remoteView.BlockLocator(nil),
546                         hashStop: tip(branch1Nodes).hash,
547                         headers:  nodeHeaders(branch0Nodes, 15, 16, 17),
548                         hashes:   nodeHashes(branch0Nodes, 15, 16, 17),
549                 },
550                 {
551                         // Locators based on remote being on side chain and a
552                         // stop hash in main chain, but before fork point.  The
553                         // expected result is the blocks after the fork point in
554                         // the main chain and the stop hash has no effect.
555                         name:     "remote side chain, stop in main before",
556                         locator:  remoteView.BlockLocator(nil),
557                         hashStop: branch0Nodes[13].hash,
558                         headers:  nodeHeaders(branch0Nodes, 15, 16, 17),
559                         hashes:   nodeHashes(branch0Nodes, 15, 16, 17),
560                 },
561                 {
562                         // Locators based on remote being on side chain and a
563                         // stop hash in main chain, but exactly at the fork
564                         // point.  The expected result is the blocks after the
565                         // fork point in the main chain and the stop hash has no
566                         // effect.
567                         name:     "remote side chain, stop in main exact",
568                         locator:  remoteView.BlockLocator(nil),
569                         hashStop: branch0Nodes[14].hash,
570                         headers:  nodeHeaders(branch0Nodes, 15, 16, 17),
571                         hashes:   nodeHashes(branch0Nodes, 15, 16, 17),
572                 },
573                 {
574                         // Locators based on remote being on side chain and a
575                         // stop hash in main chain just after the fork point.
576                         // The expected result is the blocks after the fork
577                         // point in the main chain up to and including the stop
578                         // hash.
579                         name:     "remote side chain, stop in main after",
580                         locator:  remoteView.BlockLocator(nil),
581                         hashStop: branch0Nodes[15].hash,
582                         headers:  nodeHeaders(branch0Nodes, 15),
583                         hashes:   nodeHashes(branch0Nodes, 15),
584                 },
585                 {
586                         // Locators based on remote being on side chain and a
587                         // stop hash in main chain some time after the fork
588                         // point.  The expected result is the blocks after the
589                         // fork point in the main chain up to and including the
590                         // stop hash.
591                         name:     "remote side chain, stop in main after more",
592                         locator:  remoteView.BlockLocator(nil),
593                         hashStop: branch0Nodes[16].hash,
594                         headers:  nodeHeaders(branch0Nodes, 15, 16),
595                         hashes:   nodeHashes(branch0Nodes, 15, 16),
596                 },
597                 {
598                         // Locators based on remote being on main chain in the
599                         // past and a stop hash local node doesn't know about.
600                         // The expected result is the blocks after the known
601                         // point in the main chain and the stop hash has no
602                         // effect.
603                         name:     "remote main chain past, unknown stop",
604                         locator:  localView.BlockLocator(branch0Nodes[12]),
605                         hashStop: chainhash.Hash{0x01},
606                         headers:  nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
607                         hashes:   nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
608                 },
609                 {
610                         // Locators based on remote being on main chain in the
611                         // past and a stop hash in a side chain.  The expected
612                         // result is the blocks after the known point in the
613                         // main chain and the stop hash has no effect.
614                         name:     "remote main chain past, stop in side",
615                         locator:  localView.BlockLocator(branch0Nodes[12]),
616                         hashStop: tip(branch1Nodes).hash,
617                         headers:  nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
618                         hashes:   nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
619                 },
620                 {
621                         // Locators based on remote being on main chain in the
622                         // past and a stop hash in the main chain before that
623                         // point.  The expected result is the blocks after the
624                         // known point in the main chain and the stop hash has
625                         // no effect.
626                         name:     "remote main chain past, stop in main before",
627                         locator:  localView.BlockLocator(branch0Nodes[12]),
628                         hashStop: branch0Nodes[11].hash,
629                         headers:  nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
630                         hashes:   nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
631                 },
632                 {
633                         // Locators based on remote being on main chain in the
634                         // past and a stop hash in the main chain exactly at that
635                         // point.  The expected result is the blocks after the
636                         // known point in the main chain and the stop hash has
637                         // no effect.
638                         name:     "remote main chain past, stop in main exact",
639                         locator:  localView.BlockLocator(branch0Nodes[12]),
640                         hashStop: branch0Nodes[12].hash,
641                         headers:  nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
642                         hashes:   nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
643                 },
644                 {
645                         // Locators based on remote being on main chain in the
646                         // past and a stop hash in the main chain just after
647                         // that point.  The expected result is the blocks after
648                         // the known point in the main chain and the stop hash
649                         // has no effect.
650                         name:     "remote main chain past, stop in main after",
651                         locator:  localView.BlockLocator(branch0Nodes[12]),
652                         hashStop: branch0Nodes[13].hash,
653                         headers:  nodeHeaders(branch0Nodes, 13),
654                         hashes:   nodeHashes(branch0Nodes, 13),
655                 },
656                 {
657                         // Locators based on remote being on main chain in the
658                         // past and a stop hash in the main chain some time
659                         // after that point.  The expected result is the blocks
660                         // after the known point in the main chain and the stop
661                         // hash has no effect.
662                         name:     "remote main chain past, stop in main after more",
663                         locator:  localView.BlockLocator(branch0Nodes[12]),
664                         hashStop: branch0Nodes[15].hash,
665                         headers:  nodeHeaders(branch0Nodes, 13, 14, 15),
666                         hashes:   nodeHashes(branch0Nodes, 13, 14, 15),
667                 },
668                 {
669                         // Locators based on remote being at exactly the same
670                         // point in the main chain and a stop hash local node
671                         // doesn't know about.  The expected result is no
672                         // located inventory.
673                         name:     "remote main chain same, unknown stop",
674                         locator:  localView.BlockLocator(nil),
675                         hashStop: chainhash.Hash{0x01},
676                         headers:  nil,
677                         hashes:   nil,
678                 },
679                 {
680                         // Locators based on remote being at exactly the same
681                         // point in the main chain and a stop hash at exactly
682                         // the same point.  The expected result is no located
683                         // inventory.
684                         name:     "remote main chain same, stop same point",
685                         locator:  localView.BlockLocator(nil),
686                         hashStop: tip(branch0Nodes).hash,
687                         headers:  nil,
688                         hashes:   nil,
689                 },
690                 {
691                         // Locators from remote that don't include any blocks
692                         // the local node knows.  This would happen if the
693                         // remote node is on a completely separate chain that
694                         // isn't rooted with the same genesis block.  The
695                         // expected result is the blocks after the genesis
696                         // block.
697                         name:     "remote unrelated chain",
698                         locator:  unrelatedView.BlockLocator(nil),
699                         hashStop: chainhash.Hash{},
700                         headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
701                                 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
702                         hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
703                                 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
704                 },
705                 {
706                         // Locators from remote for second block in main chain
707                         // and no stop hash, but with an overridden max limit.
708                         // The expected result is the blocks after the second
709                         // block limited by the max.
710                         name:       "remote genesis",
711                         locator:    locatorHashes(branch0Nodes, 0),
712                         hashStop:   chainhash.Hash{},
713                         maxAllowed: 3,
714                         headers:    nodeHeaders(branch0Nodes, 1, 2, 3),
715                         hashes:     nodeHashes(branch0Nodes, 1, 2, 3),
716                 },
717                 {
718                         // Poorly formed locator.
719                         //
720                         // Locator from remote that only includes a single
721                         // block on a side chain the local node knows.  The
722                         // expected result is the blocks after the genesis
723                         // block since even though the block is known, it is on
724                         // a side chain and there are no more locators to find
725                         // the fork point.
726                         name:     "weak locator, single known side block",
727                         locator:  locatorHashes(branch1Nodes, 1),
728                         hashStop: chainhash.Hash{},
729                         headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
730                                 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
731                         hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
732                                 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
733                 },
734                 {
735                         // Poorly formed locator.
736                         //
737                         // Locator from remote that only includes multiple
738                         // blocks on a side chain the local node knows however
739                         // none in the main chain.  The expected result is the
740                         // blocks after the genesis block since even though the
741                         // blocks are known, they are all on a side chain and
742                         // there are no more locators to find the fork point.
743                         name:     "weak locator, multiple known side blocks",
744                         locator:  locatorHashes(branch1Nodes, 1),
745                         hashStop: chainhash.Hash{},
746                         headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
747                                 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
748                         hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
749                                 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
750                 },
751                 {
752                         // Poorly formed locator.
753                         //
754                         // Locator from remote that only includes multiple
755                         // blocks on a side chain the local node knows however
756                         // none in the main chain but includes a stop hash in
757                         // the main chain.  The expected result is the blocks
758                         // after the genesis block up to the stop hash since
759                         // even though the blocks are known, they are all on a
760                         // side chain and there are no more locators to find the
761                         // fork point.
762                         name:     "weak locator, multiple known side blocks, stop in main",
763                         locator:  locatorHashes(branch1Nodes, 1),
764                         hashStop: branch0Nodes[5].hash,
765                         headers:  nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5),
766                         hashes:   nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5),
767                 },
768         }
769         for _, test := range tests {
770                 // Ensure the expected headers are located.
771                 var headers []wire.BlockHeader
772                 if test.maxAllowed != 0 {
773                         // Need to use the unexported function to override the
774                         // max allowed for headers.
775                         chain.chainLock.RLock()
776                         headers = chain.locateHeaders(test.locator,
777                                 &test.hashStop, test.maxAllowed)
778                         chain.chainLock.RUnlock()
779                 } else {
780                         headers = chain.LocateHeaders(test.locator,
781                                 &test.hashStop)
782                 }
783                 if !reflect.DeepEqual(headers, test.headers) {
784                         t.Errorf("%s: unxpected headers -- got %v, want %v",
785                                 test.name, headers, test.headers)
786                         continue
787                 }
788
789                 // Ensure the expected block hashes are located.
790                 maxAllowed := uint32(wire.MaxBlocksPerMsg)
791                 if test.maxAllowed != 0 {
792                         maxAllowed = test.maxAllowed
793                 }
794                 hashes := chain.LocateBlocks(test.locator, &test.hashStop,
795                         maxAllowed)
796                 if !reflect.DeepEqual(hashes, test.hashes) {
797                         t.Errorf("%s: unxpected hashes -- got %v, want %v",
798                                 test.name, hashes, test.hashes)
799                         continue
800                 }
801         }
802 }