Merge pull request #846 from wpaulino/private-channel-routing
multi: support multi-hop payments over private channels
This commit is contained in:
commit
435e68a438
@ -1713,6 +1713,12 @@ var addInvoiceCommand = cli.Command{
|
|||||||
"specified an expiry of 3600 seconds (1 hour) " +
|
"specified an expiry of 3600 seconds (1 hour) " +
|
||||||
"is implied.",
|
"is implied.",
|
||||||
},
|
},
|
||||||
|
cli.BoolTFlag{
|
||||||
|
Name: "private",
|
||||||
|
Usage: "encode routing hints in the invoice with " +
|
||||||
|
"private channels in order to assist the " +
|
||||||
|
"payer in reaching you",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: actionDecorator(addInvoice),
|
Action: actionDecorator(addInvoice),
|
||||||
}
|
}
|
||||||
@ -1771,6 +1777,7 @@ func addInvoice(ctx *cli.Context) error {
|
|||||||
DescriptionHash: descHash,
|
DescriptionHash: descHash,
|
||||||
FallbackAddr: ctx.String("fallback_addr"),
|
FallbackAddr: ctx.String("fallback_addr"),
|
||||||
Expiry: ctx.Int64("expiry"),
|
Expiry: ctx.Int64("expiry"),
|
||||||
|
Private: ctx.Bool("private"),
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.AddInvoice(context.Background(), invoice)
|
resp, err := client.AddInvoice(context.Background(), invoice)
|
||||||
|
448
lnd_test.go
448
lnd_test.go
@ -144,19 +144,20 @@ func mineBlocks(t *harnessTest, net *lntest.NetworkHarness, num uint32) []*wire.
|
|||||||
// channel.
|
// channel.
|
||||||
func openChannelAndAssert(ctx context.Context, t *harnessTest,
|
func openChannelAndAssert(ctx context.Context, t *harnessTest,
|
||||||
net *lntest.NetworkHarness, alice, bob *lntest.HarnessNode,
|
net *lntest.NetworkHarness, alice, bob *lntest.HarnessNode,
|
||||||
fundingAmt btcutil.Amount, pushAmt btcutil.Amount) *lnrpc.ChannelPoint {
|
fundingAmt btcutil.Amount, pushAmt btcutil.Amount,
|
||||||
|
private bool) *lnrpc.ChannelPoint {
|
||||||
|
|
||||||
chanOpenUpdate, err := net.OpenChannel(ctx, alice, bob, fundingAmt,
|
chanOpenUpdate, err := net.OpenChannel(
|
||||||
pushAmt, false)
|
ctx, alice, bob, fundingAmt, pushAmt, private,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to open channel: %v", err)
|
t.Fatalf("unable to open channel: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mine 6 blocks, then wait for Alice's node to notify us that the
|
// Mine 6 blocks, then wait for Alice's node to notify us that the
|
||||||
// channel has been opened. The funding transaction should be found
|
// channel has been opened. The funding transaction should be found
|
||||||
// within the first newly mined block. We mine 6 blocks to make sure
|
// within the first newly mined block. We mine 6 blocks so that in the
|
||||||
// the channel is public, as it will not be announced to the network
|
// case that the channel is public, it is announced to the network.
|
||||||
// before the funding transaction is 6 blocks deep.
|
|
||||||
block := mineBlocks(t, net, 6)[0]
|
block := mineBlocks(t, net, 6)[0]
|
||||||
|
|
||||||
fundingChanPoint, err := net.WaitForChannelOpen(ctx, chanOpenUpdate)
|
fundingChanPoint, err := net.WaitForChannelOpen(ctx, chanOpenUpdate)
|
||||||
@ -458,8 +459,9 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// assertions will be executed to ensure the funding process completed
|
// assertions will be executed to ensure the funding process completed
|
||||||
// successfully.
|
// successfully.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
||||||
err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint)
|
err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint)
|
||||||
@ -517,8 +519,9 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// Create a channel Alice->Bob.
|
// Create a channel Alice->Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
||||||
err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint)
|
err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint)
|
||||||
@ -543,8 +546,9 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint2 := openChannelAndAssert(ctxt, t, net, net.Bob, carol,
|
chanPoint2 := openChannelAndAssert(
|
||||||
chanAmt, pushAmt)
|
ctxt, t, net, net.Bob, carol, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
||||||
err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint2)
|
err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint2)
|
||||||
@ -756,7 +760,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint3 := openChannelAndAssert(
|
chanPoint3 := openChannelAndAssert(
|
||||||
ctxt, t, net, net.Alice, carol, chanAmt, pushAmt,
|
ctxt, t, net, net.Alice, carol, chanAmt, pushAmt, false,
|
||||||
)
|
)
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
||||||
@ -1297,8 +1301,9 @@ func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to connect alice and bob: %v", err)
|
t.Fatalf("unable to connect alice and bob: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chanPoint := openChannelAndAssert(ctx, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
amount, 0)
|
ctx, t, net, net.Alice, net.Bob, amount, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// Wait for both Alice and Bob to recognize this new channel.
|
// Wait for both Alice and Bob to recognize this new channel.
|
||||||
ctxt, _ := context.WithTimeout(context.Background(), timeout)
|
ctxt, _ := context.WithTimeout(context.Background(), timeout)
|
||||||
@ -1467,8 +1472,9 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
carolStartingBalance := carolBalResp.ConfirmedBalance
|
carolStartingBalance := carolBalResp.ConfirmedBalance
|
||||||
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, carol,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, carol, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
|
|
||||||
// Wait for Alice and Carol to receive the channel edge from the
|
// Wait for Alice and Carol to receive the channel edge from the
|
||||||
// funding manager.
|
// funding manager.
|
||||||
@ -2054,8 +2060,9 @@ func testSphinxReplayPersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, carol,
|
chanPoint := openChannelAndAssert(
|
||||||
dave, chanAmt, 0)
|
ctxt, t, net, carol, dave, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
assertAmountSent := func(amt btcutil.Amount) {
|
assertAmountSent := func(amt btcutil.Amount) {
|
||||||
// Both channels should also have properly accounted from the
|
// Both channels should also have properly accounted from the
|
||||||
@ -2201,8 +2208,9 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// the sole funder of the channel.
|
// the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanAmt := btcutil.Amount(100000)
|
chanAmt := btcutil.Amount(100000)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
assertAmountSent := func(amt btcutil.Amount) {
|
assertAmountSent := func(amt btcutil.Amount) {
|
||||||
// Both channels should also have properly accounted from the
|
// Both channels should also have properly accounted from the
|
||||||
@ -2356,8 +2364,9 @@ func testListPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
chanAmt := btcutil.Amount(100000)
|
chanAmt := btcutil.Amount(100000)
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// Now that the channel is open, create an invoice for Bob which
|
// Now that the channel is open, create an invoice for Bob which
|
||||||
// expects a payment of 1000 satoshis from Alice paid via a particular
|
// expects a payment of 1000 satoshis from Alice paid via a particular
|
||||||
@ -2537,8 +2546,9 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
@ -2573,8 +2583,9 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to dave: %v", err)
|
t.Fatalf("unable to send coins to dave: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointDave := openChannelAndAssert(ctxt, t, net, dave,
|
chanPointDave := openChannelAndAssert(
|
||||||
net.Alice, chanAmt, 0)
|
ctxt, t, net, dave, net.Alice, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointDave)
|
networkChans = append(networkChans, chanPointDave)
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2603,8 +2614,9 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, 0)
|
ctxt, t, net, carol, dave, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
@ -2800,8 +2812,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// Open a channel with 200k satoshis between Alice and Bob.
|
// Open a channel with 200k satoshis between Alice and Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt*2, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt*2, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
@ -2830,8 +2843,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to dave: %v", err)
|
t.Fatalf("unable to send coins to dave: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointDave := openChannelAndAssert(ctxt, t, net, dave,
|
chanPointDave := openChannelAndAssert(
|
||||||
net.Alice, chanAmt, 0)
|
ctxt, t, net, dave, net.Alice, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointDave)
|
networkChans = append(networkChans, chanPointDave)
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2860,8 +2874,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, 0)
|
ctxt, t, net, carol, dave, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
@ -3116,6 +3131,223 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testMultiHopOverPrivateChannels tests that private channels can be used as
|
||||||
|
// intermediate hops in a route for payments.
|
||||||
|
func testMultiHopOverPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
|
// We'll test that multi-hop payments over private channels work as
|
||||||
|
// intended. To do so, we'll create the following topology:
|
||||||
|
// private public private
|
||||||
|
// Alice <--100k--> Bob <--100k--> Carol <--100k--> Dave
|
||||||
|
|
||||||
|
ctxb := context.Background()
|
||||||
|
timeout := time.Duration(15 * time.Second)
|
||||||
|
const chanAmt = btcutil.Amount(100000)
|
||||||
|
|
||||||
|
// First, we'll open a private channel between Alice and Bob with Alice
|
||||||
|
// being the funder.
|
||||||
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
|
chanPointAlice := openChannelAndAssert(
|
||||||
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, true,
|
||||||
|
)
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err := net.Alice.WaitForNetworkChannelOpen(ctxb, chanPointAlice)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice didn't see the channel alice <-> bob before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = net.Bob.WaitForNetworkChannelOpen(ctxb, chanPointAlice)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob didn't see the channel alice <-> bob before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve Alice's funding outpoint.
|
||||||
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to get txid: %v", err)
|
||||||
|
}
|
||||||
|
aliceChanTXID, err := chainhash.NewHash(txidHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create sha hash: %v", err)
|
||||||
|
}
|
||||||
|
aliceFundPoint := wire.OutPoint{
|
||||||
|
Hash: *aliceChanTXID,
|
||||||
|
Index: chanPointAlice.OutputIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, we'll create Carol's node and open a public channel between
|
||||||
|
// her and Bob with Bob being the funder.
|
||||||
|
carol, err := net.NewNode(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create carol's node: %v", err)
|
||||||
|
}
|
||||||
|
if err := net.ConnectNodes(ctxb, net.Bob, carol); err != nil {
|
||||||
|
t.Fatalf("unable to connect bob to carol: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
chanPointBob := openChannelAndAssert(
|
||||||
|
ctxt, t, net, net.Bob, carol, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = net.Bob.WaitForNetworkChannelOpen(ctxb, chanPointBob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob didn't see the channel bob <-> carol before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = carol.WaitForNetworkChannelOpen(ctxb, chanPointBob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("carol didn't see the channel bob <-> carol before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = net.Alice.WaitForNetworkChannelOpen(ctxb, chanPointBob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice didn't see the channel bob <-> carol before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve Bob's funding outpoint.
|
||||||
|
txidHash, err = getChanPointFundingTxid(chanPointBob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to get txid: %v", err)
|
||||||
|
}
|
||||||
|
bobChanTXID, err := chainhash.NewHash(txidHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create sha hash: %v", err)
|
||||||
|
}
|
||||||
|
bobFundPoint := wire.OutPoint{
|
||||||
|
Hash: *bobChanTXID,
|
||||||
|
Index: chanPointBob.OutputIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, we'll create Dave's node and open a private channel between him
|
||||||
|
// and Carol with Carol being the funder.
|
||||||
|
dave, err := net.NewNode(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create dave's node: %v", err)
|
||||||
|
}
|
||||||
|
if err := net.ConnectNodes(ctxb, carol, dave); err != nil {
|
||||||
|
t.Fatalf("unable to connect carol to dave: %v", err)
|
||||||
|
}
|
||||||
|
err = net.SendCoins(ctxb, btcutil.SatoshiPerBitcoin, carol)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
chanPointCarol := openChannelAndAssert(
|
||||||
|
ctxt, t, net, carol, dave, chanAmt, 0, true,
|
||||||
|
)
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = carol.WaitForNetworkChannelOpen(ctxb, chanPointCarol)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("carol didn't see the channel carol <-> dave before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = dave.WaitForNetworkChannelOpen(ctxb, chanPointCarol)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("dave didn't see the channel carol <-> dave before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = dave.WaitForNetworkChannelOpen(ctxb, chanPointBob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("dave didn't see the channel bob <-> carol before "+
|
||||||
|
"timeout: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve Carol's funding point.
|
||||||
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to get txid: %v", err)
|
||||||
|
}
|
||||||
|
carolChanTXID, err := chainhash.NewHash(txidHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create sha hash: %v", err)
|
||||||
|
}
|
||||||
|
carolFundPoint := wire.OutPoint{
|
||||||
|
Hash: *carolChanTXID,
|
||||||
|
Index: chanPointCarol.OutputIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that all the channels are set up according to the topology from
|
||||||
|
// above, we can proceed to test payments. We'll create an invoice for
|
||||||
|
// Dave of 20k satoshis and pay it with Alice. Since there is no public
|
||||||
|
// route from Alice to Dave, we'll need to use the private channel
|
||||||
|
// between Carol and Dave as a routing hint encoded in the invoice.
|
||||||
|
const paymentAmt = 20000
|
||||||
|
|
||||||
|
// Create the invoice for Dave.
|
||||||
|
invoice := &lnrpc.Invoice{
|
||||||
|
Memo: "two hopz!",
|
||||||
|
Value: paymentAmt,
|
||||||
|
Private: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := dave.AddInvoice(ctxb, invoice)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to add invoice for dave: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let Alice pay the invoice.
|
||||||
|
payReqs := []string{resp.PaymentRequest}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
err = completePaymentRequests(ctxt, net.Alice, payReqs, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to send payments from alice to dave: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When asserting the amount of satoshis moved, we'll factor in the
|
||||||
|
// default base fee, as we didn't modify the fee structure when opening
|
||||||
|
// the channels.
|
||||||
|
const baseFee = 1
|
||||||
|
|
||||||
|
// Dave should have received 20k satoshis from Carol.
|
||||||
|
assertAmountPaid(t, ctxb, "Carol(local) [private=>] Dave(remote)",
|
||||||
|
dave, carolFundPoint, 0, paymentAmt)
|
||||||
|
|
||||||
|
// Carol should have sent 20k satoshis to Dave.
|
||||||
|
assertAmountPaid(t, ctxb, "Carol(local) [private=>] Dave(remote)",
|
||||||
|
carol, carolFundPoint, paymentAmt, 0)
|
||||||
|
|
||||||
|
// Carol should have received 20k satoshis + fee for one hop from Bob.
|
||||||
|
assertAmountPaid(t, ctxb, "Bob(local) => Carol(remote)",
|
||||||
|
carol, bobFundPoint, 0, paymentAmt+baseFee)
|
||||||
|
|
||||||
|
// Bob should have sent 20k satoshis + fee for one hop to Carol.
|
||||||
|
assertAmountPaid(t, ctxb, "Bob(local) => Carol(remote)",
|
||||||
|
net.Bob, bobFundPoint, paymentAmt+baseFee, 0)
|
||||||
|
|
||||||
|
// Bob should have received 20k satoshis + fee for two hops from Alice.
|
||||||
|
assertAmountPaid(t, ctxb, "Alice(local) [private=>] Bob(remote)", net.Bob,
|
||||||
|
aliceFundPoint, 0, paymentAmt+baseFee*2)
|
||||||
|
|
||||||
|
// Alice should have sent 20k satoshis + fee for two hops to Bob.
|
||||||
|
assertAmountPaid(t, ctxb, "Alice(local) [private=>] Bob(remote)", net.Alice,
|
||||||
|
aliceFundPoint, paymentAmt+baseFee*2, 0)
|
||||||
|
|
||||||
|
// At this point, the payment was successful. We can now close all the
|
||||||
|
// channels and shutdown the nodes created throughout this test.
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAlice, false)
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
closeChannelAndAssert(ctxt, t, net, net.Bob, chanPointBob, false)
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false)
|
||||||
|
|
||||||
|
if err := net.ShutdownNode(carol); err != nil {
|
||||||
|
t.Fatalf("unable to shutdown carol's node: %v", err)
|
||||||
|
}
|
||||||
|
if err := net.ShutdownNode(dave); err != nil {
|
||||||
|
t.Fatalf("unable to shutdown dave's node: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
|
func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
const chanAmt = btcutil.Amount(500000)
|
const chanAmt = btcutil.Amount(500000)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
@ -3124,8 +3356,9 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Open a channel with 500k satoshis between Alice and Bob with Alice
|
// Open a channel with 500k satoshis between Alice and Bob with Alice
|
||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// Next create a new invoice for Bob requesting 1k satoshis.
|
// Next create a new invoice for Bob requesting 1k satoshis.
|
||||||
// TODO(roasbeef): make global list of invoices for each node to re-use
|
// TODO(roasbeef): make global list of invoices for each node to re-use
|
||||||
@ -3233,8 +3466,9 @@ func testBasicChannelCreation(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
chanPoints := make([]*lnrpc.ChannelPoint, numChannels)
|
chanPoints := make([]*lnrpc.ChannelPoint, numChannels)
|
||||||
for i := 0; i < numChannels; i++ {
|
for i := 0; i < numChannels; i++ {
|
||||||
ctx, _ := context.WithTimeout(context.Background(), timeout)
|
ctx, _ := context.WithTimeout(context.Background(), timeout)
|
||||||
chanPoints[i] = openChannelAndAssert(ctx, t, net, net.Alice,
|
chanPoints[i] = openChannelAndAssert(
|
||||||
net.Bob, amount, 0)
|
ctx, t, net, net.Alice, net.Bob, amount, 0, false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the channel between Alice and Bob, asserting that the
|
// Close the channel between Alice and Bob, asserting that the
|
||||||
@ -3460,8 +3694,9 @@ func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// closure by Bob, we'll first open up a channel between them with a
|
// closure by Bob, we'll first open up a channel between them with a
|
||||||
// 0.5 BTC value.
|
// 0.5 BTC value.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// With the channel open, we'll create a few invoices for Bob that
|
// With the channel open, we'll create a few invoices for Bob that
|
||||||
// Alice will pay to in order to advance the state of the channel.
|
// Alice will pay to in order to advance the state of the channel.
|
||||||
@ -3709,8 +3944,9 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness
|
|||||||
// closure by Carol, we'll first open up a channel between them with a
|
// closure by Carol, we'll first open up a channel between them with a
|
||||||
// 0.5 BTC value.
|
// 0.5 BTC value.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, carol,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, carol, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// With the channel open, we'll create a few invoices for Carol that
|
// With the channel open, we'll create a few invoices for Carol that
|
||||||
// Alice will pay to in order to advance the state of the channel.
|
// Alice will pay to in order to advance the state of the channel.
|
||||||
@ -3945,7 +4181,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
|
|||||||
// maxFundingAmount (2^24) satoshis value.
|
// maxFundingAmount (2^24) satoshis value.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(
|
chanPoint := openChannelAndAssert(
|
||||||
ctxt, t, net, dave, carol, chanAmt, pushAmt,
|
ctxt, t, net, dave, carol, chanAmt, pushAmt, false,
|
||||||
)
|
)
|
||||||
|
|
||||||
// With the channel open, we'll create a few invoices for Carol that
|
// With the channel open, we'll create a few invoices for Carol that
|
||||||
@ -4268,8 +4504,9 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// First establish a channel with a capacity of 0.5 BTC between Alice
|
// First establish a channel with a capacity of 0.5 BTC between Alice
|
||||||
// and Bob.
|
// and Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPointAlice := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
if err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPointAlice); err != nil {
|
if err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPointAlice); err != nil {
|
||||||
t.Fatalf("channel not seen by alice before timeout: %v", err)
|
t.Fatalf("channel not seen by alice before timeout: %v", err)
|
||||||
@ -4312,8 +4549,9 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
const bobChanAmt = maxFundingAmount
|
const bobChanAmt = maxFundingAmount
|
||||||
chanPointBob := openChannelAndAssert(ctxt, t, net, net.Bob, carol,
|
chanPointBob := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Bob, carol, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// Ensure that Alice has Carol in her routing table before proceeding.
|
// Ensure that Alice has Carol in her routing table before proceeding.
|
||||||
nodeInfoReq := &lnrpc.NodeInfoRequest{
|
nodeInfoReq := &lnrpc.NodeInfoRequest{
|
||||||
@ -4600,8 +4838,9 @@ func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest)
|
|||||||
|
|
||||||
// Open a new channel between Alice and Bob.
|
// Open a new channel between Alice and Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// The channel opening above should have triggered a few notifications
|
// The channel opening above should have triggered a few notifications
|
||||||
// sent to the notification client. We'll expect two channel updates,
|
// sent to the notification client. We'll expect two channel updates,
|
||||||
@ -4714,8 +4953,9 @@ func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest)
|
|||||||
t.Fatalf("unable to connect bob to carol: %v", err)
|
t.Fatalf("unable to connect bob to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint = openChannelAndAssert(ctxt, t, net, net.Bob, carol,
|
chanPoint = openChannelAndAssert(
|
||||||
chanAmt, 0)
|
ctxt, t, net, net.Bob, carol, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// Reconnect Alice and Bob. This should result in the nodes syncing up
|
// Reconnect Alice and Bob. This should result in the nodes syncing up
|
||||||
// their respective graph state, with the new addition being the
|
// their respective graph state, with the new addition being the
|
||||||
@ -4811,8 +5051,9 @@ func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Bob, dave,
|
chanPoint := openChannelAndAssert(
|
||||||
1000000, 0)
|
ctxt, t, net, net.Bob, dave, 1000000, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
// When Alice now connects with Dave, Alice will get his node announcement.
|
// When Alice now connects with Dave, Alice will get his node announcement.
|
||||||
if err := net.ConnectNodes(ctxb, net.Alice, dave); err != nil {
|
if err := net.ConnectNodes(ctxb, net.Alice, dave); err != nil {
|
||||||
@ -4869,8 +5110,9 @@ func testNodeSignVerify(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// Create a channel between alice and bob.
|
// Create a channel between alice and bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
aliceBobCh := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
aliceBobCh := openChannelAndAssert(
|
||||||
chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
|
|
||||||
aliceMsg := []byte("alice msg")
|
aliceMsg := []byte("alice msg")
|
||||||
|
|
||||||
@ -4968,8 +5210,9 @@ func testAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Alice should send all money from her side to Bob.
|
// Alice should send all money from her side to Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
channelCapacity := btcutil.Amount(paymentAmt * 2000)
|
channelCapacity := btcutil.Amount(paymentAmt * 2000)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
channelCapacity, 0)
|
ctxt, t, net, net.Alice, net.Bob, channelCapacity, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
info, err := getChanInfo(net.Alice)
|
info, err := getChanInfo(net.Alice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -5150,8 +5393,10 @@ func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest)
|
|||||||
// amount of payments, between Alice and Bob, at the end of the test
|
// amount of payments, between Alice and Bob, at the end of the test
|
||||||
// Alice should send all money from her side to Bob.
|
// Alice should send all money from her side to Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob,
|
chanPoint := openChannelAndAssert(
|
||||||
paymentAmt*2000, paymentAmt*1000)
|
ctxt, t, net, net.Alice, net.Bob, paymentAmt*2000,
|
||||||
|
paymentAmt*1000, false,
|
||||||
|
)
|
||||||
|
|
||||||
info, err := getChanInfo(net.Alice)
|
info, err := getChanInfo(net.Alice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -5466,7 +5711,7 @@ func createThreeHopHodlNetwork(t *harnessTest,
|
|||||||
timeout := time.Duration(time.Second * 15)
|
timeout := time.Duration(time.Second * 15)
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
aliceChanPoint := openChannelAndAssert(
|
aliceChanPoint := openChannelAndAssert(
|
||||||
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0,
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
)
|
)
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
||||||
@ -5496,7 +5741,7 @@ func createThreeHopHodlNetwork(t *harnessTest,
|
|||||||
// open, our topology looks like: A -> B -> C.
|
// open, our topology looks like: A -> B -> C.
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
bobChanPoint := openChannelAndAssert(
|
bobChanPoint := openChannelAndAssert(
|
||||||
ctxt, t, net, net.Bob, carol, chanAmt, 0,
|
ctxt, t, net, net.Bob, carol, chanAmt, 0, false,
|
||||||
)
|
)
|
||||||
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
ctxt, _ = context.WithTimeout(ctxb, time.Second*15)
|
||||||
err = net.Bob.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
err = net.Bob.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
||||||
@ -6763,8 +7008,9 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
@ -6799,8 +7045,9 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to dave: %v", err)
|
t.Fatalf("unable to send coins to dave: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointDave := openChannelAndAssert(ctxt, t, net, dave,
|
chanPointDave := openChannelAndAssert(
|
||||||
net.Alice, chanAmt, pushAmt)
|
ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointDave)
|
networkChans = append(networkChans, chanPointDave)
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -6830,8 +7077,9 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, pushAmt)
|
ctxt, t, net, carol, dave, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
@ -7081,8 +7329,9 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
@ -7117,8 +7366,9 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to dave: %v", err)
|
t.Fatalf("unable to send coins to dave: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointDave := openChannelAndAssert(ctxt, t, net, dave,
|
chanPointDave := openChannelAndAssert(
|
||||||
net.Alice, chanAmt, pushAmt)
|
ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointDave)
|
networkChans = append(networkChans, chanPointDave)
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -7148,8 +7398,9 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, pushAmt)
|
ctxt, t, net, carol, dave, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
@ -7404,8 +7655,9 @@ func testSwitchOfflineDeliveryPersistence(net *lntest.NetworkHarness, t *harness
|
|||||||
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
@ -7440,8 +7692,9 @@ func testSwitchOfflineDeliveryPersistence(net *lntest.NetworkHarness, t *harness
|
|||||||
t.Fatalf("unable to send coins to dave: %v", err)
|
t.Fatalf("unable to send coins to dave: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointDave := openChannelAndAssert(ctxt, t, net, dave,
|
chanPointDave := openChannelAndAssert(
|
||||||
net.Alice, chanAmt, pushAmt)
|
ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointDave)
|
networkChans = append(networkChans, chanPointDave)
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -7471,8 +7724,9 @@ func testSwitchOfflineDeliveryPersistence(net *lntest.NetworkHarness, t *harness
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, pushAmt)
|
ctxt, t, net, carol, dave, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
@ -7728,8 +7982,9 @@ func testSwitchOfflineDeliveryOutgoingOffline(
|
|||||||
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
// Open a channel with 100k satoshis between Alice and Bob with Alice
|
||||||
// being the sole funder of the channel.
|
// being the sole funder of the channel.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt, pushAmt)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
txidHash, err := getChanPointFundingTxid(chanPointAlice)
|
||||||
@ -7764,8 +8019,9 @@ func testSwitchOfflineDeliveryOutgoingOffline(
|
|||||||
t.Fatalf("unable to send coins to dave: %v", err)
|
t.Fatalf("unable to send coins to dave: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointDave := openChannelAndAssert(ctxt, t, net, dave,
|
chanPointDave := openChannelAndAssert(
|
||||||
net.Alice, chanAmt, pushAmt)
|
ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointDave)
|
networkChans = append(networkChans, chanPointDave)
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
txidHash, err = getChanPointFundingTxid(chanPointDave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -7795,8 +8051,9 @@ func testSwitchOfflineDeliveryOutgoingOffline(
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, pushAmt)
|
ctxt, t, net, carol, dave, chanAmt, pushAmt, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
txidHash, err = getChanPointFundingTxid(chanPointCarol)
|
||||||
@ -8000,8 +8257,9 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// Open a channel between Alice and Bob.
|
// Open a channel between Alice and Bob.
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice,
|
chanPointAlice := openChannelAndAssert(
|
||||||
net.Bob, chanAmt, 0)
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointAlice)
|
networkChans = append(networkChans, chanPointAlice)
|
||||||
|
|
||||||
// Create Carol and establish a channel from Bob.
|
// Create Carol and establish a channel from Bob.
|
||||||
@ -8017,8 +8275,9 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to bob: %v", err)
|
t.Fatalf("unable to send coins to bob: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointBob := openChannelAndAssert(ctxt, t, net, net.Bob,
|
chanPointBob := openChannelAndAssert(
|
||||||
carol, chanAmt, 0)
|
ctxt, t, net, net.Bob, carol, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointBob)
|
networkChans = append(networkChans, chanPointBob)
|
||||||
|
|
||||||
// Create Dave and establish a channel from Carol.
|
// Create Dave and establish a channel from Carol.
|
||||||
@ -8034,8 +8293,9 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to send coins to carol: %v", err)
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
chanPointCarol := openChannelAndAssert(ctxt, t, net, carol,
|
chanPointCarol := openChannelAndAssert(
|
||||||
dave, chanAmt, 0)
|
ctxt, t, net, carol, dave, chanAmt, 0, false,
|
||||||
|
)
|
||||||
networkChans = append(networkChans, chanPointCarol)
|
networkChans = append(networkChans, chanPointCarol)
|
||||||
|
|
||||||
// Wait for all nodes to have seen all channels.
|
// Wait for all nodes to have seen all channels.
|
||||||
@ -8237,6 +8497,10 @@ var testsCases = []*testCase{
|
|||||||
name: "private channels",
|
name: "private channels",
|
||||||
test: testPrivateChannels,
|
test: testPrivateChannels,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "multi-hop payments over private channels",
|
||||||
|
test: testMultiHopOverPrivateChannels,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "multiple channel creation",
|
name: "multiple channel creation",
|
||||||
test: testBasicChannelCreation,
|
test: testBasicChannelCreation,
|
||||||
|
879
lnrpc/rpc.pb.go
879
lnrpc/rpc.pb.go
@ -82,6 +82,8 @@ It has these top-level messages:
|
|||||||
NodeUpdate
|
NodeUpdate
|
||||||
ChannelEdgeUpdate
|
ChannelEdgeUpdate
|
||||||
ClosedChannelUpdate
|
ClosedChannelUpdate
|
||||||
|
HopHint
|
||||||
|
RouteHint
|
||||||
Invoice
|
Invoice
|
||||||
AddInvoiceResponse
|
AddInvoiceResponse
|
||||||
PaymentHash
|
PaymentHash
|
||||||
@ -519,9 +521,7 @@ func (m *ChannelPoint) String() string { return proto.CompactTextStri
|
|||||||
func (*ChannelPoint) ProtoMessage() {}
|
func (*ChannelPoint) ProtoMessage() {}
|
||||||
func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
|
func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
|
||||||
|
|
||||||
type isChannelPoint_FundingTxid interface {
|
type isChannelPoint_FundingTxid interface{ isChannelPoint_FundingTxid() }
|
||||||
isChannelPoint_FundingTxid()
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChannelPoint_FundingTxidBytes struct {
|
type ChannelPoint_FundingTxidBytes struct {
|
||||||
FundingTxidBytes []byte `protobuf:"bytes,1,opt,name=funding_txid_bytes,proto3,oneof"`
|
FundingTxidBytes []byte `protobuf:"bytes,1,opt,name=funding_txid_bytes,proto3,oneof"`
|
||||||
@ -1608,9 +1608,7 @@ func (m *CloseStatusUpdate) String() string { return proto.CompactTex
|
|||||||
func (*CloseStatusUpdate) ProtoMessage() {}
|
func (*CloseStatusUpdate) ProtoMessage() {}
|
||||||
func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} }
|
func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} }
|
||||||
|
|
||||||
type isCloseStatusUpdate_Update interface {
|
type isCloseStatusUpdate_Update interface{ isCloseStatusUpdate_Update() }
|
||||||
isCloseStatusUpdate_Update()
|
|
||||||
}
|
|
||||||
|
|
||||||
type CloseStatusUpdate_ClosePending struct {
|
type CloseStatusUpdate_ClosePending struct {
|
||||||
ClosePending *PendingUpdate `protobuf:"bytes,1,opt,name=close_pending,oneof"`
|
ClosePending *PendingUpdate `protobuf:"bytes,1,opt,name=close_pending,oneof"`
|
||||||
@ -1873,9 +1871,7 @@ func (m *OpenStatusUpdate) String() string { return proto.CompactText
|
|||||||
func (*OpenStatusUpdate) ProtoMessage() {}
|
func (*OpenStatusUpdate) ProtoMessage() {}
|
||||||
func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} }
|
func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} }
|
||||||
|
|
||||||
type isOpenStatusUpdate_Update interface {
|
type isOpenStatusUpdate_Update interface{ isOpenStatusUpdate_Update() }
|
||||||
isOpenStatusUpdate_Update()
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenStatusUpdate_ChanPending struct {
|
type OpenStatusUpdate_ChanPending struct {
|
||||||
ChanPending *PendingUpdate `protobuf:"bytes,1,opt,name=chan_pending,oneof"`
|
ChanPending *PendingUpdate `protobuf:"bytes,1,opt,name=chan_pending,oneof"`
|
||||||
@ -2808,7 +2804,7 @@ func (m *RoutingPolicy) GetFeeRateMilliMsat() int64 {
|
|||||||
// *
|
// *
|
||||||
// A fully authenticated channel along with all its unique attributes.
|
// A fully authenticated channel along with all its unique attributes.
|
||||||
// Once an authenticated channel announcement has been processed on the network,
|
// Once an authenticated channel announcement has been processed on the network,
|
||||||
// then a instance of ChannelEdgeInfo encapsulating the channels attributes is
|
// then an instance of ChannelEdgeInfo encapsulating the channels attributes is
|
||||||
// stored. The other portions relevant to routing policy of a channel are stored
|
// stored. The other portions relevant to routing policy of a channel are stored
|
||||||
// within a ChannelEdgePolicy for each direction of the channel.
|
// within a ChannelEdgePolicy for each direction of the channel.
|
||||||
type ChannelEdge struct {
|
type ChannelEdge struct {
|
||||||
@ -3230,6 +3226,80 @@ func (m *ClosedChannelUpdate) GetChanPoint() *ChannelPoint {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HopHint struct {
|
||||||
|
// / The public key of the node at the start of the channel.
|
||||||
|
NodeId string `protobuf:"bytes,1,opt,name=node_id" json:"node_id,omitempty"`
|
||||||
|
// / The unique identifier of the channel.
|
||||||
|
ChanId uint64 `protobuf:"varint,2,opt,name=chan_id" json:"chan_id,omitempty"`
|
||||||
|
// / The base fee of the channel denominated in millisatoshis.
|
||||||
|
FeeBaseMsat uint32 `protobuf:"varint,3,opt,name=fee_base_msat" json:"fee_base_msat,omitempty"`
|
||||||
|
// *
|
||||||
|
// The fee rate of the channel for sending one satoshi across it denominated in
|
||||||
|
// millionths of a satoshi.
|
||||||
|
FeeProportionalMillionths uint32 `protobuf:"varint,4,opt,name=fee_proportional_millionths" json:"fee_proportional_millionths,omitempty"`
|
||||||
|
// / The time-lock delta of the channel.
|
||||||
|
CltvExpiryDelta uint32 `protobuf:"varint,5,opt,name=cltv_expiry_delta" json:"cltv_expiry_delta,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HopHint) Reset() { *m = HopHint{} }
|
||||||
|
func (m *HopHint) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*HopHint) ProtoMessage() {}
|
||||||
|
func (*HopHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{74} }
|
||||||
|
|
||||||
|
func (m *HopHint) GetNodeId() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.NodeId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HopHint) GetChanId() uint64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.ChanId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HopHint) GetFeeBaseMsat() uint32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.FeeBaseMsat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HopHint) GetFeeProportionalMillionths() uint32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.FeeProportionalMillionths
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HopHint) GetCltvExpiryDelta() uint32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.CltvExpiryDelta
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteHint struct {
|
||||||
|
// *
|
||||||
|
// A list of hop hints that when chained together can assist in reaching a
|
||||||
|
// specific destination.
|
||||||
|
HopHints []*HopHint `protobuf:"bytes,1,rep,name=hop_hints" json:"hop_hints,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RouteHint) Reset() { *m = RouteHint{} }
|
||||||
|
func (m *RouteHint) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*RouteHint) ProtoMessage() {}
|
||||||
|
func (*RouteHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{75} }
|
||||||
|
|
||||||
|
func (m *RouteHint) GetHopHints() []*HopHint {
|
||||||
|
if m != nil {
|
||||||
|
return m.HopHints
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Invoice struct {
|
type Invoice struct {
|
||||||
// *
|
// *
|
||||||
// An optional memo to attach along with the invoice. Used for record keeping
|
// An optional memo to attach along with the invoice. Used for record keeping
|
||||||
@ -3269,12 +3339,18 @@ type Invoice struct {
|
|||||||
FallbackAddr string `protobuf:"bytes,12,opt,name=fallback_addr" json:"fallback_addr,omitempty"`
|
FallbackAddr string `protobuf:"bytes,12,opt,name=fallback_addr" json:"fallback_addr,omitempty"`
|
||||||
// / Delta to use for the time-lock of the CLTV extended to the final hop.
|
// / Delta to use for the time-lock of the CLTV extended to the final hop.
|
||||||
CltvExpiry uint64 `protobuf:"varint,13,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"`
|
CltvExpiry uint64 `protobuf:"varint,13,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"`
|
||||||
|
// *
|
||||||
|
// Route hints that can each be individually used to assist in reaching the
|
||||||
|
// invoice's destination.
|
||||||
|
RouteHints []*RouteHint `protobuf:"bytes,14,rep,name=route_hints" json:"route_hints,omitempty"`
|
||||||
|
// / Whether this invoice should include routing hints for private channels.
|
||||||
|
Private bool `protobuf:"varint,15,opt,name=private" json:"private,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Invoice) Reset() { *m = Invoice{} }
|
func (m *Invoice) Reset() { *m = Invoice{} }
|
||||||
func (m *Invoice) String() string { return proto.CompactTextString(m) }
|
func (m *Invoice) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Invoice) ProtoMessage() {}
|
func (*Invoice) ProtoMessage() {}
|
||||||
func (*Invoice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{74} }
|
func (*Invoice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{76} }
|
||||||
|
|
||||||
func (m *Invoice) GetMemo() string {
|
func (m *Invoice) GetMemo() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3367,6 +3443,20 @@ func (m *Invoice) GetCltvExpiry() uint64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Invoice) GetRouteHints() []*RouteHint {
|
||||||
|
if m != nil {
|
||||||
|
return m.RouteHints
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Invoice) GetPrivate() bool {
|
||||||
|
if m != nil {
|
||||||
|
return m.Private
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type AddInvoiceResponse struct {
|
type AddInvoiceResponse struct {
|
||||||
RHash []byte `protobuf:"bytes,1,opt,name=r_hash,proto3" json:"r_hash,omitempty"`
|
RHash []byte `protobuf:"bytes,1,opt,name=r_hash,proto3" json:"r_hash,omitempty"`
|
||||||
// *
|
// *
|
||||||
@ -3379,7 +3469,7 @@ type AddInvoiceResponse struct {
|
|||||||
func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} }
|
func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} }
|
||||||
func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) }
|
func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*AddInvoiceResponse) ProtoMessage() {}
|
func (*AddInvoiceResponse) ProtoMessage() {}
|
||||||
func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{75} }
|
func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{77} }
|
||||||
|
|
||||||
func (m *AddInvoiceResponse) GetRHash() []byte {
|
func (m *AddInvoiceResponse) GetRHash() []byte {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3407,7 +3497,7 @@ type PaymentHash struct {
|
|||||||
func (m *PaymentHash) Reset() { *m = PaymentHash{} }
|
func (m *PaymentHash) Reset() { *m = PaymentHash{} }
|
||||||
func (m *PaymentHash) String() string { return proto.CompactTextString(m) }
|
func (m *PaymentHash) String() string { return proto.CompactTextString(m) }
|
||||||
func (*PaymentHash) ProtoMessage() {}
|
func (*PaymentHash) ProtoMessage() {}
|
||||||
func (*PaymentHash) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{76} }
|
func (*PaymentHash) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{78} }
|
||||||
|
|
||||||
func (m *PaymentHash) GetRHashStr() string {
|
func (m *PaymentHash) GetRHashStr() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3431,7 +3521,7 @@ type ListInvoiceRequest struct {
|
|||||||
func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} }
|
func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} }
|
||||||
func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) }
|
func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ListInvoiceRequest) ProtoMessage() {}
|
func (*ListInvoiceRequest) ProtoMessage() {}
|
||||||
func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{77} }
|
func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{79} }
|
||||||
|
|
||||||
func (m *ListInvoiceRequest) GetPendingOnly() bool {
|
func (m *ListInvoiceRequest) GetPendingOnly() bool {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3447,7 +3537,7 @@ type ListInvoiceResponse struct {
|
|||||||
func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} }
|
func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} }
|
||||||
func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) }
|
func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ListInvoiceResponse) ProtoMessage() {}
|
func (*ListInvoiceResponse) ProtoMessage() {}
|
||||||
func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{78} }
|
func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{80} }
|
||||||
|
|
||||||
func (m *ListInvoiceResponse) GetInvoices() []*Invoice {
|
func (m *ListInvoiceResponse) GetInvoices() []*Invoice {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3462,7 +3552,7 @@ type InvoiceSubscription struct {
|
|||||||
func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} }
|
func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} }
|
||||||
func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) }
|
func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) }
|
||||||
func (*InvoiceSubscription) ProtoMessage() {}
|
func (*InvoiceSubscription) ProtoMessage() {}
|
||||||
func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{79} }
|
func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{81} }
|
||||||
|
|
||||||
type Payment struct {
|
type Payment struct {
|
||||||
// / The payment hash
|
// / The payment hash
|
||||||
@ -3482,7 +3572,7 @@ type Payment struct {
|
|||||||
func (m *Payment) Reset() { *m = Payment{} }
|
func (m *Payment) Reset() { *m = Payment{} }
|
||||||
func (m *Payment) String() string { return proto.CompactTextString(m) }
|
func (m *Payment) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Payment) ProtoMessage() {}
|
func (*Payment) ProtoMessage() {}
|
||||||
func (*Payment) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{80} }
|
func (*Payment) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{82} }
|
||||||
|
|
||||||
func (m *Payment) GetPaymentHash() string {
|
func (m *Payment) GetPaymentHash() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3532,7 +3622,7 @@ type ListPaymentsRequest struct {
|
|||||||
func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} }
|
func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} }
|
||||||
func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) }
|
func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ListPaymentsRequest) ProtoMessage() {}
|
func (*ListPaymentsRequest) ProtoMessage() {}
|
||||||
func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{81} }
|
func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{83} }
|
||||||
|
|
||||||
type ListPaymentsResponse struct {
|
type ListPaymentsResponse struct {
|
||||||
// / The list of payments
|
// / The list of payments
|
||||||
@ -3542,7 +3632,7 @@ type ListPaymentsResponse struct {
|
|||||||
func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} }
|
func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} }
|
||||||
func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) }
|
func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ListPaymentsResponse) ProtoMessage() {}
|
func (*ListPaymentsResponse) ProtoMessage() {}
|
||||||
func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{82} }
|
func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{84} }
|
||||||
|
|
||||||
func (m *ListPaymentsResponse) GetPayments() []*Payment {
|
func (m *ListPaymentsResponse) GetPayments() []*Payment {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3557,7 +3647,7 @@ type DeleteAllPaymentsRequest struct {
|
|||||||
func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsRequest{} }
|
func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsRequest{} }
|
||||||
func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) }
|
func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*DeleteAllPaymentsRequest) ProtoMessage() {}
|
func (*DeleteAllPaymentsRequest) ProtoMessage() {}
|
||||||
func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{83} }
|
func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{85} }
|
||||||
|
|
||||||
type DeleteAllPaymentsResponse struct {
|
type DeleteAllPaymentsResponse struct {
|
||||||
}
|
}
|
||||||
@ -3565,7 +3655,7 @@ type DeleteAllPaymentsResponse struct {
|
|||||||
func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResponse{} }
|
func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResponse{} }
|
||||||
func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) }
|
func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*DeleteAllPaymentsResponse) ProtoMessage() {}
|
func (*DeleteAllPaymentsResponse) ProtoMessage() {}
|
||||||
func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{84} }
|
func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{86} }
|
||||||
|
|
||||||
type DebugLevelRequest struct {
|
type DebugLevelRequest struct {
|
||||||
Show bool `protobuf:"varint,1,opt,name=show" json:"show,omitempty"`
|
Show bool `protobuf:"varint,1,opt,name=show" json:"show,omitempty"`
|
||||||
@ -3575,7 +3665,7 @@ type DebugLevelRequest struct {
|
|||||||
func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} }
|
func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} }
|
||||||
func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) }
|
func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*DebugLevelRequest) ProtoMessage() {}
|
func (*DebugLevelRequest) ProtoMessage() {}
|
||||||
func (*DebugLevelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{85} }
|
func (*DebugLevelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{87} }
|
||||||
|
|
||||||
func (m *DebugLevelRequest) GetShow() bool {
|
func (m *DebugLevelRequest) GetShow() bool {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3598,7 +3688,7 @@ type DebugLevelResponse struct {
|
|||||||
func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} }
|
func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} }
|
||||||
func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) }
|
func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*DebugLevelResponse) ProtoMessage() {}
|
func (*DebugLevelResponse) ProtoMessage() {}
|
||||||
func (*DebugLevelResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{86} }
|
func (*DebugLevelResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} }
|
||||||
|
|
||||||
func (m *DebugLevelResponse) GetSubSystems() string {
|
func (m *DebugLevelResponse) GetSubSystems() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3615,7 +3705,7 @@ type PayReqString struct {
|
|||||||
func (m *PayReqString) Reset() { *m = PayReqString{} }
|
func (m *PayReqString) Reset() { *m = PayReqString{} }
|
||||||
func (m *PayReqString) String() string { return proto.CompactTextString(m) }
|
func (m *PayReqString) String() string { return proto.CompactTextString(m) }
|
||||||
func (*PayReqString) ProtoMessage() {}
|
func (*PayReqString) ProtoMessage() {}
|
||||||
func (*PayReqString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{87} }
|
func (*PayReqString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{89} }
|
||||||
|
|
||||||
func (m *PayReqString) GetPayReq() string {
|
func (m *PayReqString) GetPayReq() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3625,21 +3715,22 @@ func (m *PayReqString) GetPayReq() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PayReq struct {
|
type PayReq struct {
|
||||||
Destination string `protobuf:"bytes,1,opt,name=destination" json:"destination,omitempty"`
|
Destination string `protobuf:"bytes,1,opt,name=destination" json:"destination,omitempty"`
|
||||||
PaymentHash string `protobuf:"bytes,2,opt,name=payment_hash" json:"payment_hash,omitempty"`
|
PaymentHash string `protobuf:"bytes,2,opt,name=payment_hash" json:"payment_hash,omitempty"`
|
||||||
NumSatoshis int64 `protobuf:"varint,3,opt,name=num_satoshis" json:"num_satoshis,omitempty"`
|
NumSatoshis int64 `protobuf:"varint,3,opt,name=num_satoshis" json:"num_satoshis,omitempty"`
|
||||||
Timestamp int64 `protobuf:"varint,4,opt,name=timestamp" json:"timestamp,omitempty"`
|
Timestamp int64 `protobuf:"varint,4,opt,name=timestamp" json:"timestamp,omitempty"`
|
||||||
Expiry int64 `protobuf:"varint,5,opt,name=expiry" json:"expiry,omitempty"`
|
Expiry int64 `protobuf:"varint,5,opt,name=expiry" json:"expiry,omitempty"`
|
||||||
Description string `protobuf:"bytes,6,opt,name=description" json:"description,omitempty"`
|
Description string `protobuf:"bytes,6,opt,name=description" json:"description,omitempty"`
|
||||||
DescriptionHash string `protobuf:"bytes,7,opt,name=description_hash" json:"description_hash,omitempty"`
|
DescriptionHash string `protobuf:"bytes,7,opt,name=description_hash" json:"description_hash,omitempty"`
|
||||||
FallbackAddr string `protobuf:"bytes,8,opt,name=fallback_addr" json:"fallback_addr,omitempty"`
|
FallbackAddr string `protobuf:"bytes,8,opt,name=fallback_addr" json:"fallback_addr,omitempty"`
|
||||||
CltvExpiry int64 `protobuf:"varint,9,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"`
|
CltvExpiry int64 `protobuf:"varint,9,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"`
|
||||||
|
RouteHints []*RouteHint `protobuf:"bytes,10,rep,name=route_hints" json:"route_hints,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PayReq) Reset() { *m = PayReq{} }
|
func (m *PayReq) Reset() { *m = PayReq{} }
|
||||||
func (m *PayReq) String() string { return proto.CompactTextString(m) }
|
func (m *PayReq) String() string { return proto.CompactTextString(m) }
|
||||||
func (*PayReq) ProtoMessage() {}
|
func (*PayReq) ProtoMessage() {}
|
||||||
func (*PayReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} }
|
func (*PayReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{90} }
|
||||||
|
|
||||||
func (m *PayReq) GetDestination() string {
|
func (m *PayReq) GetDestination() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3704,13 +3795,20 @@ func (m *PayReq) GetCltvExpiry() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *PayReq) GetRouteHints() []*RouteHint {
|
||||||
|
if m != nil {
|
||||||
|
return m.RouteHints
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type FeeReportRequest struct {
|
type FeeReportRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} }
|
func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} }
|
||||||
func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) }
|
func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*FeeReportRequest) ProtoMessage() {}
|
func (*FeeReportRequest) ProtoMessage() {}
|
||||||
func (*FeeReportRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{89} }
|
func (*FeeReportRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{91} }
|
||||||
|
|
||||||
type ChannelFeeReport struct {
|
type ChannelFeeReport struct {
|
||||||
// / The channel that this fee report belongs to.
|
// / The channel that this fee report belongs to.
|
||||||
@ -3726,7 +3824,7 @@ type ChannelFeeReport struct {
|
|||||||
func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} }
|
func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} }
|
||||||
func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) }
|
func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ChannelFeeReport) ProtoMessage() {}
|
func (*ChannelFeeReport) ProtoMessage() {}
|
||||||
func (*ChannelFeeReport) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{90} }
|
func (*ChannelFeeReport) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{92} }
|
||||||
|
|
||||||
func (m *ChannelFeeReport) GetChanPoint() string {
|
func (m *ChannelFeeReport) GetChanPoint() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3770,7 +3868,7 @@ type FeeReportResponse struct {
|
|||||||
func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} }
|
func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} }
|
||||||
func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) }
|
func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*FeeReportResponse) ProtoMessage() {}
|
func (*FeeReportResponse) ProtoMessage() {}
|
||||||
func (*FeeReportResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{91} }
|
func (*FeeReportResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{93} }
|
||||||
|
|
||||||
func (m *FeeReportResponse) GetChannelFees() []*ChannelFeeReport {
|
func (m *FeeReportResponse) GetChannelFees() []*ChannelFeeReport {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -3816,11 +3914,9 @@ type PolicyUpdateRequest struct {
|
|||||||
func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} }
|
func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} }
|
||||||
func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) }
|
func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*PolicyUpdateRequest) ProtoMessage() {}
|
func (*PolicyUpdateRequest) ProtoMessage() {}
|
||||||
func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{92} }
|
func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} }
|
||||||
|
|
||||||
type isPolicyUpdateRequest_Scope interface {
|
type isPolicyUpdateRequest_Scope interface{ isPolicyUpdateRequest_Scope() }
|
||||||
isPolicyUpdateRequest_Scope()
|
|
||||||
}
|
|
||||||
|
|
||||||
type PolicyUpdateRequest_Global struct {
|
type PolicyUpdateRequest_Global struct {
|
||||||
Global bool `protobuf:"varint,1,opt,name=global,oneof"`
|
Global bool `protobuf:"varint,1,opt,name=global,oneof"`
|
||||||
@ -3953,7 +4049,7 @@ type PolicyUpdateResponse struct {
|
|||||||
func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} }
|
func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} }
|
||||||
func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) }
|
func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*PolicyUpdateResponse) ProtoMessage() {}
|
func (*PolicyUpdateResponse) ProtoMessage() {}
|
||||||
func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{93} }
|
func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{95} }
|
||||||
|
|
||||||
type ForwardingHistoryRequest struct {
|
type ForwardingHistoryRequest struct {
|
||||||
// / Start time is the starting point of the forwarding history request. All records beyond this point will be included, respecting the end time, and the index offset.
|
// / Start time is the starting point of the forwarding history request. All records beyond this point will be included, respecting the end time, and the index offset.
|
||||||
@ -3969,7 +4065,7 @@ type ForwardingHistoryRequest struct {
|
|||||||
func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryRequest{} }
|
func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryRequest{} }
|
||||||
func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) }
|
func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ForwardingHistoryRequest) ProtoMessage() {}
|
func (*ForwardingHistoryRequest) ProtoMessage() {}
|
||||||
func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} }
|
func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{96} }
|
||||||
|
|
||||||
func (m *ForwardingHistoryRequest) GetStartTime() uint64 {
|
func (m *ForwardingHistoryRequest) GetStartTime() uint64 {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -4017,7 +4113,7 @@ type ForwardingEvent struct {
|
|||||||
func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} }
|
func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} }
|
||||||
func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) }
|
func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ForwardingEvent) ProtoMessage() {}
|
func (*ForwardingEvent) ProtoMessage() {}
|
||||||
func (*ForwardingEvent) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{95} }
|
func (*ForwardingEvent) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{97} }
|
||||||
|
|
||||||
func (m *ForwardingEvent) GetTimestamp() uint64 {
|
func (m *ForwardingEvent) GetTimestamp() uint64 {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -4071,7 +4167,7 @@ type ForwardingHistoryResponse struct {
|
|||||||
func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResponse{} }
|
func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResponse{} }
|
||||||
func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) }
|
func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ForwardingHistoryResponse) ProtoMessage() {}
|
func (*ForwardingHistoryResponse) ProtoMessage() {}
|
||||||
func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{96} }
|
func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{98} }
|
||||||
|
|
||||||
func (m *ForwardingHistoryResponse) GetForwardingEvents() []*ForwardingEvent {
|
func (m *ForwardingHistoryResponse) GetForwardingEvents() []*ForwardingEvent {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
@ -4166,6 +4262,8 @@ func init() {
|
|||||||
proto.RegisterType((*NodeUpdate)(nil), "lnrpc.NodeUpdate")
|
proto.RegisterType((*NodeUpdate)(nil), "lnrpc.NodeUpdate")
|
||||||
proto.RegisterType((*ChannelEdgeUpdate)(nil), "lnrpc.ChannelEdgeUpdate")
|
proto.RegisterType((*ChannelEdgeUpdate)(nil), "lnrpc.ChannelEdgeUpdate")
|
||||||
proto.RegisterType((*ClosedChannelUpdate)(nil), "lnrpc.ClosedChannelUpdate")
|
proto.RegisterType((*ClosedChannelUpdate)(nil), "lnrpc.ClosedChannelUpdate")
|
||||||
|
proto.RegisterType((*HopHint)(nil), "lnrpc.HopHint")
|
||||||
|
proto.RegisterType((*RouteHint)(nil), "lnrpc.RouteHint")
|
||||||
proto.RegisterType((*Invoice)(nil), "lnrpc.Invoice")
|
proto.RegisterType((*Invoice)(nil), "lnrpc.Invoice")
|
||||||
proto.RegisterType((*AddInvoiceResponse)(nil), "lnrpc.AddInvoiceResponse")
|
proto.RegisterType((*AddInvoiceResponse)(nil), "lnrpc.AddInvoiceResponse")
|
||||||
proto.RegisterType((*PaymentHash)(nil), "lnrpc.PaymentHash")
|
proto.RegisterType((*PaymentHash)(nil), "lnrpc.PaymentHash")
|
||||||
@ -6203,346 +6301,353 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{
|
|||||||
func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) }
|
func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) }
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
var fileDescriptor0 = []byte{
|
||||||
// 5446 bytes of a gzipped FileDescriptorProto
|
// 5566 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0xcd, 0x93, 0x1c, 0xc9,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0xcd, 0x93, 0x1c, 0xc9,
|
||||||
0x55, 0xb8, 0xaa, 0xa7, 0xe7, 0xa3, 0x5f, 0xf7, 0x7c, 0xe5, 0x8c, 0x46, 0xad, 0x5e, 0x59, 0xab,
|
0x55, 0x57, 0xf5, 0xf4, 0x7c, 0xf4, 0xeb, 0x9e, 0x9e, 0x99, 0x9c, 0xd1, 0xa8, 0xd5, 0xd2, 0x6a,
|
||||||
0x4d, 0x6f, 0x58, 0xfa, 0xcd, 0x6f, 0xd1, 0x68, 0xc7, 0xf6, 0xb2, 0xac, 0xc0, 0x0e, 0x7d, 0xcf,
|
0xb5, 0xe5, 0x8d, 0x95, 0x18, 0x16, 0x8d, 0x76, 0x6c, 0x2f, 0xeb, 0x15, 0xac, 0xd1, 0xf7, 0xac,
|
||||||
0xda, 0x5a, 0x79, 0x5c, 0x23, 0x79, 0xc1, 0x0b, 0xb4, 0x6b, 0xba, 0x73, 0x7a, 0xca, 0xea, 0xae,
|
0xad, 0x95, 0xc7, 0x35, 0x92, 0x17, 0xbc, 0x40, 0xbb, 0xa6, 0x3b, 0xa7, 0xa7, 0xac, 0xea, 0xaa,
|
||||||
0xaa, 0xad, 0xaa, 0x9e, 0x51, 0xef, 0xa2, 0x08, 0x3e, 0x22, 0x38, 0xe1, 0xe0, 0x00, 0x17, 0x43,
|
0xda, 0xaa, 0xea, 0x19, 0xf5, 0x2e, 0x8a, 0xe0, 0x23, 0x82, 0x13, 0x0e, 0x0e, 0x70, 0x31, 0x04,
|
||||||
0x38, 0x88, 0xb0, 0x2f, 0x70, 0xe0, 0xc8, 0xc9, 0x04, 0x7f, 0x80, 0x23, 0x08, 0x0e, 0x3e, 0x39,
|
0x41, 0x84, 0x7d, 0x81, 0x03, 0x47, 0x4e, 0xe6, 0x2f, 0x70, 0x04, 0xc1, 0x61, 0x4f, 0x0e, 0x6e,
|
||||||
0xb8, 0xf1, 0x71, 0x00, 0x82, 0x23, 0x17, 0x0e, 0x04, 0xf1, 0x5e, 0x7e, 0x54, 0x66, 0x55, 0x8d,
|
0x7c, 0x1c, 0xc0, 0xc1, 0x85, 0x08, 0x2e, 0x1c, 0x08, 0xe2, 0xbd, 0xfc, 0xa8, 0xcc, 0xaa, 0x1a,
|
||||||
0x24, 0xdb, 0xc0, 0xad, 0xf3, 0xe5, 0xcb, 0x97, 0x5f, 0xef, 0xbd, 0x7c, 0x5f, 0xd5, 0xd0, 0x4a,
|
0x49, 0xb6, 0xc1, 0xb7, 0xce, 0x5f, 0xbe, 0x7a, 0xf9, 0xf5, 0xde, 0xcb, 0xf7, 0x5e, 0x66, 0x36,
|
||||||
0x93, 0xc1, 0xf5, 0x24, 0x8d, 0xf3, 0x98, 0xcd, 0x8f, 0xa3, 0x34, 0x19, 0xf4, 0x2e, 0x8d, 0xe2,
|
0xb4, 0xd2, 0x64, 0x78, 0x2d, 0x49, 0xe3, 0x3c, 0x66, 0xf3, 0x61, 0x94, 0x26, 0xc3, 0xfe, 0xc5,
|
||||||
0x78, 0x34, 0x16, 0x3b, 0x41, 0x12, 0xee, 0x04, 0x51, 0x14, 0xe7, 0x41, 0x1e, 0xc6, 0x51, 0x26,
|
0x71, 0x1c, 0x8f, 0x43, 0xbe, 0xed, 0x27, 0xc1, 0xb6, 0x1f, 0x45, 0x71, 0xee, 0xe7, 0x41, 0x1c,
|
||||||
0x91, 0xf8, 0xb7, 0x60, 0xe5, 0x81, 0x88, 0x0e, 0x84, 0x18, 0xfa, 0xe2, 0xe3, 0xa9, 0xc8, 0x72,
|
0x65, 0x82, 0xc8, 0xfd, 0x16, 0x74, 0xef, 0xf3, 0x68, 0x9f, 0xf3, 0x91, 0xc7, 0x3f, 0x9e, 0xf2,
|
||||||
0xf6, 0xff, 0x61, 0x3d, 0x10, 0x9f, 0x08, 0x31, 0xec, 0x27, 0x41, 0x96, 0x25, 0xc7, 0x69, 0x90,
|
0x2c, 0x67, 0xbf, 0x08, 0x6b, 0x3e, 0xff, 0x84, 0xf3, 0xd1, 0x20, 0xf1, 0xb3, 0x2c, 0x39, 0x4a,
|
||||||
0x89, 0xae, 0x77, 0xc5, 0xbb, 0xd6, 0xf1, 0xd7, 0x64, 0xc7, 0xbe, 0x81, 0xb3, 0x37, 0xa0, 0x93,
|
0xfd, 0x8c, 0xf7, 0x9c, 0xcb, 0xce, 0xd5, 0x8e, 0xb7, 0x2a, 0x2a, 0xf6, 0x34, 0xce, 0x5e, 0x83,
|
||||||
0x21, 0xaa, 0x88, 0xf2, 0x34, 0x4e, 0x66, 0xdd, 0x06, 0xe1, 0xb5, 0x11, 0x76, 0x4f, 0x82, 0xf8,
|
0x4e, 0x86, 0xa4, 0x3c, 0xca, 0xd3, 0x38, 0x99, 0xf5, 0x1a, 0x44, 0xd7, 0x46, 0xec, 0xae, 0x80,
|
||||||
0x18, 0x56, 0xcd, 0x0c, 0x59, 0x12, 0x47, 0x99, 0x60, 0x37, 0x60, 0x73, 0x10, 0x26, 0xc7, 0x22,
|
0xdc, 0x10, 0x56, 0x74, 0x0b, 0x59, 0x12, 0x47, 0x19, 0x67, 0xd7, 0x61, 0x63, 0x18, 0x24, 0x47,
|
||||||
0xed, 0xd3, 0xe0, 0x49, 0x24, 0x26, 0x71, 0x14, 0x0e, 0xba, 0xde, 0x95, 0xb9, 0x6b, 0x2d, 0x9f,
|
0x3c, 0x1d, 0xd0, 0xc7, 0x93, 0x88, 0x4f, 0xe2, 0x28, 0x18, 0xf6, 0x9c, 0xcb, 0x73, 0x57, 0x5b,
|
||||||
0xc9, 0x3e, 0x1c, 0xf1, 0x81, 0xea, 0x61, 0x57, 0x61, 0x55, 0x44, 0x12, 0x2e, 0x86, 0x34, 0x4a,
|
0x1e, 0x13, 0x75, 0xf8, 0xc5, 0x07, 0xb2, 0x86, 0x5d, 0x81, 0x15, 0x1e, 0x09, 0x9c, 0x8f, 0xe8,
|
||||||
0x4d, 0xb5, 0x52, 0x80, 0x71, 0x00, 0xff, 0x53, 0x0f, 0xd6, 0xdf, 0x8f, 0xc2, 0xfc, 0xc3, 0x60,
|
0x2b, 0xd9, 0x54, 0xb7, 0x80, 0xf1, 0x03, 0xf7, 0xcf, 0x1d, 0x58, 0x7b, 0x3f, 0x0a, 0xf2, 0x0f,
|
||||||
0x3c, 0x16, 0xb9, 0xde, 0xd3, 0x55, 0x58, 0x3d, 0x25, 0x00, 0xed, 0xe9, 0x34, 0x4e, 0x87, 0x6a,
|
0xfd, 0x30, 0xe4, 0xb9, 0x1a, 0xd3, 0x15, 0x58, 0x39, 0x21, 0x80, 0xc6, 0x74, 0x12, 0xa7, 0x23,
|
||||||
0x47, 0x2b, 0x12, 0xbc, 0xaf, 0xa0, 0x67, 0xae, 0xac, 0x71, 0xe6, 0xca, 0x6a, 0x8f, 0x6b, 0xae,
|
0x39, 0xa2, 0xae, 0x80, 0xf7, 0x24, 0x7a, 0x6a, 0xcf, 0x1a, 0xa7, 0xf6, 0xac, 0x76, 0xba, 0xe6,
|
||||||
0xfe, 0xb8, 0xf8, 0x26, 0x30, 0x7b, 0x71, 0xf2, 0x38, 0xf8, 0x97, 0x60, 0xe3, 0x49, 0x34, 0x8e,
|
0xea, 0xa7, 0xcb, 0xdd, 0x00, 0x66, 0x76, 0x4e, 0x4c, 0x87, 0xfb, 0x1e, 0xac, 0x3f, 0x8e, 0xc2,
|
||||||
0x07, 0x4f, 0x7f, 0xb6, 0x45, 0xf3, 0x2d, 0xd8, 0x74, 0xc7, 0x2b, 0xba, 0xdf, 0x6d, 0x40, 0xfb,
|
0x78, 0xf8, 0xe4, 0xa7, 0xeb, 0xb4, 0xbb, 0x09, 0x1b, 0xf6, 0xf7, 0x92, 0xef, 0x77, 0x1b, 0xd0,
|
||||||
0x71, 0x1a, 0x44, 0x59, 0x30, 0xc0, 0x2b, 0x67, 0x5d, 0x58, 0xcc, 0x9f, 0xf5, 0x8f, 0x83, 0xec,
|
0x7e, 0x94, 0xfa, 0x51, 0xe6, 0x0f, 0x71, 0xc9, 0x59, 0x0f, 0x16, 0xf3, 0xa7, 0x83, 0x23, 0x3f,
|
||||||
0x98, 0x08, 0xb5, 0x7c, 0xdd, 0x64, 0x5b, 0xb0, 0x10, 0x4c, 0xe2, 0x69, 0x94, 0xd3, 0xa9, 0xce,
|
0x3b, 0x22, 0x46, 0x2d, 0x4f, 0x15, 0xd9, 0x26, 0x2c, 0xf8, 0x93, 0x78, 0x1a, 0xe5, 0x34, 0xab,
|
||||||
0xf9, 0xaa, 0xc5, 0xde, 0x82, 0xf5, 0x68, 0x3a, 0xe9, 0x0f, 0xe2, 0xe8, 0x28, 0x4c, 0x27, 0x92,
|
0x73, 0x9e, 0x2c, 0xb1, 0x37, 0x61, 0x2d, 0x9a, 0x4e, 0x06, 0xc3, 0x38, 0x3a, 0x0c, 0xd2, 0x89,
|
||||||
0x71, 0x68, 0x73, 0xf3, 0x7e, 0xb5, 0x83, 0x5d, 0x06, 0x38, 0xc4, 0x65, 0xc8, 0x29, 0x9a, 0x34,
|
0x10, 0x1c, 0x1a, 0xdc, 0xbc, 0x57, 0xad, 0x60, 0x97, 0x00, 0x0e, 0xb0, 0x1b, 0xa2, 0x89, 0x26,
|
||||||
0x85, 0x05, 0x61, 0x1c, 0x3a, 0xaa, 0x25, 0xc2, 0xd1, 0x71, 0xde, 0x9d, 0x27, 0x42, 0x0e, 0x0c,
|
0x35, 0x61, 0x20, 0xcc, 0x85, 0x8e, 0x2c, 0xf1, 0x60, 0x7c, 0x94, 0xf7, 0xe6, 0x89, 0x91, 0x85,
|
||||||
0x69, 0xe4, 0xe1, 0x44, 0xf4, 0xb3, 0x3c, 0x98, 0x24, 0xdd, 0x05, 0x5a, 0x8d, 0x05, 0xa1, 0xfe,
|
0x21, 0x8f, 0x3c, 0x98, 0xf0, 0x41, 0x96, 0xfb, 0x93, 0xa4, 0xb7, 0x40, 0xbd, 0x31, 0x10, 0xaa,
|
||||||
0x38, 0x0f, 0xc6, 0xfd, 0x23, 0x21, 0xb2, 0xee, 0xa2, 0xea, 0x37, 0x10, 0xf6, 0x39, 0x58, 0x19,
|
0x8f, 0x73, 0x3f, 0x1c, 0x1c, 0x72, 0x9e, 0xf5, 0x16, 0x65, 0xbd, 0x46, 0xd8, 0x1b, 0xd0, 0x1d,
|
||||||
0x8a, 0x2c, 0xef, 0x07, 0xc3, 0x61, 0x2a, 0xb2, 0x4c, 0x64, 0xdd, 0x25, 0xba, 0xba, 0x12, 0x94,
|
0xf1, 0x2c, 0x1f, 0xf8, 0xa3, 0x51, 0xca, 0xb3, 0x8c, 0x67, 0xbd, 0x25, 0x5a, 0xba, 0x12, 0xea,
|
||||||
0x77, 0x61, 0xeb, 0x81, 0xc8, 0xad, 0xd3, 0xc9, 0xd4, 0xb1, 0xf3, 0x87, 0xc0, 0x2c, 0xf0, 0x5d,
|
0xf6, 0x60, 0xf3, 0x3e, 0xcf, 0x8d, 0xd9, 0xc9, 0xe4, 0xb4, 0xbb, 0x0f, 0x80, 0x19, 0xf0, 0x1d,
|
||||||
0x91, 0x07, 0xe1, 0x38, 0x63, 0xef, 0x40, 0x27, 0xb7, 0x90, 0x89, 0x55, 0xdb, 0xbb, 0xec, 0x3a,
|
0x9e, 0xfb, 0x41, 0x98, 0xb1, 0xb7, 0xa1, 0x93, 0x1b, 0xc4, 0x24, 0xaa, 0xed, 0x1d, 0x76, 0x8d,
|
||||||
0xc9, 0xd8, 0x75, 0x6b, 0x80, 0xef, 0xe0, 0xf1, 0xff, 0xf4, 0xa0, 0x7d, 0x20, 0x22, 0x23, 0x5d,
|
0x74, 0xec, 0x9a, 0xf1, 0x81, 0x67, 0xd1, 0xb9, 0xff, 0xed, 0x40, 0x7b, 0x9f, 0x47, 0x5a, 0xbb,
|
||||||
0x0c, 0x9a, 0xb8, 0x12, 0x75, 0x93, 0xf4, 0x9b, 0xbd, 0x0e, 0x6d, 0x5a, 0x5d, 0x96, 0xa7, 0x61,
|
0x18, 0x34, 0xb1, 0x27, 0x72, 0x25, 0xe9, 0x37, 0x7b, 0x15, 0xda, 0xd4, 0xbb, 0x2c, 0x4f, 0x83,
|
||||||
0x34, 0xa2, 0x2b, 0x68, 0xf9, 0x80, 0xa0, 0x03, 0x82, 0xb0, 0x35, 0x98, 0x0b, 0x26, 0x39, 0x1d,
|
0x68, 0x4c, 0x4b, 0xd0, 0xf2, 0x00, 0xa1, 0x7d, 0x42, 0xd8, 0x2a, 0xcc, 0xf9, 0x93, 0x9c, 0x26,
|
||||||
0xfc, 0x9c, 0x8f, 0x3f, 0x51, 0xee, 0x92, 0x60, 0x36, 0x11, 0x51, 0x5e, 0x1c, 0x76, 0xc7, 0x6f,
|
0x7e, 0xce, 0xc3, 0x9f, 0xa8, 0x77, 0x89, 0x3f, 0x9b, 0xf0, 0x28, 0x2f, 0x26, 0xbb, 0xe3, 0xb5,
|
||||||
0x2b, 0xd8, 0x1e, 0x9e, 0xf6, 0x75, 0xd8, 0xb0, 0x51, 0x34, 0xf5, 0x79, 0xa2, 0xbe, 0x6e, 0x61,
|
0x25, 0xb6, 0x8b, 0xb3, 0x7d, 0x0d, 0xd6, 0x4d, 0x12, 0xc5, 0x7d, 0x9e, 0xb8, 0xaf, 0x19, 0x94,
|
||||||
0xaa, 0x49, 0xae, 0xc2, 0xaa, 0xc6, 0x4f, 0xe5, 0x62, 0xe9, 0xf8, 0x5b, 0xfe, 0x8a, 0x02, 0xeb,
|
0xb2, 0x91, 0x2b, 0xb0, 0xa2, 0xe8, 0x53, 0xd1, 0x59, 0x9a, 0xfe, 0x96, 0xd7, 0x95, 0xb0, 0x1a,
|
||||||
0x2d, 0x5c, 0x83, 0xb5, 0xa3, 0x30, 0x0a, 0xc6, 0xfd, 0xc1, 0x38, 0x3f, 0xe9, 0x0f, 0xc5, 0x38,
|
0xc2, 0x55, 0x58, 0x3d, 0x0c, 0x22, 0x3f, 0x1c, 0x0c, 0xc3, 0xfc, 0x78, 0x30, 0xe2, 0x61, 0xee,
|
||||||
0x0f, 0xe8, 0x22, 0xe6, 0xfd, 0x15, 0x82, 0xdf, 0x19, 0xe7, 0x27, 0x77, 0x11, 0xca, 0xff, 0xd8,
|
0xd3, 0x42, 0xcc, 0x7b, 0x5d, 0xc2, 0x6f, 0x87, 0xf9, 0xf1, 0x1d, 0x44, 0xdd, 0x3f, 0x75, 0xa0,
|
||||||
0x83, 0x8e, 0xdc, 0xbc, 0x12, 0xfc, 0x37, 0x61, 0x59, 0xcf, 0x21, 0xd2, 0x34, 0x4e, 0x15, 0x1f,
|
0x23, 0x06, 0x2f, 0x15, 0xff, 0x75, 0x58, 0x56, 0x6d, 0xf0, 0x34, 0x8d, 0x53, 0x29, 0x87, 0x36,
|
||||||
0xba, 0x40, 0xb6, 0x0d, 0x6b, 0x1a, 0x90, 0xa4, 0x22, 0x9c, 0x04, 0x23, 0xa1, 0xa4, 0xbd, 0x02,
|
0xc8, 0xb6, 0x60, 0x55, 0x01, 0x49, 0xca, 0x83, 0x89, 0x3f, 0xe6, 0x52, 0xdb, 0x2b, 0x38, 0xdb,
|
||||||
0x67, 0xbb, 0x05, 0xc5, 0x34, 0x9e, 0xe6, 0x52, 0xf4, 0xda, 0xbb, 0x1d, 0x75, 0x31, 0x3e, 0xc2,
|
0x29, 0x38, 0xa6, 0xf1, 0x34, 0x17, 0xaa, 0xd7, 0xde, 0xe9, 0xc8, 0x85, 0xf1, 0x10, 0xf3, 0x6c,
|
||||||
0x7c, 0x17, 0x85, 0x7f, 0xdf, 0x83, 0xce, 0x9d, 0xe3, 0x20, 0x8a, 0xc4, 0x78, 0x3f, 0x0e, 0xa3,
|
0x12, 0xf7, 0x7b, 0x0e, 0x74, 0x6e, 0x1f, 0xf9, 0x51, 0xc4, 0xc3, 0xbd, 0x38, 0x88, 0x72, 0x76,
|
||||||
0x9c, 0xdd, 0x00, 0x76, 0x34, 0x8d, 0x86, 0x61, 0x34, 0xea, 0xe7, 0xcf, 0xc2, 0x61, 0xff, 0x70,
|
0x1d, 0xd8, 0xe1, 0x34, 0x1a, 0x05, 0xd1, 0x78, 0x90, 0x3f, 0x0d, 0x46, 0x83, 0x83, 0x59, 0xce,
|
||||||
0x96, 0x8b, 0x4c, 0x5e, 0xd1, 0xde, 0x39, 0xbf, 0xa6, 0x8f, 0xbd, 0x05, 0x6b, 0x0e, 0x34, 0xcb,
|
0x33, 0xb1, 0x44, 0xbb, 0x67, 0xbc, 0x9a, 0x3a, 0xf6, 0x26, 0xac, 0x5a, 0x68, 0x96, 0xa7, 0x62,
|
||||||
0x53, 0x79, 0x6f, 0x7b, 0xe7, 0xfc, 0x4a, 0x0f, 0x32, 0x7e, 0x3c, 0xcd, 0x93, 0x69, 0xde, 0x0f,
|
0xdd, 0x76, 0xcf, 0x78, 0x95, 0x1a, 0x14, 0xfc, 0x78, 0x9a, 0x27, 0xd3, 0x7c, 0x10, 0x44, 0x23,
|
||||||
0xa3, 0xa1, 0x78, 0x46, 0x6b, 0x5c, 0xf6, 0x1d, 0xd8, 0xed, 0x15, 0xe8, 0xd8, 0xe3, 0xf8, 0x97,
|
0xfe, 0x94, 0xfa, 0xb8, 0xec, 0x59, 0xd8, 0xad, 0x2e, 0x74, 0xcc, 0xef, 0xdc, 0xf7, 0x60, 0xf5,
|
||||||
0x60, 0xed, 0x21, 0x4a, 0x44, 0x14, 0x46, 0xa3, 0x5b, 0x92, 0x6d, 0x51, 0x4c, 0x93, 0xe9, 0xe1,
|
0x01, 0x6a, 0x44, 0x14, 0x44, 0xe3, 0x9b, 0x42, 0x6c, 0x51, 0x4d, 0x93, 0xe9, 0xc1, 0x13, 0x3e,
|
||||||
0x53, 0x31, 0x53, 0xe7, 0xa6, 0x5a, 0xc8, 0x54, 0xc7, 0x71, 0x96, 0x2b, 0xce, 0xa1, 0xdf, 0xfc,
|
0x93, 0xf3, 0x26, 0x4b, 0x28, 0x54, 0x47, 0x71, 0x96, 0x4b, 0xc9, 0xa1, 0xdf, 0xee, 0x3f, 0x3b,
|
||||||
0x1f, 0x3d, 0x58, 0xc5, 0xb3, 0xff, 0x20, 0x88, 0x66, 0xfa, 0xe6, 0x1e, 0x42, 0x07, 0x49, 0x3d,
|
0xb0, 0x82, 0x73, 0xff, 0x81, 0x1f, 0xcd, 0xd4, 0xca, 0x3d, 0x80, 0x0e, 0xb2, 0x7a, 0x14, 0xdf,
|
||||||
0x8e, 0x6f, 0x49, 0x61, 0x97, 0x4c, 0x7c, 0x4d, 0x9d, 0x55, 0x09, 0xfb, 0xba, 0x8d, 0x8a, 0xca,
|
0x14, 0xca, 0x2e, 0x84, 0xf8, 0xaa, 0x9c, 0xab, 0x12, 0xf5, 0x35, 0x93, 0x14, 0x8d, 0xf9, 0xcc,
|
||||||
0x7c, 0xe6, 0x3b, 0xa3, 0x91, 0x6d, 0xf3, 0x20, 0x1d, 0x89, 0x9c, 0xd4, 0x80, 0x52, 0x0b, 0x20,
|
0xb3, 0xbe, 0x46, 0xb1, 0xcd, 0xfd, 0x74, 0xcc, 0x73, 0x32, 0x03, 0xd2, 0x2c, 0x80, 0x80, 0x6e,
|
||||||
0x41, 0x77, 0xe2, 0xe8, 0x88, 0x5d, 0x81, 0x4e, 0x16, 0xe4, 0xfd, 0x44, 0xa4, 0x74, 0x6a, 0xc4,
|
0xc7, 0xd1, 0x21, 0xbb, 0x0c, 0x9d, 0xcc, 0xcf, 0x07, 0x09, 0x4f, 0x69, 0xd6, 0x48, 0xf4, 0xe6,
|
||||||
0x7a, 0x73, 0x3e, 0x64, 0x41, 0xbe, 0x2f, 0xd2, 0xdb, 0xb3, 0x5c, 0xf4, 0xbe, 0x0c, 0xeb, 0x95,
|
0x3c, 0xc8, 0xfc, 0x7c, 0x8f, 0xa7, 0xb7, 0x66, 0x39, 0xef, 0x7f, 0x19, 0xd6, 0x2a, 0xad, 0xa0,
|
||||||
0x59, 0x90, 0xdb, 0x8b, 0x2d, 0xe2, 0x4f, 0xb6, 0x09, 0xf3, 0x27, 0xc1, 0x78, 0x2a, 0x94, 0x76,
|
0xb4, 0x17, 0x43, 0xc4, 0x9f, 0x6c, 0x03, 0xe6, 0x8f, 0xfd, 0x70, 0xca, 0xa5, 0x75, 0x12, 0x85,
|
||||||
0x92, 0x8d, 0xf7, 0x1a, 0xef, 0x7a, 0xfc, 0x73, 0xb0, 0x56, 0x2c, 0x5b, 0x31, 0x19, 0x83, 0x26,
|
0x77, 0x1b, 0xef, 0x38, 0xee, 0x1b, 0xb0, 0x5a, 0x74, 0x5b, 0x0a, 0x19, 0x83, 0x26, 0xce, 0xa0,
|
||||||
0x9e, 0xa0, 0x22, 0x40, 0xbf, 0xf9, 0xef, 0x78, 0x12, 0xf1, 0x4e, 0x1c, 0x1a, 0x49, 0x47, 0x44,
|
0x64, 0x40, 0xbf, 0xdd, 0xdf, 0x73, 0x04, 0xe1, 0xed, 0x38, 0xd0, 0x9a, 0x8e, 0x84, 0x68, 0x10,
|
||||||
0x54, 0x08, 0x1a, 0x11, 0x7f, 0x9f, 0xa9, 0x09, 0x7f, 0xfe, 0xcd, 0xf2, 0xab, 0xb0, 0x6e, 0x2d,
|
0x14, 0x21, 0xfe, 0x3e, 0xd5, 0x12, 0xfe, 0xec, 0x83, 0x75, 0xaf, 0xc0, 0x9a, 0xd1, 0x85, 0xe7,
|
||||||
0xe1, 0x05, 0x8b, 0xfd, 0x8e, 0x07, 0xeb, 0x8f, 0xc4, 0xa9, 0xba, 0x75, 0xbd, 0xda, 0x77, 0xa1,
|
0x74, 0xf6, 0x3b, 0x0e, 0xac, 0x3d, 0xe4, 0x27, 0x72, 0xd5, 0x55, 0x6f, 0xdf, 0x81, 0x66, 0x3e,
|
||||||
0x99, 0xcf, 0x12, 0xf9, 0x14, 0xaf, 0xec, 0xbe, 0xa9, 0x2e, 0xad, 0x82, 0x77, 0x5d, 0x35, 0x1f,
|
0x4b, 0xc4, 0x56, 0xdc, 0xdd, 0x79, 0x5d, 0x2e, 0x5a, 0x85, 0xee, 0x9a, 0x2c, 0x3e, 0x9a, 0x25,
|
||||||
0xcf, 0x12, 0xe1, 0xd3, 0x08, 0xfe, 0x25, 0x68, 0x5b, 0x40, 0x76, 0x01, 0x36, 0x3e, 0x7c, 0xff,
|
0xdc, 0xa3, 0x2f, 0xdc, 0xf7, 0xa0, 0x6d, 0x80, 0xec, 0x1c, 0xac, 0x7f, 0xf8, 0xfe, 0xa3, 0x87,
|
||||||
0xf1, 0xa3, 0x7b, 0x07, 0x07, 0xfd, 0xfd, 0x27, 0xb7, 0xbf, 0x7a, 0xef, 0xd7, 0xfa, 0x7b, 0xb7,
|
0x77, 0xf7, 0xf7, 0x07, 0x7b, 0x8f, 0x6f, 0x7d, 0xf5, 0xee, 0x6f, 0x0c, 0x76, 0x6f, 0xee, 0xef,
|
||||||
0x0e, 0xf6, 0xd6, 0xce, 0xb1, 0x2d, 0x60, 0x8f, 0xee, 0x1d, 0x3c, 0xbe, 0x77, 0xd7, 0x81, 0x7b,
|
0xae, 0x9e, 0x61, 0x9b, 0xc0, 0x1e, 0xde, 0xdd, 0x7f, 0x74, 0xf7, 0x8e, 0x85, 0x3b, 0x6e, 0x1f,
|
||||||
0xbc, 0x07, 0xdd, 0x47, 0xe2, 0xf4, 0xc3, 0x30, 0x8f, 0x44, 0x96, 0xb9, 0xb3, 0xf1, 0xeb, 0xc0,
|
0x7a, 0x0f, 0xf9, 0xc9, 0x87, 0x41, 0x1e, 0xf1, 0x2c, 0xb3, 0x5b, 0x73, 0xaf, 0x01, 0x33, 0xbb,
|
||||||
0xec, 0x25, 0xa8, 0x5d, 0x75, 0x61, 0x51, 0xa9, 0x5a, 0xfd, 0xd2, 0xa8, 0x26, 0xff, 0x1c, 0xb0,
|
0x20, 0x47, 0xd5, 0x83, 0x45, 0x69, 0x6a, 0xd5, 0x4e, 0x23, 0x8b, 0xee, 0x1b, 0xc0, 0xf6, 0x83,
|
||||||
0x83, 0x70, 0x14, 0x7d, 0x20, 0xb2, 0x2c, 0x18, 0x09, 0xbd, 0xb7, 0x35, 0x98, 0x9b, 0x64, 0x23,
|
0x71, 0xf4, 0x01, 0xcf, 0x32, 0x7f, 0xcc, 0xd5, 0xd8, 0x56, 0x61, 0x6e, 0x92, 0x8d, 0xa5, 0x51,
|
||||||
0xa5, 0x14, 0xf1, 0x27, 0xff, 0x3c, 0x6c, 0x38, 0x78, 0x8a, 0xf0, 0x25, 0x68, 0x65, 0xe1, 0x28,
|
0xc4, 0x9f, 0xee, 0xe7, 0x61, 0xdd, 0xa2, 0x93, 0x8c, 0x2f, 0x42, 0x2b, 0x0b, 0xc6, 0x91, 0x9f,
|
||||||
0x0a, 0xf2, 0x69, 0x2a, 0x14, 0xe9, 0x02, 0xc0, 0xef, 0xc3, 0xe6, 0x37, 0x44, 0x1a, 0x1e, 0xcd,
|
0x4f, 0x53, 0x2e, 0x59, 0x17, 0x80, 0x7b, 0x0f, 0x36, 0xbe, 0xc1, 0xd3, 0xe0, 0x70, 0xf6, 0x22,
|
||||||
0x5e, 0x46, 0xde, 0xa5, 0xd3, 0x28, 0xd3, 0xb9, 0x07, 0xe7, 0x4b, 0x74, 0xd4, 0xf4, 0x92, 0x11,
|
0xf6, 0x36, 0x9f, 0x46, 0x99, 0xcf, 0x5d, 0x38, 0x5b, 0xe2, 0x23, 0x9b, 0x17, 0x82, 0x28, 0x97,
|
||||||
0xd5, 0x75, 0x2d, 0xf9, 0xb2, 0x61, 0x89, 0x65, 0xc3, 0x16, 0x4b, 0xfe, 0x04, 0xd8, 0x9d, 0x38,
|
0x6b, 0xc9, 0x13, 0x05, 0x43, 0x2d, 0x1b, 0xa6, 0x5a, 0xba, 0x8f, 0x81, 0xdd, 0x8e, 0xa3, 0x88,
|
||||||
0x8a, 0xc4, 0x20, 0xdf, 0x17, 0x22, 0x2d, 0xec, 0xab, 0x82, 0xeb, 0xda, 0xbb, 0x17, 0xd4, 0x3d,
|
0x0f, 0xf3, 0x3d, 0xce, 0xd3, 0xc2, 0xbf, 0x2a, 0xa4, 0xae, 0xbd, 0x73, 0x4e, 0xae, 0x63, 0x59,
|
||||||
0x96, 0x65, 0x5d, 0xb1, 0x23, 0x83, 0x66, 0x22, 0xd2, 0x09, 0x11, 0x5e, 0xf2, 0xe9, 0x37, 0x3f,
|
0xd7, 0xa5, 0x38, 0x32, 0x68, 0x26, 0x3c, 0x9d, 0x10, 0xe3, 0x25, 0x8f, 0x7e, 0xbb, 0x67, 0x61,
|
||||||
0x0f, 0x1b, 0x0e, 0x59, 0xf5, 0xda, 0xbf, 0x0d, 0xe7, 0xef, 0x86, 0xd9, 0xa0, 0x3a, 0x61, 0x17,
|
0xdd, 0x62, 0x2b, 0x77, 0xfb, 0xb7, 0xe0, 0xec, 0x9d, 0x20, 0x1b, 0x56, 0x1b, 0xec, 0xc1, 0x62,
|
||||||
0x16, 0x93, 0xe9, 0x61, 0xbf, 0x90, 0x29, 0xdd, 0xc4, 0x47, 0xb0, 0x3c, 0x44, 0x11, 0xfb, 0x7d,
|
0x32, 0x3d, 0x18, 0x14, 0x3a, 0xa5, 0x8a, 0xb8, 0x09, 0x96, 0x3f, 0x91, 0xcc, 0xfe, 0xd0, 0x81,
|
||||||
0x0f, 0x9a, 0x7b, 0x8f, 0x1f, 0xde, 0x61, 0x3d, 0x58, 0x0a, 0xa3, 0x41, 0x3c, 0xc1, 0xa7, 0x43,
|
0xe6, 0xee, 0xa3, 0x07, 0xb7, 0x59, 0x1f, 0x96, 0x82, 0x68, 0x18, 0x4f, 0x70, 0xeb, 0x10, 0x83,
|
||||||
0x6e, 0xda, 0xb4, 0xcf, 0x94, 0x95, 0x4b, 0xd0, 0xa2, 0x17, 0x07, 0xdf, 0x75, 0x65, 0x0a, 0x15,
|
0xd6, 0xe5, 0x53, 0x75, 0xe5, 0x22, 0xb4, 0x68, 0xc7, 0xc1, 0x7d, 0x5d, 0xba, 0x42, 0x05, 0x80,
|
||||||
0x00, 0xb4, 0x29, 0xc4, 0xb3, 0x24, 0x4c, 0xc9, 0x68, 0xd0, 0xa6, 0x40, 0x93, 0x34, 0x62, 0xb5,
|
0x3e, 0x05, 0x7f, 0x9a, 0x04, 0x29, 0x39, 0x0d, 0xca, 0x15, 0x68, 0x92, 0x45, 0xac, 0x56, 0xb8,
|
||||||
0x83, 0xff, 0x57, 0x13, 0x16, 0x95, 0xae, 0xa6, 0xf9, 0x06, 0x79, 0x78, 0x22, 0xd4, 0x4a, 0x54,
|
0xff, 0xd3, 0x84, 0x45, 0x69, 0xab, 0xa9, 0xbd, 0x61, 0x1e, 0x1c, 0x73, 0xd9, 0x13, 0x59, 0xc2,
|
||||||
0x0b, 0x5f, 0x95, 0x54, 0x4c, 0xe2, 0x5c, 0xf4, 0x9d, 0x6b, 0x70, 0x81, 0x88, 0x35, 0x90, 0x84,
|
0x5d, 0x25, 0xe5, 0x93, 0x38, 0xe7, 0x03, 0x6b, 0x19, 0x6c, 0x10, 0xa9, 0x86, 0x82, 0xd1, 0x20,
|
||||||
0xfa, 0x09, 0x6a, 0x7d, 0x5a, 0x59, 0xcb, 0x77, 0x81, 0x78, 0x58, 0x08, 0xe8, 0x87, 0x43, 0x5a,
|
0x41, 0xab, 0x4f, 0x3d, 0x6b, 0x79, 0x36, 0x88, 0x93, 0x85, 0xc0, 0x20, 0x18, 0x51, 0x9f, 0x9a,
|
||||||
0x53, 0xd3, 0xd7, 0x4d, 0x3c, 0x89, 0x41, 0x90, 0x04, 0x83, 0x30, 0x9f, 0x29, 0xe1, 0x36, 0x6d,
|
0x9e, 0x2a, 0xe2, 0x4c, 0x0c, 0xfd, 0xc4, 0x1f, 0x06, 0xf9, 0x4c, 0x2a, 0xb7, 0x2e, 0x23, 0xef,
|
||||||
0xa4, 0x3d, 0x8e, 0x07, 0xc1, 0xb8, 0x7f, 0x18, 0x8c, 0x83, 0x68, 0x20, 0x94, 0xe1, 0xe2, 0x02,
|
0x30, 0x1e, 0xfa, 0xe1, 0xe0, 0xc0, 0x0f, 0xfd, 0x68, 0xc8, 0xa5, 0xe3, 0x62, 0x83, 0xe8, 0x9b,
|
||||||
0xd1, 0x36, 0x51, 0x4b, 0xd2, 0x68, 0xd2, 0x7e, 0x29, 0x41, 0xd1, 0xc6, 0x19, 0xc4, 0x93, 0x49,
|
0xc8, 0x2e, 0x29, 0x32, 0xe1, 0xbf, 0x94, 0x50, 0xf4, 0x71, 0x86, 0xf1, 0x64, 0x12, 0xe4, 0xe8,
|
||||||
0x98, 0xa3, 0x49, 0xd3, 0x5d, 0x92, 0x8a, 0xa4, 0x80, 0xd0, 0x4e, 0x64, 0xeb, 0x54, 0x9e, 0x5e,
|
0xd2, 0xf4, 0x96, 0x84, 0x21, 0x29, 0x10, 0x1a, 0x89, 0x28, 0x9d, 0x88, 0xd9, 0x6b, 0x89, 0xd6,
|
||||||
0x4b, 0xce, 0xe6, 0x00, 0x91, 0xca, 0x91, 0x10, 0xa4, 0x90, 0x9e, 0x9e, 0x76, 0x41, 0x52, 0x29,
|
0x2c, 0x10, 0xb9, 0x1c, 0x72, 0x4e, 0x06, 0xe9, 0xc9, 0x49, 0x0f, 0x04, 0x97, 0x02, 0xc1, 0x75,
|
||||||
0x20, 0x78, 0x0f, 0xd3, 0x28, 0x13, 0x79, 0x3e, 0x16, 0x43, 0xb3, 0xa0, 0x36, 0xa1, 0x55, 0x3b,
|
0x98, 0x46, 0x19, 0xcf, 0xf3, 0x90, 0x8f, 0x74, 0x87, 0xda, 0x44, 0x56, 0xad, 0x60, 0xd7, 0x61,
|
||||||
0xd8, 0x0d, 0xd8, 0x90, 0x56, 0x56, 0x16, 0xe4, 0x71, 0x76, 0x1c, 0x66, 0xfd, 0x4c, 0x44, 0x79,
|
0x5d, 0x78, 0x59, 0x99, 0x9f, 0xc7, 0xd9, 0x51, 0x90, 0x0d, 0x32, 0x1e, 0xe5, 0xbd, 0x0e, 0xd1,
|
||||||
0xb7, 0x43, 0xf8, 0x75, 0x5d, 0xec, 0x5d, 0xb8, 0x50, 0x02, 0xa7, 0x62, 0x20, 0xc2, 0x13, 0x31,
|
0xd7, 0x55, 0xb1, 0x77, 0xe0, 0x5c, 0x09, 0x4e, 0xf9, 0x90, 0x07, 0xc7, 0x7c, 0xd4, 0x5b, 0xa6,
|
||||||
0xec, 0x2e, 0xd3, 0xa8, 0xb3, 0xba, 0xd9, 0x15, 0x68, 0xa3, 0x71, 0x39, 0x4d, 0x86, 0x01, 0xbe,
|
0xaf, 0x4e, 0xab, 0x66, 0x97, 0xa1, 0x8d, 0xce, 0xe5, 0x34, 0x19, 0xf9, 0xb8, 0x0f, 0x77, 0x69,
|
||||||
0xc3, 0x2b, 0x74, 0x0f, 0x36, 0x88, 0xbd, 0x0d, 0xcb, 0x89, 0x90, 0x8f, 0xe5, 0x71, 0x3e, 0x1e,
|
0x1d, 0x4c, 0x88, 0xbd, 0x05, 0xcb, 0x09, 0x17, 0x9b, 0xe5, 0x51, 0x1e, 0x0e, 0xb3, 0xde, 0x0a,
|
||||||
0x64, 0xdd, 0x55, 0x7a, 0xc9, 0xda, 0x4a, 0x98, 0x90, 0x73, 0x7d, 0x17, 0x03, 0x99, 0x72, 0x90,
|
0xed, 0x64, 0x6d, 0xa9, 0x4c, 0x28, 0xb9, 0x9e, 0x4d, 0x81, 0x42, 0x39, 0xcc, 0xc8, 0x5d, 0xf1,
|
||||||
0x91, 0xb9, 0x12, 0xcc, 0xba, 0x6b, 0xc4, 0x6e, 0x05, 0x80, 0x64, 0x24, 0x0d, 0x4f, 0x82, 0x5c,
|
0x67, 0xbd, 0x55, 0x12, 0xb7, 0x02, 0x20, 0x1d, 0x49, 0x83, 0x63, 0x3f, 0xe7, 0xbd, 0x35, 0x92,
|
||||||
0x74, 0xd7, 0x89, 0xb7, 0x74, 0x93, 0xff, 0x99, 0x07, 0x1b, 0x0f, 0xc3, 0x2c, 0x57, 0x4c, 0x68,
|
0x2d, 0x55, 0x74, 0xff, 0xd2, 0x81, 0xf5, 0x07, 0x41, 0x96, 0x4b, 0x21, 0xd4, 0xe6, 0xf8, 0x55,
|
||||||
0xd4, 0xf1, 0xeb, 0xd0, 0x96, 0xec, 0xd7, 0x8f, 0xa3, 0xf1, 0x4c, 0x71, 0x24, 0x48, 0xd0, 0xd7,
|
0x68, 0x0b, 0xf1, 0x1b, 0xc4, 0x51, 0x38, 0x93, 0x12, 0x09, 0x02, 0xfa, 0x5a, 0x14, 0xce, 0xd8,
|
||||||
0xa2, 0xf1, 0x8c, 0x7d, 0x16, 0x96, 0xc3, 0xc8, 0x46, 0x91, 0x32, 0xdc, 0xd1, 0x40, 0x42, 0x7a,
|
0xe7, 0x60, 0x39, 0x88, 0x4c, 0x12, 0xa1, 0xc3, 0x1d, 0x05, 0x12, 0xd1, 0xab, 0xd0, 0x4e, 0xa6,
|
||||||
0x1d, 0xda, 0xc9, 0xf4, 0x70, 0x1c, 0x0e, 0x24, 0xca, 0x9c, 0xa4, 0x22, 0x41, 0x84, 0x80, 0x86,
|
0x07, 0x61, 0x30, 0x14, 0x24, 0x73, 0x82, 0x8b, 0x80, 0x88, 0x00, 0x1d, 0x3d, 0xd1, 0x13, 0x41,
|
||||||
0x9e, 0x5c, 0x89, 0xc4, 0x68, 0x12, 0x46, 0x5b, 0xc1, 0x10, 0x85, 0xdf, 0x86, 0x4d, 0x77, 0x81,
|
0xd1, 0x24, 0x8a, 0xb6, 0xc4, 0x90, 0xc4, 0xbd, 0x05, 0x1b, 0x76, 0x07, 0xa5, 0xb1, 0xda, 0x82,
|
||||||
0x4a, 0x59, 0x6d, 0xc3, 0x92, 0xe2, 0xed, 0xac, 0xdb, 0xa6, 0xf3, 0x59, 0x51, 0xe7, 0xa3, 0x50,
|
0x25, 0x29, 0xdb, 0x59, 0xaf, 0x4d, 0xf3, 0xd3, 0x95, 0xf3, 0x23, 0x49, 0x3d, 0x5d, 0xef, 0xfe,
|
||||||
0x7d, 0xd3, 0xcf, 0xff, 0xd5, 0x83, 0x26, 0x2a, 0x80, 0xb3, 0x95, 0x85, 0xad, 0xd3, 0xe7, 0x1c,
|
0xbb, 0x03, 0x4d, 0x34, 0x00, 0xa7, 0x1b, 0x0b, 0xd3, 0xa6, 0xcf, 0x59, 0x36, 0x9d, 0xfc, 0x7e,
|
||||||
0x9d, 0x4e, 0x76, 0x3f, 0x5a, 0x45, 0x92, 0x25, 0xa4, 0xd8, 0x58, 0x90, 0xa2, 0x3f, 0x15, 0x83,
|
0xf4, 0x8a, 0x84, 0x48, 0x08, 0xb5, 0x31, 0x90, 0xa2, 0x3e, 0xe5, 0xc3, 0x63, 0xd2, 0x1d, 0x5d,
|
||||||
0x13, 0x92, 0x1d, 0xd3, 0x8f, 0x10, 0x94, 0x2c, 0x7c, 0x3a, 0x69, 0xb4, 0x14, 0x1c, 0xd3, 0xd6,
|
0x8f, 0x08, 0x6a, 0x16, 0x6e, 0x9d, 0xf4, 0xb5, 0x50, 0x1c, 0x5d, 0x56, 0x75, 0xf4, 0xe5, 0x62,
|
||||||
0x7d, 0x34, 0x72, 0xb1, 0xe8, 0xa3, 0x71, 0x5d, 0x58, 0x0c, 0xa3, 0xc3, 0x78, 0x1a, 0x0d, 0x49,
|
0x51, 0x47, 0xdf, 0xf5, 0x60, 0x31, 0x88, 0x0e, 0xe2, 0x69, 0x34, 0x22, 0x25, 0x59, 0xf2, 0x54,
|
||||||
0x48, 0x96, 0x7c, 0xdd, 0xc4, 0xcb, 0x4e, 0xc8, 0x92, 0x0a, 0x27, 0x42, 0x49, 0x47, 0x01, 0xe0,
|
0x11, 0x17, 0x3b, 0x21, 0x4f, 0x2a, 0x98, 0x70, 0xa9, 0x1d, 0x05, 0xe0, 0x32, 0x74, 0xad, 0x32,
|
||||||
0x0c, 0x4d, 0xab, 0x8c, 0x14, 0x9e, 0x79, 0xc7, 0xde, 0x81, 0x75, 0x0b, 0xa6, 0x4e, 0xf0, 0x0d,
|
0x32, 0x78, 0x7a, 0x1f, 0x7b, 0x1b, 0xd6, 0x0c, 0x4c, 0xce, 0xe0, 0x6b, 0x30, 0x9f, 0x20, 0x20,
|
||||||
0x98, 0x4f, 0x10, 0xa0, 0x0c, 0x25, 0xcd, 0x5e, 0xa4, 0x29, 0x65, 0x0f, 0x5f, 0x43, 0xff, 0x39,
|
0x1d, 0x25, 0x25, 0x5e, 0x64, 0x29, 0x45, 0x8d, 0xbb, 0x8a, 0xf1, 0x73, 0xfe, 0x7e, 0x74, 0x18,
|
||||||
0x7f, 0x3f, 0x3a, 0x8a, 0x35, 0xa5, 0x9f, 0xcc, 0xa1, 0xc3, 0xab, 0x40, 0x8a, 0xd0, 0x35, 0x58,
|
0x2b, 0x4e, 0x3f, 0x9a, 0xc3, 0x80, 0x57, 0x42, 0x92, 0xd1, 0x55, 0x58, 0x09, 0x46, 0x3c, 0xca,
|
||||||
0x0d, 0x87, 0x22, 0xca, 0xc3, 0x7c, 0xd6, 0x77, 0x2c, 0xb8, 0x32, 0x18, 0x5f, 0x98, 0x60, 0x1c,
|
0x83, 0x7c, 0x36, 0xb0, 0x3c, 0xb8, 0x32, 0x8c, 0x3b, 0x8c, 0x1f, 0x06, 0x7e, 0x26, 0x6d, 0x98,
|
||||||
0x06, 0x99, 0xd2, 0x61, 0xb2, 0xc1, 0x76, 0x61, 0x13, 0xd9, 0x5f, 0x73, 0xb4, 0xb9, 0x56, 0x69,
|
0x28, 0xb0, 0x1d, 0xd8, 0x40, 0xf1, 0x57, 0x12, 0xad, 0x97, 0x55, 0x38, 0x92, 0xb5, 0x75, 0xa8,
|
||||||
0x48, 0xd6, 0xf6, 0xa1, 0xc4, 0x22, 0x5c, 0x71, 0xa0, 0x19, 0x22, 0x35, 0x6d, 0x5d, 0x17, 0x9e,
|
0xb1, 0x88, 0x4b, 0x09, 0xd4, 0x9f, 0x08, 0x4b, 0x5b, 0x57, 0x85, 0xb3, 0x26, 0x38, 0xe1, 0x90,
|
||||||
0x9a, 0xa4, 0x84, 0x5b, 0x9e, 0x97, 0x22, 0x62, 0x00, 0x15, 0xef, 0x6d, 0x41, 0x1a, 0xb1, 0x65,
|
0xe7, 0x85, 0x8a, 0x68, 0xa0, 0x12, 0xbd, 0x2d, 0x08, 0x27, 0xb6, 0x1c, 0xbd, 0x19, 0x11, 0xe0,
|
||||||
0xef, 0xcd, 0xf2, 0x00, 0x97, 0x2a, 0x1e, 0xe0, 0x35, 0x58, 0xcd, 0x66, 0xd1, 0x40, 0x0c, 0xfb,
|
0x52, 0x25, 0x02, 0xbc, 0x0a, 0x2b, 0xd9, 0x2c, 0x1a, 0xf2, 0xd1, 0x20, 0x8f, 0xb1, 0xdd, 0x20,
|
||||||
0x79, 0x8c, 0xf3, 0x86, 0x11, 0xdd, 0xce, 0x92, 0x5f, 0x06, 0x93, 0xaf, 0x2a, 0xb2, 0x3c, 0x12,
|
0xa2, 0xd5, 0x59, 0xf2, 0xca, 0x30, 0xc5, 0xaa, 0x3c, 0xcb, 0x23, 0x9e, 0x93, 0xe9, 0x5a, 0xf2,
|
||||||
0x39, 0xa9, 0xae, 0x25, 0x5f, 0x37, 0xf1, 0x15, 0x20, 0x14, 0xc9, 0xd4, 0x2d, 0x5f, 0xb5, 0xf0,
|
0x54, 0x11, 0x77, 0x01, 0x22, 0x11, 0x42, 0xdd, 0xf2, 0x64, 0x09, 0xb7, 0xca, 0x69, 0x1a, 0x64,
|
||||||
0xa9, 0x9c, 0xa6, 0x61, 0xd6, 0xed, 0x10, 0x94, 0x7e, 0xb3, 0x2f, 0xc0, 0xf9, 0x43, 0xf4, 0xac,
|
0xbd, 0x0e, 0xa1, 0xf4, 0x9b, 0x7d, 0x01, 0xce, 0x1e, 0x60, 0x64, 0x75, 0xc4, 0xfd, 0x11, 0x4f,
|
||||||
0x8e, 0x45, 0x30, 0x14, 0x29, 0xdd, 0xbe, 0x74, 0x2c, 0xa5, 0x06, 0xaa, 0xef, 0xc4, 0xb9, 0x4f,
|
0x69, 0xf5, 0x45, 0x60, 0x29, 0x2c, 0x50, 0x7d, 0x25, 0xb6, 0x7d, 0xcc, 0xd3, 0x2c, 0x88, 0x23,
|
||||||
0x44, 0x9a, 0x85, 0x71, 0x44, 0xba, 0xa7, 0xe5, 0xeb, 0x26, 0xff, 0x84, 0x5e, 0x74, 0xe3, 0xf2,
|
0xb2, 0x3d, 0x2d, 0x4f, 0x15, 0xdd, 0x4f, 0x68, 0x47, 0xd7, 0x21, 0xef, 0x63, 0x32, 0x47, 0xec,
|
||||||
0x3e, 0x21, 0x75, 0xc4, 0x5e, 0x83, 0x96, 0xdc, 0x63, 0x76, 0x1c, 0x28, 0x23, 0x63, 0x89, 0x00,
|
0x02, 0xb4, 0xc4, 0x18, 0xb3, 0x23, 0x5f, 0x3a, 0x19, 0x4b, 0x04, 0xec, 0x1f, 0xf9, 0xa8, 0xc0,
|
||||||
0x07, 0xc7, 0x01, 0x0a, 0xb0, 0x73, 0x6c, 0x0d, 0xb2, 0x1c, 0xdb, 0x04, 0xdb, 0x93, 0xa7, 0xf6,
|
0xd6, 0xb4, 0x35, 0xc8, 0x73, 0x6c, 0x13, 0xb6, 0x2b, 0x66, 0xed, 0x75, 0xe8, 0xaa, 0x60, 0x3a,
|
||||||
0x26, 0xac, 0x68, 0x67, 0x3a, 0xeb, 0x8f, 0xc5, 0x51, 0xae, 0x1d, 0x84, 0x68, 0x3a, 0xc1, 0xe9,
|
0x1b, 0x84, 0xfc, 0x30, 0x57, 0x01, 0x42, 0x34, 0x9d, 0x60, 0x73, 0xd9, 0x03, 0x7e, 0x98, 0xbb,
|
||||||
0xb2, 0x87, 0xe2, 0x28, 0xe7, 0x8f, 0x60, 0x5d, 0xc9, 0xed, 0xd7, 0x12, 0xa1, 0xa7, 0xfe, 0xa5,
|
0x0f, 0x61, 0x4d, 0xea, 0xed, 0xd7, 0x12, 0xae, 0x9a, 0xfe, 0x52, 0x79, 0x53, 0x13, 0x5e, 0xc5,
|
||||||
0xf2, 0xa3, 0x26, 0xad, 0x8a, 0x0d, 0x57, 0xd0, 0xc9, 0xcb, 0x29, 0xbd, 0x74, 0xdc, 0x07, 0xa6,
|
0xba, 0xad, 0xe8, 0x14, 0xe5, 0x94, 0x76, 0x3a, 0xd7, 0x03, 0x26, 0xab, 0x6f, 0x87, 0x71, 0xc6,
|
||||||
0xba, 0xef, 0x8c, 0xe3, 0x4c, 0x28, 0x82, 0x1c, 0x3a, 0x83, 0x71, 0x9c, 0x69, 0x37, 0x44, 0x6d,
|
0x25, 0x43, 0x17, 0x3a, 0xc3, 0x30, 0xce, 0x54, 0x18, 0x22, 0x87, 0x63, 0x61, 0x38, 0x3f, 0xd9,
|
||||||
0xc7, 0x81, 0xe1, 0xf9, 0x64, 0xd3, 0xc1, 0x00, 0x35, 0x81, 0xd4, 0x69, 0xba, 0xc9, 0xff, 0xdc,
|
0x74, 0x38, 0x44, 0x4b, 0x20, 0x6c, 0x9a, 0x2a, 0xba, 0x7f, 0xe5, 0xc0, 0x3a, 0x71, 0x53, 0x16,
|
||||||
0x83, 0x0d, 0xa2, 0xa6, 0x35, 0x8c, 0xb1, 0x5d, 0x5f, 0x7d, 0x99, 0x9d, 0x81, 0xed, 0x9a, 0x6d,
|
0x46, 0xfb, 0xae, 0x2f, 0xdf, 0xcd, 0xce, 0xd0, 0x0c, 0xcd, 0x36, 0x60, 0xfe, 0x30, 0x4e, 0x87,
|
||||||
0xc2, 0xfc, 0x51, 0x9c, 0x0e, 0x84, 0x9a, 0x49, 0x36, 0x7e, 0x7a, 0x6b, 0xbc, 0x59, 0xb1, 0xc6,
|
0x5c, 0xb6, 0x24, 0x0a, 0x3f, 0xb9, 0x37, 0xde, 0xac, 0x78, 0xe3, 0x3f, 0x72, 0x60, 0x8d, 0xba,
|
||||||
0x7f, 0xe2, 0xc1, 0x3a, 0x2d, 0xf5, 0x20, 0x0f, 0xf2, 0x69, 0xa6, 0xb6, 0xff, 0xcb, 0xb0, 0x8c,
|
0xba, 0x9f, 0xfb, 0xf9, 0x34, 0x93, 0xc3, 0xff, 0x15, 0x58, 0xc6, 0xa1, 0x72, 0xa5, 0x4e, 0xb2,
|
||||||
0x5b, 0x15, 0x5a, 0x9c, 0xd4, 0x42, 0x37, 0x8d, 0xe4, 0x13, 0x54, 0x22, 0xef, 0x9d, 0xf3, 0x5d,
|
0xa3, 0x1b, 0x5a, 0xf3, 0x09, 0x15, 0xc4, 0xbb, 0x67, 0x3c, 0x9b, 0x98, 0x7d, 0x19, 0x3a, 0x66,
|
||||||
0x64, 0xf6, 0x65, 0xe8, 0xd8, 0x11, 0x11, 0x5a, 0x73, 0x7b, 0xf7, 0xa2, 0xde, 0x65, 0x85, 0x73,
|
0x46, 0x84, 0xfa, 0xdc, 0xde, 0x39, 0xaf, 0x46, 0x59, 0x91, 0x9c, 0xdd, 0x33, 0x9e, 0xf5, 0x01,
|
||||||
0xf6, 0xce, 0xf9, 0xce, 0x00, 0x76, 0x13, 0x80, 0xcc, 0x0d, 0x22, 0xab, 0x5c, 0xd9, 0x8b, 0xee,
|
0xbb, 0x01, 0x40, 0xee, 0x06, 0xb1, 0x95, 0xa1, 0xec, 0x79, 0x7b, 0x92, 0x8c, 0xc5, 0xda, 0x3d,
|
||||||
0x21, 0x59, 0x97, 0xb5, 0x77, 0xce, 0xb7, 0xd0, 0x6f, 0x2f, 0xc1, 0x82, 0x7c, 0x1f, 0xf9, 0x03,
|
0xe3, 0x19, 0xe4, 0xb7, 0x96, 0x60, 0x41, 0xec, 0x8f, 0xee, 0x7d, 0x58, 0xb6, 0x7a, 0x6a, 0x45,
|
||||||
0x58, 0x76, 0x56, 0xea, 0x78, 0x19, 0x1d, 0xe9, 0x65, 0x54, 0x9c, 0xd2, 0x46, 0xd5, 0x29, 0xe5,
|
0x19, 0x1d, 0x11, 0x65, 0x54, 0x82, 0xd2, 0x46, 0x35, 0x28, 0x75, 0xff, 0xb5, 0x01, 0x0c, 0xa5,
|
||||||
0xff, 0xdc, 0x00, 0x86, 0xdc, 0x56, 0xba, 0x4e, 0x7c, 0xa0, 0xe3, 0xa1, 0x63, 0x6e, 0x75, 0x7c,
|
0xad, 0xb4, 0x9c, 0xb8, 0x41, 0xc7, 0x23, 0xcb, 0xdd, 0xea, 0x78, 0x26, 0xc4, 0xae, 0x01, 0x33,
|
||||||
0x1b, 0xc4, 0xae, 0x03, 0xb3, 0x9a, 0x3a, 0xf6, 0x20, 0xdf, 0x8d, 0x9a, 0x1e, 0x54, 0x70, 0xd2,
|
0x8a, 0x2a, 0xf7, 0x20, 0xf6, 0x8d, 0x9a, 0x1a, 0x34, 0x70, 0xc2, 0x57, 0x52, 0x31, 0xb0, 0x74,
|
||||||
0x56, 0xd2, 0x3e, 0xb0, 0x32, 0x2c, 0xe5, 0xbd, 0xd5, 0xf6, 0xe1, 0xd3, 0x90, 0x4c, 0xb3, 0x63,
|
0x2c, 0xc5, 0xba, 0xd5, 0xd6, 0xe1, 0xd6, 0x90, 0x4c, 0xb3, 0x23, 0x74, 0x20, 0x94, 0x43, 0xa6,
|
||||||
0x34, 0x20, 0xb4, 0x41, 0xa6, 0xdb, 0x65, 0x06, 0x59, 0x78, 0x29, 0x83, 0x2c, 0x96, 0x19, 0xc4,
|
0xca, 0x65, 0x01, 0x59, 0x78, 0xa1, 0x80, 0x2c, 0x96, 0x05, 0xc4, 0x74, 0x09, 0x96, 0x2c, 0x97,
|
||||||
0x36, 0x09, 0x96, 0x1c, 0x93, 0x00, 0xed, 0xaf, 0x49, 0x18, 0x91, 0x5d, 0xd1, 0x9f, 0xe0, 0xec,
|
0x00, 0xfd, 0xaf, 0x49, 0x10, 0x91, 0x5f, 0x31, 0x98, 0x60, 0xeb, 0xd2, 0xff, 0xb2, 0x40, 0xb6,
|
||||||
0xca, 0xfe, 0x72, 0x80, 0x6c, 0x1b, 0xd6, 0x94, 0x5d, 0x57, 0xd8, 0x1d, 0x40, 0x67, 0x5c, 0x81,
|
0x05, 0xab, 0xd2, 0xaf, 0x2b, 0xfc, 0x0e, 0xa0, 0x39, 0xae, 0xe0, 0xee, 0x67, 0x0e, 0xac, 0xe2,
|
||||||
0xf3, 0x1f, 0x7b, 0xb0, 0x86, 0xe7, 0xec, 0xf0, 0xe2, 0x7b, 0x40, 0xa2, 0xf0, 0x8a, 0xac, 0xe8,
|
0x3c, 0x5b, 0xb2, 0xf8, 0x2e, 0x90, 0x2a, 0xbc, 0xa4, 0x28, 0x5a, 0xb4, 0x3f, 0xbb, 0x24, 0xbe,
|
||||||
0xe0, 0xfe, 0xfc, 0x9c, 0xf8, 0x2e, 0xb4, 0x88, 0x60, 0x9c, 0x88, 0x48, 0x31, 0x62, 0xd7, 0x65,
|
0x03, 0x2d, 0x62, 0x18, 0x27, 0x3c, 0x92, 0x82, 0xd8, 0xb3, 0x05, 0xb1, 0xb0, 0x42, 0xbb, 0x67,
|
||||||
0xc4, 0x42, 0x0b, 0xed, 0x9d, 0xf3, 0x0b, 0x64, 0x8b, 0x0d, 0xff, 0xce, 0x83, 0xb6, 0x5a, 0xe6,
|
0xbc, 0x82, 0xd8, 0x10, 0xc3, 0x7f, 0x70, 0xa0, 0x2d, 0xbb, 0xf9, 0x53, 0xc7, 0x12, 0x7d, 0x58,
|
||||||
0xcf, 0xec, 0x4b, 0xf4, 0x60, 0x09, 0x39, 0xd2, 0x32, 0xd8, 0x4d, 0x1b, 0x5f, 0x93, 0x09, 0x3a,
|
0x42, 0x89, 0x34, 0x1c, 0x76, 0x5d, 0xc6, 0xdd, 0x64, 0x82, 0x01, 0x1b, 0x6e, 0x9f, 0x56, 0x1c,
|
||||||
0x6c, 0xf8, 0x7c, 0x3a, 0x7e, 0x44, 0x19, 0x8c, 0x6f, 0x21, 0x29, 0xdc, 0xac, 0x9f, 0x87, 0xe3,
|
0x51, 0x86, 0x71, 0x2f, 0x24, 0x83, 0x9b, 0x0d, 0xf2, 0x20, 0x1c, 0xa8, 0x5a, 0x99, 0x80, 0xac,
|
||||||
0xbe, 0xee, 0x55, 0x01, 0xc8, 0xba, 0x2e, 0xd4, 0x3b, 0x59, 0x1e, 0x8c, 0x84, 0x7a, 0xe6, 0x64,
|
0xab, 0x42, 0xbb, 0x93, 0xe5, 0xfe, 0x98, 0xcb, 0x6d, 0x4e, 0x14, 0x30, 0x60, 0x92, 0x03, 0x2a,
|
||||||
0x03, 0x1d, 0x26, 0xb5, 0xa1, 0x92, 0x39, 0xc8, 0x7f, 0x04, 0x70, 0xa1, 0xd2, 0x65, 0xc2, 0xdd,
|
0xb9, 0x83, 0xee, 0x0f, 0x01, 0xce, 0x55, 0xaa, 0x74, 0xba, 0x5b, 0x3a, 0xc8, 0x61, 0x30, 0x39,
|
||||||
0xca, 0x40, 0x1e, 0x87, 0x93, 0xc3, 0xd8, 0xd8, 0xda, 0x9e, 0x6d, 0x3b, 0x3b, 0x5d, 0x6c, 0x04,
|
0x88, 0xb5, 0xaf, 0xed, 0x98, 0xbe, 0xb3, 0x55, 0xc5, 0xc6, 0x70, 0x56, 0xed, 0xe7, 0x38, 0xa7,
|
||||||
0xe7, 0xf5, 0x7b, 0x8e, 0x67, 0x5a, 0xbc, 0xde, 0x0d, 0x32, 0x44, 0xde, 0x76, 0x79, 0xa0, 0x3c,
|
0xc5, 0xee, 0xdd, 0x20, 0x47, 0xe4, 0x2d, 0x5b, 0x06, 0xca, 0x0d, 0x2a, 0xdc, 0xd4, 0xdc, 0x7a,
|
||||||
0xa1, 0x86, 0xdb, 0x92, 0x5b, 0x4f, 0x8f, 0x1d, 0x43, 0xd7, 0x18, 0x0e, 0x4a, 0xc5, 0x5b, 0xc6,
|
0x7e, 0xec, 0x08, 0x7a, 0xda, 0x71, 0x90, 0x26, 0xde, 0x70, 0x2e, 0xb0, 0xad, 0x37, 0x5f, 0xd0,
|
||||||
0x05, 0xce, 0xf5, 0xd6, 0x4b, 0xe6, 0x22, 0x7d, 0x34, 0xd4, 0xd3, 0x9c, 0x49, 0x8d, 0xcd, 0xe0,
|
0x16, 0xd9, 0xa3, 0x91, 0x6a, 0xe6, 0x54, 0x6e, 0x6c, 0x06, 0x97, 0x54, 0x1d, 0xd9, 0xf0, 0x6a,
|
||||||
0xb2, 0xee, 0x23, 0x1d, 0x5e, 0x9d, 0xaf, 0xf9, 0x4a, 0x7b, 0xbb, 0x8f, 0x83, 0xdd, 0x49, 0x5f,
|
0x7b, 0xcd, 0x97, 0x1a, 0xdb, 0x3d, 0xfc, 0xd8, 0x6e, 0xf4, 0x05, 0x8c, 0xfb, 0x3f, 0x74, 0xa0,
|
||||||
0x42, 0xb8, 0xf7, 0x23, 0x0f, 0x56, 0x5c, 0x72, 0xc8, 0x3a, 0x4a, 0x08, 0xb5, 0x32, 0xd2, 0x06,
|
0x6b, 0xb3, 0x43, 0xd1, 0x91, 0x4a, 0xa8, 0x8c, 0x91, 0x72, 0xc8, 0x4a, 0x70, 0x35, 0x6c, 0x6c,
|
||||||
0x59, 0x09, 0x5c, 0x75, 0x1b, 0x1b, 0x75, 0x6e, 0xa3, 0xed, 0x1c, 0xce, 0xbd, 0xcc, 0x39, 0x6c,
|
0xd4, 0x85, 0x8d, 0x66, 0x70, 0x38, 0xf7, 0xa2, 0xe0, 0xb0, 0xf9, 0x72, 0xc1, 0xe1, 0x7c, 0x5d,
|
||||||
0xbe, 0x9a, 0x73, 0x38, 0x5f, 0xe7, 0x1c, 0xf6, 0xfe, 0xc3, 0x03, 0x56, 0xbd, 0x5f, 0xf6, 0x40,
|
0x70, 0xd8, 0xff, 0x2f, 0x07, 0x58, 0x75, 0x7d, 0xd9, 0x7d, 0x11, 0xb7, 0x46, 0x3c, 0x94, 0x76,
|
||||||
0xfa, 0xad, 0x91, 0x18, 0x2b, 0x3d, 0xf1, 0x0b, 0xaf, 0xc6, 0x23, 0xfa, 0x0c, 0xf5, 0x68, 0x64,
|
0xe2, 0x97, 0x5e, 0x4e, 0x46, 0xd4, 0x1c, 0xaa, 0xaf, 0x51, 0x58, 0x4d, 0x43, 0x60, 0xba, 0x2d,
|
||||||
0x56, 0x5b, 0x11, 0xd8, 0x66, 0xcb, 0xb2, 0x5f, 0xd7, 0x55, 0x72, 0x57, 0x9b, 0x2f, 0x77, 0x57,
|
0xcb, 0x5e, 0x5d, 0x55, 0x29, 0x5c, 0x6d, 0xbe, 0x38, 0x5c, 0x9d, 0x7f, 0x71, 0xb8, 0xba, 0x50,
|
||||||
0xe7, 0x5f, 0xee, 0xae, 0x2e, 0x94, 0xdd, 0xd5, 0xde, 0x6f, 0xc1, 0xb2, 0x73, 0xeb, 0xff, 0x73,
|
0x0e, 0x57, 0xfb, 0xbf, 0x03, 0xcb, 0xd6, 0xaa, 0xff, 0xdf, 0x8d, 0xb8, 0xec, 0xf2, 0x88, 0x05,
|
||||||
0x3b, 0x2e, 0x9b, 0x3c, 0xf2, 0x82, 0x1d, 0x58, 0xef, 0xdf, 0x1a, 0xc0, 0xaa, 0x9c, 0xf7, 0x7f,
|
0xb6, 0xb0, 0xfe, 0x8f, 0x1b, 0xc0, 0xaa, 0x92, 0xf7, 0x73, 0xed, 0x03, 0xc9, 0x91, 0x65, 0x40,
|
||||||
0xba, 0x06, 0xe2, 0x23, 0x47, 0x81, 0xcc, 0x29, 0x3e, 0x72, 0x54, 0xc7, 0xff, 0xa6, 0x52, 0x7c,
|
0xe6, 0xa4, 0x1c, 0x59, 0xa6, 0xe3, 0xff, 0xd3, 0x28, 0xbe, 0x09, 0x6b, 0x29, 0x1f, 0xc6, 0xc7,
|
||||||
0x0b, 0xd6, 0x53, 0x31, 0x88, 0x4f, 0x28, 0x09, 0xe7, 0x86, 0x3a, 0xaa, 0x1d, 0x68, 0xf4, 0xb9,
|
0x74, 0x08, 0x67, 0xa7, 0x3a, 0xaa, 0x15, 0xe8, 0xf4, 0xd9, 0x41, 0xfa, 0x92, 0x75, 0x66, 0x62,
|
||||||
0x4e, 0xfa, 0x92, 0x93, 0x33, 0xb1, 0x5e, 0x86, 0x92, 0xaf, 0xce, 0xb7, 0x60, 0x53, 0xa6, 0xb2,
|
0xec, 0x0c, 0xa5, 0x58, 0xdd, 0xdd, 0x84, 0x0d, 0x71, 0x94, 0x75, 0x4b, 0xb0, 0x52, 0x46, 0xf6,
|
||||||
0x6e, 0x4b, 0x52, 0x5a, 0xc9, 0x7e, 0xcf, 0x83, 0xf3, 0xa5, 0x8e, 0x22, 0xb1, 0x20, 0xf5, 0xa8,
|
0x2f, 0x1c, 0x38, 0x5b, 0xaa, 0x28, 0x0e, 0x16, 0x84, 0x1d, 0xb5, 0x8d, 0xab, 0x0d, 0x62, 0xff,
|
||||||
0xab, 0x5c, 0x5d, 0x20, 0xae, 0x5f, 0x31, 0xb0, 0xb5, 0x7e, 0xf9, 0xde, 0x54, 0x3b, 0xf0, 0x7c,
|
0xa5, 0x00, 0x1b, 0xfd, 0x17, 0xfb, 0x4d, 0xb5, 0x02, 0xe7, 0x67, 0x1a, 0x55, 0xe9, 0xc5, 0xac,
|
||||||
0xa6, 0x51, 0x15, 0x5f, 0x9e, 0x7a, 0x5d, 0x17, 0xbf, 0x00, 0xe7, 0xd5, 0xcd, 0x96, 0x16, 0x7e,
|
0xd7, 0x55, 0xb9, 0xe7, 0xe0, 0xac, 0x5c, 0xd9, 0x52, 0xc7, 0x0f, 0x61, 0xb3, 0x5c, 0x51, 0x64,
|
||||||
0x04, 0x5b, 0xe5, 0x8e, 0x22, 0x52, 0xea, 0x2e, 0x59, 0x37, 0xd1, 0x24, 0x72, 0x74, 0xb6, 0xbb,
|
0x4a, 0xed, 0x2e, 0xab, 0x22, 0xba, 0x44, 0x96, 0xcd, 0xb6, 0xfb, 0x5b, 0x5b, 0xe7, 0xfe, 0x36,
|
||||||
0xde, 0xda, 0x3e, 0xfe, 0x9b, 0xc0, 0xbe, 0x3e, 0x15, 0xe9, 0x8c, 0xd2, 0x1e, 0x26, 0x54, 0x71,
|
0xb0, 0xaf, 0x4f, 0x79, 0x3a, 0xa3, 0x63, 0x0f, 0x9d, 0xaa, 0x38, 0x57, 0x8e, 0xe9, 0x17, 0x92,
|
||||||
0xa1, 0xec, 0xd3, 0x2f, 0x24, 0xd3, 0xc3, 0xaf, 0x8a, 0x99, 0xce, 0x2b, 0x35, 0x8a, 0xbc, 0xd2,
|
0xe9, 0xc1, 0x57, 0xf9, 0x4c, 0x9d, 0x2b, 0x35, 0x8a, 0x73, 0xa5, 0x57, 0x00, 0x30, 0x14, 0xa1,
|
||||||
0x67, 0x00, 0xd0, 0x15, 0xa1, 0x3c, 0x89, 0xce, 0xf4, 0xa1, 0x0f, 0x28, 0x09, 0xf2, 0x9b, 0xb0,
|
0x73, 0x12, 0x75, 0xd2, 0x87, 0x31, 0xa0, 0x60, 0xe8, 0xde, 0x80, 0x75, 0x8b, 0xbf, 0x9e, 0xfd,
|
||||||
0xe1, 0xd0, 0x37, 0xa7, 0xbf, 0xa0, 0x46, 0x48, 0x47, 0xd9, 0xcd, 0xbe, 0xa8, 0x3e, 0xfe, 0xef,
|
0x05, 0xf9, 0x85, 0x08, 0x94, 0xed, 0xd3, 0x17, 0x59, 0xe7, 0xfe, 0x87, 0x03, 0x73, 0xbb, 0x71,
|
||||||
0x1e, 0xcc, 0xed, 0xc5, 0x89, 0x1d, 0x62, 0xf3, 0xdc, 0x10, 0x9b, 0xd2, 0xb5, 0x7d, 0xa3, 0x4a,
|
0x62, 0xa6, 0xd8, 0x1c, 0x3b, 0xc5, 0x26, 0x6d, 0xed, 0x40, 0x9b, 0xd2, 0x86, 0xb4, 0x14, 0x26,
|
||||||
0x1b, 0x4a, 0x53, 0xd8, 0x40, 0xb6, 0x0d, 0x2b, 0xc1, 0x24, 0x47, 0x57, 0xf1, 0x28, 0x4e, 0x4f,
|
0xc8, 0xb6, 0xa0, 0xeb, 0x4f, 0x72, 0x0c, 0x15, 0x0f, 0xe3, 0xf4, 0xc4, 0x4f, 0x47, 0x62, 0x49,
|
||||||
0x83, 0x74, 0x28, 0xaf, 0xe4, 0x76, 0xa3, 0xeb, 0xf9, 0xa5, 0x1e, 0xb6, 0x09, 0x73, 0x46, 0x29,
|
0x6e, 0x35, 0x7a, 0x8e, 0x57, 0xaa, 0x61, 0x1b, 0x30, 0xa7, 0x8d, 0x12, 0x11, 0x60, 0x11, 0x9d,
|
||||||
0x11, 0x02, 0x36, 0xd1, 0xd8, 0xa0, 0x48, 0xe3, 0x4c, 0x79, 0xb9, 0xaa, 0x85, 0x37, 0xee, 0x8e,
|
0x0d, 0xca, 0x34, 0xce, 0x64, 0x94, 0x2b, 0x4b, 0xb8, 0xe2, 0xf6, 0xf7, 0xc2, 0xbd, 0x13, 0x12,
|
||||||
0x97, 0xe6, 0x9d, 0xe4, 0xf0, 0xba, 0x2e, 0xd4, 0xfb, 0xa8, 0xa3, 0x08, 0x4d, 0x85, 0x27, 0x74,
|
0x5e, 0x57, 0x85, 0x76, 0x1f, 0x6d, 0x14, 0x91, 0xc9, 0xf4, 0x84, 0x2a, 0xbb, 0xff, 0xe6, 0xc0,
|
||||||
0x9b, 0xff, 0x8b, 0x07, 0xf3, 0x74, 0x02, 0x28, 0x93, 0x92, 0x11, 0x29, 0x91, 0x49, 0x61, 0x51,
|
0x3c, 0xcd, 0x00, 0xea, 0xa4, 0x10, 0x44, 0x3a, 0xc8, 0xa4, 0xb4, 0xa8, 0x23, 0x74, 0xb2, 0x04,
|
||||||
0x4f, 0xca, 0x64, 0x09, 0xcc, 0xb8, 0x93, 0xde, 0x6c, 0x98, 0x65, 0xdb, 0x29, 0xce, 0x2b, 0xd0,
|
0x33, 0xd7, 0x3a, 0xde, 0x6c, 0xe8, 0x6e, 0x9b, 0x47, 0x9c, 0x97, 0xa1, 0x25, 0x4a, 0xfa, 0x4c,
|
||||||
0x92, 0x2d, 0x93, 0x13, 0x24, 0x94, 0x02, 0xc8, 0x2e, 0x43, 0xf3, 0x38, 0x4e, 0xf4, 0x8b, 0x0a,
|
0x90, 0x48, 0x0a, 0x90, 0x5d, 0x82, 0xe6, 0x51, 0x9c, 0xa8, 0x1d, 0x15, 0x54, 0x56, 0x2c, 0x4e,
|
||||||
0x3a, 0x2a, 0x16, 0x27, 0x3e, 0xc1, 0x8b, 0xf5, 0x20, 0x3d, 0xb9, 0x78, 0xa9, 0x93, 0xcb, 0x60,
|
0x3c, 0xc2, 0x8b, 0xfe, 0x20, 0x3f, 0xd1, 0x79, 0x61, 0x93, 0xcb, 0x30, 0xee, 0x4a, 0x9a, 0xad,
|
||||||
0x7c, 0x95, 0x0c, 0x59, 0xfb, 0x30, 0x4a, 0x50, 0xbe, 0x0d, 0xab, 0x8f, 0xe2, 0xa1, 0xb0, 0xe2,
|
0x39, 0x19, 0x25, 0xd4, 0xdd, 0x82, 0x95, 0x87, 0xf1, 0x88, 0x1b, 0x79, 0x90, 0x53, 0xa5, 0xce,
|
||||||
0x20, 0x67, 0x72, 0x1d, 0xff, 0x6d, 0x0f, 0x96, 0x34, 0x32, 0xbb, 0x06, 0x4d, 0x7c, 0x6a, 0x4b,
|
0xfd, 0x5d, 0x07, 0x96, 0x14, 0x31, 0xbb, 0x0a, 0x4d, 0xdc, 0x6a, 0x4b, 0xce, 0xad, 0xce, 0x86,
|
||||||
0xc6, 0xad, 0x89, 0x86, 0x23, 0x9e, 0x4f, 0x18, 0xa8, 0x22, 0xc9, 0x4b, 0x2e, 0x4c, 0x21, 0xed,
|
0x23, 0x9d, 0x47, 0x14, 0x68, 0x22, 0x29, 0x4a, 0x2e, 0x5c, 0x21, 0x15, 0x23, 0x17, 0x4e, 0x86,
|
||||||
0x23, 0x17, 0x46, 0x86, 0x59, 0x6e, 0xe9, 0x31, 0x2e, 0x41, 0xf9, 0x5f, 0x78, 0xb0, 0xec, 0xcc,
|
0xee, 0x6e, 0x69, 0x33, 0x2e, 0xa1, 0xee, 0x5f, 0x3b, 0xb0, 0x6c, 0xb5, 0x81, 0x21, 0x4d, 0xe8,
|
||||||
0x81, 0x2e, 0xcd, 0x38, 0xc8, 0x72, 0x15, 0x61, 0x54, 0xd7, 0x63, 0x83, 0xec, 0xc8, 0x58, 0xc3,
|
0x67, 0xb9, 0xcc, 0x30, 0xca, 0xe5, 0x31, 0x21, 0x33, 0x33, 0xd6, 0xb0, 0x33, 0x63, 0x3a, 0x67,
|
||||||
0x8d, 0x8c, 0x99, 0x98, 0xcd, 0x9c, 0x1d, 0xb3, 0xb9, 0x01, 0xad, 0x22, 0x09, 0xdd, 0x74, 0x54,
|
0x33, 0x67, 0xe6, 0x6c, 0xae, 0x43, 0xab, 0x38, 0x84, 0x6e, 0x5a, 0xa6, 0x0f, 0x5b, 0x54, 0x79,
|
||||||
0x1f, 0xce, 0xa8, 0xe3, 0xfc, 0x05, 0x12, 0xd2, 0x19, 0xc4, 0xe3, 0x38, 0x55, 0x39, 0x5a, 0xd9,
|
0xfe, 0x82, 0x08, 0xf9, 0x0c, 0xe3, 0x30, 0x4e, 0xe5, 0x19, 0xad, 0x28, 0xb8, 0x37, 0xa0, 0x6d,
|
||||||
0xe0, 0x37, 0xa1, 0x6d, 0xe1, 0xe3, 0x32, 0x22, 0x91, 0x9f, 0xc6, 0xe9, 0x53, 0x1d, 0xa0, 0x53,
|
0xd0, 0x63, 0x37, 0x22, 0x9e, 0x9f, 0xc4, 0xe9, 0x13, 0x95, 0xa0, 0x93, 0x45, 0x7d, 0x9c, 0xd5,
|
||||||
0x4d, 0x93, 0xce, 0x6a, 0x14, 0xe9, 0x2c, 0xfe, 0x97, 0x1e, 0x2c, 0x23, 0x0f, 0x86, 0xd1, 0x68,
|
0x28, 0x8e, 0xb3, 0xdc, 0xbf, 0x71, 0x60, 0x19, 0x65, 0x30, 0x88, 0xc6, 0x7b, 0x71, 0x18, 0x0c,
|
||||||
0x3f, 0x1e, 0x87, 0x83, 0x19, 0xdd, 0xbd, 0x66, 0x37, 0x95, 0xbc, 0xd5, 0xbc, 0xe8, 0x82, 0x91,
|
0x67, 0xb4, 0xf6, 0x4a, 0xdc, 0xe4, 0xe1, 0xad, 0x92, 0x45, 0x1b, 0x46, 0xd9, 0x56, 0x11, 0x8d,
|
||||||
0xb7, 0xb5, 0x47, 0xa3, 0x04, 0xd1, 0xb4, 0x51, 0x52, 0x91, 0xcf, 0x0f, 0x83, 0x4c, 0x31, 0xbf,
|
0x54, 0x44, 0x5d, 0x46, 0x4d, 0x45, 0x39, 0x3f, 0xf0, 0x33, 0x29, 0xfc, 0x72, 0x2f, 0xb2, 0x40,
|
||||||
0x7a, 0x8b, 0x1c, 0x20, 0xca, 0x13, 0x02, 0xd2, 0x20, 0x17, 0xfd, 0x49, 0x38, 0x1e, 0x87, 0x12,
|
0xd4, 0x27, 0x04, 0x52, 0x3f, 0xe7, 0x83, 0x49, 0x10, 0x86, 0x81, 0xa0, 0x15, 0x2e, 0x42, 0x5d,
|
||||||
0x57, 0x9a, 0x08, 0x75, 0x5d, 0xfc, 0x87, 0x0d, 0x68, 0x2b, 0x4d, 0x79, 0x6f, 0x38, 0x92, 0xa1,
|
0x95, 0xfb, 0x83, 0x06, 0xb4, 0xa5, 0xa5, 0xbc, 0x3b, 0x1a, 0x8b, 0x54, 0xb8, 0x74, 0xb4, 0xb4,
|
||||||
0x70, 0x65, 0x68, 0x19, 0x75, 0x61, 0x41, 0x74, 0xbf, 0x63, 0x9a, 0x59, 0x90, 0xf2, 0xb5, 0xce,
|
0xb9, 0x30, 0x10, 0x55, 0x6f, 0xb9, 0x66, 0x06, 0x52, 0x5e, 0xd6, 0xb9, 0xea, 0xb2, 0x5e, 0x84,
|
||||||
0x55, 0xaf, 0xf5, 0x12, 0xb4, 0x90, 0xbd, 0xde, 0x26, 0x1b, 0x50, 0xd6, 0x2c, 0x14, 0x00, 0xdd,
|
0x16, 0x8a, 0xd7, 0x5b, 0xe4, 0x03, 0x8a, 0x3b, 0x0b, 0x05, 0xa0, 0x6a, 0x77, 0xa8, 0x76, 0xbe,
|
||||||
0xbb, 0x4b, 0xbd, 0xf3, 0x45, 0x2f, 0x01, 0x1c, 0xab, 0x6f, 0xa1, 0x64, 0xf5, 0xbd, 0x0b, 0x1d,
|
0xa8, 0x25, 0xc0, 0xf2, 0xfa, 0x16, 0x4a, 0x5e, 0xdf, 0x3b, 0xd0, 0x91, 0x6c, 0x68, 0xde, 0xc9,
|
||||||
0x45, 0x86, 0xce, 0x9d, 0xb4, 0x43, 0xc1, 0xe0, 0xce, 0x9d, 0xf8, 0x0e, 0xa6, 0x1e, 0xb9, 0xab,
|
0x3a, 0x14, 0x02, 0x6e, 0xad, 0x89, 0x67, 0x51, 0xaa, 0x2f, 0x77, 0xd4, 0x97, 0x4b, 0x2f, 0xfa,
|
||||||
0x47, 0x2e, 0xbd, 0x6c, 0xa4, 0xc6, 0xa4, 0xcc, 0x90, 0x3c, 0x9b, 0x07, 0x69, 0x90, 0x1c, 0xeb,
|
0x52, 0x51, 0xd2, 0xc9, 0x90, 0x98, 0x9b, 0xfb, 0xa9, 0x9f, 0x1c, 0xa9, 0xdd, 0x67, 0xa4, 0x8f,
|
||||||
0xd7, 0x67, 0x68, 0xd2, 0xdd, 0x04, 0x66, 0xdb, 0x30, 0x8f, 0xc3, 0xb4, 0xb6, 0xae, 0x17, 0x3a,
|
0xbb, 0x09, 0x66, 0x5b, 0x30, 0x8f, 0x9f, 0x29, 0x6b, 0x5d, 0xaf, 0x74, 0x82, 0x84, 0x5d, 0x85,
|
||||||
0x89, 0xc2, 0xae, 0xc1, 0xbc, 0x18, 0x8e, 0x84, 0xf6, 0x3c, 0x98, 0xeb, 0x03, 0xe2, 0x1d, 0xf9,
|
0x79, 0x3e, 0x1a, 0x73, 0x15, 0x79, 0x30, 0x3b, 0x06, 0xc4, 0x35, 0xf2, 0x04, 0x01, 0x9a, 0x00,
|
||||||
0x12, 0x01, 0x55, 0x00, 0x42, 0x4b, 0x2a, 0xc0, 0xd5, 0xf4, 0x0b, 0xd8, 0x7c, 0x7f, 0xc8, 0x37,
|
0x44, 0x4b, 0x26, 0xc0, 0xb6, 0xf4, 0x0b, 0x58, 0x7c, 0x7f, 0xe4, 0x6e, 0x00, 0x7b, 0x28, 0xa4,
|
||||||
0x81, 0x3d, 0x92, 0x5c, 0x6b, 0x47, 0x4e, 0x7f, 0x6f, 0x0e, 0xda, 0x16, 0x18, 0xa5, 0x79, 0x84,
|
0xd6, 0xcc, 0x9c, 0xfe, 0xc1, 0x1c, 0xb4, 0x0d, 0x18, 0xb5, 0x79, 0x8c, 0x1d, 0x1e, 0x8c, 0x02,
|
||||||
0x0b, 0xee, 0x0f, 0xc3, 0x60, 0x22, 0x72, 0x91, 0x2a, 0x4e, 0x2d, 0x41, 0x11, 0x2f, 0x38, 0x19,
|
0x7f, 0xc2, 0x73, 0x9e, 0x4a, 0x49, 0x2d, 0xa1, 0x48, 0xe7, 0x1f, 0x8f, 0x07, 0xf1, 0x34, 0x1f,
|
||||||
0xf5, 0xe3, 0x69, 0xde, 0x1f, 0x8a, 0x51, 0x2a, 0xe4, 0x1b, 0x89, 0x8f, 0x81, 0x03, 0x45, 0xbc,
|
0x8c, 0xf8, 0x38, 0xe5, 0x62, 0x8f, 0xc4, 0xcd, 0xc0, 0x42, 0x91, 0x6e, 0xe2, 0x3f, 0x35, 0xe9,
|
||||||
0x49, 0xf0, 0xcc, 0xc6, 0x93, 0xfc, 0x50, 0x82, 0xea, 0x38, 0xa8, 0x3c, 0xa3, 0x66, 0x11, 0x07,
|
0x84, 0x3c, 0x94, 0x50, 0x95, 0x07, 0x15, 0x73, 0xd4, 0x2c, 0xf2, 0xa0, 0x62, 0x46, 0xca, 0x76,
|
||||||
0x95, 0x27, 0x52, 0xd6, 0x43, 0xf3, 0x35, 0x7a, 0xe8, 0x1d, 0xd8, 0x92, 0x1a, 0x47, 0xc9, 0x66,
|
0x68, 0xbe, 0xc6, 0x0e, 0xbd, 0x0d, 0x9b, 0xc2, 0xe2, 0x48, 0xdd, 0x1c, 0x94, 0xc4, 0xe4, 0x94,
|
||||||
0xbf, 0xc4, 0x26, 0x67, 0xf4, 0xb2, 0x6d, 0x58, 0xc3, 0x35, 0x6b, 0x06, 0xcf, 0xc2, 0x4f, 0x64,
|
0x5a, 0xb6, 0x05, 0xab, 0xd8, 0x67, 0x25, 0xe0, 0x59, 0xf0, 0x89, 0xc8, 0x4c, 0x38, 0x5e, 0x05,
|
||||||
0x64, 0xc2, 0xf3, 0x2b, 0x70, 0xc4, 0x45, 0x71, 0x74, 0x70, 0x65, 0xae, 0xa8, 0x02, 0x27, 0xdc,
|
0x47, 0x5a, 0x54, 0x47, 0x8b, 0x56, 0x9c, 0x15, 0x55, 0x70, 0xa2, 0xf5, 0x9f, 0xda, 0xb4, 0x2d,
|
||||||
0xe0, 0x99, 0x8b, 0xdb, 0x52, 0xb8, 0x25, 0x38, 0x5f, 0x86, 0xf6, 0x41, 0x1e, 0x27, 0xfa, 0x52,
|
0x49, 0x5b, 0xc2, 0xdd, 0x65, 0x68, 0xef, 0xe7, 0x71, 0xa2, 0x16, 0xa5, 0x0b, 0x1d, 0x51, 0x94,
|
||||||
0x56, 0xa0, 0x23, 0x9b, 0x2a, 0x33, 0xf8, 0x1a, 0x5c, 0x24, 0x2e, 0x7a, 0x1c, 0x27, 0xf1, 0x38,
|
0x27, 0x83, 0x17, 0xe0, 0x3c, 0x49, 0xd1, 0xa3, 0x38, 0x89, 0xc3, 0x78, 0x3c, 0xdb, 0x9f, 0x1e,
|
||||||
0x1e, 0xcd, 0x0e, 0xa6, 0x87, 0xd9, 0x20, 0x0d, 0x13, 0xf4, 0x08, 0xf8, 0xdf, 0x7a, 0xb0, 0xe1,
|
0x64, 0xc3, 0x34, 0x48, 0x30, 0x22, 0x70, 0xff, 0xde, 0x81, 0x75, 0xab, 0x56, 0xa6, 0x32, 0xbe,
|
||||||
0xf4, 0xaa, 0x50, 0xc6, 0x17, 0x24, 0x4b, 0x9b, 0x94, 0x8e, 0x64, 0xbc, 0x75, 0x4b, 0x1d, 0x4a,
|
0x20, 0x44, 0x5a, 0x1f, 0xe9, 0x08, 0xc1, 0x5b, 0x33, 0xcc, 0xa1, 0x20, 0x14, 0x49, 0xa4, 0xc7,
|
||||||
0x44, 0x19, 0x44, 0x7a, 0xa2, 0xb2, 0x3c, 0xb7, 0x60, 0x55, 0xaf, 0x4c, 0x0f, 0x94, 0x5c, 0xd8,
|
0xf2, 0x94, 0xe7, 0x26, 0xac, 0xa8, 0x9e, 0xa9, 0x0f, 0x85, 0x14, 0xf6, 0xaa, 0x52, 0x28, 0xbf,
|
||||||
0xad, 0x72, 0xa1, 0x1a, 0xbf, 0xa2, 0x06, 0x68, 0x12, 0xbf, 0x22, 0xed, 0x6a, 0x31, 0xa4, 0x3d,
|
0xef, 0xca, 0x0f, 0x14, 0x8b, 0x5f, 0x15, 0x7e, 0x35, 0x1f, 0xd1, 0x18, 0x55, 0x4c, 0xdb, 0x57,
|
||||||
0x6a, 0x9f, 0xb6, 0xa7, 0xc7, 0xdb, 0xc6, 0xbc, 0x5e, 0xc1, 0xc0, 0x00, 0x33, 0xfe, 0x07, 0x1e,
|
0xdf, 0x9b, 0xce, 0xbc, 0xea, 0xc1, 0x50, 0x83, 0x99, 0xfb, 0x47, 0x0e, 0x40, 0xd1, 0x3b, 0x14,
|
||||||
0x40, 0xb1, 0x3a, 0x64, 0x8c, 0x42, 0xa5, 0xcb, 0x62, 0x35, 0x4b, 0x7d, 0xbf, 0x01, 0x1d, 0x13,
|
0x8c, 0xc2, 0xa4, 0x8b, 0xcb, 0x6a, 0x86, 0xf9, 0x7e, 0x0d, 0x3a, 0x3a, 0x9b, 0x5f, 0xec, 0x12,
|
||||||
0xcd, 0x2f, 0x5e, 0x89, 0xb6, 0x86, 0xa1, 0xc1, 0x75, 0x15, 0x56, 0x47, 0xe3, 0xf8, 0x90, 0x9e,
|
0x6d, 0x85, 0xa1, 0xc3, 0x75, 0x05, 0x56, 0xc6, 0x61, 0x7c, 0x40, 0x5b, 0x2c, 0x1d, 0x35, 0x67,
|
||||||
0x58, 0x4a, 0x35, 0x67, 0x2a, 0x3f, 0xba, 0x22, 0xc1, 0xf7, 0x15, 0xb4, 0x78, 0x52, 0x9a, 0xd6,
|
0xf2, 0x7c, 0xb4, 0x2b, 0xe0, 0x7b, 0x12, 0x2d, 0xb6, 0x94, 0xa6, 0xb1, 0xa5, 0xb8, 0xdf, 0x69,
|
||||||
0x93, 0xc2, 0xbf, 0xd3, 0x30, 0x31, 0xe0, 0x62, 0xcf, 0x67, 0x4a, 0x19, 0xdb, 0xad, 0x28, 0xc7,
|
0xe8, 0x1c, 0x70, 0x31, 0xe6, 0x53, 0xb5, 0x8c, 0xed, 0x54, 0x8c, 0xe3, 0x29, 0x29, 0x57, 0xca,
|
||||||
0x33, 0x42, 0xae, 0x14, 0xbd, 0xd9, 0x7f, 0xa9, 0x23, 0x7b, 0x13, 0x56, 0x52, 0xa9, 0x7d, 0xb4,
|
0xde, 0xec, 0xbd, 0x30, 0x90, 0xbd, 0x01, 0xdd, 0x54, 0x58, 0x1f, 0x65, 0x9a, 0x9a, 0xcf, 0x31,
|
||||||
0x6a, 0x6a, 0xbe, 0x40, 0x35, 0x2d, 0xa7, 0xce, 0xbb, 0xf3, 0xff, 0x60, 0x2d, 0x18, 0x9e, 0x88,
|
0x4d, 0xcb, 0xa9, 0xb5, 0xef, 0xfc, 0x02, 0xac, 0xfa, 0xa3, 0x63, 0x9e, 0xe6, 0x01, 0x45, 0x34,
|
||||||
0x34, 0x0f, 0xc9, 0xa3, 0xa1, 0x47, 0x5f, 0x2a, 0xd4, 0x55, 0x0b, 0x4e, 0x6f, 0xf1, 0x55, 0x58,
|
0xb4, 0xe9, 0x0b, 0x83, 0xba, 0x62, 0xe0, 0xb4, 0x17, 0x5f, 0x81, 0x15, 0x79, 0x26, 0xad, 0x29,
|
||||||
0x55, 0x39, 0x69, 0x83, 0xa9, 0x2a, 0x91, 0x0a, 0x30, 0x22, 0xf2, 0x1f, 0xe8, 0x70, 0xb3, 0x7b,
|
0xe5, 0x4d, 0xa4, 0x02, 0x46, 0x42, 0xf7, 0xfb, 0x2a, 0xdd, 0x6c, 0xaf, 0xe1, 0xe9, 0x33, 0x62,
|
||||||
0x87, 0x67, 0x9f, 0x88, 0xbd, 0xbb, 0x46, 0x69, 0x77, 0x9f, 0x55, 0xa1, 0xdf, 0xa1, 0x76, 0x9b,
|
0x8e, 0xae, 0x51, 0x1a, 0xdd, 0xe7, 0x64, 0xea, 0x77, 0xa4, 0xc2, 0x26, 0x99, 0x84, 0x17, 0xa0,
|
||||||
0x54, 0x10, 0x5e, 0x02, 0x55, 0xa8, 0xde, 0x3d, 0xd2, 0xe6, 0xab, 0x1c, 0x29, 0xff, 0xde, 0x1c,
|
0x4c, 0xd5, 0xdb, 0x53, 0xda, 0x7c, 0x99, 0x29, 0x75, 0x3f, 0x73, 0x60, 0x71, 0x37, 0x4e, 0x76,
|
||||||
0x2c, 0xbe, 0x1f, 0x9d, 0xc4, 0xe1, 0x80, 0x02, 0xb1, 0x13, 0x31, 0x89, 0x75, 0xb9, 0x07, 0xfe,
|
0xe5, 0xf1, 0x32, 0x29, 0x82, 0xbe, 0xf1, 0xa1, 0x8a, 0xa6, 0x57, 0xdc, 0xa8, 0x78, 0xc5, 0xd5,
|
||||||
0xc6, 0x17, 0x9d, 0x52, 0x9f, 0x49, 0xae, 0x22, 0xa9, 0xba, 0x89, 0xaf, 0x5b, 0x5a, 0x94, 0x40,
|
0xbd, 0x76, 0xb9, 0xbc, 0xd7, 0xfe, 0x1a, 0x5c, 0xa0, 0x68, 0x39, 0x8d, 0x93, 0x38, 0x45, 0x65,
|
||||||
0x49, 0x4e, 0xb1, 0x20, 0x68, 0xc7, 0xa6, 0x76, 0xfd, 0x97, 0x6a, 0x15, 0xf5, 0x32, 0xf3, 0x56,
|
0xf4, 0x43, 0xb1, 0xb1, 0xc6, 0x51, 0x7e, 0xa4, 0xcc, 0xd8, 0xf3, 0x48, 0x28, 0x3a, 0x0a, 0xf3,
|
||||||
0xbd, 0x0c, 0x85, 0xed, 0x65, 0x56, 0x97, 0x8e, 0x73, 0xc9, 0xd7, 0x4d, 0xb2, 0xbb, 0x53, 0x21,
|
0xe3, 0x81, 0x70, 0x86, 0xa5, 0x6f, 0x20, 0xac, 0x5b, 0xb5, 0xc2, 0xfd, 0x12, 0xb4, 0xc8, 0xb9,
|
||||||
0x9d, 0x7a, 0x7a, 0x27, 0x17, 0x95, 0xdd, 0x6d, 0x03, 0xf1, 0x2d, 0x95, 0x03, 0x24, 0x8e, 0xd4,
|
0xa5, 0x61, 0xbd, 0x09, 0xad, 0xa3, 0x38, 0x19, 0x1c, 0x05, 0x51, 0xae, 0x94, 0xbb, 0x5b, 0x78,
|
||||||
0x35, 0x36, 0x08, 0x6d, 0x8b, 0x72, 0x09, 0x59, 0x4b, 0x5e, 0x71, 0x09, 0x8c, 0x0a, 0x69, 0x28,
|
0x9d, 0xbb, 0x34, 0x21, 0x9a, 0xc0, 0xfd, 0xf1, 0x1c, 0x2c, 0xbe, 0x1f, 0x1d, 0xc7, 0xc1, 0x90,
|
||||||
0x8c, 0xde, 0x90, 0x7b, 0x00, 0x59, 0xe2, 0x55, 0x86, 0x5b, 0xd6, 0xba, 0xcc, 0x4e, 0x6b, 0x6b,
|
0x32, 0xd3, 0x13, 0x3e, 0x89, 0xd5, 0xfd, 0x17, 0xfc, 0x8d, 0x53, 0x41, 0x67, 0xc1, 0x49, 0x2e,
|
||||||
0x1d, 0x6d, 0x90, 0x60, 0x3c, 0x3e, 0x0c, 0x06, 0x4f, 0xa9, 0xb0, 0x8f, 0x92, 0xd1, 0x2d, 0xdf,
|
0x53, 0xcb, 0xaa, 0x88, 0xdb, 0x7d, 0x5a, 0xdc, 0x09, 0x13, 0xaa, 0x63, 0x20, 0xe8, 0xd8, 0xa7,
|
||||||
0x05, 0xe2, 0xaa, 0xa9, 0x4e, 0x4d, 0x91, 0x58, 0x96, 0xc9, 0x64, 0x0b, 0xc4, 0xbf, 0x01, 0xec,
|
0xe6, 0x85, 0x38, 0x59, 0x2a, 0x2e, 0x10, 0xcd, 0x1b, 0x17, 0x88, 0xe8, 0x1c, 0x43, 0x1c, 0x73,
|
||||||
0xd6, 0x70, 0xa8, 0x6e, 0xc8, 0xf8, 0x34, 0xc5, 0xd9, 0x7a, 0xce, 0xd9, 0xd6, 0xec, 0xb1, 0x51,
|
0x93, 0x7c, 0x2d, 0x79, 0xaa, 0x48, 0x81, 0x48, 0xca, 0x45, 0x96, 0x83, 0x1c, 0x87, 0x45, 0x19,
|
||||||
0xbb, 0x47, 0x7e, 0x0f, 0xda, 0xfb, 0x56, 0x3d, 0x1e, 0x5d, 0xa6, 0xae, 0xc4, 0x53, 0x0c, 0x60,
|
0x88, 0x98, 0x20, 0x3a, 0x17, 0xe2, 0x03, 0x41, 0x23, 0x8c, 0xaf, 0x09, 0xa1, 0xb3, 0x55, 0xbe,
|
||||||
0x41, 0xac, 0x09, 0x1b, 0xf6, 0x84, 0xfc, 0x17, 0x81, 0x3d, 0x0c, 0xb3, 0xdc, 0xac, 0x4f, 0x1e,
|
0x53, 0xd7, 0x12, 0x32, 0x5f, 0x82, 0xd1, 0x42, 0x8f, 0xb8, 0x36, 0xa4, 0x62, 0x0c, 0x20, 0xee,
|
||||||
0xe0, 0x1b, 0xd0, 0x31, 0x1e, 0x60, 0x91, 0x7f, 0x6e, 0x2b, 0x18, 0xe5, 0x85, 0x6f, 0xc9, 0xc4,
|
0xbc, 0x95, 0x71, 0x23, 0x7c, 0x11, 0xc7, 0xf5, 0x2a, 0x7c, 0x41, 0x41, 0xf1, 0xc3, 0xf0, 0xc0,
|
||||||
0x75, 0x79, 0x63, 0xdb, 0xb0, 0x14, 0x4a, 0x90, 0xd6, 0xc3, 0x3a, 0x2d, 0xac, 0x31, 0x4d, 0x3f,
|
0x1f, 0x3e, 0xa1, 0x9b, 0x8e, 0x74, 0x3a, 0xdf, 0xf2, 0x6c, 0x10, 0x7b, 0x6d, 0xac, 0x26, 0x9d,
|
||||||
0x1a, 0x14, 0x0a, 0xe8, 0xa8, 0xf9, 0x1f, 0x7a, 0xb0, 0xa8, 0xb6, 0x86, 0xcf, 0xa1, 0x53, 0x89,
|
0x84, 0x35, 0x3d, 0x13, 0x62, 0x3b, 0xd0, 0xa6, 0x90, 0x4d, 0xae, 0x67, 0x97, 0xd6, 0x73, 0xd5,
|
||||||
0x28, 0x37, 0xe6, 0xc0, 0xea, 0xeb, 0xb7, 0xaa, 0x5c, 0x37, 0x57, 0xc7, 0x75, 0x0c, 0x9a, 0x49,
|
0x8c, 0xe9, 0x68, 0x45, 0x4d, 0x22, 0x33, 0x5b, 0xbe, 0x62, 0x1f, 0xa0, 0x7f, 0x03, 0xd8, 0xcd,
|
||||||
0x90, 0x1f, 0x93, 0x05, 0xdd, 0xf2, 0xe9, 0x37, 0xfa, 0xad, 0xe8, 0xd5, 0x49, 0xee, 0x26, 0x8f,
|
0xd1, 0x48, 0xae, 0xb7, 0x0e, 0x19, 0x8b, 0x95, 0x72, 0xac, 0x95, 0xaa, 0x99, 0xb1, 0x46, 0xed,
|
||||||
0xae, 0xae, 0x64, 0x50, 0xea, 0x8c, 0x0a, 0x1c, 0x37, 0x45, 0xa9, 0x5e, 0x09, 0x37, 0x11, 0x5c,
|
0x8c, 0xb9, 0x77, 0xa1, 0xbd, 0x67, 0x5c, 0x77, 0x24, 0xd1, 0x50, 0x17, 0x1d, 0xa5, 0x38, 0x19,
|
||||||
0x95, 0x46, 0x2f, 0xc0, 0xc5, 0x79, 0x29, 0x12, 0xe5, 0xf3, 0x52, 0xa8, 0xbe, 0xe9, 0xe7, 0x3d,
|
0x88, 0xd1, 0x60, 0xc3, 0x6c, 0xd0, 0xfd, 0x65, 0x60, 0x0f, 0x82, 0x2c, 0xd7, 0xfd, 0x13, 0xcb,
|
||||||
0xe8, 0xde, 0x15, 0x63, 0x91, 0x8b, 0x5b, 0xe3, 0x71, 0x99, 0xfe, 0x6b, 0x70, 0xb1, 0xa6, 0x4f,
|
0xf1, 0x1a, 0x74, 0x74, 0x80, 0x5d, 0x1c, 0xef, 0xb7, 0x25, 0x46, 0xc7, 0xee, 0x37, 0xc5, 0xbd,
|
||||||
0xbd, 0xaa, 0xf7, 0x61, 0xfd, 0xae, 0x38, 0x9c, 0x8e, 0x1e, 0x8a, 0x93, 0x22, 0xcd, 0xc2, 0xa0,
|
0x80, 0xf2, 0xc0, 0xb6, 0x60, 0x29, 0x10, 0x50, 0x59, 0x13, 0x14, 0xa5, 0xae, 0x47, 0x7f, 0x4d,
|
||||||
0x99, 0x1d, 0xc7, 0xa7, 0xea, 0x6e, 0xe9, 0x37, 0x3a, 0xe8, 0x63, 0xc4, 0xe9, 0x67, 0x89, 0x18,
|
0x82, 0xd6, 0x2e, 0xfa, 0x03, 0x07, 0x16, 0xe5, 0xd0, 0xd0, 0xdb, 0xb0, 0x2e, 0x7a, 0x8a, 0x81,
|
||||||
0xe8, 0xca, 0x25, 0x82, 0x1c, 0x24, 0x62, 0xc0, 0xdf, 0x01, 0x66, 0xd3, 0x51, 0x5b, 0x40, 0xc9,
|
0x59, 0x58, 0xfd, 0xf5, 0xb8, 0xaa, 0x0c, 0xcf, 0xd5, 0xc9, 0x30, 0x83, 0x66, 0xe2, 0xe7, 0x47,
|
||||||
0x9d, 0x1e, 0xf6, 0xb3, 0x59, 0x96, 0x8b, 0x89, 0x2e, 0xc9, 0xb2, 0x41, 0xfc, 0x2a, 0x74, 0xf6,
|
0x14, 0xa0, 0xb4, 0x3c, 0xfa, 0xcd, 0x56, 0x45, 0xd0, 0x2c, 0x74, 0x85, 0x02, 0xe6, 0xba, 0x1b,
|
||||||
0x83, 0x99, 0x2f, 0x3e, 0x56, 0xc5, 0xa0, 0xe8, 0xbc, 0x05, 0x33, 0x64, 0x65, 0xe3, 0xbc, 0x51,
|
0x99, 0xc2, 0x24, 0x57, 0x70, 0x1c, 0x14, 0x9d, 0xa4, 0x0b, 0x5c, 0x27, 0xc8, 0xe5, 0x2d, 0x85,
|
||||||
0x37, 0xff, 0x9b, 0x06, 0x2c, 0x48, 0x4c, 0xa4, 0x3a, 0x14, 0x59, 0x1e, 0x46, 0x32, 0xc5, 0xa0,
|
0x02, 0x2e, 0xe6, 0x4b, 0xb2, 0x28, 0xcf, 0x97, 0x24, 0xf5, 0x74, 0xbd, 0xdb, 0x87, 0xde, 0x1d,
|
||||||
0xa8, 0x5a, 0xa0, 0x0a, 0x6f, 0x34, 0x6a, 0x78, 0x43, 0x99, 0x53, 0xba, 0x0a, 0x44, 0x31, 0x81,
|
0x1e, 0xf2, 0x9c, 0xdf, 0x0c, 0xc3, 0x32, 0xff, 0x0b, 0x70, 0xbe, 0xa6, 0x4e, 0x3a, 0x2d, 0xf7,
|
||||||
0x03, 0xc3, 0x77, 0xb7, 0x48, 0xdd, 0x4a, 0xef, 0xa1, 0x00, 0x94, 0xbc, 0xf9, 0x42, 0x3f, 0xc8,
|
0x60, 0xed, 0x0e, 0x3f, 0x98, 0x8e, 0x1f, 0xf0, 0xe3, 0xe2, 0x14, 0x8b, 0x41, 0x33, 0x3b, 0x8a,
|
||||||
0xf5, 0x69, 0xa6, 0x55, 0xec, 0x60, 0x83, 0x6a, 0xb5, 0xd0, 0xa2, 0xe4, 0x9a, 0x8a, 0x16, 0xaa,
|
0x4f, 0xe4, 0xda, 0xd2, 0x6f, 0xf6, 0x0a, 0x40, 0x88, 0x34, 0x83, 0x2c, 0xe1, 0x43, 0x75, 0x31,
|
||||||
0x68, 0x9b, 0xa5, 0x57, 0xd0, 0x36, 0xd2, 0xc6, 0x72, 0xb4, 0x0d, 0x83, 0xb5, 0xfb, 0x42, 0xf8,
|
0x8c, 0x90, 0xfd, 0x84, 0x0f, 0xdd, 0xb7, 0x81, 0x99, 0x7c, 0xe4, 0x10, 0xd0, 0x0e, 0x4c, 0x0f,
|
||||||
0x22, 0x89, 0x53, 0x5d, 0x51, 0xcb, 0xbf, 0xeb, 0xc1, 0x9a, 0x7a, 0x3d, 0x4c, 0x1f, 0x7b, 0xc3,
|
0x06, 0xd9, 0x2c, 0xcb, 0xf9, 0x44, 0xdd, 0x78, 0x33, 0x21, 0xf7, 0x0a, 0x74, 0xf6, 0xfc, 0x99,
|
||||||
0x79, 0x6a, 0xbc, 0xba, 0xa8, 0xf3, 0x9b, 0xb0, 0x4c, 0xce, 0x96, 0x09, 0x41, 0xa8, 0x78, 0x89,
|
0xc7, 0x3f, 0x96, 0x77, 0x6d, 0x31, 0x36, 0xf6, 0x67, 0x28, 0xca, 0x3a, 0x36, 0xa6, 0x6a, 0xf7,
|
||||||
0x03, 0xc4, 0x35, 0xe9, 0x38, 0xea, 0x24, 0x1c, 0xab, 0x03, 0xb6, 0x41, 0x3a, 0x8a, 0x81, 0xce,
|
0x3f, 0x1b, 0xb0, 0x20, 0x28, 0x91, 0xeb, 0x88, 0x67, 0x79, 0x10, 0x89, 0x13, 0x1c, 0xc9, 0xd5,
|
||||||
0x18, 0x1d, 0xaf, 0xe7, 0x9b, 0x36, 0xff, 0x6b, 0x0f, 0xd6, 0xad, 0x05, 0x2b, 0x8e, 0xba, 0x09,
|
0x80, 0x2a, 0xb2, 0xd1, 0xa8, 0x91, 0x0d, 0xe9, 0xad, 0xaa, 0x4b, 0x36, 0x52, 0x08, 0x2c, 0x0c,
|
||||||
0x3a, 0x4d, 0x2b, 0x23, 0x15, 0x52, 0x30, 0x2e, 0xb8, 0x2f, 0x61, 0x31, 0xcc, 0x41, 0xa6, 0x8b,
|
0xdd, 0x9a, 0xe2, 0x64, 0x5c, 0x04, 0x67, 0x05, 0x50, 0x4a, 0x96, 0x14, 0xd6, 0x46, 0xf4, 0x4f,
|
||||||
0x09, 0x66, 0xb4, 0xc0, 0x6c, 0x2a, 0x6b, 0xdb, 0x9a, 0xbe, 0x0d, 0x42, 0xa6, 0x38, 0x15, 0xe2,
|
0x09, 0xad, 0x14, 0x07, 0x13, 0xaa, 0xb5, 0x69, 0x8b, 0x42, 0x6a, 0x2a, 0x36, 0xad, 0x62, 0xbb,
|
||||||
0xa9, 0x41, 0x99, 0x23, 0x14, 0x07, 0x46, 0x59, 0xb8, 0x38, 0xca, 0x8f, 0x0d, 0x92, 0x2c, 0x3c,
|
0x96, 0x5e, 0xc2, 0x76, 0x09, 0x17, 0xf6, 0x79, 0xb6, 0x0b, 0x5e, 0xc2, 0x76, 0xb9, 0x0c, 0x56,
|
||||||
0x71, 0x81, 0xfc, 0xef, 0x3d, 0xd8, 0x90, 0x16, 0x88, 0xb2, 0xef, 0x4c, 0x51, 0xdc, 0x82, 0x34,
|
0xef, 0x71, 0xee, 0x71, 0xdc, 0x15, 0x95, 0x38, 0x7d, 0xd7, 0x81, 0x55, 0xb9, 0xa1, 0xeb, 0x3a,
|
||||||
0xb9, 0xa4, 0x74, 0xed, 0x9d, 0xf3, 0x55, 0x9b, 0x7d, 0xf1, 0x15, 0xad, 0x26, 0x93, 0x7d, 0x3d,
|
0xf6, 0x9a, 0xb5, 0xfb, 0x3b, 0x75, 0x07, 0x01, 0xaf, 0xc3, 0x32, 0xed, 0xc9, 0x3a, 0x2b, 0x24,
|
||||||
0xe3, 0x2e, 0xe6, 0xea, 0xee, 0xe2, 0x05, 0x27, 0x5d, 0xe7, 0x99, 0xcf, 0xd7, 0x7a, 0xe6, 0xb7,
|
0x53, 0x58, 0x16, 0x88, 0xe3, 0x50, 0xa9, 0xed, 0x49, 0x10, 0xca, 0x45, 0x31, 0x21, 0x95, 0x58,
|
||||||
0x17, 0x61, 0x3e, 0x1b, 0xc4, 0x89, 0xe0, 0x5b, 0xb0, 0xe9, 0x6e, 0x4e, 0xa9, 0x93, 0xef, 0x7b,
|
0xc2, 0xf8, 0x98, 0x96, 0xc4, 0xf1, 0x74, 0xd9, 0xfd, 0x3b, 0x07, 0xd6, 0x8c, 0x0e, 0x4b, 0x29,
|
||||||
0xd0, 0xbd, 0x2f, 0xe3, 0x54, 0x61, 0x34, 0xda, 0x0b, 0xb3, 0x3c, 0x4e, 0x4d, 0x15, 0xf0, 0x65,
|
0xbc, 0x01, 0xea, 0xe4, 0x5c, 0x24, 0x8f, 0x84, 0x32, 0x9d, 0xb3, 0x9d, 0x93, 0xe2, 0x33, 0x8b,
|
||||||
0x80, 0x2c, 0x0f, 0xd2, 0x5c, 0x56, 0xc7, 0x28, 0x9f, 0xba, 0x80, 0xe0, 0x1a, 0x45, 0x34, 0x94,
|
0x98, 0x16, 0xd3, 0x9f, 0x51, 0x07, 0xb3, 0xe9, 0x44, 0x7a, 0x20, 0x26, 0x84, 0x82, 0x74, 0xc2,
|
||||||
0xbd, 0xf2, 0x6e, 0x4c, 0x1b, 0x2f, 0x86, 0x32, 0xc3, 0xfd, 0xf8, 0xe8, 0x28, 0x13, 0xc6, 0x46,
|
0xf9, 0x13, 0x4d, 0x32, 0x47, 0x24, 0x16, 0x46, 0x07, 0xa3, 0xe8, 0x4b, 0x68, 0x22, 0x71, 0x17,
|
||||||
0xb2, 0x61, 0xe8, 0x66, 0xa1, 0xf4, 0xa2, 0x63, 0x21, 0x4e, 0x48, 0x6d, 0x4a, 0x1f, 0xaa, 0x04,
|
0xc8, 0x06, 0xdd, 0x7f, 0x74, 0x60, 0x5d, 0x38, 0x85, 0xd2, 0xe5, 0xd6, 0xf7, 0x14, 0x17, 0x84,
|
||||||
0xe5, 0x7f, 0xe5, 0xc1, 0x6a, 0xb1, 0xc8, 0x7b, 0x08, 0x74, 0x25, 0x5d, 0x2e, 0xcd, 0x92, 0x74,
|
0x17, 0x2c, 0x34, 0x72, 0xf7, 0x8c, 0x27, 0xcb, 0xec, 0x8b, 0x2f, 0xe9, 0xc8, 0xea, 0x03, 0xf1,
|
||||||
0xed, 0xed, 0x87, 0xc3, 0x7e, 0x18, 0xa9, 0xb5, 0x59, 0x10, 0x92, 0x3e, 0xd5, 0x8a, 0xa7, 0xba,
|
0x53, 0xd6, 0x62, 0xae, 0x6e, 0x2d, 0x9e, 0x33, 0xd3, 0x75, 0xc9, 0x92, 0xf9, 0xda, 0x64, 0xc9,
|
||||||
0x12, 0xc9, 0x06, 0xc9, 0x34, 0x63, 0x8e, 0xa3, 0x65, 0x19, 0x92, 0x6a, 0x51, 0x71, 0xd3, 0x24,
|
0xad, 0x45, 0x98, 0xcf, 0x86, 0x71, 0xc2, 0xdd, 0x4d, 0xd8, 0xb0, 0x07, 0x27, 0x4d, 0xd0, 0xf7,
|
||||||
0xa7, 0x51, 0x0b, 0x32, 0x26, 0xa9, 0x9a, 0xfa, 0xad, 0x59, 0x24, 0x28, 0xfe, 0xe4, 0x7f, 0xe8,
|
0x1c, 0xe8, 0xdd, 0x13, 0xa9, 0xc3, 0x20, 0x1a, 0xef, 0x06, 0x59, 0x1e, 0xa7, 0xfa, 0x62, 0xf6,
|
||||||
0xc1, 0xc5, 0x9a, 0xc3, 0x55, 0x92, 0x71, 0x17, 0xd6, 0x8f, 0x4c, 0xa7, 0x3e, 0x00, 0x29, 0x1e,
|
0x25, 0x80, 0x2c, 0xf7, 0xd3, 0x5c, 0x5c, 0x58, 0x92, 0x69, 0x8e, 0x02, 0xc1, 0x3e, 0xf2, 0x68,
|
||||||
0x5b, 0x8a, 0x8b, 0x4a, 0x9b, 0xf6, 0xab, 0x03, 0xd8, 0x5b, 0xb0, 0x4e, 0x41, 0x0a, 0x79, 0xa4,
|
0x24, 0x6a, 0xc5, 0xda, 0xe8, 0x32, 0x2e, 0x0c, 0x1d, 0xd6, 0x0f, 0xe2, 0xc3, 0xc3, 0x8c, 0x6b,
|
||||||
0x4e, 0x86, 0xbe, 0xda, 0xb1, 0xfb, 0x83, 0x06, 0xac, 0xc8, 0xb8, 0xb8, 0xfc, 0x0e, 0x44, 0xa4,
|
0xb7, 0xd5, 0xc4, 0x30, 0xf2, 0x45, 0x8d, 0xc7, 0x58, 0x8f, 0x1f, 0x93, 0xa9, 0x15, 0xfe, 0x60,
|
||||||
0xec, 0x03, 0x58, 0x54, 0x5f, 0xdd, 0xb0, 0xf3, 0x6a, 0x5a, 0xf7, 0x3b, 0x9f, 0xde, 0x56, 0x19,
|
0x09, 0x75, 0xff, 0xd6, 0x81, 0x95, 0xa2, 0x93, 0x77, 0x11, 0xb4, 0xad, 0x83, 0xe8, 0x9a, 0x61,
|
||||||
0xac, 0x78, 0x67, 0xe3, 0x77, 0x7f, 0xfc, 0x4f, 0x7f, 0xd4, 0x58, 0x66, 0xed, 0x9d, 0x93, 0xb7,
|
0x1d, 0x54, 0x02, 0x26, 0x18, 0x0d, 0x82, 0x48, 0xf6, 0xcd, 0x40, 0x48, 0x63, 0x65, 0x29, 0x9e,
|
||||||
0x77, 0x46, 0x22, 0xca, 0x90, 0xc6, 0xaf, 0x03, 0x14, 0x1f, 0xae, 0xb0, 0xae, 0x31, 0x18, 0x4a,
|
0xaa, 0xcb, 0x61, 0x26, 0x24, 0x4e, 0x7e, 0x73, 0xfc, 0x5a, 0xdc, 0x0c, 0x93, 0x25, 0xba, 0x6f,
|
||||||
0x1f, 0xda, 0xf4, 0x2e, 0xd6, 0xf4, 0x28, 0xba, 0x17, 0x89, 0xee, 0x06, 0x5f, 0x41, 0xba, 0x61,
|
0x36, 0xc9, 0xe9, 0xab, 0x05, 0xe1, 0x10, 0xcb, 0xa2, 0xda, 0x9f, 0x16, 0x09, 0xc5, 0x9f, 0xee,
|
||||||
0x14, 0xe6, 0xf2, 0x2b, 0x96, 0xf7, 0xbc, 0x6d, 0x36, 0x84, 0x8e, 0xfd, 0x01, 0x0b, 0xd3, 0xfe,
|
0x1f, 0x3b, 0x70, 0xbe, 0x66, 0x72, 0xa5, 0x66, 0xdc, 0x81, 0xb5, 0x43, 0x5d, 0xa9, 0x26, 0x40,
|
||||||
0x59, 0xcd, 0x57, 0x31, 0xbd, 0xd7, 0x6a, 0xfb, 0xb4, 0x73, 0x4a, 0x73, 0x9c, 0xe7, 0x6b, 0x38,
|
0xa8, 0xc7, 0xa6, 0x94, 0xa2, 0xd2, 0xa0, 0xbd, 0xea, 0x07, 0xe8, 0x1e, 0x53, 0xde, 0x48, 0x4c,
|
||||||
0xc7, 0x94, 0x30, 0xcc, 0x2c, 0xbb, 0xff, 0xf0, 0x1a, 0xb4, 0x4c, 0x8c, 0x83, 0x7d, 0x1b, 0x96,
|
0xa9, 0x75, 0x69, 0xa2, 0x5a, 0xb1, 0xf3, 0xfd, 0x06, 0x74, 0xc5, 0x51, 0x85, 0x78, 0x9a, 0xc3,
|
||||||
0x9d, 0x54, 0x02, 0xd3, 0x84, 0xeb, 0x32, 0x0f, 0xbd, 0x4b, 0xf5, 0x9d, 0x6a, 0xda, 0xcb, 0x34,
|
0x53, 0xf6, 0x01, 0x2c, 0xca, 0x87, 0x50, 0xec, 0xac, 0x6c, 0xd6, 0x7e, 0x7a, 0xd5, 0xdf, 0x2c,
|
||||||
0x6d, 0x97, 0x6d, 0xe1, 0xb4, 0x2a, 0x16, 0xbf, 0x43, 0x09, 0x14, 0x59, 0xcc, 0xf4, 0x14, 0x56,
|
0xc3, 0x52, 0x76, 0xd6, 0x7f, 0xff, 0xb3, 0x7f, 0xf9, 0x93, 0xc6, 0x32, 0x6b, 0x6f, 0x1f, 0xbf,
|
||||||
0xdc, 0xf0, 0x3f, 0xbb, 0xe4, 0x2a, 0x94, 0xd2, 0x6c, 0x9f, 0x39, 0xa3, 0x57, 0x4d, 0x77, 0x89,
|
0xb5, 0x3d, 0xe6, 0x51, 0x86, 0x3c, 0x7e, 0x13, 0xa0, 0x78, 0x4b, 0xc4, 0x7a, 0xda, 0xc9, 0x28,
|
||||||
0xa6, 0xdb, 0x62, 0x9b, 0xf6, 0x74, 0x26, 0xf6, 0x20, 0xa8, 0xfc, 0xcc, 0xfe, 0xb2, 0x85, 0x7d,
|
0xbd, 0x7d, 0xea, 0x9f, 0xaf, 0xa9, 0x91, 0x7c, 0xcf, 0x13, 0xdf, 0x75, 0xb7, 0x8b, 0x7c, 0x83,
|
||||||
0xc6, 0x5c, 0x75, 0xdd, 0x17, 0x2f, 0xe6, 0xd2, 0xaa, 0x9f, 0xbd, 0xf0, 0x2e, 0x4d, 0xc5, 0x18,
|
0x28, 0xc8, 0xc5, 0xc3, 0xa2, 0x77, 0x9d, 0x2d, 0x36, 0x82, 0x8e, 0xf9, 0xa6, 0x88, 0xa9, 0x90,
|
||||||
0x1d, 0xa8, 0xfd, 0x61, 0x0b, 0xfb, 0x08, 0x5a, 0xa6, 0x9a, 0x9d, 0x5d, 0xb0, 0x3e, 0x21, 0xb0,
|
0xb9, 0xe6, 0xa1, 0x52, 0xff, 0x42, 0x6d, 0x9d, 0xca, 0x17, 0x50, 0x1b, 0x67, 0xdd, 0x55, 0x6c,
|
||||||
0x4b, 0xec, 0x7b, 0xdd, 0x6a, 0x47, 0xdd, 0x55, 0xd9, 0x94, 0x91, 0x21, 0x1e, 0xc2, 0x79, 0x65,
|
0x63, 0x4a, 0x14, 0xba, 0x95, 0x9d, 0x7f, 0xba, 0x00, 0x2d, 0x9d, 0x76, 0x62, 0xdf, 0x86, 0x65,
|
||||||
0x70, 0x1e, 0x8a, 0x9f, 0x66, 0x27, 0x35, 0xdf, 0xe3, 0xdc, 0xf0, 0xd8, 0x4d, 0x58, 0xd2, 0x1f,
|
0xeb, 0x74, 0x87, 0x29, 0xc6, 0x75, 0x87, 0x41, 0xfd, 0x8b, 0xf5, 0x95, 0xb2, 0xd9, 0x4b, 0xd4,
|
||||||
0x09, 0xb0, 0xad, 0xfa, 0x8f, 0x1d, 0x7a, 0x17, 0x2a, 0x70, 0x25, 0xcf, 0xb7, 0x00, 0x8a, 0x02,
|
0x6c, 0x8f, 0x6d, 0x62, 0xb3, 0xf2, 0x78, 0x64, 0x9b, 0xce, 0xb4, 0xc4, 0xfd, 0xb2, 0x27, 0xd0,
|
||||||
0x77, 0xc3, 0xf9, 0x95, 0xb2, 0x7b, 0x73, 0x88, 0x35, 0xd5, 0xf0, 0x23, 0x2a, 0xe7, 0x77, 0xeb,
|
0xb5, 0x4f, 0x64, 0xd8, 0x45, 0xdb, 0xa0, 0x94, 0x5a, 0x7b, 0xe5, 0x94, 0x5a, 0xd9, 0xdc, 0x45,
|
||||||
0xe7, 0xd9, 0xeb, 0x05, 0x7e, 0x6d, 0x65, 0xfd, 0x0b, 0x08, 0xf2, 0x2d, 0x3a, 0xbb, 0x35, 0x46,
|
0x6a, 0x6e, 0x93, 0x6d, 0x98, 0xcd, 0xe9, 0x74, 0x10, 0xa7, 0x1b, 0x81, 0xe6, 0x63, 0x23, 0xf6,
|
||||||
0xa2, 0x14, 0x89, 0x53, 0x5d, 0x88, 0x79, 0x17, 0xda, 0x56, 0xd1, 0x3c, 0xd3, 0x14, 0xaa, 0x05,
|
0x8a, 0x5e, 0xea, 0xba, 0x47, 0x48, 0x7a, 0xd1, 0xaa, 0x2f, 0x91, 0xdc, 0x1e, 0x35, 0xc5, 0x18,
|
||||||
0xf7, 0xbd, 0x5e, 0x5d, 0x97, 0x5a, 0xee, 0x57, 0x60, 0xd9, 0xa9, 0x7e, 0x37, 0x92, 0x51, 0x57,
|
0x4d, 0xa8, 0xf9, 0xd6, 0x88, 0x7d, 0x04, 0x2d, 0xfd, 0xc0, 0x80, 0x9d, 0x33, 0x5e, 0x75, 0x98,
|
||||||
0x5b, 0x6f, 0x24, 0xa3, 0xbe, 0x60, 0xfe, 0x9b, 0xd0, 0xb6, 0x6a, 0xd5, 0x99, 0x55, 0x80, 0x52,
|
0xaf, 0x1e, 0xfa, 0xbd, 0x6a, 0x45, 0xdd, 0x52, 0x99, 0x9c, 0x51, 0x20, 0x1e, 0xc0, 0x59, 0xe9,
|
||||||
0xaa, 0x52, 0x37, 0x2b, 0xaa, 0x2b, 0x6d, 0xdf, 0xa4, 0xfd, 0xae, 0xf0, 0x16, 0xee, 0x97, 0xaa,
|
0xa4, 0x1e, 0xf0, 0x9f, 0x64, 0x24, 0x35, 0x4f, 0xa4, 0xae, 0x3b, 0xec, 0x06, 0x2c, 0xa9, 0x77,
|
||||||
0x11, 0x91, 0x49, 0xbe, 0x0d, 0x2b, 0x6e, 0xf5, 0xba, 0x91, 0xaa, 0xda, 0x3a, 0x78, 0x23, 0x55,
|
0x1b, 0x6c, 0xb3, 0xfe, 0xfd, 0x49, 0xff, 0x5c, 0x05, 0x97, 0xfa, 0x7c, 0x13, 0xa0, 0x78, 0x73,
|
||||||
0x67, 0x94, 0xbc, 0x2b, 0x86, 0xdc, 0xde, 0x30, 0x93, 0xec, 0x7c, 0xaa, 0x22, 0xfc, 0xcf, 0xd9,
|
0xa0, 0x25, 0xbf, 0xf2, 0x12, 0x42, 0x4f, 0x62, 0xcd, 0x03, 0x85, 0x31, 0xbd, 0xb0, 0xb0, 0x9f,
|
||||||
0xd7, 0x51, 0x75, 0xa8, 0xf2, 0x50, 0x56, 0xd4, 0xec, 0xbb, 0x45, 0xa4, 0x86, 0xdb, 0x2b, 0x95,
|
0x34, 0xb0, 0x57, 0x0b, 0xfa, 0xda, 0xc7, 0x0e, 0xcf, 0x61, 0xe8, 0x6e, 0xd2, 0xdc, 0xad, 0x32,
|
||||||
0xa4, 0x7c, 0x9d, 0x88, 0xb7, 0x59, 0xb1, 0x03, 0xa9, 0xa1, 0xa9, 0x4c, 0xd4, 0xd2, 0xd0, 0x76,
|
0x52, 0xa5, 0x88, 0x9f, 0xa8, 0xbb, 0xb1, 0x77, 0xa0, 0x6d, 0xbc, 0x63, 0x60, 0x8a, 0x43, 0xf5,
|
||||||
0x25, 0xa9, 0xa5, 0xa1, 0x9d, 0x6a, 0xd2, 0xb2, 0x86, 0xce, 0x43, 0xa4, 0x11, 0xc1, 0x6a, 0x29,
|
0x0d, 0x44, 0xbf, 0x5f, 0x57, 0x25, 0xbb, 0xfb, 0x15, 0x58, 0xb6, 0x1e, 0x24, 0x68, 0xcd, 0xa8,
|
||||||
0xe9, 0x6c, 0x84, 0xa5, 0xbe, 0x64, 0xa5, 0x77, 0xf9, 0xc5, 0xb9, 0x6a, 0x57, 0xcd, 0x68, 0xf5,
|
0x7b, 0xee, 0xa0, 0x35, 0xa3, 0xfe, 0x0d, 0xc3, 0x37, 0xa1, 0x6d, 0x3c, 0x1f, 0x60, 0xc6, 0x9d,
|
||||||
0xb2, 0xa3, 0x2b, 0x8c, 0x7e, 0x03, 0x3a, 0x76, 0xd5, 0xb1, 0xd1, 0xd9, 0x35, 0xb5, 0xd2, 0x46,
|
0xa0, 0xd2, 0xc3, 0x01, 0xdd, 0xa3, 0xba, 0xd7, 0x06, 0x1b, 0x34, 0xde, 0xae, 0xdb, 0xc2, 0xf1,
|
||||||
0x67, 0xd7, 0x95, 0x29, 0xeb, 0xcb, 0x65, 0x1d, 0x7b, 0x1a, 0xf6, 0x4d, 0x58, 0xb5, 0xca, 0x1b,
|
0xd2, 0x05, 0x51, 0x14, 0x92, 0x6f, 0x43, 0xd7, 0x7e, 0x50, 0xa0, 0xb5, 0xaa, 0xf6, 0x69, 0x82,
|
||||||
0x0e, 0x66, 0xd1, 0xc0, 0x30, 0x4f, 0xb5, 0x20, 0xad, 0x57, 0x67, 0x9f, 0xf1, 0x0b, 0x44, 0x78,
|
0xd6, 0xaa, 0x53, 0x5e, 0x21, 0x48, 0x81, 0xdc, 0x5a, 0xd7, 0x8d, 0x6c, 0x7f, 0x2a, 0x0f, 0x5d,
|
||||||
0x9d, 0x3b, 0x84, 0x91, 0x71, 0xee, 0x40, 0xdb, 0x2e, 0x9d, 0x78, 0x01, 0xdd, 0x0b, 0x56, 0x97,
|
0x9e, 0xb1, 0xaf, 0xa3, 0xe9, 0x90, 0x37, 0x76, 0x59, 0xf1, 0x8c, 0xc2, 0xbe, 0xd7, 0xab, 0xa5,
|
||||||
0x5d, 0x9b, 0x75, 0xc3, 0x63, 0x7f, 0xe2, 0x41, 0xc7, 0x2e, 0x75, 0x64, 0x4e, 0x50, 0xb1, 0x44,
|
0xbd, 0x72, 0xb9, 0xd7, 0x5d, 0x23, 0xe6, 0x6d, 0x56, 0x8c, 0x40, 0x58, 0x68, 0xba, 0xb9, 0x6b,
|
||||||
0xa7, 0x6b, 0xf7, 0xd9, 0x84, 0xb8, 0x4f, 0x8b, 0x7c, 0xb8, 0xfd, 0x15, 0xe7, 0x90, 0x3f, 0x75,
|
0x58, 0x68, 0xf3, 0x72, 0xaf, 0x61, 0xa1, 0xad, 0x0b, 0xbe, 0x65, 0x0b, 0x9d, 0x07, 0xc8, 0x23,
|
||||||
0xec, 0xfc, 0xeb, 0xe5, 0x0f, 0xca, 0x9e, 0x97, 0x11, 0xec, 0xa2, 0xbd, 0xe7, 0x37, 0x3c, 0xf6,
|
0x82, 0x95, 0xd2, 0x3d, 0x00, 0xad, 0x2c, 0xf5, 0xb7, 0x88, 0xfa, 0x97, 0x9e, 0x7f, 0x7d, 0xc0,
|
||||||
0x9e, 0xfc, 0xe8, 0x50, 0xfb, 0xe8, 0xcc, 0x52, 0x6e, 0xe5, 0x23, 0xb3, 0xbf, 0xcf, 0xbb, 0xe6,
|
0x36, 0x33, 0xca, 0xbc, 0x6c, 0xab, 0x4b, 0x5f, 0xbf, 0x05, 0x1d, 0xf3, 0x22, 0xb8, 0xb6, 0xd9,
|
||||||
0xdd, 0xf0, 0xd8, 0xb7, 0xe4, 0x77, 0x63, 0x6a, 0x2c, 0x9d, 0xfc, 0xab, 0x8e, 0xe7, 0x6f, 0xd2,
|
0x35, 0xd7, 0xd7, 0xb5, 0xcd, 0xae, 0xbb, 0x39, 0xae, 0x16, 0x97, 0x75, 0xcc, 0x66, 0xd8, 0x37,
|
||||||
0x6e, 0x2e, 0xf3, 0x8b, 0xce, 0x6e, 0xca, 0xda, 0x7d, 0x1f, 0xa0, 0x08, 0xb8, 0xb0, 0x52, 0xf4,
|
0x61, 0xc5, 0xb8, 0x71, 0xb2, 0x3f, 0x8b, 0x86, 0x5a, 0x78, 0xaa, 0x77, 0x04, 0xfb, 0x75, 0xfe,
|
||||||
0xc1, 0xe8, 0xbd, 0x6a, 0x4c, 0xc6, 0xbd, 0x51, 0x1d, 0xa4, 0x40, 0x8a, 0x1f, 0x49, 0x66, 0x54,
|
0x99, 0x7b, 0x8e, 0x18, 0xaf, 0xb9, 0x16, 0x63, 0x14, 0x9c, 0xdb, 0xd0, 0x36, 0x6f, 0xb3, 0x3c,
|
||||||
0xf8, 0x99, 0xb9, 0xd2, 0x6a, 0xe0, 0xa4, 0xd7, 0xab, 0xeb, 0xaa, 0x63, 0x45, 0x4d, 0x9f, 0x3d,
|
0x87, 0xef, 0x39, 0xa3, 0xca, 0xbc, 0x2e, 0x77, 0xdd, 0x61, 0x7f, 0xe6, 0x40, 0xc7, 0xbc, 0x7d,
|
||||||
0x81, 0xe5, 0x87, 0x71, 0xfc, 0x74, 0x9a, 0x98, 0x20, 0x9e, 0xeb, 0xff, 0xef, 0x05, 0xd9, 0x71,
|
0xca, 0xac, 0x3c, 0x6f, 0x89, 0x4f, 0xcf, 0xac, 0x33, 0x19, 0xb9, 0x1e, 0x75, 0xf2, 0xc1, 0xd6,
|
||||||
0xaf, 0xb4, 0x0b, 0x7e, 0x85, 0x48, 0xf5, 0x58, 0xd7, 0x22, 0xb5, 0xf3, 0x69, 0x11, 0xee, 0x79,
|
0x57, 0xac, 0x49, 0xfe, 0xd4, 0xf2, 0xf3, 0xaf, 0x95, 0xdf, 0xf8, 0x3d, 0x2b, 0x13, 0x98, 0xf7,
|
||||||
0xce, 0x02, 0x58, 0x37, 0x6f, 0x9c, 0x59, 0x78, 0xcf, 0x25, 0x63, 0x47, 0x5d, 0x2a, 0x53, 0x38,
|
0x28, 0x9f, 0x5d, 0x77, 0xd8, 0xbb, 0xe2, 0x1d, 0xa8, 0x8a, 0xeb, 0x99, 0x61, 0xdc, 0xca, 0x53,
|
||||||
0x56, 0x87, 0x5e, 0xed, 0x4e, 0xa6, 0x69, 0xde, 0xf0, 0xd8, 0x3e, 0x74, 0xee, 0x8a, 0x41, 0x3c,
|
0x66, 0x3e, 0x99, 0xbc, 0xea, 0x5c, 0x77, 0xd8, 0xb7, 0xc4, 0x53, 0x3e, 0xf9, 0x2d, 0xcd, 0xfc,
|
||||||
0x14, 0xca, 0x63, 0xdf, 0x28, 0x16, 0x6e, 0x5c, 0xfd, 0xde, 0xb2, 0x03, 0x74, 0xa5, 0x3e, 0x09,
|
0xcb, 0x7e, 0xef, 0xbe, 0x4e, 0xa3, 0xb9, 0xe4, 0x9e, 0xb7, 0x46, 0x53, 0xb6, 0xee, 0x7b, 0x00,
|
||||||
0x66, 0xa9, 0xf8, 0x78, 0xe7, 0x53, 0x15, 0x0b, 0x78, 0xae, 0xa5, 0x5e, 0xc7, 0x2f, 0x1c, 0xa9,
|
0x45, 0x92, 0x86, 0x95, 0x32, 0x16, 0xda, 0xee, 0x55, 0xf3, 0x38, 0xf6, 0x8a, 0xaa, 0xc4, 0x06,
|
||||||
0x2f, 0x05, 0x3c, 0x1c, 0xa9, 0xaf, 0x04, 0x3c, 0x9c, 0xa3, 0xd6, 0xf1, 0x13, 0x36, 0x86, 0xf5,
|
0x72, 0xfc, 0x48, 0x08, 0xa3, 0xa4, 0xcf, 0xf4, 0x92, 0x56, 0x93, 0x2d, 0xfd, 0x7e, 0x5d, 0x55,
|
||||||
0x4a, 0x8c, 0xc4, 0xbc, 0x94, 0x67, 0x45, 0x56, 0x7a, 0x57, 0xce, 0x46, 0x70, 0x67, 0xdb, 0x76,
|
0x9d, 0x28, 0x2a, 0xfe, 0xec, 0x31, 0x2c, 0x3f, 0x88, 0xe3, 0x27, 0xd3, 0x44, 0xa7, 0x11, 0xed,
|
||||||
0x67, 0x3b, 0x80, 0xe5, 0xbb, 0x42, 0x1e, 0x96, 0x4c, 0x8c, 0xf5, 0x5c, 0x35, 0x62, 0x27, 0xd1,
|
0x9c, 0xc1, 0xae, 0x9f, 0x1d, 0xf5, 0x4b, 0xa3, 0x70, 0x2f, 0x13, 0xab, 0x3e, 0xeb, 0x19, 0xac,
|
||||||
0xca, 0x2a, 0x86, 0xfa, 0x5c, 0xb5, 0x4e, 0x59, 0x29, 0xf6, 0x11, 0xb4, 0x1f, 0x88, 0x5c, 0x67,
|
0xb6, 0x3f, 0x2d, 0x52, 0x44, 0xcf, 0x98, 0x0f, 0x6b, 0x7a, 0x8f, 0xd3, 0x1d, 0xef, 0xdb, 0x6c,
|
||||||
0xc2, 0x8c, 0xbd, 0x51, 0x4a, 0x8d, 0xf5, 0x6a, 0x12, 0x69, 0x2e, 0xcf, 0x10, 0xb5, 0x1d, 0x31,
|
0xcc, 0x4c, 0x4d, 0xa5, 0x09, 0xcb, 0xeb, 0x50, 0xbd, 0xdd, 0xce, 0x14, 0xcf, 0xeb, 0x0e, 0xdb,
|
||||||
0x1c, 0x09, 0x29, 0xec, 0xfd, 0x70, 0xf8, 0x9c, 0xfd, 0x2a, 0x11, 0x37, 0xc9, 0xf3, 0x2d, 0x2b,
|
0x83, 0xce, 0x1d, 0x3e, 0x8c, 0x47, 0x5c, 0x46, 0xf9, 0xeb, 0x45, 0xc7, 0x75, 0x7a, 0xa0, 0xbf,
|
||||||
0x81, 0x62, 0x13, 0x5f, 0x2d, 0xc1, 0xeb, 0x28, 0x47, 0xf1, 0x50, 0x58, 0x0f, 0x5c, 0x04, 0x6d,
|
0x6c, 0x81, 0xb6, 0xd6, 0x27, 0xfe, 0x2c, 0xe5, 0x1f, 0x6f, 0x7f, 0x2a, 0xf3, 0x07, 0xcf, 0x94,
|
||||||
0xab, 0xb2, 0xc3, 0x08, 0x50, 0xb5, 0x9a, 0xc4, 0x08, 0x50, 0x4d, 0x21, 0x08, 0xbf, 0x46, 0xf3,
|
0xd6, 0xab, 0x9c, 0x87, 0xa5, 0xf5, 0xa5, 0x24, 0x89, 0xa5, 0xf5, 0x95, 0x24, 0x89, 0x35, 0xd5,
|
||||||
0x70, 0x76, 0xa5, 0x98, 0x47, 0x16, 0x7f, 0x14, 0x33, 0xed, 0x7c, 0x1a, 0x4c, 0xf2, 0xe7, 0xec,
|
0x2a, 0xe7, 0xc2, 0x42, 0x58, 0xab, 0xe4, 0x55, 0xf4, 0x4e, 0x79, 0x5a, 0x36, 0xa6, 0x7f, 0xf9,
|
||||||
0x43, 0xfa, 0x6e, 0xc2, 0xce, 0xf6, 0x15, 0xf6, 0x4e, 0x39, 0x31, 0x68, 0x0e, 0xcb, 0xea, 0x72,
|
0x74, 0x02, 0xbb, 0xb5, 0x2d, 0xbb, 0xb5, 0x7d, 0x58, 0xbe, 0xc3, 0xc5, 0x64, 0x89, 0xb3, 0xca,
|
||||||
0x6d, 0x20, 0x39, 0x15, 0xbd, 0x83, 0x5f, 0x04, 0x38, 0xc8, 0xe3, 0xe4, 0x6e, 0x20, 0x26, 0x71,
|
0xbe, 0x6d, 0x46, 0xcc, 0x73, 0xcd, 0xb2, 0x89, 0xa1, 0x3a, 0xdb, 0xac, 0xd3, 0x41, 0x21, 0xfb,
|
||||||
0x54, 0x68, 0xae, 0x22, 0xa3, 0x55, 0x68, 0x2e, 0x2b, 0xad, 0xc5, 0x3e, 0xb4, 0x2c, 0x4e, 0x27,
|
0x08, 0xda, 0xf7, 0x79, 0xae, 0x0e, 0x27, 0xb5, 0xbf, 0x51, 0x3a, 0xad, 0xec, 0xd7, 0x9c, 0x6d,
|
||||||
0x59, 0xaa, 0x99, 0xeb, 0xcc, 0xa4, 0x97, 0x39, 0x90, 0x9a, 0xc4, 0xd7, 0x0d, 0x0f, 0xed, 0xc7,
|
0xda, 0x32, 0x43, 0xdc, 0xb6, 0xf9, 0x68, 0xcc, 0x85, 0xb2, 0x0f, 0x82, 0xd1, 0x33, 0xf6, 0xeb,
|
||||||
0x22, 0x22, 0x67, 0xec, 0xc7, 0x4a, 0xb0, 0xcf, 0xa8, 0xbd, 0x9a, 0xf0, 0xdd, 0x3e, 0xb4, 0x8a,
|
0xc4, 0x5c, 0xdf, 0x67, 0xd8, 0x34, 0xce, 0xb4, 0x4c, 0xe6, 0x2b, 0x25, 0xbc, 0x8e, 0x73, 0x14,
|
||||||
0xb0, 0x90, 0x7e, 0x92, 0xca, 0x41, 0x24, 0xf3, 0xc6, 0x54, 0x82, 0x35, 0x7c, 0x8d, 0x8e, 0x0a,
|
0x8f, 0xb8, 0xb1, 0xc1, 0x45, 0xd0, 0x36, 0x2e, 0xdb, 0x68, 0x05, 0xaa, 0x5e, 0xf0, 0xd1, 0x0a,
|
||||||
0xd8, 0x12, 0x1e, 0x15, 0x45, 0x60, 0x42, 0xd8, 0x90, 0x0b, 0x34, 0x0f, 0x26, 0xe5, 0x68, 0xf4,
|
0x54, 0x73, 0x37, 0xc7, 0xbd, 0x4a, 0xed, 0xb8, 0xec, 0x72, 0xd1, 0x8e, 0xb8, 0x8f, 0x53, 0xb4,
|
||||||
0x4e, 0x6a, 0x02, 0x26, 0x46, 0x9a, 0x6b, 0xe3, 0x0d, 0x8e, 0x6f, 0x87, 0xdc, 0x2a, 0xf3, 0x43,
|
0xb4, 0xfd, 0xa9, 0x3f, 0xc9, 0x9f, 0xb1, 0x0f, 0xe9, 0x29, 0x8b, 0x79, 0x00, 0x5b, 0xf8, 0x3b,
|
||||||
0xa8, 0x9a, 0x27, 0xb0, 0x5e, 0x71, 0x96, 0x8d, 0x48, 0x9f, 0x15, 0xa3, 0x30, 0x22, 0x7d, 0xa6,
|
0xe5, 0xb3, 0x5a, 0x3d, 0x59, 0x46, 0x95, 0xed, 0x03, 0x89, 0xa6, 0x68, 0x1f, 0xfc, 0x22, 0xc0,
|
||||||
0x9f, 0xcd, 0xcf, 0xd3, 0x94, 0xab, 0x1c, 0x70, 0xca, 0xec, 0x34, 0xcc, 0x07, 0xc7, 0xef, 0x79,
|
0x7e, 0x1e, 0x27, 0x77, 0x7c, 0x3e, 0x89, 0xa3, 0xc2, 0x72, 0x15, 0x87, 0x8c, 0x85, 0xe5, 0x32,
|
||||||
0xdb, 0x87, 0x0b, 0xf4, 0xb7, 0x16, 0x9f, 0xff, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbc, 0xb9,
|
0x4e, 0x1a, 0xd9, 0x87, 0x86, 0xc7, 0x69, 0x9d, 0x5f, 0x2b, 0xe1, 0x3a, 0xf5, 0x1c, 0x52, 0x4f,
|
||||||
0x7b, 0x12, 0x08, 0x43, 0x00, 0x00,
|
0x48, 0xcd, 0x59, 0xe4, 0x75, 0x07, 0xfd, 0xc7, 0x22, 0x8b, 0xa7, 0xfd, 0xc7, 0x4a, 0x82, 0x50,
|
||||||
|
0x9b, 0xbd, 0x9a, 0x94, 0xdf, 0x1e, 0xb4, 0x8a, 0xb4, 0x90, 0xda, 0x92, 0xca, 0x49, 0x24, 0xbd,
|
||||||
|
0xc7, 0x54, 0x92, 0x35, 0xee, 0x2a, 0x4d, 0x15, 0xb0, 0x25, 0x9c, 0x2a, 0xca, 0xc0, 0x04, 0xb0,
|
||||||
|
0x2e, 0x3a, 0xa8, 0x37, 0x4c, 0x3a, 0x36, 0x53, 0x23, 0xa9, 0x49, 0x98, 0x68, 0x6d, 0xae, 0xcd,
|
||||||
|
0x37, 0x58, 0xb1, 0x1d, 0x4a, 0xab, 0x38, 0xb2, 0x43, 0xd3, 0x3c, 0x81, 0xb5, 0x4a, 0xb0, 0xac,
|
||||||
|
0x55, 0xfa, 0xb4, 0x1c, 0x85, 0x56, 0xe9, 0x53, 0xe3, 0x6c, 0xf7, 0x2c, 0x35, 0xb9, 0xe2, 0x02,
|
||||||
|
0x36, 0x99, 0x9d, 0x04, 0xf9, 0xf0, 0xe8, 0x5d, 0x67, 0xeb, 0x60, 0x81, 0xfe, 0x69, 0xe4, 0xf3,
|
||||||
|
0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x0b, 0xc7, 0xfe, 0x7f, 0x9b, 0x44, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
@ -592,18 +592,10 @@ func RegisterWalletUnlockerHandlerFromEndpoint(ctx context.Context, mux *runtime
|
|||||||
// RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux".
|
// RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux".
|
||||||
// The handlers forward requests to the grpc endpoint over "conn".
|
// The handlers forward requests to the grpc endpoint over "conn".
|
||||||
func RegisterWalletUnlockerHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
func RegisterWalletUnlockerHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||||
return RegisterWalletUnlockerHandlerClient(ctx, mux, NewWalletUnlockerClient(conn))
|
client := NewWalletUnlockerClient(conn)
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux".
|
|
||||||
// The handlers forward requests to the grpc endpoint over the given implementation of "WalletUnlockerClient".
|
|
||||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WalletUnlockerClient"
|
|
||||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
|
||||||
// "WalletUnlockerClient" to call the correct interceptors.
|
|
||||||
func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WalletUnlockerClient) error {
|
|
||||||
|
|
||||||
mux.Handle("GET", pattern_WalletUnlocker_GenSeed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_WalletUnlocker_GenSeed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -632,7 +624,7 @@ func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.Serve
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_WalletUnlocker_InitWallet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_WalletUnlocker_InitWallet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -661,7 +653,7 @@ func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.Serve
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_WalletUnlocker_UnlockWallet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_WalletUnlocker_UnlockWallet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -736,18 +728,10 @@ func RegisterLightningHandlerFromEndpoint(ctx context.Context, mux *runtime.Serv
|
|||||||
// RegisterLightningHandler registers the http handlers for service Lightning to "mux".
|
// RegisterLightningHandler registers the http handlers for service Lightning to "mux".
|
||||||
// The handlers forward requests to the grpc endpoint over "conn".
|
// The handlers forward requests to the grpc endpoint over "conn".
|
||||||
func RegisterLightningHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
func RegisterLightningHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||||
return RegisterLightningHandlerClient(ctx, mux, NewLightningClient(conn))
|
client := NewLightningClient(conn)
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterLightningHandler registers the http handlers for service Lightning to "mux".
|
|
||||||
// The handlers forward requests to the grpc endpoint over the given implementation of "LightningClient".
|
|
||||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "LightningClient"
|
|
||||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
|
||||||
// "LightningClient" to call the correct interceptors.
|
|
||||||
func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, client LightningClient) error {
|
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_WalletBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_WalletBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -776,7 +760,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_ChannelBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_ChannelBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -805,7 +789,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_GetTransactions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_GetTransactions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -834,7 +818,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_SendCoins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_SendCoins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -863,7 +847,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_NewWitnessAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_NewWitnessAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -892,7 +876,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_ConnectPeer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_ConnectPeer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -921,7 +905,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("DELETE", pattern_Lightning_DisconnectPeer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("DELETE", pattern_Lightning_DisconnectPeer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -950,7 +934,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_ListPeers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_ListPeers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -979,7 +963,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1008,7 +992,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_PendingChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_PendingChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1037,7 +1021,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_ListChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_ListChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1066,7 +1050,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_OpenChannelSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_OpenChannelSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1095,7 +1079,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("DELETE", pattern_Lightning_CloseChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("DELETE", pattern_Lightning_CloseChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1124,7 +1108,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_SendPaymentSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_SendPaymentSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1153,7 +1137,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_AddInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_AddInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1182,7 +1166,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_ListInvoices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_ListInvoices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1211,7 +1195,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_LookupInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_LookupInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1240,7 +1224,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_SubscribeInvoices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_SubscribeInvoices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1269,7 +1253,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_DecodePayReq_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_DecodePayReq_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1298,7 +1282,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_ListPayments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_ListPayments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1327,7 +1311,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("DELETE", pattern_Lightning_DeleteAllPayments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("DELETE", pattern_Lightning_DeleteAllPayments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1356,7 +1340,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_DescribeGraph_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_DescribeGraph_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1385,7 +1369,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_GetChanInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_GetChanInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1414,7 +1398,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_GetNodeInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_GetNodeInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1443,7 +1427,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_QueryRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_QueryRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1472,7 +1456,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_GetNetworkInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_GetNetworkInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1501,7 +1485,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Lightning_FeeReport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Lightning_FeeReport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1530,7 +1514,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_UpdateChannelPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_UpdateChannelPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
@ -1559,7 +1543,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_ForwardingHistory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_ForwardingHistory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if cn, ok := w.(http.CloseNotifier); ok {
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
go func(done <-chan struct{}, closed <-chan bool) {
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
|
@ -1369,6 +1369,34 @@ message ClosedChannelUpdate {
|
|||||||
ChannelPoint chan_point = 4;
|
ChannelPoint chan_point = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message HopHint {
|
||||||
|
/// The public key of the node at the start of the channel.
|
||||||
|
string node_id = 1 [json_name = "node_id"];
|
||||||
|
|
||||||
|
/// The unique identifier of the channel.
|
||||||
|
uint64 chan_id = 2 [json_name = "chan_id"];
|
||||||
|
|
||||||
|
/// The base fee of the channel denominated in millisatoshis.
|
||||||
|
uint32 fee_base_msat = 3 [json_name = "fee_base_msat"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
The fee rate of the channel for sending one satoshi across it denominated in
|
||||||
|
millionths of a satoshi.
|
||||||
|
*/
|
||||||
|
uint32 fee_proportional_millionths = 4 [json_name = "fee_proportional_millionths"];
|
||||||
|
|
||||||
|
/// The time-lock delta of the channel.
|
||||||
|
uint32 cltv_expiry_delta = 5 [json_name = "cltv_expiry_delta"];
|
||||||
|
}
|
||||||
|
|
||||||
|
message RouteHint {
|
||||||
|
/**
|
||||||
|
A list of hop hints that when chained together can assist in reaching a
|
||||||
|
specific destination.
|
||||||
|
*/
|
||||||
|
repeated HopHint hop_hints = 1 [json_name = "hop_hints"];
|
||||||
|
}
|
||||||
|
|
||||||
message Invoice {
|
message Invoice {
|
||||||
/**
|
/**
|
||||||
An optional memo to attach along with the invoice. Used for record keeping
|
An optional memo to attach along with the invoice. Used for record keeping
|
||||||
@ -1424,6 +1452,15 @@ message Invoice {
|
|||||||
|
|
||||||
/// Delta to use for the time-lock of the CLTV extended to the final hop.
|
/// Delta to use for the time-lock of the CLTV extended to the final hop.
|
||||||
uint64 cltv_expiry = 13 [json_name = "cltv_expiry"];
|
uint64 cltv_expiry = 13 [json_name = "cltv_expiry"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
Route hints that can each be individually used to assist in reaching the
|
||||||
|
invoice's destination.
|
||||||
|
*/
|
||||||
|
repeated RouteHint route_hints = 14 [json_name = "route_hints"];
|
||||||
|
|
||||||
|
/// Whether this invoice should include routing hints for private channels.
|
||||||
|
bool private = 15 [json_name = "private"];
|
||||||
}
|
}
|
||||||
message AddInvoiceResponse {
|
message AddInvoiceResponse {
|
||||||
bytes r_hash = 1 [json_name = "r_hash"];
|
bytes r_hash = 1 [json_name = "r_hash"];
|
||||||
@ -1513,6 +1550,7 @@ message PayReq {
|
|||||||
string description_hash = 7 [json_name = "description_hash"];
|
string description_hash = 7 [json_name = "description_hash"];
|
||||||
string fallback_addr = 8 [json_name = "fallback_addr"];
|
string fallback_addr = 8 [json_name = "fallback_addr"];
|
||||||
int64 cltv_expiry = 9 [json_name = "cltv_expiry"];
|
int64 cltv_expiry = 9 [json_name = "cltv_expiry"];
|
||||||
|
repeated RouteHint route_hints = 10 [json_name = "route_hints"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message FeeReportRequest {}
|
message FeeReportRequest {}
|
||||||
|
@ -789,14 +789,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"NewAddressRequestAddressType": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"WITNESS_PUBKEY_HASH",
|
|
||||||
"NESTED_PUBKEY_HASH"
|
|
||||||
],
|
|
||||||
"default": "WITNESS_PUBKEY_HASH"
|
|
||||||
},
|
|
||||||
"PendingChannelsResponseClosedChannel": {
|
"PendingChannelsResponseClosedChannel": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1515,6 +1507,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lnrpcHopHint": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"node_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "/ The public key of the node at the start of the channel."
|
||||||
|
},
|
||||||
|
"chan_id": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "/ The unique identifier of the channel."
|
||||||
|
},
|
||||||
|
"fee_base_msat": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "/ The base fee of the channel denominated in millisatoshis."
|
||||||
|
},
|
||||||
|
"fee_proportional_millionths": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "*\nThe fee rate of the channel for sending one satoshi across it denominated in\nmillionths of a satoshi."
|
||||||
|
},
|
||||||
|
"cltv_expiry_delta": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "/ The time-lock delta of the channel."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"lnrpcInitWalletRequest": {
|
"lnrpcInitWalletRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1604,6 +1625,18 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uint64",
|
"format": "uint64",
|
||||||
"description": "/ Delta to use for the time-lock of the CLTV extended to the final hop."
|
"description": "/ Delta to use for the time-lock of the CLTV extended to the final hop."
|
||||||
|
},
|
||||||
|
"route_hints": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/lnrpcRouteHint"
|
||||||
|
},
|
||||||
|
"description": "*\nRoute hints that can each be individually used to assist in reaching the\ninvoice's destination."
|
||||||
|
},
|
||||||
|
"private": {
|
||||||
|
"type": "boolean",
|
||||||
|
"format": "boolean",
|
||||||
|
"description": "/ Whether this invoice should include routing hints for private channels."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1887,6 +1920,12 @@
|
|||||||
"cltv_expiry": {
|
"cltv_expiry": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "int64"
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"route_hints": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/lnrpcRouteHint"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2127,6 +2166,18 @@
|
|||||||
},
|
},
|
||||||
"description": "*\nA path through the channel graph which runs over one or more channels in\nsuccession. This struct carries all the information required to craft the\nSphinx onion packet, and send the payment along the first hop in the path. A\nroute is only selected as valid if all the channels have sufficient capacity to\ncarry the initial payment amount after fees are accounted for."
|
"description": "*\nA path through the channel graph which runs over one or more channels in\nsuccession. This struct carries all the information required to craft the\nSphinx onion packet, and send the payment along the first hop in the path. A\nroute is only selected as valid if all the channels have sufficient capacity to\ncarry the initial payment amount after fees are accounted for."
|
||||||
},
|
},
|
||||||
|
"lnrpcRouteHint": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"hop_hints": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/lnrpcHopHint"
|
||||||
|
},
|
||||||
|
"description": "*\nA list of hop hints that when chained together can assist in reaching a\nspecific destination."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"lnrpcRoutingPolicy": {
|
"lnrpcRoutingPolicy": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/roasbeef/btcd/btcec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -148,20 +150,69 @@ func (m *missionControl) GraphPruneView() graphPruneView {
|
|||||||
// and will now be pruned after a decay like the main view within mission
|
// and will now be pruned after a decay like the main view within mission
|
||||||
// control. We do this as we want to avoid the case where we continually try a
|
// control. We do this as we want to avoid the case where we continually try a
|
||||||
// bad edge or route multiple times in a session. This can lead to an infinite
|
// bad edge or route multiple times in a session. This can lead to an infinite
|
||||||
// loop if payment attempts take long enough.
|
// loop if payment attempts take long enough. An additional set of edges can
|
||||||
|
// also be provided to assist in reaching the payment's destination.
|
||||||
type paymentSession struct {
|
type paymentSession struct {
|
||||||
pruneViewSnapshot graphPruneView
|
pruneViewSnapshot graphPruneView
|
||||||
|
|
||||||
|
additionalEdges map[Vertex][]*channeldb.ChannelEdgePolicy
|
||||||
|
|
||||||
mc *missionControl
|
mc *missionControl
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPaymentSession creates a new payment session backed by the latest prune
|
// NewPaymentSession creates a new payment session backed by the latest prune
|
||||||
// view from Mission Control.
|
// view from Mission Control. An optional set of routing hints can be provided
|
||||||
func (m *missionControl) NewPaymentSession() *paymentSession {
|
// in order to populate additional edges to explore when finding a path to the
|
||||||
|
// payment's destination.
|
||||||
|
func (m *missionControl) NewPaymentSession(routeHints [][]HopHint,
|
||||||
|
target *btcec.PublicKey) *paymentSession {
|
||||||
|
|
||||||
viewSnapshot := m.GraphPruneView()
|
viewSnapshot := m.GraphPruneView()
|
||||||
|
|
||||||
|
edges := make(map[Vertex][]*channeldb.ChannelEdgePolicy)
|
||||||
|
|
||||||
|
// Traverse through all of the available hop hints and include them in
|
||||||
|
// our edges map, indexed by the public key of the channel's starting
|
||||||
|
// node.
|
||||||
|
for _, routeHint := range routeHints {
|
||||||
|
// If multiple hop hints are provided within a single route
|
||||||
|
// hint, we'll assume they must be chained together and sorted
|
||||||
|
// in forward order in order to reach the target successfully.
|
||||||
|
for i, hopHint := range routeHint {
|
||||||
|
// In order to determine the end node of this hint,
|
||||||
|
// we'll need to look at the next hint's start node. If
|
||||||
|
// we've reached the end of the hints list, we can
|
||||||
|
// assume we've reached the destination.
|
||||||
|
endNode := &channeldb.LightningNode{}
|
||||||
|
if i != len(routeHint)-1 {
|
||||||
|
endNode.AddPubKey(routeHint[i+1].NodeID)
|
||||||
|
} else {
|
||||||
|
endNode.AddPubKey(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, create the channel edge from the hop hint
|
||||||
|
// and add it to list of edges corresponding to the node
|
||||||
|
// at the start of the channel.
|
||||||
|
edge := &channeldb.ChannelEdgePolicy{
|
||||||
|
Node: endNode,
|
||||||
|
ChannelID: hopHint.ChannelID,
|
||||||
|
FeeBaseMSat: lnwire.MilliSatoshi(
|
||||||
|
hopHint.FeeBaseMSat,
|
||||||
|
),
|
||||||
|
FeeProportionalMillionths: lnwire.MilliSatoshi(
|
||||||
|
hopHint.FeeProportionalMillionths,
|
||||||
|
),
|
||||||
|
TimeLockDelta: hopHint.CLTVExpiryDelta,
|
||||||
|
}
|
||||||
|
|
||||||
|
v := NewVertex(hopHint.NodeID)
|
||||||
|
edges[v] = append(edges[v], edge)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &paymentSession{
|
return &paymentSession{
|
||||||
pruneViewSnapshot: viewSnapshot,
|
pruneViewSnapshot: viewSnapshot,
|
||||||
|
additionalEdges: edges,
|
||||||
mc: m,
|
mc: m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,8 +282,11 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
|||||||
// Taking into account this prune view, we'll attempt to locate a path
|
// Taking into account this prune view, we'll attempt to locate a path
|
||||||
// to our destination, respecting the recommendations from
|
// to our destination, respecting the recommendations from
|
||||||
// missionControl.
|
// missionControl.
|
||||||
path, err := findPath(nil, p.mc.graph, p.mc.selfNode, payment.Target,
|
path, err := findPath(
|
||||||
pruneView.vertexes, pruneView.edges, payment.Amount)
|
nil, p.mc.graph, p.additionalEdges, p.mc.selfNode,
|
||||||
|
payment.Target, pruneView.vertexes, pruneView.edges,
|
||||||
|
payment.Amount,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,28 @@ const (
|
|||||||
infinity = math.MaxInt64
|
infinity = math.MaxInt64
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HopHint is a routing hint that contains the minimum information of a channel
|
||||||
|
// required for an intermediate hop in a route to forward the payment to the
|
||||||
|
// next. This should be ideally used for private channels, since they are not
|
||||||
|
// publicly advertised to the network for routing.
|
||||||
|
type HopHint struct {
|
||||||
|
// NodeID is the public key of the node at the start of the channel.
|
||||||
|
NodeID *btcec.PublicKey
|
||||||
|
|
||||||
|
// ChannelID is the unique identifier of the channel.
|
||||||
|
ChannelID uint64
|
||||||
|
|
||||||
|
// FeeBaseMSat is the base fee of the channel in millisatoshis.
|
||||||
|
FeeBaseMSat uint32
|
||||||
|
|
||||||
|
// FeeProportionalMillionths is the fee rate, in millionths of a
|
||||||
|
// satoshi, for every satoshi sent through the channel.
|
||||||
|
FeeProportionalMillionths uint32
|
||||||
|
|
||||||
|
// CLTVExpiryDelta is the time-lock delta of the channel.
|
||||||
|
CLTVExpiryDelta uint16
|
||||||
|
}
|
||||||
|
|
||||||
// ChannelHop is an intermediate hop within the network with a greater
|
// ChannelHop is an intermediate hop within the network with a greater
|
||||||
// multi-hop payment route. This struct contains the relevant routing policy of
|
// multi-hop payment route. This struct contains the relevant routing policy of
|
||||||
// the particular edge, as well as the total capacity, and origin chain of the
|
// the particular edge, as well as the total capacity, and origin chain of the
|
||||||
@ -433,6 +455,7 @@ func edgeWeight(amt lnwire.MilliSatoshi, e *channeldb.ChannelEdgePolicy) int64 {
|
|||||||
// function returns a slice of ChannelHop structs which encoded the chosen path
|
// function returns a slice of ChannelHop structs which encoded the chosen path
|
||||||
// from the target to the source.
|
// from the target to the source.
|
||||||
func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
||||||
|
additionalEdges map[Vertex][]*channeldb.ChannelEdgePolicy,
|
||||||
sourceNode *channeldb.LightningNode, target *btcec.PublicKey,
|
sourceNode *channeldb.LightningNode, target *btcec.PublicKey,
|
||||||
ignoredNodes map[Vertex]struct{}, ignoredEdges map[uint64]struct{},
|
ignoredNodes map[Vertex]struct{}, ignoredEdges map[uint64]struct{},
|
||||||
amt lnwire.MilliSatoshi) ([]*ChannelHop, error) {
|
amt lnwire.MilliSatoshi) ([]*ChannelHop, error) {
|
||||||
@ -451,9 +474,8 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
// traversal.
|
// traversal.
|
||||||
var nodeHeap distanceHeap
|
var nodeHeap distanceHeap
|
||||||
|
|
||||||
// For each node/Vertex the graph we create an entry in the distance
|
// For each node in the graph, we create an entry in the distance
|
||||||
// map for the node set with a distance of "infinity". We also mark
|
// map for the node set with a distance of "infinity".
|
||||||
// add the node to our set of unvisited nodes.
|
|
||||||
distance := make(map[Vertex]nodeWithDist)
|
distance := make(map[Vertex]nodeWithDist)
|
||||||
if err := graph.ForEachNode(tx, func(_ *bolt.Tx, node *channeldb.LightningNode) error {
|
if err := graph.ForEachNode(tx, func(_ *bolt.Tx, node *channeldb.LightningNode) error {
|
||||||
// TODO(roasbeef): with larger graph can just use disk seeks
|
// TODO(roasbeef): with larger graph can just use disk seeks
|
||||||
@ -467,6 +489,86 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll also include all the nodes found within the additional edges
|
||||||
|
// that are not known to us yet in the distance map.
|
||||||
|
for vertex := range additionalEdges {
|
||||||
|
node := &channeldb.LightningNode{PubKeyBytes: vertex}
|
||||||
|
distance[vertex] = nodeWithDist{
|
||||||
|
dist: infinity,
|
||||||
|
node: node,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't always assume that the end destination is publicly
|
||||||
|
// advertised to the network and included in the graph.ForEachNode call
|
||||||
|
// above, so we'll manually include the target node.
|
||||||
|
targetVertex := NewVertex(target)
|
||||||
|
targetNode := &channeldb.LightningNode{PubKeyBytes: targetVertex}
|
||||||
|
distance[targetVertex] = nodeWithDist{
|
||||||
|
dist: infinity,
|
||||||
|
node: targetNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll use this map as a series of "previous" hop pointers. So to get
|
||||||
|
// to `Vertex` we'll take the edge that it's mapped to within `prev`.
|
||||||
|
prev := make(map[Vertex]edgeWithPrev)
|
||||||
|
|
||||||
|
// processEdge is a helper closure that will be used to make sure edges
|
||||||
|
// satisfy our specific requirements.
|
||||||
|
processEdge := func(edge *channeldb.ChannelEdgePolicy,
|
||||||
|
capacity btcutil.Amount, pivot Vertex) {
|
||||||
|
|
||||||
|
v := Vertex(edge.Node.PubKeyBytes)
|
||||||
|
|
||||||
|
// If the edge is currently disabled, then we'll stop here, as
|
||||||
|
// we shouldn't attempt to route through it.
|
||||||
|
edgeFlags := lnwire.ChanUpdateFlag(edge.Flags)
|
||||||
|
if edgeFlags&lnwire.ChanUpdateDisabled != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this vertex or edge has been black listed, then we'll skip
|
||||||
|
// exploring this edge.
|
||||||
|
if _, ok := ignoredNodes[v]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := ignoredEdges[edge.ChannelID]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the tentative distance to this new channel/edge which
|
||||||
|
// is the distance to our pivot node plus the weight of this
|
||||||
|
// edge.
|
||||||
|
tempDist := distance[pivot].dist + edgeWeight(amt, edge)
|
||||||
|
|
||||||
|
// If this new tentative distance is better than the current
|
||||||
|
// best known distance to this node, then we record the new
|
||||||
|
// better distance, and also populate our "next hop" map with
|
||||||
|
// this edge. We'll also shave off irrelevant edges by adding
|
||||||
|
// the sufficient capacity of an edge and clearing their
|
||||||
|
// min-htlc amount to our relaxation condition.
|
||||||
|
if tempDist < distance[v].dist && capacity >= amt.ToSatoshis() &&
|
||||||
|
amt >= edge.MinHTLC && edge.TimeLockDelta != 0 {
|
||||||
|
|
||||||
|
distance[v] = nodeWithDist{
|
||||||
|
dist: tempDist,
|
||||||
|
node: edge.Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
prev[v] = edgeWithPrev{
|
||||||
|
edge: &ChannelHop{
|
||||||
|
ChannelEdgePolicy: edge,
|
||||||
|
Capacity: capacity,
|
||||||
|
},
|
||||||
|
prevNode: pivot,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this new node to our heap as we'd like to further
|
||||||
|
// explore down this edge.
|
||||||
|
heap.Push(&nodeHeap, distance[v])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): also add path caching
|
// TODO(roasbeef): also add path caching
|
||||||
// * similar to route caching, but doesn't factor in the amount
|
// * similar to route caching, but doesn't factor in the amount
|
||||||
|
|
||||||
@ -483,11 +585,6 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
// heap.
|
// heap.
|
||||||
heap.Push(&nodeHeap, distance[sourceVertex])
|
heap.Push(&nodeHeap, distance[sourceVertex])
|
||||||
|
|
||||||
targetBytes := target.SerializeCompressed()
|
|
||||||
|
|
||||||
// We'll use this map as a series of "previous" hop pointers. So to get
|
|
||||||
// to `Vertex` we'll take the edge that it's mapped to within `prev`.
|
|
||||||
prev := make(map[Vertex]edgeWithPrev)
|
|
||||||
for nodeHeap.Len() != 0 {
|
for nodeHeap.Len() != 0 {
|
||||||
// Fetch the node within the smallest distance from our source
|
// Fetch the node within the smallest distance from our source
|
||||||
// from the heap.
|
// from the heap.
|
||||||
@ -497,7 +594,7 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
// If we've reached our target (or we don't have any outgoing
|
// If we've reached our target (or we don't have any outgoing
|
||||||
// edges), then we're done here and can exit the graph
|
// edges), then we're done here and can exit the graph
|
||||||
// traversal early.
|
// traversal early.
|
||||||
if bytes.Equal(bestNode.PubKeyBytes[:], targetBytes) {
|
if bytes.Equal(bestNode.PubKeyBytes[:], targetVertex[:]) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,65 +604,9 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
pivot := Vertex(bestNode.PubKeyBytes)
|
pivot := Vertex(bestNode.PubKeyBytes)
|
||||||
err := bestNode.ForEachChannel(tx, func(tx *bolt.Tx,
|
err := bestNode.ForEachChannel(tx, func(tx *bolt.Tx,
|
||||||
edgeInfo *channeldb.ChannelEdgeInfo,
|
edgeInfo *channeldb.ChannelEdgeInfo,
|
||||||
outEdge, inEdge *channeldb.ChannelEdgePolicy) error {
|
outEdge, _ *channeldb.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
v := Vertex(outEdge.Node.PubKeyBytes)
|
processEdge(outEdge, edgeInfo.Capacity, pivot)
|
||||||
|
|
||||||
// If the outgoing edge is currently disabled, then
|
|
||||||
// we'll stop here, as we shouldn't attempt to route
|
|
||||||
// through it.
|
|
||||||
edgeFlags := lnwire.ChanUpdateFlag(outEdge.Flags)
|
|
||||||
if edgeFlags&lnwire.ChanUpdateDisabled == lnwire.ChanUpdateDisabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this Vertex or edge has been black listed, then
|
|
||||||
// we'll skip exploring this edge during this
|
|
||||||
// iteration.
|
|
||||||
if _, ok := ignoredNodes[v]; ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, ok := ignoredEdges[outEdge.ChannelID]; ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the tentative distance to this new
|
|
||||||
// channel/edge which is the distance to our current
|
|
||||||
// pivot node plus the weight of this edge.
|
|
||||||
tempDist := distance[pivot].dist + edgeWeight(amt, outEdge)
|
|
||||||
|
|
||||||
// If this new tentative distance is better than the
|
|
||||||
// current best known distance to this node, then we
|
|
||||||
// record the new better distance, and also populate
|
|
||||||
// our "next hop" map with this edge. We'll also shave
|
|
||||||
// off irrelevant edges by adding the sufficient
|
|
||||||
// capacity of an edge and clearing their min-htlc
|
|
||||||
// amount to our relaxation condition.
|
|
||||||
if tempDist < distance[v].dist &&
|
|
||||||
edgeInfo.Capacity >= amt.ToSatoshis() &&
|
|
||||||
amt >= outEdge.MinHTLC &&
|
|
||||||
outEdge.TimeLockDelta != 0 {
|
|
||||||
|
|
||||||
distance[v] = nodeWithDist{
|
|
||||||
dist: tempDist,
|
|
||||||
node: outEdge.Node,
|
|
||||||
}
|
|
||||||
prev[v] = edgeWithPrev{
|
|
||||||
// We'll use the *incoming* edge here
|
|
||||||
// as we need to use the routing policy
|
|
||||||
// specified by the node this channel
|
|
||||||
// connects to.
|
|
||||||
edge: &ChannelHop{
|
|
||||||
ChannelEdgePolicy: outEdge,
|
|
||||||
Capacity: edgeInfo.Capacity,
|
|
||||||
},
|
|
||||||
prevNode: bestNode.PubKeyBytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add this new node to our heap as we'd like
|
|
||||||
// to further explore down this edge.
|
|
||||||
heap.Push(&nodeHeap, distance[v])
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(roasbeef): return min HTLC as error in end?
|
// TODO(roasbeef): return min HTLC as error in end?
|
||||||
|
|
||||||
@ -574,6 +615,15 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then, we'll examine all the additional edges from the node
|
||||||
|
// we're currently visiting. Since we don't know the capacity
|
||||||
|
// of the private channel, we'll assume it was selected as a
|
||||||
|
// routing hint due to having enough capacity for the payment
|
||||||
|
// and use the payment amount as its capacity.
|
||||||
|
for _, edge := range additionalEdges[bestNode.PubKeyBytes] {
|
||||||
|
processEdge(edge, amt.ToSatoshis(), pivot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the target node isn't found in the prev hop map, then a path
|
// If the target node isn't found in the prev hop map, then a path
|
||||||
@ -647,7 +697,8 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
// selfNode) to the target destination that's capable of carrying amt
|
// selfNode) to the target destination that's capable of carrying amt
|
||||||
// satoshis along the path before fees are calculated.
|
// satoshis along the path before fees are calculated.
|
||||||
startingPath, err := findPath(
|
startingPath, err := findPath(
|
||||||
tx, graph, source, target, ignoredVertexes, ignoredEdges, amt,
|
tx, graph, nil, source, target, ignoredVertexes, ignoredEdges,
|
||||||
|
amt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to find path: %v", err)
|
log.Errorf("Unable to find path: %v", err)
|
||||||
@ -720,8 +771,8 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph,
|
|||||||
// root path removed, we'll attempt to find another
|
// root path removed, we'll attempt to find another
|
||||||
// shortest path from the spur node to the destination.
|
// shortest path from the spur node to the destination.
|
||||||
spurPath, err := findPath(
|
spurPath, err := findPath(
|
||||||
tx, graph, spurNode, target, ignoredVertexes,
|
tx, graph, nil, spurNode, target,
|
||||||
ignoredEdges, amt,
|
ignoredVertexes, ignoredEdges, amt,
|
||||||
)
|
)
|
||||||
|
|
||||||
// If we weren't able to find a path, we'll continue to
|
// If we weren't able to find a path, we'll continue to
|
||||||
|
@ -311,8 +311,10 @@ func TestBasicGraphPathFinding(t *testing.T) {
|
|||||||
|
|
||||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||||
target := aliases["sophon"]
|
target := aliases["sophon"]
|
||||||
path, err := findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
path, err := findPath(
|
||||||
ignoredEdges, paymentAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, paymentAmt,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
}
|
}
|
||||||
@ -451,8 +453,10 @@ func TestBasicGraphPathFinding(t *testing.T) {
|
|||||||
// exist two possible paths in the graph, but the shorter (1 hop) path
|
// exist two possible paths in the graph, but the shorter (1 hop) path
|
||||||
// should be selected.
|
// should be selected.
|
||||||
target = aliases["luoji"]
|
target = aliases["luoji"]
|
||||||
path, err = findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
path, err = findPath(
|
||||||
ignoredEdges, paymentAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, paymentAmt,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find route: %v", err)
|
t.Fatalf("unable to find route: %v", err)
|
||||||
}
|
}
|
||||||
@ -485,6 +489,69 @@ func TestBasicGraphPathFinding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPathFindingWithAdditionalEdges(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
||||||
|
defer cleanUp()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceNode, err := graph.SourceNode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to fetch source node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||||
|
|
||||||
|
// In this test, we'll test that we're able to find paths through
|
||||||
|
// private channels when providing them as additional edges in our path
|
||||||
|
// finding algorithm. To do so, we'll create a new node, doge, and
|
||||||
|
// create a private channel between it and songoku. We'll then attempt
|
||||||
|
// to find a path from our source node, roasbeef, to doge.
|
||||||
|
dogePubKeyHex := "03dd46ff29a6941b4a2607525b043ec9b020b3f318a1bf281536fd7011ec59c882"
|
||||||
|
dogePubKeyBytes, err := hex.DecodeString(dogePubKeyHex)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to decode public key: %v", err)
|
||||||
|
}
|
||||||
|
dogePubKey, err := btcec.ParsePubKey(dogePubKeyBytes, btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to parse public key from bytes: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doge := &channeldb.LightningNode{}
|
||||||
|
doge.AddPubKey(dogePubKey)
|
||||||
|
doge.Alias = "doge"
|
||||||
|
|
||||||
|
// Create the channel edge going from songoku to doge and include it in
|
||||||
|
// our map of additional edges.
|
||||||
|
songokuToDoge := &channeldb.ChannelEdgePolicy{
|
||||||
|
Node: doge,
|
||||||
|
ChannelID: 1337,
|
||||||
|
FeeBaseMSat: 1,
|
||||||
|
FeeProportionalMillionths: 1000,
|
||||||
|
TimeLockDelta: 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalEdges := map[Vertex][]*channeldb.ChannelEdgePolicy{
|
||||||
|
NewVertex(aliases["songoku"]): {songokuToDoge},
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should now be able to find a path from roasbeef to doge.
|
||||||
|
path, err := findPath(
|
||||||
|
nil, graph, additionalEdges, sourceNode, dogePubKey, nil, nil,
|
||||||
|
paymentAmt,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to find private path to doge: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The path should represent the following hops:
|
||||||
|
// roasbeef -> songoku -> doge
|
||||||
|
assertExpectedPath(t, path, "songoku", "doge")
|
||||||
|
}
|
||||||
|
|
||||||
func TestKShortestPathFinding(t *testing.T) {
|
func TestKShortestPathFinding(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -529,23 +596,11 @@ func TestKShortestPathFinding(t *testing.T) {
|
|||||||
t.Fatalf("paths found not ordered properly")
|
t.Fatalf("paths found not ordered properly")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, we'll assert the exact expected ordering of both paths
|
|
||||||
// found.
|
|
||||||
assertExpectedPath := func(path []*ChannelHop, nodeAliases ...string) {
|
|
||||||
for i, hop := range path {
|
|
||||||
if hop.Node.Alias != nodeAliases[i] {
|
|
||||||
t.Fatalf("expected %v to be pos #%v in hop, "+
|
|
||||||
"instead %v was", nodeAliases[i], i,
|
|
||||||
hop.Node.Alias)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The first route should be a direct route to luo ji.
|
// The first route should be a direct route to luo ji.
|
||||||
assertExpectedPath(paths[0], "roasbeef", "luoji")
|
assertExpectedPath(t, paths[0], "roasbeef", "luoji")
|
||||||
|
|
||||||
// The second route should be a route to luo ji via satoshi.
|
// The second route should be a route to luo ji via satoshi.
|
||||||
assertExpectedPath(paths[1], "roasbeef", "satoshi", "luoji")
|
assertExpectedPath(t, paths[1], "roasbeef", "satoshi", "luoji")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewRoutePathTooLong(t *testing.T) {
|
func TestNewRoutePathTooLong(t *testing.T) {
|
||||||
@ -572,8 +627,10 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
// We start by confirming that routing a payment 20 hops away is possible.
|
// We start by confirming that routing a payment 20 hops away is possible.
|
||||||
// Alice should be able to find a valid route to ursula.
|
// Alice should be able to find a valid route to ursula.
|
||||||
target := aliases["ursula"]
|
target := aliases["ursula"]
|
||||||
_, err = findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
_, err = findPath(
|
||||||
ignoredEdges, paymentAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, paymentAmt,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("path should have been found")
|
t.Fatalf("path should have been found")
|
||||||
}
|
}
|
||||||
@ -581,8 +638,10 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
// Vincent is 21 hops away from Alice, and thus no valid route should be
|
// Vincent is 21 hops away from Alice, and thus no valid route should be
|
||||||
// presented to Alice.
|
// presented to Alice.
|
||||||
target = aliases["vincent"]
|
target = aliases["vincent"]
|
||||||
path, err := findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
path, err := findPath(
|
||||||
ignoredEdges, paymentAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, paymentAmt,
|
||||||
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should not have been able to find path, supposed to be "+
|
t.Fatalf("should not have been able to find path, supposed to be "+
|
||||||
"greater than 20 hops, found route with %v hops",
|
"greater than 20 hops, found route with %v hops",
|
||||||
@ -621,8 +680,10 @@ func TestPathNotAvailable(t *testing.T) {
|
|||||||
t.Fatalf("unable to parse pubkey: %v", err)
|
t.Fatalf("unable to parse pubkey: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = findPath(nil, graph, sourceNode, unknownNode, ignoredVertexes,
|
_, err = findPath(
|
||||||
ignoredEdges, 100)
|
nil, graph, nil, sourceNode, unknownNode, ignoredVertexes,
|
||||||
|
ignoredEdges, 100,
|
||||||
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
t.Fatalf("path shouldn't have been found: %v", err)
|
t.Fatalf("path shouldn't have been found: %v", err)
|
||||||
}
|
}
|
||||||
@ -655,8 +716,10 @@ func TestPathInsufficientCapacity(t *testing.T) {
|
|||||||
target := aliases["sophon"]
|
target := aliases["sophon"]
|
||||||
|
|
||||||
payAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
payAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
||||||
_, err = findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
_, err = findPath(
|
||||||
ignoredEdges, payAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, payAmt,
|
||||||
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -683,8 +746,10 @@ func TestRouteFailMinHTLC(t *testing.T) {
|
|||||||
// attempt should fail.
|
// attempt should fail.
|
||||||
target := aliases["songoku"]
|
target := aliases["songoku"]
|
||||||
payAmt := lnwire.MilliSatoshi(10)
|
payAmt := lnwire.MilliSatoshi(10)
|
||||||
_, err = findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
_, err = findPath(
|
||||||
ignoredEdges, payAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, payAmt,
|
||||||
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -711,8 +776,10 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
// succeed without issue, and return a single path.
|
// succeed without issue, and return a single path.
|
||||||
target := aliases["songoku"]
|
target := aliases["songoku"]
|
||||||
payAmt := lnwire.NewMSatFromSatoshis(10000)
|
payAmt := lnwire.NewMSatFromSatoshis(10000)
|
||||||
_, err = findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
_, err = findPath(
|
||||||
ignoredEdges, payAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, payAmt,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
}
|
}
|
||||||
@ -730,8 +797,10 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
|
|
||||||
// Now, if we attempt to route through that edge, we should get a
|
// Now, if we attempt to route through that edge, we should get a
|
||||||
// failure as it is no longer eligible.
|
// failure as it is no longer eligible.
|
||||||
_, err = findPath(nil, graph, sourceNode, target, ignoredVertexes,
|
_, err = findPath(
|
||||||
ignoredEdges, payAmt)
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
||||||
|
ignoredEdges, payAmt,
|
||||||
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -967,3 +1036,16 @@ func TestPathFindSpecExample(t *testing.T) {
|
|||||||
startingHeight+DefaultFinalCLTVDelta)
|
startingHeight+DefaultFinalCLTVDelta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertExpectedPath(t *testing.T, path []*ChannelHop, nodeAliases ...string) {
|
||||||
|
if len(path) != len(nodeAliases) {
|
||||||
|
t.Fatal("number of hops and number of aliases do not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, hop := range path {
|
||||||
|
if hop.Node.Alias != nodeAliases[i] {
|
||||||
|
t.Fatalf("expected %v to be pos #%v in hop, instead "+
|
||||||
|
"%v was", nodeAliases[i], i, hop.Node.Alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1482,6 +1482,16 @@ type LightningPayment struct {
|
|||||||
// indefinitely.
|
// indefinitely.
|
||||||
PayAttemptTimeout time.Duration
|
PayAttemptTimeout time.Duration
|
||||||
|
|
||||||
|
// RouteHints represents the different routing hints that can be used to
|
||||||
|
// assist a payment in reaching its destination successfully. These
|
||||||
|
// hints will act as intermediate hops along the route.
|
||||||
|
//
|
||||||
|
// NOTE: This is optional unless required by the payment. When providing
|
||||||
|
// multiple routes, ensure the hop hints within each route are chained
|
||||||
|
// together and sorted in forward order in order to reach the
|
||||||
|
// destination successfully.
|
||||||
|
RouteHints [][]HopHint
|
||||||
|
|
||||||
// TODO(roasbeef): add e2e message?
|
// TODO(roasbeef): add e2e message?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1495,7 +1505,14 @@ type LightningPayment struct {
|
|||||||
func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route, error) {
|
func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route, error) {
|
||||||
log.Tracef("Dispatching route for lightning payment: %v",
|
log.Tracef("Dispatching route for lightning payment: %v",
|
||||||
newLogClosure(func() string {
|
newLogClosure(func() string {
|
||||||
|
// Remove the public key curve parameters when logging
|
||||||
|
// the route to prevent spamming the logs.
|
||||||
payment.Target.Curve = nil
|
payment.Target.Curve = nil
|
||||||
|
for _, routeHint := range payment.RouteHints {
|
||||||
|
for _, hopHint := range routeHint {
|
||||||
|
hopHint.NodeID.Curve = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return spew.Sdump(payment)
|
return spew.Sdump(payment)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -1537,7 +1554,9 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route
|
|||||||
// Before starting the HTLC routing attempt, we'll create a fresh
|
// Before starting the HTLC routing attempt, we'll create a fresh
|
||||||
// payment session which will report our errors back to mission
|
// payment session which will report our errors back to mission
|
||||||
// control.
|
// control.
|
||||||
paySession := r.missionControl.NewPaymentSession()
|
paySession := r.missionControl.NewPaymentSession(
|
||||||
|
payment.RouteHints, payment.Target,
|
||||||
|
)
|
||||||
|
|
||||||
// We'll continue until either our payment succeeds, or we encounter a
|
// We'll continue until either our payment succeeds, or we encounter a
|
||||||
// critical error during path finding.
|
// critical error during path finding.
|
||||||
|
@ -1602,8 +1602,8 @@ func TestFindPathFeeWeighting(t *testing.T) {
|
|||||||
// the edge weighting, we should select the direct path over the 2 hop
|
// the edge weighting, we should select the direct path over the 2 hop
|
||||||
// path even though the direct path has a higher potential time lock.
|
// path even though the direct path has a higher potential time lock.
|
||||||
path, err := findPath(
|
path, err := findPath(
|
||||||
nil, ctx.graph, sourceNode, target, ignoreVertex, ignoreEdge,
|
nil, ctx.graph, nil, sourceNode, target, ignoreVertex,
|
||||||
amt,
|
ignoreEdge, amt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
|
165
rpcserver.go
165
rpcserver.go
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@ -1703,12 +1704,13 @@ func validatePayReqExpiry(payReq *zpay32.Invoice) error {
|
|||||||
// Lightning Network with a single persistent connection.
|
// Lightning Network with a single persistent connection.
|
||||||
func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer) error {
|
func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer) error {
|
||||||
// For each payment we need to know the msat amount, the destination
|
// For each payment we need to know the msat amount, the destination
|
||||||
// public key, and the payment hash.
|
// public key, the payment hash, and the optional route hints.
|
||||||
type payment struct {
|
type payment struct {
|
||||||
msat lnwire.MilliSatoshi
|
msat lnwire.MilliSatoshi
|
||||||
dest []byte
|
dest []byte
|
||||||
pHash []byte
|
pHash []byte
|
||||||
cltvDelta uint16
|
cltvDelta uint16
|
||||||
|
routeHints [][]routing.HopHint
|
||||||
}
|
}
|
||||||
payChan := make(chan *payment)
|
payChan := make(chan *payment)
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
@ -1820,6 +1822,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
|
|
||||||
p.pHash = payReq.PaymentHash[:]
|
p.pHash = payReq.PaymentHash[:]
|
||||||
p.cltvDelta = uint16(payReq.MinFinalCLTVExpiry())
|
p.cltvDelta = uint16(payReq.MinFinalCLTVExpiry())
|
||||||
|
p.routeHints = payReq.RouteHints
|
||||||
} else {
|
} else {
|
||||||
// If the payment request field was not
|
// If the payment request field was not
|
||||||
// specified, construct the payment from
|
// specified, construct the payment from
|
||||||
@ -1903,6 +1906,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
Target: destNode,
|
Target: destNode,
|
||||||
Amount: p.msat,
|
Amount: p.msat,
|
||||||
PaymentHash: rHash,
|
PaymentHash: rHash,
|
||||||
|
RouteHints: p.routeHints,
|
||||||
}
|
}
|
||||||
if p.cltvDelta != 0 {
|
if p.cltvDelta != 0 {
|
||||||
payment.FinalCLTVDelta = &p.cltvDelta
|
payment.FinalCLTVDelta = &p.cltvDelta
|
||||||
@ -1960,10 +1964,11 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
destPub *btcec.PublicKey
|
destPub *btcec.PublicKey
|
||||||
amtMSat lnwire.MilliSatoshi
|
amtMSat lnwire.MilliSatoshi
|
||||||
rHash [32]byte
|
rHash [32]byte
|
||||||
cltvDelta uint16
|
cltvDelta uint16
|
||||||
|
routeHints [][]routing.HopHint
|
||||||
)
|
)
|
||||||
|
|
||||||
// If the proto request has an encoded payment request, then we we'll
|
// If the proto request has an encoded payment request, then we we'll
|
||||||
@ -1996,6 +2001,7 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
|
|
||||||
rHash = *payReq.PaymentHash
|
rHash = *payReq.PaymentHash
|
||||||
cltvDelta = uint16(payReq.MinFinalCLTVExpiry())
|
cltvDelta = uint16(payReq.MinFinalCLTVExpiry())
|
||||||
|
routeHints = payReq.RouteHints
|
||||||
|
|
||||||
// Otherwise, the payment conditions have been manually
|
// Otherwise, the payment conditions have been manually
|
||||||
// specified in the proto.
|
// specified in the proto.
|
||||||
@ -2046,6 +2052,7 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
Target: destPub,
|
Target: destPub,
|
||||||
Amount: amtMSat,
|
Amount: amtMSat,
|
||||||
PaymentHash: rHash,
|
PaymentHash: rHash,
|
||||||
|
RouteHints: routeHints,
|
||||||
}
|
}
|
||||||
if cltvDelta != 0 {
|
if cltvDelta != 0 {
|
||||||
payment.FinalCLTVDelta = &cltvDelta
|
payment.FinalCLTVDelta = &cltvDelta
|
||||||
@ -2202,13 +2209,107 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
options = append(options, zpay32.CLTVExpiry(uint64(defaultDelta)))
|
options = append(options, zpay32.CLTVExpiry(uint64(defaultDelta)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we were requested to include routing hints in the invoice, then
|
||||||
|
// we'll fetch all of our available private channels and create routing
|
||||||
|
// hints for them.
|
||||||
|
if invoice.Private {
|
||||||
|
openChannels, err := r.server.chanDB.FetchAllChannels()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not fetch all channels")
|
||||||
|
}
|
||||||
|
|
||||||
|
graph := r.server.chanDB.ChannelGraph()
|
||||||
|
|
||||||
|
numHints := 0
|
||||||
|
for _, channel := range openChannels {
|
||||||
|
// We'll restrict the number of individual route hints
|
||||||
|
// to 20 to avoid creating overly large invoices.
|
||||||
|
if numHints > 20 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we're only interested in our private channels,
|
||||||
|
// we'll skip public ones.
|
||||||
|
isPublic := channel.ChannelFlags&lnwire.FFAnnounceChannel != 0
|
||||||
|
if isPublic {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the counterparty has enough balance in the
|
||||||
|
// channel for our amount. We do this in order to reduce
|
||||||
|
// payment errors when attempting to use this channel
|
||||||
|
// as a hint.
|
||||||
|
chanPoint := lnwire.NewChanIDFromOutPoint(
|
||||||
|
&channel.FundingOutpoint,
|
||||||
|
)
|
||||||
|
if amtMSat >= channel.LocalCommitment.RemoteBalance {
|
||||||
|
rpcsLog.Debugf("Skipping channel %v due to "+
|
||||||
|
"not having enough remote balance",
|
||||||
|
chanPoint)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the channel is active.
|
||||||
|
link, err := r.server.htlcSwitch.GetLink(chanPoint)
|
||||||
|
if err != nil {
|
||||||
|
rpcsLog.Errorf("Unable to get link for "+
|
||||||
|
"channel %v: %v", chanPoint, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !link.EligibleToForward() {
|
||||||
|
rpcsLog.Debugf("Skipping link %v due to not "+
|
||||||
|
"being eligible to forward payments",
|
||||||
|
chanPoint)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the policies for each end of the channel.
|
||||||
|
chanID := channel.ShortChanID.ToUint64()
|
||||||
|
_, p1, p2, err := graph.FetchChannelEdgesByID(chanID)
|
||||||
|
if err != nil {
|
||||||
|
rpcsLog.Errorf("Unable to fetch the routing "+
|
||||||
|
"policies for the edges of the channel "+
|
||||||
|
"%v: %v", chanPoint, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we'll need to determine which is the correct
|
||||||
|
// policy for HTLCs being sent from the remote node.
|
||||||
|
var remotePolicy *channeldb.ChannelEdgePolicy
|
||||||
|
|
||||||
|
remotePub := channel.IdentityPub.SerializeCompressed()
|
||||||
|
if bytes.Equal(remotePub, p1.Node.PubKeyBytes[:]) {
|
||||||
|
remotePolicy = p1
|
||||||
|
} else {
|
||||||
|
remotePolicy = p2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, create the routing hint for this channel and
|
||||||
|
// add it to our list of route hints.
|
||||||
|
hint := routing.HopHint{
|
||||||
|
NodeID: channel.IdentityPub,
|
||||||
|
ChannelID: chanID,
|
||||||
|
FeeBaseMSat: uint32(remotePolicy.FeeBaseMSat),
|
||||||
|
FeeProportionalMillionths: uint32(
|
||||||
|
remotePolicy.FeeProportionalMillionths,
|
||||||
|
),
|
||||||
|
CLTVExpiryDelta: remotePolicy.TimeLockDelta,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the route hint in our set of options that
|
||||||
|
// will be used when creating the invoice.
|
||||||
|
routeHint := []routing.HopHint{hint}
|
||||||
|
options = append(options, zpay32.RouteHint(routeHint))
|
||||||
|
|
||||||
|
numHints++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Create and encode the payment request as a bech32 (zpay32) string.
|
// Create and encode the payment request as a bech32 (zpay32) string.
|
||||||
creationDate := time.Now()
|
creationDate := time.Now()
|
||||||
payReq, err := zpay32.NewInvoice(
|
payReq, err := zpay32.NewInvoice(
|
||||||
activeNetParams.Params,
|
activeNetParams.Params, rHash, creationDate, options...,
|
||||||
rHash,
|
|
||||||
creationDate,
|
|
||||||
options...,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -2282,6 +2383,9 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) {
|
|||||||
// The expiry will default to 9 blocks if not specified explicitly.
|
// The expiry will default to 9 blocks if not specified explicitly.
|
||||||
cltvExpiry := decoded.MinFinalCLTVExpiry()
|
cltvExpiry := decoded.MinFinalCLTVExpiry()
|
||||||
|
|
||||||
|
// Convert between the `lnrpc` and `routing` types.
|
||||||
|
routeHints := createRPCRouteHints(decoded.RouteHints)
|
||||||
|
|
||||||
preimage := invoice.Terms.PaymentPreimage
|
preimage := invoice.Terms.PaymentPreimage
|
||||||
satAmt := invoice.Terms.Value.ToSatoshis()
|
satAmt := invoice.Terms.Value.ToSatoshis()
|
||||||
|
|
||||||
@ -2299,9 +2403,40 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) {
|
|||||||
Expiry: expiry,
|
Expiry: expiry,
|
||||||
CltvExpiry: cltvExpiry,
|
CltvExpiry: cltvExpiry,
|
||||||
FallbackAddr: fallbackAddr,
|
FallbackAddr: fallbackAddr,
|
||||||
|
RouteHints: routeHints,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createRPCRouteHints takes in the decoded form of an invoice's route hints
|
||||||
|
// and converts them into the lnrpc type.
|
||||||
|
func createRPCRouteHints(routeHints [][]routing.HopHint) []*lnrpc.RouteHint {
|
||||||
|
var res []*lnrpc.RouteHint
|
||||||
|
|
||||||
|
for _, route := range routeHints {
|
||||||
|
hopHints := make([]*lnrpc.HopHint, 0, len(route))
|
||||||
|
for _, hop := range route {
|
||||||
|
pubKey := hex.EncodeToString(
|
||||||
|
hop.NodeID.SerializeCompressed(),
|
||||||
|
)
|
||||||
|
|
||||||
|
hint := &lnrpc.HopHint{
|
||||||
|
NodeId: pubKey,
|
||||||
|
ChanId: hop.ChannelID,
|
||||||
|
FeeBaseMsat: hop.FeeBaseMSat,
|
||||||
|
FeeProportionalMillionths: hop.FeeProportionalMillionths,
|
||||||
|
CltvExpiryDelta: uint32(hop.CLTVExpiryDelta),
|
||||||
|
}
|
||||||
|
|
||||||
|
hopHints = append(hopHints, hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
routeHint := &lnrpc.RouteHint{HopHints: hopHints}
|
||||||
|
res = append(res, routeHint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// LookupInvoice attempts to look up an invoice according to its payment hash.
|
// LookupInvoice attempts to look up an invoice according to its payment hash.
|
||||||
// The passed payment hash *must* be exactly 32 bytes, if not an error is
|
// The passed payment hash *must* be exactly 32 bytes, if not an error is
|
||||||
// returned.
|
// returned.
|
||||||
@ -3120,6 +3255,9 @@ func (r *rpcServer) DecodePayReq(ctx context.Context,
|
|||||||
// explicitly.
|
// explicitly.
|
||||||
expiry := int64(payReq.Expiry().Seconds())
|
expiry := int64(payReq.Expiry().Seconds())
|
||||||
|
|
||||||
|
// Convert between the `lnrpc` and `routing` types.
|
||||||
|
routeHints := createRPCRouteHints(payReq.RouteHints)
|
||||||
|
|
||||||
amt := int64(0)
|
amt := int64(0)
|
||||||
if payReq.MilliSat != nil {
|
if payReq.MilliSat != nil {
|
||||||
amt = int64(payReq.MilliSat.ToSatoshis())
|
amt = int64(payReq.MilliSat.ToSatoshis())
|
||||||
@ -3136,6 +3274,7 @@ func (r *rpcServer) DecodePayReq(ctx context.Context,
|
|||||||
FallbackAddr: fallbackAddr,
|
FallbackAddr: fallbackAddr,
|
||||||
Expiry: expiry,
|
Expiry: expiry,
|
||||||
CltvExpiry: int64(payReq.MinFinalCLTVExpiry()),
|
CltvExpiry: int64(payReq.MinFinalCLTVExpiry()),
|
||||||
|
RouteHints: routeHints,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +37,9 @@ const (
|
|||||||
// with zeroes.
|
// with zeroes.
|
||||||
pubKeyBase32Len = 53
|
pubKeyBase32Len = 53
|
||||||
|
|
||||||
// routingInfoLen is the number of bytes needed to encode the extra
|
// hopHintLen is the number of bytes needed to encode the hop hint of a
|
||||||
// routing info of a single private route.
|
// single private route.
|
||||||
routingInfoLen = 51
|
hopHintLen = 51
|
||||||
|
|
||||||
// The following byte values correspond to the supported field types.
|
// The following byte values correspond to the supported field types.
|
||||||
// The field name is the character representing that 5-bit value in the
|
// The field name is the character representing that 5-bit value in the
|
||||||
@ -141,31 +141,12 @@ type Invoice struct {
|
|||||||
// Optional.
|
// Optional.
|
||||||
FallbackAddr btcutil.Address
|
FallbackAddr btcutil.Address
|
||||||
|
|
||||||
// RoutingInfo is one or more entries containing extra routing
|
// RouteHints represents one or more different route hints. Each route
|
||||||
// information for a private route to the target node.
|
// hint can be individually used to reach the destination. These usually
|
||||||
// Optional.
|
// represent private routes.
|
||||||
RoutingInfo []ExtraRoutingInfo
|
//
|
||||||
}
|
// NOTE: This is optional.
|
||||||
|
RouteHints [][]routing.HopHint
|
||||||
// ExtraRoutingInfo holds the information needed to route a payment along one
|
|
||||||
// private channel.
|
|
||||||
type ExtraRoutingInfo struct {
|
|
||||||
// PubKey is the public key of the node at the start of this channel.
|
|
||||||
PubKey *btcec.PublicKey
|
|
||||||
|
|
||||||
// ShortChanID is the channel ID of the channel.
|
|
||||||
ShortChanID uint64
|
|
||||||
|
|
||||||
// FeeBaseMsat is the base fee in millisatoshis required for routing
|
|
||||||
// along this channel.
|
|
||||||
FeeBaseMsat uint32
|
|
||||||
|
|
||||||
// FeeProportionalMillionths is the proportional fee in millionths of a
|
|
||||||
// satoshi required for routing along this channel.
|
|
||||||
FeeProportionalMillionths uint32
|
|
||||||
|
|
||||||
// CltvExpDelta is this channel's cltv expiry delta.
|
|
||||||
CltvExpDelta uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amount is a functional option that allows callers of NewInvoice to set the
|
// Amount is a functional option that allows callers of NewInvoice to set the
|
||||||
@ -231,12 +212,11 @@ func FallbackAddr(fallbackAddr btcutil.Address) func(*Invoice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoutingInfo is a functional option that allows callers of NewInvoice to set
|
// RouteHint is a functional option that allows callers of NewInvoice to add
|
||||||
// one or more entries containing extra routing information for a private route
|
// one or more hop hints that represent a private route to the destination.
|
||||||
// to the target node.
|
func RouteHint(routeHint []routing.HopHint) func(*Invoice) {
|
||||||
func RoutingInfo(routingInfo []ExtraRoutingInfo) func(*Invoice) {
|
|
||||||
return func(i *Invoice) {
|
return func(i *Invoice) {
|
||||||
i.RoutingInfo = routingInfo
|
i.RouteHints = append(i.RouteHints, routeHint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,10 +505,19 @@ func validateInvoice(invoice *Invoice) error {
|
|||||||
return fmt.Errorf("neither description nor description hash set")
|
return fmt.Errorf("neither description nor description hash set")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can have at most 20 extra hops for routing.
|
// We'll restrict invoices to include up to 20 different private route
|
||||||
if len(invoice.RoutingInfo) > 20 {
|
// hints. We do this to avoid overly large invoices.
|
||||||
return fmt.Errorf("too many extra hops: %d",
|
if len(invoice.RouteHints) > 20 {
|
||||||
len(invoice.RoutingInfo))
|
return fmt.Errorf("too many private routes: %d",
|
||||||
|
len(invoice.RouteHints))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each route hint can have at most 20 hops.
|
||||||
|
for i, routeHint := range invoice.RouteHints {
|
||||||
|
if len(routeHint) > 20 {
|
||||||
|
return fmt.Errorf("route hint %d has too many extra "+
|
||||||
|
"hops: %d", i, len(routeHint))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we support the field lengths.
|
// Check that we support the field lengths.
|
||||||
@ -666,13 +655,15 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
|
|||||||
|
|
||||||
invoice.FallbackAddr, err = parseFallbackAddr(base32Data, net)
|
invoice.FallbackAddr, err = parseFallbackAddr(base32Data, net)
|
||||||
case fieldTypeR:
|
case fieldTypeR:
|
||||||
if invoice.RoutingInfo != nil {
|
// An `r` field can be included in an invoice multiple
|
||||||
// We skip the field if we have already seen a
|
// times, so we won't skip it if we have already seen
|
||||||
// supported one.
|
// one.
|
||||||
continue
|
routeHint, err := parseRouteHint(base32Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice.RoutingInfo, err = parseRoutingInfo(base32Data)
|
invoice.RouteHints = append(invoice.RouteHints, routeHint)
|
||||||
default:
|
default:
|
||||||
// Ignore unknown type.
|
// Ignore unknown type.
|
||||||
}
|
}
|
||||||
@ -850,35 +841,38 @@ func parseFallbackAddr(data []byte, net *chaincfg.Params) (btcutil.Address, erro
|
|||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseRoutingInfo converts the data (encoded in base32) into an array
|
// parseRouteHint converts the data (encoded in base32) into an array containing
|
||||||
// containing one or more entries of extra routing info.
|
// one or more routing hop hints that represent a single route hint.
|
||||||
func parseRoutingInfo(data []byte) ([]ExtraRoutingInfo, error) {
|
func parseRouteHint(data []byte) ([]routing.HopHint, error) {
|
||||||
base256Data, err := bech32.ConvertBits(data, 5, 8, false)
|
base256Data, err := bech32.ConvertBits(data, 5, 8, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(base256Data)%routingInfoLen != 0 {
|
if len(base256Data)%hopHintLen != 0 {
|
||||||
return nil, fmt.Errorf("expected length multiple of %d bytes, got %d",
|
return nil, fmt.Errorf("expected length multiple of %d bytes, "+
|
||||||
routingInfoLen, len(base256Data))
|
"got %d", hopHintLen, len(base256Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
var routingInfo []ExtraRoutingInfo
|
var routeHint []routing.HopHint
|
||||||
info := ExtraRoutingInfo{}
|
|
||||||
for len(base256Data) > 0 {
|
for len(base256Data) > 0 {
|
||||||
info.PubKey, err = btcec.ParsePubKey(base256Data[:33], btcec.S256())
|
hopHint := routing.HopHint{}
|
||||||
|
hopHint.NodeID, err = btcec.ParsePubKey(base256Data[:33], btcec.S256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
info.ShortChanID = binary.BigEndian.Uint64(base256Data[33:41])
|
hopHint.ChannelID = binary.BigEndian.Uint64(base256Data[33:41])
|
||||||
info.FeeBaseMsat = binary.BigEndian.Uint32(base256Data[41:45])
|
hopHint.FeeBaseMSat = binary.BigEndian.Uint32(base256Data[41:45])
|
||||||
info.FeeProportionalMillionths = binary.BigEndian.Uint32(base256Data[45:49])
|
hopHint.FeeProportionalMillionths = binary.BigEndian.Uint32(base256Data[45:49])
|
||||||
info.CltvExpDelta = binary.BigEndian.Uint16(base256Data[49:51])
|
hopHint.CLTVExpiryDelta = binary.BigEndian.Uint16(base256Data[49:51])
|
||||||
routingInfo = append(routingInfo, info)
|
|
||||||
|
routeHint = append(routeHint, hopHint)
|
||||||
|
|
||||||
base256Data = base256Data[51:]
|
base256Data = base256Data[51:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return routingInfo, nil
|
return routeHint, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeTaggedFields writes the non-nil tagged fields of the Invoice to the
|
// writeTaggedFields writes the non-nil tagged fields of the Invoice to the
|
||||||
@ -977,25 +971,37 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(invoice.RoutingInfo) > 0 {
|
for _, routeHint := range invoice.RouteHints {
|
||||||
// Each extra routing info is encoded using 51 bytes.
|
// Each hop hint is encoded using 51 bytes, so we'll make to
|
||||||
routingDataBase256 := make([]byte, 0, 51*len(invoice.RoutingInfo))
|
// sure to allocate enough space for the whole route hint.
|
||||||
for _, r := range invoice.RoutingInfo {
|
routeHintBase256 := make([]byte, 0, hopHintLen*len(routeHint))
|
||||||
base256 := make([]byte, 51)
|
|
||||||
copy(base256[:33], r.PubKey.SerializeCompressed())
|
for _, hopHint := range routeHint {
|
||||||
binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID)
|
hopHintBase256 := make([]byte, hopHintLen)
|
||||||
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat)
|
copy(hopHintBase256[:33], hopHint.NodeID.SerializeCompressed())
|
||||||
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
|
binary.BigEndian.PutUint64(
|
||||||
binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta)
|
hopHintBase256[33:41], hopHint.ChannelID,
|
||||||
routingDataBase256 = append(routingDataBase256, base256...)
|
)
|
||||||
|
binary.BigEndian.PutUint32(
|
||||||
|
hopHintBase256[41:45], hopHint.FeeBaseMSat,
|
||||||
|
)
|
||||||
|
binary.BigEndian.PutUint32(
|
||||||
|
hopHintBase256[45:49], hopHint.FeeProportionalMillionths,
|
||||||
|
)
|
||||||
|
binary.BigEndian.PutUint16(
|
||||||
|
hopHintBase256[49:51], hopHint.CLTVExpiryDelta,
|
||||||
|
)
|
||||||
|
routeHintBase256 = append(routeHintBase256, hopHintBase256...)
|
||||||
}
|
}
|
||||||
routingDataBase32, err := bech32.ConvertBits(routingDataBase256,
|
|
||||||
8, 5, true)
|
routeHintBase32, err := bech32.ConvertBits(
|
||||||
|
routeHintBase256, 8, 5, true,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeTaggedField(bufferBase32, fieldTypeR, routingDataBase32)
|
err = writeTaggedField(bufferBase32, fieldTypeR, routeHintBase32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/chaincfg"
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
"github.com/roasbeef/btcutil"
|
"github.com/roasbeef/btcutil"
|
||||||
@ -706,18 +707,18 @@ func TestParseFallbackAddr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestParseRoutingInfo checks that the routing info is properly parsed.
|
// TestParseRouteHint checks that the routing info is properly parsed.
|
||||||
func TestParseRoutingInfo(t *testing.T) {
|
func TestParseRouteHint(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
var testSingleHopData []byte
|
var testSingleHopData []byte
|
||||||
for _, r := range testSingleHop {
|
for _, r := range testSingleHop {
|
||||||
base256 := make([]byte, 51)
|
base256 := make([]byte, 51)
|
||||||
copy(base256[:33], r.PubKey.SerializeCompressed())
|
copy(base256[:33], r.NodeID.SerializeCompressed())
|
||||||
binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID)
|
binary.BigEndian.PutUint64(base256[33:41], r.ChannelID)
|
||||||
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat)
|
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMSat)
|
||||||
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
|
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
|
||||||
binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta)
|
binary.BigEndian.PutUint16(base256[49:51], r.CLTVExpiryDelta)
|
||||||
testSingleHopData = append(testSingleHopData, base256...)
|
testSingleHopData = append(testSingleHopData, base256...)
|
||||||
}
|
}
|
||||||
testSingleHopData, _ = bech32.ConvertBits(testSingleHopData, 8, 5, true)
|
testSingleHopData, _ = bech32.ConvertBits(testSingleHopData, 8, 5, true)
|
||||||
@ -725,11 +726,11 @@ func TestParseRoutingInfo(t *testing.T) {
|
|||||||
var testDoubleHopData []byte
|
var testDoubleHopData []byte
|
||||||
for _, r := range testDoubleHop {
|
for _, r := range testDoubleHop {
|
||||||
base256 := make([]byte, 51)
|
base256 := make([]byte, 51)
|
||||||
copy(base256[:33], r.PubKey.SerializeCompressed())
|
copy(base256[:33], r.NodeID.SerializeCompressed())
|
||||||
binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID)
|
binary.BigEndian.PutUint64(base256[33:41], r.ChannelID)
|
||||||
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat)
|
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMSat)
|
||||||
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
|
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
|
||||||
binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta)
|
binary.BigEndian.PutUint16(base256[49:51], r.CLTVExpiryDelta)
|
||||||
testDoubleHopData = append(testDoubleHopData, base256...)
|
testDoubleHopData = append(testDoubleHopData, base256...)
|
||||||
}
|
}
|
||||||
testDoubleHopData, _ = bech32.ConvertBits(testDoubleHopData, 8, 5, true)
|
testDoubleHopData, _ = bech32.ConvertBits(testDoubleHopData, 8, 5, true)
|
||||||
@ -737,7 +738,7 @@ func TestParseRoutingInfo(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
data []byte
|
data []byte
|
||||||
valid bool
|
valid bool
|
||||||
result []ExtraRoutingInfo
|
result []routing.HopHint
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
data: []byte{0x0, 0x0, 0x0, 0x0},
|
data: []byte{0x0, 0x0, 0x0, 0x0},
|
||||||
@ -746,7 +747,7 @@ func TestParseRoutingInfo(t *testing.T) {
|
|||||||
{
|
{
|
||||||
data: []byte{},
|
data: []byte{},
|
||||||
valid: true,
|
valid: true,
|
||||||
result: []ExtraRoutingInfo{},
|
result: []routing.HopHint{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: testSingleHopData,
|
data: testSingleHopData,
|
||||||
@ -765,13 +766,13 @@ func TestParseRoutingInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
routingInfo, err := parseRoutingInfo(test.data)
|
routeHint, err := parseRouteHint(test.data)
|
||||||
if (err == nil) != test.valid {
|
if (err == nil) != test.valid {
|
||||||
t.Errorf("routing info decoding test %d failed: %v", i, err)
|
t.Errorf("routing info decoding test %d failed: %v", i, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if test.valid {
|
if test.valid {
|
||||||
if err := compareRoutingInfos(test.result, routingInfo); err != nil {
|
if err := compareRouteHints(test.result, routeHint); err != nil {
|
||||||
t.Fatalf("test %d failed decoding routing info: %v", i, err)
|
t.Fatalf("test %d failed decoding routing info: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/chaincfg"
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
@ -47,34 +48,34 @@ var (
|
|||||||
testAddrMainnetP2WPKH, _ = btcutil.DecodeAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", &chaincfg.MainNetParams)
|
testAddrMainnetP2WPKH, _ = btcutil.DecodeAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", &chaincfg.MainNetParams)
|
||||||
testAddrMainnetP2WSH, _ = btcutil.DecodeAddress("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", &chaincfg.MainNetParams)
|
testAddrMainnetP2WSH, _ = btcutil.DecodeAddress("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", &chaincfg.MainNetParams)
|
||||||
|
|
||||||
testRoutingInfoPubkeyBytes, _ = hex.DecodeString("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255")
|
testHopHintPubkeyBytes1, _ = hex.DecodeString("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255")
|
||||||
testRoutingInfoPubkey, _ = btcec.ParsePubKey(testRoutingInfoPubkeyBytes, btcec.S256())
|
testHopHintPubkey1, _ = btcec.ParsePubKey(testHopHintPubkeyBytes1, btcec.S256())
|
||||||
testRoutingInfoPubkeyBytes2, _ = hex.DecodeString("039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255")
|
testHopHintPubkeyBytes2, _ = hex.DecodeString("039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255")
|
||||||
testRoutingInfoPubkey2, _ = btcec.ParsePubKey(testRoutingInfoPubkeyBytes2, btcec.S256())
|
testHopHintPubkey2, _ = btcec.ParsePubKey(testHopHintPubkeyBytes2, btcec.S256())
|
||||||
|
|
||||||
testSingleHop = []ExtraRoutingInfo{
|
testSingleHop = []routing.HopHint{
|
||||||
{
|
{
|
||||||
PubKey: testRoutingInfoPubkey,
|
NodeID: testHopHintPubkey1,
|
||||||
ShortChanID: 0x0102030405060708,
|
ChannelID: 0x0102030405060708,
|
||||||
FeeBaseMsat: 0,
|
FeeBaseMSat: 0,
|
||||||
FeeProportionalMillionths: 20,
|
FeeProportionalMillionths: 20,
|
||||||
CltvExpDelta: 3,
|
CLTVExpiryDelta: 3,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
testDoubleHop = []ExtraRoutingInfo{
|
testDoubleHop = []routing.HopHint{
|
||||||
{
|
{
|
||||||
PubKey: testRoutingInfoPubkey,
|
NodeID: testHopHintPubkey1,
|
||||||
ShortChanID: 0x0102030405060708,
|
ChannelID: 0x0102030405060708,
|
||||||
FeeBaseMsat: 1,
|
FeeBaseMSat: 1,
|
||||||
FeeProportionalMillionths: 20,
|
FeeProportionalMillionths: 20,
|
||||||
CltvExpDelta: 3,
|
CLTVExpiryDelta: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
PubKey: testRoutingInfoPubkey2,
|
NodeID: testHopHintPubkey2,
|
||||||
ShortChanID: 0x030405060708090a,
|
ChannelID: 0x030405060708090a,
|
||||||
FeeBaseMsat: 2,
|
FeeBaseMSat: 2,
|
||||||
FeeProportionalMillionths: 30,
|
FeeProportionalMillionths: 30,
|
||||||
CltvExpDelta: 4,
|
CLTVExpiryDelta: 4,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +414,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testRustyAddr,
|
FallbackAddr: testRustyAddr,
|
||||||
RoutingInfo: testSingleHop,
|
RouteHints: [][]routing.HopHint{testSingleHop},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -436,7 +437,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testRustyAddr,
|
FallbackAddr: testRustyAddr,
|
||||||
RoutingInfo: testDoubleHop,
|
RouteHints: [][]routing.HopHint{testDoubleHop},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -680,7 +681,7 @@ func TestNewInvoice(t *testing.T) {
|
|||||||
Amount(testMillisat20mBTC),
|
Amount(testMillisat20mBTC),
|
||||||
DescriptionHash(testDescriptionHash),
|
DescriptionHash(testDescriptionHash),
|
||||||
FallbackAddr(testRustyAddr),
|
FallbackAddr(testRustyAddr),
|
||||||
RoutingInfo(testDoubleHop),
|
RouteHint(testDoubleHop),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
valid: true,
|
valid: true,
|
||||||
@ -802,7 +803,19 @@ func compareInvoices(expected, actual *Invoice) error {
|
|||||||
expected.FallbackAddr, actual.FallbackAddr)
|
expected.FallbackAddr, actual.FallbackAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return compareRoutingInfos(expected.RoutingInfo, actual.RoutingInfo)
|
if len(expected.RouteHints) != len(actual.RouteHints) {
|
||||||
|
return fmt.Errorf("expected %d RouteHints, got %d",
|
||||||
|
len(expected.RouteHints), len(actual.RouteHints))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, routeHint := range expected.RouteHints {
|
||||||
|
err := compareRouteHints(routeHint, actual.RouteHints[i])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func comparePubkeys(a, b *btcec.PublicKey) bool {
|
func comparePubkeys(a, b *btcec.PublicKey) bool {
|
||||||
@ -831,36 +844,36 @@ func compareHashes(a, b *[32]byte) bool {
|
|||||||
return bytes.Equal(a[:], b[:])
|
return bytes.Equal(a[:], b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareRoutingInfos(a, b []ExtraRoutingInfo) error {
|
func compareRouteHints(a, b []routing.HopHint) error {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return fmt.Errorf("expected len routingInfo %d, got %d",
|
return fmt.Errorf("expected len routingInfo %d, got %d",
|
||||||
len(a), len(b))
|
len(a), len(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(a); i++ {
|
for i := 0; i < len(a); i++ {
|
||||||
if !comparePubkeys(a[i].PubKey, b[i].PubKey) {
|
if !comparePubkeys(a[i].NodeID, b[i].NodeID) {
|
||||||
return fmt.Errorf("expected routingInfo pubkey %x, "+
|
return fmt.Errorf("expected routeHint nodeID %x, "+
|
||||||
"got %x", a[i].PubKey, b[i].PubKey)
|
"got %x", a[i].NodeID, b[i].NodeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a[i].ShortChanID != b[i].ShortChanID {
|
if a[i].ChannelID != b[i].ChannelID {
|
||||||
return fmt.Errorf("expected routingInfo shortChanID "+
|
return fmt.Errorf("expected routeHint channelID "+
|
||||||
"%d, got %d", a[i].ShortChanID, b[i].ShortChanID)
|
"%d, got %d", a[i].ChannelID, b[i].ChannelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a[i].FeeBaseMsat != b[i].FeeBaseMsat {
|
if a[i].FeeBaseMSat != b[i].FeeBaseMSat {
|
||||||
return fmt.Errorf("expected routingInfo feeBaseMsat %d, got %d",
|
return fmt.Errorf("expected routeHint feeBaseMsat %d, got %d",
|
||||||
a[i].FeeBaseMsat, b[i].FeeBaseMsat)
|
a[i].FeeBaseMSat, b[i].FeeBaseMSat)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a[i].FeeProportionalMillionths != b[i].FeeProportionalMillionths {
|
if a[i].FeeProportionalMillionths != b[i].FeeProportionalMillionths {
|
||||||
return fmt.Errorf("expected routingInfo feeProportionalMillionths %d, got %d",
|
return fmt.Errorf("expected routeHint feeProportionalMillionths %d, got %d",
|
||||||
a[i].FeeProportionalMillionths, b[i].FeeProportionalMillionths)
|
a[i].FeeProportionalMillionths, b[i].FeeProportionalMillionths)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a[i].CltvExpDelta != b[i].CltvExpDelta {
|
if a[i].CLTVExpiryDelta != b[i].CLTVExpiryDelta {
|
||||||
return fmt.Errorf("expected routingInfo cltvExpDelta "+
|
return fmt.Errorf("expected routeHint cltvExpiryDelta "+
|
||||||
"%d, got %d", a[i].CltvExpDelta, b[i].CltvExpDelta)
|
"%d, got %d", a[i].CLTVExpiryDelta, b[i].CLTVExpiryDelta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user