decred.org/dcrdex@v1.0.5/client/asset/btc/livetest/regnet_test.go (about)

     1  //go:build harness
     2  
     3  package livetest
     4  
     5  import (
     6  	"context"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"os/exec"
    10  	"os/user"
    11  	"path/filepath"
    12  	"testing"
    13  	"time"
    14  
    15  	"decred.org/dcrdex/client/asset"
    16  	"decred.org/dcrdex/client/asset/btc"
    17  	"decred.org/dcrdex/dex"
    18  	"decred.org/dcrdex/dex/encode"
    19  )
    20  
    21  const (
    22  	alphaAddress  = "bcrt1qaujcvxuvp9vdcqaa6s3acyh8kxmuyqnyg4jcfl"
    23  	betaAddress   = "bcrt1qwhxklx3vms6xc0lxlunez93m9wn8qzxkkn5dy2"
    24  	gammaAddress  = "bcrt1qll362edf4levwg7yqyt7kawjklvejvj74w87py"
    25  	walletTypeSPV = "SPV"
    26  )
    27  
    28  var (
    29  	tBTC = &dex.Asset{
    30  		ID:         0,
    31  		Symbol:     "btc",
    32  		Version:    0, // match btc.version
    33  		MaxFeeRate: 10,
    34  		SwapConf:   1,
    35  	}
    36  
    37  	usr, _        = user.Current()
    38  	harnessCtlDir = filepath.Join(usr.HomeDir, "dextest", "btc", "harness-ctl")
    39  	tPW           = []byte("abc")
    40  )
    41  
    42  func TestWallet(t *testing.T) {
    43  	const lotSize = 1e6
    44  
    45  	fmt.Println("////////// RPC WALLET W/O SPLIT //////////")
    46  	Run(t, &Config{
    47  		NewWallet: btc.NewWallet,
    48  		LotSize:   lotSize,
    49  		Asset:     tBTC,
    50  	})
    51  
    52  	fmt.Println("////////// RPC WALLET WITH SPLIT //////////")
    53  	Run(t, &Config{
    54  		NewWallet: btc.NewWallet,
    55  		LotSize:   lotSize,
    56  		Asset:     tBTC,
    57  		SplitTx:   true,
    58  	})
    59  
    60  	spvDir := t.TempDir()
    61  
    62  	createWallet := func(cfg *asset.WalletConfig, name string, logger dex.Logger) error {
    63  		// var seed [32]byte
    64  		// copy(seed[:], []byte(name))
    65  		seed := encode.RandomBytes(32)
    66  
    67  		err := (&btc.Driver{}).Create(&asset.CreateWalletParams{
    68  			Type:    walletTypeSPV,
    69  			Seed:    seed[:],
    70  			Pass:    tPW, // match walletPassword in livetest.go -> Run
    71  			DataDir: cfg.DataDir,
    72  			Net:     dex.Simnet,
    73  			Logger:  logger,
    74  		})
    75  		if err != nil {
    76  			return fmt.Errorf("error creating SPV wallet: %w", err)
    77  		}
    78  
    79  		w, err := btc.NewWallet(cfg, logger, dex.Regtest)
    80  		if err != nil {
    81  			t.Fatalf("error creating backend: %v", err)
    82  		}
    83  
    84  		ctx, cancel := context.WithCancel(context.Background())
    85  		defer cancel()
    86  		cm := dex.NewConnectionMaster(w)
    87  		err = cm.Connect(ctx)
    88  		if err != nil {
    89  			t.Fatalf("error connecting backend: %v", err)
    90  		}
    91  		defer cm.Disconnect()
    92  
    93  		addr, err := w.DepositAddress()
    94  		if err != nil {
    95  			return fmt.Errorf("Address error: %w", err)
    96  		}
    97  
    98  		// TODO: Randomize the address scope passed to
    99  		// btcwallet.Wallet.{NewAddress, NewChangeAddress} between
   100  		// waddrmgr.KeyScopeBIP0084 and waddrmgr.KeyScopeBIP0044 so that we
   101  		// know we can handle non-segwit previous outpoints too.
   102  		if err := loadAddress(addr); err != nil {
   103  			return fmt.Errorf("loadAddress error: %v", err)
   104  		}
   105  
   106  		time.Sleep(time.Second * 3)
   107  
   108  		for {
   109  			ss, err := w.SyncStatus()
   110  			if err != nil {
   111  				return fmt.Errorf("SyncStatus error: %w", err)
   112  			}
   113  			if ss.Synced {
   114  				break
   115  			}
   116  			fmt.Printf("%s sync progress %.1f \n", name, ss.BlockProgress()*100)
   117  			time.Sleep(time.Second)
   118  		}
   119  
   120  		bal, _ := w.Balance()
   121  		logger.Infof("%s with address %s is synced with balance = %+v \n", name, addr, bal)
   122  
   123  		return nil
   124  	}
   125  
   126  	spvConstructor := func(cfg *asset.WalletConfig, logger dex.Logger, network dex.Network) (asset.Wallet, error) {
   127  		token := hex.EncodeToString(encode.RandomBytes(4))
   128  		cfg.Type = walletTypeSPV
   129  		cfg.DataDir = filepath.Join(spvDir, token)
   130  
   131  		name := parseName(cfg.Settings)
   132  
   133  		// regtest connects to alpha node by default if "peer" isn't set.
   134  		if name == "beta" {
   135  			cfg.Settings["peer"] = "localhost:20576" // beta node
   136  		}
   137  
   138  		err := createWallet(cfg, name, logger)
   139  		if err != nil {
   140  			return nil, fmt.Errorf("createWallet error: %v", err)
   141  		}
   142  
   143  		w, err := btc.NewWallet(cfg, logger, network)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  
   148  		return w, nil
   149  	}
   150  
   151  	fmt.Println("////////// SPV WALLET W/O SPLIT //////////")
   152  	Run(t, &Config{
   153  		NewWallet: spvConstructor,
   154  		LotSize:   lotSize,
   155  		Asset:     tBTC,
   156  		SPV:       true,
   157  	})
   158  
   159  	fmt.Println("////////// SPV WALLET WITH SPLIT //////////")
   160  	Run(t, &Config{
   161  		NewWallet: spvConstructor,
   162  		LotSize:   lotSize,
   163  		Asset:     tBTC,
   164  		SPV:       true,
   165  		SplitTx:   true,
   166  	})
   167  }
   168  
   169  func loadAddress(addr string) error {
   170  	for _, v := range []string{"10", "18", "5", "7", "1", "15", "3", "25"} {
   171  		if err := runCmd("./alpha", "sendtoaddress", addr, v); err != nil {
   172  			return err
   173  		}
   174  	}
   175  	return runCmd("./mine-alpha", "1")
   176  }
   177  
   178  func runCmdWithOutput(exe string, args ...string) (string, error) {
   179  	cmd := exec.Command(exe, args...)
   180  	cmd.Dir = harnessCtlDir
   181  	b, err := cmd.Output()
   182  	// if len(op) > 0 {
   183  	// 	fmt.Printf("output from command %q: %s \n", cmd, string(op))
   184  	// }
   185  	return string(b), err
   186  }
   187  
   188  func runCmd(exe string, args ...string) error {
   189  	_, err := runCmdWithOutput(exe, args...)
   190  	return err
   191  }
   192  
   193  func parseName(settings map[string]string) string {
   194  	name := settings["walletname"]
   195  	if name == "" {
   196  		name = filepath.Base(settings["datadir"])
   197  	}
   198  	return name
   199  }