Skip to content

Commit

Permalink
Merge pull request lightninglabs#289 from lightninglabs/self-chan-bal…
Browse files Browse the repository at this point in the history
…ance

sidecar channels 1/3: Allow self channel balance on bid orders
  • Loading branch information
Roasbeef authored Mar 22, 2021
2 parents 90e5c29 + 7f49066 commit aa2d01d
Show file tree
Hide file tree
Showing 22 changed files with 1,402 additions and 1,088 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ profile.tmp
/auctioncli
/itest/lnd-itest
/itest/btcd-itest
/itest/regtest/*.log
/itest/regtest/*
/itest/.backendlogs/*
/itest/.minerlogs/*
6 changes: 5 additions & 1 deletion admin_rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ func (s *adminRPCServer) ListOrders(ctx context.Context,
State: auctioneerrpc.OrderState(
o.Details().State,
),
UserAgent: o.UserAgent,
UserAgent: o.UserAgent,
SelfChanBalance: uint64(o.SelfChanBalance),
})
}
}
Expand Down Expand Up @@ -587,6 +588,9 @@ func (s *adminRPCServer) BatchSnapshot(ctx context.Context,
),
LeaseDurationBlocks: bid.LeaseDuration(),
Version: uint32(bid.Version),
SelfChanBalance: uint64(
bid.SelfChanBalance,
),
},
MatchingRate: uint32(quote.MatchingRate),
TotalSatsCleared: uint64(quote.TotalSatsCleared),
Expand Down
849 changes: 431 additions & 418 deletions adminrpc/admin.pb.go

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion adminrpc/admin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ message ServerBid {
poolrpc.OrderState state = 4;

/*
The minium node tier this order should be matched with. Only asks backed by
The minimum node tier this order should be matched with. Only asks backed by
a node this tier or higher will be eligible for matching with this bid.
*/
poolrpc.NodeTier min_node_tier = 5;
Expand All @@ -190,6 +190,11 @@ message ServerBid {
The user agent string this order was submitted with.
*/
string user_agent = 6;

/*
The initial self balance that was chosen by the user for this bid.
*/
uint64 self_chan_balance = 7;
}

