liquidity/test: add autoloop in tests

pull/419/head
carla 2 years ago
parent 5280721636
commit 66d16f52a7
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91

@ -471,6 +471,349 @@ func TestCompositeRules(t *testing.T) {
c.stop()
}
// TestAutoLoopInEnabled tests dispatch of autoloop in swaps.
func TestAutoLoopInEnabled(t *testing.T) {
defer test.Guard(t)()
var (
chan1 = lndclient.ChannelInfo{
ChannelID: chanID1.ToUint64(),
PubKeyBytes: peer1,
Capacity: 100000,
RemoteBalance: 100000,
LocalBalance: 0,
}
chan2 = lndclient.ChannelInfo{
ChannelID: chanID2.ToUint64(),
PubKeyBytes: peer2,
Capacity: 200000,
RemoteBalance: 200000,
LocalBalance: 0,
}
channels = []lndclient.ChannelInfo{
chan1, chan2,
}
// Create a rule which will loop in, with no inbound liquidity
// reserve.
rule = &SwapRule{
ThresholdRule: NewThresholdRule(0, 60),
Type: swap.TypeIn,
}
// Under these rules, we'll have the following recommended
// swaps:
peer1ExpectedAmt btcutil.Amount = 80000
peer2ExpectedAmt btcutil.Amount = 160000
// Set our per-swap budget to 5% of swap amount.
swapFeePPM uint64 = 50000
htlcConfTarget int32 = 10
// Calculate the maximum amount we'll pay for each swap and
// set our budget to be able to accommodate both.
peer1MaxFee = ppmToSat(peer1ExpectedAmt, swapFeePPM)
peer2MaxFee = ppmToSat(peer2ExpectedAmt, swapFeePPM)
params = Parameters{
Autoloop: true,
AutoFeeBudget: peer1MaxFee + peer2MaxFee + 1,
AutoFeeStartDate: testTime,
MaxAutoInFlight: 2,
FailureBackOff: time.Hour,
FeeLimit: NewFeePortion(swapFeePPM),
ChannelRules: make(map[lnwire.ShortChannelID]*SwapRule),
PeerRules: map[route.Vertex]*SwapRule{
peer1: rule,
peer2: rule,
},
HtlcConfTarget: htlcConfTarget,
SweepConfTarget: loop.DefaultSweepConfTarget,
}
)
c := newAutoloopTestCtx(t, params, channels, testRestrictions)
c.start()
// Calculate our maximum allowed fees and create quotes that fall within
// our budget.
var (
quote1 = &loop.LoopInQuote{
SwapFee: peer1MaxFee / 4,
MinerFee: peer1MaxFee / 8,
}
quote2Unaffordable = &loop.LoopInQuote{
SwapFee: peer2MaxFee * 2,
MinerFee: peer2MaxFee * 2,
}
quoteRequest1 = &loop.LoopInQuoteRequest{
Amount: peer1ExpectedAmt,
HtlcConfTarget: htlcConfTarget,
LastHop: &peer1,
}
quoteRequest2 = &loop.LoopInQuoteRequest{
Amount: peer2ExpectedAmt,
HtlcConfTarget: htlcConfTarget,
LastHop: &peer2,
}
peer1Swap = &loop.LoopInRequest{
Amount: peer1ExpectedAmt,
MaxSwapFee: quote1.SwapFee,
MaxMinerFee: quote1.MinerFee,
HtlcConfTarget: htlcConfTarget,
LastHop: &peer1,
ExternalHtlc: false,
Label: labels.AutoloopLabel(swap.TypeIn),
Initiator: autoloopSwapInitiator,
}
)
// Tick our autolooper with no existing swaps. Both of our peers
// require swaps, but one of our peer's quotes is too expensive.
step := &autoloopStep{
minAmt: 1,
maxAmt: peer2ExpectedAmt + 1,
quotesIn: []quoteInRequestResp{
{
request: quoteRequest1,
quote: quote1,
},
{
request: quoteRequest2,
quote: quote2Unaffordable,
},
},
expectedIn: []loopInRequestResp{
{
request: peer1Swap,
response: &loop.LoopInSwapInfo{
SwapHash: lntypes.Hash{1},
},
},
},
}
c.autoloop(step)
// Now, we tick again with our first swap in progress. This time, we
// provide a quote for our second swap which is more affordable, so we
// expect it to be dispatched.
var (
quote2Affordable = &loop.LoopInQuote{
SwapFee: peer2MaxFee / 8,
MinerFee: peer2MaxFee / 2,
}
peer2Swap = &loop.LoopInRequest{
Amount: peer2ExpectedAmt,
MaxSwapFee: quote2Affordable.SwapFee,
MaxMinerFee: quote2Affordable.MinerFee,
HtlcConfTarget: htlcConfTarget,
LastHop: &peer2,
ExternalHtlc: false,
Label: labels.AutoloopLabel(swap.TypeIn),
Initiator: autoloopSwapInitiator,
}
existing = []*loopdb.LoopIn{
existingInFromRequest(peer1Swap, testTime, nil),
}
)
step = &autoloopStep{
minAmt: 1,
maxAmt: peer2ExpectedAmt + 1,
quotesIn: []quoteInRequestResp{
{
request: quoteRequest2,
quote: quote2Affordable,
},
},
existingIn: existing,
expectedIn: []loopInRequestResp{
{
request: peer2Swap,
response: &loop.LoopInSwapInfo{
SwapHash: lntypes.Hash{2},
},
},
},
}
c.autoloop(step)
c.stop()
}
// TestAutoloopBothTypes tests dispatching of a loop out and loop in swap at the
// same time.
func TestAutoloopBothTypes(t *testing.T) {
defer test.Guard(t)()
var (
chan1 = lndclient.ChannelInfo{
ChannelID: chanID1.ToUint64(),
PubKeyBytes: peer1,
Capacity: 1000000,
LocalBalance: 1000000,
}
chan2 = lndclient.ChannelInfo{
ChannelID: chanID2.ToUint64(),
PubKeyBytes: peer2,
Capacity: 200000,
RemoteBalance: 200000,
LocalBalance: 0,
}
channels = []lndclient.ChannelInfo{
chan1, chan2,
}
// Create a rule which will loop out, with no outbound liquidity
// reserve.
outRule = &SwapRule{
ThresholdRule: NewThresholdRule(40, 0),
Type: swap.TypeOut,
}
// Create a rule which will loop in, with no inbound liquidity
// reserve.
inRule = &SwapRule{
ThresholdRule: NewThresholdRule(0, 60),
Type: swap.TypeIn,
}
// Under this rule, we expect a loop in swap.
loopOutAmt btcutil.Amount = 700000
loopInAmount btcutil.Amount = 160000
// Set our per-swap budget to 5% of swap amount.
swapFeePPM uint64 = 50000
htlcConfTarget int32 = 10
// Calculate the maximum amount we'll pay for our loop in.
loopOutMaxFee = ppmToSat(loopOutAmt, swapFeePPM)
loopInMaxFee = ppmToSat(loopInAmount, swapFeePPM)
params = Parameters{
Autoloop: true,
AutoFeeBudget: loopOutMaxFee + loopInMaxFee + 1,
AutoFeeStartDate: testTime,
MaxAutoInFlight: 2,
FailureBackOff: time.Hour,
FeeLimit: NewFeePortion(swapFeePPM),
ChannelRules: map[lnwire.ShortChannelID]*SwapRule{
chanID1: outRule,
},
PeerRules: map[route.Vertex]*SwapRule{
peer2: inRule,
},
HtlcConfTarget: htlcConfTarget,
SweepConfTarget: loop.DefaultSweepConfTarget,
}
)
c := newAutoloopTestCtx(t, params, channels, testRestrictions)
c.start()
// Calculate our maximum allowed fees and create quotes that fall within
// our budget.
var (
loopOutQuote = &loop.LoopOutQuote{
SwapFee: loopOutMaxFee / 4,
PrepayAmount: loopOutMaxFee / 4,
}
loopOutQuoteReq = &loop.LoopOutQuoteRequest{
Amount: loopOutAmt,
SweepConfTarget: params.SweepConfTarget,
SwapPublicationDeadline: testTime,
}
prepayMaxFee, routeMaxFee,
minerFee = params.FeeLimit.loopOutFees(
loopOutAmt, loopOutQuote,
)
loopOutSwap = &loop.OutRequest{
Amount: loopOutAmt,
MaxSwapRoutingFee: routeMaxFee,
MaxPrepayRoutingFee: prepayMaxFee,
MaxSwapFee: loopOutQuote.SwapFee,
MaxPrepayAmount: loopOutQuote.PrepayAmount,
MaxMinerFee: minerFee,
SweepConfTarget: params.SweepConfTarget,
OutgoingChanSet: loopdb.ChannelSet{
chanID1.ToUint64(),
},
Label: labels.AutoloopLabel(swap.TypeOut),
Initiator: autoloopSwapInitiator,
}
loopinQuote = &loop.LoopInQuote{
SwapFee: loopInMaxFee / 4,
MinerFee: loopInMaxFee / 8,
}
loopInQuoteReq = &loop.LoopInQuoteRequest{
Amount: loopInAmount,
HtlcConfTarget: htlcConfTarget,
LastHop: &peer2,
}
loopInSwap = &loop.LoopInRequest{
Amount: loopInAmount,
MaxSwapFee: loopinQuote.SwapFee,
MaxMinerFee: loopinQuote.MinerFee,
HtlcConfTarget: htlcConfTarget,
LastHop: &peer2,
ExternalHtlc: false,
Label: labels.AutoloopLabel(swap.TypeIn),
Initiator: autoloopSwapInitiator,
}
)
step := &autoloopStep{
minAmt: 1,
maxAmt: loopOutAmt + 1,
quotesOut: []quoteRequestResp{
{
request: loopOutQuoteReq,
quote: loopOutQuote,
},
},
quotesIn: []quoteInRequestResp{
{
request: loopInQuoteReq,
quote: loopinQuote,
},
},
expectedOut: []loopOutRequestResp{
{
request: loopOutSwap,
response: &loop.LoopOutSwapInfo{
SwapHash: lntypes.Hash{1},
},
},
},
expectedIn: []loopInRequestResp{
{
request: loopInSwap,
response: &loop.LoopInSwapInfo{
SwapHash: lntypes.Hash{2},
},
},
},
}
c.autoloop(step)
c.stop()
}
// existingSwapFromRequest is a helper function which returns the db
// representation of a loop out request with the event set provided.
func existingSwapFromRequest(request *loop.OutRequest, initTime time.Time,
@ -496,3 +839,24 @@ func existingSwapFromRequest(request *loop.OutRequest, initTime time.Time,
},
}
}
func existingInFromRequest(in *loop.LoopInRequest, initTime time.Time,
events []*loopdb.LoopEvent) *loopdb.LoopIn {
return &loopdb.LoopIn{
Loop: loopdb.Loop{
Events: events,
},
Contract: &loopdb.LoopInContract{
SwapContract: loopdb.SwapContract{
MaxSwapFee: in.MaxSwapFee,
MaxMinerFee: in.MaxMinerFee,
InitiationTime: initTime,
Label: in.Label,
},
HtlcConfTarget: in.HtlcConfTarget,
LastHop: in.LastHop,
ExternalHtlc: in.ExternalHtlc,
},
}
}

Loading…
Cancel
Save