github.com/decred/dcrlnd@v0.7.6/lntest/fee_service.go (about)

     1  package lntest
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"sync"
    10  
    11  	"github.com/decred/dcrlnd/lnwallet/chainfee"
    12  )
    13  
    14  const (
    15  	// feeServiceTarget is the confirmation target for which a fee estimate
    16  	// is returned. Requests for higher confirmation targets will fall back
    17  	// to this.
    18  	feeServiceTarget = 1
    19  )
    20  
    21  // feeService runs a web service that provides fee estimation information.
    22  type feeService struct {
    23  	feeEstimates
    24  
    25  	srv *http.Server
    26  	wg  sync.WaitGroup
    27  
    28  	url string
    29  
    30  	lock sync.Mutex
    31  }
    32  
    33  // feeEstimates contains the current fee estimates.
    34  type feeEstimates struct {
    35  	Fees map[uint32]uint32 `json:"fee_by_block_target"`
    36  }
    37  
    38  // startFeeService spins up a go-routine to serve fee estimates.
    39  func startFeeService() *feeService {
    40  	port := NextAvailablePort()
    41  	f := feeService{
    42  		url: fmt.Sprintf("http://localhost:%v/fee-estimates.json", port),
    43  	}
    44  
    45  	// Initialize default fee estimate.
    46  	f.Fees = map[uint32]uint32{feeServiceTarget: 1e4}
    47  
    48  	listenAddr := fmt.Sprintf(":%v", port)
    49  	mux := http.NewServeMux()
    50  	mux.HandleFunc("/fee-estimates.json", f.handleRequest)
    51  
    52  	f.srv = &http.Server{
    53  		Addr:    listenAddr,
    54  		Handler: mux,
    55  	}
    56  
    57  	f.wg.Add(1)
    58  	go func() {
    59  		defer f.wg.Done()
    60  
    61  		if err := f.srv.ListenAndServe(); err != http.ErrServerClosed {
    62  			fmt.Printf("error: cannot start fee api: %v", err)
    63  		}
    64  	}()
    65  
    66  	return &f
    67  }
    68  
    69  // handleRequest handles a client request for fee estimates.
    70  func (f *feeService) handleRequest(w http.ResponseWriter, r *http.Request) {
    71  	f.lock.Lock()
    72  	defer f.lock.Unlock()
    73  
    74  	bytes, err := json.Marshal(f.feeEstimates)
    75  	if err != nil {
    76  		fmt.Printf("error: cannot serialize "+
    77  			"estimates: %v", err)
    78  
    79  		return
    80  	}
    81  
    82  	_, err = io.WriteString(w, string(bytes))
    83  	if err != nil {
    84  		fmt.Printf("error: cannot send estimates: %v",
    85  			err)
    86  	}
    87  }
    88  
    89  // stop stops the web server.
    90  func (f *feeService) stop() {
    91  	if err := f.srv.Shutdown(context.Background()); err != nil {
    92  		fmt.Printf("error: cannot stop fee api: %v", err)
    93  	}
    94  
    95  	f.wg.Wait()
    96  }
    97  
    98  // setFee changes the current fee estimate for the fixed confirmation target.
    99  func (f *feeService) setFee(fee chainfee.AtomPerKByte) {
   100  	f.lock.Lock()
   101  	defer f.lock.Unlock()
   102  
   103  	f.Fees[feeServiceTarget] = uint32(fee)
   104  }
   105  
   106  // setFeeWithConf sets a fee for the given confirmation target.
   107  func (f *feeService) setFeeWithConf(fee chainfee.AtomPerKByte, conf uint32) {
   108  	f.lock.Lock()
   109  	defer f.lock.Unlock()
   110  
   111  	f.Fees[conf] = uint32(fee)
   112  }