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 // }