OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / database / ffldb / interface_test.go
1 // Copyright (c) 2015-2016 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 // This file intended to be copied into each backend driver directory.  Each
6 // driver should have their own driver_test.go file which creates a database and
7 // invokes the testInterface function in this file to ensure the driver properly
8 // implements the interface.
9 //
10 // NOTE: When copying this file into the backend driver folder, the package name
11 // will need to be changed accordingly.
12
13 package ffldb_test
14
15 import (
16         "bytes"
17         "compress/bzip2"
18         "encoding/binary"
19         "fmt"
20         "io"
21         "os"
22         "path/filepath"
23         "reflect"
24         "sync/atomic"
25         "testing"
26         "time"
27
28         "github.com/btcsuite/btcd/chaincfg"
29         "github.com/btcsuite/btcd/chaincfg/chainhash"
30         "github.com/btcsuite/btcd/database"
31         "github.com/btcsuite/btcd/wire"
32         "github.com/btcsuite/btcutil"
33 )
34
35 var (
36         // blockDataNet is the expected network in the test block data.
37         blockDataNet = wire.MainNet
38
39         // blockDataFile is the path to a file containing the first 256 blocks
40         // of the block chain.
41         blockDataFile = filepath.Join("..", "testdata", "blocks1-256.bz2")
42
43         // errSubTestFail is used to signal that a sub test returned false.
44         errSubTestFail = fmt.Errorf("sub test failure")
45 )
46
47 // loadBlocks loads the blocks contained in the testdata directory and returns
48 // a slice of them.
49 func loadBlocks(t *testing.T, dataFile string, network wire.BitcoinNet) ([]*btcutil.Block, error) {
50         // Open the file that contains the blocks for reading.
51         fi, err := os.Open(dataFile)
52         if err != nil {
53                 t.Errorf("failed to open file %v, err %v", dataFile, err)
54                 return nil, err
55         }
56         defer func() {
57                 if err := fi.Close(); err != nil {
58                         t.Errorf("failed to close file %v %v", dataFile,
59                                 err)
60                 }
61         }()
62         dr := bzip2.NewReader(fi)
63
64         // Set the first block as the genesis block.
65         blocks := make([]*btcutil.Block, 0, 256)
66         genesis := btcutil.NewBlock(chaincfg.MainNetParams.GenesisBlock)
67         blocks = append(blocks, genesis)
68
69         // Load the remaining blocks.
70         for height := 1; ; height++ {
71                 var net uint32
72                 err := binary.Read(dr, binary.LittleEndian, &net)
73                 if err == io.EOF {
74                         // Hit end of file at the expected offset.  No error.
75                         break
76                 }
77                 if err != nil {
78                         t.Errorf("Failed to load network type for block %d: %v",
79                                 height, err)
80                         return nil, err
81                 }
82                 if net != uint32(network) {
83                         t.Errorf("Block doesn't match network: %v expects %v",
84                                 net, network)
85                         return nil, err
86                 }
87
88                 var blockLen uint32
89                 err = binary.Read(dr, binary.LittleEndian, &blockLen)
90                 if err != nil {
91                         t.Errorf("Failed to load block size for block %d: %v",
92                                 height, err)
93                         return nil, err
94                 }
95
96                 // Read the block.
97                 blockBytes := make([]byte, blockLen)
98                 _, err = io.ReadFull(dr, blockBytes)
99                 if err != nil {
100                         t.Errorf("Failed to load block %d: %v", height, err)
101                         return nil, err
102                 }
103
104                 // Deserialize and store the block.
105                 block, err := btcutil.NewBlockFromBytes(blockBytes)
106                 if err != nil {
107                         t.Errorf("Failed to parse block %v: %v", height, err)
108                         return nil, err
109                 }
110                 blocks = append(blocks, block)
111         }
112
113         return blocks, nil
114 }
115
116 // checkDbError ensures the passed error is a database.Error with an error code
117 // that matches the passed  error code.
118 func checkDbError(t *testing.T, testName string, gotErr error, wantErrCode database.ErrorCode) bool {
119         dbErr, ok := gotErr.(database.Error)
120         if !ok {
121                 t.Errorf("%s: unexpected error type - got %T, want %T",
122                         testName, gotErr, database.Error{})
123                 return false
124         }
125         if dbErr.ErrorCode != wantErrCode {
126                 t.Errorf("%s: unexpected error code - got %s (%s), want %s",
127                         testName, dbErr.ErrorCode, dbErr.Description,
128                         wantErrCode)
129                 return false
130         }
131
132         return true
133 }
134
135 // testContext is used to store context information about a running test which
136 // is passed into helper functions.
137 type testContext struct {
138         t           *testing.T
139         db          database.DB
140         bucketDepth int
141         isWritable  bool
142         blocks      []*btcutil.Block
143 }
144
145 // keyPair houses a key/value pair.  It is used over maps so ordering can be
146 // maintained.
147 type keyPair struct {
148         key   []byte
149         value []byte
150 }
151
152 // lookupKey is a convenience method to lookup the requested key from the
153 // provided keypair slice along with whether or not the key was found.
154 func lookupKey(key []byte, values []keyPair) ([]byte, bool) {
155         for _, item := range values {
156                 if bytes.Equal(item.key, key) {
157                         return item.value, true
158                 }
159         }
160
161         return nil, false
162 }
163
164 // toGetValues returns a copy of the provided keypairs with all of the nil
165 // values set to an empty byte slice.  This is used to ensure that keys set to
166 // nil values result in empty byte slices when retrieved instead of nil.
167 func toGetValues(values []keyPair) []keyPair {
168         ret := make([]keyPair, len(values))
169         copy(ret, values)
170         for i := range ret {
171                 if ret[i].value == nil {
172                         ret[i].value = make([]byte, 0)
173                 }
174         }
175         return ret
176 }
177
178 // rollbackValues returns a copy of the provided keypairs with all values set to
179 // nil.  This is used to test that values are properly rolled back.
180 func rollbackValues(values []keyPair) []keyPair {
181         ret := make([]keyPair, len(values))
182         copy(ret, values)
183         for i := range ret {
184                 ret[i].value = nil
185         }
186         return ret
187 }
188
189 // testCursorKeyPair checks that the provide key and value match the expected
190 // keypair at the provided index.  It also ensures the index is in range for the
191 // provided slice of expected keypairs.
192 func testCursorKeyPair(tc *testContext, k, v []byte, index int, values []keyPair) bool {
193         if index >= len(values) || index < 0 {
194                 tc.t.Errorf("Cursor: exceeded the expected range of values - "+
195                         "index %d, num values %d", index, len(values))
196                 return false
197         }
198
199         pair := &values[index]
200         if !bytes.Equal(k, pair.key) {
201                 tc.t.Errorf("Mismatched cursor key: index %d does not match "+
202                         "the expected key - got %q, want %q", index, k,
203                         pair.key)
204                 return false
205         }
206         if !bytes.Equal(v, pair.value) {
207                 tc.t.Errorf("Mismatched cursor value: index %d does not match "+
208                         "the expected value - got %q, want %q", index, v,
209                         pair.value)
210                 return false
211         }
212
213         return true
214 }
215
216 // testGetValues checks that all of the provided key/value pairs can be
217 // retrieved from the database and the retrieved values match the provided
218 // values.
219 func testGetValues(tc *testContext, bucket database.Bucket, values []keyPair) bool {
220         for _, item := range values {
221                 gotValue := bucket.Get(item.key)
222                 if !reflect.DeepEqual(gotValue, item.value) {
223                         tc.t.Errorf("Get: unexpected value for %q - got %q, "+
224                                 "want %q", item.key, gotValue, item.value)
225                         return false
226                 }
227         }
228
229         return true
230 }
231
232 // testPutValues stores all of the provided key/value pairs in the provided
233 // bucket while checking for errors.
234 func testPutValues(tc *testContext, bucket database.Bucket, values []keyPair) bool {
235         for _, item := range values {
236                 if err := bucket.Put(item.key, item.value); err != nil {
237                         tc.t.Errorf("Put: unexpected error: %v", err)
238                         return false
239                 }
240         }
241
242         return true
243 }
244
245 // testDeleteValues removes all of the provided key/value pairs from the
246 // provided bucket.
247 func testDeleteValues(tc *testContext, bucket database.Bucket, values []keyPair) bool {
248         for _, item := range values {
249                 if err := bucket.Delete(item.key); err != nil {
250                         tc.t.Errorf("Delete: unexpected error: %v", err)
251                         return false
252                 }
253         }
254
255         return true
256 }
257
258 // testCursorInterface ensures the cursor itnerface is working properly by
259 // exercising all of its functions on the passed bucket.
260 func testCursorInterface(tc *testContext, bucket database.Bucket) bool {
261         // Ensure a cursor can be obtained for the bucket.
262         cursor := bucket.Cursor()
263         if cursor == nil {
264                 tc.t.Error("Bucket.Cursor: unexpected nil cursor returned")
265                 return false
266         }
267
268         // Ensure the cursor returns the same bucket it was created for.
269         if cursor.Bucket() != bucket {
270                 tc.t.Error("Cursor.Bucket: does not match the bucket it was " +
271                         "created for")
272                 return false
273         }
274
275         if tc.isWritable {
276                 unsortedValues := []keyPair{
277                         {[]byte("cursor"), []byte("val1")},
278                         {[]byte("abcd"), []byte("val2")},
279                         {[]byte("bcd"), []byte("val3")},
280                         {[]byte("defg"), nil},
281                 }
282                 sortedValues := []keyPair{
283                         {[]byte("abcd"), []byte("val2")},
284                         {[]byte("bcd"), []byte("val3")},
285                         {[]byte("cursor"), []byte("val1")},
286                         {[]byte("defg"), nil},
287                 }
288
289                 // Store the values to be used in the cursor tests in unsorted
290                 // order and ensure they were actually stored.
291                 if !testPutValues(tc, bucket, unsortedValues) {
292                         return false
293                 }
294                 if !testGetValues(tc, bucket, toGetValues(unsortedValues)) {
295                         return false
296                 }
297
298                 // Ensure the cursor returns all items in byte-sorted order when
299                 // iterating forward.
300                 curIdx := 0
301                 for ok := cursor.First(); ok; ok = cursor.Next() {
302                         k, v := cursor.Key(), cursor.Value()
303                         if !testCursorKeyPair(tc, k, v, curIdx, sortedValues) {
304                                 return false
305                         }
306                         curIdx++
307                 }
308                 if curIdx != len(unsortedValues) {
309                         tc.t.Errorf("Cursor: expected to iterate %d values, "+
310                                 "but only iterated %d", len(unsortedValues),
311                                 curIdx)
312                         return false
313                 }
314
315                 // Ensure the cursor returns all items in reverse byte-sorted
316                 // order when iterating in reverse.
317                 curIdx = len(sortedValues) - 1
318                 for ok := cursor.Last(); ok; ok = cursor.Prev() {
319                         k, v := cursor.Key(), cursor.Value()
320                         if !testCursorKeyPair(tc, k, v, curIdx, sortedValues) {
321                                 return false
322                         }
323                         curIdx--
324                 }
325                 if curIdx > -1 {
326                         tc.t.Errorf("Reverse cursor: expected to iterate %d "+
327                                 "values, but only iterated %d",
328                                 len(sortedValues), len(sortedValues)-(curIdx+1))
329                         return false
330                 }
331
332                 // Ensure forward iteration works as expected after seeking.
333                 middleIdx := (len(sortedValues) - 1) / 2
334                 seekKey := sortedValues[middleIdx].key
335                 curIdx = middleIdx
336                 for ok := cursor.Seek(seekKey); ok; ok = cursor.Next() {
337                         k, v := cursor.Key(), cursor.Value()
338                         if !testCursorKeyPair(tc, k, v, curIdx, sortedValues) {
339                                 return false
340                         }
341                         curIdx++
342                 }
343                 if curIdx != len(sortedValues) {
344                         tc.t.Errorf("Cursor after seek: expected to iterate "+
345                                 "%d values, but only iterated %d",
346                                 len(sortedValues)-middleIdx, curIdx-middleIdx)
347                         return false
348                 }
349
350                 // Ensure reverse iteration works as expected after seeking.
351                 curIdx = middleIdx
352                 for ok := cursor.Seek(seekKey); ok; ok = cursor.Prev() {
353                         k, v := cursor.Key(), cursor.Value()
354                         if !testCursorKeyPair(tc, k, v, curIdx, sortedValues) {
355                                 return false
356                         }
357                         curIdx--
358                 }
359                 if curIdx > -1 {
360                         tc.t.Errorf("Reverse cursor after seek: expected to "+
361                                 "iterate %d values, but only iterated %d",
362                                 len(sortedValues)-middleIdx, middleIdx-curIdx)
363                         return false
364                 }
365
366                 // Ensure the cursor deletes items properly.
367                 if !cursor.First() {
368                         tc.t.Errorf("Cursor.First: no value")
369                         return false
370                 }
371                 k := cursor.Key()
372                 if err := cursor.Delete(); err != nil {
373                         tc.t.Errorf("Cursor.Delete: unexpected error: %v", err)
374                         return false
375                 }
376                 if val := bucket.Get(k); val != nil {
377                         tc.t.Errorf("Cursor.Delete: value for key %q was not "+
378                                 "deleted", k)
379                         return false
380                 }
381         }
382
383         return true
384 }
385
386 // testNestedBucket reruns the testBucketInterface against a nested bucket along
387 // with a counter to only test a couple of level deep.
388 func testNestedBucket(tc *testContext, testBucket database.Bucket) bool {
389         // Don't go more than 2 nested levels deep.
390         if tc.bucketDepth > 1 {
391                 return true
392         }
393
394         tc.bucketDepth++
395         defer func() {
396                 tc.bucketDepth--
397         }()
398         return testBucketInterface(tc, testBucket)
399 }
400
401 // testBucketInterface ensures the bucket interface is working properly by
402 // exercising all of its functions.  This includes the cursor interface for the
403 // cursor returned from the bucket.
404 func testBucketInterface(tc *testContext, bucket database.Bucket) bool {
405         if bucket.Writable() != tc.isWritable {
406                 tc.t.Errorf("Bucket writable state does not match.")
407                 return false
408         }
409
410         if tc.isWritable {
411                 // keyValues holds the keys and values to use when putting
412                 // values into the bucket.
413                 keyValues := []keyPair{
414                         {[]byte("bucketkey1"), []byte("foo1")},
415                         {[]byte("bucketkey2"), []byte("foo2")},
416                         {[]byte("bucketkey3"), []byte("foo3")},
417                         {[]byte("bucketkey4"), nil},
418                 }
419                 expectedKeyValues := toGetValues(keyValues)
420                 if !testPutValues(tc, bucket, keyValues) {
421                         return false
422                 }
423
424                 if !testGetValues(tc, bucket, expectedKeyValues) {
425                         return false
426                 }
427
428                 // Ensure errors returned from the user-supplied ForEach
429                 // function are returned.
430                 forEachError := fmt.Errorf("example foreach error")
431                 err := bucket.ForEach(func(k, v []byte) error {
432                         return forEachError
433                 })
434                 if err != forEachError {
435                         tc.t.Errorf("ForEach: inner function error not "+
436                                 "returned - got %v, want %v", err, forEachError)
437                         return false
438                 }
439
440                 // Iterate all of the keys using ForEach while making sure the
441                 // stored values are the expected values.
442                 keysFound := make(map[string]struct{}, len(keyValues))
443                 err = bucket.ForEach(func(k, v []byte) error {
444                         wantV, found := lookupKey(k, expectedKeyValues)
445                         if !found {
446                                 return fmt.Errorf("ForEach: key '%s' should "+
447                                         "exist", k)
448                         }
449
450                         if !reflect.DeepEqual(v, wantV) {
451                                 return fmt.Errorf("ForEach: value for key '%s' "+
452                                         "does not match - got %s, want %s", k,
453                                         v, wantV)
454                         }
455
456                         keysFound[string(k)] = struct{}{}
457                         return nil
458                 })
459                 if err != nil {
460                         tc.t.Errorf("%v", err)
461                         return false
462                 }
463
464                 // Ensure all keys were iterated.
465                 for _, item := range keyValues {
466                         if _, ok := keysFound[string(item.key)]; !ok {
467                                 tc.t.Errorf("ForEach: key '%s' was not iterated "+
468                                         "when it should have been", item.key)
469                                 return false
470                         }
471                 }
472
473                 // Delete the keys and ensure they were deleted.
474                 if !testDeleteValues(tc, bucket, keyValues) {
475                         return false
476                 }
477                 if !testGetValues(tc, bucket, rollbackValues(keyValues)) {
478                         return false
479                 }
480
481                 // Ensure creating a new bucket works as expected.
482                 testBucketName := []byte("testbucket")
483                 testBucket, err := bucket.CreateBucket(testBucketName)
484                 if err != nil {
485                         tc.t.Errorf("CreateBucket: unexpected error: %v", err)
486                         return false
487                 }
488                 if !testNestedBucket(tc, testBucket) {
489                         return false
490                 }
491
492                 // Ensure errors returned from the user-supplied ForEachBucket
493                 // function are returned.
494                 err = bucket.ForEachBucket(func(k []byte) error {
495                         return forEachError
496                 })
497                 if err != forEachError {
498                         tc.t.Errorf("ForEachBucket: inner function error not "+
499                                 "returned - got %v, want %v", err, forEachError)
500                         return false
501                 }
502
503                 // Ensure creating a bucket that already exists fails with the
504                 // expected error.
505                 wantErrCode := database.ErrBucketExists
506                 _, err = bucket.CreateBucket(testBucketName)
507                 if !checkDbError(tc.t, "CreateBucket", err, wantErrCode) {
508                         return false
509                 }
510
511                 // Ensure CreateBucketIfNotExists returns an existing bucket.
512                 testBucket, err = bucket.CreateBucketIfNotExists(testBucketName)
513                 if err != nil {
514                         tc.t.Errorf("CreateBucketIfNotExists: unexpected "+
515                                 "error: %v", err)
516                         return false
517                 }
518                 if !testNestedBucket(tc, testBucket) {
519                         return false
520                 }
521
522                 // Ensure retrieving an existing bucket works as expected.
523                 testBucket = bucket.Bucket(testBucketName)
524                 if !testNestedBucket(tc, testBucket) {
525                         return false
526                 }
527
528                 // Ensure deleting a bucket works as intended.
529                 if err := bucket.DeleteBucket(testBucketName); err != nil {
530                         tc.t.Errorf("DeleteBucket: unexpected error: %v", err)
531                         return false
532                 }
533                 if b := bucket.Bucket(testBucketName); b != nil {
534                         tc.t.Errorf("DeleteBucket: bucket '%s' still exists",
535                                 testBucketName)
536                         return false
537                 }
538
539                 // Ensure deleting a bucket that doesn't exist returns the
540                 // expected error.
541                 wantErrCode = database.ErrBucketNotFound
542                 err = bucket.DeleteBucket(testBucketName)
543                 if !checkDbError(tc.t, "DeleteBucket", err, wantErrCode) {
544                         return false
545                 }
546
547                 // Ensure CreateBucketIfNotExists creates a new bucket when
548                 // it doesn't already exist.
549                 testBucket, err = bucket.CreateBucketIfNotExists(testBucketName)
550                 if err != nil {
551                         tc.t.Errorf("CreateBucketIfNotExists: unexpected "+
552                                 "error: %v", err)
553                         return false
554                 }
555                 if !testNestedBucket(tc, testBucket) {
556                         return false
557                 }
558
559                 // Ensure the cursor interface works as expected.
560                 if !testCursorInterface(tc, testBucket) {
561                         return false
562                 }
563
564                 // Delete the test bucket to avoid leaving it around for future
565                 // calls.
566                 if err := bucket.DeleteBucket(testBucketName); err != nil {
567                         tc.t.Errorf("DeleteBucket: unexpected error: %v", err)
568                         return false
569                 }
570                 if b := bucket.Bucket(testBucketName); b != nil {
571                         tc.t.Errorf("DeleteBucket: bucket '%s' still exists",
572                                 testBucketName)
573                         return false
574                 }
575         } else {
576                 // Put should fail with bucket that is not writable.
577                 testName := "unwritable tx put"
578                 wantErrCode := database.ErrTxNotWritable
579                 failBytes := []byte("fail")
580                 err := bucket.Put(failBytes, failBytes)
581                 if !checkDbError(tc.t, testName, err, wantErrCode) {
582                         return false
583                 }
584
585                 // Delete should fail with bucket that is not writable.
586                 testName = "unwritable tx delete"
587                 err = bucket.Delete(failBytes)
588                 if !checkDbError(tc.t, testName, err, wantErrCode) {
589                         return false
590                 }
591
592                 // CreateBucket should fail with bucket that is not writable.
593                 testName = "unwritable tx create bucket"
594                 _, err = bucket.CreateBucket(failBytes)
595                 if !checkDbError(tc.t, testName, err, wantErrCode) {
596                         return false
597                 }
598
599                 // CreateBucketIfNotExists should fail with bucket that is not
600                 // writable.
601                 testName = "unwritable tx create bucket if not exists"
602                 _, err = bucket.CreateBucketIfNotExists(failBytes)
603                 if !checkDbError(tc.t, testName, err, wantErrCode) {
604                         return false
605                 }
606
607                 // DeleteBucket should fail with bucket that is not writable.
608                 testName = "unwritable tx delete bucket"
609                 err = bucket.DeleteBucket(failBytes)
610                 if !checkDbError(tc.t, testName, err, wantErrCode) {
611                         return false
612                 }
613
614                 // Ensure the cursor interface works as expected with read-only
615                 // buckets.
616                 if !testCursorInterface(tc, bucket) {
617                         return false
618                 }
619         }
620
621         return true
622 }
623
624 // rollbackOnPanic rolls the passed transaction back if the code in the calling
625 // function panics.  This is useful in case the tests unexpectedly panic which
626 // would leave any manually created transactions with the database mutex locked
627 // thereby leading to a deadlock and masking the real reason for the panic.  It
628 // also logs a test error and repanics so the original panic can be traced.
629 func rollbackOnPanic(t *testing.T, tx database.Tx) {
630         if err := recover(); err != nil {
631                 t.Errorf("Unexpected panic: %v", err)
632                 _ = tx.Rollback()
633                 panic(err)
634         }
635 }
636
637 // testMetadataManualTxInterface ensures that the manual transactions metadata
638 // interface works as expected.
639 func testMetadataManualTxInterface(tc *testContext) bool {
640         // populateValues tests that populating values works as expected.
641         //
642         // When the writable flag is false, a read-only tranasction is created,
643         // standard bucket tests for read-only transactions are performed, and
644         // the Commit function is checked to ensure it fails as expected.
645         //
646         // Otherwise, a read-write transaction is created, the values are
647         // written, standard bucket tests for read-write transactions are
648         // performed, and then the transaction is either committed or rolled
649         // back depending on the flag.
650         bucket1Name := []byte("bucket1")
651         populateValues := func(writable, rollback bool, putValues []keyPair) bool {
652                 tx, err := tc.db.Begin(writable)
653                 if err != nil {
654                         tc.t.Errorf("Begin: unexpected error %v", err)
655                         return false
656                 }
657                 defer rollbackOnPanic(tc.t, tx)
658
659                 metadataBucket := tx.Metadata()
660                 if metadataBucket == nil {
661                         tc.t.Errorf("Metadata: unexpected nil bucket")
662                         _ = tx.Rollback()
663                         return false
664                 }
665
666                 bucket1 := metadataBucket.Bucket(bucket1Name)
667                 if bucket1 == nil {
668                         tc.t.Errorf("Bucket1: unexpected nil bucket")
669                         return false
670                 }
671
672                 tc.isWritable = writable
673                 if !testBucketInterface(tc, bucket1) {
674                         _ = tx.Rollback()
675                         return false
676                 }
677
678                 if !writable {
679                         // The transaction is not writable, so it should fail
680                         // the commit.
681                         testName := "unwritable tx commit"
682                         wantErrCode := database.ErrTxNotWritable
683                         err := tx.Commit()
684                         if !checkDbError(tc.t, testName, err, wantErrCode) {
685                                 _ = tx.Rollback()
686                                 return false
687                         }
688                 } else {
689                         if !testPutValues(tc, bucket1, putValues) {
690                                 return false
691                         }
692
693                         if rollback {
694                                 // Rollback the transaction.
695                                 if err := tx.Rollback(); err != nil {
696                                         tc.t.Errorf("Rollback: unexpected "+
697                                                 "error %v", err)
698                                         return false
699                                 }
700                         } else {
701                                 // The commit should succeed.
702                                 if err := tx.Commit(); err != nil {
703                                         tc.t.Errorf("Commit: unexpected error "+
704                                                 "%v", err)
705                                         return false
706                                 }
707                         }
708                 }
709
710                 return true
711         }
712
713         // checkValues starts a read-only transaction and checks that all of
714         // the key/value pairs specified in the expectedValues parameter match
715         // what's in the database.
716         checkValues := func(expectedValues []keyPair) bool {
717                 tx, err := tc.db.Begin(false)
718                 if err != nil {
719                         tc.t.Errorf("Begin: unexpected error %v", err)
720                         return false
721                 }
722                 defer rollbackOnPanic(tc.t, tx)
723
724                 metadataBucket := tx.Metadata()
725                 if metadataBucket == nil {
726                         tc.t.Errorf("Metadata: unexpected nil bucket")
727                         _ = tx.Rollback()
728                         return false
729                 }
730
731                 bucket1 := metadataBucket.Bucket(bucket1Name)
732                 if bucket1 == nil {
733                         tc.t.Errorf("Bucket1: unexpected nil bucket")
734                         return false
735                 }
736
737                 if !testGetValues(tc, bucket1, expectedValues) {
738                         _ = tx.Rollback()
739                         return false
740                 }
741
742                 // Rollback the read-only transaction.
743                 if err := tx.Rollback(); err != nil {
744                         tc.t.Errorf("Commit: unexpected error %v", err)
745                         return false
746                 }
747
748                 return true
749         }
750
751         // deleteValues starts a read-write transaction and deletes the keys
752         // in the passed key/value pairs.
753         deleteValues := func(values []keyPair) bool {
754                 tx, err := tc.db.Begin(true)
755                 if err != nil {
756
757                 }
758                 defer rollbackOnPanic(tc.t, tx)
759
760                 metadataBucket := tx.Metadata()
761                 if metadataBucket == nil {
762                         tc.t.Errorf("Metadata: unexpected nil bucket")
763                         _ = tx.Rollback()
764                         return false
765                 }
766
767                 bucket1 := metadataBucket.Bucket(bucket1Name)
768                 if bucket1 == nil {
769                         tc.t.Errorf("Bucket1: unexpected nil bucket")
770                         return false
771                 }
772
773                 // Delete the keys and ensure they were deleted.
774                 if !testDeleteValues(tc, bucket1, values) {
775                         _ = tx.Rollback()
776                         return false
777                 }
778                 if !testGetValues(tc, bucket1, rollbackValues(values)) {
779                         _ = tx.Rollback()
780                         return false
781                 }
782
783                 // Commit the changes and ensure it was successful.
784                 if err := tx.Commit(); err != nil {
785                         tc.t.Errorf("Commit: unexpected error %v", err)
786                         return false
787                 }
788
789                 return true
790         }
791
792         // keyValues holds the keys and values to use when putting values into a
793         // bucket.
794         var keyValues = []keyPair{
795                 {[]byte("umtxkey1"), []byte("foo1")},
796                 {[]byte("umtxkey2"), []byte("foo2")},
797                 {[]byte("umtxkey3"), []byte("foo3")},
798                 {[]byte("umtxkey4"), nil},
799         }
800
801         // Ensure that attempting populating the values using a read-only
802         // transaction fails as expected.
803         if !populateValues(false, true, keyValues) {
804                 return false
805         }
806         if !checkValues(rollbackValues(keyValues)) {
807                 return false
808         }
809
810         // Ensure that attempting populating the values using a read-write
811         // transaction and then rolling it back yields the expected values.
812         if !populateValues(true, true, keyValues) {
813                 return false
814         }
815         if !checkValues(rollbackValues(keyValues)) {
816                 return false
817         }
818
819         // Ensure that attempting populating the values using a read-write
820         // transaction and then committing it stores the expected values.
821         if !populateValues(true, false, keyValues) {
822                 return false
823         }
824         if !checkValues(toGetValues(keyValues)) {
825                 return false
826         }
827
828         // Clean up the keys.
829         if !deleteValues(keyValues) {
830                 return false
831         }
832
833         return true
834 }
835
836 // testManagedTxPanics ensures calling Rollback of Commit inside a managed
837 // transaction panics.
838 func testManagedTxPanics(tc *testContext) bool {
839         testPanic := func(fn func()) (paniced bool) {
840                 // Setup a defer to catch the expected panic and update the
841                 // return variable.
842                 defer func() {
843                         if err := recover(); err != nil {
844                                 paniced = true
845                         }
846                 }()
847
848                 fn()
849                 return false
850         }
851
852         // Ensure calling Commit on a managed read-only transaction panics.
853         paniced := testPanic(func() {
854                 tc.db.View(func(tx database.Tx) error {
855                         tx.Commit()
856                         return nil
857                 })
858         })
859         if !paniced {
860                 tc.t.Error("Commit called inside View did not panic")
861                 return false
862         }
863
864         // Ensure calling Rollback on a managed read-only transaction panics.
865         paniced = testPanic(func() {
866                 tc.db.View(func(tx database.Tx) error {
867                         tx.Rollback()
868                         return nil
869                 })
870         })
871         if !paniced {
872                 tc.t.Error("Rollback called inside View did not panic")
873                 return false
874         }
875
876         // Ensure calling Commit on a managed read-write transaction panics.
877         paniced = testPanic(func() {
878                 tc.db.Update(func(tx database.Tx) error {
879                         tx.Commit()
880                         return nil
881                 })
882         })
883         if !paniced {
884                 tc.t.Error("Commit called inside Update did not panic")
885                 return false
886         }
887
888         // Ensure calling Rollback on a managed read-write transaction panics.
889         paniced = testPanic(func() {
890                 tc.db.Update(func(tx database.Tx) error {
891                         tx.Rollback()
892                         return nil
893                 })
894         })
895         if !paniced {
896                 tc.t.Error("Rollback called inside Update did not panic")
897                 return false
898         }
899
900         return true
901 }
902
903 // testMetadataTxInterface tests all facets of the managed read/write and
904 // manual transaction metadata interfaces as well as the bucket interfaces under
905 // them.
906 func testMetadataTxInterface(tc *testContext) bool {
907         if !testManagedTxPanics(tc) {
908                 return false
909         }
910
911         bucket1Name := []byte("bucket1")
912         err := tc.db.Update(func(tx database.Tx) error {
913                 _, err := tx.Metadata().CreateBucket(bucket1Name)
914                 return err
915         })
916         if err != nil {
917                 tc.t.Errorf("Update: unexpected error creating bucket: %v", err)
918                 return false
919         }
920
921         if !testMetadataManualTxInterface(tc) {
922                 return false
923         }
924
925         // keyValues holds the keys and values to use when putting values
926         // into a bucket.
927         keyValues := []keyPair{
928                 {[]byte("mtxkey1"), []byte("foo1")},
929                 {[]byte("mtxkey2"), []byte("foo2")},
930                 {[]byte("mtxkey3"), []byte("foo3")},
931                 {[]byte("mtxkey4"), nil},
932         }
933
934         // Test the bucket interface via a managed read-only transaction.
935         err = tc.db.View(func(tx database.Tx) error {
936                 metadataBucket := tx.Metadata()
937                 if metadataBucket == nil {
938                         return fmt.Errorf("Metadata: unexpected nil bucket")
939                 }
940
941                 bucket1 := metadataBucket.Bucket(bucket1Name)
942                 if bucket1 == nil {
943                         return fmt.Errorf("Bucket1: unexpected nil bucket")
944                 }
945
946                 tc.isWritable = false
947                 if !testBucketInterface(tc, bucket1) {
948                         return errSubTestFail
949                 }
950
951                 return nil
952         })
953         if err != nil {
954                 if err != errSubTestFail {
955                         tc.t.Errorf("%v", err)
956                 }
957                 return false
958         }
959
960         // Ensure errors returned from the user-supplied View function are
961         // returned.
962         viewError := fmt.Errorf("example view error")
963         err = tc.db.View(func(tx database.Tx) error {
964                 return viewError
965         })
966         if err != viewError {
967                 tc.t.Errorf("View: inner function error not returned - got "+
968                         "%v, want %v", err, viewError)
969                 return false
970         }
971
972         // Test the bucket interface via a managed read-write transaction.
973         // Also, put a series of values and force a rollback so the following
974         // code can ensure the values were not stored.
975         forceRollbackError := fmt.Errorf("force rollback")
976         err = tc.db.Update(func(tx database.Tx) error {
977                 metadataBucket := tx.Metadata()
978                 if metadataBucket == nil {
979                         return fmt.Errorf("Metadata: unexpected nil bucket")
980                 }
981
982                 bucket1 := metadataBucket.Bucket(bucket1Name)
983                 if bucket1 == nil {
984                         return fmt.Errorf("Bucket1: unexpected nil bucket")
985                 }
986
987                 tc.isWritable = true
988                 if !testBucketInterface(tc, bucket1) {
989                         return errSubTestFail
990                 }
991
992                 if !testPutValues(tc, bucket1, keyValues) {
993                         return errSubTestFail
994                 }
995
996                 // Return an error to force a rollback.
997                 return forceRollbackError
998         })
999         if err != forceRollbackError {
1000                 if err == errSubTestFail {
1001                         return false
1002                 }
1003
1004                 tc.t.Errorf("Update: inner function error not returned - got "+
1005                         "%v, want %v", err, forceRollbackError)
1006                 return false
1007         }
1008
1009         // Ensure the values that should not have been stored due to the forced
1010         // rollback above were not actually stored.
1011         err = tc.db.View(func(tx database.Tx) error {
1012                 metadataBucket := tx.Metadata()
1013                 if metadataBucket == nil {
1014                         return fmt.Errorf("Metadata: unexpected nil bucket")
1015                 }
1016
1017                 if !testGetValues(tc, metadataBucket, rollbackValues(keyValues)) {
1018                         return errSubTestFail
1019                 }
1020
1021                 return nil
1022         })
1023         if err != nil {
1024                 if err != errSubTestFail {
1025                         tc.t.Errorf("%v", err)
1026                 }
1027                 return false
1028         }
1029
1030         // Store a series of values via a managed read-write transaction.
1031         err = tc.db.Update(func(tx database.Tx) error {
1032                 metadataBucket := tx.Metadata()
1033                 if metadataBucket == nil {
1034                         return fmt.Errorf("Metadata: unexpected nil bucket")
1035                 }
1036
1037                 bucket1 := metadataBucket.Bucket(bucket1Name)
1038                 if bucket1 == nil {
1039                         return fmt.Errorf("Bucket1: unexpected nil bucket")
1040                 }
1041
1042                 if !testPutValues(tc, bucket1, keyValues) {
1043                         return errSubTestFail
1044                 }
1045
1046                 return nil
1047         })
1048         if err != nil {
1049                 if err != errSubTestFail {
1050                         tc.t.Errorf("%v", err)
1051                 }
1052                 return false
1053         }
1054
1055         // Ensure the values stored above were committed as expected.
1056         err = tc.db.View(func(tx database.Tx) error {
1057                 metadataBucket := tx.Metadata()
1058                 if metadataBucket == nil {
1059                         return fmt.Errorf("Metadata: unexpected nil bucket")
1060                 }
1061
1062                 bucket1 := metadataBucket.Bucket(bucket1Name)
1063                 if bucket1 == nil {
1064                         return fmt.Errorf("Bucket1: unexpected nil bucket")
1065                 }
1066
1067                 if !testGetValues(tc, bucket1, toGetValues(keyValues)) {
1068                         return errSubTestFail
1069                 }
1070
1071                 return nil
1072         })
1073         if err != nil {
1074                 if err != errSubTestFail {
1075                         tc.t.Errorf("%v", err)
1076                 }
1077                 return false
1078         }
1079
1080         // Clean up the values stored above in a managed read-write transaction.
1081         err = tc.db.Update(func(tx database.Tx) error {
1082                 metadataBucket := tx.Metadata()
1083                 if metadataBucket == nil {
1084                         return fmt.Errorf("Metadata: unexpected nil bucket")
1085                 }
1086
1087                 bucket1 := metadataBucket.Bucket(bucket1Name)
1088                 if bucket1 == nil {
1089                         return fmt.Errorf("Bucket1: unexpected nil bucket")
1090                 }
1091
1092                 if !testDeleteValues(tc, bucket1, keyValues) {
1093                         return errSubTestFail
1094                 }
1095
1096                 return nil
1097         })
1098         if err != nil {
1099                 if err != errSubTestFail {
1100                         tc.t.Errorf("%v", err)
1101                 }
1102                 return false
1103         }
1104
1105         return true
1106 }
1107
1108 // testFetchBlockIOMissing ensures that all of the block retrieval API functions
1109 // work as expected when requesting blocks that don't exist.
1110 func testFetchBlockIOMissing(tc *testContext, tx database.Tx) bool {
1111         wantErrCode := database.ErrBlockNotFound
1112
1113         // ---------------------
1114         // Non-bulk Block IO API
1115         // ---------------------
1116
1117         // Test the individual block APIs one block at a time to ensure they
1118         // return the expected error.  Also, build the data needed to test the
1119         // bulk APIs below while looping.
1120         allBlockHashes := make([]chainhash.Hash, len(tc.blocks))
1121         allBlockRegions := make([]database.BlockRegion, len(tc.blocks))
1122         for i, block := range tc.blocks {
1123                 blockHash := block.Hash()
1124                 allBlockHashes[i] = *blockHash
1125
1126                 txLocs, err := block.TxLoc()
1127                 if err != nil {
1128                         tc.t.Errorf("block.TxLoc(%d): unexpected error: %v", i,
1129                                 err)
1130                         return false
1131                 }
1132
1133                 // Ensure FetchBlock returns expected error.
1134                 testName := fmt.Sprintf("FetchBlock #%d on missing block", i)
1135                 _, err = tx.FetchBlock(blockHash)
1136                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1137                         return false
1138                 }
1139
1140                 // Ensure FetchBlockHeader returns expected error.
1141                 testName = fmt.Sprintf("FetchBlockHeader #%d on missing block",
1142                         i)
1143                 _, err = tx.FetchBlockHeader(blockHash)
1144                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1145                         return false
1146                 }
1147
1148                 // Ensure the first transaction fetched as a block region from
1149                 // the database returns the expected error.
1150                 region := database.BlockRegion{
1151                         Hash:   blockHash,
1152                         Offset: uint32(txLocs[0].TxStart),
1153                         Len:    uint32(txLocs[0].TxLen),
1154                 }
1155                 allBlockRegions[i] = region
1156                 _, err = tx.FetchBlockRegion(&region)
1157                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1158                         return false
1159                 }
1160
1161                 // Ensure HasBlock returns false.
1162                 hasBlock, err := tx.HasBlock(blockHash)
1163                 if err != nil {
1164                         tc.t.Errorf("HasBlock #%d: unexpected err: %v", i, err)
1165                         return false
1166                 }
1167                 if hasBlock {
1168                         tc.t.Errorf("HasBlock #%d: should not have block", i)
1169                         return false
1170                 }
1171         }
1172
1173         // -----------------
1174         // Bulk Block IO API
1175         // -----------------
1176
1177         // Ensure FetchBlocks returns expected error.
1178         testName := "FetchBlocks on missing blocks"
1179         _, err := tx.FetchBlocks(allBlockHashes)
1180         if !checkDbError(tc.t, testName, err, wantErrCode) {
1181                 return false
1182         }
1183
1184         // Ensure FetchBlockHeaders returns expected error.
1185         testName = "FetchBlockHeaders on missing blocks"
1186         _, err = tx.FetchBlockHeaders(allBlockHashes)
1187         if !checkDbError(tc.t, testName, err, wantErrCode) {
1188                 return false
1189         }
1190
1191         // Ensure FetchBlockRegions returns expected error.
1192         testName = "FetchBlockRegions on missing blocks"
1193         _, err = tx.FetchBlockRegions(allBlockRegions)
1194         if !checkDbError(tc.t, testName, err, wantErrCode) {
1195                 return false
1196         }
1197
1198         // Ensure HasBlocks returns false for all blocks.
1199         hasBlocks, err := tx.HasBlocks(allBlockHashes)
1200         if err != nil {
1201                 tc.t.Errorf("HasBlocks: unexpected err: %v", err)
1202         }
1203         for i, hasBlock := range hasBlocks {
1204                 if hasBlock {
1205                         tc.t.Errorf("HasBlocks #%d: should not have block", i)
1206                         return false
1207                 }
1208         }
1209
1210         return true
1211 }
1212
1213 // testFetchBlockIO ensures all of the block retrieval API functions work as
1214 // expected for the provide set of blocks.  The blocks must already be stored in
1215 // the database, or at least stored into the the passed transaction.  It also
1216 // tests several error conditions such as ensuring the expected errors are
1217 // returned when fetching blocks, headers, and regions that don't exist.
1218 func testFetchBlockIO(tc *testContext, tx database.Tx) bool {
1219         // ---------------------
1220         // Non-bulk Block IO API
1221         // ---------------------
1222
1223         // Test the individual block APIs one block at a time.  Also, build the
1224         // data needed to test the bulk APIs below while looping.
1225         allBlockHashes := make([]chainhash.Hash, len(tc.blocks))
1226         allBlockBytes := make([][]byte, len(tc.blocks))
1227         allBlockTxLocs := make([][]wire.TxLoc, len(tc.blocks))
1228         allBlockRegions := make([]database.BlockRegion, len(tc.blocks))
1229         for i, block := range tc.blocks {
1230                 blockHash := block.Hash()
1231                 allBlockHashes[i] = *blockHash
1232
1233                 blockBytes, err := block.Bytes()
1234                 if err != nil {
1235                         tc.t.Errorf("block.Bytes(%d): unexpected error: %v", i,
1236                                 err)
1237                         return false
1238                 }
1239                 allBlockBytes[i] = blockBytes
1240
1241                 txLocs, err := block.TxLoc()
1242                 if err != nil {
1243                         tc.t.Errorf("block.TxLoc(%d): unexpected error: %v", i,
1244                                 err)
1245                         return false
1246                 }
1247                 allBlockTxLocs[i] = txLocs
1248
1249                 // Ensure the block data fetched from the database matches the
1250                 // expected bytes.
1251                 gotBlockBytes, err := tx.FetchBlock(blockHash)
1252                 if err != nil {
1253                         tc.t.Errorf("FetchBlock(%s): unexpected error: %v",
1254                                 blockHash, err)
1255                         return false
1256                 }
1257                 if !bytes.Equal(gotBlockBytes, blockBytes) {
1258                         tc.t.Errorf("FetchBlock(%s): bytes mismatch: got %x, "+
1259                                 "want %x", blockHash, gotBlockBytes, blockBytes)
1260                         return false
1261                 }
1262
1263                 // Ensure the block header fetched from the database matches the
1264                 // expected bytes.
1265                 wantHeaderBytes := blockBytes[0:wire.MaxBlockHeaderPayload]
1266                 gotHeaderBytes, err := tx.FetchBlockHeader(blockHash)
1267                 if err != nil {
1268                         tc.t.Errorf("FetchBlockHeader(%s): unexpected error: %v",
1269                                 blockHash, err)
1270                         return false
1271                 }
1272                 if !bytes.Equal(gotHeaderBytes, wantHeaderBytes) {
1273                         tc.t.Errorf("FetchBlockHeader(%s): bytes mismatch: "+
1274                                 "got %x, want %x", blockHash, gotHeaderBytes,
1275                                 wantHeaderBytes)
1276                         return false
1277                 }
1278
1279                 // Ensure the first transaction fetched as a block region from
1280                 // the database matches the expected bytes.
1281                 region := database.BlockRegion{
1282                         Hash:   blockHash,
1283                         Offset: uint32(txLocs[0].TxStart),
1284                         Len:    uint32(txLocs[0].TxLen),
1285                 }
1286                 allBlockRegions[i] = region
1287                 endRegionOffset := region.Offset + region.Len
1288                 wantRegionBytes := blockBytes[region.Offset:endRegionOffset]
1289                 gotRegionBytes, err := tx.FetchBlockRegion(&region)
1290                 if err != nil {
1291                         tc.t.Errorf("FetchBlockRegion(%s): unexpected error: %v",
1292                                 blockHash, err)
1293                         return false
1294                 }
1295                 if !bytes.Equal(gotRegionBytes, wantRegionBytes) {
1296                         tc.t.Errorf("FetchBlockRegion(%s): bytes mismatch: "+
1297                                 "got %x, want %x", blockHash, gotRegionBytes,
1298                                 wantRegionBytes)
1299                         return false
1300                 }
1301
1302                 // Ensure the block header fetched from the database matches the
1303                 // expected bytes.
1304                 hasBlock, err := tx.HasBlock(blockHash)
1305                 if err != nil {
1306                         tc.t.Errorf("HasBlock(%s): unexpected error: %v",
1307                                 blockHash, err)
1308                         return false
1309                 }
1310                 if !hasBlock {
1311                         tc.t.Errorf("HasBlock(%s): database claims it doesn't "+
1312                                 "have the block when it should", blockHash)
1313                         return false
1314                 }
1315
1316                 // -----------------------
1317                 // Invalid blocks/regions.
1318                 // -----------------------
1319
1320                 // Ensure fetching a block that doesn't exist returns the
1321                 // expected error.
1322                 badBlockHash := &chainhash.Hash{}
1323                 testName := fmt.Sprintf("FetchBlock(%s) invalid block",
1324                         badBlockHash)
1325                 wantErrCode := database.ErrBlockNotFound
1326                 _, err = tx.FetchBlock(badBlockHash)
1327                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1328                         return false
1329                 }
1330
1331                 // Ensure fetching a block header that doesn't exist returns
1332                 // the expected error.
1333                 testName = fmt.Sprintf("FetchBlockHeader(%s) invalid block",
1334                         badBlockHash)
1335                 _, err = tx.FetchBlockHeader(badBlockHash)
1336                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1337                         return false
1338                 }
1339
1340                 // Ensure fetching a block region in a block that doesn't exist
1341                 // return the expected error.
1342                 testName = fmt.Sprintf("FetchBlockRegion(%s) invalid hash",
1343                         badBlockHash)
1344                 wantErrCode = database.ErrBlockNotFound
1345                 region.Hash = badBlockHash
1346                 region.Offset = ^uint32(0)
1347                 _, err = tx.FetchBlockRegion(&region)
1348                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1349                         return false
1350                 }
1351
1352                 // Ensure fetching a block region that is out of bounds returns
1353                 // the expected error.
1354                 testName = fmt.Sprintf("FetchBlockRegion(%s) invalid region",
1355                         blockHash)
1356                 wantErrCode = database.ErrBlockRegionInvalid
1357                 region.Hash = blockHash
1358                 region.Offset = ^uint32(0)
1359                 _, err = tx.FetchBlockRegion(&region)
1360                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1361                         return false
1362                 }
1363         }
1364
1365         // -----------------
1366         // Bulk Block IO API
1367         // -----------------
1368
1369         // Ensure the bulk block data fetched from the database matches the
1370         // expected bytes.
1371         blockData, err := tx.FetchBlocks(allBlockHashes)
1372         if err != nil {
1373                 tc.t.Errorf("FetchBlocks: unexpected error: %v", err)
1374                 return false
1375         }
1376         if len(blockData) != len(allBlockBytes) {
1377                 tc.t.Errorf("FetchBlocks: unexpected number of results - got "+
1378                         "%d, want %d", len(blockData), len(allBlockBytes))
1379                 return false
1380         }
1381         for i := 0; i < len(blockData); i++ {
1382                 blockHash := allBlockHashes[i]
1383                 wantBlockBytes := allBlockBytes[i]
1384                 gotBlockBytes := blockData[i]
1385                 if !bytes.Equal(gotBlockBytes, wantBlockBytes) {
1386                         tc.t.Errorf("FetchBlocks(%s): bytes mismatch: got %x, "+
1387                                 "want %x", blockHash, gotBlockBytes,
1388                                 wantBlockBytes)
1389                         return false
1390                 }
1391         }
1392
1393         // Ensure the bulk block headers fetched from the database match the
1394         // expected bytes.
1395         blockHeaderData, err := tx.FetchBlockHeaders(allBlockHashes)
1396         if err != nil {
1397                 tc.t.Errorf("FetchBlockHeaders: unexpected error: %v", err)
1398                 return false
1399         }
1400         if len(blockHeaderData) != len(allBlockBytes) {
1401                 tc.t.Errorf("FetchBlockHeaders: unexpected number of results "+
1402                         "- got %d, want %d", len(blockHeaderData),
1403                         len(allBlockBytes))
1404                 return false
1405         }
1406         for i := 0; i < len(blockHeaderData); i++ {
1407                 blockHash := allBlockHashes[i]
1408                 wantHeaderBytes := allBlockBytes[i][0:wire.MaxBlockHeaderPayload]
1409                 gotHeaderBytes := blockHeaderData[i]
1410                 if !bytes.Equal(gotHeaderBytes, wantHeaderBytes) {
1411                         tc.t.Errorf("FetchBlockHeaders(%s): bytes mismatch: "+
1412                                 "got %x, want %x", blockHash, gotHeaderBytes,
1413                                 wantHeaderBytes)
1414                         return false
1415                 }
1416         }
1417
1418         // Ensure the first transaction of every block fetched in bulk block
1419         // regions from the database matches the expected bytes.
1420         allRegionBytes, err := tx.FetchBlockRegions(allBlockRegions)
1421         if err != nil {
1422                 tc.t.Errorf("FetchBlockRegions: unexpected error: %v", err)
1423                 return false
1424
1425         }
1426         if len(allRegionBytes) != len(allBlockRegions) {
1427                 tc.t.Errorf("FetchBlockRegions: unexpected number of results "+
1428                         "- got %d, want %d", len(allRegionBytes),
1429                         len(allBlockRegions))
1430                 return false
1431         }
1432         for i, gotRegionBytes := range allRegionBytes {
1433                 region := &allBlockRegions[i]
1434                 endRegionOffset := region.Offset + region.Len
1435                 wantRegionBytes := blockData[i][region.Offset:endRegionOffset]
1436                 if !bytes.Equal(gotRegionBytes, wantRegionBytes) {
1437                         tc.t.Errorf("FetchBlockRegions(%d): bytes mismatch: "+
1438                                 "got %x, want %x", i, gotRegionBytes,
1439                                 wantRegionBytes)
1440                         return false
1441                 }
1442         }
1443
1444         // Ensure the bulk determination of whether a set of block hashes are in
1445         // the database returns true for all loaded blocks.
1446         hasBlocks, err := tx.HasBlocks(allBlockHashes)
1447         if err != nil {
1448                 tc.t.Errorf("HasBlocks: unexpected error: %v", err)
1449                 return false
1450         }
1451         for i, hasBlock := range hasBlocks {
1452                 if !hasBlock {
1453                         tc.t.Errorf("HasBlocks(%d): should have block", i)
1454                         return false
1455                 }
1456         }
1457
1458         // -----------------------
1459         // Invalid blocks/regions.
1460         // -----------------------
1461
1462         // Ensure fetching blocks for which one doesn't exist returns the
1463         // expected error.
1464         testName := "FetchBlocks invalid hash"
1465         badBlockHashes := make([]chainhash.Hash, len(allBlockHashes)+1)
1466         copy(badBlockHashes, allBlockHashes)
1467         badBlockHashes[len(badBlockHashes)-1] = chainhash.Hash{}
1468         wantErrCode := database.ErrBlockNotFound
1469         _, err = tx.FetchBlocks(badBlockHashes)
1470         if !checkDbError(tc.t, testName, err, wantErrCode) {
1471                 return false
1472         }
1473
1474         // Ensure fetching block headers for which one doesn't exist returns the
1475         // expected error.
1476         testName = "FetchBlockHeaders invalid hash"
1477         _, err = tx.FetchBlockHeaders(badBlockHashes)
1478         if !checkDbError(tc.t, testName, err, wantErrCode) {
1479                 return false
1480         }
1481
1482         // Ensure fetching block regions for which one of blocks doesn't exist
1483         // returns expected error.
1484         testName = "FetchBlockRegions invalid hash"
1485         badBlockRegions := make([]database.BlockRegion, len(allBlockRegions)+1)
1486         copy(badBlockRegions, allBlockRegions)
1487         badBlockRegions[len(badBlockRegions)-1].Hash = &chainhash.Hash{}
1488         wantErrCode = database.ErrBlockNotFound
1489         _, err = tx.FetchBlockRegions(badBlockRegions)
1490         if !checkDbError(tc.t, testName, err, wantErrCode) {
1491                 return false
1492         }
1493
1494         // Ensure fetching block regions that are out of bounds returns the
1495         // expected error.
1496         testName = "FetchBlockRegions invalid regions"
1497         badBlockRegions = badBlockRegions[:len(badBlockRegions)-1]
1498         for i := range badBlockRegions {
1499                 badBlockRegions[i].Offset = ^uint32(0)
1500         }
1501         wantErrCode = database.ErrBlockRegionInvalid
1502         _, err = tx.FetchBlockRegions(badBlockRegions)
1503         return checkDbError(tc.t, testName, err, wantErrCode)
1504 }
1505
1506 // testBlockIOTxInterface ensures that the block IO interface works as expected
1507 // for both managed read/write and manual transactions.  This function leaves
1508 // all of the stored blocks in the database.
1509 func testBlockIOTxInterface(tc *testContext) bool {
1510         // Ensure attempting to store a block with a read-only transaction fails
1511         // with the expected error.
1512         err := tc.db.View(func(tx database.Tx) error {
1513                 wantErrCode := database.ErrTxNotWritable
1514                 for i, block := range tc.blocks {
1515                         testName := fmt.Sprintf("StoreBlock(%d) on ro tx", i)
1516                         err := tx.StoreBlock(block)
1517                         if !checkDbError(tc.t, testName, err, wantErrCode) {
1518                                 return errSubTestFail
1519                         }
1520                 }
1521
1522                 return nil
1523         })
1524         if err != nil {
1525                 if err != errSubTestFail {
1526                         tc.t.Errorf("%v", err)
1527                 }
1528                 return false
1529         }
1530
1531         // Populate the database with loaded blocks and ensure all of the data
1532         // fetching APIs work properly on them within the transaction before a
1533         // commit or rollback.  Then, force a rollback so the code below can
1534         // ensure none of the data actually gets stored.
1535         forceRollbackError := fmt.Errorf("force rollback")
1536         err = tc.db.Update(func(tx database.Tx) error {
1537                 // Store all blocks in the same transaction.
1538                 for i, block := range tc.blocks {
1539                         err := tx.StoreBlock(block)
1540                         if err != nil {
1541                                 tc.t.Errorf("StoreBlock #%d: unexpected error: "+
1542                                         "%v", i, err)
1543                                 return errSubTestFail
1544                         }
1545                 }
1546
1547                 // Ensure attempting to store the same block again, before the
1548                 // transaction has been committed, returns the expected error.
1549                 wantErrCode := database.ErrBlockExists
1550                 for i, block := range tc.blocks {
1551                         testName := fmt.Sprintf("duplicate block entry #%d "+
1552                                 "(before commit)", i)
1553                         err := tx.StoreBlock(block)
1554                         if !checkDbError(tc.t, testName, err, wantErrCode) {
1555                                 return errSubTestFail
1556                         }
1557                 }
1558
1559                 // Ensure that all data fetches from the stored blocks before
1560                 // the transaction has been committed work as expected.
1561                 if !testFetchBlockIO(tc, tx) {
1562                         return errSubTestFail
1563                 }
1564
1565                 return forceRollbackError
1566         })
1567         if err != forceRollbackError {
1568                 if err == errSubTestFail {
1569                         return false
1570                 }
1571
1572                 tc.t.Errorf("Update: inner function error not returned - got "+
1573                         "%v, want %v", err, forceRollbackError)
1574                 return false
1575         }
1576
1577         // Ensure rollback was successful
1578         err = tc.db.View(func(tx database.Tx) error {
1579                 if !testFetchBlockIOMissing(tc, tx) {
1580                         return errSubTestFail
1581                 }
1582                 return nil
1583         })
1584         if err != nil {
1585                 if err != errSubTestFail {
1586                         tc.t.Errorf("%v", err)
1587                 }
1588                 return false
1589         }
1590
1591         // Populate the database with loaded blocks and ensure all of the data
1592         // fetching APIs work properly.
1593         err = tc.db.Update(func(tx database.Tx) error {
1594                 // Store a bunch of blocks in the same transaction.
1595                 for i, block := range tc.blocks {
1596                         err := tx.StoreBlock(block)
1597                         if err != nil {
1598                                 tc.t.Errorf("StoreBlock #%d: unexpected error: "+
1599                                         "%v", i, err)
1600                                 return errSubTestFail
1601                         }
1602                 }
1603
1604                 // Ensure attempting to store the same block again while in the
1605                 // same transaction, but before it has been committed, returns
1606                 // the expected error.
1607                 for i, block := range tc.blocks {
1608                         testName := fmt.Sprintf("duplicate block entry #%d "+
1609                                 "(before commit)", i)
1610                         wantErrCode := database.ErrBlockExists
1611                         err := tx.StoreBlock(block)
1612                         if !checkDbError(tc.t, testName, err, wantErrCode) {
1613                                 return errSubTestFail
1614                         }
1615                 }
1616
1617                 // Ensure that all data fetches from the stored blocks before
1618                 // the transaction has been committed work as expected.
1619                 if !testFetchBlockIO(tc, tx) {
1620                         return errSubTestFail
1621                 }
1622
1623                 return nil
1624         })
1625         if err != nil {
1626                 if err != errSubTestFail {
1627                         tc.t.Errorf("%v", err)
1628                 }
1629                 return false
1630         }
1631
1632         // Ensure all data fetch tests work as expected using a managed
1633         // read-only transaction after the data was successfully committed
1634         // above.
1635         err = tc.db.View(func(tx database.Tx) error {
1636                 if !testFetchBlockIO(tc, tx) {
1637                         return errSubTestFail
1638                 }
1639
1640                 return nil
1641         })
1642         if err != nil {
1643                 if err != errSubTestFail {
1644                         tc.t.Errorf("%v", err)
1645                 }
1646                 return false
1647         }
1648
1649         // Ensure all data fetch tests work as expected using a managed
1650         // read-write transaction after the data was successfully committed
1651         // above.
1652         err = tc.db.Update(func(tx database.Tx) error {
1653                 if !testFetchBlockIO(tc, tx) {
1654                         return errSubTestFail
1655                 }
1656
1657                 // Ensure attempting to store existing blocks again returns the
1658                 // expected error.  Note that this is different from the
1659                 // previous version since this is a new transaction after the
1660                 // blocks have been committed.
1661                 wantErrCode := database.ErrBlockExists
1662                 for i, block := range tc.blocks {
1663                         testName := fmt.Sprintf("duplicate block entry #%d "+
1664                                 "(before commit)", i)
1665                         err := tx.StoreBlock(block)
1666                         if !checkDbError(tc.t, testName, err, wantErrCode) {
1667                                 return errSubTestFail
1668                         }
1669                 }
1670
1671                 return nil
1672         })
1673         if err != nil {
1674                 if err != errSubTestFail {
1675                         tc.t.Errorf("%v", err)
1676                 }
1677                 return false
1678         }
1679
1680         return true
1681 }
1682
1683 // testClosedTxInterface ensures that both the metadata and block IO API
1684 // functions behave as expected when attempted against a closed transaction.
1685 func testClosedTxInterface(tc *testContext, tx database.Tx) bool {
1686         wantErrCode := database.ErrTxClosed
1687         bucket := tx.Metadata()
1688         cursor := tx.Metadata().Cursor()
1689         bucketName := []byte("closedtxbucket")
1690         keyName := []byte("closedtxkey")
1691
1692         // ------------
1693         // Metadata API
1694         // ------------
1695
1696         // Ensure that attempting to get an existing bucket returns nil when the
1697         // transaction is closed.
1698         if b := bucket.Bucket(bucketName); b != nil {
1699                 tc.t.Errorf("Bucket: did not return nil on closed tx")
1700                 return false
1701         }
1702
1703         // Ensure CreateBucket returns expected error.
1704         testName := "CreateBucket on closed tx"
1705         _, err := bucket.CreateBucket(bucketName)
1706         if !checkDbError(tc.t, testName, err, wantErrCode) {
1707                 return false
1708         }
1709
1710         // Ensure CreateBucketIfNotExists returns expected error.
1711         testName = "CreateBucketIfNotExists on closed tx"
1712         _, err = bucket.CreateBucketIfNotExists(bucketName)
1713         if !checkDbError(tc.t, testName, err, wantErrCode) {
1714                 return false
1715         }
1716
1717         // Ensure Delete returns expected error.
1718         testName = "Delete on closed tx"
1719         err = bucket.Delete(keyName)
1720         if !checkDbError(tc.t, testName, err, wantErrCode) {
1721                 return false
1722         }
1723
1724         // Ensure DeleteBucket returns expected error.
1725         testName = "DeleteBucket on closed tx"
1726         err = bucket.DeleteBucket(bucketName)
1727         if !checkDbError(tc.t, testName, err, wantErrCode) {
1728                 return false
1729         }
1730
1731         // Ensure ForEach returns expected error.
1732         testName = "ForEach on closed tx"
1733         err = bucket.ForEach(nil)
1734         if !checkDbError(tc.t, testName, err, wantErrCode) {
1735                 return false
1736         }
1737
1738         // Ensure ForEachBucket returns expected error.
1739         testName = "ForEachBucket on closed tx"
1740         err = bucket.ForEachBucket(nil)
1741         if !checkDbError(tc.t, testName, err, wantErrCode) {
1742                 return false
1743         }
1744
1745         // Ensure Get returns expected error.
1746         testName = "Get on closed tx"
1747         if k := bucket.Get(keyName); k != nil {
1748                 tc.t.Errorf("Get: did not return nil on closed tx")
1749                 return false
1750         }
1751
1752         // Ensure Put returns expected error.
1753         testName = "Put on closed tx"
1754         err = bucket.Put(keyName, []byte("test"))
1755         if !checkDbError(tc.t, testName, err, wantErrCode) {
1756                 return false
1757         }
1758
1759         // -------------------
1760         // Metadata Cursor API
1761         // -------------------
1762
1763         // Ensure attempting to get a bucket from a cursor on a closed tx gives
1764         // back nil.
1765         if b := cursor.Bucket(); b != nil {
1766                 tc.t.Error("Cursor.Bucket: returned non-nil on closed tx")
1767                 return false
1768         }
1769
1770         // Ensure Cursor.Delete returns expected error.
1771         testName = "Cursor.Delete on closed tx"
1772         err = cursor.Delete()
1773         if !checkDbError(tc.t, testName, err, wantErrCode) {
1774                 return false
1775         }
1776
1777         // Ensure Cursor.First on a closed tx returns false and nil key/value.
1778         if cursor.First() {
1779                 tc.t.Error("Cursor.First: claims ok on closed tx")
1780                 return false
1781         }
1782         if cursor.Key() != nil || cursor.Value() != nil {
1783                 tc.t.Error("Cursor.First: key and/or value are not nil on " +
1784                         "closed tx")
1785                 return false
1786         }
1787
1788         // Ensure Cursor.Last on a closed tx returns false and nil key/value.
1789         if cursor.Last() {
1790                 tc.t.Error("Cursor.Last: claims ok on closed tx")
1791                 return false
1792         }
1793         if cursor.Key() != nil || cursor.Value() != nil {
1794                 tc.t.Error("Cursor.Last: key and/or value are not nil on " +
1795                         "closed tx")
1796                 return false
1797         }
1798
1799         // Ensure Cursor.Next on a closed tx returns false and nil key/value.
1800         if cursor.Next() {
1801                 tc.t.Error("Cursor.Next: claims ok on closed tx")
1802                 return false
1803         }
1804         if cursor.Key() != nil || cursor.Value() != nil {
1805                 tc.t.Error("Cursor.Next: key and/or value are not nil on " +
1806                         "closed tx")
1807                 return false
1808         }
1809
1810         // Ensure Cursor.Prev on a closed tx returns false and nil key/value.
1811         if cursor.Prev() {
1812                 tc.t.Error("Cursor.Prev: claims ok on closed tx")
1813                 return false
1814         }
1815         if cursor.Key() != nil || cursor.Value() != nil {
1816                 tc.t.Error("Cursor.Prev: key and/or value are not nil on " +
1817                         "closed tx")
1818                 return false
1819         }
1820
1821         // Ensure Cursor.Seek on a closed tx returns false and nil key/value.
1822         if cursor.Seek([]byte{}) {
1823                 tc.t.Error("Cursor.Seek: claims ok on closed tx")
1824                 return false
1825         }
1826         if cursor.Key() != nil || cursor.Value() != nil {
1827                 tc.t.Error("Cursor.Seek: key and/or value are not nil on " +
1828                         "closed tx")
1829                 return false
1830         }
1831
1832         // ---------------------
1833         // Non-bulk Block IO API
1834         // ---------------------
1835
1836         // Test the individual block APIs one block at a time to ensure they
1837         // return the expected error.  Also, build the data needed to test the
1838         // bulk APIs below while looping.
1839         allBlockHashes := make([]chainhash.Hash, len(tc.blocks))
1840         allBlockRegions := make([]database.BlockRegion, len(tc.blocks))
1841         for i, block := range tc.blocks {
1842                 blockHash := block.Hash()
1843                 allBlockHashes[i] = *blockHash
1844
1845                 txLocs, err := block.TxLoc()
1846                 if err != nil {
1847                         tc.t.Errorf("block.TxLoc(%d): unexpected error: %v", i,
1848                                 err)
1849                         return false
1850                 }
1851
1852                 // Ensure StoreBlock returns expected error.
1853                 testName = "StoreBlock on closed tx"
1854                 err = tx.StoreBlock(block)
1855                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1856                         return false
1857                 }
1858
1859                 // Ensure FetchBlock returns expected error.
1860                 testName = fmt.Sprintf("FetchBlock #%d on closed tx", i)
1861                 _, err = tx.FetchBlock(blockHash)
1862                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1863                         return false
1864                 }
1865
1866                 // Ensure FetchBlockHeader returns expected error.
1867                 testName = fmt.Sprintf("FetchBlockHeader #%d on closed tx", i)
1868                 _, err = tx.FetchBlockHeader(blockHash)
1869                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1870                         return false
1871                 }
1872
1873                 // Ensure the first transaction fetched as a block region from
1874                 // the database returns the expected error.
1875                 region := database.BlockRegion{
1876                         Hash:   blockHash,
1877                         Offset: uint32(txLocs[0].TxStart),
1878                         Len:    uint32(txLocs[0].TxLen),
1879                 }
1880                 allBlockRegions[i] = region
1881                 _, err = tx.FetchBlockRegion(&region)
1882                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1883                         return false
1884                 }
1885
1886                 // Ensure HasBlock returns expected error.
1887                 testName = fmt.Sprintf("HasBlock #%d on closed tx", i)
1888                 _, err = tx.HasBlock(blockHash)
1889                 if !checkDbError(tc.t, testName, err, wantErrCode) {
1890                         return false
1891                 }
1892         }
1893
1894         // -----------------
1895         // Bulk Block IO API
1896         // -----------------
1897
1898         // Ensure FetchBlocks returns expected error.
1899         testName = "FetchBlocks on closed tx"
1900         _, err = tx.FetchBlocks(allBlockHashes)
1901         if !checkDbError(tc.t, testName, err, wantErrCode) {
1902                 return false
1903         }
1904
1905         // Ensure FetchBlockHeaders returns expected error.
1906         testName = "FetchBlockHeaders on closed tx"
1907         _, err = tx.FetchBlockHeaders(allBlockHashes)
1908         if !checkDbError(tc.t, testName, err, wantErrCode) {
1909                 return false
1910         }
1911
1912         // Ensure FetchBlockRegions returns expected error.
1913         testName = "FetchBlockRegions on closed tx"
1914         _, err = tx.FetchBlockRegions(allBlockRegions)
1915         if !checkDbError(tc.t, testName, err, wantErrCode) {
1916                 return false
1917         }
1918
1919         // Ensure HasBlocks returns expected error.
1920         testName = "HasBlocks on closed tx"
1921         _, err = tx.HasBlocks(allBlockHashes)
1922         if !checkDbError(tc.t, testName, err, wantErrCode) {
1923                 return false
1924         }
1925
1926         // ---------------
1927         // Commit/Rollback
1928         // ---------------
1929
1930         // Ensure that attempting to rollback or commit a transaction that is
1931         // already closed returns the expected error.
1932         err = tx.Rollback()
1933         if !checkDbError(tc.t, "closed tx rollback", err, wantErrCode) {
1934                 return false
1935         }
1936         err = tx.Commit()
1937         return checkDbError(tc.t, "closed tx commit", err, wantErrCode)
1938 }
1939
1940 // testTxClosed ensures that both the metadata and block IO API functions behave
1941 // as expected when attempted against both read-only and read-write
1942 // transactions.
1943 func testTxClosed(tc *testContext) bool {
1944         bucketName := []byte("closedtxbucket")
1945         keyName := []byte("closedtxkey")
1946
1947         // Start a transaction, create a bucket and key used for testing, and
1948         // immediately perform a commit on it so it is closed.
1949         tx, err := tc.db.Begin(true)
1950         if err != nil {
1951                 tc.t.Errorf("Begin(true): unexpected error: %v", err)
1952                 return false
1953         }
1954         defer rollbackOnPanic(tc.t, tx)
1955         if _, err := tx.Metadata().CreateBucket(bucketName); err != nil {
1956                 tc.t.Errorf("CreateBucket: unexpected error: %v", err)
1957                 return false
1958         }
1959         if err := tx.Metadata().Put(keyName, []byte("test")); err != nil {
1960                 tc.t.Errorf("Put: unexpected error: %v", err)
1961                 return false
1962         }
1963         if err := tx.Commit(); err != nil {
1964                 tc.t.Errorf("Commit: unexpected error: %v", err)
1965                 return false
1966         }
1967
1968         // Ensure invoking all of the functions on the closed read-write
1969         // transaction behave as expected.
1970         if !testClosedTxInterface(tc, tx) {
1971                 return false
1972         }
1973
1974         // Repeat the tests with a rolled-back read-only transaction.
1975         tx, err = tc.db.Begin(false)
1976         if err != nil {
1977                 tc.t.Errorf("Begin(false): unexpected error: %v", err)
1978                 return false
1979         }
1980         defer rollbackOnPanic(tc.t, tx)
1981         if err := tx.Rollback(); err != nil {
1982                 tc.t.Errorf("Rollback: unexpected error: %v", err)
1983                 return false
1984         }
1985
1986         // Ensure invoking all of the functions on the closed read-only
1987         // transaction behave as expected.
1988         return testClosedTxInterface(tc, tx)
1989 }
1990
1991 // testConcurrecy ensure the database properly supports concurrent readers and
1992 // only a single writer.  It also ensures views act as snapshots at the time
1993 // they are acquired.
1994 func testConcurrecy(tc *testContext) bool {
1995         // sleepTime is how long each of the concurrent readers should sleep to
1996         // aid in detection of whether or not the data is actually being read
1997         // concurrently.  It starts with a sane lower bound.
1998         var sleepTime = time.Millisecond * 250
1999
2000         // Determine about how long it takes for a single block read.  When it's
2001         // longer than the default minimum sleep time, adjust the sleep time to
2002         // help prevent durations that are too short which would cause erroneous
2003         // test failures on slower systems.
2004         startTime := time.Now()
2005         err := tc.db.View(func(tx database.Tx) error {
2006                 _, err := tx.FetchBlock(tc.blocks[0].Hash())
2007                 return err
2008         })
2009         if err != nil {
2010                 tc.t.Errorf("Unexpected error in view: %v", err)
2011                 return false
2012         }
2013         elapsed := time.Since(startTime)
2014         if sleepTime < elapsed {
2015                 sleepTime = elapsed
2016         }
2017         tc.t.Logf("Time to load block 0: %v, using sleep time: %v", elapsed,
2018                 sleepTime)
2019
2020         // reader takes a block number to load and channel to return the result
2021         // of the operation on.  It is used below to launch multiple concurrent
2022         // readers.
2023         numReaders := len(tc.blocks)
2024         resultChan := make(chan bool, numReaders)
2025         reader := func(blockNum int) {
2026                 err := tc.db.View(func(tx database.Tx) error {
2027                         time.Sleep(sleepTime)
2028                         _, err := tx.FetchBlock(tc.blocks[blockNum].Hash())
2029                         return err
2030                 })
2031                 if err != nil {
2032                         tc.t.Errorf("Unexpected error in concurrent view: %v",
2033                                 err)
2034                         resultChan <- false
2035                 }
2036                 resultChan <- true
2037         }
2038
2039         // Start up several concurrent readers for the same block and wait for
2040         // the results.
2041         startTime = time.Now()
2042         for i := 0; i < numReaders; i++ {
2043                 go reader(0)
2044         }
2045         for i := 0; i < numReaders; i++ {
2046                 if result := <-resultChan; !result {
2047                         return false
2048                 }
2049         }
2050         elapsed = time.Since(startTime)
2051         tc.t.Logf("%d concurrent reads of same block elapsed: %v", numReaders,
2052                 elapsed)
2053
2054         // Consider it a failure if it took longer than half the time it would
2055         // take with no concurrency.
2056         if elapsed > sleepTime*time.Duration(numReaders/2) {
2057                 tc.t.Errorf("Concurrent views for same block did not appear to "+
2058                         "run simultaneously: elapsed %v", elapsed)
2059                 return false
2060         }
2061
2062         // Start up several concurrent readers for different blocks and wait for
2063         // the results.
2064         startTime = time.Now()
2065         for i := 0; i < numReaders; i++ {
2066                 go reader(i)
2067         }
2068         for i := 0; i < numReaders; i++ {
2069                 if result := <-resultChan; !result {
2070                         return false
2071                 }
2072         }
2073         elapsed = time.Since(startTime)
2074         tc.t.Logf("%d concurrent reads of different blocks elapsed: %v",
2075                 numReaders, elapsed)
2076
2077         // Consider it a failure if it took longer than half the time it would
2078         // take with no concurrency.
2079         if elapsed > sleepTime*time.Duration(numReaders/2) {
2080                 tc.t.Errorf("Concurrent views for different blocks did not "+
2081                         "appear to run simultaneously: elapsed %v", elapsed)
2082                 return false
2083         }
2084
2085         // Start up a few readers and wait for them to acquire views.  Each
2086         // reader waits for a signal from the writer to be finished to ensure
2087         // that the data written by the writer is not seen by the view since it
2088         // was started before the data was set.
2089         concurrentKey := []byte("notthere")
2090         concurrentVal := []byte("someval")
2091         started := make(chan struct{})
2092         writeComplete := make(chan struct{})
2093         reader = func(blockNum int) {
2094                 err := tc.db.View(func(tx database.Tx) error {
2095                         started <- struct{}{}
2096
2097                         // Wait for the writer to complete.
2098                         <-writeComplete
2099
2100                         // Since this reader was created before the write took
2101                         // place, the data it added should not be visible.
2102                         val := tx.Metadata().Get(concurrentKey)
2103                         if val != nil {
2104                                 return fmt.Errorf("%s should not be visible",
2105                                         concurrentKey)
2106                         }
2107                         return nil
2108                 })
2109                 if err != nil {
2110                         tc.t.Errorf("Unexpected error in concurrent view: %v",
2111                                 err)
2112                         resultChan <- false
2113                 }
2114                 resultChan <- true
2115         }
2116         for i := 0; i < numReaders; i++ {
2117                 go reader(0)
2118         }
2119         for i := 0; i < numReaders; i++ {
2120                 <-started
2121         }
2122
2123         // All readers are started and waiting for completion of the writer.
2124         // Set some data the readers are expecting to not find and signal the
2125         // readers the write is done by closing the writeComplete channel.
2126         err = tc.db.Update(func(tx database.Tx) error {
2127                 return tx.Metadata().Put(concurrentKey, concurrentVal)
2128         })
2129         if err != nil {
2130                 tc.t.Errorf("Unexpected error in update: %v", err)
2131                 return false
2132         }
2133         close(writeComplete)
2134
2135         // Wait for reader results.
2136         for i := 0; i < numReaders; i++ {
2137                 if result := <-resultChan; !result {
2138                         return false
2139                 }
2140         }
2141
2142         // Start a few writers and ensure the total time is at least the
2143         // writeSleepTime * numWriters.  This ensures only one write transaction
2144         // can be active at a time.
2145         writeSleepTime := time.Millisecond * 250
2146         writer := func() {
2147                 err := tc.db.Update(func(tx database.Tx) error {
2148                         time.Sleep(writeSleepTime)
2149                         return nil
2150                 })
2151                 if err != nil {
2152                         tc.t.Errorf("Unexpected error in concurrent view: %v",
2153                                 err)
2154                         resultChan <- false
2155                 }
2156                 resultChan <- true
2157         }
2158         numWriters := 3
2159         startTime = time.Now()
2160         for i := 0; i < numWriters; i++ {
2161                 go writer()
2162         }
2163         for i := 0; i < numWriters; i++ {
2164                 if result := <-resultChan; !result {
2165                         return false
2166                 }
2167         }
2168         elapsed = time.Since(startTime)
2169         tc.t.Logf("%d concurrent writers elapsed using sleep time %v: %v",
2170                 numWriters, writeSleepTime, elapsed)
2171
2172         // The total time must have been at least the sum of all sleeps if the
2173         // writes blocked properly.
2174         if elapsed < writeSleepTime*time.Duration(numWriters) {
2175                 tc.t.Errorf("Concurrent writes appeared to run simultaneously: "+
2176                         "elapsed %v", elapsed)
2177                 return false
2178         }
2179
2180         return true
2181 }
2182
2183 // testConcurrentClose ensures that closing the database with open transactions
2184 // blocks until the transactions are finished.
2185 //
2186 // The database will be closed upon returning from this function.
2187 func testConcurrentClose(tc *testContext) bool {
2188         // Start up a few readers and wait for them to acquire views.  Each
2189         // reader waits for a signal to complete to ensure the transactions stay
2190         // open until they are explicitly signalled to be closed.
2191         var activeReaders int32
2192         numReaders := 3
2193         started := make(chan struct{})
2194         finishReaders := make(chan struct{})
2195         resultChan := make(chan bool, numReaders+1)
2196         reader := func() {
2197                 err := tc.db.View(func(tx database.Tx) error {
2198                         atomic.AddInt32(&activeReaders, 1)
2199                         started <- struct{}{}
2200                         <-finishReaders
2201                         atomic.AddInt32(&activeReaders, -1)
2202                         return nil
2203                 })
2204                 if err != nil {
2205                         tc.t.Errorf("Unexpected error in concurrent view: %v",
2206                                 err)
2207                         resultChan <- false
2208                 }
2209                 resultChan <- true
2210         }
2211         for i := 0; i < numReaders; i++ {
2212                 go reader()
2213         }
2214         for i := 0; i < numReaders; i++ {
2215                 <-started
2216         }
2217
2218         // Close the database in a separate goroutine.  This should block until
2219         // the transactions are finished.  Once the close has taken place, the
2220         // dbClosed channel is closed to signal the main goroutine below.
2221         dbClosed := make(chan struct{})
2222         go func() {
2223                 started <- struct{}{}
2224                 err := tc.db.Close()
2225                 if err != nil {
2226                         tc.t.Errorf("Unexpected error in concurrent view: %v",
2227                                 err)
2228                         resultChan <- false
2229                 }
2230                 close(dbClosed)
2231                 resultChan <- true
2232         }()
2233         <-started
2234
2235         // Wait a short period and then signal the reader transactions to
2236         // finish.  When the db closed channel is received, ensure there are no
2237         // active readers open.
2238         time.AfterFunc(time.Millisecond*250, func() { close(finishReaders) })
2239         <-dbClosed
2240         if nr := atomic.LoadInt32(&activeReaders); nr != 0 {
2241                 tc.t.Errorf("Close did not appear to block with active "+
2242                         "readers: %d active", nr)
2243                 return false
2244         }
2245
2246         // Wait for all results.
2247         for i := 0; i < numReaders+1; i++ {
2248                 if result := <-resultChan; !result {
2249                         return false
2250                 }
2251         }
2252
2253         return true
2254 }
2255
2256 // testInterface tests performs tests for the various interfaces of the database
2257 // package which require state in the database for the given database type.
2258 func testInterface(t *testing.T, db database.DB) {
2259         // Create a test context to pass around.
2260         context := testContext{t: t, db: db}
2261
2262         // Load the test blocks and store in the test context for use throughout
2263         // the tests.
2264         blocks, err := loadBlocks(t, blockDataFile, blockDataNet)
2265         if err != nil {
2266                 t.Errorf("loadBlocks: Unexpected error: %v", err)
2267                 return
2268         }
2269         context.blocks = blocks
2270
2271         // Test the transaction metadata interface including managed and manual
2272         // transactions as well as buckets.
2273         if !testMetadataTxInterface(&context) {
2274                 return
2275         }
2276
2277         // Test the transaction block IO interface using managed and manual
2278         // transactions.  This function leaves all of the stored blocks in the
2279         // database since they're used later.
2280         if !testBlockIOTxInterface(&context) {
2281                 return
2282         }
2283
2284         // Test all of the transaction interface functions against a closed
2285         // transaction work as expected.
2286         if !testTxClosed(&context) {
2287                 return
2288         }
2289
2290         // Test the database properly supports concurrency.
2291         if !testConcurrecy(&context) {
2292                 return
2293         }
2294
2295         // Test that closing the database with open transactions blocks until
2296         // the transactions are finished.
2297         //
2298         // The database will be closed upon returning from this function, so it
2299         // must be the last thing called.
2300         testConcurrentClose(&context)
2301 }