mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-29 03:01:52 +01:00
lntemp+itest: create interface WebFeeService
This commit adds a new interface, `WebFeeService`, so external projects can create their own mocked fee services.
This commit is contained in:
parent
9d79e76876
commit
353b744039
@ -11,46 +11,68 @@ import (
|
||||
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// WebFeeService defines an interface that's used to provide fee estimation
|
||||
// service used in the integration tests. It must provide an URL so that a lnd
|
||||
// node can be started with the flag `--feeurl` and uses the customized fee
|
||||
// estimator.
|
||||
type WebFeeService interface {
|
||||
// Start starts the service.
|
||||
Start() error
|
||||
|
||||
// Stop stops the service.
|
||||
Stop() error
|
||||
|
||||
// URL returns the service's endpoint.
|
||||
URL() string
|
||||
|
||||
// SetFeeRate sets the estimated fee rate for a given confirmation
|
||||
// target.
|
||||
SetFeeRate(feeRate chainfee.SatPerKWeight, conf uint32)
|
||||
}
|
||||
|
||||
const (
|
||||
// feeServiceTarget is the confirmation target for which a fee estimate
|
||||
// is returned. Requests for higher confirmation targets will fall back
|
||||
// to this.
|
||||
feeServiceTarget = 1
|
||||
|
||||
// DefaultFeeRateSatPerKw specifies the default fee rate used in the
|
||||
// tests.
|
||||
DefaultFeeRateSatPerKw = 12500
|
||||
)
|
||||
|
||||
// feeService runs a web service that provides fee estimation information.
|
||||
type feeService struct {
|
||||
feeEstimates
|
||||
// FeeService runs a web service that provides fee estimation information.
|
||||
type FeeService struct {
|
||||
*testing.T
|
||||
|
||||
t *testing.T
|
||||
|
||||
srv *http.Server
|
||||
wg sync.WaitGroup
|
||||
|
||||
url string
|
||||
feeRateMap map[uint32]uint32
|
||||
url string
|
||||
|
||||
srv *http.Server
|
||||
wg sync.WaitGroup
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// feeEstimates contains the current fee estimates.
|
||||
type feeEstimates struct {
|
||||
Fees map[uint32]uint32 `json:"fee_by_block_target"`
|
||||
}
|
||||
// Compile-time check for the WebFeeService interface.
|
||||
var _ WebFeeService = (*FeeService)(nil)
|
||||
|
||||
// startFeeService spins up a go-routine to serve fee estimates.
|
||||
func startFeeService(t *testing.T) *feeService {
|
||||
// Start spins up a go-routine to serve fee estimates.
|
||||
func NewFeeService(t *testing.T) *FeeService {
|
||||
port := lntest.NextAvailablePort()
|
||||
f := feeService{
|
||||
t: t,
|
||||
f := FeeService{
|
||||
T: t,
|
||||
url: fmt.Sprintf(
|
||||
"http://localhost:%v/fee-estimates.json", port,
|
||||
),
|
||||
}
|
||||
|
||||
// Initialize default fee estimate.
|
||||
f.Fees = map[uint32]uint32{feeServiceTarget: 50000}
|
||||
f.feeRateMap = map[uint32]uint32{
|
||||
feeServiceTarget: DefaultFeeRateSatPerKw,
|
||||
}
|
||||
|
||||
listenAddr := fmt.Sprintf(":%v", port)
|
||||
mux := http.NewServeMux()
|
||||
@ -60,50 +82,59 @@ func startFeeService(t *testing.T) *feeService {
|
||||
Addr: listenAddr,
|
||||
Handler: mux,
|
||||
}
|
||||
return &f
|
||||
}
|
||||
|
||||
// Start starts the web server.
|
||||
func (f *FeeService) Start() error {
|
||||
f.wg.Add(1)
|
||||
go func() {
|
||||
defer f.wg.Done()
|
||||
|
||||
if err := f.srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
f.t.Errorf("error: cannot start fee api: %v", err)
|
||||
require.NoErrorf(f, err, "cannot start fee api")
|
||||
}
|
||||
}()
|
||||
|
||||
return &f
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleRequest handles a client request for fee estimates.
|
||||
func (f *feeService) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
func (f *FeeService) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
bytes, err := json.Marshal(f.feeEstimates)
|
||||
if err != nil {
|
||||
f.t.Errorf("error: cannot serialize estimates: %v", err)
|
||||
|
||||
return
|
||||
}
|
||||
bytes, err := json.Marshal(
|
||||
struct {
|
||||
Fees map[uint32]uint32 `json:"fee_by_block_target"`
|
||||
}{
|
||||
Fees: f.feeRateMap,
|
||||
},
|
||||
)
|
||||
require.NoErrorf(f, err, "cannot serialize estimates")
|
||||
|
||||
_, err = io.WriteString(w, string(bytes))
|
||||
if err != nil {
|
||||
f.t.Errorf("error: cannot send estimates: %v", err)
|
||||
}
|
||||
require.NoError(f, err, "cannot send estimates")
|
||||
}
|
||||
|
||||
// stop stops the web server.
|
||||
func (f *feeService) stop() {
|
||||
if err := f.srv.Shutdown(context.Background()); err != nil {
|
||||
f.t.Errorf("error: cannot stop fee api: %v", err)
|
||||
}
|
||||
// Stop stops the web server.
|
||||
func (f *FeeService) Stop() error {
|
||||
err := f.srv.Shutdown(context.Background())
|
||||
require.NoError(f, err, "cannot stop fee api")
|
||||
|
||||
f.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// setFee changes the current fee estimate for the fixed confirmation target.
|
||||
func (f *feeService) setFee(fee chainfee.SatPerKWeight) {
|
||||
// SetFeeRate sets a fee for the given confirmation target.
|
||||
func (f *FeeService) SetFeeRate(fee chainfee.SatPerKWeight, conf uint32) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
f.Fees[feeServiceTarget] = uint32(fee.FeePerKVByte())
|
||||
f.feeRateMap[conf] = uint32(fee.FeePerKVByte())
|
||||
}
|
||||
|
||||
// URL returns the service endpoint.
|
||||
func (f *FeeService) URL() string {
|
||||
return f.url
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ type HarnessTest struct {
|
||||
|
||||
// feeService is a web service that provides external fee estimates to
|
||||
// lnd.
|
||||
feeService *feeService
|
||||
feeService WebFeeService
|
||||
|
||||
// Channel for transmitting stderr output from failed lightning node
|
||||
// to main process.
|
||||
@ -79,7 +79,7 @@ type HarnessTest struct {
|
||||
|
||||
// NewHarnessTest creates a new instance of a harnessTest from a regular
|
||||
// testing.T instance.
|
||||
func NewHarnessTest(t *testing.T, lndBinary string,
|
||||
func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
|
||||
dbBackend lntest.DatabaseBackend) *HarnessTest {
|
||||
|
||||
// Create the run context.
|
||||
@ -87,10 +87,11 @@ func NewHarnessTest(t *testing.T, lndBinary string,
|
||||
|
||||
manager := newNodeManager(lndBinary, dbBackend)
|
||||
return &HarnessTest{
|
||||
T: t,
|
||||
manager: manager,
|
||||
runCtx: ctxt,
|
||||
cancel: cancel,
|
||||
T: t,
|
||||
manager: manager,
|
||||
feeService: feeService,
|
||||
runCtx: ctxt,
|
||||
cancel: cancel,
|
||||
// We need to use buffered channel here as we don't want to
|
||||
// block sending errors.
|
||||
lndErrorChan: make(chan error, 10),
|
||||
@ -118,11 +119,12 @@ func (h *HarnessTest) Start(chain node.BackendConfig, miner *HarnessMiner) {
|
||||
}()
|
||||
|
||||
// Start the fee service.
|
||||
h.feeService = startFeeService(h.T)
|
||||
err := h.feeService.Start()
|
||||
require.NoError(h, err, "failed to start fee service")
|
||||
|
||||
// Assemble the node manager with chainBackend and feeServiceURL.
|
||||
h.manager.chainBackend = chain
|
||||
h.manager.feeServiceURL = h.feeService.url
|
||||
h.manager.feeServiceURL = h.feeService.URL()
|
||||
|
||||
// Assemble the miner.
|
||||
h.Miner = miner
|
||||
@ -229,7 +231,8 @@ func (h *HarnessTest) Stop() {
|
||||
close(h.lndErrorChan)
|
||||
|
||||
// Stop the fee service.
|
||||
h.feeService.stop()
|
||||
err := h.feeService.Stop()
|
||||
require.NoError(h, err, "failed to stop fee service")
|
||||
|
||||
// Stop the chainBackend.
|
||||
h.stopChainBackend()
|
||||
@ -436,8 +439,13 @@ func (h *HarnessTest) RestartNodeWithExtraArgs(hn *node.HarnessNode,
|
||||
}
|
||||
|
||||
// SetFeeEstimate sets a fee rate to be returned from fee estimator.
|
||||
//
|
||||
// NOTE: this method will set the fee rate for a conf target of 1, which is the
|
||||
// fallback fee rate for a `WebAPIEstimator` if a higher conf target's fee rate
|
||||
// is not set. This means if the fee rate for conf target 6 is set, the fee
|
||||
// estimator will use that value instead.
|
||||
func (h *HarnessTest) SetFeeEstimate(fee chainfee.SatPerKWeight) {
|
||||
h.feeService.setFee(fee)
|
||||
h.feeService.SetFeeRate(fee, 1)
|
||||
}
|
||||
|
||||
// validateNodeState checks that the node doesn't have any uncleaned states
|
||||
|
@ -17,7 +17,9 @@ import (
|
||||
// 3. start a chain backend(btcd, bitcoind, or neutrino).
|
||||
// 4. connect the miner and the chain backend.
|
||||
// 5. start the HarnessTest.
|
||||
func SetupHarness(t *testing.T, binaryPath, dbBackendName string) *HarnessTest {
|
||||
func SetupHarness(t *testing.T, binaryPath, dbBackendName string,
|
||||
feeService WebFeeService) *HarnessTest {
|
||||
|
||||
t.Log("Setting up HarnessTest...")
|
||||
|
||||
// Parse testing flags that influence our test execution.
|
||||
@ -28,7 +30,7 @@ func SetupHarness(t *testing.T, binaryPath, dbBackendName string) *HarnessTest {
|
||||
dbBackend := prepareDbBackend(t, dbBackendName)
|
||||
|
||||
// Create a new HarnessTest.
|
||||
ht := NewHarnessTest(t, binaryPath, dbBackend)
|
||||
ht := NewHarnessTest(t, binaryPath, feeService, dbBackend)
|
||||
|
||||
// Init the miner.
|
||||
t.Log("Prepare the miner and mine blocks to activate segwit...")
|
||||
|
@ -68,9 +68,14 @@ func TestLightningNetworkDaemonTemp(t *testing.T) {
|
||||
testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
|
||||
lntest.ApplyPortOffset(uint32(trancheIndex) * 1000)
|
||||
|
||||
// Create a simple fee service.
|
||||
feeService := lntemp.NewFeeService(t)
|
||||
|
||||
// Get the binary path and setup the harness test.
|
||||
binary := getLndBinary(t)
|
||||
harnessTest := lntemp.SetupHarness(t, binary, *dbBackendFlag)
|
||||
harnessTest := lntemp.SetupHarness(
|
||||
t, binary, *dbBackendFlag, feeService,
|
||||
)
|
||||
defer harnessTest.Stop()
|
||||
|
||||
// Setup standby nodes, Alice and Bob, which will be alive and shared
|
||||
@ -105,9 +110,6 @@ func TestLightningNetworkDaemonTemp(t *testing.T) {
|
||||
ht.Alice.AddToLogf(logLine)
|
||||
ht.Bob.AddToLogf(logLine)
|
||||
|
||||
// Start every test with the default static fee
|
||||
// estimate.
|
||||
ht.SetFeeEstimate(12500)
|
||||
ht.EnsureConnected(ht.Alice, ht.Bob)
|
||||
|
||||
ht.RunTestCase(testCase)
|
||||
|
Loading…
x
Reference in New Issue
Block a user