github.com/lbryio/lbcd@v0.22.119/database/ffldb/interface_test.go (about)

     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/lbryio/lbcd/chaincfg/chainhash"
    29  	"github.com/lbryio/lbcd/database"
    30  	"github.com/lbryio/lbcd/wire"
    31  	btcutil "github.com/lbryio/lbcutil"
    32  )
    33  
    34  var (
    35  	// blockDataNet is the expected network in the test block data.
    36  	blockDataNet = wire.MainNet
    37  
    38  	// blockDataFile is the path to a file containing the first 256 blocks
    39  	// of the block chain.
    40  	blockDataFile = filepath.Join("..", "testdata", "blocks1-256.bz2")
    41  
    42  	// errSubTestFail is used to signal that a sub test returned false.
    43  	errSubTestFail = fmt.Errorf("sub test failure")
    44  )
    45  
    46  // loadBlocks loads the blocks contained in the testdata directory and returns
    47  // a slice of them.
    48  func loadBlocks(t *testing.T, dataFile string, network wire.BitcoinNet) ([]*btcutil.Block, error) {
    49  	// Open the file that contains the blocks for reading.
    50  	fi, err := os.Open(dataFile)
    51  	if err != nil {
    52  		t.Errorf("failed to open file %v, err %v", dataFile, err)
    53  		return nil, err
    54  	}
    55  	defer func() {
    56  		if err := fi.Close(); err != nil {
    57  			t.Errorf("failed to close file %v %v", dataFile,
    58  				err)
    59  		}
    60  	}()
    61  	dr := bzip2.NewReader(fi)
    62  
    63  	// Set the first block as the genesis block.
    64  	blocks := make([]*btcutil.Block, 0, 257)
    65  
    66  	// Load the remaining blocks.
    67  	for {
    68  		var net uint32
    69  		err := binary.Read(dr, binary.LittleEndian, &net)
    70  		if err == io.EOF {
    71  			// Hit end of file at the expected offset.  No error.
    72  			break
    73  		}
    74  		if err != nil {
    75  			t.Errorf("Failed to load network type for block %d: %v",
    76  				len(blocks), err)
    77  			return nil, err
    78  		}
    79  		if net != uint32(network) {
    80  			continue
    81  		}
    82  
    83  		var blockLen uint32
    84  		err = binary.Read(dr, binary.LittleEndian, &blockLen)
    85  		if err != nil {
    86  			t.Errorf("Failed to load block size for block %d: %v",
    87  				len(blocks), err)
    88  			return nil, err
    89  		}
    90  
    91  		// Read the block.
    92  		blockBytes := make([]byte, blockLen)
    93  		_, err = io.ReadFull(dr, blockBytes)
    94  		if err != nil {
    95  			t.Errorf("Failed to load block %d: %v", len(blocks), err)
    96  			return nil, err
    97  		}
    98  
    99  		// Deserialize and store the block.
   100  		block, err := btcutil.NewBlockFromBytes(blockBytes)
   101  		if err != nil {
   102  			t.Errorf("Failed to parse block %v: %v", len(blocks), err)
   103  			return nil, err
   104  		}
   105  		// NOTE: there's a bug here in that it doesn't read the checksum;
   106  		// we account for that by checking the network above; it probably skips every other block
   107  		blocks = append(blocks, block)
   108  		if len(blocks) == 257 {
   109  			break
   110  		}
   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 block hash exists as expected.
  1303  		hasBlock, err := tx.HasBlock(blockHash)
  1304  		if err != nil {
  1305  			tc.t.Errorf("HasBlock(%s): unexpected error: %v",
  1306  				blockHash, err)
  1307  			return false
  1308  		}
  1309  		if !hasBlock {
  1310  			tc.t.Errorf("HasBlock(%s): database claims it doesn't "+
  1311  				"have the block when it should", blockHash)
  1312  			return false
  1313  		}
  1314  
  1315  		// -----------------------
  1316  		// Invalid blocks/regions.
  1317  		// -----------------------
  1318  
  1319  		// Ensure fetching a block that doesn't exist returns the
  1320  		// expected error.
  1321  		badBlockHash := &chainhash.Hash{}
  1322  		testName := fmt.Sprintf("FetchBlock(%s) invalid block",
  1323  			badBlockHash)
  1324  		wantErrCode := database.ErrBlockNotFound
  1325  		_, err = tx.FetchBlock(badBlockHash)
  1326  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1327  			return false
  1328  		}
  1329  
  1330  		// Ensure fetching a block header that doesn't exist returns
  1331  		// the expected error.
  1332  		testName = fmt.Sprintf("FetchBlockHeader(%s) invalid block",
  1333  			badBlockHash)
  1334  		_, err = tx.FetchBlockHeader(badBlockHash)
  1335  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1336  			return false
  1337  		}
  1338  
  1339  		// Ensure fetching a block region in a block that doesn't exist
  1340  		// return the expected error.
  1341  		testName = fmt.Sprintf("FetchBlockRegion(%s) invalid hash",
  1342  			badBlockHash)
  1343  		wantErrCode = database.ErrBlockNotFound
  1344  		region.Hash = badBlockHash
  1345  		region.Offset = ^uint32(0)
  1346  		_, err = tx.FetchBlockRegion(&region)
  1347  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1348  			return false
  1349  		}
  1350  
  1351  		// Ensure fetching a block region that is out of bounds returns
  1352  		// the expected error.
  1353  		testName = fmt.Sprintf("FetchBlockRegion(%s) invalid region",
  1354  			blockHash)
  1355  		wantErrCode = database.ErrBlockRegionInvalid
  1356  		region.Hash = blockHash
  1357  		region.Offset = ^uint32(0)
  1358  		_, err = tx.FetchBlockRegion(&region)
  1359  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1360  			return false
  1361  		}
  1362  	}
  1363  
  1364  	// -----------------
  1365  	// Bulk Block IO API
  1366  	// -----------------
  1367  
  1368  	// Ensure the bulk block data fetched from the database matches the
  1369  	// expected bytes.
  1370  	blockData, err := tx.FetchBlocks(allBlockHashes)
  1371  	if err != nil {
  1372  		tc.t.Errorf("FetchBlocks: unexpected error: %v", err)
  1373  		return false
  1374  	}
  1375  	if len(blockData) != len(allBlockBytes) {
  1376  		tc.t.Errorf("FetchBlocks: unexpected number of results - got "+
  1377  			"%d, want %d", len(blockData), len(allBlockBytes))
  1378  		return false
  1379  	}
  1380  	for i := 0; i < len(blockData); i++ {
  1381  		blockHash := allBlockHashes[i]
  1382  		wantBlockBytes := allBlockBytes[i]
  1383  		gotBlockBytes := blockData[i]
  1384  		if !bytes.Equal(gotBlockBytes, wantBlockBytes) {
  1385  			tc.t.Errorf("FetchBlocks(%s): bytes mismatch: got %x, "+
  1386  				"want %x", blockHash, gotBlockBytes,
  1387  				wantBlockBytes)
  1388  			return false
  1389  		}
  1390  	}
  1391  
  1392  	// Ensure the bulk block headers fetched from the database match the
  1393  	// expected bytes.
  1394  	blockHeaderData, err := tx.FetchBlockHeaders(allBlockHashes)
  1395  	if err != nil {
  1396  		tc.t.Errorf("FetchBlockHeaders: unexpected error: %v", err)
  1397  		return false
  1398  	}
  1399  	if len(blockHeaderData) != len(allBlockBytes) {
  1400  		tc.t.Errorf("FetchBlockHeaders: unexpected number of results "+
  1401  			"- got %d, want %d", len(blockHeaderData),
  1402  			len(allBlockBytes))
  1403  		return false
  1404  	}
  1405  	for i := 0; i < len(blockHeaderData); i++ {
  1406  		blockHash := allBlockHashes[i]
  1407  		wantHeaderBytes := allBlockBytes[i][0:wire.MaxBlockHeaderPayload]
  1408  		gotHeaderBytes := blockHeaderData[i]
  1409  		if !bytes.Equal(gotHeaderBytes, wantHeaderBytes) {
  1410  			tc.t.Errorf("FetchBlockHeaders(%s): bytes mismatch: "+
  1411  				"got %x, want %x", blockHash, gotHeaderBytes,
  1412  				wantHeaderBytes)
  1413  			return false
  1414  		}
  1415  	}
  1416  
  1417  	// Ensure the first transaction of every block fetched in bulk block
  1418  	// regions from the database matches the expected bytes.
  1419  	allRegionBytes, err := tx.FetchBlockRegions(allBlockRegions)
  1420  	if err != nil {
  1421  		tc.t.Errorf("FetchBlockRegions: unexpected error: %v", err)
  1422  		return false
  1423  
  1424  	}
  1425  	if len(allRegionBytes) != len(allBlockRegions) {
  1426  		tc.t.Errorf("FetchBlockRegions: unexpected number of results "+
  1427  			"- got %d, want %d", len(allRegionBytes),
  1428  			len(allBlockRegions))
  1429  		return false
  1430  	}
  1431  	for i, gotRegionBytes := range allRegionBytes {
  1432  		region := &allBlockRegions[i]
  1433  		endRegionOffset := region.Offset + region.Len
  1434  		wantRegionBytes := blockData[i][region.Offset:endRegionOffset]
  1435  		if !bytes.Equal(gotRegionBytes, wantRegionBytes) {
  1436  			tc.t.Errorf("FetchBlockRegions(%d): bytes mismatch: "+
  1437  				"got %x, want %x", i, gotRegionBytes,
  1438  				wantRegionBytes)
  1439  			return false
  1440  		}
  1441  	}
  1442  
  1443  	// Ensure the bulk determination of whether a set of block hashes are in
  1444  	// the database returns true for all loaded blocks.
  1445  	hasBlocks, err := tx.HasBlocks(allBlockHashes)
  1446  	if err != nil {
  1447  		tc.t.Errorf("HasBlocks: unexpected error: %v", err)
  1448  		return false
  1449  	}
  1450  	for i, hasBlock := range hasBlocks {
  1451  		if !hasBlock {
  1452  			tc.t.Errorf("HasBlocks(%d): should have block", i)
  1453  			return false
  1454  		}
  1455  	}
  1456  
  1457  	// -----------------------
  1458  	// Invalid blocks/regions.
  1459  	// -----------------------
  1460  
  1461  	// Ensure fetching blocks for which one doesn't exist returns the
  1462  	// expected error.
  1463  	testName := "FetchBlocks invalid hash"
  1464  	badBlockHashes := make([]chainhash.Hash, len(allBlockHashes)+1)
  1465  	copy(badBlockHashes, allBlockHashes)
  1466  	badBlockHashes[len(badBlockHashes)-1] = chainhash.Hash{}
  1467  	wantErrCode := database.ErrBlockNotFound
  1468  	_, err = tx.FetchBlocks(badBlockHashes)
  1469  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1470  		return false
  1471  	}
  1472  
  1473  	// Ensure fetching block headers for which one doesn't exist returns the
  1474  	// expected error.
  1475  	testName = "FetchBlockHeaders invalid hash"
  1476  	_, err = tx.FetchBlockHeaders(badBlockHashes)
  1477  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1478  		return false
  1479  	}
  1480  
  1481  	// Ensure fetching block regions for which one of blocks doesn't exist
  1482  	// returns expected error.
  1483  	testName = "FetchBlockRegions invalid hash"
  1484  	badBlockRegions := make([]database.BlockRegion, len(allBlockRegions)+1)
  1485  	copy(badBlockRegions, allBlockRegions)
  1486  	badBlockRegions[len(badBlockRegions)-1].Hash = &chainhash.Hash{}
  1487  	wantErrCode = database.ErrBlockNotFound
  1488  	_, err = tx.FetchBlockRegions(badBlockRegions)
  1489  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1490  		return false
  1491  	}
  1492  
  1493  	// Ensure fetching block regions that are out of bounds returns the
  1494  	// expected error.
  1495  	testName = "FetchBlockRegions invalid regions"
  1496  	badBlockRegions = badBlockRegions[:len(badBlockRegions)-1]
  1497  	for i := range badBlockRegions {
  1498  		badBlockRegions[i].Offset = ^uint32(0)
  1499  	}
  1500  	wantErrCode = database.ErrBlockRegionInvalid
  1501  	_, err = tx.FetchBlockRegions(badBlockRegions)
  1502  	return checkDbError(tc.t, testName, err, wantErrCode)
  1503  }
  1504  
  1505  // testBlockIOTxInterface ensures that the block IO interface works as expected
  1506  // for both managed read/write and manual transactions.  This function leaves
  1507  // all of the stored blocks in the database.
  1508  func testBlockIOTxInterface(tc *testContext) bool {
  1509  	// Ensure attempting to store a block with a read-only transaction fails
  1510  	// with the expected error.
  1511  	err := tc.db.View(func(tx database.Tx) error {
  1512  		wantErrCode := database.ErrTxNotWritable
  1513  		for i, block := range tc.blocks {
  1514  			testName := fmt.Sprintf("StoreBlock(%d) on ro tx", i)
  1515  			err := tx.StoreBlock(block)
  1516  			if !checkDbError(tc.t, testName, err, wantErrCode) {
  1517  				return errSubTestFail
  1518  			}
  1519  		}
  1520  
  1521  		return nil
  1522  	})
  1523  	if err != nil {
  1524  		if err != errSubTestFail {
  1525  			tc.t.Errorf("%v", err)
  1526  		}
  1527  		return false
  1528  	}
  1529  
  1530  	// Populate the database with loaded blocks and ensure all of the data
  1531  	// fetching APIs work properly on them within the transaction before a
  1532  	// commit or rollback.  Then, force a rollback so the code below can
  1533  	// ensure none of the data actually gets stored.
  1534  	forceRollbackError := fmt.Errorf("force rollback")
  1535  	err = tc.db.Update(func(tx database.Tx) error {
  1536  		// Store all blocks in the same transaction.
  1537  		for i, block := range tc.blocks {
  1538  			err := tx.StoreBlock(block)
  1539  			if err != nil {
  1540  				tc.t.Errorf("StoreBlock #%d: unexpected error: "+
  1541  					"%v", i, err)
  1542  				return errSubTestFail
  1543  			}
  1544  		}
  1545  
  1546  		// Ensure attempting to store the same block again, before the
  1547  		// transaction has been committed, returns the expected error.
  1548  		wantErrCode := database.ErrBlockExists
  1549  		for i, block := range tc.blocks {
  1550  			testName := fmt.Sprintf("duplicate block entry #%d "+
  1551  				"(before commit)", i)
  1552  			err := tx.StoreBlock(block)
  1553  			if !checkDbError(tc.t, testName, err, wantErrCode) {
  1554  				return errSubTestFail
  1555  			}
  1556  		}
  1557  
  1558  		// Ensure that all data fetches from the stored blocks before
  1559  		// the transaction has been committed work as expected.
  1560  		if !testFetchBlockIO(tc, tx) {
  1561  			return errSubTestFail
  1562  		}
  1563  
  1564  		return forceRollbackError
  1565  	})
  1566  	if err != forceRollbackError {
  1567  		if err == errSubTestFail {
  1568  			return false
  1569  		}
  1570  
  1571  		tc.t.Errorf("Update: inner function error not returned - got "+
  1572  			"%v, want %v", err, forceRollbackError)
  1573  		return false
  1574  	}
  1575  
  1576  	// Ensure rollback was successful
  1577  	err = tc.db.View(func(tx database.Tx) error {
  1578  		if !testFetchBlockIOMissing(tc, tx) {
  1579  			return errSubTestFail
  1580  		}
  1581  		return nil
  1582  	})
  1583  	if err != nil {
  1584  		if err != errSubTestFail {
  1585  			tc.t.Errorf("%v", err)
  1586  		}
  1587  		return false
  1588  	}
  1589  
  1590  	// Populate the database with loaded blocks and ensure all of the data
  1591  	// fetching APIs work properly.
  1592  	err = tc.db.Update(func(tx database.Tx) error {
  1593  		// Store a bunch of blocks in the same transaction.
  1594  		for i, block := range tc.blocks {
  1595  			err := tx.StoreBlock(block)
  1596  			if err != nil {
  1597  				tc.t.Errorf("StoreBlock #%d: unexpected error: "+
  1598  					"%v", i, err)
  1599  				return errSubTestFail
  1600  			}
  1601  		}
  1602  
  1603  		// Ensure attempting to store the same block again while in the
  1604  		// same transaction, but before it has been committed, returns
  1605  		// the expected error.
  1606  		for i, block := range tc.blocks {
  1607  			testName := fmt.Sprintf("duplicate block entry #%d "+
  1608  				"(before commit)", i)
  1609  			wantErrCode := database.ErrBlockExists
  1610  			err := tx.StoreBlock(block)
  1611  			if !checkDbError(tc.t, testName, err, wantErrCode) {
  1612  				return errSubTestFail
  1613  			}
  1614  		}
  1615  
  1616  		// Ensure that all data fetches from the stored blocks before
  1617  		// the transaction has been committed work as expected.
  1618  		if !testFetchBlockIO(tc, tx) {
  1619  			return errSubTestFail
  1620  		}
  1621  
  1622  		return nil
  1623  	})
  1624  	if err != nil {
  1625  		if err != errSubTestFail {
  1626  			tc.t.Errorf("%v", err)
  1627  		}
  1628  		return false
  1629  	}
  1630  
  1631  	// Ensure all data fetch tests work as expected using a managed
  1632  	// read-only transaction after the data was successfully committed
  1633  	// above.
  1634  	err = tc.db.View(func(tx database.Tx) error {
  1635  		if !testFetchBlockIO(tc, tx) {
  1636  			return errSubTestFail
  1637  		}
  1638  
  1639  		return nil
  1640  	})
  1641  	if err != nil {
  1642  		if err != errSubTestFail {
  1643  			tc.t.Errorf("%v", err)
  1644  		}
  1645  		return false
  1646  	}
  1647  
  1648  	// Ensure all data fetch tests work as expected using a managed
  1649  	// read-write transaction after the data was successfully committed
  1650  	// above.
  1651  	err = tc.db.Update(func(tx database.Tx) error {
  1652  		if !testFetchBlockIO(tc, tx) {
  1653  			return errSubTestFail
  1654  		}
  1655  
  1656  		// Ensure attempting to store existing blocks again returns the
  1657  		// expected error.  Note that this is different from the
  1658  		// previous version since this is a new transaction after the
  1659  		// blocks have been committed.
  1660  		wantErrCode := database.ErrBlockExists
  1661  		for i, block := range tc.blocks {
  1662  			testName := fmt.Sprintf("duplicate block entry #%d "+
  1663  				"(before commit)", i)
  1664  			err := tx.StoreBlock(block)
  1665  			if !checkDbError(tc.t, testName, err, wantErrCode) {
  1666  				return errSubTestFail
  1667  			}
  1668  		}
  1669  
  1670  		return nil
  1671  	})
  1672  	if err != nil {
  1673  		if err != errSubTestFail {
  1674  			tc.t.Errorf("%v", err)
  1675  		}
  1676  		return false
  1677  	}
  1678  
  1679  	return true
  1680  }
  1681  
  1682  // testClosedTxInterface ensures that both the metadata and block IO API
  1683  // functions behave as expected when attempted against a closed transaction.
  1684  func testClosedTxInterface(tc *testContext, tx database.Tx) bool {
  1685  	wantErrCode := database.ErrTxClosed
  1686  	bucket := tx.Metadata()
  1687  	cursor := tx.Metadata().Cursor()
  1688  	bucketName := []byte("closedtxbucket")
  1689  	keyName := []byte("closedtxkey")
  1690  
  1691  	// ------------
  1692  	// Metadata API
  1693  	// ------------
  1694  
  1695  	// Ensure that attempting to get an existing bucket returns nil when the
  1696  	// transaction is closed.
  1697  	if b := bucket.Bucket(bucketName); b != nil {
  1698  		tc.t.Errorf("Bucket: did not return nil on closed tx")
  1699  		return false
  1700  	}
  1701  
  1702  	// Ensure CreateBucket returns expected error.
  1703  	testName := "CreateBucket on closed tx"
  1704  	_, err := bucket.CreateBucket(bucketName)
  1705  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1706  		return false
  1707  	}
  1708  
  1709  	// Ensure CreateBucketIfNotExists returns expected error.
  1710  	testName = "CreateBucketIfNotExists on closed tx"
  1711  	_, err = bucket.CreateBucketIfNotExists(bucketName)
  1712  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1713  		return false
  1714  	}
  1715  
  1716  	// Ensure Delete returns expected error.
  1717  	testName = "Delete on closed tx"
  1718  	err = bucket.Delete(keyName)
  1719  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1720  		return false
  1721  	}
  1722  
  1723  	// Ensure DeleteBucket returns expected error.
  1724  	testName = "DeleteBucket on closed tx"
  1725  	err = bucket.DeleteBucket(bucketName)
  1726  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1727  		return false
  1728  	}
  1729  
  1730  	// Ensure ForEach returns expected error.
  1731  	testName = "ForEach on closed tx"
  1732  	err = bucket.ForEach(nil)
  1733  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1734  		return false
  1735  	}
  1736  
  1737  	// Ensure ForEachBucket returns expected error.
  1738  	testName = "ForEachBucket on closed tx"
  1739  	err = bucket.ForEachBucket(nil)
  1740  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1741  		return false
  1742  	}
  1743  
  1744  	// Ensure Get returns expected error.
  1745  	testName = "Get on closed tx"
  1746  	if k := bucket.Get(keyName); k != nil {
  1747  		tc.t.Errorf("Get: did not return nil on closed tx")
  1748  		return false
  1749  	}
  1750  
  1751  	// Ensure Put returns expected error.
  1752  	testName = "Put on closed tx"
  1753  	err = bucket.Put(keyName, []byte("test"))
  1754  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1755  		return false
  1756  	}
  1757  
  1758  	// -------------------
  1759  	// Metadata Cursor API
  1760  	// -------------------
  1761  
  1762  	// Ensure attempting to get a bucket from a cursor on a closed tx gives
  1763  	// back nil.
  1764  	if b := cursor.Bucket(); b != nil {
  1765  		tc.t.Error("Cursor.Bucket: returned non-nil on closed tx")
  1766  		return false
  1767  	}
  1768  
  1769  	// Ensure Cursor.Delete returns expected error.
  1770  	testName = "Cursor.Delete on closed tx"
  1771  	err = cursor.Delete()
  1772  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1773  		return false
  1774  	}
  1775  
  1776  	// Ensure Cursor.First on a closed tx returns false and nil key/value.
  1777  	if cursor.First() {
  1778  		tc.t.Error("Cursor.First: claims ok on closed tx")
  1779  		return false
  1780  	}
  1781  	if cursor.Key() != nil || cursor.Value() != nil {
  1782  		tc.t.Error("Cursor.First: key and/or value are not nil on " +
  1783  			"closed tx")
  1784  		return false
  1785  	}
  1786  
  1787  	// Ensure Cursor.Last on a closed tx returns false and nil key/value.
  1788  	if cursor.Last() {
  1789  		tc.t.Error("Cursor.Last: claims ok on closed tx")
  1790  		return false
  1791  	}
  1792  	if cursor.Key() != nil || cursor.Value() != nil {
  1793  		tc.t.Error("Cursor.Last: key and/or value are not nil on " +
  1794  			"closed tx")
  1795  		return false
  1796  	}
  1797  
  1798  	// Ensure Cursor.Next on a closed tx returns false and nil key/value.
  1799  	if cursor.Next() {
  1800  		tc.t.Error("Cursor.Next: claims ok on closed tx")
  1801  		return false
  1802  	}
  1803  	if cursor.Key() != nil || cursor.Value() != nil {
  1804  		tc.t.Error("Cursor.Next: key and/or value are not nil on " +
  1805  			"closed tx")
  1806  		return false
  1807  	}
  1808  
  1809  	// Ensure Cursor.Prev on a closed tx returns false and nil key/value.
  1810  	if cursor.Prev() {
  1811  		tc.t.Error("Cursor.Prev: claims ok on closed tx")
  1812  		return false
  1813  	}
  1814  	if cursor.Key() != nil || cursor.Value() != nil {
  1815  		tc.t.Error("Cursor.Prev: key and/or value are not nil on " +
  1816  			"closed tx")
  1817  		return false
  1818  	}
  1819  
  1820  	// Ensure Cursor.Seek on a closed tx returns false and nil key/value.
  1821  	if cursor.Seek([]byte{}) {
  1822  		tc.t.Error("Cursor.Seek: claims ok on closed tx")
  1823  		return false
  1824  	}
  1825  	if cursor.Key() != nil || cursor.Value() != nil {
  1826  		tc.t.Error("Cursor.Seek: key and/or value are not nil on " +
  1827  			"closed tx")
  1828  		return false
  1829  	}
  1830  
  1831  	// ---------------------
  1832  	// Non-bulk Block IO API
  1833  	// ---------------------
  1834  
  1835  	// Test the individual block APIs one block at a time to ensure they
  1836  	// return the expected error.  Also, build the data needed to test the
  1837  	// bulk APIs below while looping.
  1838  	allBlockHashes := make([]chainhash.Hash, len(tc.blocks))
  1839  	allBlockRegions := make([]database.BlockRegion, len(tc.blocks))
  1840  	for i, block := range tc.blocks {
  1841  		blockHash := block.Hash()
  1842  		allBlockHashes[i] = *blockHash
  1843  
  1844  		txLocs, err := block.TxLoc()
  1845  		if err != nil {
  1846  			tc.t.Errorf("block.TxLoc(%d): unexpected error: %v", i,
  1847  				err)
  1848  			return false
  1849  		}
  1850  
  1851  		// Ensure StoreBlock returns expected error.
  1852  		testName = "StoreBlock on closed tx"
  1853  		err = tx.StoreBlock(block)
  1854  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1855  			return false
  1856  		}
  1857  
  1858  		// Ensure FetchBlock returns expected error.
  1859  		testName = fmt.Sprintf("FetchBlock #%d on closed tx", i)
  1860  		_, err = tx.FetchBlock(blockHash)
  1861  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1862  			return false
  1863  		}
  1864  
  1865  		// Ensure FetchBlockHeader returns expected error.
  1866  		testName = fmt.Sprintf("FetchBlockHeader #%d on closed tx", i)
  1867  		_, err = tx.FetchBlockHeader(blockHash)
  1868  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1869  			return false
  1870  		}
  1871  
  1872  		// Ensure the first transaction fetched as a block region from
  1873  		// the database returns the expected error.
  1874  		region := database.BlockRegion{
  1875  			Hash:   blockHash,
  1876  			Offset: uint32(txLocs[0].TxStart),
  1877  			Len:    uint32(txLocs[0].TxLen),
  1878  		}
  1879  		allBlockRegions[i] = region
  1880  		_, err = tx.FetchBlockRegion(&region)
  1881  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1882  			return false
  1883  		}
  1884  
  1885  		// Ensure HasBlock returns expected error.
  1886  		testName = fmt.Sprintf("HasBlock #%d on closed tx", i)
  1887  		_, err = tx.HasBlock(blockHash)
  1888  		if !checkDbError(tc.t, testName, err, wantErrCode) {
  1889  			return false
  1890  		}
  1891  	}
  1892  
  1893  	// -----------------
  1894  	// Bulk Block IO API
  1895  	// -----------------
  1896  
  1897  	// Ensure FetchBlocks returns expected error.
  1898  	testName = "FetchBlocks on closed tx"
  1899  	_, err = tx.FetchBlocks(allBlockHashes)
  1900  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1901  		return false
  1902  	}
  1903  
  1904  	// Ensure FetchBlockHeaders returns expected error.
  1905  	testName = "FetchBlockHeaders on closed tx"
  1906  	_, err = tx.FetchBlockHeaders(allBlockHashes)
  1907  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1908  		return false
  1909  	}
  1910  
  1911  	// Ensure FetchBlockRegions returns expected error.
  1912  	testName = "FetchBlockRegions on closed tx"
  1913  	_, err = tx.FetchBlockRegions(allBlockRegions)
  1914  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1915  		return false
  1916  	}
  1917  
  1918  	// Ensure HasBlocks returns expected error.
  1919  	testName = "HasBlocks on closed tx"
  1920  	_, err = tx.HasBlocks(allBlockHashes)
  1921  	if !checkDbError(tc.t, testName, err, wantErrCode) {
  1922  		return false
  1923  	}
  1924  
  1925  	// ---------------
  1926  	// Commit/Rollback
  1927  	// ---------------
  1928  
  1929  	// Ensure that attempting to rollback or commit a transaction that is
  1930  	// already closed returns the expected error.
  1931  	err = tx.Rollback()
  1932  	if !checkDbError(tc.t, "closed tx rollback", err, wantErrCode) {
  1933  		return false
  1934  	}
  1935  	err = tx.Commit()
  1936  	return checkDbError(tc.t, "closed tx commit", err, wantErrCode)
  1937  }
  1938  
  1939  // testTxClosed ensures that both the metadata and block IO API functions behave
  1940  // as expected when attempted against both read-only and read-write
  1941  // transactions.
  1942  func testTxClosed(tc *testContext) bool {
  1943  	bucketName := []byte("closedtxbucket")
  1944  	keyName := []byte("closedtxkey")
  1945  
  1946  	// Start a transaction, create a bucket and key used for testing, and
  1947  	// immediately perform a commit on it so it is closed.
  1948  	tx, err := tc.db.Begin(true)
  1949  	if err != nil {
  1950  		tc.t.Errorf("Begin(true): unexpected error: %v", err)
  1951  		return false
  1952  	}
  1953  	defer rollbackOnPanic(tc.t, tx)
  1954  	if _, err := tx.Metadata().CreateBucket(bucketName); err != nil {
  1955  		tc.t.Errorf("CreateBucket: unexpected error: %v", err)
  1956  		return false
  1957  	}
  1958  	if err := tx.Metadata().Put(keyName, []byte("test")); err != nil {
  1959  		tc.t.Errorf("Put: unexpected error: %v", err)
  1960  		return false
  1961  	}
  1962  	if err := tx.Commit(); err != nil {
  1963  		tc.t.Errorf("Commit: unexpected error: %v", err)
  1964  		return false
  1965  	}
  1966  
  1967  	// Ensure invoking all of the functions on the closed read-write
  1968  	// transaction behave as expected.
  1969  	if !testClosedTxInterface(tc, tx) {
  1970  		return false
  1971  	}
  1972  
  1973  	// Repeat the tests with a rolled-back read-only transaction.
  1974  	tx, err = tc.db.Begin(false)
  1975  	if err != nil {
  1976  		tc.t.Errorf("Begin(false): unexpected error: %v", err)
  1977  		return false
  1978  	}
  1979  	defer rollbackOnPanic(tc.t, tx)
  1980  	if err := tx.Rollback(); err != nil {
  1981  		tc.t.Errorf("Rollback: unexpected error: %v", err)
  1982  		return false
  1983  	}
  1984  
  1985  	// Ensure invoking all of the functions on the closed read-only
  1986  	// transaction behave as expected.
  1987  	return testClosedTxInterface(tc, tx)
  1988  }
  1989  
  1990  // testConcurrecy ensure the database properly supports concurrent readers and
  1991  // only a single writer.  It also ensures views act as snapshots at the time
  1992  // they are acquired.
  1993  func testConcurrecy(tc *testContext) bool {
  1994  	// sleepTime is how long each of the concurrent readers should sleep to
  1995  	// aid in detection of whether or not the data is actually being read
  1996  	// concurrently.  It starts with a sane lower bound.
  1997  	var sleepTime = time.Millisecond * 250
  1998  
  1999  	// Determine about how long it takes for a single block read.  When it's
  2000  	// longer than the default minimum sleep time, adjust the sleep time to
  2001  	// help prevent durations that are too short which would cause erroneous
  2002  	// test failures on slower systems.
  2003  	startTime := time.Now()
  2004  	err := tc.db.View(func(tx database.Tx) error {
  2005  		_, err := tx.FetchBlock(tc.blocks[0].Hash())
  2006  		return err
  2007  	})
  2008  	if err != nil {
  2009  		tc.t.Errorf("Unexpected error in view: %v", err)
  2010  		return false
  2011  	}
  2012  	elapsed := time.Since(startTime)
  2013  	if sleepTime < elapsed {
  2014  		sleepTime = elapsed
  2015  	}
  2016  	tc.t.Logf("Time to load block 0: %v, using sleep time: %v", elapsed,
  2017  		sleepTime)
  2018  
  2019  	// reader takes a block number to load and channel to return the result
  2020  	// of the operation on.  It is used below to launch multiple concurrent
  2021  	// readers.
  2022  	numReaders := len(tc.blocks)
  2023  	resultChan := make(chan bool, numReaders)
  2024  	reader := func(blockNum int) {
  2025  		err := tc.db.View(func(tx database.Tx) error {
  2026  			time.Sleep(sleepTime)
  2027  			_, err := tx.FetchBlock(tc.blocks[blockNum].Hash())
  2028  			return err
  2029  		})
  2030  		if err != nil {
  2031  			tc.t.Errorf("Unexpected error in concurrent view: %v",
  2032  				err)
  2033  			resultChan <- false
  2034  		}
  2035  		resultChan <- true
  2036  	}
  2037  
  2038  	// Start up several concurrent readers for the same block and wait for
  2039  	// the results.
  2040  	startTime = time.Now()
  2041  	for i := 0; i < numReaders; i++ {
  2042  		go reader(0)
  2043  	}
  2044  	for i := 0; i < numReaders; i++ {
  2045  		if result := <-resultChan; !result {
  2046  			return false
  2047  		}
  2048  	}
  2049  	elapsed = time.Since(startTime)
  2050  	tc.t.Logf("%d concurrent reads of same block elapsed: %v", numReaders,
  2051  		elapsed)
  2052  
  2053  	// Consider it a failure if it took longer than half the time it would
  2054  	// take with no concurrency.
  2055  	if elapsed > sleepTime*time.Duration(numReaders/2) {
  2056  		tc.t.Errorf("Concurrent views for same block did not appear to "+
  2057  			"run simultaneously: elapsed %v", elapsed)
  2058  		return false
  2059  	}
  2060  
  2061  	// Start up several concurrent readers for different blocks and wait for
  2062  	// the results.
  2063  	startTime = time.Now()
  2064  	for i := 0; i < numReaders; i++ {
  2065  		go reader(i)
  2066  	}
  2067  	for i := 0; i < numReaders; i++ {
  2068  		if result := <-resultChan; !result {
  2069  			return false
  2070  		}
  2071  	}
  2072  	elapsed = time.Since(startTime)
  2073  	tc.t.Logf("%d concurrent reads of different blocks elapsed: %v",
  2074  		numReaders, elapsed)
  2075  
  2076  	// Consider it a failure if it took longer than half the time it would
  2077  	// take with no concurrency.
  2078  	if elapsed > sleepTime*time.Duration(numReaders/2) {
  2079  		tc.t.Errorf("Concurrent views for different blocks did not "+
  2080  			"appear to run simultaneously: elapsed %v", elapsed)
  2081  		return false
  2082  	}
  2083  
  2084  	// Start up a few readers and wait for them to acquire views.  Each
  2085  	// reader waits for a signal from the writer to be finished to ensure
  2086  	// that the data written by the writer is not seen by the view since it
  2087  	// was started before the data was set.
  2088  	concurrentKey := []byte("notthere")
  2089  	concurrentVal := []byte("someval")
  2090  	started := make(chan struct{})
  2091  	writeComplete := make(chan struct{})
  2092  	reader = func(blockNum int) {
  2093  		err := tc.db.View(func(tx database.Tx) error {
  2094  			started <- struct{}{}
  2095  
  2096  			// Wait for the writer to complete.
  2097  			<-writeComplete
  2098  
  2099  			// Since this reader was created before the write took
  2100  			// place, the data it added should not be visible.
  2101  			val := tx.Metadata().Get(concurrentKey)
  2102  			if val != nil {
  2103  				return fmt.Errorf("%s should not be visible",
  2104  					concurrentKey)
  2105  			}
  2106  			return nil
  2107  		})
  2108  		if err != nil {
  2109  			tc.t.Errorf("Unexpected error in concurrent view: %v",
  2110  				err)
  2111  			resultChan <- false
  2112  		}
  2113  		resultChan <- true
  2114  	}
  2115  	for i := 0; i < numReaders; i++ {
  2116  		go reader(0)
  2117  	}
  2118  	for i := 0; i < numReaders; i++ {
  2119  		<-started
  2120  	}
  2121  
  2122  	// All readers are started and waiting for completion of the writer.
  2123  	// Set some data the readers are expecting to not find and signal the
  2124  	// readers the write is done by closing the writeComplete channel.
  2125  	err = tc.db.Update(func(tx database.Tx) error {
  2126  		return tx.Metadata().Put(concurrentKey, concurrentVal)
  2127  	})
  2128  	if err != nil {
  2129  		tc.t.Errorf("Unexpected error in update: %v", err)
  2130  		return false
  2131  	}
  2132  	close(writeComplete)
  2133  
  2134  	// Wait for reader results.
  2135  	for i := 0; i < numReaders; i++ {
  2136  		if result := <-resultChan; !result {
  2137  			return false
  2138  		}
  2139  	}
  2140  
  2141  	// Start a few writers and ensure the total time is at least the
  2142  	// writeSleepTime * numWriters.  This ensures only one write transaction
  2143  	// can be active at a time.
  2144  	writeSleepTime := time.Millisecond * 250
  2145  	writer := func() {
  2146  		err := tc.db.Update(func(tx database.Tx) error {
  2147  			time.Sleep(writeSleepTime)
  2148  			return nil
  2149  		})
  2150  		if err != nil {
  2151  			tc.t.Errorf("Unexpected error in concurrent view: %v",
  2152  				err)
  2153  			resultChan <- false
  2154  		}
  2155  		resultChan <- true
  2156  	}
  2157  	numWriters := 3
  2158  	startTime = time.Now()
  2159  	for i := 0; i < numWriters; i++ {
  2160  		go writer()
  2161  	}
  2162  	for i := 0; i < numWriters; i++ {
  2163  		if result := <-resultChan; !result {
  2164  			return false
  2165  		}
  2166  	}
  2167  	elapsed = time.Since(startTime)
  2168  	tc.t.Logf("%d concurrent writers elapsed using sleep time %v: %v",
  2169  		numWriters, writeSleepTime, elapsed)
  2170  
  2171  	// The total time must have been at least the sum of all sleeps if the
  2172  	// writes blocked properly.
  2173  	if elapsed < writeSleepTime*time.Duration(numWriters) {
  2174  		tc.t.Errorf("Concurrent writes appeared to run simultaneously: "+
  2175  			"elapsed %v", elapsed)
  2176  		return false
  2177  	}
  2178  
  2179  	return true
  2180  }
  2181  
  2182  // testConcurrentClose ensures that closing the database with open transactions
  2183  // blocks until the transactions are finished.
  2184  //
  2185  // The database will be closed upon returning from this function.
  2186  func testConcurrentClose(tc *testContext) bool {
  2187  	// Start up a few readers and wait for them to acquire views.  Each
  2188  	// reader waits for a signal to complete to ensure the transactions stay
  2189  	// open until they are explicitly signalled to be closed.
  2190  	var activeReaders int32
  2191  	numReaders := 3
  2192  	started := make(chan struct{})
  2193  	finishReaders := make(chan struct{})
  2194  	resultChan := make(chan bool, numReaders+1)
  2195  	reader := func() {
  2196  		err := tc.db.View(func(tx database.Tx) error {
  2197  			atomic.AddInt32(&activeReaders, 1)
  2198  			started <- struct{}{}
  2199  			<-finishReaders
  2200  			atomic.AddInt32(&activeReaders, -1)
  2201  			return nil
  2202  		})
  2203  		if err != nil {
  2204  			tc.t.Errorf("Unexpected error in concurrent view: %v",
  2205  				err)
  2206  			resultChan <- false
  2207  		}
  2208  		resultChan <- true
  2209  	}
  2210  	for i := 0; i < numReaders; i++ {
  2211  		go reader()
  2212  	}
  2213  	for i := 0; i < numReaders; i++ {
  2214  		<-started
  2215  	}
  2216  
  2217  	// Close the database in a separate goroutine.  This should block until
  2218  	// the transactions are finished.  Once the close has taken place, the
  2219  	// dbClosed channel is closed to signal the main goroutine below.
  2220  	dbClosed := make(chan struct{})
  2221  	go func() {
  2222  		started <- struct{}{}
  2223  		err := tc.db.Close()
  2224  		if err != nil {
  2225  			tc.t.Errorf("Unexpected error in concurrent view: %v",
  2226  				err)
  2227  			resultChan <- false
  2228  		}
  2229  		close(dbClosed)
  2230  		resultChan <- true
  2231  	}()
  2232  	<-started
  2233  
  2234  	// Wait a short period and then signal the reader transactions to
  2235  	// finish.  When the db closed channel is received, ensure there are no
  2236  	// active readers open.
  2237  	time.AfterFunc(time.Millisecond*250, func() { close(finishReaders) })
  2238  	<-dbClosed
  2239  	if nr := atomic.LoadInt32(&activeReaders); nr != 0 {
  2240  		tc.t.Errorf("Close did not appear to block with active "+
  2241  			"readers: %d active", nr)
  2242  		return false
  2243  	}
  2244  
  2245  	// Wait for all results.
  2246  	for i := 0; i < numReaders+1; i++ {
  2247  		if result := <-resultChan; !result {
  2248  			return false
  2249  		}
  2250  	}
  2251  
  2252  	return true
  2253  }
  2254  
  2255  // testInterface tests performs tests for the various interfaces of the database
  2256  // package which require state in the database for the given database type.
  2257  func testInterface(t *testing.T, db database.DB) {
  2258  	// Create a test context to pass around.
  2259  	context := testContext{t: t, db: db}
  2260  
  2261  	// Load the test blocks and store in the test context for use throughout
  2262  	// the tests.
  2263  	blocks, err := loadBlocks(t, blockDataFile, blockDataNet)
  2264  	if err != nil {
  2265  		t.Errorf("loadBlocks: Unexpected error: %v", err)
  2266  		return
  2267  	}
  2268  	context.blocks = blocks
  2269  
  2270  	// Test the transaction metadata interface including managed and manual
  2271  	// transactions as well as buckets.
  2272  	if !testMetadataTxInterface(&context) {
  2273  		return
  2274  	}
  2275  
  2276  	// Test the transaction block IO interface using managed and manual
  2277  	// transactions.  This function leaves all of the stored blocks in the
  2278  	// database since they're used later.
  2279  	if !testBlockIOTxInterface(&context) {
  2280  		return
  2281  	}
  2282  
  2283  	// Test all of the transaction interface functions against a closed
  2284  	// transaction work as expected.
  2285  	if !testTxClosed(&context) {
  2286  		return
  2287  	}
  2288  
  2289  	// Test the database properly supports concurrency.
  2290  	if !testConcurrecy(&context) {
  2291  		return
  2292  	}
  2293  
  2294  	// Test that closing the database with open transactions blocks until
  2295  	// the transactions are finished.
  2296  	//
  2297  	// The database will be closed upon returning from this function, so it
  2298  	// must be the last thing called.
  2299  	testConcurrentClose(&context)
  2300  }