decred.org/dcrdex@v1.0.5/server/asset/btc/live_test.go (about)

     1  //go:build btclive
     2  
     3  // To run tests against a node on another machine, you can create a config file
     4  // and specify the path with the environmental variable DEX_BTC_CONFIGPATH.
     5  
     6  // Since at least one live test runs for an hour, you should run live tests
     7  // individually using the -run flag. All of these tests will only run with the
     8  // 'btclive' build tag, specified with the -tags flag.
     9  //
    10  // go test -v -tags btclive -run UTXOStats
    11  // -----------------------------------
    12  // Grab the most recent block and iterate it's outputs, taking account of
    13  // how many UTXOs are found, how many are of an unknown type, etc.
    14  //
    15  // go test -v -tags btclive -run P2SHStats
    16  // -----------------------------------------
    17  // For each output in the last block, check it's previous outpoint to see if
    18  // it's a P2SH or P2WSH. If so, takes statistics on the script types, including
    19  // for the redeem script.
    20  //
    21  // go test -v -tags btclive -run BlockMonitor -timeout 61m
    22  // ------------------------------------------
    23  // Monitor the blockchain for a while and make sure that the block cache is
    24  // updating appropriately.
    25  //
    26  // go test -v -tags btclive -run LiveFees
    27  // ------------------------------------------
    28  // Test that fees rates are parsed without error and that a few historical fee
    29  // rates are correct.
    30  //
    31  // go test -v -tags btclive -run TestMedianFeeRates
    32  // ------------------------------------------
    33  // Test that the median-fee feeRate fallback calculation works.
    34  //
    35  // This last test does not pass. Leave as a code example for now.
    36  // go test -v -tags btclive -run Plugin
    37  // ------------------------------------------
    38  // Import the constructor from a plugin and do some basic function checks.
    39  // The plugin will need to be built first. To build, run
    40  //    go build -buildmode=plugin
    41  // from the package directory.
    42  
    43  package btc
    44  
    45  import (
    46  	"bytes"
    47  	"context"
    48  	"encoding/hex"
    49  	"fmt"
    50  	"os"
    51  	"testing"
    52  	"time"
    53  
    54  	"decred.org/dcrdex/dex"
    55  	"decred.org/dcrdex/server/asset"
    56  	"github.com/btcsuite/btcd/btcjson"
    57  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    58  )
    59  
    60  var (
    61  	btc *Backend
    62  	ctx context.Context
    63  )
    64  
    65  func TestGetRawTransaction(t *testing.T) {
    66  	expTxB, _ := hex.DecodeString("010000000001017d2cc6700c20cb64879eab415a0f3ba0b" +
    67  		"d6c51bb2d95e3cc09a8f24c52d0335d0100000000ffffffff02ac2c15000000000017a" +
    68  		"91431ab6a773ae3e4c857dea6db96ca513a96369f27879364f60100000000220020f52" +
    69  		"e2cb266ee5919630b79207a3c946f655267eff4a1d3d829a17b5804320649050048304" +
    70  		"502210088128c387df6642fe56275722dc2a700535eeab88ef1a5ca077815ff538b83e" +
    71  		"4022010dc3cb58bac19613b69345fed923ff204b36d84d3c325df3ba63f5bab42198b0" +
    72  		"147304402201bb828e28c5e91fa9af8c80451ee390006f10eded73156d4e7b71937d32" +
    73  		"76ef102207e28c40aba395b5962d8fb1bfbcf4008888ac44b4c1b85827965ef0c69759" +
    74  		"e4701483045022100f2c4a38556127f879fe205e7d325a445033e413dbac5fec99e858" +
    75  		"133b1f37e2602201cd0cde48637beb036b507ee21b387103ff9d93751b6aac51ed4d02" +
    76  		"77fff78ef018b53210288f5e79b55ab76d7c263628fad475bd4cc4cee466acced9b41f" +
    77  		"d3a5cb71233a22102b976a06ed75f1931a303f587ccb2b9f18fe07c9d6aaceadb353ef" +
    78  		"945579e93d52102d5c87f884d6b828e9786d49b4cee87c72e589b14e1668f4dcd40dd2" +
    79  		"25be16a8621035eca61acb63c8738d5bccd57fb6544ca77dbc13593ce3e6754f8db563" +
    80  		"05bf16b54ae00000000")
    81  
    82  	txHash, err := chainhash.NewHashFromStr("79275472daabf4e79ef4dea9402841e61743e0080d4dd26a74819cfd64acadf9")
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	txB, err := btc.node.GetRawTransaction(txHash)
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	if !bytes.Equal(txB, expTxB) {
    91  		t.Errorf("wrong tx bytes")
    92  	}
    93  }
    94  
    95  func TestMain(m *testing.M) {
    96  	// Wrap everything for defers.
    97  	doIt := func() int {
    98  		logger := dex.StdOutLogger("BTCTEST", dex.LevelTrace)
    99  
   100  		dexAsset, err := NewBackend(&asset.BackendConfig{
   101  			AssetID:    BipID,
   102  			ConfigPath: os.Getenv("DEX_BTC_CONFIGPATH"),
   103  			Logger:     logger,
   104  			Net:        dex.Mainnet,
   105  		})
   106  		if err != nil {
   107  			fmt.Printf("NewBackend error: %v\n", err)
   108  			return 1
   109  		}
   110  
   111  		var ok bool
   112  		btc, ok = dexAsset.(*Backend)
   113  		if !ok {
   114  			fmt.Printf("Could not cast asset.Backend to *Backend")
   115  			return 1
   116  		}
   117  
   118  		var cancel context.CancelFunc
   119  		ctx, cancel = context.WithCancel(context.Background())
   120  		wg, err := dexAsset.Connect(ctx)
   121  		if err != nil {
   122  			fmt.Printf("Connect failed: %v", err)
   123  			return 1
   124  		}
   125  		defer func() {
   126  			cancel()
   127  			wg.Wait()
   128  		}()
   129  
   130  		return m.Run()
   131  	}
   132  
   133  	os.Exit(doIt())
   134  }
   135  
   136  // TestUTXOStats is routed through the exported testing utility LiveUTXOStats,
   137  // enabling use by bitcoin clone backends during compatibility testing. See
   138  // LiveUTXOStats in testing.go for an explanation of the test.
   139  func TestUTXOStats(t *testing.T) {
   140  	LiveUTXOStats(btc, t)
   141  }
   142  
   143  // TestP2SHStats is routed through the exported testing utility LiveP2SHStats,
   144  // enabling use by bitcoin clone backends during compatibility testing. See
   145  // LiveP2SHStats in testing.go for an explanation of the test.
   146  func TestP2SHStats(t *testing.T) {
   147  	LiveP2SHStats(btc, t, 10000)
   148  }
   149  
   150  // TestBlockMonitor is a live test that connects to bitcoind and listens for
   151  // block updates, checking the state of the cache along the way. See TestReorg
   152  // for additional testing of the block monitor loop.
   153  func TestBlockMonitor(t *testing.T) {
   154  	testDuration := 60 * time.Minute
   155  	fmt.Printf("Starting BlockMonitor test. Test will last for %d minutes\n", int(testDuration.Minutes()))
   156  	blockChan := btc.BlockChannel(5)
   157  	expire := time.NewTimer(testDuration).C
   158  	lastHeight := btc.blockCache.tipHeight()
   159  out:
   160  	for {
   161  		select {
   162  		case update := <-blockChan:
   163  			if update.Err != nil {
   164  				t.Fatalf("error encountered while monitoring blocks: %v", update.Err)
   165  			}
   166  			tipHeight := btc.blockCache.tipHeight()
   167  			if update.Reorg {
   168  				fmt.Printf("block received at height %d causes a %d block reorg\n", tipHeight, lastHeight-tipHeight+1)
   169  			} else {
   170  				fmt.Printf("block received for height %d\n", tipHeight)
   171  			}
   172  			lastHeight = tipHeight
   173  			_, found := btc.blockCache.atHeight(tipHeight)
   174  			if !found {
   175  				t.Fatalf("did not find newly connected block at height %d", tipHeight)
   176  			}
   177  		case <-ctx.Done():
   178  			break out
   179  		case <-expire:
   180  			break out
   181  		}
   182  	}
   183  }
   184  
   185  func TestLiveFees(t *testing.T) {
   186  	LiveFeeRates(btc, t, map[string]uint64{
   187  		"a32697f1796b7b87d953637ac827e11b84c6b0f9237cff793f329f877af50aea": 5848,
   188  		"f3e3e209672fc057bd896c0f703f092a251fa4dca09d062a0223f760661b8187": 506,
   189  		"a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d": 4191,
   190  	})
   191  }
   192  
   193  func TestMedianFeeRates(t *testing.T) {
   194  	TestMedianFees(btc, t)
   195  	TestMedianFeesTheHardWay(btc, t)
   196  	// Just for comparison
   197  	feeRate, err := btc.node.EstimateSmartFee(1, &btcjson.EstimateModeConservative)
   198  	if err != nil {
   199  		fmt.Printf("EstimateSmartFee unavailable: %v \n", err)
   200  	} else {
   201  		fmt.Printf("EstimateSmartFee: %d \n", feeRate)
   202  	}
   203  }
   204  
   205  // This test does not pass yet.
   206  // type backendConstructor func(context.Context, string, asset.Logger, asset.Network) (asset.Backend, error)
   207  //
   208  // // TestPlugin checks for a plugin file with the default name in the current
   209  // // directory.
   210  // // To build as a plugin: go build -buildmode=plugin
   211  // func TestPlugin(t *testing.T) {
   212  // 	dir, err := os.Getwd()
   213  // 	if err != nil {
   214  // 		t.Fatalf("error retrieving working directory: %v", err)
   215  // 	}
   216  // 	pluginPath := filepath.Join(dir, "btc.so")
   217  // 	if _, err = os.Stat(pluginPath); os.IsNotExist(err) {
   218  // 		t.Fatalf("no plugin found")
   219  // 	}
   220  // 	module, err := plugin.Open(pluginPath)
   221  // 	if err != nil {
   222  // 		t.Fatalf("error opening plugin from %s: %v", pluginPath, err)
   223  // 	}
   224  // 	newBackend, err := module.Lookup("NewBackend")
   225  // 	if err != nil {
   226  // 		t.Fatalf("error looking up symbol: %v", err)
   227  // 	}
   228  // 	constructor, ok := newBackend.(backendConstructor)
   229  // 	if !ok {
   230  // 		t.Fatalf("failed to cast imported symbol as backend constructor")
   231  // 	}
   232  // 	logger := slog.NewBackend(os.Stdout).Logger("PLUGIN")
   233  // 	ctx, shutdown := context.WithCancel(context.Background())
   234  // 	defer shutdown()
   235  // 	dexAsset, err := constructor(ctx, SystemConfigPath("bitcoin"), logger, dex.Mainnet)
   236  // 	if err != nil {
   237  // 		t.Fatalf("error creating Backend from imported constructor: %v", err)
   238  // 	}
   239  // 	btc, ok := dexAsset.(*Backend)
   240  // 	if !ok {
   241  // 		t.Fatalf("failed to cast plugin Backend to *Backend")
   242  // 	}
   243  // 	_, err = btc.node.GetBestBlockHash()
   244  // 	if err != nil {
   245  // 		t.Fatalf("error retrieving best block hash: %v", err)
   246  // 	}
   247  // }