github.com/lbryio/lbcd@v0.22.119/integration/rpctest/rpc_harness_test.go (about)

     1  // Copyright (c) 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 is ignored during the regular tests due to the following build tag.
     6  //go:build rpctest
     7  // +build rpctest
     8  
     9  package rpctest
    10  
    11  import (
    12  	"fmt"
    13  	"os"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/lbryio/lbcd/chaincfg"
    18  	"github.com/lbryio/lbcd/chaincfg/chainhash"
    19  	"github.com/lbryio/lbcd/txscript"
    20  	"github.com/lbryio/lbcd/wire"
    21  	btcutil "github.com/lbryio/lbcutil"
    22  )
    23  
    24  func testSendOutputs(r *Harness, t *testing.T) {
    25  	genSpend := func(amt btcutil.Amount) *chainhash.Hash {
    26  		// Grab a fresh address from the wallet.
    27  		addr, err := r.NewAddress()
    28  		if err != nil {
    29  			t.Fatalf("unable to get new address: %v", err)
    30  		}
    31  
    32  		// Next, send amt BTC to this address, spending from one of our mature
    33  		// coinbase outputs.
    34  		addrScript, err := txscript.PayToAddrScript(addr)
    35  		if err != nil {
    36  			t.Fatalf("unable to generate pkscript to addr: %v", err)
    37  		}
    38  		output := wire.NewTxOut(int64(amt), addrScript)
    39  		txid, err := r.SendOutputs([]*wire.TxOut{output}, 10)
    40  		if err != nil {
    41  			t.Fatalf("coinbase spend failed: %v", err)
    42  		}
    43  		return txid
    44  	}
    45  
    46  	assertTxMined := func(txid *chainhash.Hash, blockHash *chainhash.Hash) {
    47  		block, err := r.Client.GetBlock(blockHash)
    48  		if err != nil {
    49  			t.Fatalf("unable to get block: %v", err)
    50  		}
    51  
    52  		numBlockTxns := len(block.Transactions)
    53  		if numBlockTxns < 2 {
    54  			t.Fatalf("crafted transaction wasn't mined, block should have "+
    55  				"at least %v transactions instead has %v", 2, numBlockTxns)
    56  		}
    57  
    58  		minedTx := block.Transactions[1]
    59  		txHash := minedTx.TxHash()
    60  		if txHash != *txid {
    61  			t.Fatalf("txid's don't match, %v vs %v", txHash, txid)
    62  		}
    63  	}
    64  
    65  	// First, generate a small spend which will require only a single
    66  	// input.
    67  	txid := genSpend(btcutil.Amount(btcutil.SatoshiPerBitcoin))
    68  
    69  	// Generate a single block, the transaction the wallet created should
    70  	// be found in this block.
    71  	blockHashes, err := r.Client.Generate(1)
    72  	if err != nil {
    73  		t.Fatalf("unable to generate single block: %v", err)
    74  	}
    75  	assertTxMined(txid, blockHashes[0])
    76  
    77  	// Next, generate a spend much greater than the block reward. This
    78  	// transaction should also have been mined properly.
    79  	txid = genSpend(btcutil.Amount(10 * btcutil.SatoshiPerBitcoin))
    80  	blockHashes, err = r.Client.Generate(1)
    81  	if err != nil {
    82  		t.Fatalf("unable to generate single block: %v", err)
    83  	}
    84  	assertTxMined(txid, blockHashes[0])
    85  }
    86  
    87  func assertConnectedTo(t *testing.T, nodeA *Harness, nodeB *Harness) {
    88  	nodeAPeers, err := nodeA.Client.GetPeerInfo()
    89  	if err != nil {
    90  		t.Fatalf("unable to get nodeA's peer info")
    91  	}
    92  
    93  	nodeAddr := nodeB.node.config.listen
    94  	addrFound := false
    95  	for _, peerInfo := range nodeAPeers {
    96  		if peerInfo.Addr == nodeAddr {
    97  			addrFound = true
    98  			break
    99  		}
   100  	}
   101  
   102  	if !addrFound {
   103  		t.Fatal("nodeA not connected to nodeB")
   104  	}
   105  }
   106  
   107  func testConnectNode(r *Harness, t *testing.T) {
   108  	// Create a fresh test harness.
   109  	harness, err := New(&chaincfg.RegressionNetParams, nil, nil, "")
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  	if err := harness.SetUp(false, 0); err != nil {
   114  		t.Fatalf("unable to complete rpctest setup: %v", err)
   115  	}
   116  	defer harness.TearDown()
   117  
   118  	// Establish a p2p connection from our new local harness to the main
   119  	// harness.
   120  	if err := ConnectNode(harness, r); err != nil {
   121  		t.Fatalf("unable to connect local to main harness: %v", err)
   122  	}
   123  
   124  	// The main harness should show up in our local harness' peer's list,
   125  	// and vice verse.
   126  	assertConnectedTo(t, harness, r)
   127  }
   128  
   129  func testTearDownAll(t *testing.T) {
   130  	// Grab a local copy of the currently active harnesses before
   131  	// attempting to tear them all down.
   132  	initialActiveHarnesses := ActiveHarnesses()
   133  
   134  	// Tear down all currently active harnesses.
   135  	if err := TearDownAll(); err != nil {
   136  		t.Fatalf("unable to teardown all harnesses: %v", err)
   137  	}
   138  
   139  	// The global testInstances map should now be fully purged with no
   140  	// active test harnesses remaining.
   141  	if len(ActiveHarnesses()) != 0 {
   142  		t.Fatalf("test harnesses still active after TearDownAll")
   143  	}
   144  
   145  	for _, harness := range initialActiveHarnesses {
   146  		// Ensure all test directories have been deleted.
   147  		if _, err := os.Stat(harness.testNodeDir); err == nil {
   148  			t.Errorf("created test datadir was not deleted.")
   149  		}
   150  	}
   151  }
   152  
   153  func testActiveHarnesses(r *Harness, t *testing.T) {
   154  	numInitialHarnesses := len(ActiveHarnesses())
   155  
   156  	// Create a single test harness.
   157  	harness1, err := New(&chaincfg.RegressionNetParams, nil, nil, "")
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	defer harness1.TearDown()
   162  
   163  	// With the harness created above, a single harness should be detected
   164  	// as active.
   165  	numActiveHarnesses := len(ActiveHarnesses())
   166  	if !(numActiveHarnesses > numInitialHarnesses) {
   167  		t.Fatalf("ActiveHarnesses not updated, should have an " +
   168  			"additional test harness listed.")
   169  	}
   170  }
   171  
   172  func testJoinMempools(r *Harness, t *testing.T) {
   173  	// Assert main test harness has no transactions in its mempool.
   174  	pooledHashes, err := r.Client.GetRawMempool()
   175  	if err != nil {
   176  		t.Fatalf("unable to get mempool for main test harness: %v", err)
   177  	}
   178  	if len(pooledHashes) != 0 {
   179  		t.Fatal("main test harness mempool not empty")
   180  	}
   181  
   182  	// Create a local test harness with only the genesis block.  The nodes
   183  	// will be synced below so the same transaction can be sent to both
   184  	// nodes without it being an orphan.
   185  	harness, err := New(&chaincfg.RegressionNetParams, nil, nil, "")
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  	if err := harness.SetUp(false, 0); err != nil {
   190  		t.Fatalf("unable to complete rpctest setup: %v", err)
   191  	}
   192  	defer harness.TearDown()
   193  
   194  	nodeSlice := []*Harness{r, harness}
   195  
   196  	// Both mempools should be considered synced as they are empty.
   197  	// Therefore, this should return instantly.
   198  	if err := JoinNodes(nodeSlice, Mempools); err != nil {
   199  		t.Fatalf("unable to join node on mempools: %v", err)
   200  	}
   201  
   202  	// Generate a coinbase spend to a new address within the main harness'
   203  	// mempool.
   204  	addr, err := r.NewAddress()
   205  	addrScript, err := txscript.PayToAddrScript(addr)
   206  	if err != nil {
   207  		t.Fatalf("unable to generate pkscript to addr: %v", err)
   208  	}
   209  	output := wire.NewTxOut(5e8, addrScript)
   210  	testTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
   211  	if err != nil {
   212  		t.Fatalf("coinbase spend failed: %v", err)
   213  	}
   214  	if _, err := r.Client.SendRawTransaction(testTx, true); err != nil {
   215  		t.Fatalf("send transaction failed: %v", err)
   216  	}
   217  
   218  	// Wait until the transaction shows up to ensure the two mempools are
   219  	// not the same.
   220  	harnessSynced := make(chan struct{})
   221  	go func() {
   222  		for {
   223  			poolHashes, err := r.Client.GetRawMempool()
   224  			if err != nil {
   225  				t.Fatalf("failed to retrieve harness mempool: %v", err)
   226  			}
   227  			if len(poolHashes) > 0 {
   228  				break
   229  			}
   230  			time.Sleep(time.Millisecond * 100)
   231  		}
   232  		harnessSynced <- struct{}{}
   233  	}()
   234  	select {
   235  	case <-harnessSynced:
   236  	case <-time.After(time.Minute):
   237  		t.Fatalf("harness node never received transaction")
   238  	}
   239  
   240  	// This select case should fall through to the default as the goroutine
   241  	// should be blocked on the JoinNodes call.
   242  	poolsSynced := make(chan struct{})
   243  	go func() {
   244  		if err := JoinNodes(nodeSlice, Mempools); err != nil {
   245  			t.Fatalf("unable to join node on mempools: %v", err)
   246  		}
   247  		poolsSynced <- struct{}{}
   248  	}()
   249  	select {
   250  	case <-poolsSynced:
   251  		t.Fatalf("mempools detected as synced yet harness has a new tx")
   252  	default:
   253  	}
   254  
   255  	// Establish an outbound connection from the local harness to the main
   256  	// harness and wait for the chains to be synced.
   257  	if err := ConnectNode(harness, r); err != nil {
   258  		t.Fatalf("unable to connect harnesses: %v", err)
   259  	}
   260  	if err := JoinNodes(nodeSlice, Blocks); err != nil {
   261  		t.Fatalf("unable to join node on blocks: %v", err)
   262  	}
   263  
   264  	// Send the transaction to the local harness which will result in synced
   265  	// mempools.
   266  	if _, err := harness.Client.SendRawTransaction(testTx, true); err != nil {
   267  		t.Fatalf("send transaction failed: %v", err)
   268  	}
   269  
   270  	// Select once again with a special timeout case after 1 minute. The
   271  	// goroutine above should now be blocked on sending into the unbuffered
   272  	// channel. The send should immediately succeed. In order to avoid the
   273  	// test hanging indefinitely, a 1 minute timeout is in place.
   274  	select {
   275  	case <-poolsSynced:
   276  		// fall through
   277  	case <-time.After(time.Minute):
   278  		t.Fatalf("mempools never detected as synced")
   279  	}
   280  }
   281  
   282  func testJoinBlocks(r *Harness, t *testing.T) {
   283  	// Create a second harness with only the genesis block so it is behind
   284  	// the main harness.
   285  	harness, err := New(&chaincfg.RegressionNetParams, nil, nil, "")
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  	if err := harness.SetUp(false, 0); err != nil {
   290  		t.Fatalf("unable to complete rpctest setup: %v", err)
   291  	}
   292  	defer harness.TearDown()
   293  
   294  	nodeSlice := []*Harness{r, harness}
   295  	blocksSynced := make(chan struct{})
   296  	go func() {
   297  		if err := JoinNodes(nodeSlice, Blocks); err != nil {
   298  			t.Fatalf("unable to join node on blocks: %v", err)
   299  		}
   300  		blocksSynced <- struct{}{}
   301  	}()
   302  
   303  	// This select case should fall through to the default as the goroutine
   304  	// should be blocked on the JoinNodes calls.
   305  	select {
   306  	case <-blocksSynced:
   307  		t.Fatalf("blocks detected as synced yet local harness is behind")
   308  	default:
   309  	}
   310  
   311  	// Connect the local harness to the main harness which will sync the
   312  	// chains.
   313  	if err := ConnectNode(harness, r); err != nil {
   314  		t.Fatalf("unable to connect harnesses: %v", err)
   315  	}
   316  
   317  	// Select once again with a special timeout case after 1 minute. The
   318  	// goroutine above should now be blocked on sending into the unbuffered
   319  	// channel. The send should immediately succeed. In order to avoid the
   320  	// test hanging indefinitely, a 1 minute timeout is in place.
   321  	select {
   322  	case <-blocksSynced:
   323  		// fall through
   324  	case <-time.After(time.Minute):
   325  		t.Fatalf("blocks never detected as synced")
   326  	}
   327  }
   328  
   329  func testGenerateAndSubmitBlock(r *Harness, t *testing.T) {
   330  	// Generate a few test spend transactions.
   331  	addr, err := r.NewAddress()
   332  	if err != nil {
   333  		t.Fatalf("unable to generate new address: %v", err)
   334  	}
   335  	pkScript, err := txscript.PayToAddrScript(addr)
   336  	if err != nil {
   337  		t.Fatalf("unable to create script: %v", err)
   338  	}
   339  	output := wire.NewTxOut(btcutil.SatoshiPerBitcoin/50, pkScript)
   340  
   341  	const numTxns = 5
   342  	txns := make([]*btcutil.Tx, 0, numTxns)
   343  	for i := 0; i < numTxns; i++ {
   344  		tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
   345  		if err != nil {
   346  			t.Fatalf("unable to create tx: %v", err)
   347  		}
   348  
   349  		txns = append(txns, btcutil.NewTx(tx))
   350  	}
   351  
   352  	// Now generate a block with the default block version, and a zero'd
   353  	// out time.
   354  	block, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{})
   355  	if err != nil {
   356  		t.Fatalf("unable to generate block: %v", err)
   357  	}
   358  
   359  	// Ensure that all created transactions were included, and that the
   360  	// block version was properly set to the default.
   361  	numBlocksTxns := len(block.Transactions())
   362  	if numBlocksTxns != numTxns+1 {
   363  		t.Fatalf("block did not include all transactions: "+
   364  			"expected %v, got %v", numTxns+1, numBlocksTxns)
   365  	}
   366  	blockVersion := block.MsgBlock().Header.Version
   367  	if blockVersion != BlockVersion {
   368  		t.Fatalf("block version is not default: expected %v, got %v",
   369  			BlockVersion, blockVersion)
   370  	}
   371  
   372  	// Next generate a block with a "non-standard" block version along with
   373  	// time stamp a minute after the previous block's timestamp.
   374  	timestamp := block.MsgBlock().Header.Timestamp.Add(time.Minute)
   375  	targetBlockVersion := int32(1337)
   376  	block, err = r.GenerateAndSubmitBlock(nil, targetBlockVersion, timestamp)
   377  	if err != nil {
   378  		t.Fatalf("unable to generate block: %v", err)
   379  	}
   380  
   381  	// Finally ensure that the desired block version and timestamp were set
   382  	// properly.
   383  	header := block.MsgBlock().Header
   384  	blockVersion = header.Version
   385  	if blockVersion != targetBlockVersion {
   386  		t.Fatalf("block version mismatch: expected %v, got %v",
   387  			targetBlockVersion, blockVersion)
   388  	}
   389  	if !timestamp.Equal(header.Timestamp) {
   390  		t.Fatalf("header time stamp mismatch: expected %v, got %v",
   391  			timestamp, header.Timestamp)
   392  	}
   393  }
   394  
   395  func testGenerateAndSubmitBlockWithCustomCoinbaseOutputs(r *Harness,
   396  	t *testing.T) {
   397  	// Generate a few test spend transactions.
   398  	addr, err := r.NewAddress()
   399  	if err != nil {
   400  		t.Fatalf("unable to generate new address: %v", err)
   401  	}
   402  	pkScript, err := txscript.PayToAddrScript(addr)
   403  	if err != nil {
   404  		t.Fatalf("unable to create script: %v", err)
   405  	}
   406  	output := wire.NewTxOut(btcutil.SatoshiPerBitcoin, pkScript)
   407  
   408  	const numTxns = 5
   409  	txns := make([]*btcutil.Tx, 0, numTxns)
   410  	for i := 0; i < numTxns; i++ {
   411  		tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
   412  		if err != nil {
   413  			t.Fatalf("unable to create tx: %v", err)
   414  		}
   415  
   416  		txns = append(txns, btcutil.NewTx(tx))
   417  	}
   418  
   419  	// Now generate a block with the default block version, a zero'd out
   420  	// time, and a burn output.
   421  	block, err := r.GenerateAndSubmitBlockWithCustomCoinbaseOutputs(txns,
   422  		-1, time.Time{}, []wire.TxOut{{
   423  			Value:    0,
   424  			PkScript: []byte{},
   425  		}})
   426  	if err != nil {
   427  		t.Fatalf("unable to generate block: %v", err)
   428  	}
   429  
   430  	// Ensure that all created transactions were included, and that the
   431  	// block version was properly set to the default.
   432  	numBlocksTxns := len(block.Transactions())
   433  	if numBlocksTxns != numTxns+1 {
   434  		t.Fatalf("block did not include all transactions: "+
   435  			"expected %v, got %v", numTxns+1, numBlocksTxns)
   436  	}
   437  	blockVersion := block.MsgBlock().Header.Version
   438  	if blockVersion != BlockVersion {
   439  		t.Fatalf("block version is not default: expected %v, got %v",
   440  			BlockVersion, blockVersion)
   441  	}
   442  
   443  	// Next generate a block with a "non-standard" block version along with
   444  	// time stamp a minute after the previous block's timestamp.
   445  	timestamp := block.MsgBlock().Header.Timestamp.Add(time.Minute)
   446  	targetBlockVersion := int32(1337)
   447  	block, err = r.GenerateAndSubmitBlockWithCustomCoinbaseOutputs(nil,
   448  		targetBlockVersion, timestamp, []wire.TxOut{{
   449  			Value:    0,
   450  			PkScript: []byte{},
   451  		}})
   452  	if err != nil {
   453  		t.Fatalf("unable to generate block: %v", err)
   454  	}
   455  
   456  	// Finally ensure that the desired block version and timestamp were set
   457  	// properly.
   458  	header := block.MsgBlock().Header
   459  	blockVersion = header.Version
   460  	if blockVersion != targetBlockVersion {
   461  		t.Fatalf("block version mismatch: expected %v, got %v",
   462  			targetBlockVersion, blockVersion)
   463  	}
   464  	if !timestamp.Equal(header.Timestamp) {
   465  		t.Fatalf("header time stamp mismatch: expected %v, got %v",
   466  			timestamp, header.Timestamp)
   467  	}
   468  }
   469  
   470  func testMemWalletReorg(r *Harness, t *testing.T) {
   471  	// Create a fresh harness, we'll be using the main harness to force a
   472  	// re-org on this local harness.
   473  	harness, err := New(&chaincfg.RegressionNetParams, nil, nil, "")
   474  	if err != nil {
   475  		t.Fatal(err)
   476  	}
   477  	if err := harness.SetUp(true, 5); err != nil {
   478  		t.Fatalf("unable to complete rpctest setup: %v", err)
   479  	}
   480  	defer harness.TearDown()
   481  
   482  	// The internal wallet of this harness should now have 250 BTC, but BTC is 50x LBC per generated coin.
   483  	expectedBalance := btcutil.Amount(5 * btcutil.SatoshiPerBitcoin)
   484  	walletBalance := harness.ConfirmedBalance()
   485  	if expectedBalance != walletBalance {
   486  		t.Fatalf("wallet balance incorrect: expected %v, got %v",
   487  			expectedBalance, walletBalance)
   488  	}
   489  
   490  	// Now connect this local harness to the main harness then wait for
   491  	// their chains to synchronize.
   492  	if err := ConnectNode(harness, r); err != nil {
   493  		t.Fatalf("unable to connect harnesses: %v", err)
   494  	}
   495  	nodeSlice := []*Harness{r, harness}
   496  	if err := JoinNodes(nodeSlice, Blocks); err != nil {
   497  		t.Fatalf("unable to join node on blocks: %v", err)
   498  	}
   499  
   500  	// The original wallet should now have a balance of 0 BTC as its entire
   501  	// chain should have been decimated in favor of the main harness'
   502  	// chain.
   503  	expectedBalance = btcutil.Amount(0)
   504  	walletBalance = harness.ConfirmedBalance()
   505  	if expectedBalance != walletBalance {
   506  		t.Fatalf("wallet balance incorrect: expected %v, got %v",
   507  			expectedBalance, walletBalance)
   508  	}
   509  }
   510  
   511  func testMemWalletLockedOutputs(r *Harness, t *testing.T) {
   512  	// Obtain the initial balance of the wallet at this point.
   513  	startingBalance := r.ConfirmedBalance()
   514  
   515  	// First, create a signed transaction spending some outputs.
   516  	addr, err := r.NewAddress()
   517  	if err != nil {
   518  		t.Fatalf("unable to generate new address: %v", err)
   519  	}
   520  	pkScript, err := txscript.PayToAddrScript(addr)
   521  	if err != nil {
   522  		t.Fatalf("unable to create script: %v", err)
   523  	}
   524  	outputAmt := btcutil.Amount(btcutil.SatoshiPerBitcoin)
   525  	output := wire.NewTxOut(int64(outputAmt), pkScript)
   526  	tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
   527  	if err != nil {
   528  		t.Fatalf("unable to create transaction: %v", err)
   529  	}
   530  
   531  	// The current wallet balance should now be at least 50 BTC less
   532  	// (accounting for fees) than the period balance
   533  	currentBalance := r.ConfirmedBalance()
   534  	if !(currentBalance <= startingBalance-outputAmt) {
   535  		t.Fatalf("spent outputs not locked: previous balance %v, "+
   536  			"current balance %v", startingBalance, currentBalance)
   537  	}
   538  
   539  	// Now unlocked all the spent inputs within the unbroadcast signed
   540  	// transaction. The current balance should now be exactly that of the
   541  	// starting balance.
   542  	r.UnlockOutputs(tx.TxIn)
   543  	currentBalance = r.ConfirmedBalance()
   544  	if currentBalance != startingBalance {
   545  		t.Fatalf("current and starting balance should now match: "+
   546  			"expected %v, got %v", startingBalance, currentBalance)
   547  	}
   548  }
   549  
   550  var harnessTestCases = []HarnessTestCase{
   551  	testSendOutputs,
   552  	testConnectNode,
   553  	testActiveHarnesses,
   554  	testJoinBlocks,
   555  	testJoinMempools, // Depends on results of testJoinBlocks
   556  	testGenerateAndSubmitBlock,
   557  	testGenerateAndSubmitBlockWithCustomCoinbaseOutputs,
   558  	testMemWalletReorg,
   559  	testMemWalletLockedOutputs,
   560  }
   561  
   562  var mainHarness *Harness
   563  
   564  const (
   565  	numMatureOutputs = 25
   566  )
   567  
   568  func TestMain(m *testing.M) {
   569  	var err error
   570  	mainHarness, err = New(&chaincfg.RegressionNetParams, nil, nil, "")
   571  	if err != nil {
   572  		fmt.Println("unable to create main harness: ", err)
   573  		os.Exit(1)
   574  	}
   575  
   576  	// Initialize the main mining node with a chain of length 125,
   577  	// providing 25 mature coinbases to allow spending from for testing
   578  	// purposes.
   579  	if err = mainHarness.SetUp(true, numMatureOutputs); err != nil {
   580  		fmt.Println("unable to setup test chain: ", err)
   581  
   582  		// Even though the harness was not fully setup, it still needs
   583  		// to be torn down to ensure all resources such as temp
   584  		// directories are cleaned up.  The error is intentionally
   585  		// ignored since this is already an error path and nothing else
   586  		// could be done about it anyways.
   587  		_ = mainHarness.TearDown()
   588  		os.Exit(1)
   589  	}
   590  
   591  	exitCode := m.Run()
   592  
   593  	// Clean up any active harnesses that are still currently running.
   594  	if len(ActiveHarnesses()) > 0 {
   595  		if err := TearDownAll(); err != nil {
   596  			fmt.Println("unable to tear down chain: ", err)
   597  			os.Exit(1)
   598  		}
   599  	}
   600  
   601  	os.Exit(exitCode)
   602  }
   603  
   604  func TestHarness(t *testing.T) {
   605  	expectedBalance := btcutil.Amount(numMatureOutputs * btcutil.SatoshiPerBitcoin)
   606  	harnessBalance := mainHarness.ConfirmedBalance()
   607  	if harnessBalance != expectedBalance {
   608  		t.Fatalf("expected wallet balance of %v instead have %v",
   609  			expectedBalance, harnessBalance)
   610  	}
   611  
   612  	// Current tip should be at a height of numMatureOutputs plus the
   613  	// required number of blocks for coinbase maturity.
   614  	nodeInfo, err := mainHarness.Client.GetInfo()
   615  	if err != nil {
   616  		t.Fatalf("unable to execute getinfo on node: %v", err)
   617  	}
   618  	expectedChainHeight := numMatureOutputs + uint32(mainHarness.ActiveNet.CoinbaseMaturity)
   619  	if uint32(nodeInfo.Blocks) != expectedChainHeight {
   620  		t.Errorf("Chain height is %v, should be %v",
   621  			nodeInfo.Blocks, expectedChainHeight)
   622  	}
   623  
   624  	for _, testCase := range harnessTestCases {
   625  		testCase(mainHarness, t)
   626  	}
   627  
   628  	testTearDownAll(t)
   629  }