message AccountDetailsRequest {
Expand Down
860 changes: 439 additions & 421 deletions auctioneerrpc/auctioneer.pb.go

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion auctioneerrpc/auctioneer.proto
Original file line number Diff line number Diff line change
Expand Up @@ -889,10 +889,20 @@ message ServerBid {
uint32 version = 4;

/*
The minium node tier this order should be matched with. Only asks backed by
The minimum node tier this order should be matched with. Only asks backed by
a node this tier or higher will be eligible for matching with this bid.
*/
NodeTier min_node_tier = 5;

/*
Give the incoming channel that results from this bid being matched an
initial outbound balance by adding additional funds from the taker's account
into the channel. As a simplification for the execution protocol and the
channel reserve calculations, the self_chan_balance can be at most the same
as the order amount and the min_chan_amt must be set to the full order
amount.
*/
uint64 self_chan_balance = 6;
}

message ServerAsk {
Expand Down
7 changes: 6 additions & 1 deletion auctioneerrpc/auctioneer.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,12 @@
},
"min_node_tier": {
"$ref": "#/definitions/poolrpcNodeTier",
"description": "The minium node tier this order should be matched with. Only asks backed by\na node this tier or higher will be eligible for matching with this bid."
"description": "The minimum node tier this order should be matched with. Only asks backed by\na node this tier or higher will be eligible for matching with this bid."
},
"self_chan_balance": {
"type": "string",
"format": "uint64",
"description": "Give the incoming channel that results from this bid being matched an\ninitial outbound balance by adding additional funds from the taker's account\ninto the channel. As a simplification for the execution protocol and the\nchannel reserve calculations, the self_chan_balance can be at most the same\nas the order amount and the min_chan_amt must be set to the full order\namount."
}
}
},
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ require (
github.com/grpc-ecosystem/grpc-gateway v1.14.6
github.com/jessevdk/go-flags v1.4.0
github.com/lightninglabs/aperture v0.1.5-beta
github.com/lightninglabs/lndclient v0.11.0-5
github.com/lightninglabs/pool v0.4.3-alpha.0.20210205091118-d27fd7a40d23
github.com/lightninglabs/lndclient v0.12.0-3
github.com/lightninglabs/pool v0.4.4-alpha.0.20210316143314-9fb2862fede4
github.com/lightninglabs/pool/auctioneerrpc v1.0.1
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
github.com/lightningnetwork/lnd v0.12.0-beta.rc5
github.com/lightningnetwork/lnd v0.12.0-beta
github.com/lightningnetwork/lnd/cert v1.0.3
github.com/lightningnetwork/lnd/ticker v1.0.0
github.com/prometheus/client_golang v1.5.1
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -272,25 +272,25 @@ github.com/lightninglabs/aperture v0.1.5-beta/go.mod h1:9xl4mx778ZAzrB87nLHMqk+X
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
github.com/lightninglabs/lndclient v0.11.0-4/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI=
github.com/lightninglabs/lndclient v0.11.0-5 h1:nHDit/3siG8wvzbQPiyGVpu9v5llqThJK1KmG/IZTIw=
github.com/lightninglabs/lndclient v0.11.0-5/go.mod h1:nIQ+lDm7JGRmP7OSeVfhOAyoqD4GA4NYU8GTsTXITbE=
github.com/lightninglabs/lndclient v0.12.0-3 h1:8UaZDS0V2WB7n20GHtNYgCe3QmFOuGdkTR57DIlQPvU=
github.com/lightninglabs/lndclient v0.12.0-3/go.mod h1:p1F007BFuiUrbM8rR1leL1yhyJJOQNkrPxybMHktQoI=
github.com/lightninglabs/neutrino v0.11.0 h1:lPpYFCtsfJX2W5zI4pWycPmbbBdr7zU+BafYdLoD6k0=
github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg=
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 h1:j4iZ1XlUAPQmW6oSzMcJGILYsRHNs+4O3Gk+2Ms5Dww=
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0=
github.com/lightninglabs/neutrino v0.11.1-0.20201210023533-e1978372d15e h1:K5LCCnSAk3NVT/aCy8wNPv0I5JfyLgijg1VX8Gz306E=
github.com/lightninglabs/neutrino v0.11.1-0.20201210023533-e1978372d15e/go.mod h1:KDWfQDKp+CFBxO1t2NRmWuagTY2sYIjpHB1k5vrojTI=
github.com/lightninglabs/pool v0.4.3-alpha.0.20210205091118-d27fd7a40d23 h1:OkE75xl1ZT9sMyUXyhfjpDkxxlui/91IMl+brqqK+ww=
github.com/lightninglabs/pool v0.4.3-alpha.0.20210205091118-d27fd7a40d23/go.mod h1:03AAPYbRyuzqOLnj/AvDzSiueX67n+R14tYWDGIEXik=
github.com/lightninglabs/pool v0.4.4-alpha.0.20210316143314-9fb2862fede4 h1:2QKwlN2pletWFBsDp2dAjs1nncnfa1YUZXJ5jQEPL1M=
github.com/lightninglabs/pool v0.4.4-alpha.0.20210316143314-9fb2862fede4/go.mod h1:KeTN3RQ8Yw5ZUaxkcOqzfeybsb4ev4zhtfnUrNrS2Ok=
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display h1:RZJ8H4ueU/aQ9pFtx5wqsuD3B/DezrewJeVwDKKYY8E=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOBU042GKFHrdbgGiKax4xVrFiZu51lhacUZQ9MnE=
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea h1:oCj48NQ8u7Vz+MmzHqt0db6mxcFZo3Ho7M5gCJauY/k=
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
github.com/lightningnetwork/lnd v0.11.0-beta/go.mod h1:CzArvT7NFDLhVyW06+NJWSuWFmE6Ea+AjjA3txUBqTM=
github.com/lightningnetwork/lnd v0.11.1-beta/go.mod h1:PGIgxy8aH70Li33YVYkHSaCM8m8LjEevk5h1Dpldrr4=
github.com/lightningnetwork/lnd v0.12.0-beta.rc5 h1:fUBal/d82ApcWTkI8JgERZ+jxeu0h4XwLRrEwOFPMqY=
github.com/lightningnetwork/lnd v0.12.0-beta.rc5/go.mod h1:2GyP1IG1kXV5Af/LOCxnXfux1OP3fAGr8zptS5PB2YI=
github.com/lightningnetwork/lnd v0.12.0-beta h1:m4Whrt0dvlnVD6OQT8kDd2utulnoZEcrq8BJlEPSiiY=
github.com/lightningnetwork/lnd v0.12.0-beta/go.mod h1:2GyP1IG1kXV5Af/LOCxnXfux1OP3fAGr8zptS5PB2YI=
github.com/lightningnetwork/lnd/cert v1.0.2 h1:g2rEu+sM2Uyz0bpfuvwri/ks6R/26H5iY1NcGbpDJ+c=
github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo=
github.com/lightningnetwork/lnd/cert v1.0.3 h1:/K2gjzLgVI8we2IIPKc0ztWTEa85uds5sWXi1K6mOT0=
Expand Down
190 changes: 190 additions & 0 deletions itest/self_chan_balance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package itest

import (
"context"
"fmt"

"github.com/btcsuite/btcutil"
orderT "github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/poolrpc"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/stretchr/testify/require"
)

// testSelfChanBalance tests that opening a channel with a self channel balance
// through a bid order is possible.
func testSelfChanBalance(t *harnessTest) {
ctx := context.Background()

// We need a third lnd node, Charlie that is used for the second trader.
charlie, err := t.lndHarness.NewNode("charlie", nil)
require.NoError(t.t, err)
secondTrader := setupTraderHarness(
t.t, t.lndHarness.BackendCfg, charlie, t.auctioneer,
)
defer shutdownAndAssert(t, charlie, secondTrader)
err = t.lndHarness.SendCoins(ctx, 5_000_000, charlie)
require.NoError(t.t, err)

// Create an account over 2M sats that is valid for the next 1000 blocks
// for both traders. To test the message multi-plexing between token IDs
// and accounts, we add a secondary account to the second trader.
makerAccount := openAccountAndAssert(
t, t.trader, &poolrpc.InitAccountRequest{
AccountValue: defaultAccountValue,
AccountExpiry: &poolrpc.InitAccountRequest_RelativeHeight{
RelativeHeight: 1_000,
},
},
)
takerAccount := openAccountAndAssert(
t, secondTrader, &poolrpc.InitAccountRequest{
AccountValue: defaultAccountValue,
AccountExpiry: &poolrpc.InitAccountRequest_RelativeHeight{
RelativeHeight: 1_000,
},
},
)

// Now that the accounts are confirmed, submit an ask order from our
// default trader, selling 2 units (200k sats) of liquidity. This ask
// has the wrong order version and won't be matched with the self chan
// balance bid.
const orderFixedRate = 100
ask1Amt := btcutil.Amount(200_000)
_, err = submitAskOrder(
t.trader, makerAccount.TraderKey, orderFixedRate, ask1Amt,
)
require.NoError(t.t, err)

// From the secondary account of the second trader, we also create an
// order to buy some units. The order has a self channel balance set.
const selfChanBalance = 20_000
bidAmt := btcutil.Amount(100_000)
_, err = submitBidOrder(
secondTrader, takerAccount.TraderKey, orderFixedRate, bidAmt,
func(bid *poolrpc.SubmitOrderRequest_Bid) {
bid.Bid.SelfChanBalance = selfChanBalance
bid.Bid.Version = uint32(orderT.VersionSelfChanBalance)
},
)
require.NoError(t.t, err)

// Since the ask is of the wrong version, a batch should not be
// cleared, so a batch transaction should not be broadcast. Kick the
// auctioneer and wait for it to return back to the order submit state.
// No tx should be in the mempool as no market should be possible.
_, _ = executeBatch(t, 0)

// Let's add a second ask with the correct version now so it can be
// matched against the bid.
ask2Amt := btcutil.Amount(300_000)
_, err = submitAskOrder(
t.trader, makerAccount.TraderKey, orderFixedRate, ask2Amt,
func(ask *poolrpc.SubmitOrderRequest_Ask) {
ask.Ask.Version = uint32(orderT.VersionSelfChanBalance)
},
)
require.NoError(t.t, err)

// Let's kick the auctioneer again to try and create a batch.
_, batchTXIDs := executeBatch(t, 1)
firstBatchTXID := batchTXIDs[0]

// At this point, the lnd nodes backed by each trader should have a
// single pending channel, which matches the amount of the order
// executed above.
//
// In our case, Bob is the maker so he should be marked as the
// initiator of the channel.
assertPendingChannel(
t, t.trader.cfg.LndNode, bidAmt+selfChanBalance, true,
charlie.PubKey,
func(c *lnrpc.PendingChannelsResponse_PendingChannel) error {
if c.RemoteBalance != selfChanBalance {
return fmt.Errorf("unexpected remote balance "+
"%d, wanted %d", c.RemoteBalance,
selfChanBalance)
}

return nil
},
)
assertPendingChannel(
t, charlie, bidAmt+selfChanBalance, false,
t.trader.cfg.LndNode.PubKey,
func(c *lnrpc.PendingChannelsResponse_PendingChannel) error {
if c.LocalBalance != selfChanBalance {
return fmt.Errorf("unexpected local balance "+
"%d, wanted %d", c.LocalBalance,
selfChanBalance)
}

return nil
},
)

// We'll now mine a block to confirm the channel. We should find the
// channel in the listchannels output for both nodes, and the
// thaw_height should be set accordingly.
blocks := mineBlocks(t, t.lndHarness, 1, 1)

// The block above should contain the batch transaction found in the
// mempool above.
assertTxInBlock(t, blocks[0], firstBatchTXID)

// We'll now mine another 3 blocks to ensure the channel itself is
// fully confirmed and the accounts in the open state again.
_ = mineBlocks(t, t.lndHarness, 3, 0)

// Now that the channels are confirmed, they should both be active, and
// we should be able to make a payment between this new channel
// established.
assertActiveChannel(
t, t.trader.cfg.LndNode, int64(bidAmt+selfChanBalance),
*firstBatchTXID, charlie.PubKey, defaultOrderDuration,
func(c *lnrpc.Channel) error {
if c.RemoteBalance != selfChanBalance {
return fmt.Errorf("unexpected remote balance "+
"%d, wanted %d", c.RemoteBalance,
selfChanBalance)
}

return nil
},
)
assertActiveChannel(
t, charlie, int64(bidAmt+selfChanBalance), *firstBatchTXID,
t.trader.cfg.LndNode.PubKey, defaultOrderDuration,
func(c *lnrpc.Channel) error {
if c.LocalBalance != selfChanBalance {
return fmt.Errorf("unexpected local balance "+
"%d, wanted %d", c.LocalBalance,
selfChanBalance)
}

return nil
},
)

// Finally make sure the accounts were charged correctly. The base order
// fee is 1 satoshi and the rate is 1/1000.
submissionFee := 1 + (bidAmt / 1000)
premium := orderT.FixedRatePremium(orderFixedRate).LumpSumPremium(
bidAmt, defaultOrderDuration,
)
chainFees := orderT.EstimateTraderFee(1, chainfee.SatPerKWeight(12_500))
makerBalance := btcutil.Amount(defaultAccountValue) - submissionFee -
chainFees - bidAmt + premium
takerBalance := btcutil.Amount(defaultAccountValue) - submissionFee -
chainFees - selfChanBalance - premium
assertTraderAccount(
t, t.trader, makerAccount.TraderKey, makerBalance,
makerAccount.ExpirationHeight, poolrpc.AccountState_OPEN,
)
assertTraderAccount(
t, secondTrader, takerAccount.TraderKey, takerBalance,
takerAccount.ExpirationHeight, poolrpc.AccountState_OPEN,
)
}
27 changes: 24 additions & 3 deletions itest/test_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -795,8 +795,12 @@ func traderOutputScript(t *harnessTest, traderNode *lntest.HarnessNode) []byte {
return addrScript
}

type pendingChanCheck func(
channel *lnrpc.PendingChannelsResponse_PendingChannel) error

func assertPendingChannel(t *harnessTest, node *lntest.HarnessNode,
chanAmt btcutil.Amount, initiator bool, chanPeer [33]byte) {
chanAmt btcutil.Amount, initiator bool, chanPeer [33]byte,
moreChecks ...pendingChanCheck) {

req := &lnrpc.PendingChannelsRequest{}
err := wait.NoError(func() error {
Expand Down Expand Up @@ -845,6 +849,13 @@ func assertPendingChannel(t *harnessTest, node *lntest.HarnessNode,
"got %v", initiator, channel.Initiator)
}

for _, chk := range moreChecks {
if err := chk(channel); err != nil {
return fmt.Errorf("custom check failed: %v",
err)
}
}

return nil
}, defaultWaitTimeout)
if err != nil {
Expand Down Expand Up @@ -958,9 +969,12 @@ func completePaymentRequests(ctx context.Context, client lnrpc.LightningClient,
return nil
}

type activeChanCheck func(channel *lnrpc.Channel) error

func assertActiveChannel(t *harnessTest, node *lntest.HarnessNode,
chanAmt int64, fundingTXID chainhash.Hash, chanPeer [33]byte,
chanDuration uint32) *lnrpc.ChannelPoint { // nolint:unparam
chanDuration uint32,
moreChecks ...activeChanCheck) *lnrpc.ChannelPoint { // nolint:unparam

var chanPointStr string
req := &lnrpc.ListChannelsRequest{}
Expand Down Expand Up @@ -1009,6 +1023,13 @@ func assertActiveChannel(t *harnessTest, node *lntest.HarnessNode,
"got %v", chanDuration, pendingChan.ThawHeight)
}

for _, chk := range moreChecks {
if err := chk(pendingChan); err != nil {
return fmt.Errorf("custom check failed: %v",
err)
}
}

chanPointStr = pendingChan.ChannelPoint
return nil
}, defaultWaitTimeout)
Expand Down Expand Up @@ -1158,7 +1179,7 @@ func assertNoOrders(t *harnessTest, trader *traderHarness) {
func assertAskOrderState(t *harnessTest, trader *traderHarness,
unfilledUnits uint32, orderNonce orderT.Nonce) {

// TODO(roasbeef): add LookupORder method for client RPC
// TODO(roasbeef): add LookupOrder method for client RPC
err := wait.NoError(func() error {
req := &poolrpc.ListOrdersRequest{}
resp, err := trader.ListOrders(context.Background(), req)
Expand Down
4 changes: 4 additions & 0 deletions itest/test_list_on.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@ var testCases = []*testCase{
name: "batch extra inputs outputs",
test: testBatchIO,
},
{
name: "self channel balance",
test: testSelfChanBalance,
},
}
Loading

0 comments on commit aa2d01d

Please sign in to comment.