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

     1  //go:build !btclive && !btcfees && !feefetcher
     2  
     3  // These tests will not be run if the btclive build tag is set. In that case,
     4  // the live_test.go tests will run.
     5  
     6  package btc
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"crypto/sha256"
    12  	"encoding/hex"
    13  	"encoding/json"
    14  	"errors"
    15  	"fmt"
    16  	"math/rand"
    17  	"net"
    18  	"os"
    19  	"path/filepath"
    20  	"strconv"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	"decred.org/dcrdex/dex"
    26  	"decred.org/dcrdex/dex/config"
    27  	dexbtc "decred.org/dcrdex/dex/networks/btc"
    28  	"github.com/btcsuite/btcd/btcec/v2"
    29  	"github.com/btcsuite/btcd/btcec/v2/ecdsa"
    30  	"github.com/btcsuite/btcd/btcjson"
    31  	"github.com/btcsuite/btcd/btcutil"
    32  	"github.com/btcsuite/btcd/chaincfg"
    33  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    34  	"github.com/btcsuite/btcd/txscript"
    35  	"github.com/btcsuite/btcd/wire"
    36  	"gopkg.in/ini.v1"
    37  )
    38  
    39  var (
    40  	testParams     = &chaincfg.MainNetParams
    41  	mainnetPort    = 8332
    42  	blockPollDelay time.Duration
    43  	defaultHost    = "127.0.0.1"
    44  )
    45  
    46  func TestMain(m *testing.M) {
    47  	// Set any created Backends to poll for blocks every 50 ms to
    48  	// accommodate reorg testing.
    49  	blockPollInterval = time.Millisecond * 50
    50  	// blockPollDelay must be long enough to allow for block polling go-routine
    51  	// to run at least a single tick (must be at least as long as blockPollInterval
    52  	// and ideally significantly longer).
    53  	blockPollDelay = blockPollInterval + time.Millisecond*50
    54  	os.Exit(m.Run())
    55  }
    56  
    57  // TestConfig tests the LoadConfig function.
    58  func TestConfig(t *testing.T) {
    59  	cfg := &dexbtc.RPCConfig{}
    60  	parsedCfg := &dexbtc.RPCConfig{}
    61  
    62  	tempDir := t.TempDir()
    63  	filePath := filepath.Join(tempDir, "test.conf")
    64  
    65  	runCfg := func(inCfg *dexbtc.RPCConfig) error {
    66  		*cfg = *inCfg
    67  		cfgFile := ini.Empty()
    68  		err := cfgFile.ReflectFrom(cfg)
    69  		if err != nil {
    70  			return err
    71  		}
    72  		err = cfgFile.SaveTo(filePath)
    73  		if err != nil {
    74  			return err
    75  		}
    76  		parsedCfg = new(dexbtc.RPCConfig)
    77  		err = config.ParseInto(filePath, parsedCfg)
    78  		if err != nil {
    79  			return err
    80  		}
    81  		return dexbtc.CheckRPCConfig(parsedCfg, assetName, dex.Mainnet, dexbtc.RPCPorts)
    82  	}
    83  
    84  	// Check that there is an error from an unpopulated configuration.
    85  	err := runCfg(cfg)
    86  	if err == nil {
    87  		t.Fatalf("no error for empty config")
    88  	}
    89  
    90  	// Try with just the name. Error expected.
    91  	err = runCfg(&dexbtc.RPCConfig{
    92  		RPCUser: "somename",
    93  	})
    94  	if err == nil {
    95  		t.Fatalf("no error when just name provided")
    96  	}
    97  
    98  	// Try with just the password. Error expected.
    99  	err = runCfg(&dexbtc.RPCConfig{
   100  		RPCPass: "somepass",
   101  	})
   102  	if err == nil {
   103  		t.Fatalf("no error when just password provided")
   104  	}
   105  
   106  	// Give both name and password. This should not be an error.
   107  	err = runCfg(&dexbtc.RPCConfig{
   108  		RPCUser: "somename",
   109  		RPCPass: "somepass",
   110  	})
   111  	if err != nil {
   112  		t.Fatalf("unexpected error when both name and password provided: %v", err)
   113  	}
   114  	h, p, err := net.SplitHostPort(parsedCfg.RPCBind)
   115  	if err != nil {
   116  		t.Fatalf("error splitting host and port from %q: %v", parsedCfg.RPCBind, err)
   117  	}
   118  	if h != defaultHost {
   119  		t.Fatalf("unexpected default host. wanted %s, got %s", defaultHost, h)
   120  	}
   121  	if p != strconv.Itoa(mainnetPort) {
   122  		t.Fatalf("unexpected default port. wanted %d, got %s", mainnetPort, p)
   123  	}
   124  	// sanity check for name and password match
   125  	if parsedCfg.RPCUser != cfg.RPCUser {
   126  		t.Fatalf("name mismatch")
   127  	}
   128  	if parsedCfg.RPCPass != cfg.RPCPass {
   129  		t.Fatalf("password mismatch")
   130  	}
   131  	if parsedCfg.IsPublicProvider {
   132  		t.Fatalf("IsPublicProvider was unexpectedly set true")
   133  	}
   134  
   135  	// Check with a designated port, but no host specified.
   136  	err = runCfg(&dexbtc.RPCConfig{
   137  		RPCUser: "somename",
   138  		RPCPass: "somepass",
   139  		RPCPort: 1234,
   140  	})
   141  	if err != nil {
   142  		t.Fatalf("unexpected error when setting port: %v", err)
   143  	}
   144  	// See that RPCBind returns localhost.
   145  	h, p, err = net.SplitHostPort(parsedCfg.RPCBind)
   146  	if err != nil {
   147  		t.Fatalf("error splitting host and port when setting port: %v", err)
   148  	}
   149  	if h != defaultHost {
   150  		t.Fatalf("unexpected host when setting port. wanted %s, got %s", defaultHost, h)
   151  	}
   152  	if p != "1234" {
   153  		t.Fatalf("unexpected custom port. wanted 1234, got %s", p)
   154  	}
   155  
   156  	// Check with rpcbind set (without designated port) and custom rpcport.
   157  	err = runCfg(&dexbtc.RPCConfig{
   158  		RPCUser: "somename",
   159  		RPCPass: "somepass",
   160  		RPCBind: "127.0.0.2",
   161  		RPCPort: 1234,
   162  	})
   163  	if err != nil {
   164  		t.Fatalf("unexpected error when setting portless rpcbind: %v", err)
   165  	}
   166  	h, p, err = net.SplitHostPort(parsedCfg.RPCBind)
   167  	if err != nil {
   168  		t.Fatalf("error splitting host and port when setting portless rpcbind: %v", err)
   169  	}
   170  	if h != "127.0.0.2" {
   171  		t.Fatalf("unexpected host when setting portless rpcbind. wanted 127.0.0.2, got %s", h)
   172  	}
   173  	if p != "1234" {
   174  		t.Fatalf("unexpected custom port when setting portless rpcbind. wanted 1234, got %s", p)
   175  	}
   176  
   177  	// Check with a port set with both rpcbind and rpcport. The rpcbind port
   178  	// should take precedence.
   179  	err = runCfg(&dexbtc.RPCConfig{
   180  		RPCUser: "somename",
   181  		RPCPass: "somepass",
   182  		RPCBind: "127.0.0.2:1234",
   183  		RPCPort: 1235,
   184  	})
   185  	if err != nil {
   186  		t.Fatalf("unexpected error when setting port twice: %v", err)
   187  	}
   188  	h, p, err = net.SplitHostPort(parsedCfg.RPCBind)
   189  	if err != nil {
   190  		t.Fatalf("error splitting host and port when setting port twice: %v", err)
   191  	}
   192  	if h != "127.0.0.2" {
   193  		t.Fatalf("unexpected host when setting port twice. wanted 127.0.0.2, got %s", h)
   194  	}
   195  	if p != "1234" {
   196  		t.Fatalf("unexpected custom port when setting port twice. wanted 1234, got %s", p)
   197  	}
   198  
   199  	// Check with just a port for rpcbind and make sure it gets parsed.
   200  	err = runCfg(&dexbtc.RPCConfig{
   201  		RPCUser: "somename",
   202  		RPCPass: "somepass",
   203  		RPCBind: ":1234",
   204  	})
   205  	if err != nil {
   206  		t.Fatalf("unexpected error when setting port-only rpcbind: %v", err)
   207  	}
   208  	h, p, err = net.SplitHostPort(parsedCfg.RPCBind)
   209  	if err != nil {
   210  		t.Fatalf("error splitting host and port when setting port-only rpcbind: %v", err)
   211  	}
   212  	if h != defaultHost {
   213  		t.Fatalf("unexpected host when setting port-only rpcbind. wanted %s, got %s", defaultHost, h)
   214  	}
   215  	if p != "1234" {
   216  		t.Fatalf("unexpected custom port when setting port-only rpcbind. wanted 1234, got %s", p)
   217  	}
   218  
   219  	// IPv6
   220  	err = runCfg(&dexbtc.RPCConfig{
   221  		RPCUser: "somename",
   222  		RPCPass: "somepass",
   223  		RPCBind: "[24c2:2865:4c7e:fd9b:76ea:4aa0:263d:6377]:1234",
   224  	})
   225  	if err != nil {
   226  		t.Fatalf("unexpected error when trying IPv6: %v", err)
   227  	}
   228  	h, p, err = net.SplitHostPort(parsedCfg.RPCBind)
   229  	if err != nil {
   230  		t.Fatalf("error splitting host and port when trying IPv6: %v", err)
   231  	}
   232  	if h != "24c2:2865:4c7e:fd9b:76ea:4aa0:263d:6377" {
   233  		t.Fatalf("unexpected host when trying IPv6. wanted %s, got %s", "24c2:2865:4c7e:fd9b:76ea:4aa0:263d:6377", h)
   234  	}
   235  	if p != "1234" {
   236  		t.Fatalf("unexpected custom port when trying IPv6. wanted 1234, got %s", p)
   237  	}
   238  
   239  	// Check with an https URL, signifying a public RPC provider.
   240  	err = runCfg(&dexbtc.RPCConfig{
   241  		RPCBind: "https://provider.com/my-api-key/btc",
   242  	})
   243  	if err != nil {
   244  		t.Fatalf("unexpected error when trying public provider: %v", err)
   245  	}
   246  	if parsedCfg.RPCBind != "provider.com/my-api-key/btc" {
   247  		t.Fatalf("wrong host parsed. wanted %s, go %s", "provider.com/my-api-key/btc", parsedCfg.RPCBind)
   248  	}
   249  	if !parsedCfg.IsPublicProvider {
   250  		t.Fatalf("UseTLS not set")
   251  	}
   252  }
   253  
   254  // The remaining tests use the testBlockchain which feeds a testNode stub for
   255  // rpcclient.Client. UTXOs, transactions and blocks are added to the blockchain
   256  // as jsonrpc types to be requested by the Backend.
   257  //
   258  // General formula for testing
   259  // 1. Create a Backend with the node field set to a testNode
   260  // 2. Create a fake UTXO and all of the associated jsonrpc-type blocks and
   261  //    transactions and add the to the test blockchain.
   262  // 3. Verify the Backend and UTXO methods are returning whatever is expected.
   263  // 4. Optionally add more blocks and/or transactions to the blockchain and check
   264  //    return values again, as things near the top of the chain can change.
   265  
   266  func randomBytes(len int) []byte {
   267  	bytes := make([]byte, len)
   268  	rand.Read(bytes)
   269  	return bytes
   270  }
   271  
   272  func randomHash() *chainhash.Hash {
   273  	hash := new(chainhash.Hash)
   274  	err := hash.SetBytes(randomBytes(32))
   275  	if err != nil {
   276  		fmt.Printf("chainhash.Hash.SetBytes error: %v\n", err)
   277  	}
   278  	return hash
   279  }
   280  
   281  // A fake "blockchain" to be used for RPC calls by the btcNode.
   282  type testBlockChain struct {
   283  	txOuts map[string]*btcjson.GetTxOutResult
   284  	txRaws map[chainhash.Hash]*btcjson.TxRawResult
   285  	blocks map[chainhash.Hash]*btcjson.GetBlockVerboseResult
   286  	hashes map[int64]*chainhash.Hash
   287  }
   288  
   289  // The testChain is a "blockchain" to store RPC responses for the Backend
   290  // node stub to request.
   291  var testChainMtx sync.RWMutex
   292  var testChain testBlockChain
   293  var testBestBlock testBlock
   294  
   295  type testBlock struct {
   296  	hash   chainhash.Hash
   297  	height uint32
   298  }
   299  
   300  // This must be called before using the testNode.
   301  func cleanTestChain() {
   302  	testChainMtx.Lock()
   303  	defer testChainMtx.Unlock()
   304  	testBestBlock = testBlock{
   305  		hash:   zeroHash,
   306  		height: 0,
   307  	}
   308  	testChain = testBlockChain{
   309  		txOuts: make(map[string]*btcjson.GetTxOutResult),
   310  		txRaws: make(map[chainhash.Hash]*btcjson.TxRawResult),
   311  		blocks: make(map[chainhash.Hash]*btcjson.GetBlockVerboseResult),
   312  		hashes: make(map[int64]*chainhash.Hash),
   313  	}
   314  }
   315  
   316  // A stub to replace rpcclient.Client for offline testing.
   317  type testNode struct {
   318  	rawResult []byte
   319  	rawErr    error
   320  }
   321  
   322  // Encode utxo info as a concatenated string hash:vout.
   323  func txOutID(txHash *chainhash.Hash, index uint32) string {
   324  	return txHash.String() + ":" + strconv.Itoa(int(index))
   325  }
   326  
   327  func mustUnmarshal(data []byte, thing any) {
   328  	if err := json.Unmarshal(data, thing); err != nil {
   329  		panic(err.Error())
   330  	}
   331  }
   332  
   333  func (t *testNode) Shutdown() {}
   334  
   335  func (t *testNode) WaitForShutdown() {}
   336  
   337  func (t *testNode) RawRequest(_ context.Context, method string, params []json.RawMessage) (json.RawMessage, error) {
   338  	switch method {
   339  	case methodGetBestBlockHash:
   340  		testChainMtx.RLock()
   341  		defer testChainMtx.RUnlock()
   342  		bbHash := testBestBlock.hash
   343  		return json.Marshal(bbHash.String())
   344  	case methodGetBlock:
   345  		testChainMtx.RLock()
   346  		defer testChainMtx.RUnlock()
   347  		var blkHash string
   348  		mustUnmarshal(params[0], &blkHash)
   349  		blockHash, err := chainhash.NewHashFromStr(blkHash)
   350  		if err != nil {
   351  			return nil, fmt.Errorf("rawrequest: %v method param unmarshal error: %v",
   352  				method, err)
   353  		}
   354  		block, found := testChain.blocks[*blockHash]
   355  		if !found {
   356  			return nil, fmt.Errorf("test block not found")
   357  		}
   358  		return json.Marshal(block)
   359  	case methodGetRawTransaction:
   360  		testChainMtx.RLock()
   361  		defer testChainMtx.RUnlock()
   362  		var hash string
   363  		mustUnmarshal(params[0], &hash)
   364  		txHash, err := chainhash.NewHashFromStr(hash)
   365  		if err != nil {
   366  			return nil, fmt.Errorf("rawrequest: %v method param unmarshal error: %v",
   367  				method, err)
   368  		}
   369  		tx, found := testChain.txRaws[*txHash]
   370  		if !found {
   371  			return nil, fmt.Errorf("test transaction not found")
   372  		}
   373  		return json.Marshal(tx)
   374  	case methodGetTxOut:
   375  		testChainMtx.RLock()
   376  		defer testChainMtx.RUnlock()
   377  		var hash string
   378  		mustUnmarshal(params[0], &hash)
   379  		txHash, err := chainhash.NewHashFromStr(hash)
   380  		if err != nil {
   381  			return nil, fmt.Errorf("rawrequest: %v method param unmarshal error: %v",
   382  				method, err)
   383  		}
   384  		var index uint32
   385  		mustUnmarshal(params[1], &index)
   386  		outID := txOutID(txHash, index)
   387  		out := testChain.txOuts[outID]
   388  		// Unfound is not an error for GetTxOut.
   389  		return json.Marshal(out)
   390  	case methodEstimateSmartFee:
   391  		const optimalFeeRate uint64 = 24
   392  		optimalRate := float64(optimalFeeRate) * 1e-5
   393  		return json.Marshal(&btcjson.EstimateSmartFeeResult{
   394  			Blocks:  2,
   395  			FeeRate: &optimalRate,
   396  		})
   397  	case methodGetBlockchainInfo:
   398  		if t.rawErr != nil {
   399  			return nil, t.rawErr
   400  		}
   401  		return t.rawResult, nil
   402  	}
   403  	return nil, nil
   404  }
   405  
   406  // Create a btcjson.GetTxOutResult such as is returned from GetTxOut.
   407  func testGetTxOut(confirmations, value int64, pkScript []byte) *btcjson.GetTxOutResult {
   408  	return &btcjson.GetTxOutResult{
   409  		Value:         float64(value) / 1e8,
   410  		Confirmations: confirmations,
   411  		ScriptPubKey: btcjson.ScriptPubKeyResult{
   412  			Hex: hex.EncodeToString(pkScript),
   413  		},
   414  	}
   415  }
   416  
   417  // Create a *btcjson.TxRawResult such as is returned by
   418  // GetRawTransactionVerbose.
   419  func testRawTransactionVerbose(msgTx *wire.MsgTx, txid, blockHash *chainhash.Hash,
   420  	confirmations int64) *btcjson.TxRawResult {
   421  
   422  	var hash string
   423  	if blockHash != nil {
   424  		hash = blockHash.String()
   425  	}
   426  	w := bytes.NewBuffer(make([]byte, 0))
   427  	err := msgTx.Serialize(w)
   428  	if err != nil {
   429  		fmt.Printf("error encoding MsgTx\n")
   430  	}
   431  	hexTx := w.Bytes()
   432  	return &btcjson.TxRawResult{
   433  		Hex:           hex.EncodeToString(hexTx),
   434  		Txid:          txid.String(),
   435  		BlockHash:     hash,
   436  		Confirmations: uint64(confirmations),
   437  	}
   438  }
   439  
   440  // Add a transaction output and it's getrawtransaction data.
   441  func testAddTxOut(msgTx *wire.MsgTx, vout uint32, txHash, blockHash *chainhash.Hash, confirmations int64) *btcjson.GetTxOutResult {
   442  	testChainMtx.Lock()
   443  	defer testChainMtx.Unlock()
   444  	txOut := testGetTxOut(confirmations, msgTx.TxOut[vout].Value, msgTx.TxOut[vout].PkScript)
   445  	testChain.txOuts[txOutID(txHash, vout)] = txOut
   446  	testAddTxVerbose(msgTx, txHash, blockHash, confirmations)
   447  	return txOut
   448  }
   449  
   450  // Add a btcjson.TxRawResult to the blockchain.
   451  func testAddTxVerbose(msgTx *wire.MsgTx, txHash, blockHash *chainhash.Hash, confirmations int64) *btcjson.TxRawResult {
   452  	tx := testRawTransactionVerbose(msgTx, txHash, blockHash, confirmations)
   453  	testChain.txRaws[*txHash] = tx
   454  	return tx
   455  }
   456  
   457  func testDeleteTxOut(txHash *chainhash.Hash, vout uint32) {
   458  	testChainMtx.Lock()
   459  	defer testChainMtx.Unlock()
   460  	txOutID(txHash, vout)
   461  	delete(testChain.txOuts, txOutID(txHash, vout))
   462  }
   463  
   464  // Create a *btcjson.GetBlockVerboseResult such as is returned by
   465  // GetBlockVerbose.
   466  func testBlockVerbose(blockHash, prevHash *chainhash.Hash, confirmations, height int64) *btcjson.GetBlockVerboseResult {
   467  	return &btcjson.GetBlockVerboseResult{
   468  		Hash:          blockHash.String(),
   469  		Confirmations: confirmations,
   470  		Height:        height,
   471  		PreviousHash:  prevHash.String(),
   472  	}
   473  }
   474  
   475  // Add a GetBlockVerboseResult to the blockchain.
   476  func testAddBlockVerbose(blockHash, prevHash *chainhash.Hash, confirmations int64, height uint32) *chainhash.Hash {
   477  	testChainMtx.Lock()
   478  	defer testChainMtx.Unlock()
   479  	if blockHash == nil {
   480  		blockHash = randomHash()
   481  	}
   482  	if height >= testBestBlock.height {
   483  		testBestBlock = testBlock{
   484  			hash:   *blockHash,
   485  			height: height,
   486  		}
   487  	}
   488  	if prevHash == nil {
   489  		if height == testBestBlock.height+1 {
   490  			prevHash = &testBestBlock.hash
   491  		} else {
   492  			prevHash = &zeroHash
   493  		}
   494  	}
   495  	testChain.blocks[*blockHash] = testBlockVerbose(blockHash, prevHash, confirmations, int64(height))
   496  	return blockHash
   497  }
   498  
   499  func testClearBestBlock() {
   500  	testChainMtx.Lock()
   501  	defer testChainMtx.Unlock()
   502  	testBestBlock = testBlock{}
   503  }
   504  
   505  // An element of the TxRawResult vout array.
   506  func testVout(value float64, pkScript []byte) btcjson.Vout {
   507  	return btcjson.Vout{
   508  		Value: value,
   509  		ScriptPubKey: btcjson.ScriptPubKeyResult{
   510  			Hex: hex.EncodeToString(pkScript),
   511  		},
   512  	}
   513  }
   514  
   515  // An element of the TxRawResult vin array.
   516  func testVin(txHash *chainhash.Hash, vout uint32) btcjson.Vin {
   517  	return btcjson.Vin{
   518  		Txid: txHash.String(),
   519  		Vout: vout,
   520  	}
   521  }
   522  
   523  type testAuth struct {
   524  	pubkey []byte
   525  	pkHash []byte
   526  	msg    []byte
   527  	sig    []byte
   528  }
   529  
   530  type testMsgTx struct {
   531  	tx   *wire.MsgTx
   532  	auth *testAuth
   533  	vout uint32
   534  }
   535  
   536  func s256Auth(msg []byte) *testAuth {
   537  	priv, err := btcec.NewPrivateKey()
   538  	if err != nil {
   539  		fmt.Printf("s256Auth error: %v\n", err)
   540  	}
   541  	pubkey := priv.PubKey().SerializeCompressed()
   542  	if msg == nil {
   543  		msg = randomBytes(32)
   544  	}
   545  	hash := sha256.Sum256(msg)
   546  	sig := ecdsa.Sign(priv, hash[:])
   547  	return &testAuth{
   548  		pubkey: pubkey,
   549  		pkHash: btcutil.Hash160(pubkey),
   550  		msg:    msg,
   551  		sig:    sig.Serialize(),
   552  	}
   553  }
   554  
   555  // Generate a public key on the secp256k1 curve.
   556  func genPubkey() ([]byte, []byte) {
   557  	priv, err := btcec.NewPrivateKey()
   558  	if err != nil {
   559  		panic(err.Error())
   560  	}
   561  	pub := priv.PubKey()
   562  	pubkey := pub.SerializeCompressed()
   563  	pkHash := btcutil.Hash160(pubkey)
   564  	return pubkey, pkHash
   565  }
   566  
   567  // A pay-to-script-hash pubkey script.
   568  func newP2PKHScript(segwit bool) ([]byte, *testAuth) {
   569  	auth := s256Auth(nil)
   570  	var pkScript []byte
   571  	var err error
   572  	if segwit {
   573  		pkScript, err = txscript.NewScriptBuilder().
   574  			AddOp(txscript.OP_0).
   575  			AddData(auth.pkHash).
   576  			Script()
   577  		if err != nil {
   578  			fmt.Printf("newP2PKHScript error: %v\n", err)
   579  		}
   580  	} else {
   581  		pkScript, err = txscript.NewScriptBuilder().
   582  			AddOps([]byte{
   583  				txscript.OP_DUP,
   584  				txscript.OP_HASH160,
   585  			}).
   586  			AddData(auth.pkHash).
   587  			AddOps([]byte{
   588  				txscript.OP_EQUALVERIFY,
   589  				txscript.OP_CHECKSIG,
   590  			}).Script()
   591  		if err != nil {
   592  			fmt.Printf("newP2PKHScript error: %v\n", err)
   593  		}
   594  	}
   595  
   596  	return pkScript, auth
   597  }
   598  
   599  // A MsgTx for a regular transaction with a single output. No inputs, so it's
   600  // not really a valid transaction, but that's okay on testBlockchain.
   601  func testMakeMsgTx(segwit bool) *testMsgTx {
   602  	pkScript, auth := newP2PKHScript(segwit)
   603  	msgTx := wire.NewMsgTx(wire.TxVersion)
   604  	msgTx.AddTxOut(wire.NewTxOut(1, pkScript))
   605  	return &testMsgTx{
   606  		tx:   msgTx,
   607  		auth: auth,
   608  	}
   609  }
   610  
   611  type testMsgTxSwap struct {
   612  	tx        *wire.MsgTx
   613  	contract  []byte
   614  	recipient btcutil.Address
   615  	refund    btcutil.Address
   616  }
   617  
   618  // Create a swap (initialization) contract with random pubkeys and return the
   619  // pubkey script and addresses.
   620  func testSwapContract(segwit bool) ([]byte, btcutil.Address, btcutil.Address) {
   621  	lockTime := time.Now().Add(time.Hour * 8).Unix()
   622  	secretHash := randomBytes(32)
   623  	_, receiverPKH := genPubkey()
   624  	_, senderPKH := genPubkey()
   625  	contract, err := txscript.NewScriptBuilder().
   626  		AddOps([]byte{
   627  			txscript.OP_IF,
   628  			txscript.OP_SIZE,
   629  		}).AddInt64(32).
   630  		AddOps([]byte{
   631  			txscript.OP_EQUALVERIFY,
   632  			txscript.OP_SHA256,
   633  		}).AddData(secretHash).
   634  		AddOps([]byte{
   635  			txscript.OP_EQUALVERIFY,
   636  			txscript.OP_DUP,
   637  			txscript.OP_HASH160,
   638  		}).AddData(receiverPKH).
   639  		AddOp(txscript.OP_ELSE).
   640  		AddInt64(lockTime).AddOps([]byte{
   641  		txscript.OP_CHECKLOCKTIMEVERIFY,
   642  		txscript.OP_DROP,
   643  		txscript.OP_DUP,
   644  		txscript.OP_HASH160,
   645  	}).AddData(senderPKH).
   646  		AddOps([]byte{
   647  			txscript.OP_ENDIF,
   648  			txscript.OP_EQUALVERIFY,
   649  			txscript.OP_CHECKSIG,
   650  		}).Script()
   651  	if err != nil {
   652  		fmt.Printf("testSwapContract error: %v\n", err)
   653  	}
   654  	var receiverAddr, refundAddr btcutil.Address
   655  	if segwit {
   656  		receiverAddr, _ = btcutil.NewAddressWitnessPubKeyHash(receiverPKH, testParams)
   657  		refundAddr, _ = btcutil.NewAddressWitnessPubKeyHash(senderPKH, testParams)
   658  	} else {
   659  		receiverAddr, _ = btcutil.NewAddressPubKeyHash(receiverPKH, testParams)
   660  		refundAddr, _ = btcutil.NewAddressPubKeyHash(senderPKH, testParams)
   661  	}
   662  
   663  	return contract, receiverAddr, refundAddr
   664  }
   665  
   666  func testMsgTxSwapInit(val int64, segwit bool) *testMsgTxSwap {
   667  	msgTx := wire.NewMsgTx(wire.TxVersion)
   668  	contract, recipient, refund := testSwapContract(segwit)
   669  	scriptHash := btcutil.Hash160(contract)
   670  	pkScript, err := txscript.NewScriptBuilder().
   671  		AddOp(txscript.OP_HASH160).
   672  		AddData(scriptHash).
   673  		AddOp(txscript.OP_EQUAL).
   674  		Script()
   675  	if err != nil {
   676  		fmt.Printf("script building error in testMsgTxSwapInit: %v", err)
   677  	}
   678  	msgTx.AddTxOut(wire.NewTxOut(val, pkScript))
   679  	return &testMsgTxSwap{
   680  		tx:        msgTx,
   681  		contract:  contract,
   682  		recipient: recipient,
   683  		refund:    refund,
   684  	}
   685  }
   686  
   687  type testMultiSigAuth struct {
   688  	pubkeys  [][]byte
   689  	pkHashes [][]byte
   690  	msg      []byte
   691  	sigs     [][]byte
   692  }
   693  
   694  // Information about a transaction with a P2SH output.
   695  type testMsgTxP2SH struct {
   696  	tx     *wire.MsgTx
   697  	auth   *testMultiSigAuth
   698  	vout   uint32
   699  	script []byte
   700  	n      int
   701  	m      int
   702  }
   703  
   704  // An M-of-N multi-sig script.
   705  func testMultiSigScriptMofN(m, n int) ([]byte, *testMultiSigAuth) {
   706  	// serialized compressed pubkey used for multisig
   707  	addrs := make([]*btcutil.AddressPubKey, 0, n)
   708  	auth := &testMultiSigAuth{
   709  		msg: randomBytes(32),
   710  	}
   711  
   712  	for i := 0; i < n; i++ {
   713  		a := s256Auth(auth.msg)
   714  		if i < m {
   715  			auth.pubkeys = append(auth.pubkeys, a.pubkey)
   716  			auth.pkHashes = append(auth.pkHashes, a.pkHash)
   717  			auth.sigs = append(auth.sigs, a.sig)
   718  		}
   719  		addr, err := btcutil.NewAddressPubKey(a.pubkey, testParams)
   720  		if err != nil {
   721  			fmt.Printf("error creating AddressSecpPubKey: %v\n", err)
   722  			return nil, nil
   723  		}
   724  		addrs = append(addrs, addr)
   725  	}
   726  	script, err := txscript.MultiSigScript(addrs, m)
   727  	if err != nil {
   728  		fmt.Printf("error creating MultiSigScript: %v\n", err)
   729  		return nil, nil
   730  	}
   731  	return script, auth
   732  }
   733  
   734  // A pay-to-script-hash M-of-N multi-sig output and vout 0 of a MsgTx.
   735  func testMsgTxP2SHMofN(m, n int, segwit bool) *testMsgTxP2SH {
   736  	script, auth := testMultiSigScriptMofN(m, n)
   737  	var pkScript []byte
   738  	var err error
   739  	if segwit {
   740  		scriptHash := sha256.Sum256(script)
   741  		pkScript, err = txscript.NewScriptBuilder().
   742  			AddOp(txscript.OP_0).
   743  			AddData(scriptHash[:]).
   744  			Script()
   745  		if err != nil {
   746  			fmt.Printf("error building script in testMsgTxP2SHMofN: %v", err)
   747  		}
   748  	} else {
   749  		scriptHash := btcutil.Hash160(script)
   750  		pkScript, err = txscript.NewScriptBuilder().
   751  			AddOp(txscript.OP_HASH160).
   752  			AddData(scriptHash).
   753  			AddOp(txscript.OP_EQUAL).
   754  			Script()
   755  		if err != nil {
   756  			fmt.Printf("error building script in testMsgTxP2SHMofN: %v", err)
   757  		}
   758  	}
   759  	msgTx := wire.NewMsgTx(wire.TxVersion)
   760  	msgTx.AddTxOut(wire.NewTxOut(1, pkScript))
   761  	return &testMsgTxP2SH{
   762  		tx:     msgTx,
   763  		auth:   auth,
   764  		script: script,
   765  		vout:   0,
   766  		n:      n,
   767  		m:      m,
   768  	}
   769  }
   770  
   771  // Make a backend that logs to stdout.
   772  func testBackend(segwit bool) (*Backend, func()) {
   773  	logger := dex.StdOutLogger("TEST", dex.LevelTrace)
   774  	// skip both loading config file and rpcclient.New in Connect. Manually
   775  	// create the Backend and set the node to our node stub.
   776  	btc := newBTC(&BackendCloneConfig{
   777  		Name:           "btc",
   778  		Segwit:         segwit,
   779  		AddressDecoder: btcutil.DecodeAddress,
   780  		Logger:         logger,
   781  		ChainParams:    testParams,
   782  	}, nil)
   783  	btc.node = &RPCClient{
   784  		requester: &testNode{},
   785  	}
   786  
   787  	ctx, cancel := context.WithCancel(context.Background())
   788  	var wg sync.WaitGroup
   789  	wg.Add(1)
   790  	go func() {
   791  		btc.run(ctx)
   792  		wg.Done()
   793  	}()
   794  	shutdown := func() {
   795  		cancel()
   796  		wg.Wait()
   797  	}
   798  	return btc, shutdown
   799  }
   800  
   801  // TestUTXOs tests UTXO-related paths.
   802  func TestUTXOs(t *testing.T) {
   803  	// The various UTXO types to check:
   804  	// 1. A valid UTXO in a mempool transaction
   805  	// 2. A valid UTXO in a mined
   806  	// 3. A UTXO that is invalid because it is non-existent
   807  	// 4. A UTXO that is invalid because it has the wrong script type
   808  	// 5. A UTXO that becomes invalid in a reorg
   809  	// 6. A UTXO with a pay-to-script-hash for a 1-of-2 multisig redeem script
   810  	// 7. A UTXO with a pay-to-script-hash for a 2-of-2 multisig redeem script
   811  	// 8. A UTXO spending a pay-to-witness-pubkey-hash (P2WPKH) script.
   812  	// 9. A UTXO spending a pay-to-witness-script-hash (P2WSH) 2-of-2 multisig
   813  	//    redeem script
   814  	// 10. A UTXO from a coinbase transaction, before and after maturing.
   815  
   816  	// Create a Backend with the test node.
   817  	btc, shutdown := testBackend(false)
   818  	defer shutdown()
   819  
   820  	// The vout will be randomized during reset.
   821  	const txHeight = uint32(50)
   822  
   823  	// A general reset function that clears the testBlockchain and the blockCache.
   824  	reset := func() {
   825  		btc.blockCache.mtx.Lock()
   826  		defer btc.blockCache.mtx.Unlock()
   827  		cleanTestChain()
   828  		newBC := newBlockCache()
   829  		btc.blockCache.blocks = newBC.blocks
   830  		btc.blockCache.mainchain = newBC.mainchain
   831  		btc.blockCache.best = newBC.best
   832  	}
   833  
   834  	// CASE 1: A valid UTXO in a mempool transaction
   835  	reset()
   836  	txHash := randomHash()
   837  	blockHash := randomHash()
   838  	msg := testMakeMsgTx(false)
   839  	// For a regular test tx, the output is at output index 0. Pass nil for the
   840  	// block hash and 0 for the block height and confirmations for a mempool tx.
   841  	txout := testAddTxOut(msg.tx, msg.vout, txHash, nil, 0)
   842  	// Set the value for this one.
   843  	txout.Value = 5.0
   844  	// There is no block info to add, since this is a mempool transaction
   845  	utxo, err := btc.utxo(txHash, msg.vout, nil)
   846  	if err != nil {
   847  		t.Fatalf("case 1 - unexpected error: %v", err)
   848  	}
   849  	// While we're here, check the spend script size and value are correct.
   850  	scriptSize := utxo.SpendSize()
   851  	wantScriptSize := uint32(dexbtc.TxInOverhead + 1 + dexbtc.RedeemP2PKHSigScriptSize)
   852  	if scriptSize != wantScriptSize {
   853  		t.Fatalf("case 1 - unexpected spend script size reported. expected %d, got %d", wantScriptSize, scriptSize)
   854  	}
   855  	if utxo.Value() != 500_000_000 {
   856  		t.Fatalf("case 1 - unexpected output value. expected 500,000,000, got %d", utxo.Value())
   857  	}
   858  	// Now "mine" the transaction.
   859  	testAddBlockVerbose(blockHash, nil, 1, txHeight)
   860  	// Overwrite the test blockchain transaction details.
   861  	testAddTxOut(msg.tx, 0, txHash, blockHash, 1)
   862  	// "mining" the block should cause a reorg.
   863  	confs, err := utxo.Confirmations(context.Background())
   864  	if err != nil {
   865  		t.Fatalf("case 1 - error retrieving confirmations after transaction \"mined\": %v", err)
   866  	}
   867  	if confs != 1 {
   868  		// The confirmation count is not taken from the wire.TxOut.Confirmations,
   869  		// so check that it is correctly calculated based on height.
   870  		t.Fatalf("case 1 - expected 1 confirmation after mining transaction, found %d", confs)
   871  	}
   872  	// Make sure the pubkey spends the output.
   873  	err = utxo.Auth([][]byte{msg.auth.pubkey}, [][]byte{msg.auth.sig}, msg.auth.msg)
   874  	if err != nil {
   875  		t.Fatalf("case 1 - Auth error: %v", err)
   876  	}
   877  
   878  	// CASE 2: A valid UTXO in a mined block. This UTXO will have non-zero
   879  	// confirmations, a valid pkScipt
   880  	reset()
   881  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
   882  	txHash = randomHash()
   883  	msg = testMakeMsgTx(false)
   884  	testAddTxOut(msg.tx, msg.vout, txHash, blockHash, 1)
   885  	utxo, err = btc.utxo(txHash, msg.vout, nil)
   886  	if err != nil {
   887  		t.Fatalf("case 2 - unexpected error: %v", err)
   888  	}
   889  	err = utxo.Auth([][]byte{msg.auth.pubkey}, [][]byte{msg.auth.sig}, msg.auth.msg)
   890  	if err != nil {
   891  		t.Fatalf("case 2 - Auth error: %v", err)
   892  	}
   893  
   894  	// CASE 3: A UTXO that is invalid because it is non-existent
   895  	reset()
   896  	_, err = btc.utxo(randomHash(), 0, nil)
   897  	if err == nil {
   898  		t.Fatalf("case 3 - received no error for a non-existent UTXO")
   899  	}
   900  
   901  	// CASE 4: A UTXO that is invalid because it has the wrong script type.
   902  	reset()
   903  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
   904  	txHash = randomHash()
   905  	msg = testMakeMsgTx(false)
   906  	// make the script nonsense.
   907  	msg.tx.TxOut[0].PkScript = []byte{0x00, 0x01, 0x02, 0x03}
   908  	testAddTxOut(msg.tx, msg.vout, txHash, blockHash, 1)
   909  	_, err = btc.utxo(txHash, msg.vout, nil)
   910  	if err == nil {
   911  		t.Fatalf("case 4 - received no error for a UTXO with wrong script type")
   912  	}
   913  
   914  	// CASE 5: A UTXO that becomes invalid in a reorg
   915  	reset()
   916  	txHash = randomHash()
   917  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
   918  	msg = testMakeMsgTx(false)
   919  	testAddTxOut(msg.tx, msg.vout, txHash, blockHash, 1)
   920  	utxo, err = btc.utxo(txHash, msg.vout, nil)
   921  	if err != nil {
   922  		t.Fatalf("case 5 - received error for utxo")
   923  	}
   924  	_, err = utxo.Confirmations(context.Background())
   925  	if err != nil {
   926  		t.Fatalf("case 5 - received error before reorg")
   927  	}
   928  	testAddBlockVerbose(nil, nil, 1, txHeight)
   929  	// Remove the txout from the blockchain, since bitcoind would no longer
   930  	// return it.
   931  	testDeleteTxOut(txHash, msg.vout)
   932  	time.Sleep(blockPollDelay)
   933  	_, err = utxo.Confirmations(context.Background())
   934  	if err == nil {
   935  		t.Fatalf("case 5 - received no error for orphaned transaction")
   936  	}
   937  	// Now put it back in mempool and check again.
   938  	testAddTxOut(msg.tx, msg.vout, txHash, nil, 0)
   939  	confs, err = utxo.Confirmations(context.Background())
   940  	if err != nil {
   941  		t.Fatalf("case 5 - error checking confirmations on orphaned transaction back in mempool: %v", err)
   942  	}
   943  	if confs != 0 {
   944  		t.Fatalf("case 5 - expected 0 confirmations, got %d", confs)
   945  	}
   946  
   947  	// CASE 6: A UTXO with a pay-to-script-hash for a 1-of-2 multisig redeem
   948  	// script
   949  	reset()
   950  	txHash = randomHash()
   951  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
   952  	msgMultiSig := testMsgTxP2SHMofN(1, 2, false)
   953  	testAddTxOut(msgMultiSig.tx, msgMultiSig.vout, txHash, blockHash, 1)
   954  	// First try to get the UTXO without providing the raw script.
   955  	_, err = btc.utxo(txHash, msgMultiSig.vout, nil)
   956  	if err == nil {
   957  		t.Fatalf("no error thrown for p2sh utxo when no script was provided")
   958  	}
   959  	// Now provide the script.
   960  	utxo, err = btc.utxo(txHash, msgMultiSig.vout, msgMultiSig.script)
   961  	if err != nil {
   962  		t.Fatalf("case 6 - received error for utxo: %v", err)
   963  	}
   964  	confs, err = utxo.Confirmations(context.Background())
   965  	if err != nil {
   966  		t.Fatalf("case 6 - error getting confirmations: %v", err)
   967  	}
   968  	if confs != 1 {
   969  		t.Fatalf("case 6 - expected 1 confirmation, got %d", confs)
   970  	}
   971  	err = utxo.Auth(msgMultiSig.auth.pubkeys[:1], msgMultiSig.auth.sigs[:1], msgMultiSig.auth.msg)
   972  	if err != nil {
   973  		t.Fatalf("case 6 - Auth error: %v", err)
   974  	}
   975  
   976  	// CASE 7: A UTXO with a pay-to-script-hash for a 2-of-2 multisig redeem
   977  	// script
   978  	reset()
   979  	txHash = randomHash()
   980  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
   981  	msgMultiSig = testMsgTxP2SHMofN(2, 2, false)
   982  	testAddTxOut(msgMultiSig.tx, msgMultiSig.vout, txHash, blockHash, 1)
   983  	utxo, err = btc.utxo(txHash, msgMultiSig.vout, msgMultiSig.script)
   984  	if err != nil {
   985  		t.Fatalf("case 7 - received error for utxo: %v", err)
   986  	}
   987  	// Try to get by with just one of the pubkeys.
   988  	err = utxo.Auth(msgMultiSig.auth.pubkeys[:1], msgMultiSig.auth.sigs[:1], msgMultiSig.auth.msg)
   989  	if err == nil {
   990  		t.Fatalf("case 7 - no error when only provided one of two required pubkeys")
   991  	}
   992  	// Now do both.
   993  	err = utxo.Auth(msgMultiSig.auth.pubkeys, msgMultiSig.auth.sigs, msgMultiSig.auth.msg)
   994  	if err != nil {
   995  		t.Fatalf("case 7 - Auth error: %v", err)
   996  	}
   997  
   998  	// CASE 8: A UTXO spending a pay-to-witness-pubkey-hash (P2WPKH) script.
   999  	reset()
  1000  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
  1001  	txHash = randomHash()
  1002  	msg = testMakeMsgTx(true) // true - P2WPKH at vout 0
  1003  	testAddTxOut(msg.tx, msg.vout, txHash, blockHash, 1)
  1004  	utxo, err = btc.utxo(txHash, msg.vout, nil)
  1005  	if err != nil {
  1006  		t.Fatalf("case 8 - unexpected error: %v", err)
  1007  	}
  1008  	// Check that the segwit flag is set.
  1009  	if !utxo.scriptType.IsSegwit() {
  1010  		t.Fatalf("case 8 - script type parsed as non-segwit")
  1011  	}
  1012  	err = utxo.Auth([][]byte{msg.auth.pubkey}, [][]byte{msg.auth.sig}, msg.auth.msg)
  1013  	if err != nil {
  1014  		t.Fatalf("case 8 - Auth error: %v", err)
  1015  	}
  1016  
  1017  	// CASE 9: A UTXO spending a pay-to-witness-script-hash (P2WSH) 2-of-2
  1018  	// multisig redeem script
  1019  	reset()
  1020  	txHash = randomHash()
  1021  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
  1022  	msgMultiSig = testMsgTxP2SHMofN(2, 2, true)
  1023  	testAddTxOut(msgMultiSig.tx, msgMultiSig.vout, txHash, blockHash, 1)
  1024  	utxo, err = btc.utxo(txHash, msgMultiSig.vout, msgMultiSig.script)
  1025  	if err != nil {
  1026  		t.Fatalf("case 9 - received error for utxo: %v", err)
  1027  	}
  1028  	// Check that the script is flagged segwit
  1029  	if !utxo.scriptType.IsSegwit() {
  1030  		t.Fatalf("case 9 - script type parsed as non-segwit")
  1031  	}
  1032  	// Try to get by with just one of the pubkeys.
  1033  	err = utxo.Auth(msgMultiSig.auth.pubkeys[:1], msgMultiSig.auth.sigs[:1], msgMultiSig.auth.msg)
  1034  	if err == nil {
  1035  		t.Fatalf("case 9 - no error when only provided one of two required pubkeys")
  1036  	}
  1037  	// Now do both.
  1038  	err = utxo.Auth(msgMultiSig.auth.pubkeys, msgMultiSig.auth.sigs, msgMultiSig.auth.msg)
  1039  	if err != nil {
  1040  		t.Fatalf("case 9 - Auth error: %v", err)
  1041  	}
  1042  
  1043  	// CASE 10: A UTXO from a coinbase transaction, before and after maturing.
  1044  	reset()
  1045  	blockHash = testAddBlockVerbose(nil, nil, 1, txHeight)
  1046  	txHash = randomHash()
  1047  	msg = testMakeMsgTx(false)
  1048  	txOut := testAddTxOut(msg.tx, msg.vout, txHash, blockHash, 1)
  1049  	txOut.Coinbase = true
  1050  	_, err = btc.utxo(txHash, msg.vout, nil)
  1051  	if err == nil {
  1052  		t.Fatalf("case 10 - no error for immature transaction")
  1053  	}
  1054  	if !errors.Is(err, immatureTransactionError) {
  1055  		t.Fatalf("case 10 - expected immatureTransactionError, got: %v", err)
  1056  	}
  1057  	// Mature the transaction
  1058  	maturity := uint32(testParams.CoinbaseMaturity)
  1059  	testAddBlockVerbose(nil, nil, 1, txHeight+maturity-1)
  1060  	txOut.Confirmations = int64(maturity)
  1061  	time.Sleep(blockPollDelay)
  1062  	_, err = btc.utxo(txHash, msg.vout, nil)
  1063  	if err != nil {
  1064  		t.Fatalf("case 10 - unexpected error after maturing: %v", err)
  1065  	}
  1066  
  1067  	// CASE 11: A swap contract
  1068  	val := int64(5)
  1069  	cleanTestChain()
  1070  	txHash = randomHash()
  1071  	blockHash = randomHash()
  1072  	swap := testMsgTxSwapInit(val, btc.segwit)
  1073  	testAddBlockVerbose(blockHash, nil, 1, txHeight)
  1074  	btcVal := btcutil.Amount(val).ToBTC()
  1075  	testAddTxOut(swap.tx, 0, txHash, blockHash, 1).Value = btcVal
  1076  	verboseTx := testChain.txRaws[*txHash]
  1077  
  1078  	spentTxHash := randomHash()
  1079  	verboseTx.Vin = append(verboseTx.Vin, testVin(spentTxHash, 0))
  1080  	// We need to add that transaction to the blockchain too, because it will
  1081  	// be requested for the previous outpoint value.
  1082  	spentMsg := testMakeMsgTx(false)
  1083  	spentTx := testAddTxVerbose(spentMsg.tx, spentTxHash, blockHash, 2)
  1084  	spentTx.Vout = []btcjson.Vout{testVout(1, nil)}
  1085  	swapOut := swap.tx.TxOut[0]
  1086  	btcVal = btcutil.Amount(swapOut.Value).ToBTC()
  1087  	verboseTx.Vout = append(verboseTx.Vout, testVout(btcVal, swapOut.PkScript))
  1088  	utxo, err = btc.utxo(txHash, 0, swap.contract)
  1089  	if err != nil {
  1090  		t.Fatalf("case 11 - received error for utxo: %v", err)
  1091  	}
  1092  
  1093  	// Now try again with the correct vout.
  1094  	contract, err := btc.auditContract(utxo.Output) // sets refund and swap addresses
  1095  	if err != nil {
  1096  		t.Fatalf("case 11 - unexpected error auditing contract: %v", err)
  1097  	}
  1098  	if contract.SwapAddress != swap.recipient.String() {
  1099  		t.Fatalf("case 11 - wrong recipient. wanted '%s' got '%s'", contract.SwapAddress, swap.recipient.String())
  1100  	}
  1101  	if contract.Value() != 5 {
  1102  		t.Fatalf("case 11 - unexpected output value. wanted 5, got %d", contract.Value())
  1103  	}
  1104  }
  1105  
  1106  func TestRedemption(t *testing.T) {
  1107  	t.Run("segwit", func(t *testing.T) {
  1108  		testRedemption(t, true)
  1109  	})
  1110  	t.Run("non-segwit", func(t *testing.T) {
  1111  		testRedemption(t, false)
  1112  	})
  1113  }
  1114  
  1115  func testRedemption(t *testing.T, segwit bool) {
  1116  	btc, shutdown := testBackend(false)
  1117  	defer shutdown()
  1118  
  1119  	// The vout will be randomized during reset.
  1120  	txHeight := uint32(32)
  1121  	cleanTestChain()
  1122  	txHash := randomHash()
  1123  	redemptionID := toCoinID(txHash, 0)
  1124  	// blockHash := randomHash()
  1125  	spentHash := randomHash()
  1126  	spentVout := uint32(0)
  1127  	spentID := toCoinID(spentHash, spentVout)
  1128  	verboseTx := testAddTxVerbose(testMakeMsgTx(segwit).tx, spentHash, nil, 0)
  1129  	verboseTx.Vout = append(verboseTx.Vout, btcjson.Vout{
  1130  		Value: 5,
  1131  	})
  1132  	msg := testMakeMsgTx(segwit)
  1133  	vin := btcjson.Vin{
  1134  		Txid: spentHash.String(),
  1135  		Vout: spentVout,
  1136  	}
  1137  
  1138  	// A valid mempool redemption.
  1139  	verboseTx = testAddTxVerbose(msg.tx, txHash, nil, 0)
  1140  	verboseTx.Vin = append(verboseTx.Vin, vin)
  1141  	redemption, err := btc.Redemption(redemptionID, spentID, nil)
  1142  	if err != nil {
  1143  		t.Fatalf("Redemption error: %v", err)
  1144  	}
  1145  	confs, err := redemption.Confirmations(context.Background())
  1146  	if err != nil {
  1147  		t.Fatalf("redemption Confirmations error: %v", err)
  1148  	}
  1149  	if confs != 0 {
  1150  		t.Fatalf("expected 0 confirmations, got %d", confs)
  1151  	}
  1152  
  1153  	// Missing transaction
  1154  	testChainMtx.Lock()
  1155  	delete(testChain.txRaws, *txHash)
  1156  	testChainMtx.Unlock()
  1157  	_, err = btc.Redemption(redemptionID, spentID, nil)
  1158  	if err == nil {
  1159  		t.Fatalf("No error for missing transaction")
  1160  	}
  1161  
  1162  	// Doesn't spend transaction.
  1163  	verboseTx = testAddTxVerbose(msg.tx, txHash, nil, 0)
  1164  	verboseTx.Vin = append(verboseTx.Vin, btcjson.Vin{
  1165  		Txid: randomHash().String(),
  1166  	})
  1167  	_, err = btc.Redemption(redemptionID, spentID, nil)
  1168  	if err == nil {
  1169  		t.Fatalf("No error for wrong previous outpoint")
  1170  	}
  1171  
  1172  	// Mined transaction.
  1173  	blockHash := randomHash()
  1174  	blockHeight := txHeight - 1
  1175  	verboseTx = testAddTxVerbose(msg.tx, txHash, blockHash, int64(blockHeight))
  1176  	verboseTx.Vin = append(verboseTx.Vin, vin)
  1177  	testAddBlockVerbose(blockHash, nil, 1, blockHeight)
  1178  	redemption, err = btc.Redemption(redemptionID, spentID, nil)
  1179  	if err != nil {
  1180  		t.Fatalf("Redemption with confs error: %v", err)
  1181  	}
  1182  	confs, err = redemption.Confirmations(context.Background())
  1183  	if err != nil {
  1184  		t.Fatalf("redemption with confs Confirmations error: %v", err)
  1185  	}
  1186  	if confs != 1 {
  1187  		t.Fatalf("expected 1 confirmation, got %d", confs)
  1188  	}
  1189  }
  1190  
  1191  // TestReorg tests various reorg paths. Because bitcoind doesn't support
  1192  // websocket notifications, and ZeroMQ is not desirable, Backend polls for
  1193  // new block data every 5 seconds or so. The poll interval means it's possible
  1194  // for various flavors of reorg to happen before a new block is detected. These
  1195  // tests check that reorgs of various depths are correctly handled by the
  1196  // block monitor loop and the block cache.
  1197  func TestReorg(t *testing.T) {
  1198  	// Create a Backend with the test node.
  1199  	btc, shutdown := testBackend(false)
  1200  	defer shutdown()
  1201  
  1202  	// Clear the blockchain and set the provided chain to build on the ancestor
  1203  	// block.
  1204  	reset := func() {
  1205  		btc.blockCache.mtx.Lock()
  1206  		defer btc.blockCache.mtx.Unlock()
  1207  		cleanTestChain()
  1208  		newBC := newBlockCache()
  1209  		btc.blockCache.blocks = newBC.blocks
  1210  		btc.blockCache.mainchain = newBC.mainchain
  1211  		btc.blockCache.best = newBC.best
  1212  	}
  1213  	reset()
  1214  
  1215  	ancestorHeight := uint32(50)
  1216  	ancestorHash := testAddBlockVerbose(nil, nil, 0, ancestorHeight)
  1217  
  1218  	makeChain := func() []*chainhash.Hash {
  1219  		chain := make([]*chainhash.Hash, 0, 3)
  1220  		for i := 0; i < 3; i++ {
  1221  			h := testAddBlockVerbose(nil, nil, 0, ancestorHeight+1+uint32(i))
  1222  			chain = append(chain, h)
  1223  		}
  1224  		return chain
  1225  	}
  1226  	chainA := makeChain()
  1227  	chainB := makeChain()
  1228  
  1229  	setChain := func(hashes []*chainhash.Hash) {
  1230  		testClearBestBlock()
  1231  		rootConfs := int64(len(hashes)) + 1
  1232  		// Add the ancestor block
  1233  		testAddBlockVerbose(ancestorHash, nil, rootConfs, ancestorHeight)
  1234  		prevHash := ancestorHash
  1235  		for i, hash := range hashes {
  1236  			prevHash = testAddBlockVerbose(hash, prevHash, rootConfs-int64(i), ancestorHeight+uint32(i))
  1237  
  1238  		}
  1239  		time.Sleep(blockPollDelay)
  1240  	}
  1241  
  1242  	setSidechainConfs := func(hashes []*chainhash.Hash) {
  1243  		btc.blockCache.mtx.Lock() // read from (*blockCache).add in cache.go
  1244  		testChainMtx.Lock()       // field of testChain
  1245  		defer testChainMtx.Unlock()
  1246  		defer btc.blockCache.mtx.Unlock()
  1247  		for _, hash := range hashes {
  1248  			block, found := testChain.blocks[*hash]
  1249  			if !found {
  1250  				t.Fatalf("test block not found")
  1251  			}
  1252  			// Set Confirmations
  1253  			block.Confirmations = -1
  1254  		}
  1255  	}
  1256  
  1257  	checkOrphanState := func(hashes []*chainhash.Hash, orphanState bool) bool {
  1258  		for _, hash := range hashes {
  1259  			blk, err := btc.getBtcBlock(hash)
  1260  			if err != nil {
  1261  				t.Fatalf("error retrieving block after reorg: %v\n", err)
  1262  			}
  1263  			if blk.orphaned != orphanState {
  1264  				return false
  1265  			}
  1266  		}
  1267  		return true
  1268  	}
  1269  
  1270  	// The test will start with chain A at length lenA above the ancestor. A reorg
  1271  	// of length lenB will fully replace chain A. Chain A should be fully
  1272  	// orphaned and chain B should be fully mainchain afterwards.
  1273  	test := func(lenA, lenB int) {
  1274  		reset()
  1275  		setChain(chainA[:lenA])
  1276  		// Check that chain A is all mainchain.
  1277  		if !checkOrphanState(chainA[:lenA], false) {
  1278  			t.Fatalf("chain A block not mainchain for test %d:%d before reorg", lenA, lenB)
  1279  		}
  1280  		// Reorg the chain.
  1281  		setSidechainConfs(chainA[:lenA])
  1282  		setChain(chainB[:lenB])
  1283  		// Chain A should all be orphaned.
  1284  		if !checkOrphanState(chainA[:lenA], true) {
  1285  			t.Fatalf("chain A block still mainchain for test %d:%d after reorg", lenA, lenB)
  1286  		}
  1287  		// Chain B should all be mainchain.
  1288  		if !checkOrphanState(chainB[:lenB], false) {
  1289  			t.Fatalf("chain B block not mainchain for test %d:%d after reorg", lenA, lenB)
  1290  		}
  1291  	}
  1292  
  1293  	// Now run 9 tests.
  1294  	for a := 1; a <= 3; a++ {
  1295  		for b := 1; b <= 3; b++ {
  1296  			test(a, b)
  1297  		}
  1298  	}
  1299  
  1300  	// Create a transaction at the tip, then orphan the block and move the
  1301  	// transaction to mempool.
  1302  	reset()
  1303  	setChain(chainA)
  1304  	tipHeight := btc.blockCache.tipHeight()
  1305  	txHash := randomHash()
  1306  	tip, found := btc.blockCache.atHeight(tipHeight)
  1307  	if !found {
  1308  		t.Fatalf("did not find newly connected block at height %d, likely cache sync issue", tipHeight)
  1309  	}
  1310  	msg := testMakeMsgTx(false)
  1311  	testAddBlockVerbose(&tip.hash, nil, 1, tipHeight)
  1312  	testAddTxOut(msg.tx, 0, txHash, &tip.hash, 1)
  1313  	utxo, err := btc.utxo(txHash, msg.vout, nil)
  1314  	if err != nil {
  1315  		t.Fatalf("utxo error 1: %v", err)
  1316  	}
  1317  	confs, err := utxo.Confirmations(context.Background())
  1318  	if err != nil {
  1319  		t.Fatalf("Confirmations error: %v", err)
  1320  	}
  1321  	if confs != 1 {
  1322  		t.Fatalf("wrong number of confirmations. expected 1, got %d", confs)
  1323  	}
  1324  
  1325  	// Orphan the block and move the transaction to mempool.
  1326  	btc.blockCache.reorg(int64(ancestorHeight))
  1327  	testAddTxOut(msg.tx, 0, txHash, nil, 0)
  1328  	confs, err = utxo.Confirmations(context.Background())
  1329  	if err != nil {
  1330  		t.Fatalf("Confirmations error after reorg: %v", err)
  1331  	}
  1332  	if confs != 0 {
  1333  		t.Fatalf("Expected zero confirmations after reorg, found %d", confs)
  1334  	}
  1335  
  1336  	// Start over, but put it in a lower block instead.
  1337  	reset()
  1338  	setChain(chainA)
  1339  	tip, found = btc.blockCache.atHeight(tipHeight)
  1340  	if !found {
  1341  		t.Fatalf("did not find newly connected block at height %d, likely cache sync issue", tipHeight)
  1342  	}
  1343  	testAddBlockVerbose(&tip.hash, nil, 1, tipHeight)
  1344  	testAddTxOut(msg.tx, 0, txHash, &tip.hash, 1)
  1345  	utxo, err = btc.utxo(txHash, msg.vout, nil)
  1346  	if err != nil {
  1347  		t.Fatalf("utxo error 2: %v", err)
  1348  	}
  1349  
  1350  	// Reorg and add a single block with the transaction.
  1351  	btc.blockCache.reorg(int64(ancestorHeight))
  1352  	newBlockHash := randomHash()
  1353  	testAddTxOut(msg.tx, 0, txHash, newBlockHash, 1)
  1354  	testAddBlockVerbose(newBlockHash, ancestorHash, 1, ancestorHeight+1)
  1355  	time.Sleep(blockPollDelay)
  1356  	confs, err = utxo.Confirmations(context.Background())
  1357  	if err != nil {
  1358  		t.Fatalf("Confirmations error after reorg to lower block: %v", err)
  1359  	}
  1360  	if confs != 1 {
  1361  		t.Fatalf("Expected zero confirmations after reorg to lower block, found %d", confs)
  1362  	}
  1363  }
  1364  
  1365  // TestAuxiliary checks the UTXO convenience functions like TxHash, Vout, and
  1366  // TxID.
  1367  func TestAuxiliary(t *testing.T) {
  1368  	// Create a Backend with the test node.
  1369  	btc, shutdown := testBackend(false)
  1370  	defer shutdown()
  1371  
  1372  	// Add a transaction and retrieve it.
  1373  	cleanTestChain()
  1374  	maturity := int64(testParams.CoinbaseMaturity)
  1375  	msg := testMakeMsgTx(false)
  1376  	valueSats := int64(29e6)
  1377  	msg.tx.TxOut[0].Value = valueSats
  1378  	txid := hex.EncodeToString(randomBytes(32))
  1379  	txHash, _ := chainhash.NewHashFromStr(txid)
  1380  	txHeight := rand.Uint32()
  1381  	blockHash := testAddBlockVerbose(nil, nil, 1, txHeight)
  1382  	testAddTxOut(msg.tx, msg.vout, txHash, blockHash, maturity)
  1383  	coinID := toCoinID(txHash, msg.vout)
  1384  
  1385  	verboseTx := testChain.txRaws[*txHash]
  1386  	vout := btcjson.Vout{
  1387  		Value: 0.29,
  1388  		N:     0,
  1389  		//ScriptPubKey
  1390  	}
  1391  	verboseTx.Vout = append(verboseTx.Vout, vout)
  1392  
  1393  	utxo, err := btc.FundingCoin(context.Background(), coinID, nil)
  1394  	if err != nil {
  1395  		t.Fatalf("unexpected error: %v", err)
  1396  	}
  1397  	if utxo.Coin().TxID() != txid {
  1398  		t.Fatalf("utxo txid doesn't match")
  1399  	}
  1400  
  1401  	if utxo.(*UTXO).value != uint64(msg.tx.TxOut[0].Value) {
  1402  		t.Errorf("incorrect value. got %d, wanted %d", utxo.(*UTXO).value, msg.tx.TxOut[0].Value)
  1403  	}
  1404  
  1405  	voutVal, err := btc.prevOutputValue(txid, 0)
  1406  	if err != nil {
  1407  		t.Fatalf("prevOutputValue: %v", err)
  1408  	}
  1409  	if voutVal != uint64(msg.tx.TxOut[0].Value) {
  1410  		t.Errorf("incorrect value. got %d, wanted %d", utxo.(*UTXO).value, msg.tx.TxOut[0].Value)
  1411  	}
  1412  }
  1413  
  1414  // TestCheckSwapAddress checks that addresses are parsing or not parsing as
  1415  // expected.
  1416  func TestCheckSwapAddress(t *testing.T) {
  1417  	btc, shutdown := testBackend(false) // non-segwit
  1418  	defer shutdown()
  1419  
  1420  	type test struct {
  1421  		addr    string
  1422  		wantErr bool
  1423  	}
  1424  	tests := []test{
  1425  		{"", true}, // "unknown format"
  1426  		{"18Zpft83eov56iESWuPpV8XFLJ1b8gMZy7", false},                                // p2pkh (ok)
  1427  		{"3GD2fSQxhkXDAW66i6JBwCqhLFSvhMNrtJ", true},                                 // p2sh
  1428  		{"03aab68960ac1cc2a4151e40c530fcf32284afaed0cebbaec98500c8f3c491d50b", true}, // pubkey (not really address)
  1429  		{"bc1qq3wc0u7x0nezw3hfjkh45ffk09gm4ghl0k7dwe", true},                         // p2wpkh (segwit)
  1430  		{"bc1qdn28r3yr790mjzadkd79sgdkm92jdfq6j5zxsz6w0j9hvwsmr4ys7yn244", true},     // p2wsh
  1431  		{"28Zpft83eov56iESWuPpV8XFLJ1b8gMZy7", true},                                 // wrong network (checksum mismatch)
  1432  		{"3GD2fSQxhkXDAW66i6JBwCqhLFSvhMNrtO", true},                                 // capital letter O not base 58 (unknown format)
  1433  		{"3GD2fSQx", true}, // checksum mismatch
  1434  	}
  1435  	for _, test := range tests {
  1436  		if btc.CheckSwapAddress(test.addr) != !test.wantErr {
  1437  			t.Fatalf("wantErr = %t, address = %s", test.wantErr, test.addr)
  1438  		}
  1439  	}
  1440  
  1441  	btcSegwit, shutdown := testBackend(true) // segwit
  1442  	defer shutdown()
  1443  
  1444  	tests = []test{
  1445  		{"18Zpft83eov56iESWuPpV8XFLJ1b8gMZy7", true},                                 // p2pkh (non-segwit)
  1446  		{"3GD2fSQxhkXDAW66i6JBwCqhLFSvhMNrtJ", true},                                 // p2sh
  1447  		{"03aab68960ac1cc2a4151e40c530fcf32284afaed0cebbaec98500c8f3c491d50b", true}, // pubkey (not really address)
  1448  		{"bc1qq3wc0u7x0nezw3hfjkh45ffk09gm4ghl0k7dwe", false},                        // p2wpkh (ok)
  1449  		{"bc1qdn28r3yr790mjzadkd79sgdkm92jdfq6j5zxsz6w0j9hvwsmr4ys7yn244", true},     // p2wsh
  1450  		{"28Zpft83eov56iESWuPpV8XFLJ1b8gMZy7", true},                                 // wrong network (checksum mismatch)
  1451  		{"3GD2fSQxhkXDAW66i6JBwCqhLFSvhMNrtO", true},                                 // capital letter O not base 58 (unknown format)
  1452  		{"3GD2fSQx", true}, // checksum mismatch
  1453  	}
  1454  	for _, test := range tests {
  1455  		if btcSegwit.CheckSwapAddress(test.addr) != !test.wantErr {
  1456  			t.Fatalf("wantErr = %t, address = %s", test.wantErr, test.addr)
  1457  		}
  1458  	}
  1459  }
  1460  
  1461  func TestDriver_DecodeCoinID(t *testing.T) {
  1462  	tests := []struct {
  1463  		name    string
  1464  		coinID  []byte
  1465  		want    string
  1466  		wantErr bool
  1467  	}{
  1468  		{
  1469  			"ok",
  1470  			[]byte{
  1471  				0x16, 0x8f, 0x34, 0x3a, 0xdf, 0x17, 0xe0, 0xc3,
  1472  				0xa2, 0xe8, 0x88, 0x79, 0x8, 0x87, 0x17, 0xb8,
  1473  				0xac, 0x93, 0x47, 0xb9, 0x66, 0xd, 0xa7, 0x4b,
  1474  				0xde, 0x3e, 0x1d, 0x1f, 0x47, 0x94, 0x9f, 0xdf, // 32 byte hash
  1475  				0x0, 0x0, 0x0, 0x1, // 4 byte vout
  1476  			},
  1477  			"df9f94471f1d3ede4ba70d66b94793acb81787087988e8a2c3e017df3a348f16:1",
  1478  			false,
  1479  		},
  1480  		{
  1481  			"bad",
  1482  			[]byte{
  1483  				0x16, 0x8f, 0x34, 0x3a, 0xdf, 0x17, 0xe0, 0xc3,
  1484  				0xa2, 0xe8, 0x88, 0x79, 0x8, 0x87, 0x17, 0xb8,
  1485  				0xac, 0x93, 0x47, 0xb9, 0x66, 0xd, 0xa7, 0x4b,
  1486  				0xde, 0x3e, 0x1d, 0x1f, 0x47, 0x94, 0x9f, // 31 bytes
  1487  				0x0, 0x0, 0x0, 0x1,
  1488  			},
  1489  			"",
  1490  			true,
  1491  		},
  1492  	}
  1493  	for _, tt := range tests {
  1494  		t.Run(tt.name, func(t *testing.T) {
  1495  			d := &Driver{}
  1496  			got, err := d.DecodeCoinID(tt.coinID)
  1497  			if (err != nil) != tt.wantErr {
  1498  				t.Errorf("Driver.DecodeCoinID() error = %v, wantErr %v", err, tt.wantErr)
  1499  				return
  1500  			}
  1501  			if got != tt.want {
  1502  				t.Errorf("Driver.DecodeCoinID() = %v, want %v", got, tt.want)
  1503  			}
  1504  		})
  1505  	}
  1506  }
  1507  
  1508  func TestSynced(t *testing.T) {
  1509  	btc, shutdown := testBackend(true)
  1510  	defer shutdown()
  1511  	tNode := btc.node.requester.(*testNode)
  1512  	tNode.rawResult, _ = json.Marshal(&btcjson.GetBlockChainInfoResult{
  1513  		Headers: 100,
  1514  		Blocks:  99,
  1515  	})
  1516  	synced, err := btc.Synced()
  1517  	if err != nil {
  1518  		t.Fatalf("Synced error: %v", err)
  1519  	}
  1520  	if !synced {
  1521  		t.Fatalf("not synced when should be synced")
  1522  	}
  1523  
  1524  	tNode.rawResult, _ = json.Marshal(&btcjson.GetBlockChainInfoResult{
  1525  		Headers: 100,
  1526  		Blocks:  50,
  1527  	})
  1528  	synced, err = btc.Synced()
  1529  	if err != nil {
  1530  		t.Fatalf("Synced error: %v", err)
  1531  	}
  1532  	if synced {
  1533  		t.Fatalf("synced when shouldn't be synced")
  1534  	}
  1535  
  1536  	tNode.rawErr = fmt.Errorf("test error")
  1537  	_, err = btc.Synced()
  1538  	if err == nil {
  1539  		t.Fatalf("getblockchaininfo error not propagated")
  1540  	}
  1541  	tNode.rawErr = nil
  1542  }