Merge pull request #5047 from wpaulino/import-account-or-pubkey

multi: support derived public key import
This commit is contained in:
Olaoluwa Osuntokun 2021-04-05 19:41:11 -07:00 committed by GitHub
commit d8ecc16eb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 4863 additions and 1558 deletions

@ -77,7 +77,7 @@ func syncNotifierWithMiner(t *testing.T, notifier *BitcoindNotifier,
t.Helper() t.Helper()
_, minerHeight, err := miner.Node.GetBestBlock() _, minerHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to retrieve miner's current height: %v", err) t.Fatalf("unable to retrieve miner's current height: %v", err)
} }
@ -173,7 +173,7 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
"mempool, but did not: %v", txStatus) "mempool, but did not: %v", txStatus)
} }
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -247,14 +247,14 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
// ensured above. // ensured above.
outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
spendTxHash, err := miner.Node.SendRawTransaction(spendTx, true) spendTxHash, err := miner.Client.SendRawTransaction(spendTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast tx: %v", err) t.Fatalf("unable to broadcast tx: %v", err)
} }
if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil { if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }

@ -132,7 +132,7 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
// We'll now confirm this transaction and re-attempt to retrieve its // We'll now confirm this transaction and re-attempt to retrieve its
// confirmation details. // confirmation details.
if _, err := harness.Node.Generate(1); err != nil { if _, err := harness.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -188,7 +188,7 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
// Now, we'll create a test transaction and attempt to retrieve its // Now, we'll create a test transaction and attempt to retrieve its
// confirmation details. We'll note its broadcast height to use as the // confirmation details. We'll note its broadcast height to use as the
// height hint when manually scanning the chain. // height hint when manually scanning the chain.
_, currentHeight, err := harness.Node.GetBestBlock() _, currentHeight, err := harness.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to retrieve current height: %v", err) t.Fatalf("unable to retrieve current height: %v", err)
} }
@ -219,7 +219,7 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
// We'll now confirm this transaction and re-attempt to retrieve its // We'll now confirm this transaction and re-attempt to retrieve its
// confirmation details. // confirmation details.
if _, err := harness.Node.Generate(1); err != nil { if _, err := harness.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }

@ -43,7 +43,7 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -67,7 +67,7 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
// Now generate a single block, the transaction should be included which // Now generate a single block, the transaction should be included which
// should trigger a notification event. // should trigger a notification event.
blockHash, err := miner.Node.Generate(1) blockHash, err := miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -81,7 +81,7 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
// Finally, we'll verify that the tx index returned is the exact same // Finally, we'll verify that the tx index returned is the exact same
// as the tx index of the transaction within the block itself. // as the tx index of the transaction within the block itself.
msgBlock, err := miner.Node.GetBlock(blockHash[0]) msgBlock, err := miner.Client.GetBlock(blockHash[0])
if err != nil { if err != nil {
t.Fatalf("unable to fetch block: %v", err) t.Fatalf("unable to fetch block: %v", err)
} }
@ -117,7 +117,7 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -139,7 +139,7 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
// Now generate a six blocks. The transaction should be included in the // Now generate a six blocks. The transaction should be included in the
// first block, which will be built upon by the other 5 blocks. // first block, which will be built upon by the other 5 blocks.
if _, err := miner.Node.Generate(6); err != nil { if _, err := miner.Client.Generate(6); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -163,7 +163,7 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
confSpread := [6]uint32{1, 2, 3, 6, 20, 22} confSpread := [6]uint32{1, 2, 3, 6, 20, 22}
confIntents := make([]*chainntnfs.ConfirmationEvent, len(confSpread)) confIntents := make([]*chainntnfs.ConfirmationEvent, len(confSpread))
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -215,7 +215,7 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
// Generate the number of blocks necessary to trigger this // Generate the number of blocks necessary to trigger this
// current confirmation notification. // current confirmation notification.
if _, err := miner.Node.Generate(blocksToGen); err != nil { if _, err := miner.Client.Generate(blocksToGen); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -275,7 +275,7 @@ func testSpendNotification(miner *rpctest.Harness,
// To do so, we first create a new output to our test target address. // To do so, we first create a new output to our test target address.
outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -308,7 +308,7 @@ func testSpendNotification(miner *rpctest.Harness,
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
// Broadcast our spending transaction. // Broadcast our spending transaction.
spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true) spenderSha, err := miner.Client.SendRawTransaction(spendingTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast tx: %v", err) t.Fatalf("unable to broadcast tx: %v", err)
} }
@ -365,11 +365,11 @@ func testSpendNotification(miner *rpctest.Harness,
// Now we mine a single block, which should include our spend. The // Now we mine a single block, which should include our spend. The
// notification should also be sent off. // notification should also be sent off.
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
_, currentHeight, err = miner.Node.GetBestBlock() _, currentHeight, err = miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -425,7 +425,7 @@ func testBlockEpochNotification(miner *rpctest.Harness,
// Now generate 10 blocks, the clients above should each receive 10 // Now generate 10 blocks, the clients above should each receive 10
// notifications, thereby unblocking the goroutine above. // notifications, thereby unblocking the goroutine above.
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Client.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -455,7 +455,7 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
numConfs = 1 numConfs = 1
) )
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -492,7 +492,7 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
// Finally, generate a single block which should trigger the unblocking // Finally, generate a single block which should trigger the unblocking
// of all numConfsClients blocked on the channel read above. // of all numConfsClients blocked on the channel read above.
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -525,7 +525,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// older blocks when the confirmation event is registered below to ensure // older blocks when the confirmation event is registered below to ensure
// that the TXID hasn't already been included in the chain, otherwise the // that the TXID hasn't already been included in the chain, otherwise the
// notification will never be sent. // notification will never be sent.
_, err = miner.Node.Generate(1) _, err = miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -546,13 +546,13 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
// Now generate another block containing txs 1 & 2. // Now generate another block containing txs 1 & 2.
blockHash, err := miner.Node.Generate(1) blockHash, err := miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -579,7 +579,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
case confInfo := <-ntfn1.Confirmed: case confInfo := <-ntfn1.Confirmed:
// Finally, we'll verify that the tx index returned is the exact same // Finally, we'll verify that the tx index returned is the exact same
// as the tx index of the transaction within the block itself. // as the tx index of the transaction within the block itself.
msgBlock, err := miner.Node.GetBlock(blockHash[0]) msgBlock, err := miner.Client.GetBlock(blockHash[0])
if err != nil { if err != nil {
t.Fatalf("unable to fetch block: %v", err) t.Fatalf("unable to fetch block: %v", err)
} }
@ -622,7 +622,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
} }
// Fully confirm tx3. // Fully confirm tx3.
_, err = miner.Node.Generate(2) _, err = miner.Client.Generate(2)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -710,7 +710,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -719,7 +719,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
// Add a block right before registering, this makes race conditions // Add a block right before registering, this makes race conditions
// between the historical dispatcher and the normal dispatcher more obvious // between the historical dispatcher and the normal dispatcher more obvious
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -738,7 +738,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
} }
// Generate another 2 blocks, this should dispatch the confirm notification // Generate another 2 blocks, this should dispatch the confirm notification
if _, err := miner.Node.Generate(2); err != nil { if _, err := miner.Client.Generate(2); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -753,7 +753,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err = miner.Node.GetBestBlock() _, currentHeight, err = miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -773,7 +773,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -806,14 +806,14 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
// To do so, we first create a new output to our test target address. // To do so, we first create a new output to our test target address.
outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
_, heightHint, err := miner.Node.GetBestBlock() _, heightHint, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
// We'll then spend this output and broadcast the spend transaction. // We'll then spend this output and broadcast the spend transaction.
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true) spenderSha, err := miner.Client.SendRawTransaction(spendingTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast tx: %v", err) t.Fatalf("unable to broadcast tx: %v", err)
} }
@ -829,10 +829,10 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
} }
// Now we mine an additional block, which should include our spend. // Now we mine an additional block, which should include our spend.
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
_, spendHeight, err := miner.Node.GetBestBlock() _, spendHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -895,7 +895,7 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
// Bury the spend even deeper, and do the same check. // Bury the spend even deeper, and do the same check.
const numBlocks = 10 const numBlocks = 10
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Client.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -925,7 +925,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
// ourselves. // ourselves.
outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, node) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, node)
_, currentHeight, err := node.Node.GetBestBlock() _, currentHeight, err := node.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -961,7 +961,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
spendClients[1].Cancel() spendClients[1].Cancel()
// Broadcast our spending transaction. // Broadcast our spending transaction.
spenderSha, err := node.Node.SendRawTransaction(spendingTx, true) spenderSha, err := node.Client.SendRawTransaction(spendingTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast tx: %v", err) t.Fatalf("unable to broadcast tx: %v", err)
} }
@ -972,7 +972,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
// Now we mine a single block, which should include our spend. The // Now we mine a single block, which should include our spend. The
// notification should also be sent off. // notification should also be sent off.
if _, err := node.Node.Generate(1); err != nil { if _, err := node.Client.Generate(1); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -1036,7 +1036,7 @@ func testCancelEpochNtfn(node *rpctest.Harness,
// Now mine a single block, this should trigger the logic to dispatch // Now mine a single block, this should trigger the logic to dispatch
// epoch notifications. // epoch notifications.
if _, err := node.Node.Generate(1); err != nil { if _, err := node.Client.Generate(1); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -1089,12 +1089,12 @@ func testReorgConf(miner *rpctest.Harness,
} }
// The two should be on the same blockheight. // The two should be on the same blockheight.
_, nodeHeight1, err := miner.Node.GetBestBlock() _, nodeHeight1, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
_, nodeHeight2, err := miner2.Node.GetBestBlock() _, nodeHeight2, err := miner2.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -1106,7 +1106,7 @@ func testReorgConf(miner *rpctest.Harness,
// We disconnect the two nodes, such that we can start mining on them // We disconnect the two nodes, such that we can start mining on them
// individually without the other one learning about the new blocks. // individually without the other one learning about the new blocks.
err = miner.Node.AddNode(miner2.P2PAddress(), rpcclient.ANRemove) err = miner.Client.AddNode(miner2.P2PAddress(), rpcclient.ANRemove)
if err != nil { if err != nil {
t.Fatalf("unable to remove node: %v", err) t.Fatalf("unable to remove node: %v", err)
} }
@ -1119,7 +1119,7 @@ func testReorgConf(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -1142,7 +1142,7 @@ func testReorgConf(miner *rpctest.Harness,
} }
// Now generate a single block, the transaction should be included. // Now generate a single block, the transaction should be included.
_, err = miner.Node.Generate(1) _, err = miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -1157,7 +1157,7 @@ func testReorgConf(miner *rpctest.Harness,
// Reorganize transaction out of the chain by generating a longer fork // Reorganize transaction out of the chain by generating a longer fork
// from the other miner. The transaction is not included in this fork. // from the other miner. The transaction is not included in this fork.
miner2.Node.Generate(2) miner2.Client.Generate(2)
// Reconnect nodes to reach consensus on the longest chain. miner2's chain // Reconnect nodes to reach consensus on the longest chain. miner2's chain
// should win and become active on miner1. // should win and become active on miner1.
@ -1169,12 +1169,12 @@ func testReorgConf(miner *rpctest.Harness,
t.Fatalf("unable to join node on blocks: %v", err) t.Fatalf("unable to join node on blocks: %v", err)
} }
_, nodeHeight1, err = miner.Node.GetBestBlock() _, nodeHeight1, err = miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
_, nodeHeight2, err = miner2.Node.GetBestBlock() _, nodeHeight2, err = miner2.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -1195,12 +1195,12 @@ func testReorgConf(miner *rpctest.Harness,
// Now confirm the transaction on the longest chain and verify that we // Now confirm the transaction on the longest chain and verify that we
// receive the notification. // receive the notification.
tx, err := miner.Node.GetRawTransaction(txid) tx, err := miner.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
t.Fatalf("unable to get raw tx: %v", err) t.Fatalf("unable to get raw tx: %v", err)
} }
txid, err = miner2.Node.SendRawTransaction(tx.MsgTx(), false) txid, err = miner2.Client.SendRawTransaction(tx.MsgTx(), false)
if err != nil { if err != nil {
t.Fatalf("unable to get send tx: %v", err) t.Fatalf("unable to get send tx: %v", err)
} }
@ -1208,7 +1208,7 @@ func testReorgConf(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, err = miner.Node.Generate(3) _, err = miner.Client.Generate(3)
if err != nil { if err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -1229,7 +1229,7 @@ func testReorgSpend(miner *rpctest.Harness,
// We'll start by creating an output and registering a spend // We'll start by creating an output and registering a spend
// notification for it. // notification for it.
outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
_, heightHint, err := miner.Node.GetBestBlock() _, heightHint, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to retrieve current height: %v", err) t.Fatalf("unable to retrieve current height: %v", err)
} }
@ -1270,11 +1270,11 @@ func testReorgSpend(miner *rpctest.Harness,
if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil { if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil {
t.Fatalf("unable to sync miners: %v", err) t.Fatalf("unable to sync miners: %v", err)
} }
_, minerHeight1, err := miner.Node.GetBestBlock() _, minerHeight1, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get miner1's current height: %v", err) t.Fatalf("unable to get miner1's current height: %v", err)
} }
_, minerHeight2, err := miner2.Node.GetBestBlock() _, minerHeight2, err := miner2.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get miner2's current height: %v", err) t.Fatalf("unable to get miner2's current height: %v", err)
} }
@ -1285,7 +1285,7 @@ func testReorgSpend(miner *rpctest.Harness,
// We disconnect the two nodes, such that we can start mining on them // We disconnect the two nodes, such that we can start mining on them
// individually without the other one learning about the new blocks. // individually without the other one learning about the new blocks.
err = miner.Node.AddNode(miner2.P2PAddress(), rpcclient.ANRemove) err = miner.Client.AddNode(miner2.P2PAddress(), rpcclient.ANRemove)
if err != nil { if err != nil {
t.Fatalf("unable to disconnect miners: %v", err) t.Fatalf("unable to disconnect miners: %v", err)
} }
@ -1293,7 +1293,7 @@ func testReorgSpend(miner *rpctest.Harness,
// Craft the spending transaction for the outpoint created above and // Craft the spending transaction for the outpoint created above and
// confirm it under the chain of the original miner. // confirm it under the chain of the original miner.
spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
spendTxHash, err := miner.Node.SendRawTransaction(spendTx, true) spendTxHash, err := miner.Client.SendRawTransaction(spendTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast spend tx: %v", err) t.Fatalf("unable to broadcast spend tx: %v", err)
} }
@ -1301,10 +1301,10 @@ func testReorgSpend(miner *rpctest.Harness,
t.Fatalf("spend tx not relayed to miner: %v", err) t.Fatalf("spend tx not relayed to miner: %v", err)
} }
const numBlocks = 1 const numBlocks = 1
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Client.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
_, spendHeight, err := miner.Node.GetBestBlock() _, spendHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get spend height: %v", err) t.Fatalf("unable to get spend height: %v", err)
} }
@ -1322,7 +1322,7 @@ func testReorgSpend(miner *rpctest.Harness,
// Now, with the other miner, we'll generate one more block than the // Now, with the other miner, we'll generate one more block than the
// other miner and connect them to cause a reorg. // other miner and connect them to cause a reorg.
if _, err := miner2.Node.Generate(numBlocks + 1); err != nil { if _, err := miner2.Client.Generate(numBlocks + 1); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
if err := rpctest.ConnectNode(miner, miner2); err != nil { if err := rpctest.ConnectNode(miner, miner2); err != nil {
@ -1332,11 +1332,11 @@ func testReorgSpend(miner *rpctest.Harness,
if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil { if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil {
t.Fatalf("unable to sync miners: %v", err) t.Fatalf("unable to sync miners: %v", err)
} }
_, minerHeight1, err = miner.Node.GetBestBlock() _, minerHeight1, err = miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get miner1's current height: %v", err) t.Fatalf("unable to get miner1's current height: %v", err)
} }
_, minerHeight2, err = miner2.Node.GetBestBlock() _, minerHeight2, err = miner2.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get miner2's current height: %v", err) t.Fatalf("unable to get miner2's current height: %v", err)
} }
@ -1358,16 +1358,16 @@ func testReorgSpend(miner *rpctest.Harness,
// Now that both miners are on the same chain, we'll confirm the // Now that both miners are on the same chain, we'll confirm the
// spending transaction of the outpoint and receive a notification for // spending transaction of the outpoint and receive a notification for
// it. // it.
if _, err = miner2.Node.SendRawTransaction(spendTx, true); err != nil { if _, err = miner2.Client.SendRawTransaction(spendTx, true); err != nil {
t.Fatalf("unable to broadcast spend tx: %v", err) t.Fatalf("unable to broadcast spend tx: %v", err)
} }
if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil { if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Client.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
_, spendHeight, err = miner.Node.GetBestBlock() _, spendHeight, err = miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to retrieve current height: %v", err) t.Fatalf("unable to retrieve current height: %v", err)
} }
@ -1392,7 +1392,7 @@ func testCatchUpClientOnMissedBlocks(miner *rpctest.Harness,
const numClients = 5 const numClients = 5
var wg sync.WaitGroup var wg sync.WaitGroup
outdatedHash, outdatedHeight, err := miner.Node.GetBestBlock() outdatedHash, outdatedHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to retrieve current height: %v", err) t.Fatalf("unable to retrieve current height: %v", err)
} }
@ -1400,7 +1400,7 @@ func testCatchUpClientOnMissedBlocks(miner *rpctest.Harness,
// This function is used by UnsafeStart to ensure all notifications // This function is used by UnsafeStart to ensure all notifications
// are fully drained before clients register for notifications. // are fully drained before clients register for notifications.
generateBlocks := func() error { generateBlocks := func() error {
_, err = miner.Node.Generate(numBlocks) _, err = miner.Client.Generate(numBlocks)
return err return err
} }
@ -1484,7 +1484,7 @@ func testCatchUpOnMissedBlocks(miner *rpctest.Harness,
const numClients = 5 const numClients = 5
var wg sync.WaitGroup var wg sync.WaitGroup
_, bestHeight, err := miner.Node.GetBestBlock() _, bestHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -1492,7 +1492,7 @@ func testCatchUpOnMissedBlocks(miner *rpctest.Harness,
// This function is used by UnsafeStart to ensure all notifications // This function is used by UnsafeStart to ensure all notifications
// are fully drained before clients register for notifications. // are fully drained before clients register for notifications.
generateBlocks := func() error { generateBlocks := func() error {
_, err = miner.Node.Generate(numBlocks) _, err = miner.Client.Generate(numBlocks)
return err return err
} }
@ -1527,7 +1527,7 @@ func testCatchUpOnMissedBlocks(miner *rpctest.Harness,
// Generate a single block to trigger the backlog of historical // Generate a single block to trigger the backlog of historical
// notifications for the previously mined blocks. // notifications for the previously mined blocks.
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -1618,12 +1618,12 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
} }
// The two should be on the same blockheight. // The two should be on the same blockheight.
_, nodeHeight1, err := miner1.Node.GetBestBlock() _, nodeHeight1, err := miner1.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
_, nodeHeight2, err := miner2.Node.GetBestBlock() _, nodeHeight2, err := miner2.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -1635,20 +1635,20 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
// We disconnect the two nodes, such that we can start mining on them // We disconnect the two nodes, such that we can start mining on them
// individually without the other one learning about the new blocks. // individually without the other one learning about the new blocks.
err = miner1.Node.AddNode(miner2.P2PAddress(), rpcclient.ANRemove) err = miner1.Client.AddNode(miner2.P2PAddress(), rpcclient.ANRemove)
if err != nil { if err != nil {
t.Fatalf("unable to remove node: %v", err) t.Fatalf("unable to remove node: %v", err)
} }
// Now mine on each chain separately // Now mine on each chain separately
blocks, err := miner1.Node.Generate(numBlocks) blocks, err := miner1.Client.Generate(numBlocks)
if err != nil { if err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
// We generate an extra block on miner 2's chain to ensure it is the // We generate an extra block on miner 2's chain to ensure it is the
// longer chain. // longer chain.
_, err = miner2.Node.Generate(numBlocks + 1) _, err = miner2.Client.Generate(numBlocks + 1)
if err != nil { if err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
@ -1665,12 +1665,12 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
// The two should be on the same block hash. // The two should be on the same block hash.
timeout := time.After(10 * time.Second) timeout := time.After(10 * time.Second)
for { for {
nodeHash1, _, err := miner1.Node.GetBestBlock() nodeHash1, _, err := miner1.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current block hash: %v", err) t.Fatalf("unable to get current block hash: %v", err)
} }
nodeHash2, _, err := miner2.Node.GetBestBlock() nodeHash2, _, err := miner2.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current block hash: %v", err) t.Fatalf("unable to get current block hash: %v", err)
} }
@ -1721,7 +1721,7 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
// Generate a single block, which should trigger the notifier to rewind // Generate a single block, which should trigger the notifier to rewind
// to the common ancestor and dispatch notifications from there. // to the common ancestor and dispatch notifications from there.
_, err = miner2.Node.Generate(1) _, err = miner2.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }

@ -82,7 +82,7 @@ func WaitForMempoolTx(miner *rpctest.Harness, txid *chainhash.Hash) error {
trickle := time.After(2 * TrickleInterval) trickle := time.After(2 * TrickleInterval)
for { for {
// Check for the harness' knowledge of the txid. // Check for the harness' knowledge of the txid.
tx, err := miner.Node.GetRawTransaction(txid) tx, err := miner.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
jsonErr, ok := err.(*btcjson.RPCError) jsonErr, ok := err.(*btcjson.RPCError)
if ok && jsonErr.Code == btcjson.ErrRPCNoTxInfo { if ok && jsonErr.Code == btcjson.ErrRPCNoTxInfo {
@ -138,7 +138,7 @@ func CreateSpendableOutput(t *testing.T,
if err := WaitForMempoolTx(miner, txid); err != nil { if err := WaitForMempoolTx(miner, txid); err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }

@ -127,6 +127,13 @@ var newAddressCommand = cli.Command{
Category: "Wallet", Category: "Wallet",
Usage: "Generates a new address.", Usage: "Generates a new address.",
ArgsUsage: "address-type", ArgsUsage: "address-type",
Flags: []cli.Flag{
cli.StringFlag{
Name: "account",
Usage: "(optional) the name of the account to " +
"generate a new address for",
},
},
Description: ` Description: `
Generate a wallet new address. Address-types has to be one of: Generate a wallet new address. Address-types has to be one of:
- p2wkh: Pay to witness key hash - p2wkh: Pay to witness key hash
@ -136,13 +143,16 @@ var newAddressCommand = cli.Command{
func newAddress(ctx *cli.Context) error { func newAddress(ctx *cli.Context) error {
ctxc := getContext() ctxc := getContext()
client, cleanUp := getClient(ctx)
defer cleanUp()
stringAddrType := ctx.Args().First() // Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() != 1 || ctx.NumFlags() > 1 {
return cli.ShowCommandHelp(ctx, "newaddress")
}
// Map the string encoded address type, to the concrete typed address // Map the string encoded address type, to the concrete typed address
// type enum. An unrecognized address type will result in an error. // type enum. An unrecognized address type will result in an error.
stringAddrType := ctx.Args().First()
var addrType lnrpc.AddressType var addrType lnrpc.AddressType
switch stringAddrType { // TODO(roasbeef): make them ints on the cli? switch stringAddrType { // TODO(roasbeef): make them ints on the cli?
case "p2wkh": case "p2wkh":
@ -154,8 +164,12 @@ func newAddress(ctx *cli.Context) error {
"are: p2wkh and np2wkh", stringAddrType) "are: p2wkh and np2wkh", stringAddrType)
} }
client, cleanUp := getClient(ctx)
defer cleanUp()
addr, err := client.NewAddress(ctxc, &lnrpc.NewAddressRequest{ addr, err := client.NewAddress(ctxc, &lnrpc.NewAddressRequest{
Type: addrType, Type: addrType,
Account: ctx.String("account"),
}) })
if err != nil { if err != nil {
return err return err

@ -3,8 +3,8 @@
package main package main
import ( import (
"context"
"encoding/base64" "encoding/base64"
"encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
@ -29,6 +29,18 @@ var (
finalizePsbtCommand, finalizePsbtCommand,
}, },
} }
// accountsCommand is a wallet subcommand that is responsible for
// account management operations.
accountsCommand = cli.Command{
Name: "accounts",
Usage: "Interact with wallet accounts.",
Subcommands: []cli.Command{
listAccountsCommand,
importAccountCommand,
importPubKeyCommand,
},
}
) )
// walletCommands will return the set of commands to enable for walletrpc // walletCommands will return the set of commands to enable for walletrpc
@ -49,11 +61,28 @@ func walletCommands() []cli.Command {
releaseOutputCommand, releaseOutputCommand,
listLeasesCommand, listLeasesCommand,
psbtCommand, psbtCommand,
accountsCommand,
}, },
}, },
} }
} }
func parseAddrType(addrTypeStr string) (walletrpc.AddressType, error) {
switch addrTypeStr {
case "":
return walletrpc.AddressType_UNKNOWN, nil
case "p2wkh":
return walletrpc.AddressType_WITNESS_PUBKEY_HASH, nil
case "np2wkh":
return walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH, nil
case "np2wkh-p2wkh":
return walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH, nil
default:
return 0, errors.New("invalid address type, supported address " +
"types are: p2wkh, np2wkh, and np2wkh-p2wkh")
}
}
func getWalletClient(ctx *cli.Context) (walletrpc.WalletKitClient, func()) { func getWalletClient(ctx *cli.Context) (walletrpc.WalletKitClient, func()) {
conn := getClientConn(ctx, false) conn := getClientConn(ctx, false)
cleanUp := func() { cleanUp := func() {
@ -523,6 +552,11 @@ var fundPsbtCommand = cli.Command{
Usage: "a manual fee expressed in sat/vbyte that " + Usage: "a manual fee expressed in sat/vbyte that " +
"should be used when creating the transaction", "should be used when creating the transaction",
}, },
cli.StringFlag{
Name: "account",
Usage: "(optional) the name of the account to use to " +
"create/fund the PSBT",
},
}, },
Action: actionDecorator(fundPsbt), Action: actionDecorator(fundPsbt),
} }
@ -536,7 +570,9 @@ func fundPsbt(ctx *cli.Context) error {
return cli.ShowCommandHelp(ctx, "fund") return cli.ShowCommandHelp(ctx, "fund")
} }
req := &walletrpc.FundPsbtRequest{} req := &walletrpc.FundPsbtRequest{
Account: ctx.String("account"),
}
// Parse template flags. // Parse template flags.
switch { switch {
@ -691,6 +727,11 @@ var finalizePsbtCommand = cli.Command{
Name: "funded_psbt", Name: "funded_psbt",
Usage: "the base64 encoded PSBT to finalize", Usage: "the base64 encoded PSBT to finalize",
}, },
cli.StringFlag{
Name: "account",
Usage: "(optional) the name of the account to " +
"finalize the PSBT with",
},
}, },
Action: actionDecorator(finalizePsbt), Action: actionDecorator(finalizePsbt),
} }
@ -700,7 +741,7 @@ func finalizePsbt(ctx *cli.Context) error {
// Display the command's help message if we do not have the expected // Display the command's help message if we do not have the expected
// number of arguments/flags. // number of arguments/flags.
if ctx.NArg() != 1 && ctx.NumFlags() != 1 { if ctx.NArg() > 1 || ctx.NumFlags() > 2 {
return cli.ShowCommandHelp(ctx, "finalize") return cli.ShowCommandHelp(ctx, "finalize")
} }
@ -723,6 +764,7 @@ func finalizePsbt(ctx *cli.Context) error {
} }
req := &walletrpc.FinalizePsbtRequest{ req := &walletrpc.FinalizePsbtRequest{
FundedPsbt: psbtBytes, FundedPsbt: psbtBytes,
Account: ctx.String("account"),
} }
walletClient, cleanUp := getWalletClient(ctx) walletClient, cleanUp := getWalletClient(ctx)
@ -813,17 +855,207 @@ var listLeasesCommand = cli.Command{
} }
func listLeases(ctx *cli.Context) error { func listLeases(ctx *cli.Context) error {
req := &walletrpc.ListLeasesRequest{} ctxc := getContext()
walletClient, cleanUp := getWalletClient(ctx) walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp() defer cleanUp()
response, err := walletClient.ListLeases(context.Background(), req) req := &walletrpc.ListLeasesRequest{}
response, err := walletClient.ListLeases(ctxc, req)
if err != nil { if err != nil {
return err return err
} }
printJSON(marshallLocks(response.LockedUtxos)) printJSON(marshallLocks(response.LockedUtxos))
return nil
}
var listAccountsCommand = cli.Command{
Name: "list",
Usage: "Retrieve information of existing on-chain wallet accounts.",
Description: `
ListAccounts retrieves all accounts belonging to the wallet by default.
A name and key scope filter can be provided to filter through all of the
wallet accounts and return only those matching.
`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "(optional) only accounts matching this name " +
"are returned",
},
cli.StringFlag{
Name: "address_type",
Usage: "(optional) only accounts matching this " +
"address type are returned",
},
},
Action: actionDecorator(listAccounts),
}
func listAccounts(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() > 0 || ctx.NumFlags() > 2 {
return cli.ShowCommandHelp(ctx, "list")
}
addrType, err := parseAddrType(ctx.String("address_type"))
if err != nil {
return err
}
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()
req := &walletrpc.ListAccountsRequest{
Name: ctx.String("name"),
AddressType: addrType,
}
resp, err := walletClient.ListAccounts(ctxc, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil return nil
} }
var importAccountCommand = cli.Command{
Name: "import",
Usage: "Import an on-chain account into the wallet through its " +
"extended public key.",
ArgsUsage: "extended_public_key name",
Description: `
Imports an account backed by an account extended public key. The master
key fingerprint denotes the fingerprint of the root key corresponding to
the account public key (also known as the key with derivation path m/).
This may be required by some hardware wallets for proper identification
and signing.
The address type can usually be inferred from the key's version, but may
be required for certain keys to map them into the proper scope.
For BIP-0044 keys, an address type must be specified as we intend to not
support importing BIP-0044 keys into the wallet using the legacy
pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will
force the standard BIP-0049 derivation scheme, while a witness address
type will force the standard BIP-0084 derivation scheme.
For BIP-0049 keys, an address type must also be specified to make a
distinction between the standard BIP-0049 address schema (nested witness
pubkeys everywhere) and our own BIP-0049Plus address schema (nested
pubkeys externally, witness pubkeys internally).
NOTE: Events (deposits/spends) for keys derived from an account will
only be detected by lnd if they happen after the import. Rescans to
detect past events will be supported later on.
`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "address_type",
Usage: "(optional) specify the type of addresses the " +
"imported account should generate",
},
cli.StringFlag{
Name: "master_key_fingerprint",
Usage: "(optional) the fingerprint of the root key " +
"(derivation path m/) corresponding to the " +
"account public key",
},
},
Action: actionDecorator(importAccount),
}
func importAccount(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() != 2 || ctx.NumFlags() > 2 {
return cli.ShowCommandHelp(ctx, "import")
}
addrType, err := parseAddrType(ctx.String("address_type"))
if err != nil {
return err
}
var masterKeyFingerprint uint32
if ctx.IsSet("master_key_fingerprint") {
mkfp, err := hex.DecodeString(ctx.String("master_key_fingerprint"))
if err != nil {
return fmt.Errorf("invalid master key fingerprint: %v", err)
}
masterKeyFingerprint = binary.LittleEndian.Uint32(mkfp)
}
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()
req := &walletrpc.ImportAccountRequest{
Name: ctx.Args().Get(1),
ExtendedPublicKey: ctx.Args().Get(0),
MasterKeyFingerprint: masterKeyFingerprint,
AddressType: addrType,
}
resp, err := walletClient.ImportAccount(ctxc, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var importPubKeyCommand = cli.Command{
Name: "import-pubkey",
Usage: "Import a public key as watch-only into the wallet.",
ArgsUsage: "public_key address_type",
Description: `
Imports a public key represented in hex as watch-only into the wallet.
The address type must be one of the following: np2wkh, p2wkh.
NOTE: Events (deposits/spends) for a key will only be detected by lnd if
they happen after the import. Rescans to detect past events will be
supported later on.
`,
Action: actionDecorator(importPubKey),
}
func importPubKey(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() != 2 || ctx.NumFlags() > 0 {
return cli.ShowCommandHelp(ctx, "import-pubkey")
}
pubKeyBytes, err := hex.DecodeString(ctx.Args().Get(0))
if err != nil {
return err
}
addrType, err := parseAddrType(ctx.Args().Get(1))
if err != nil {
return err
}
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()
req := &walletrpc.ImportPublicKeyRequest{
PublicKey: pubKeyBytes,
AddressType: addrType,
}
resp, err := walletClient.ImportPublicKey(ctxc, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}

@ -1372,7 +1372,10 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
shutdown, err := getUpfrontShutdownScript( shutdown, err := getUpfrontShutdownScript(
f.cfg.EnableUpfrontShutdown, peer, acceptorResp.UpfrontShutdown, f.cfg.EnableUpfrontShutdown, peer, acceptorResp.UpfrontShutdown,
func() (lnwire.DeliveryAddress, error) { func() (lnwire.DeliveryAddress, error) {
addr, err := f.cfg.Wallet.NewAddress(lnwallet.WitnessPubKey, false) addr, err := f.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false,
lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -3153,6 +3156,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
func() (lnwire.DeliveryAddress, error) { func() (lnwire.DeliveryAddress, error) {
addr, err := f.cfg.Wallet.NewAddress( addr, err := f.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.WitnessPubKey, false,
lnwallet.DefaultAccountName,
) )
if err != nil { if err != nil {
return nil, err return nil, err

12
go.mod

@ -5,13 +5,14 @@ require (
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82 github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82
github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2 github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2
github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa github.com/btcsuite/btcd v0.21.0-beta.0.20210401013323-36a96f6a0025
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcutil v1.0.2 github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/btcsuite/btcutil/psbt v1.0.3-0.20200826194809-5f93e33af2b0 github.com/btcsuite/btcutil/psbt v1.0.3-0.20201208143702-a53e38424cce
github.com/btcsuite/btcwallet v0.11.1-0.20210312232944-4ec908df9386 github.com/btcsuite/btcwallet v0.11.1-0.20210329233242-e0607006dce6
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 github.com/btcsuite/btcwallet/wallet/txrules v1.0.0
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210329233242-e0607006dce6 // indirect
github.com/btcsuite/btcwallet/walletdb v1.3.4 github.com/btcsuite/btcwallet/walletdb v1.3.4
github.com/btcsuite/btcwallet/wtxmgr v1.2.1-0.20210312232944-4ec908df9386 github.com/btcsuite/btcwallet/wtxmgr v1.2.1-0.20210312232944-4ec908df9386
github.com/coreos/etcd v3.3.22+incompatible github.com/coreos/etcd v3.3.22+incompatible
@ -21,6 +22,7 @@ require (
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dustin/go-humanize v1.0.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-errors/errors v1.0.1 github.com/go-errors/errors v1.0.1
github.com/go-openapi/strfmt v0.19.5 // indirect github.com/go-openapi/strfmt v0.19.5 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect

24
go.sum

@ -26,23 +26,27 @@ github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcug
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa h1:sobXG8TE1VEBX4QWOzSKyulSwuOFdb8vzyhGyblXrmQ=
github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs=
github.com/btcsuite/btcd v0.21.0-beta.0.20210401013323-36a96f6a0025 h1:aoVqvZk4mLyF3WZbqEVPq+vXnwL2wekZg4P4mjYJNLs=
github.com/btcsuite/btcd v0.21.0-beta.0.20210401013323-36a96f6a0025/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20200826194809-5f93e33af2b0 h1:3Zumkyl6PWyHuVJ04me0xeD9CnPOhNgeGpapFbzy7O4= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20200826194809-5f93e33af2b0/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
github.com/btcsuite/btcwallet v0.11.1-0.20210312232944-4ec908df9386 h1:DfZIXWPAm35bW83OtS/AXH9A9pE6dxxIUhf260S9Wmo= github.com/btcsuite/btcutil/psbt v1.0.3-0.20201208143702-a53e38424cce h1:3PRwz+js0AMMV1fHRrCdQ55akoomx4Q3ulozHC3BDDY=
github.com/btcsuite/btcwallet v0.11.1-0.20210312232944-4ec908df9386/go.mod h1:P1U4LKSB/bhFQdOM7ab1XqNoBGFyFAe7eKObEBD9mIo= github.com/btcsuite/btcutil/psbt v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c= github.com/btcsuite/btcwallet v0.11.1-0.20210329233242-e0607006dce6 h1:5Y6ui667YQrFCxPYV4Pmf9jpEsIkcJxMKsXJzNsMU9o=
github.com/btcsuite/btcwallet v0.11.1-0.20210329233242-e0607006dce6/go.mod h1:JBUz2SCnYLn2Dw9bcnqZYvKchnKVvWSLv8OUzihHTcc=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6 h1:mO7NxcfgLe75paLDHx+LWNG5BskiDQigHnSVT2KvNZA=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w= github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w=
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA= github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 h1:6DxkcoMnCPY4E9cUDPB5tbuuf40SmmMkSQkoE8vCT+s=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210329233242-e0607006dce6 h1:n9SLPLz2PRg2X+lnWxioxTmtAa2ZqjR8EwL/tZD7BAY=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210329233242-e0607006dce6/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk=
github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ= github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ=
github.com/btcsuite/btcwallet/walletdb v1.3.4 h1:ExdPQSfYRLoYMEENsjWyl4w0PePLm9w3wg69nsRS2xc= github.com/btcsuite/btcwallet/walletdb v1.3.4 h1:ExdPQSfYRLoYMEENsjWyl4w0PePLm9w3wg69nsRS2xc=
@ -88,8 +92,9 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY= github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY=
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@ -310,6 +315,7 @@ golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

@ -222,9 +222,9 @@ func (b *BtcWalletKeyRing) DeriveKey(keyLoc KeyLocator) (KeyDescriptor, error) {
} }
path := waddrmgr.DerivationPath{ path := waddrmgr.DerivationPath{
Account: uint32(keyLoc.Family), InternalAccount: uint32(keyLoc.Family),
Branch: 0, Branch: 0,
Index: uint32(keyLoc.Index), Index: keyLoc.Index,
} }
addr, err := scope.DeriveFromKeyPath(addrmgrNs, path) addr, err := scope.DeriveFromKeyPath(addrmgrNs, path)
if err != nil { if err != nil {
@ -278,9 +278,9 @@ func (b *BtcWalletKeyRing) DerivePrivKey(keyDesc KeyDescriptor) (
// Now that we know the account exists, we can safely // Now that we know the account exists, we can safely
// derive the full private key from the given path. // derive the full private key from the given path.
path := waddrmgr.DerivationPath{ path := waddrmgr.DerivationPath{
Account: uint32(keyDesc.Family), InternalAccount: uint32(keyDesc.Family),
Branch: 0, Branch: 0,
Index: uint32(keyDesc.Index), Index: keyDesc.Index,
} }
addr, err := scope.DeriveFromKeyPath(addrmgrNs, path) addr, err := scope.DeriveFromKeyPath(addrmgrNs, path)
if err != nil { if err != nil {
@ -299,7 +299,7 @@ func (b *BtcWalletKeyRing) DerivePrivKey(keyDesc KeyDescriptor) (
// need to scan for the private key, assuming that we know the // need to scan for the private key, assuming that we know the
// valid key family. // valid key family.
nextPath := waddrmgr.DerivationPath{ nextPath := waddrmgr.DerivationPath{
Account: uint32(keyDesc.Family), InternalAccount: uint32(keyDesc.Family),
Branch: 0, Branch: 0,
Index: 0, Index: 0,
} }

1
lnd.go

@ -676,6 +676,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
NewAddress: func() (btcutil.Address, error) { NewAddress: func() (btcutil.Address, error) {
return activeChainControl.Wallet.NewAddress( return activeChainControl.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.WitnessPubKey, false,
lnwallet.DefaultAccountName,
) )
}, },
NodeKeyECDH: keychain.NewPubKeyECDH( NodeKeyECDH: keychain.NewPubKeyECDH(

@ -275,6 +275,9 @@ http:
- selector: walletrpc.WalletKit.DeriveKey - selector: walletrpc.WalletKit.DeriveKey
post: "/v2/wallet/key" post: "/v2/wallet/key"
body: "*" body: "*"
- selector: walletrpc.WalletKit.ImportPublicKey
post: "/v2/wallet/key/import"
body: "*"
- selector: walletrpc.WalletKit.NextAddr - selector: walletrpc.WalletKit.NextAddr
post: "/v2/wallet/address/next" post: "/v2/wallet/address/next"
body: "*" body: "*"
@ -302,6 +305,11 @@ http:
- selector: walletrpc.WalletKit.FinalizePsbt - selector: walletrpc.WalletKit.FinalizePsbt
post: "/v2/wallet/psbt/finalize" post: "/v2/wallet/psbt/finalize"
body: "*" body: "*"
- selector: walletrpc.WalletKit.ListAccounts
get: "/v2/wallet/accounts"
- selector: walletrpc.WalletKit.ImportAccount
post: "/v2/wallet/accounts/import"
body: "*"
# watchtowerrpc/watchtower.proto # watchtowerrpc/watchtower.proto
- selector: watchtowerrpc.Watchtower.GetInfo - selector: watchtowerrpc.Watchtower.GetInfo

@ -613,7 +613,7 @@ func (x Invoice_InvoiceState) String() string {
} }
func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) { func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{110, 0} return fileDescriptor_77a6da22d6a3feb1, []int{111, 0}
} }
type Payment_PaymentStatus int32 type Payment_PaymentStatus int32
@ -644,7 +644,7 @@ func (x Payment_PaymentStatus) String() string {
} }
func (Payment_PaymentStatus) EnumDescriptor() ([]byte, []int) { func (Payment_PaymentStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{118, 0} return fileDescriptor_77a6da22d6a3feb1, []int{119, 0}
} }
type HTLCAttempt_HTLCStatus int32 type HTLCAttempt_HTLCStatus int32
@ -672,7 +672,7 @@ func (x HTLCAttempt_HTLCStatus) String() string {
} }
func (HTLCAttempt_HTLCStatus) EnumDescriptor() ([]byte, []int) { func (HTLCAttempt_HTLCStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{119, 0} return fileDescriptor_77a6da22d6a3feb1, []int{120, 0}
} }
type Failure_FailureCode int32 type Failure_FailureCode int32
@ -786,7 +786,7 @@ func (x Failure_FailureCode) String() string {
} }
func (Failure_FailureCode) EnumDescriptor() ([]byte, []int) { func (Failure_FailureCode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{159, 0} return fileDescriptor_77a6da22d6a3feb1, []int{160, 0}
} }
type Utxo struct { type Utxo struct {
@ -1007,6 +1007,8 @@ type GetTransactionsRequest struct {
//unconfirmed transactions. If no end_height is provided, the call will //unconfirmed transactions. If no end_height is provided, the call will
//default to this option. //default to this option.
EndHeight int32 `protobuf:"varint,2,opt,name=end_height,json=endHeight,proto3" json:"end_height,omitempty"` EndHeight int32 `protobuf:"varint,2,opt,name=end_height,json=endHeight,proto3" json:"end_height,omitempty"`
// An optional filter to only include transactions relevant to an account.
Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -1051,6 +1053,13 @@ func (m *GetTransactionsRequest) GetEndHeight() int32 {
return 0 return 0
} }
func (m *GetTransactionsRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
type TransactionDetails struct { type TransactionDetails struct {
// The list of transactions relevant to the wallet. // The list of transactions relevant to the wallet.
Transactions []*Transaction `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"` Transactions []*Transaction `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"`
@ -2438,6 +2447,8 @@ type ListUnspentRequest struct {
MinConfs int32 `protobuf:"varint,1,opt,name=min_confs,json=minConfs,proto3" json:"min_confs,omitempty"` MinConfs int32 `protobuf:"varint,1,opt,name=min_confs,json=minConfs,proto3" json:"min_confs,omitempty"`
// The maximum number of confirmations to be included. // The maximum number of confirmations to be included.
MaxConfs int32 `protobuf:"varint,2,opt,name=max_confs,json=maxConfs,proto3" json:"max_confs,omitempty"` MaxConfs int32 `protobuf:"varint,2,opt,name=max_confs,json=maxConfs,proto3" json:"max_confs,omitempty"`
// An optional filter to only include outputs belonging to an account.
Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -2482,6 +2493,13 @@ func (m *ListUnspentRequest) GetMaxConfs() int32 {
return 0 return 0
} }
func (m *ListUnspentRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
type ListUnspentResponse struct { type ListUnspentResponse struct {
// A list of utxos // A list of utxos
Utxos []*Utxo `protobuf:"bytes,1,rep,name=utxos,proto3" json:"utxos,omitempty"` Utxos []*Utxo `protobuf:"bytes,1,rep,name=utxos,proto3" json:"utxos,omitempty"`
@ -2523,8 +2541,12 @@ func (m *ListUnspentResponse) GetUtxos() []*Utxo {
} }
type NewAddressRequest struct { type NewAddressRequest struct {
// The address type // The type of address to generate.
Type AddressType `protobuf:"varint,1,opt,name=type,proto3,enum=lnrpc.AddressType" json:"type,omitempty"` Type AddressType `protobuf:"varint,1,opt,name=type,proto3,enum=lnrpc.AddressType" json:"type,omitempty"`
//
//The name of the account to generate a new address for. If empty, the
//default wallet account is used.
Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -2562,6 +2584,13 @@ func (m *NewAddressRequest) GetType() AddressType {
return AddressType_WITNESS_PUBKEY_HASH return AddressType_WITNESS_PUBKEY_HASH
} }
func (m *NewAddressRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
type NewAddressResponse struct { type NewAddressResponse struct {
// The newly generated wallet address // The newly generated wallet address
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
@ -6957,6 +6986,55 @@ func (*ChannelEventUpdate) XXX_OneofWrappers() []interface{} {
} }
} }
type WalletAccountBalance struct {
// The confirmed balance of the account (with >= 1 confirmations).
ConfirmedBalance int64 `protobuf:"varint,1,opt,name=confirmed_balance,json=confirmedBalance,proto3" json:"confirmed_balance,omitempty"`
// The unconfirmed balance of the account (with 0 confirmations).
UnconfirmedBalance int64 `protobuf:"varint,2,opt,name=unconfirmed_balance,json=unconfirmedBalance,proto3" json:"unconfirmed_balance,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *WalletAccountBalance) Reset() { *m = WalletAccountBalance{} }
func (m *WalletAccountBalance) String() string { return proto.CompactTextString(m) }
func (*WalletAccountBalance) ProtoMessage() {}
func (*WalletAccountBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{75}
}
func (m *WalletAccountBalance) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WalletAccountBalance.Unmarshal(m, b)
}
func (m *WalletAccountBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_WalletAccountBalance.Marshal(b, m, deterministic)
}
func (m *WalletAccountBalance) XXX_Merge(src proto.Message) {
xxx_messageInfo_WalletAccountBalance.Merge(m, src)
}
func (m *WalletAccountBalance) XXX_Size() int {
return xxx_messageInfo_WalletAccountBalance.Size(m)
}
func (m *WalletAccountBalance) XXX_DiscardUnknown() {
xxx_messageInfo_WalletAccountBalance.DiscardUnknown(m)
}
var xxx_messageInfo_WalletAccountBalance proto.InternalMessageInfo
func (m *WalletAccountBalance) GetConfirmedBalance() int64 {
if m != nil {
return m.ConfirmedBalance
}
return 0
}
func (m *WalletAccountBalance) GetUnconfirmedBalance() int64 {
if m != nil {
return m.UnconfirmedBalance
}
return 0
}
type WalletBalanceRequest struct { type WalletBalanceRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
@ -6967,7 +7045,7 @@ func (m *WalletBalanceRequest) Reset() { *m = WalletBalanceRequest{} }
func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) } func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*WalletBalanceRequest) ProtoMessage() {} func (*WalletBalanceRequest) ProtoMessage() {}
func (*WalletBalanceRequest) Descriptor() ([]byte, []int) { func (*WalletBalanceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{75} return fileDescriptor_77a6da22d6a3feb1, []int{76}
} }
func (m *WalletBalanceRequest) XXX_Unmarshal(b []byte) error { func (m *WalletBalanceRequest) XXX_Unmarshal(b []byte) error {
@ -6995,6 +7073,8 @@ type WalletBalanceResponse struct {
ConfirmedBalance int64 `protobuf:"varint,2,opt,name=confirmed_balance,json=confirmedBalance,proto3" json:"confirmed_balance,omitempty"` ConfirmedBalance int64 `protobuf:"varint,2,opt,name=confirmed_balance,json=confirmedBalance,proto3" json:"confirmed_balance,omitempty"`
// The unconfirmed balance of a wallet(with 0 confirmations) // The unconfirmed balance of a wallet(with 0 confirmations)
UnconfirmedBalance int64 `protobuf:"varint,3,opt,name=unconfirmed_balance,json=unconfirmedBalance,proto3" json:"unconfirmed_balance,omitempty"` UnconfirmedBalance int64 `protobuf:"varint,3,opt,name=unconfirmed_balance,json=unconfirmedBalance,proto3" json:"unconfirmed_balance,omitempty"`
// A mapping of each wallet account's name to its balance.
AccountBalance map[string]*WalletAccountBalance `protobuf:"bytes,4,rep,name=account_balance,json=accountBalance,proto3" json:"account_balance,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -7004,7 +7084,7 @@ func (m *WalletBalanceResponse) Reset() { *m = WalletBalanceResponse{} }
func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) } func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*WalletBalanceResponse) ProtoMessage() {} func (*WalletBalanceResponse) ProtoMessage() {}
func (*WalletBalanceResponse) Descriptor() ([]byte, []int) { func (*WalletBalanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{76} return fileDescriptor_77a6da22d6a3feb1, []int{77}
} }
func (m *WalletBalanceResponse) XXX_Unmarshal(b []byte) error { func (m *WalletBalanceResponse) XXX_Unmarshal(b []byte) error {
@ -7046,6 +7126,13 @@ func (m *WalletBalanceResponse) GetUnconfirmedBalance() int64 {
return 0 return 0
} }
func (m *WalletBalanceResponse) GetAccountBalance() map[string]*WalletAccountBalance {
if m != nil {
return m.AccountBalance
}
return nil
}
type Amount struct { type Amount struct {
// Value denominated in satoshis. // Value denominated in satoshis.
Sat uint64 `protobuf:"varint,1,opt,name=sat,proto3" json:"sat,omitempty"` Sat uint64 `protobuf:"varint,1,opt,name=sat,proto3" json:"sat,omitempty"`
@ -7060,7 +7147,7 @@ func (m *Amount) Reset() { *m = Amount{} }
func (m *Amount) String() string { return proto.CompactTextString(m) } func (m *Amount) String() string { return proto.CompactTextString(m) }
func (*Amount) ProtoMessage() {} func (*Amount) ProtoMessage() {}
func (*Amount) Descriptor() ([]byte, []int) { func (*Amount) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{77} return fileDescriptor_77a6da22d6a3feb1, []int{78}
} }
func (m *Amount) XXX_Unmarshal(b []byte) error { func (m *Amount) XXX_Unmarshal(b []byte) error {
@ -7105,7 +7192,7 @@ func (m *ChannelBalanceRequest) Reset() { *m = ChannelBalanceRequest{} }
func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) } func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceRequest) ProtoMessage() {} func (*ChannelBalanceRequest) ProtoMessage() {}
func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) { func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{78} return fileDescriptor_77a6da22d6a3feb1, []int{79}
} }
func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error { func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error {
@ -7152,7 +7239,7 @@ func (m *ChannelBalanceResponse) Reset() { *m = ChannelBalanceResponse{}
func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) } func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceResponse) ProtoMessage() {} func (*ChannelBalanceResponse) ProtoMessage() {}
func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) { func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{79} return fileDescriptor_77a6da22d6a3feb1, []int{80}
} }
func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error { func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error {
@ -7314,7 +7401,7 @@ func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} }
func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) } func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) }
func (*QueryRoutesRequest) ProtoMessage() {} func (*QueryRoutesRequest) ProtoMessage() {}
func (*QueryRoutesRequest) Descriptor() ([]byte, []int) { func (*QueryRoutesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{80} return fileDescriptor_77a6da22d6a3feb1, []int{81}
} }
func (m *QueryRoutesRequest) XXX_Unmarshal(b []byte) error { func (m *QueryRoutesRequest) XXX_Unmarshal(b []byte) error {
@ -7466,7 +7553,7 @@ func (m *NodePair) Reset() { *m = NodePair{} }
func (m *NodePair) String() string { return proto.CompactTextString(m) } func (m *NodePair) String() string { return proto.CompactTextString(m) }
func (*NodePair) ProtoMessage() {} func (*NodePair) ProtoMessage() {}
func (*NodePair) Descriptor() ([]byte, []int) { func (*NodePair) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{81} return fileDescriptor_77a6da22d6a3feb1, []int{82}
} }
func (m *NodePair) XXX_Unmarshal(b []byte) error { func (m *NodePair) XXX_Unmarshal(b []byte) error {
@ -7519,7 +7606,7 @@ func (m *EdgeLocator) Reset() { *m = EdgeLocator{} }
func (m *EdgeLocator) String() string { return proto.CompactTextString(m) } func (m *EdgeLocator) String() string { return proto.CompactTextString(m) }
func (*EdgeLocator) ProtoMessage() {} func (*EdgeLocator) ProtoMessage() {}
func (*EdgeLocator) Descriptor() ([]byte, []int) { func (*EdgeLocator) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{82} return fileDescriptor_77a6da22d6a3feb1, []int{83}
} }
func (m *EdgeLocator) XXX_Unmarshal(b []byte) error { func (m *EdgeLocator) XXX_Unmarshal(b []byte) error {
@ -7572,7 +7659,7 @@ func (m *QueryRoutesResponse) Reset() { *m = QueryRoutesResponse{} }
func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) } func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) }
func (*QueryRoutesResponse) ProtoMessage() {} func (*QueryRoutesResponse) ProtoMessage() {}
func (*QueryRoutesResponse) Descriptor() ([]byte, []int) { func (*QueryRoutesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{83} return fileDescriptor_77a6da22d6a3feb1, []int{84}
} }
func (m *QueryRoutesResponse) XXX_Unmarshal(b []byte) error { func (m *QueryRoutesResponse) XXX_Unmarshal(b []byte) error {
@ -7648,7 +7735,7 @@ func (m *Hop) Reset() { *m = Hop{} }
func (m *Hop) String() string { return proto.CompactTextString(m) } func (m *Hop) String() string { return proto.CompactTextString(m) }
func (*Hop) ProtoMessage() {} func (*Hop) ProtoMessage() {}
func (*Hop) Descriptor() ([]byte, []int) { func (*Hop) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{84} return fileDescriptor_77a6da22d6a3feb1, []int{85}
} }
func (m *Hop) XXX_Unmarshal(b []byte) error { func (m *Hop) XXX_Unmarshal(b []byte) error {
@ -7770,7 +7857,7 @@ func (m *MPPRecord) Reset() { *m = MPPRecord{} }
func (m *MPPRecord) String() string { return proto.CompactTextString(m) } func (m *MPPRecord) String() string { return proto.CompactTextString(m) }
func (*MPPRecord) ProtoMessage() {} func (*MPPRecord) ProtoMessage() {}
func (*MPPRecord) Descriptor() ([]byte, []int) { func (*MPPRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{85} return fileDescriptor_77a6da22d6a3feb1, []int{86}
} }
func (m *MPPRecord) XXX_Unmarshal(b []byte) error { func (m *MPPRecord) XXX_Unmarshal(b []byte) error {
@ -7848,7 +7935,7 @@ func (m *Route) Reset() { *m = Route{} }
func (m *Route) String() string { return proto.CompactTextString(m) } func (m *Route) String() string { return proto.CompactTextString(m) }
func (*Route) ProtoMessage() {} func (*Route) ProtoMessage() {}
func (*Route) Descriptor() ([]byte, []int) { func (*Route) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{86} return fileDescriptor_77a6da22d6a3feb1, []int{87}
} }
func (m *Route) XXX_Unmarshal(b []byte) error { func (m *Route) XXX_Unmarshal(b []byte) error {
@ -7927,7 +8014,7 @@ func (m *NodeInfoRequest) Reset() { *m = NodeInfoRequest{} }
func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) } func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) }
func (*NodeInfoRequest) ProtoMessage() {} func (*NodeInfoRequest) ProtoMessage() {}
func (*NodeInfoRequest) Descriptor() ([]byte, []int) { func (*NodeInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{87} return fileDescriptor_77a6da22d6a3feb1, []int{88}
} }
func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error { func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error {
@ -7984,7 +8071,7 @@ func (m *NodeInfo) Reset() { *m = NodeInfo{} }
func (m *NodeInfo) String() string { return proto.CompactTextString(m) } func (m *NodeInfo) String() string { return proto.CompactTextString(m) }
func (*NodeInfo) ProtoMessage() {} func (*NodeInfo) ProtoMessage() {}
func (*NodeInfo) Descriptor() ([]byte, []int) { func (*NodeInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{88} return fileDescriptor_77a6da22d6a3feb1, []int{89}
} }
func (m *NodeInfo) XXX_Unmarshal(b []byte) error { func (m *NodeInfo) XXX_Unmarshal(b []byte) error {
@ -8054,7 +8141,7 @@ func (m *LightningNode) Reset() { *m = LightningNode{} }
func (m *LightningNode) String() string { return proto.CompactTextString(m) } func (m *LightningNode) String() string { return proto.CompactTextString(m) }
func (*LightningNode) ProtoMessage() {} func (*LightningNode) ProtoMessage() {}
func (*LightningNode) Descriptor() ([]byte, []int) { func (*LightningNode) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{89} return fileDescriptor_77a6da22d6a3feb1, []int{90}
} }
func (m *LightningNode) XXX_Unmarshal(b []byte) error { func (m *LightningNode) XXX_Unmarshal(b []byte) error {
@ -8129,7 +8216,7 @@ func (m *NodeAddress) Reset() { *m = NodeAddress{} }
func (m *NodeAddress) String() string { return proto.CompactTextString(m) } func (m *NodeAddress) String() string { return proto.CompactTextString(m) }
func (*NodeAddress) ProtoMessage() {} func (*NodeAddress) ProtoMessage() {}
func (*NodeAddress) Descriptor() ([]byte, []int) { func (*NodeAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{90} return fileDescriptor_77a6da22d6a3feb1, []int{91}
} }
func (m *NodeAddress) XXX_Unmarshal(b []byte) error { func (m *NodeAddress) XXX_Unmarshal(b []byte) error {
@ -8181,7 +8268,7 @@ func (m *RoutingPolicy) Reset() { *m = RoutingPolicy{} }
func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) } func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) }
func (*RoutingPolicy) ProtoMessage() {} func (*RoutingPolicy) ProtoMessage() {}
func (*RoutingPolicy) Descriptor() ([]byte, []int) { func (*RoutingPolicy) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{91} return fileDescriptor_77a6da22d6a3feb1, []int{92}
} }
func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error { func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error {
@ -8279,7 +8366,7 @@ func (m *ChannelEdge) Reset() { *m = ChannelEdge{} }
func (m *ChannelEdge) String() string { return proto.CompactTextString(m) } func (m *ChannelEdge) String() string { return proto.CompactTextString(m) }
func (*ChannelEdge) ProtoMessage() {} func (*ChannelEdge) ProtoMessage() {}
func (*ChannelEdge) Descriptor() ([]byte, []int) { func (*ChannelEdge) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{92} return fileDescriptor_77a6da22d6a3feb1, []int{93}
} }
func (m *ChannelEdge) XXX_Unmarshal(b []byte) error { func (m *ChannelEdge) XXX_Unmarshal(b []byte) error {
@ -8372,7 +8459,7 @@ func (m *ChannelGraphRequest) Reset() { *m = ChannelGraphRequest{} }
func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) } func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelGraphRequest) ProtoMessage() {} func (*ChannelGraphRequest) ProtoMessage() {}
func (*ChannelGraphRequest) Descriptor() ([]byte, []int) { func (*ChannelGraphRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{93} return fileDescriptor_77a6da22d6a3feb1, []int{94}
} }
func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error { func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error {
@ -8415,7 +8502,7 @@ func (m *ChannelGraph) Reset() { *m = ChannelGraph{} }
func (m *ChannelGraph) String() string { return proto.CompactTextString(m) } func (m *ChannelGraph) String() string { return proto.CompactTextString(m) }
func (*ChannelGraph) ProtoMessage() {} func (*ChannelGraph) ProtoMessage() {}
func (*ChannelGraph) Descriptor() ([]byte, []int) { func (*ChannelGraph) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{94} return fileDescriptor_77a6da22d6a3feb1, []int{95}
} }
func (m *ChannelGraph) XXX_Unmarshal(b []byte) error { func (m *ChannelGraph) XXX_Unmarshal(b []byte) error {
@ -8462,7 +8549,7 @@ func (m *NodeMetricsRequest) Reset() { *m = NodeMetricsRequest{} }
func (m *NodeMetricsRequest) String() string { return proto.CompactTextString(m) } func (m *NodeMetricsRequest) String() string { return proto.CompactTextString(m) }
func (*NodeMetricsRequest) ProtoMessage() {} func (*NodeMetricsRequest) ProtoMessage() {}
func (*NodeMetricsRequest) Descriptor() ([]byte, []int) { func (*NodeMetricsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{95} return fileDescriptor_77a6da22d6a3feb1, []int{96}
} }
func (m *NodeMetricsRequest) XXX_Unmarshal(b []byte) error { func (m *NodeMetricsRequest) XXX_Unmarshal(b []byte) error {
@ -8507,7 +8594,7 @@ func (m *NodeMetricsResponse) Reset() { *m = NodeMetricsResponse{} }
func (m *NodeMetricsResponse) String() string { return proto.CompactTextString(m) } func (m *NodeMetricsResponse) String() string { return proto.CompactTextString(m) }
func (*NodeMetricsResponse) ProtoMessage() {} func (*NodeMetricsResponse) ProtoMessage() {}
func (*NodeMetricsResponse) Descriptor() ([]byte, []int) { func (*NodeMetricsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{96} return fileDescriptor_77a6da22d6a3feb1, []int{97}
} }
func (m *NodeMetricsResponse) XXX_Unmarshal(b []byte) error { func (m *NodeMetricsResponse) XXX_Unmarshal(b []byte) error {
@ -8549,7 +8636,7 @@ func (m *FloatMetric) Reset() { *m = FloatMetric{} }
func (m *FloatMetric) String() string { return proto.CompactTextString(m) } func (m *FloatMetric) String() string { return proto.CompactTextString(m) }
func (*FloatMetric) ProtoMessage() {} func (*FloatMetric) ProtoMessage() {}
func (*FloatMetric) Descriptor() ([]byte, []int) { func (*FloatMetric) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{97} return fileDescriptor_77a6da22d6a3feb1, []int{98}
} }
func (m *FloatMetric) XXX_Unmarshal(b []byte) error { func (m *FloatMetric) XXX_Unmarshal(b []byte) error {
@ -8599,7 +8686,7 @@ func (m *ChanInfoRequest) Reset() { *m = ChanInfoRequest{} }
func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) } func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) }
func (*ChanInfoRequest) ProtoMessage() {} func (*ChanInfoRequest) ProtoMessage() {}
func (*ChanInfoRequest) Descriptor() ([]byte, []int) { func (*ChanInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{98} return fileDescriptor_77a6da22d6a3feb1, []int{99}
} }
func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error { func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error {
@ -8637,7 +8724,7 @@ func (m *NetworkInfoRequest) Reset() { *m = NetworkInfoRequest{} }
func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) } func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) }
func (*NetworkInfoRequest) ProtoMessage() {} func (*NetworkInfoRequest) ProtoMessage() {}
func (*NetworkInfoRequest) Descriptor() ([]byte, []int) { func (*NetworkInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{99} return fileDescriptor_77a6da22d6a3feb1, []int{100}
} }
func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error { func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error {
@ -8680,7 +8767,7 @@ func (m *NetworkInfo) Reset() { *m = NetworkInfo{} }
func (m *NetworkInfo) String() string { return proto.CompactTextString(m) } func (m *NetworkInfo) String() string { return proto.CompactTextString(m) }
func (*NetworkInfo) ProtoMessage() {} func (*NetworkInfo) ProtoMessage() {}
func (*NetworkInfo) Descriptor() ([]byte, []int) { func (*NetworkInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{100} return fileDescriptor_77a6da22d6a3feb1, []int{101}
} }
func (m *NetworkInfo) XXX_Unmarshal(b []byte) error { func (m *NetworkInfo) XXX_Unmarshal(b []byte) error {
@ -8788,7 +8875,7 @@ func (m *StopRequest) Reset() { *m = StopRequest{} }
func (m *StopRequest) String() string { return proto.CompactTextString(m) } func (m *StopRequest) String() string { return proto.CompactTextString(m) }
func (*StopRequest) ProtoMessage() {} func (*StopRequest) ProtoMessage() {}
func (*StopRequest) Descriptor() ([]byte, []int) { func (*StopRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{101} return fileDescriptor_77a6da22d6a3feb1, []int{102}
} }
func (m *StopRequest) XXX_Unmarshal(b []byte) error { func (m *StopRequest) XXX_Unmarshal(b []byte) error {
@ -8819,7 +8906,7 @@ func (m *StopResponse) Reset() { *m = StopResponse{} }
func (m *StopResponse) String() string { return proto.CompactTextString(m) } func (m *StopResponse) String() string { return proto.CompactTextString(m) }
func (*StopResponse) ProtoMessage() {} func (*StopResponse) ProtoMessage() {}
func (*StopResponse) Descriptor() ([]byte, []int) { func (*StopResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{102} return fileDescriptor_77a6da22d6a3feb1, []int{103}
} }
func (m *StopResponse) XXX_Unmarshal(b []byte) error { func (m *StopResponse) XXX_Unmarshal(b []byte) error {
@ -8850,7 +8937,7 @@ func (m *GraphTopologySubscription) Reset() { *m = GraphTopologySubscrip
func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) } func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) }
func (*GraphTopologySubscription) ProtoMessage() {} func (*GraphTopologySubscription) ProtoMessage() {}
func (*GraphTopologySubscription) Descriptor() ([]byte, []int) { func (*GraphTopologySubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{103} return fileDescriptor_77a6da22d6a3feb1, []int{104}
} }
func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error { func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error {
@ -8884,7 +8971,7 @@ func (m *GraphTopologyUpdate) Reset() { *m = GraphTopologyUpdate{} }
func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) } func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) }
func (*GraphTopologyUpdate) ProtoMessage() {} func (*GraphTopologyUpdate) ProtoMessage() {}
func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) { func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{104} return fileDescriptor_77a6da22d6a3feb1, []int{105}
} }
func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error { func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error {
@ -8945,7 +9032,7 @@ func (m *NodeUpdate) Reset() { *m = NodeUpdate{} }
func (m *NodeUpdate) String() string { return proto.CompactTextString(m) } func (m *NodeUpdate) String() string { return proto.CompactTextString(m) }
func (*NodeUpdate) ProtoMessage() {} func (*NodeUpdate) ProtoMessage() {}
func (*NodeUpdate) Descriptor() ([]byte, []int) { func (*NodeUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{105} return fileDescriptor_77a6da22d6a3feb1, []int{106}
} }
func (m *NodeUpdate) XXX_Unmarshal(b []byte) error { func (m *NodeUpdate) XXX_Unmarshal(b []byte) error {
@ -9029,7 +9116,7 @@ func (m *ChannelEdgeUpdate) Reset() { *m = ChannelEdgeUpdate{} }
func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) } func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelEdgeUpdate) ProtoMessage() {} func (*ChannelEdgeUpdate) ProtoMessage() {}
func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) { func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{106} return fileDescriptor_77a6da22d6a3feb1, []int{107}
} }
func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error { func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error {
@ -9110,7 +9197,7 @@ func (m *ClosedChannelUpdate) Reset() { *m = ClosedChannelUpdate{} }
func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) } func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelUpdate) ProtoMessage() {} func (*ClosedChannelUpdate) ProtoMessage() {}
func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) { func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{107} return fileDescriptor_77a6da22d6a3feb1, []int{108}
} }
func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error { func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error {
@ -9181,7 +9268,7 @@ func (m *HopHint) Reset() { *m = HopHint{} }
func (m *HopHint) String() string { return proto.CompactTextString(m) } func (m *HopHint) String() string { return proto.CompactTextString(m) }
func (*HopHint) ProtoMessage() {} func (*HopHint) ProtoMessage() {}
func (*HopHint) Descriptor() ([]byte, []int) { func (*HopHint) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{108} return fileDescriptor_77a6da22d6a3feb1, []int{109}
} }
func (m *HopHint) XXX_Unmarshal(b []byte) error { func (m *HopHint) XXX_Unmarshal(b []byte) error {
@ -9251,7 +9338,7 @@ func (m *RouteHint) Reset() { *m = RouteHint{} }
func (m *RouteHint) String() string { return proto.CompactTextString(m) } func (m *RouteHint) String() string { return proto.CompactTextString(m) }
func (*RouteHint) ProtoMessage() {} func (*RouteHint) ProtoMessage() {}
func (*RouteHint) Descriptor() ([]byte, []int) { func (*RouteHint) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{109} return fileDescriptor_77a6da22d6a3feb1, []int{110}
} }
func (m *RouteHint) XXX_Unmarshal(b []byte) error { func (m *RouteHint) XXX_Unmarshal(b []byte) error {
@ -9389,7 +9476,7 @@ 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) { func (*Invoice) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{110} return fileDescriptor_77a6da22d6a3feb1, []int{111}
} }
func (m *Invoice) XXX_Unmarshal(b []byte) error { func (m *Invoice) XXX_Unmarshal(b []byte) error {
@ -9620,7 +9707,7 @@ func (m *InvoiceHTLC) Reset() { *m = InvoiceHTLC{} }
func (m *InvoiceHTLC) String() string { return proto.CompactTextString(m) } func (m *InvoiceHTLC) String() string { return proto.CompactTextString(m) }
func (*InvoiceHTLC) ProtoMessage() {} func (*InvoiceHTLC) ProtoMessage() {}
func (*InvoiceHTLC) Descriptor() ([]byte, []int) { func (*InvoiceHTLC) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{111} return fileDescriptor_77a6da22d6a3feb1, []int{112}
} }
func (m *InvoiceHTLC) XXX_Unmarshal(b []byte) error { func (m *InvoiceHTLC) XXX_Unmarshal(b []byte) error {
@ -9743,7 +9830,7 @@ func (m *AMP) Reset() { *m = AMP{} }
func (m *AMP) String() string { return proto.CompactTextString(m) } func (m *AMP) String() string { return proto.CompactTextString(m) }
func (*AMP) ProtoMessage() {} func (*AMP) ProtoMessage() {}
func (*AMP) Descriptor() ([]byte, []int) { func (*AMP) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{112} return fileDescriptor_77a6da22d6a3feb1, []int{113}
} }
func (m *AMP) XXX_Unmarshal(b []byte) error { func (m *AMP) XXX_Unmarshal(b []byte) error {
@ -9826,7 +9913,7 @@ 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) { func (*AddInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{113} return fileDescriptor_77a6da22d6a3feb1, []int{114}
} }
func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error { func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error {
@ -9895,7 +9982,7 @@ 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) { func (*PaymentHash) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{114} return fileDescriptor_77a6da22d6a3feb1, []int{115}
} }
func (m *PaymentHash) XXX_Unmarshal(b []byte) error { func (m *PaymentHash) XXX_Unmarshal(b []byte) error {
@ -9955,7 +10042,7 @@ 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) { func (*ListInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{115} return fileDescriptor_77a6da22d6a3feb1, []int{116}
} }
func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error { func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error {
@ -10026,7 +10113,7 @@ 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) { func (*ListInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{116} return fileDescriptor_77a6da22d6a3feb1, []int{117}
} }
func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error { func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error {
@ -10090,7 +10177,7 @@ 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) { func (*InvoiceSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{117} return fileDescriptor_77a6da22d6a3feb1, []int{118}
} }
func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error { func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error {
@ -10167,7 +10254,7 @@ 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) { func (*Payment) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{118} return fileDescriptor_77a6da22d6a3feb1, []int{119}
} }
func (m *Payment) XXX_Unmarshal(b []byte) error { func (m *Payment) XXX_Unmarshal(b []byte) error {
@ -10322,7 +10409,7 @@ func (m *HTLCAttempt) Reset() { *m = HTLCAttempt{} }
func (m *HTLCAttempt) String() string { return proto.CompactTextString(m) } func (m *HTLCAttempt) String() string { return proto.CompactTextString(m) }
func (*HTLCAttempt) ProtoMessage() {} func (*HTLCAttempt) ProtoMessage() {}
func (*HTLCAttempt) Descriptor() ([]byte, []int) { func (*HTLCAttempt) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{119} return fileDescriptor_77a6da22d6a3feb1, []int{120}
} }
func (m *HTLCAttempt) XXX_Unmarshal(b []byte) error { func (m *HTLCAttempt) XXX_Unmarshal(b []byte) error {
@ -10422,7 +10509,7 @@ 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) { func (*ListPaymentsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{120} return fileDescriptor_77a6da22d6a3feb1, []int{121}
} }
func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error { func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error {
@ -10491,7 +10578,7 @@ 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) { func (*ListPaymentsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{121} return fileDescriptor_77a6da22d6a3feb1, []int{122}
} }
func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error { func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error {
@ -10548,7 +10635,7 @@ func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsReque
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) { func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{122} return fileDescriptor_77a6da22d6a3feb1, []int{123}
} }
func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error { func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error {
@ -10593,7 +10680,7 @@ func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResp
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) { func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{123} return fileDescriptor_77a6da22d6a3feb1, []int{124}
} }
func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error { func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error {
@ -10626,7 +10713,7 @@ func (m *AbandonChannelRequest) Reset() { *m = AbandonChannelRequest{} }
func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) } func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) }
func (*AbandonChannelRequest) ProtoMessage() {} func (*AbandonChannelRequest) ProtoMessage() {}
func (*AbandonChannelRequest) Descriptor() ([]byte, []int) { func (*AbandonChannelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{124} return fileDescriptor_77a6da22d6a3feb1, []int{125}
} }
func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error { func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error {
@ -10671,7 +10758,7 @@ func (m *AbandonChannelResponse) Reset() { *m = AbandonChannelResponse{}
func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) } func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) }
func (*AbandonChannelResponse) ProtoMessage() {} func (*AbandonChannelResponse) ProtoMessage() {}
func (*AbandonChannelResponse) Descriptor() ([]byte, []int) { func (*AbandonChannelResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{125} return fileDescriptor_77a6da22d6a3feb1, []int{126}
} }
func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error { func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error {
@ -10704,7 +10791,7 @@ 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) { func (*DebugLevelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{126} return fileDescriptor_77a6da22d6a3feb1, []int{127}
} }
func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error { func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error {
@ -10750,7 +10837,7 @@ 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) { func (*DebugLevelResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{127} return fileDescriptor_77a6da22d6a3feb1, []int{128}
} }
func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error { func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error {
@ -10790,7 +10877,7 @@ 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) { func (*PayReqString) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{128} return fileDescriptor_77a6da22d6a3feb1, []int{129}
} }
func (m *PayReqString) XXX_Unmarshal(b []byte) error { func (m *PayReqString) XXX_Unmarshal(b []byte) error {
@ -10841,7 +10928,7 @@ 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) { func (*PayReq) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{129} return fileDescriptor_77a6da22d6a3feb1, []int{130}
} }
func (m *PayReq) XXX_Unmarshal(b []byte) error { func (m *PayReq) XXX_Unmarshal(b []byte) error {
@ -10966,7 +11053,7 @@ func (m *Feature) Reset() { *m = Feature{} }
func (m *Feature) String() string { return proto.CompactTextString(m) } func (m *Feature) String() string { return proto.CompactTextString(m) }
func (*Feature) ProtoMessage() {} func (*Feature) ProtoMessage() {}
func (*Feature) Descriptor() ([]byte, []int) { func (*Feature) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{130} return fileDescriptor_77a6da22d6a3feb1, []int{131}
} }
func (m *Feature) XXX_Unmarshal(b []byte) error { func (m *Feature) XXX_Unmarshal(b []byte) error {
@ -11018,7 +11105,7 @@ 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) { func (*FeeReportRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{131} return fileDescriptor_77a6da22d6a3feb1, []int{132}
} }
func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error { func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error {
@ -11061,7 +11148,7 @@ 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) { func (*ChannelFeeReport) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{132} return fileDescriptor_77a6da22d6a3feb1, []int{133}
} }
func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error { func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error {
@ -11139,7 +11226,7 @@ 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) { func (*FeeReportResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{133} return fileDescriptor_77a6da22d6a3feb1, []int{134}
} }
func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error { func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error {
@ -11217,7 +11304,7 @@ 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) { func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{134} return fileDescriptor_77a6da22d6a3feb1, []int{135}
} }
func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error { func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error {
@ -11335,7 +11422,7 @@ 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) { func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{135} return fileDescriptor_77a6da22d6a3feb1, []int{136}
} }
func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error { func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error {
@ -11380,7 +11467,7 @@ func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryReque
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) { func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{136} return fileDescriptor_77a6da22d6a3feb1, []int{137}
} }
func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error { func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error {
@ -11466,7 +11553,7 @@ 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) { func (*ForwardingEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{137} return fileDescriptor_77a6da22d6a3feb1, []int{138}
} }
func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error { func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error {
@ -11574,7 +11661,7 @@ func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResp
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) { func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{138} return fileDescriptor_77a6da22d6a3feb1, []int{139}
} }
func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error { func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error {
@ -11621,7 +11708,7 @@ func (m *ExportChannelBackupRequest) Reset() { *m = ExportChannelBackupR
func (m *ExportChannelBackupRequest) String() string { return proto.CompactTextString(m) } func (m *ExportChannelBackupRequest) String() string { return proto.CompactTextString(m) }
func (*ExportChannelBackupRequest) ProtoMessage() {} func (*ExportChannelBackupRequest) ProtoMessage() {}
func (*ExportChannelBackupRequest) Descriptor() ([]byte, []int) { func (*ExportChannelBackupRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{139} return fileDescriptor_77a6da22d6a3feb1, []int{140}
} }
func (m *ExportChannelBackupRequest) XXX_Unmarshal(b []byte) error { func (m *ExportChannelBackupRequest) XXX_Unmarshal(b []byte) error {
@ -11668,7 +11755,7 @@ func (m *ChannelBackup) Reset() { *m = ChannelBackup{} }
func (m *ChannelBackup) String() string { return proto.CompactTextString(m) } func (m *ChannelBackup) String() string { return proto.CompactTextString(m) }
func (*ChannelBackup) ProtoMessage() {} func (*ChannelBackup) ProtoMessage() {}
func (*ChannelBackup) Descriptor() ([]byte, []int) { func (*ChannelBackup) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{140} return fileDescriptor_77a6da22d6a3feb1, []int{141}
} }
func (m *ChannelBackup) XXX_Unmarshal(b []byte) error { func (m *ChannelBackup) XXX_Unmarshal(b []byte) error {
@ -11722,7 +11809,7 @@ func (m *MultiChanBackup) Reset() { *m = MultiChanBackup{} }
func (m *MultiChanBackup) String() string { return proto.CompactTextString(m) } func (m *MultiChanBackup) String() string { return proto.CompactTextString(m) }
func (*MultiChanBackup) ProtoMessage() {} func (*MultiChanBackup) ProtoMessage() {}
func (*MultiChanBackup) Descriptor() ([]byte, []int) { func (*MultiChanBackup) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{141} return fileDescriptor_77a6da22d6a3feb1, []int{142}
} }
func (m *MultiChanBackup) XXX_Unmarshal(b []byte) error { func (m *MultiChanBackup) XXX_Unmarshal(b []byte) error {
@ -11767,7 +11854,7 @@ func (m *ChanBackupExportRequest) Reset() { *m = ChanBackupExportRequest
func (m *ChanBackupExportRequest) String() string { return proto.CompactTextString(m) } func (m *ChanBackupExportRequest) String() string { return proto.CompactTextString(m) }
func (*ChanBackupExportRequest) ProtoMessage() {} func (*ChanBackupExportRequest) ProtoMessage() {}
func (*ChanBackupExportRequest) Descriptor() ([]byte, []int) { func (*ChanBackupExportRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{142} return fileDescriptor_77a6da22d6a3feb1, []int{143}
} }
func (m *ChanBackupExportRequest) XXX_Unmarshal(b []byte) error { func (m *ChanBackupExportRequest) XXX_Unmarshal(b []byte) error {
@ -11806,7 +11893,7 @@ func (m *ChanBackupSnapshot) Reset() { *m = ChanBackupSnapshot{} }
func (m *ChanBackupSnapshot) String() string { return proto.CompactTextString(m) } func (m *ChanBackupSnapshot) String() string { return proto.CompactTextString(m) }
func (*ChanBackupSnapshot) ProtoMessage() {} func (*ChanBackupSnapshot) ProtoMessage() {}
func (*ChanBackupSnapshot) Descriptor() ([]byte, []int) { func (*ChanBackupSnapshot) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{143} return fileDescriptor_77a6da22d6a3feb1, []int{144}
} }
func (m *ChanBackupSnapshot) XXX_Unmarshal(b []byte) error { func (m *ChanBackupSnapshot) XXX_Unmarshal(b []byte) error {
@ -11854,7 +11941,7 @@ func (m *ChannelBackups) Reset() { *m = ChannelBackups{} }
func (m *ChannelBackups) String() string { return proto.CompactTextString(m) } func (m *ChannelBackups) String() string { return proto.CompactTextString(m) }
func (*ChannelBackups) ProtoMessage() {} func (*ChannelBackups) ProtoMessage() {}
func (*ChannelBackups) Descriptor() ([]byte, []int) { func (*ChannelBackups) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{144} return fileDescriptor_77a6da22d6a3feb1, []int{145}
} }
func (m *ChannelBackups) XXX_Unmarshal(b []byte) error { func (m *ChannelBackups) XXX_Unmarshal(b []byte) error {
@ -11896,7 +11983,7 @@ func (m *RestoreChanBackupRequest) Reset() { *m = RestoreChanBackupReque
func (m *RestoreChanBackupRequest) String() string { return proto.CompactTextString(m) } func (m *RestoreChanBackupRequest) String() string { return proto.CompactTextString(m) }
func (*RestoreChanBackupRequest) ProtoMessage() {} func (*RestoreChanBackupRequest) ProtoMessage() {}
func (*RestoreChanBackupRequest) Descriptor() ([]byte, []int) { func (*RestoreChanBackupRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{145} return fileDescriptor_77a6da22d6a3feb1, []int{146}
} }
func (m *RestoreChanBackupRequest) XXX_Unmarshal(b []byte) error { func (m *RestoreChanBackupRequest) XXX_Unmarshal(b []byte) error {
@ -11972,7 +12059,7 @@ func (m *RestoreBackupResponse) Reset() { *m = RestoreBackupResponse{} }
func (m *RestoreBackupResponse) String() string { return proto.CompactTextString(m) } func (m *RestoreBackupResponse) String() string { return proto.CompactTextString(m) }
func (*RestoreBackupResponse) ProtoMessage() {} func (*RestoreBackupResponse) ProtoMessage() {}
func (*RestoreBackupResponse) Descriptor() ([]byte, []int) { func (*RestoreBackupResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{146} return fileDescriptor_77a6da22d6a3feb1, []int{147}
} }
func (m *RestoreBackupResponse) XXX_Unmarshal(b []byte) error { func (m *RestoreBackupResponse) XXX_Unmarshal(b []byte) error {
@ -12003,7 +12090,7 @@ func (m *ChannelBackupSubscription) Reset() { *m = ChannelBackupSubscrip
func (m *ChannelBackupSubscription) String() string { return proto.CompactTextString(m) } func (m *ChannelBackupSubscription) String() string { return proto.CompactTextString(m) }
func (*ChannelBackupSubscription) ProtoMessage() {} func (*ChannelBackupSubscription) ProtoMessage() {}
func (*ChannelBackupSubscription) Descriptor() ([]byte, []int) { func (*ChannelBackupSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{147} return fileDescriptor_77a6da22d6a3feb1, []int{148}
} }
func (m *ChannelBackupSubscription) XXX_Unmarshal(b []byte) error { func (m *ChannelBackupSubscription) XXX_Unmarshal(b []byte) error {
@ -12034,7 +12121,7 @@ func (m *VerifyChanBackupResponse) Reset() { *m = VerifyChanBackupRespon
func (m *VerifyChanBackupResponse) String() string { return proto.CompactTextString(m) } func (m *VerifyChanBackupResponse) String() string { return proto.CompactTextString(m) }
func (*VerifyChanBackupResponse) ProtoMessage() {} func (*VerifyChanBackupResponse) ProtoMessage() {}
func (*VerifyChanBackupResponse) Descriptor() ([]byte, []int) { func (*VerifyChanBackupResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{148} return fileDescriptor_77a6da22d6a3feb1, []int{149}
} }
func (m *VerifyChanBackupResponse) XXX_Unmarshal(b []byte) error { func (m *VerifyChanBackupResponse) XXX_Unmarshal(b []byte) error {
@ -12069,7 +12156,7 @@ func (m *MacaroonPermission) Reset() { *m = MacaroonPermission{} }
func (m *MacaroonPermission) String() string { return proto.CompactTextString(m) } func (m *MacaroonPermission) String() string { return proto.CompactTextString(m) }
func (*MacaroonPermission) ProtoMessage() {} func (*MacaroonPermission) ProtoMessage() {}
func (*MacaroonPermission) Descriptor() ([]byte, []int) { func (*MacaroonPermission) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{149} return fileDescriptor_77a6da22d6a3feb1, []int{150}
} }
func (m *MacaroonPermission) XXX_Unmarshal(b []byte) error { func (m *MacaroonPermission) XXX_Unmarshal(b []byte) error {
@ -12118,7 +12205,7 @@ func (m *BakeMacaroonRequest) Reset() { *m = BakeMacaroonRequest{} }
func (m *BakeMacaroonRequest) String() string { return proto.CompactTextString(m) } func (m *BakeMacaroonRequest) String() string { return proto.CompactTextString(m) }
func (*BakeMacaroonRequest) ProtoMessage() {} func (*BakeMacaroonRequest) ProtoMessage() {}
func (*BakeMacaroonRequest) Descriptor() ([]byte, []int) { func (*BakeMacaroonRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{150} return fileDescriptor_77a6da22d6a3feb1, []int{151}
} }
func (m *BakeMacaroonRequest) XXX_Unmarshal(b []byte) error { func (m *BakeMacaroonRequest) XXX_Unmarshal(b []byte) error {
@ -12165,7 +12252,7 @@ func (m *BakeMacaroonResponse) Reset() { *m = BakeMacaroonResponse{} }
func (m *BakeMacaroonResponse) String() string { return proto.CompactTextString(m) } func (m *BakeMacaroonResponse) String() string { return proto.CompactTextString(m) }
func (*BakeMacaroonResponse) ProtoMessage() {} func (*BakeMacaroonResponse) ProtoMessage() {}
func (*BakeMacaroonResponse) Descriptor() ([]byte, []int) { func (*BakeMacaroonResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{151} return fileDescriptor_77a6da22d6a3feb1, []int{152}
} }
func (m *BakeMacaroonResponse) XXX_Unmarshal(b []byte) error { func (m *BakeMacaroonResponse) XXX_Unmarshal(b []byte) error {
@ -12203,7 +12290,7 @@ func (m *ListMacaroonIDsRequest) Reset() { *m = ListMacaroonIDsRequest{}
func (m *ListMacaroonIDsRequest) String() string { return proto.CompactTextString(m) } func (m *ListMacaroonIDsRequest) String() string { return proto.CompactTextString(m) }
func (*ListMacaroonIDsRequest) ProtoMessage() {} func (*ListMacaroonIDsRequest) ProtoMessage() {}
func (*ListMacaroonIDsRequest) Descriptor() ([]byte, []int) { func (*ListMacaroonIDsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{152} return fileDescriptor_77a6da22d6a3feb1, []int{153}
} }
func (m *ListMacaroonIDsRequest) XXX_Unmarshal(b []byte) error { func (m *ListMacaroonIDsRequest) XXX_Unmarshal(b []byte) error {
@ -12236,7 +12323,7 @@ func (m *ListMacaroonIDsResponse) Reset() { *m = ListMacaroonIDsResponse
func (m *ListMacaroonIDsResponse) String() string { return proto.CompactTextString(m) } func (m *ListMacaroonIDsResponse) String() string { return proto.CompactTextString(m) }
func (*ListMacaroonIDsResponse) ProtoMessage() {} func (*ListMacaroonIDsResponse) ProtoMessage() {}
func (*ListMacaroonIDsResponse) Descriptor() ([]byte, []int) { func (*ListMacaroonIDsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{153} return fileDescriptor_77a6da22d6a3feb1, []int{154}
} }
func (m *ListMacaroonIDsResponse) XXX_Unmarshal(b []byte) error { func (m *ListMacaroonIDsResponse) XXX_Unmarshal(b []byte) error {
@ -12276,7 +12363,7 @@ func (m *DeleteMacaroonIDRequest) Reset() { *m = DeleteMacaroonIDRequest
func (m *DeleteMacaroonIDRequest) String() string { return proto.CompactTextString(m) } func (m *DeleteMacaroonIDRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteMacaroonIDRequest) ProtoMessage() {} func (*DeleteMacaroonIDRequest) ProtoMessage() {}
func (*DeleteMacaroonIDRequest) Descriptor() ([]byte, []int) { func (*DeleteMacaroonIDRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{154} return fileDescriptor_77a6da22d6a3feb1, []int{155}
} }
func (m *DeleteMacaroonIDRequest) XXX_Unmarshal(b []byte) error { func (m *DeleteMacaroonIDRequest) XXX_Unmarshal(b []byte) error {
@ -12316,7 +12403,7 @@ func (m *DeleteMacaroonIDResponse) Reset() { *m = DeleteMacaroonIDRespon
func (m *DeleteMacaroonIDResponse) String() string { return proto.CompactTextString(m) } func (m *DeleteMacaroonIDResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteMacaroonIDResponse) ProtoMessage() {} func (*DeleteMacaroonIDResponse) ProtoMessage() {}
func (*DeleteMacaroonIDResponse) Descriptor() ([]byte, []int) { func (*DeleteMacaroonIDResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{155} return fileDescriptor_77a6da22d6a3feb1, []int{156}
} }
func (m *DeleteMacaroonIDResponse) XXX_Unmarshal(b []byte) error { func (m *DeleteMacaroonIDResponse) XXX_Unmarshal(b []byte) error {
@ -12356,7 +12443,7 @@ func (m *MacaroonPermissionList) Reset() { *m = MacaroonPermissionList{}
func (m *MacaroonPermissionList) String() string { return proto.CompactTextString(m) } func (m *MacaroonPermissionList) String() string { return proto.CompactTextString(m) }
func (*MacaroonPermissionList) ProtoMessage() {} func (*MacaroonPermissionList) ProtoMessage() {}
func (*MacaroonPermissionList) Descriptor() ([]byte, []int) { func (*MacaroonPermissionList) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{156} return fileDescriptor_77a6da22d6a3feb1, []int{157}
} }
func (m *MacaroonPermissionList) XXX_Unmarshal(b []byte) error { func (m *MacaroonPermissionList) XXX_Unmarshal(b []byte) error {
@ -12394,7 +12481,7 @@ func (m *ListPermissionsRequest) Reset() { *m = ListPermissionsRequest{}
func (m *ListPermissionsRequest) String() string { return proto.CompactTextString(m) } func (m *ListPermissionsRequest) String() string { return proto.CompactTextString(m) }
func (*ListPermissionsRequest) ProtoMessage() {} func (*ListPermissionsRequest) ProtoMessage() {}
func (*ListPermissionsRequest) Descriptor() ([]byte, []int) { func (*ListPermissionsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{157} return fileDescriptor_77a6da22d6a3feb1, []int{158}
} }
func (m *ListPermissionsRequest) XXX_Unmarshal(b []byte) error { func (m *ListPermissionsRequest) XXX_Unmarshal(b []byte) error {
@ -12429,7 +12516,7 @@ func (m *ListPermissionsResponse) Reset() { *m = ListPermissionsResponse
func (m *ListPermissionsResponse) String() string { return proto.CompactTextString(m) } func (m *ListPermissionsResponse) String() string { return proto.CompactTextString(m) }
func (*ListPermissionsResponse) ProtoMessage() {} func (*ListPermissionsResponse) ProtoMessage() {}
func (*ListPermissionsResponse) Descriptor() ([]byte, []int) { func (*ListPermissionsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{158} return fileDescriptor_77a6da22d6a3feb1, []int{159}
} }
func (m *ListPermissionsResponse) XXX_Unmarshal(b []byte) error { func (m *ListPermissionsResponse) XXX_Unmarshal(b []byte) error {
@ -12485,7 +12572,7 @@ func (m *Failure) Reset() { *m = Failure{} }
func (m *Failure) String() string { return proto.CompactTextString(m) } func (m *Failure) String() string { return proto.CompactTextString(m) }
func (*Failure) ProtoMessage() {} func (*Failure) ProtoMessage() {}
func (*Failure) Descriptor() ([]byte, []int) { func (*Failure) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{159} return fileDescriptor_77a6da22d6a3feb1, []int{160}
} }
func (m *Failure) XXX_Unmarshal(b []byte) error { func (m *Failure) XXX_Unmarshal(b []byte) error {
@ -12629,7 +12716,7 @@ func (m *ChannelUpdate) Reset() { *m = ChannelUpdate{} }
func (m *ChannelUpdate) String() string { return proto.CompactTextString(m) } func (m *ChannelUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelUpdate) ProtoMessage() {} func (*ChannelUpdate) ProtoMessage() {}
func (*ChannelUpdate) Descriptor() ([]byte, []int) { func (*ChannelUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{160} return fileDescriptor_77a6da22d6a3feb1, []int{161}
} }
func (m *ChannelUpdate) XXX_Unmarshal(b []byte) error { func (m *ChannelUpdate) XXX_Unmarshal(b []byte) error {
@ -12747,7 +12834,7 @@ func (m *MacaroonId) Reset() { *m = MacaroonId{} }
func (m *MacaroonId) String() string { return proto.CompactTextString(m) } func (m *MacaroonId) String() string { return proto.CompactTextString(m) }
func (*MacaroonId) ProtoMessage() {} func (*MacaroonId) ProtoMessage() {}
func (*MacaroonId) Descriptor() ([]byte, []int) { func (*MacaroonId) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{161} return fileDescriptor_77a6da22d6a3feb1, []int{162}
} }
func (m *MacaroonId) XXX_Unmarshal(b []byte) error { func (m *MacaroonId) XXX_Unmarshal(b []byte) error {
@ -12801,7 +12888,7 @@ func (m *Op) Reset() { *m = Op{} }
func (m *Op) String() string { return proto.CompactTextString(m) } func (m *Op) String() string { return proto.CompactTextString(m) }
func (*Op) ProtoMessage() {} func (*Op) ProtoMessage() {}
func (*Op) Descriptor() ([]byte, []int) { func (*Op) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{162} return fileDescriptor_77a6da22d6a3feb1, []int{163}
} }
func (m *Op) XXX_Unmarshal(b []byte) error { func (m *Op) XXX_Unmarshal(b []byte) error {
@ -12941,8 +13028,10 @@ func init() {
proto.RegisterType((*PendingChannelsResponse_ForceClosedChannel)(nil), "lnrpc.PendingChannelsResponse.ForceClosedChannel") proto.RegisterType((*PendingChannelsResponse_ForceClosedChannel)(nil), "lnrpc.PendingChannelsResponse.ForceClosedChannel")
proto.RegisterType((*ChannelEventSubscription)(nil), "lnrpc.ChannelEventSubscription") proto.RegisterType((*ChannelEventSubscription)(nil), "lnrpc.ChannelEventSubscription")
proto.RegisterType((*ChannelEventUpdate)(nil), "lnrpc.ChannelEventUpdate") proto.RegisterType((*ChannelEventUpdate)(nil), "lnrpc.ChannelEventUpdate")
proto.RegisterType((*WalletAccountBalance)(nil), "lnrpc.WalletAccountBalance")
proto.RegisterType((*WalletBalanceRequest)(nil), "lnrpc.WalletBalanceRequest") proto.RegisterType((*WalletBalanceRequest)(nil), "lnrpc.WalletBalanceRequest")
proto.RegisterType((*WalletBalanceResponse)(nil), "lnrpc.WalletBalanceResponse") proto.RegisterType((*WalletBalanceResponse)(nil), "lnrpc.WalletBalanceResponse")
proto.RegisterMapType((map[string]*WalletAccountBalance)(nil), "lnrpc.WalletBalanceResponse.AccountBalanceEntry")
proto.RegisterType((*Amount)(nil), "lnrpc.Amount") proto.RegisterType((*Amount)(nil), "lnrpc.Amount")
proto.RegisterType((*ChannelBalanceRequest)(nil), "lnrpc.ChannelBalanceRequest") proto.RegisterType((*ChannelBalanceRequest)(nil), "lnrpc.ChannelBalanceRequest")
proto.RegisterType((*ChannelBalanceResponse)(nil), "lnrpc.ChannelBalanceResponse") proto.RegisterType((*ChannelBalanceResponse)(nil), "lnrpc.ChannelBalanceResponse")
@ -13043,795 +13132,800 @@ func init() {
func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) } func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) }
var fileDescriptor_77a6da22d6a3feb1 = []byte{ var fileDescriptor_77a6da22d6a3feb1 = []byte{
// 12602 bytes of a gzipped FileDescriptorProto // 12685 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7d, 0x5b, 0x6c, 0x23, 0x59, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0xbd, 0x5b, 0x6c, 0x23, 0x59,
0x76, 0x58, 0xf3, 0x25, 0x92, 0x87, 0xa4, 0x44, 0x5d, 0xbd, 0xd8, 0xea, 0xe9, 0xe9, 0x9e, 0x9a, 0x7a, 0x18, 0xdc, 0xbc, 0x89, 0xe4, 0x47, 0x52, 0xa2, 0x8e, 0x6e, 0x6c, 0xf5, 0xf4, 0x74, 0x4f,
0xd9, 0x99, 0xde, 0x9e, 0x19, 0x4d, 0x4f, 0xcf, 0xf4, 0x3c, 0xb6, 0xe3, 0xf5, 0x52, 0x12, 0xd5, 0xcd, 0xec, 0x4c, 0x6f, 0xcf, 0x8e, 0xa6, 0xa7, 0x67, 0x7a, 0x2e, 0x3b, 0xbf, 0xd7, 0x4b, 0x49,
0xe2, 0xb6, 0x44, 0x6a, 0x8b, 0xd4, 0x8c, 0x67, 0x61, 0xbb, 0x5c, 0x22, 0xaf, 0xa4, 0x4a, 0x93, 0x54, 0x8b, 0xdb, 0x12, 0xa9, 0x2d, 0x52, 0x3d, 0x6e, 0xc3, 0x76, 0xb9, 0x44, 0x1e, 0x49, 0xf5,
0x55, 0xdc, 0xaa, 0xa2, 0x5a, 0xda, 0x20, 0x80, 0x3f, 0x1c, 0x3b, 0x30, 0x8c, 0x00, 0x01, 0xe2, 0x37, 0x59, 0xc5, 0xad, 0x2a, 0xaa, 0xa5, 0x0d, 0x02, 0xf8, 0xc1, 0xb1, 0x03, 0xc3, 0x08, 0x10,
0x00, 0x79, 0x18, 0x49, 0x90, 0x20, 0xf9, 0x33, 0x0c, 0xd8, 0xfe, 0x4a, 0x3e, 0xf2, 0x95, 0x20, 0x20, 0x0e, 0x10, 0x24, 0x46, 0x12, 0x24, 0x48, 0xde, 0x0c, 0x03, 0xb6, 0x9f, 0x92, 0x87, 0x3c,
0x40, 0x82, 0x20, 0x40, 0x8c, 0x3c, 0x10, 0x24, 0x08, 0x90, 0x38, 0x40, 0x0c, 0x24, 0x06, 0xfc, 0x25, 0x08, 0x90, 0x20, 0x08, 0x10, 0x23, 0x17, 0x04, 0x09, 0x02, 0x24, 0x0e, 0x10, 0x03, 0x89,
0x99, 0x04, 0x09, 0xee, 0xb9, 0x8f, 0xba, 0xf5, 0x50, 0x77, 0xcf, 0x7a, 0xb2, 0x3f, 0x12, 0xeb, 0x01, 0x3f, 0x26, 0x41, 0x82, 0xf3, 0x9d, 0x4b, 0x9d, 0xba, 0xa8, 0xbb, 0x67, 0x3d, 0xd9, 0x17,
0x9c, 0x73, 0xdf, 0xf7, 0x9e, 0x7b, 0xee, 0x39, 0xe7, 0x9e, 0x0b, 0x55, 0x7f, 0x36, 0xda, 0x9a, 0x89, 0xf5, 0x9d, 0xef, 0xdc, 0xcf, 0xf9, 0xce, 0x77, 0x3b, 0xdf, 0x81, 0xaa, 0x3f, 0x1b, 0x6d,
0xf9, 0x5e, 0xe8, 0x91, 0xd2, 0xc4, 0xf5, 0x67, 0x23, 0xe3, 0x0f, 0x73, 0x50, 0x3c, 0x0e, 0x2f, 0xcd, 0x7c, 0x2f, 0xf4, 0x48, 0x69, 0xe2, 0xfa, 0xb3, 0x91, 0xf1, 0x47, 0x39, 0x28, 0x1e, 0x87,
0x3d, 0xf2, 0x08, 0xea, 0xf6, 0x78, 0xec, 0xd3, 0x20, 0xb0, 0xc2, 0xab, 0x19, 0x6d, 0xe5, 0xee, 0x97, 0x1e, 0x79, 0x04, 0x75, 0x7b, 0x3c, 0xf6, 0x69, 0x10, 0x58, 0xe1, 0xd5, 0x8c, 0xb6, 0x72,
0xe6, 0xee, 0x2d, 0x3e, 0x24, 0x5b, 0x48, 0xb6, 0xd5, 0xe6, 0xa8, 0xe1, 0xd5, 0x8c, 0x9a, 0x35, 0x77, 0x73, 0xf7, 0x16, 0x1f, 0x92, 0x2d, 0x44, 0xdb, 0x6a, 0xf3, 0xa4, 0xe1, 0xd5, 0x8c, 0x9a,
0x3b, 0xfa, 0x20, 0x2d, 0x28, 0x8b, 0xcf, 0x56, 0xfe, 0x6e, 0xee, 0x5e, 0xd5, 0x94, 0x9f, 0xe4, 0x35, 0x3b, 0xfa, 0x20, 0x2d, 0x28, 0x8b, 0xcf, 0x56, 0xfe, 0x6e, 0xee, 0x5e, 0xd5, 0x94, 0x9f,
0x36, 0x80, 0x3d, 0xf5, 0xe6, 0x6e, 0x68, 0x05, 0x76, 0xd8, 0x2a, 0xdc, 0xcd, 0xdd, 0x2b, 0x98, 0xe4, 0x36, 0x80, 0x3d, 0xf5, 0xe6, 0x6e, 0x68, 0x05, 0x76, 0xd8, 0x2a, 0xdc, 0xcd, 0xdd, 0x2b,
0x55, 0x0e, 0x19, 0xd8, 0x21, 0xb9, 0x05, 0xd5, 0xd9, 0x33, 0x2b, 0x18, 0xf9, 0xce, 0x2c, 0x6c, 0x98, 0x55, 0x0e, 0x19, 0xd8, 0x21, 0xb9, 0x05, 0xd5, 0xd9, 0x73, 0x2b, 0x18, 0xf9, 0xce, 0x2c,
0x15, 0x31, 0x69, 0x65, 0xf6, 0x6c, 0x80, 0xdf, 0xe4, 0x5d, 0xa8, 0x78, 0xf3, 0x70, 0xe6, 0x39, 0x6c, 0x15, 0x31, 0x6b, 0x65, 0xf6, 0x7c, 0x80, 0xdf, 0xe4, 0x7d, 0xa8, 0x78, 0xf3, 0x70, 0xe6,
0x6e, 0xd8, 0x2a, 0xdd, 0xcd, 0xdd, 0xab, 0x3d, 0x5c, 0x12, 0x15, 0xe9, 0xcf, 0xc3, 0x23, 0x06, 0x39, 0x6e, 0xd8, 0x2a, 0xdd, 0xcd, 0xdd, 0xab, 0x3d, 0x5c, 0x12, 0x0d, 0xe9, 0xcf, 0xc3, 0x23,
0x36, 0x15, 0x01, 0x79, 0x0b, 0x1a, 0x23, 0xcf, 0x3d, 0x75, 0xfc, 0xa9, 0x1d, 0x3a, 0x9e, 0x1b, 0x06, 0x36, 0x15, 0x02, 0x79, 0x07, 0x1a, 0x23, 0xcf, 0x3d, 0x75, 0xfc, 0xa9, 0x1d, 0x3a, 0x9e,
0xb4, 0x16, 0xb0, 0xac, 0x38, 0xd0, 0xf8, 0x27, 0x79, 0xa8, 0x0d, 0x7d, 0xdb, 0x0d, 0xec, 0x11, 0x1b, 0xb4, 0x16, 0xb0, 0xae, 0x38, 0xd0, 0xf8, 0xc7, 0x79, 0xa8, 0x0d, 0x7d, 0xdb, 0x0d, 0xec,
0x03, 0x90, 0x0d, 0x28, 0x87, 0x97, 0xd6, 0xb9, 0x1d, 0x9c, 0x63, 0x53, 0xab, 0xe6, 0x42, 0x78, 0x11, 0x03, 0x90, 0x0d, 0x28, 0x87, 0x97, 0xd6, 0xb9, 0x1d, 0x9c, 0x63, 0x57, 0xab, 0xe6, 0x42,
0xb9, 0x6f, 0x07, 0xe7, 0x64, 0x1d, 0x16, 0x78, 0x2d, 0xb1, 0x41, 0x05, 0x53, 0x7c, 0x91, 0x77, 0x78, 0xb9, 0x6f, 0x07, 0xe7, 0x64, 0x1d, 0x16, 0x78, 0x2b, 0xb1, 0x43, 0x05, 0x53, 0x7c, 0x91,
0x61, 0xd9, 0x9d, 0x4f, 0xad, 0x78, 0x51, 0xac, 0x59, 0x25, 0xb3, 0xe9, 0xce, 0xa7, 0x3b, 0x3a, 0xf7, 0x61, 0xd9, 0x9d, 0x4f, 0xad, 0x78, 0x55, 0xac, 0x5b, 0x25, 0xb3, 0xe9, 0xce, 0xa7, 0x3b,
0x9c, 0x35, 0xfe, 0x64, 0xe2, 0x8d, 0x9e, 0xf1, 0x02, 0x78, 0xf3, 0xaa, 0x08, 0xc1, 0x32, 0xde, 0x3a, 0x9c, 0x75, 0xfe, 0x64, 0xe2, 0x8d, 0x9e, 0xf3, 0x0a, 0x78, 0xf7, 0xaa, 0x08, 0xc1, 0x3a,
0x80, 0xba, 0x40, 0x53, 0xe7, 0xec, 0x9c, 0xb7, 0xb1, 0x64, 0xd6, 0x38, 0x01, 0x82, 0x58, 0x0e, 0xde, 0x82, 0xba, 0x48, 0xa6, 0xce, 0xd9, 0x39, 0xef, 0x63, 0xc9, 0xac, 0x71, 0x04, 0x04, 0xb1,
0xa1, 0x33, 0xa5, 0x56, 0x10, 0xda, 0xd3, 0x99, 0x68, 0x52, 0x95, 0x41, 0x06, 0x0c, 0x80, 0x68, 0x12, 0x42, 0x67, 0x4a, 0xad, 0x20, 0xb4, 0xa7, 0x33, 0xd1, 0xa5, 0x2a, 0x83, 0x0c, 0x18, 0x00,
0x2f, 0xb4, 0x27, 0xd6, 0x29, 0xa5, 0x41, 0xab, 0x2c, 0xd0, 0x0c, 0xb2, 0x47, 0x69, 0x40, 0xbe, 0x93, 0xbd, 0xd0, 0x9e, 0x58, 0xa7, 0x94, 0x06, 0xad, 0xb2, 0x48, 0x66, 0x90, 0x3d, 0x4a, 0x03,
0x05, 0x8b, 0x63, 0x1a, 0x84, 0x96, 0x18, 0x0c, 0x1a, 0xb4, 0x2a, 0x77, 0x0b, 0xf7, 0xaa, 0x66, 0xf2, 0x2d, 0x58, 0x1c, 0xd3, 0x20, 0xb4, 0xc4, 0x64, 0xd0, 0xa0, 0x55, 0xb9, 0x5b, 0xb8, 0x57,
0x83, 0x41, 0xdb, 0x12, 0x48, 0x5e, 0x03, 0xf0, 0xed, 0xe7, 0x16, 0xeb, 0x08, 0x7a, 0xd9, 0xaa, 0x35, 0x1b, 0x0c, 0xda, 0x96, 0x40, 0xf2, 0x06, 0x80, 0x6f, 0xbf, 0xb0, 0xd8, 0x40, 0xd0, 0xcb,
0xf2, 0x51, 0xf0, 0xed, 0xe7, 0xc3, 0xcb, 0x7d, 0x7a, 0x49, 0x56, 0xa1, 0x34, 0xb1, 0x4f, 0xe8, 0x56, 0x95, 0xcf, 0x82, 0x6f, 0xbf, 0x18, 0x5e, 0xee, 0xd3, 0x4b, 0xb2, 0x0a, 0xa5, 0x89, 0x7d,
0xa4, 0x05, 0x88, 0xe0, 0x1f, 0xc6, 0x0f, 0x61, 0xfd, 0x09, 0x0d, 0xb5, 0xae, 0x0c, 0x4c, 0xfa, 0x42, 0x27, 0x2d, 0xc0, 0x04, 0xfe, 0x61, 0x84, 0xb0, 0xfe, 0x98, 0x86, 0xda, 0x50, 0x06, 0x26,
0xa3, 0x39, 0x0d, 0x42, 0xd6, 0xaa, 0x20, 0xb4, 0xfd, 0x50, 0xb6, 0x2a, 0xc7, 0x5b, 0x85, 0xb0, 0xfd, 0xd1, 0x9c, 0x06, 0x21, 0xeb, 0x55, 0x10, 0xda, 0x7e, 0x28, 0x7b, 0x95, 0xe3, 0xbd, 0x42,
0xa8, 0x55, 0xd4, 0x1d, 0x4b, 0x82, 0x3c, 0x12, 0x54, 0xa9, 0x3b, 0xe6, 0x68, 0xe3, 0x00, 0x88, 0x58, 0xd4, 0x2b, 0xea, 0x8e, 0x25, 0x42, 0x1e, 0x11, 0xaa, 0xd4, 0x1d, 0x8b, 0x64, 0xb6, 0x9a,
0x96, 0xf1, 0x2e, 0x0d, 0x6d, 0x67, 0x12, 0x90, 0x4f, 0xa0, 0x1e, 0x6a, 0xc5, 0xb5, 0x72, 0x77, 0x46, 0x23, 0x1c, 0xfc, 0x82, 0x58, 0x4d, 0xfc, 0xd3, 0x38, 0x00, 0xa2, 0x55, 0xb9, 0x4b, 0x43,
0x0b, 0xf7, 0x6a, 0x6a, 0x6a, 0x6a, 0x09, 0xcc, 0x18, 0x9d, 0x71, 0x0e, 0x95, 0x3d, 0x4a, 0x0f, 0xdb, 0x99, 0x04, 0xe4, 0x53, 0xa8, 0x87, 0x5a, 0x43, 0x5a, 0xb9, 0xbb, 0x85, 0x7b, 0x35, 0xb5,
0x9c, 0xa9, 0x13, 0x92, 0x75, 0x28, 0x9d, 0x3a, 0x97, 0x74, 0x8c, 0x95, 0x2a, 0xec, 0xdf, 0x30, 0x68, 0xb5, 0x0c, 0x66, 0x0c, 0xcf, 0x38, 0x87, 0xca, 0x1e, 0xa5, 0x07, 0xce, 0xd4, 0x09, 0xc9,
0xf9, 0x27, 0xb9, 0x03, 0x80, 0x3f, 0xac, 0xa9, 0x9a, 0xa5, 0xfb, 0x37, 0xcc, 0x2a, 0xc2, 0x0e, 0x3a, 0x94, 0x4e, 0x9d, 0x4b, 0x3a, 0xc6, 0xe6, 0x16, 0xf6, 0x6f, 0x98, 0xfc, 0x93, 0xdc, 0x01,
0x03, 0x3b, 0x24, 0x9b, 0x50, 0x9e, 0x51, 0x7f, 0x44, 0xe5, 0x7c, 0xd8, 0xbf, 0x61, 0x4a, 0xc0, 0xc0, 0x1f, 0xd6, 0x54, 0xad, 0xdf, 0xfd, 0x1b, 0x66, 0x15, 0x61, 0x87, 0x81, 0x1d, 0x92, 0x4d,
0x76, 0x19, 0x4a, 0x13, 0x96, 0xbb, 0xf1, 0xdf, 0x4b, 0x50, 0x1b, 0x50, 0x77, 0x2c, 0x7b, 0x82, 0x28, 0xcf, 0xa8, 0x3f, 0xa2, 0x72, 0xa5, 0xec, 0xdf, 0x30, 0x25, 0x60, 0xbb, 0x0c, 0xa5, 0x09,
0x40, 0x91, 0x75, 0x34, 0x16, 0x56, 0x37, 0xf1, 0x37, 0x79, 0x13, 0x6a, 0x38, 0x24, 0x41, 0xe8, 0x2b, 0xdd, 0xf8, 0x6f, 0x25, 0xa8, 0x0d, 0xa8, 0x3b, 0x96, 0x63, 0x44, 0xa0, 0xc8, 0xa6, 0x00,
0x3b, 0xee, 0x19, 0x5f, 0x2d, 0xdb, 0xf9, 0x56, 0xce, 0x04, 0x06, 0x1e, 0x20, 0x94, 0x34, 0xa1, 0x2b, 0xab, 0x9b, 0xf8, 0x9b, 0xbc, 0x0d, 0x35, 0x9c, 0xac, 0x20, 0xf4, 0x1d, 0xf7, 0x8c, 0xef,
0x60, 0x4f, 0xe5, 0x6a, 0x61, 0x3f, 0xc9, 0x4d, 0xa8, 0xd8, 0xd3, 0x90, 0x57, 0xaf, 0x8e, 0xe0, 0xa3, 0xed, 0x7c, 0x2b, 0x67, 0x02, 0x03, 0x0f, 0x10, 0x4a, 0x9a, 0x50, 0xb0, 0xa7, 0x72, 0x1f,
0xb2, 0x3d, 0x0d, 0xb1, 0x6a, 0x6f, 0x40, 0x7d, 0x66, 0x5f, 0x4d, 0xa9, 0x1b, 0x46, 0xd3, 0xac, 0xb1, 0x9f, 0xe4, 0x26, 0x54, 0xec, 0x69, 0xc8, 0x9b, 0x57, 0x47, 0x70, 0xd9, 0x9e, 0x86, 0xd8,
0x6e, 0xd6, 0x04, 0x0c, 0x27, 0xda, 0x43, 0x58, 0xd1, 0x49, 0x64, 0xe1, 0x25, 0x55, 0xf8, 0xb2, 0xb4, 0xb7, 0xa0, 0x3e, 0xb3, 0xaf, 0xa6, 0xd4, 0x0d, 0xa3, 0x05, 0x58, 0x37, 0x6b, 0x02, 0x86,
0x46, 0x2d, 0xea, 0xf0, 0x0e, 0x2c, 0xc9, 0x34, 0x3e, 0x6f, 0x0f, 0x4e, 0xbf, 0xaa, 0xb9, 0x28, 0x4b, 0xf0, 0x21, 0xac, 0xe8, 0x28, 0xb2, 0xf2, 0x92, 0xaa, 0x7c, 0x59, 0xc3, 0x16, 0x6d, 0x78,
0xc0, 0xb2, 0x95, 0xf7, 0xa0, 0x79, 0xea, 0xb8, 0xf6, 0xc4, 0x1a, 0x4d, 0xc2, 0x0b, 0x6b, 0x4c, 0x0f, 0x96, 0x64, 0x1e, 0x9f, 0xf7, 0x07, 0x17, 0x66, 0xd5, 0x5c, 0x14, 0x60, 0xd9, 0xcb, 0x7b,
0x27, 0xa1, 0x8d, 0x33, 0xb1, 0x64, 0x2e, 0x22, 0x7c, 0x67, 0x12, 0x5e, 0xec, 0x32, 0x28, 0x79, 0xd0, 0x3c, 0x75, 0x5c, 0x7b, 0x62, 0x8d, 0x26, 0xe1, 0x85, 0x35, 0xa6, 0x93, 0xd0, 0xc6, 0x35,
0x0f, 0xaa, 0xa7, 0x94, 0x5a, 0xd8, 0x59, 0xad, 0x4a, 0x6c, 0x41, 0xcb, 0x11, 0x32, 0x2b, 0xa7, 0x5a, 0x32, 0x17, 0x11, 0xbe, 0x33, 0x09, 0x2f, 0x76, 0x19, 0x94, 0x7c, 0x07, 0xaa, 0xa7, 0x94,
0x72, 0xac, 0xde, 0x83, 0xa6, 0x37, 0x0f, 0xcf, 0x3c, 0xc7, 0x3d, 0xb3, 0x46, 0xe7, 0xb6, 0x6b, 0x5a, 0x38, 0x58, 0xad, 0x4a, 0x6c, 0xab, 0xcb, 0x19, 0x32, 0x2b, 0xa7, 0x72, 0xae, 0xbe, 0x03,
0x39, 0x63, 0x9c, 0x9b, 0xc5, 0xed, 0xfc, 0x83, 0x9c, 0xb9, 0x28, 0x71, 0x3b, 0xe7, 0xb6, 0xdb, 0x4d, 0x6f, 0x1e, 0x9e, 0x79, 0x8e, 0x7b, 0x66, 0x8d, 0xce, 0x6d, 0xd7, 0x72, 0xc6, 0xb8, 0x6a,
0x1d, 0x93, 0xb7, 0x61, 0x69, 0x62, 0x07, 0xa1, 0x75, 0xee, 0xcd, 0xac, 0xd9, 0xfc, 0xe4, 0x19, 0x8b, 0xdb, 0xf9, 0x07, 0x39, 0x73, 0x51, 0xa6, 0xed, 0x9c, 0xdb, 0x6e, 0x77, 0x4c, 0xde, 0x85,
0xbd, 0x6a, 0x35, 0xb0, 0x23, 0x1a, 0x0c, 0xbc, 0xef, 0xcd, 0x8e, 0x10, 0xc8, 0xa6, 0x1e, 0xd6, 0xa5, 0x89, 0x1d, 0x84, 0xd6, 0xb9, 0x37, 0xb3, 0x66, 0xf3, 0x93, 0xe7, 0xf4, 0xaa, 0xd5, 0xc0,
0x93, 0x57, 0x82, 0x4d, 0xe9, 0x86, 0x59, 0x65, 0x10, 0x5e, 0xe8, 0x57, 0xb0, 0x82, 0xc3, 0x33, 0x81, 0x68, 0x30, 0xf0, 0xbe, 0x37, 0x3b, 0x42, 0x20, 0x5b, 0x94, 0xd8, 0x4e, 0xde, 0x08, 0xb6,
0x9a, 0x07, 0xa1, 0x37, 0xb5, 0x7c, 0x3a, 0xf2, 0xfc, 0x71, 0xd0, 0xaa, 0xe1, 0x5c, 0xfb, 0xb6, 0xd8, 0x1b, 0x66, 0x95, 0x41, 0x78, 0xa5, 0xcf, 0x60, 0x05, 0xa7, 0x67, 0x34, 0x0f, 0x42, 0x6f,
0xa8, 0xac, 0x36, 0xc6, 0x5b, 0xbb, 0x34, 0x08, 0x77, 0x90, 0xd8, 0xe4, 0xb4, 0x1d, 0x37, 0xf4, 0x6a, 0xf9, 0x74, 0xe4, 0xf9, 0xe3, 0xa0, 0x55, 0xc3, 0xb5, 0xf6, 0x6d, 0xd1, 0x58, 0x6d, 0x8e,
0xaf, 0xcc, 0xe5, 0x71, 0x12, 0x4e, 0xde, 0x03, 0x62, 0x4f, 0x26, 0xde, 0x73, 0x2b, 0xa0, 0x93, 0xb7, 0x76, 0x69, 0x10, 0xee, 0x20, 0xb2, 0xc9, 0x71, 0x3b, 0x6e, 0xe8, 0x5f, 0x99, 0xcb, 0xe3,
0x53, 0x4b, 0x74, 0x62, 0x6b, 0xf1, 0x6e, 0xee, 0x5e, 0xc5, 0x6c, 0x22, 0x66, 0x40, 0x27, 0xa7, 0x24, 0x9c, 0x7c, 0x07, 0x88, 0x3d, 0x99, 0x78, 0x2f, 0xac, 0x80, 0x4e, 0x4e, 0x2d, 0x31, 0x88,
0x47, 0x1c, 0x4e, 0x3e, 0x01, 0x5c, 0xa4, 0xd6, 0x29, 0xb5, 0xc3, 0xb9, 0x4f, 0x83, 0xd6, 0xd2, 0xad, 0xc5, 0xbb, 0xb9, 0x7b, 0x15, 0xb3, 0x89, 0x29, 0x03, 0x3a, 0x39, 0x3d, 0xe2, 0x70, 0xf2,
0xdd, 0xc2, 0xbd, 0xc5, 0x87, 0xcb, 0xaa, 0xbf, 0x10, 0xbc, 0xed, 0x84, 0x66, 0x9d, 0xd1, 0x89, 0x29, 0xe0, 0xf6, 0xb5, 0x4e, 0xa9, 0x1d, 0xce, 0x7d, 0x1a, 0xb4, 0x96, 0xee, 0x16, 0xee, 0x2d,
0xef, 0x40, 0x9f, 0x0d, 0x6c, 0xd5, 0xb7, 0x9a, 0xb1, 0xd9, 0xc0, 0xd6, 0xfc, 0xe6, 0x2e, 0xac, 0x3e, 0x5c, 0x56, 0xe3, 0x85, 0xe0, 0x6d, 0x27, 0x34, 0xeb, 0x0c, 0x4f, 0x7c, 0x07, 0xfa, 0x6a,
0x67, 0xd7, 0x9a, 0xcd, 0x3b, 0xd6, 0x71, 0x6c, 0xbe, 0x16, 0x4d, 0xf6, 0x93, 0x2d, 0xfe, 0x0b, 0x60, 0xf4, 0xa0, 0xd5, 0x8c, 0xad, 0x06, 0x46, 0x0d, 0x36, 0x77, 0x61, 0x3d, 0xbb, 0xd5, 0x6c,
0x7b, 0x32, 0xa7, 0x38, 0x51, 0xeb, 0x26, 0xff, 0xf8, 0x4e, 0xfe, 0xb3, 0x9c, 0xf1, 0x7b, 0x39, 0xdd, 0xb1, 0x81, 0x63, 0xeb, 0xb5, 0x68, 0xb2, 0x9f, 0x8c, 0x2c, 0x5c, 0xd8, 0x93, 0x39, 0xc5,
0xa8, 0xf3, 0x8e, 0x08, 0x66, 0x9e, 0x1b, 0x50, 0xf2, 0x26, 0x34, 0x64, 0xc9, 0xd4, 0xf7, 0x3d, 0x85, 0x5a, 0x37, 0xf9, 0xc7, 0x77, 0xf3, 0x9f, 0xe7, 0x8c, 0xdf, 0xcf, 0x41, 0x9d, 0x0f, 0x44,
0x5f, 0x30, 0x54, 0x59, 0x9d, 0x0e, 0x83, 0x91, 0x6f, 0x43, 0x53, 0x12, 0xcd, 0x7c, 0xea, 0x4c, 0x30, 0xf3, 0xdc, 0x80, 0x92, 0xb7, 0xa1, 0x21, 0x6b, 0xa6, 0xbe, 0xef, 0xf9, 0x82, 0xd4, 0xca,
0xed, 0x33, 0x99, 0xb5, 0x9c, 0x6d, 0x47, 0x02, 0x4c, 0x3e, 0x8c, 0xf2, 0xf3, 0xbd, 0x79, 0x48, 0xe6, 0x74, 0x18, 0x8c, 0x7c, 0x1b, 0x9a, 0x12, 0x69, 0xe6, 0x53, 0x67, 0x6a, 0x9f, 0xc9, 0xa2,
0x71, 0x39, 0xd4, 0x1e, 0xd6, 0x45, 0x0f, 0x98, 0x0c, 0xa6, 0x72, 0xc7, 0xaf, 0x57, 0x58, 0x0a, 0xe5, 0x6a, 0x3b, 0x12, 0x60, 0xf2, 0x51, 0x54, 0x9e, 0xef, 0xcd, 0x43, 0x8a, 0xdb, 0xa1, 0xf6,
0xc6, 0x6f, 0xe6, 0x80, 0xb0, 0x6a, 0x0f, 0x3d, 0x9e, 0x41, 0xc4, 0xb4, 0x62, 0x29, 0x73, 0xaf, 0xb0, 0x2e, 0x46, 0xc0, 0x64, 0x30, 0x55, 0x3a, 0x7e, 0xbd, 0xc6, 0x56, 0x30, 0x7e, 0x2b, 0x07,
0xbc, 0x88, 0xf2, 0x2f, 0x5a, 0x44, 0x06, 0x94, 0x78, 0xdd, 0x8b, 0x19, 0x75, 0xe7, 0xa8, 0xef, 0x84, 0x35, 0x7b, 0xe8, 0xf1, 0x02, 0x22, 0x72, 0x16, 0xcb, 0x99, 0x7b, 0xed, 0x4d, 0x94, 0x7f,
0x17, 0x2b, 0x85, 0x66, 0xd1, 0xf8, 0xf7, 0x05, 0x58, 0x65, 0x53, 0xd9, 0xa5, 0x93, 0xf6, 0x68, 0xd9, 0x26, 0x32, 0xa0, 0xc4, 0xdb, 0x5e, 0xcc, 0x68, 0x3b, 0x4f, 0xfa, 0x41, 0xb1, 0x52, 0x68,
0x44, 0x67, 0x6a, 0x79, 0xdd, 0x81, 0x9a, 0xeb, 0x8d, 0xa9, 0x9c, 0xd4, 0xbc, 0x62, 0xc0, 0x40, 0x16, 0x8d, 0x7f, 0x57, 0x80, 0x55, 0xb6, 0x94, 0x5d, 0x3a, 0x69, 0x8f, 0x46, 0x74, 0xa6, 0xb6,
0xda, 0x8c, 0x3e, 0xb7, 0x1d, 0x97, 0x57, 0x9c, 0x77, 0x66, 0x15, 0x21, 0x58, 0xed, 0xb7, 0x61, 0xd7, 0x1d, 0xa8, 0xb9, 0xde, 0x98, 0xca, 0x45, 0xcd, 0x1b, 0x06, 0x0c, 0xa4, 0xad, 0xe8, 0x73,
0x69, 0x46, 0xdd, 0xb1, 0xbe, 0x8a, 0x0a, 0x7c, 0x61, 0x08, 0xb0, 0x58, 0x40, 0x77, 0xa0, 0x76, 0xdb, 0x71, 0x79, 0xc3, 0xf9, 0x60, 0x56, 0x11, 0x82, 0xcd, 0x7e, 0x17, 0x96, 0x66, 0xd4, 0x1d,
0x3a, 0xe7, 0x74, 0x8c, 0xf7, 0x14, 0x71, 0x0e, 0x80, 0x00, 0xb5, 0x39, 0x0b, 0x9a, 0xcd, 0x83, 0xeb, 0xbb, 0xa8, 0xc0, 0x37, 0x86, 0x00, 0x8b, 0x0d, 0x74, 0x07, 0x6a, 0xa7, 0x73, 0x8e, 0xc7,
0x73, 0xc4, 0x96, 0x10, 0x5b, 0x66, 0xdf, 0x0c, 0x75, 0x1b, 0x60, 0x3c, 0x0f, 0x42, 0xb1, 0xa8, 0x68, 0x4f, 0x11, 0xd7, 0x00, 0x08, 0x50, 0x9b, 0x93, 0xa0, 0xd9, 0x3c, 0x38, 0xc7, 0xd4, 0x12,
0x16, 0x10, 0x59, 0x65, 0x10, 0xbe, 0xa8, 0xde, 0x87, 0x95, 0xa9, 0x7d, 0x69, 0xe1, 0xdc, 0xb1, 0xa6, 0x96, 0xd9, 0x37, 0x4b, 0xba, 0x0d, 0x30, 0x9e, 0x07, 0xa1, 0xd8, 0x54, 0x0b, 0x98, 0x58,
0x1c, 0xd7, 0x3a, 0x9d, 0x20, 0xdf, 0x2f, 0x23, 0x5d, 0x73, 0x6a, 0x5f, 0x7e, 0xc1, 0x30, 0x5d, 0x65, 0x10, 0xbe, 0xa9, 0x3e, 0x80, 0x95, 0xa9, 0x7d, 0x69, 0xe1, 0xda, 0xb1, 0x1c, 0xd7, 0x3a,
0x77, 0x0f, 0xe1, 0x8c, 0xf3, 0x8c, 0x78, 0x4f, 0x58, 0x3e, 0x0d, 0xa8, 0x7f, 0x41, 0x91, 0x59, 0x9d, 0xe0, 0x89, 0x50, 0x46, 0xbc, 0xe6, 0xd4, 0xbe, 0x7c, 0xca, 0x52, 0xba, 0xee, 0x1e, 0xc2,
0x14, 0xcd, 0x45, 0x01, 0x36, 0x39, 0x94, 0xd5, 0x68, 0xca, 0xda, 0x1d, 0x4e, 0x46, 0x9c, 0x33, 0x19, 0xe5, 0x19, 0xf1, 0x91, 0xb0, 0x7c, 0x1a, 0x50, 0xff, 0x82, 0x22, 0xb1, 0x28, 0x9a, 0x8b,
0x98, 0xe5, 0xa9, 0xe3, 0xee, 0x87, 0x93, 0x11, 0xdb, 0xd2, 0x18, 0xab, 0x99, 0x51, 0xdf, 0x7a, 0x02, 0x6c, 0x72, 0x28, 0x6b, 0xd1, 0x94, 0xf5, 0x3b, 0x9c, 0x8c, 0x38, 0x65, 0x30, 0xcb, 0x53,
0xf6, 0x1c, 0x97, 0x79, 0x11, 0x59, 0xcb, 0x11, 0xf5, 0x9f, 0x3e, 0x67, 0x52, 0xc7, 0x28, 0x40, 0xc7, 0xdd, 0x0f, 0x27, 0x23, 0x76, 0xd8, 0x31, 0x52, 0x33, 0xa3, 0xbe, 0xf5, 0xfc, 0x05, 0x6e,
0x5e, 0x65, 0x5f, 0xb5, 0x6a, 0xc8, 0x03, 0x2a, 0xa3, 0x80, 0x71, 0x29, 0xfb, 0x8a, 0xad, 0x53, 0xf3, 0x22, 0x92, 0x96, 0x23, 0xea, 0x3f, 0x79, 0xc1, 0xf8, 0x91, 0x51, 0x80, 0xb4, 0xca, 0xbe,
0x56, 0x5b, 0x1b, 0x47, 0x81, 0x8e, 0x31, 0xfb, 0x00, 0x99, 0x6e, 0x03, 0x2b, 0xdb, 0x16, 0x08, 0x6a, 0xd5, 0x90, 0x06, 0x54, 0x46, 0x01, 0xa3, 0x52, 0xf6, 0x15, 0xdb, 0xa7, 0xac, 0xb5, 0x36,
0x56, 0x4e, 0xc0, 0x66, 0xbd, 0xac, 0xec, 0xe9, 0xc4, 0x3e, 0x0b, 0x90, 0xeb, 0x34, 0xcc, 0xba, 0xce, 0x02, 0x1d, 0x63, 0xf1, 0x01, 0x12, 0xdd, 0x06, 0x36, 0xb6, 0x2d, 0x12, 0x58, 0x3d, 0x01,
0x00, 0xee, 0x31, 0x98, 0xf1, 0x27, 0x79, 0x58, 0x4b, 0x0c, 0xae, 0x58, 0x34, 0x4c, 0xcc, 0x40, 0x5b, 0xf5, 0xb2, 0xb1, 0xa7, 0x13, 0xfb, 0x2c, 0x40, 0xaa, 0xd3, 0x30, 0xeb, 0x02, 0xb8, 0xc7,
0x08, 0x0e, 0x6c, 0xc5, 0x14, 0x5f, 0x59, 0xa3, 0x96, 0xcf, 0x1a, 0xb5, 0x55, 0x28, 0xf1, 0xc5, 0x60, 0xc6, 0x9f, 0xe6, 0x61, 0x2d, 0x31, 0xb9, 0x62, 0xd3, 0x30, 0x06, 0x04, 0x21, 0x38, 0xb1,
0x56, 0xe0, 0x9b, 0x33, 0x95, 0xab, 0x6c, 0x3e, 0x3b, 0xf5, 0x3d, 0x26, 0x75, 0x9d, 0xcf, 0xc3, 0x15, 0x53, 0x7c, 0x65, 0xcd, 0x5a, 0x3e, 0x6b, 0xd6, 0x56, 0xa1, 0xc4, 0x37, 0x1b, 0x3f, 0x42,
0xb1, 0xf7, 0xdc, 0x15, 0xd2, 0xc7, 0x92, 0x80, 0x0f, 0x04, 0x38, 0xde, 0x15, 0xa5, 0x44, 0x57, 0xf9, 0x07, 0xdb, 0x65, 0xf3, 0xd9, 0xa9, 0xef, 0x31, 0x7e, 0xec, 0x7c, 0x1e, 0x8e, 0xbd, 0x17,
0xdc, 0x81, 0x9a, 0x18, 0x01, 0x94, 0xde, 0xf8, 0xc0, 0x82, 0x00, 0x31, 0xf1, 0xed, 0x5d, 0x20, 0xae, 0xe0, 0x4b, 0x96, 0x04, 0x7c, 0x20, 0xc0, 0xf1, 0xa1, 0x28, 0x25, 0x86, 0xe2, 0x0e, 0xd4,
0x6a, 0x3c, 0x2d, 0xd6, 0x6b, 0xb8, 0x41, 0xf1, 0x81, 0x5d, 0x72, 0xc4, 0x80, 0x1e, 0xda, 0x97, 0xc4, 0x0c, 0x20, 0x5f, 0xc7, 0x27, 0x16, 0x04, 0x88, 0x31, 0x76, 0xef, 0x03, 0x51, 0xf3, 0x69,
0xb8, 0x51, 0xbd, 0x05, 0x8b, 0x8c, 0x84, 0xf5, 0xa7, 0x35, 0x42, 0xd1, 0xaa, 0xc2, 0xfb, 0x6a, 0xb1, 0x51, 0xc3, 0x03, 0x8a, 0x4f, 0xec, 0x92, 0x23, 0x26, 0xf4, 0xd0, 0xbe, 0xc4, 0x83, 0xea,
0x6a, 0x5f, 0xb2, 0xce, 0xdc, 0x41, 0x01, 0xeb, 0x75, 0xa8, 0xc9, 0x41, 0xb5, 0x1c, 0x57, 0x8c, 0x1d, 0x58, 0x64, 0x28, 0x6c, 0x3c, 0x2d, 0x7e, 0xee, 0x57, 0xf8, 0x58, 0x4d, 0xed, 0x4b, 0x36,
0x6b, 0x55, 0x8c, 0x6b, 0xd7, 0x65, 0xdb, 0x0d, 0xc3, 0xf3, 0x7e, 0xb2, 0xc6, 0x74, 0x16, 0x9e, 0x98, 0x3b, 0xc8, 0x7a, 0xbd, 0x09, 0x35, 0x39, 0xa9, 0x96, 0xe3, 0x8a, 0x79, 0xad, 0x8a, 0x79,
0x0b, 0x36, 0xbe, 0x38, 0x75, 0x5c, 0xde, 0xbd, 0xbb, 0x0c, 0x6a, 0xfc, 0x56, 0x0e, 0xea, 0xa2, 0xed, 0xba, 0xec, 0xb8, 0x61, 0xe9, 0x7c, 0x9c, 0xac, 0x31, 0x9d, 0x85, 0xe7, 0x82, 0x8c, 0x2f,
0xd7, 0x51, 0x58, 0x24, 0x5b, 0x40, 0xe4, 0x14, 0x0f, 0x2f, 0x9d, 0xb1, 0x75, 0x72, 0x15, 0xd2, 0x4e, 0x1d, 0x97, 0x0f, 0xef, 0x2e, 0x83, 0x1a, 0xbf, 0x9d, 0x83, 0xba, 0x18, 0x75, 0x64, 0x23,
0x80, 0xaf, 0xa8, 0xfd, 0x1b, 0x66, 0x53, 0xe0, 0x86, 0x97, 0xce, 0x78, 0x9b, 0x61, 0xc8, 0x7d, 0xc9, 0x16, 0x10, 0xb9, 0xc4, 0xc3, 0x4b, 0x67, 0x6c, 0x9d, 0x5c, 0x85, 0x34, 0xe0, 0x3b, 0x6a,
0x68, 0xc6, 0xe8, 0x83, 0xd0, 0xe7, 0xcb, 0x7d, 0xff, 0x86, 0xb9, 0xa8, 0x51, 0x0f, 0x42, 0x9f, 0xff, 0x86, 0xd9, 0x14, 0x69, 0xc3, 0x4b, 0x67, 0xbc, 0xcd, 0x52, 0xc8, 0x7d, 0x68, 0xc6, 0xf0,
0x31, 0x10, 0x26, 0x8a, 0xce, 0x43, 0xcb, 0x71, 0xc7, 0xf4, 0x12, 0xc7, 0xa3, 0x61, 0xd6, 0x38, 0x83, 0xd0, 0xe7, 0xdb, 0x7d, 0xff, 0x86, 0xb9, 0xa8, 0x61, 0x0f, 0x42, 0x9f, 0x11, 0x10, 0xc6,
0xac, 0xcb, 0x40, 0xdb, 0x8b, 0x50, 0xd7, 0xb3, 0x33, 0xce, 0xa0, 0x22, 0xe5, 0x58, 0x14, 0xe4, 0xa4, 0xce, 0x43, 0xcb, 0x71, 0xc7, 0xf4, 0x12, 0xe7, 0xa3, 0x61, 0xd6, 0x38, 0xac, 0xcb, 0x40,
0x12, 0x55, 0x32, 0xab, 0xa1, 0xaa, 0xc9, 0x4d, 0xa8, 0xc4, 0x6b, 0x60, 0x96, 0xc3, 0x57, 0x2e, 0xdb, 0x8b, 0x50, 0xd7, 0x8b, 0x33, 0xce, 0xa0, 0x22, 0x39, 0x5c, 0x64, 0xf1, 0x12, 0x4d, 0x32,
0xd8, 0xf8, 0x2e, 0x34, 0x0f, 0xd8, 0x40, 0xb8, 0x6c, 0x25, 0x0b, 0xb9, 0x7c, 0x1d, 0x16, 0x34, 0xab, 0xa1, 0x6a, 0xc9, 0x4d, 0xa8, 0xc4, 0x5b, 0x60, 0x96, 0xc3, 0xd7, 0xae, 0xd8, 0xf8, 0x1e,
0x8e, 0x52, 0x35, 0xc5, 0x17, 0x93, 0x59, 0xce, 0xbd, 0x20, 0x14, 0xa5, 0xe0, 0x6f, 0xe3, 0x9f, 0x34, 0x0f, 0xd8, 0x44, 0xb8, 0x6c, 0x27, 0x0b, 0x8e, 0x7d, 0x1d, 0x16, 0x34, 0x8a, 0x52, 0x35,
0xe6, 0x80, 0x74, 0x82, 0xd0, 0x99, 0xda, 0x21, 0xdd, 0xa3, 0x8a, 0x67, 0xf6, 0xa1, 0xce, 0x72, 0xc5, 0x17, 0xe3, 0x59, 0xce, 0xbd, 0x20, 0x14, 0xb5, 0xe0, 0x6f, 0xe3, 0x9f, 0xe4, 0x80, 0x74,
0x1b, 0x7a, 0x6d, 0x2e, 0x28, 0x73, 0x81, 0xec, 0x5d, 0xc1, 0xe3, 0xd2, 0x09, 0xb6, 0x74, 0x6a, 0x82, 0xd0, 0x99, 0xda, 0x21, 0xdd, 0xa3, 0x8a, 0x66, 0xf6, 0xa1, 0xce, 0x4a, 0x1b, 0x7a, 0x6d,
0xbe, 0x4d, 0xc6, 0x32, 0x60, 0xd3, 0x2d, 0xb4, 0xfd, 0x33, 0x1a, 0xa2, 0x78, 0x2d, 0xe4, 0x42, 0xce, 0x42, 0x73, 0x86, 0xec, 0x7d, 0x41, 0xe3, 0xd2, 0x19, 0xb6, 0x74, 0x6c, 0x7e, 0x4c, 0xc6,
0xe0, 0x20, 0x26, 0x58, 0x6f, 0xfe, 0x2c, 0x2c, 0xa7, 0xf2, 0xd0, 0x37, 0xad, 0x6a, 0xc6, 0xa6, 0x0a, 0x60, 0xcb, 0x2d, 0xb4, 0xfd, 0x33, 0x1a, 0x22, 0xe3, 0x2d, 0x38, 0x46, 0xe0, 0x20, 0xc6,
0x55, 0xd0, 0x37, 0xad, 0x5f, 0xcb, 0xc1, 0x4a, 0xac, 0x62, 0x62, 0x19, 0x6e, 0x40, 0x99, 0xb1, 0x72, 0x6f, 0xfe, 0x2c, 0x2c, 0xa7, 0xca, 0xd0, 0x0f, 0xad, 0x6a, 0xc6, 0xa1, 0x55, 0xd0, 0x0f,
0x0b, 0x36, 0x79, 0x73, 0x5c, 0xdc, 0x3f, 0xa5, 0x38, 0xc1, 0x3f, 0x82, 0xd5, 0x53, 0x4a, 0x7d, 0xad, 0x5f, 0xcf, 0xc1, 0x4a, 0xac, 0x61, 0x62, 0x1b, 0x6e, 0x40, 0x99, 0x91, 0x0b, 0xb6, 0x78,
0x3b, 0x44, 0x24, 0xf2, 0x13, 0x36, 0x44, 0x3c, 0x67, 0xce, 0xf5, 0x05, 0x7e, 0x60, 0x87, 0x47, 0x73, 0x5c, 0x10, 0x38, 0xa5, 0xb8, 0xc0, 0x3f, 0x86, 0xd5, 0x53, 0x4a, 0x7d, 0x3b, 0xc4, 0x44,
0xd4, 0x67, 0xc3, 0x45, 0x0c, 0x68, 0x48, 0xe2, 0x0b, 0xa4, 0x2e, 0xe0, 0x24, 0xae, 0x05, 0x48, 0xa4, 0x27, 0x6c, 0x8a, 0x78, 0xc9, 0x9c, 0xea, 0x8b, 0xf4, 0x81, 0x1d, 0x1e, 0x51, 0x9f, 0x4d,
0xf2, 0x05, 0x03, 0x19, 0x7f, 0x94, 0x87, 0x25, 0xb6, 0x0f, 0x1d, 0xda, 0xee, 0x95, 0xec, 0xd0, 0x17, 0x31, 0xa0, 0x21, 0x91, 0x2f, 0x10, 0xbb, 0x80, 0x8b, 0xb8, 0x16, 0x20, 0xca, 0x53, 0x06,
0x83, 0xcc, 0x0e, 0xbd, 0xa7, 0x49, 0x1d, 0x1a, 0xf5, 0xd7, 0xed, 0xcd, 0x42, 0xb2, 0x37, 0xd3, 0x32, 0xfe, 0x38, 0x0f, 0x4b, 0xec, 0x1c, 0x3a, 0xb4, 0xdd, 0x2b, 0x39, 0xa0, 0x07, 0x99, 0x03,
0xd5, 0x2c, 0xa6, 0xaa, 0x49, 0xde, 0x82, 0x7a, 0xac, 0xdd, 0x25, 0xd5, 0x6e, 0x08, 0xa2, 0x06, 0x7a, 0x4f, 0xe3, 0x3a, 0x34, 0xec, 0xaf, 0x3b, 0x9a, 0x85, 0xe4, 0x68, 0xa6, 0x9b, 0x59, 0x4c,
0xab, 0x23, 0xc2, 0x82, 0x76, 0x44, 0x60, 0xac, 0x85, 0xad, 0x54, 0x56, 0x7a, 0x20, 0x24, 0x42, 0x35, 0x93, 0xbc, 0x03, 0xf5, 0x58, 0xbf, 0x4b, 0xaa, 0xdf, 0x10, 0x44, 0x1d, 0x56, 0xc2, 0xc3,
0xc6, 0xaf, 0x59, 0xd9, 0x01, 0x3b, 0x47, 0x05, 0x8c, 0x95, 0x59, 0x73, 0x57, 0x9c, 0xa5, 0xe8, 0x82, 0x26, 0x3c, 0x30, 0xd2, 0xc2, 0x76, 0x2a, 0xab, 0x3d, 0x10, 0x1c, 0x21, 0xa3, 0xd7, 0xac,
0x18, 0xf9, 0x41, 0xc5, 0x6c, 0x22, 0xe2, 0x38, 0x82, 0xff, 0xe9, 0xc7, 0xfd, 0x6d, 0x68, 0x46, 0xee, 0x80, 0x49, 0x58, 0x01, 0x23, 0x65, 0xd6, 0xdc, 0x15, 0x52, 0x16, 0x1d, 0x23, 0x3d, 0xa8,
0xdd, 0x27, 0xc6, 0x9c, 0x40, 0x91, 0xad, 0x21, 0x91, 0x01, 0xfe, 0x36, 0xfe, 0x5e, 0x9e, 0x13, 0x98, 0x4d, 0x4c, 0x38, 0x8e, 0xe0, 0x7f, 0xf6, 0x79, 0x7f, 0x17, 0x9a, 0xd1, 0xf0, 0x89, 0x39,
0xee, 0x78, 0x4e, 0x74, 0xa0, 0x21, 0x50, 0x44, 0x51, 0x4a, 0x10, 0xb2, 0xdf, 0xd7, 0x1e, 0x0f, 0x27, 0x50, 0x64, 0x7b, 0x48, 0x14, 0x80, 0xbf, 0x8d, 0xbf, 0x9b, 0xe7, 0x88, 0x3b, 0x9e, 0x13,
0x7f, 0x8a, 0x9d, 0x7e, 0x13, 0x2a, 0x01, 0xeb, 0x40, 0x7b, 0xc2, 0xfb, 0xbd, 0x62, 0x96, 0xd9, 0x89, 0x3a, 0x04, 0x8a, 0xc8, 0x4a, 0x09, 0x44, 0xf6, 0xfb, 0x5a, 0xc1, 0xf1, 0xa7, 0x38, 0xe8,
0x77, 0x7b, 0x32, 0x89, 0xc6, 0xa3, 0x7c, 0xed, 0x78, 0x54, 0x5e, 0x65, 0x3c, 0xaa, 0xd9, 0xe3, 0x37, 0xa1, 0x12, 0xb0, 0x01, 0xb4, 0x27, 0x7c, 0xdc, 0x2b, 0x66, 0x99, 0x7d, 0xb7, 0x27, 0x93,
0x61, 0xbc, 0x03, 0xcb, 0x5a, 0x2f, 0xbd, 0xa0, 0x3f, 0x7b, 0x40, 0x0e, 0x9c, 0x20, 0x3c, 0x76, 0x68, 0x3e, 0xca, 0xd7, 0xce, 0x47, 0xe5, 0x75, 0xe6, 0xa3, 0x9a, 0x3d, 0x1f, 0xc6, 0x7b, 0xb0,
0x59, 0x16, 0x4a, 0xa4, 0x89, 0x55, 0x24, 0x97, 0xa8, 0x08, 0x43, 0xda, 0x97, 0x02, 0x99, 0x17, 0xac, 0x8d, 0xd2, 0x4b, 0xc6, 0xf3, 0x1c, 0xc8, 0x81, 0x13, 0x84, 0xc7, 0x2e, 0x2b, 0x42, 0xb1,
0x48, 0xfb, 0x12, 0x91, 0xc6, 0x67, 0xb0, 0x12, 0xcb, 0x4f, 0x14, 0xfd, 0x06, 0x94, 0xe6, 0xe1, 0x34, 0xb1, 0x86, 0xe4, 0x12, 0x0d, 0x61, 0x89, 0xf6, 0xa5, 0x48, 0xcc, 0x8b, 0x44, 0xfb, 0x92,
0xa5, 0x27, 0xcf, 0x84, 0x35, 0xb1, 0x62, 0x8e, 0xc3, 0x4b, 0xcf, 0xe4, 0x18, 0xe3, 0x31, 0x2c, 0x27, 0x5e, 0x2f, 0x33, 0x7e, 0x0e, 0x2b, 0xb1, 0x9a, 0x44, 0xa3, 0xde, 0x82, 0xd2, 0x3c, 0xbc,
0xf7, 0xe8, 0x73, 0xc1, 0xfd, 0x64, 0x45, 0xde, 0x86, 0xe2, 0x4b, 0xb4, 0x1c, 0x88, 0x37, 0xb6, 0xf4, 0xa4, 0xb4, 0x58, 0x13, 0x7b, 0xe9, 0x38, 0xbc, 0xf4, 0x4c, 0x9e, 0x62, 0x1c, 0xc3, 0x72,
0x80, 0xe8, 0x89, 0x45, 0xa9, 0x9a, 0xd2, 0x23, 0x17, 0x53, 0x7a, 0x18, 0x6f, 0x03, 0x19, 0x38, 0x8f, 0xbe, 0x10, 0x74, 0x51, 0x36, 0xf1, 0x5d, 0x28, 0xbe, 0x42, 0x33, 0x82, 0xe9, 0x7a, 0x83,
0x67, 0xee, 0x21, 0x0d, 0x02, 0xfb, 0x4c, 0xf1, 0xcb, 0x26, 0x14, 0xa6, 0xc1, 0x99, 0x60, 0xee, 0xf2, 0xf1, 0x06, 0x6d, 0x01, 0xd1, 0x8b, 0x15, 0xed, 0xd1, 0x54, 0x28, 0xb9, 0x98, 0x0a, 0xc5,
0xec, 0xa7, 0xf1, 0x11, 0xac, 0xc4, 0xe8, 0x44, 0xc6, 0xaf, 0x41, 0x35, 0x70, 0xce, 0x5c, 0x94, 0x78, 0x17, 0xc8, 0xc0, 0x39, 0x73, 0x0f, 0x69, 0x10, 0xd8, 0x67, 0x8a, 0xc6, 0x36, 0xa1, 0x30,
0xe8, 0x45, 0xd6, 0x11, 0xc0, 0xd8, 0x83, 0xd5, 0x2f, 0xa8, 0xef, 0x9c, 0x5e, 0xbd, 0x2c, 0xfb, 0x0d, 0xce, 0xc4, 0x81, 0xc0, 0x7e, 0x1a, 0x1f, 0xc3, 0x4a, 0x0c, 0x4f, 0x14, 0xfc, 0x06, 0x54,
0x78, 0x3e, 0xf9, 0x64, 0x3e, 0x1d, 0x58, 0x4b, 0xe4, 0x23, 0x8a, 0xe7, 0xcb, 0x48, 0x8c, 0x64, 0x03, 0xe7, 0xcc, 0x45, 0x29, 0x40, 0x14, 0x1d, 0x01, 0x8c, 0x3d, 0x58, 0x7d, 0x4a, 0x7d, 0xe7,
0xc5, 0xe4, 0x1f, 0xda, 0x86, 0x91, 0xd7, 0x37, 0x0c, 0xc3, 0x03, 0xb2, 0xe3, 0xb9, 0x2e, 0x1d, 0xf4, 0xea, 0x55, 0xc5, 0xc7, 0xcb, 0xc9, 0x27, 0xcb, 0xe9, 0xc0, 0x5a, 0xa2, 0x1c, 0x51, 0x3d,
0x85, 0x47, 0x94, 0xfa, 0xb2, 0x32, 0xef, 0x6a, 0x6b, 0xa6, 0xf6, 0x70, 0x43, 0xf4, 0x6c, 0x72, 0xdf, 0x7a, 0x62, 0xf6, 0x2b, 0x26, 0xff, 0xd0, 0x0e, 0x99, 0xbc, 0x7e, 0xc8, 0x18, 0x1e, 0x90,
0x17, 0x12, 0x8b, 0x89, 0x40, 0x71, 0x46, 0xfd, 0x29, 0x66, 0x5c, 0x31, 0xf1, 0x37, 0xeb, 0xdc, 0x1d, 0xcf, 0x75, 0xe9, 0x28, 0x3c, 0xa2, 0xd4, 0x97, 0x8d, 0x79, 0x5f, 0xdb, 0x67, 0xb5, 0x87,
0xd0, 0x99, 0x52, 0x6f, 0x1e, 0x0a, 0xee, 0x29, 0x3f, 0x8d, 0x35, 0x58, 0x89, 0x15, 0xc8, 0x6b, 0x1b, 0x62, 0xcc, 0x93, 0x27, 0x97, 0xd8, 0x80, 0x04, 0x8a, 0x33, 0xea, 0x4f, 0xb1, 0xe0, 0x8a,
0x6d, 0x3c, 0x80, 0xb5, 0x5d, 0x27, 0x18, 0xa5, 0xab, 0xb2, 0x01, 0xe5, 0xd9, 0xfc, 0xc4, 0x8a, 0x89, 0xbf, 0xd9, 0xe0, 0x86, 0xce, 0x94, 0x7a, 0xf3, 0x50, 0x50, 0x5c, 0xf9, 0x69, 0xac, 0xc1,
0x6f, 0x75, 0x4f, 0xe9, 0x95, 0xd1, 0x82, 0xf5, 0x64, 0x0a, 0x91, 0xd7, 0xaf, 0xe6, 0xa1, 0xb8, 0x4a, 0xac, 0x42, 0xde, 0x6a, 0xe3, 0x01, 0xac, 0xed, 0x3a, 0xc1, 0x28, 0xdd, 0x94, 0x0d, 0x28,
0x3f, 0x3c, 0xd8, 0x21, 0x9b, 0x50, 0x71, 0xdc, 0x91, 0x37, 0x65, 0x82, 0x3e, 0xef, 0x0d, 0xf5, 0xcf, 0xe6, 0x27, 0x56, 0xfc, 0x78, 0x7c, 0x42, 0xaf, 0x8c, 0x16, 0xac, 0x27, 0x73, 0x88, 0xb2,
0x7d, 0x2d, 0x0b, 0xb8, 0x05, 0x55, 0x3c, 0x1f, 0x4c, 0xbc, 0xd1, 0x33, 0x21, 0x6a, 0x57, 0x18, 0x7e, 0x2d, 0x0f, 0xc5, 0xfd, 0xe1, 0xc1, 0x0e, 0xd9, 0x84, 0x8a, 0xe3, 0x8e, 0xbc, 0x29, 0x13,
0xe0, 0xc0, 0x1b, 0x3d, 0x63, 0xcb, 0x8c, 0x5e, 0xce, 0x1c, 0x1f, 0x15, 0x44, 0x52, 0x01, 0x52, 0x0e, 0xf8, 0x68, 0xa8, 0xef, 0x6b, 0xc9, 0xc6, 0x2d, 0xa8, 0xa2, 0x4c, 0x31, 0xf1, 0x46, 0xcf,
0xe4, 0xb2, 0x65, 0x84, 0x88, 0xd4, 0x24, 0x42, 0x0c, 0x62, 0x1b, 0x3b, 0x97, 0xb9, 0xab, 0xe7, 0x05, 0x7b, 0x5e, 0x61, 0x80, 0x03, 0x6f, 0xf4, 0x9c, 0x6d, 0x4d, 0x7a, 0x39, 0x73, 0x7c, 0x54,
0x28, 0x06, 0x8d, 0xe9, 0x25, 0x79, 0x1f, 0xc8, 0xa9, 0xe7, 0x3f, 0xb7, 0x7d, 0x25, 0x26, 0xba, 0x37, 0x49, 0x75, 0x4a, 0x91, 0xf3, 0xa3, 0x51, 0x42, 0xa4, 0x74, 0x11, 0xac, 0x13, 0x63, 0x06,
0x82, 0x05, 0x17, 0xcd, 0xe5, 0x08, 0x23, 0x44, 0x20, 0xf2, 0x10, 0xd6, 0x34, 0x72, 0x2d, 0x63, 0x38, 0x9f, 0x5e, 0x3d, 0x47, 0xd6, 0x69, 0x4c, 0x2f, 0xc9, 0x07, 0x40, 0x4e, 0x3d, 0xff, 0x85,
0x2e, 0xae, 0xad, 0x44, 0xc8, 0x7d, 0x59, 0x84, 0xf1, 0x2b, 0x79, 0x20, 0x22, 0xfd, 0x8e, 0xe7, 0xed, 0x2b, 0xd6, 0xd2, 0x15, 0x64, 0xbb, 0x68, 0x2e, 0x47, 0x29, 0x82, 0x6d, 0x22, 0x0f, 0x61,
0x06, 0xa1, 0x6f, 0x3b, 0x6e, 0x18, 0xc4, 0x85, 0xc6, 0x5c, 0x42, 0x68, 0xbc, 0x07, 0x4d, 0x14, 0x4d, 0x43, 0xd7, 0x0a, 0xe6, 0x2c, 0xde, 0x4a, 0x94, 0xb8, 0x2f, 0xab, 0x30, 0x7e, 0x35, 0x0f,
0x59, 0x75, 0xc9, 0x31, 0x1f, 0xc9, 0xef, 0x66, 0x24, 0x3d, 0xbe, 0x05, 0x8b, 0xd1, 0xb1, 0x41, 0x44, 0xe4, 0xdf, 0xf1, 0xdc, 0x20, 0xf4, 0x6d, 0xc7, 0x0d, 0x83, 0x38, 0xa3, 0x99, 0x4b, 0x30,
0xe9, 0x07, 0x8b, 0x66, 0x5d, 0x1d, 0x1d, 0x18, 0xd5, 0x07, 0xb0, 0xca, 0x18, 0x82, 0x14, 0x87, 0x9a, 0xf7, 0xa0, 0x89, 0x6c, 0xae, 0xce, 0x6d, 0xe6, 0x23, 0x9e, 0xdf, 0x8c, 0x38, 0xce, 0x77,
0x95, 0x1a, 0x84, 0x33, 0xce, 0xe5, 0xa9, 0x7d, 0x79, 0x44, 0xe5, 0x21, 0x05, 0xe5, 0x4c, 0x03, 0x60, 0x31, 0x12, 0x35, 0x94, 0xb6, 0xb1, 0x68, 0xd6, 0x95, 0xb8, 0xc1, 0xb0, 0x3e, 0x84, 0x55,
0x1a, 0x4a, 0x82, 0x44, 0x4a, 0xde, 0x73, 0x35, 0x21, 0x43, 0x22, 0x4d, 0xb6, 0x90, 0xbf, 0x90, 0x46, 0x44, 0x24, 0x0b, 0xad, 0x54, 0x27, 0x9c, 0xd8, 0x2e, 0x4f, 0xed, 0xcb, 0x23, 0x2a, 0x05,
0x2d, 0xe4, 0x1b, 0xff, 0xa6, 0x0a, 0x65, 0xd9, 0x8d, 0x28, 0xb1, 0x87, 0xce, 0x05, 0x8d, 0x24, 0x1b, 0xe4, 0x4d, 0x0d, 0x68, 0x28, 0xae, 0x13, 0x31, 0xf9, 0xc8, 0xd5, 0x04, 0xdf, 0x89, 0x38,
0x76, 0xf6, 0xc5, 0x0e, 0x02, 0x3e, 0x9d, 0x7a, 0xa1, 0x3a, 0xa9, 0xf1, 0x65, 0x52, 0xe7, 0x40, 0xd9, 0x82, 0xc1, 0x42, 0xb6, 0x60, 0x60, 0xfc, 0xeb, 0x2a, 0x94, 0xe5, 0x30, 0x22, 0x97, 0x1f,
0x71, 0x56, 0xd3, 0x4e, 0x0b, 0x5c, 0xad, 0xc9, 0xc5, 0x76, 0x79, 0x5a, 0xe0, 0xb2, 0xe0, 0x2d, 0x3a, 0x17, 0x34, 0xe2, 0xf2, 0xd9, 0x17, 0x13, 0x1e, 0x7c, 0x3a, 0xf5, 0x42, 0x25, 0xdd, 0xf1,
0x28, 0x4b, 0x99, 0xbf, 0xa8, 0xf4, 0x1d, 0x0b, 0x23, 0x2e, 0xf0, 0x6f, 0x42, 0x65, 0x64, 0xcf, 0x6d, 0x52, 0xe7, 0x40, 0x21, 0xdf, 0x69, 0x12, 0x06, 0x57, 0x92, 0x72, 0xca, 0x27, 0x25, 0x0c,
0xec, 0x91, 0x13, 0x72, 0x71, 0xbd, 0x60, 0xaa, 0x6f, 0x96, 0xfb, 0xc4, 0x1b, 0xd9, 0x13, 0xeb, 0xce, 0x3f, 0xde, 0x82, 0xb2, 0x94, 0x13, 0x8a, 0x4a, 0x47, 0xb2, 0x30, 0xe2, 0x42, 0xc2, 0x26,
0xc4, 0x9e, 0xd8, 0xee, 0x88, 0x0a, 0x7d, 0x61, 0x1d, 0x81, 0xdb, 0x1c, 0x46, 0xbe, 0x05, 0x8b, 0x54, 0x46, 0xf6, 0xcc, 0x1e, 0x39, 0x21, 0x67, 0xf1, 0x0b, 0xa6, 0xfa, 0x66, 0xa5, 0x4f, 0xbc,
0xa2, 0x9e, 0x92, 0x8a, 0xab, 0x0d, 0x45, 0xed, 0x25, 0x19, 0x3b, 0x55, 0x7a, 0x53, 0x36, 0x2e, 0x91, 0x3d, 0xb1, 0x4e, 0xec, 0x89, 0xed, 0x8e, 0xa8, 0xd0, 0x3e, 0xd6, 0x11, 0xb8, 0xcd, 0x61,
0xa7, 0x94, 0x9f, 0xbf, 0x0a, 0x66, 0x95, 0x43, 0xf6, 0x28, 0xb6, 0x56, 0xa0, 0x9f, 0xf3, 0x39, 0xe4, 0x5b, 0xb0, 0x28, 0xda, 0x29, 0xb1, 0xb8, 0x12, 0x52, 0xb4, 0x5e, 0xa2, 0x31, 0x49, 0xd4,
0x5c, 0xe5, 0x45, 0x71, 0xe0, 0x97, 0x7c, 0xfe, 0xa6, 0x0f, 0x61, 0x05, 0xed, 0x10, 0xf6, 0x2e, 0x9b, 0xb2, 0x79, 0x39, 0xa5, 0x5c, 0x66, 0x2b, 0x98, 0x55, 0x0e, 0xd9, 0xa3, 0xd8, 0x5b, 0x91,
0x2c, 0xcf, 0xdd, 0x80, 0x86, 0xe1, 0x84, 0x8e, 0x55, 0x5d, 0x6a, 0x48, 0xd4, 0x54, 0x08, 0x59, 0xfc, 0x82, 0xaf, 0xe1, 0x2a, 0xaf, 0x8a, 0x03, 0xbf, 0xe2, 0xeb, 0x37, 0x2d, 0xb8, 0x15, 0x34,
0x9d, 0x2d, 0x58, 0xe1, 0x8a, 0xce, 0xc0, 0x0e, 0xbd, 0xe0, 0xdc, 0x09, 0xac, 0x80, 0xba, 0x52, 0xc1, 0xed, 0x7d, 0x58, 0x9e, 0xbb, 0x01, 0x0d, 0xc3, 0x09, 0x1d, 0xab, 0xb6, 0xd4, 0x10, 0xa9,
0x15, 0xb6, 0x8c, 0xa8, 0x81, 0xc0, 0x0c, 0xb8, 0xfa, 0x64, 0x23, 0x41, 0xef, 0xd3, 0x11, 0x75, 0xa9, 0x12, 0x64, 0x73, 0xb6, 0x60, 0x85, 0xab, 0x4d, 0x03, 0x3b, 0xf4, 0x82, 0x73, 0x27, 0xb0,
0x2e, 0xe8, 0x18, 0x0f, 0x68, 0x05, 0x73, 0x2d, 0x96, 0xc6, 0x14, 0x48, 0x3c, 0x6d, 0xcf, 0xa7, 0x02, 0xea, 0x4a, 0xf5, 0xd9, 0x32, 0x26, 0x0d, 0x44, 0xca, 0x80, 0xab, 0x5c, 0x36, 0x12, 0xf8,
0xd6, 0x7c, 0x36, 0xb6, 0x99, 0x20, 0xbe, 0xc8, 0x4f, 0x3c, 0xee, 0x7c, 0x7a, 0xcc, 0x21, 0xe4, 0x3e, 0x1d, 0x51, 0xe7, 0x82, 0x8e, 0x51, 0xa8, 0x2b, 0x98, 0x6b, 0xb1, 0x3c, 0xa6, 0x48, 0x44,
0x01, 0xc8, 0x13, 0x98, 0x98, 0x33, 0x4b, 0xb1, 0x2d, 0x87, 0x71, 0x0d, 0xb3, 0x2e, 0x28, 0xf8, 0x09, 0x7d, 0x3e, 0xb5, 0xe6, 0xb3, 0xb1, 0xcd, 0x98, 0xf7, 0x45, 0x2e, 0x25, 0xb9, 0xf3, 0xe9,
0x09, 0xf1, 0x8e, 0xbe, 0x58, 0x9a, 0x6c, 0x86, 0xe1, 0x56, 0x1e, 0x2d, 0x98, 0x16, 0x94, 0x67, 0x31, 0x87, 0x90, 0x07, 0x20, 0xa5, 0x36, 0xb1, 0x66, 0x96, 0x62, 0x87, 0x11, 0xa3, 0x1a, 0x66,
0xbe, 0x73, 0x61, 0x87, 0xb4, 0xb5, 0xcc, 0xf7, 0x71, 0xf1, 0xc9, 0x18, 0xb8, 0xe3, 0x3a, 0xa1, 0x5d, 0x60, 0x70, 0xa9, 0xf2, 0x8e, 0xbe, 0x59, 0x9a, 0x6c, 0x85, 0xe1, 0xf1, 0x1f, 0x6d, 0x98,
0x63, 0x87, 0x9e, 0xdf, 0x22, 0x88, 0x8b, 0x00, 0xe4, 0x3e, 0x2c, 0xe3, 0x3c, 0x09, 0x42, 0x3b, 0x16, 0x94, 0x67, 0xbe, 0x73, 0x61, 0x87, 0xb4, 0xb5, 0xcc, 0xcf, 0x7e, 0xf1, 0xc9, 0x08, 0xb8,
0x9c, 0x07, 0xe2, 0xf8, 0xb9, 0xc2, 0x8f, 0x79, 0x0c, 0x31, 0x40, 0x38, 0x9e, 0x40, 0xc9, 0xa7, 0xe3, 0x3a, 0xa1, 0x63, 0x87, 0x9e, 0xdf, 0x22, 0x98, 0x16, 0x01, 0xc8, 0x7d, 0x58, 0xc6, 0x75,
0xb0, 0xce, 0xa7, 0x46, 0x6a, 0x69, 0xae, 0x2a, 0xe1, 0x62, 0x05, 0x29, 0x76, 0xe2, 0x6b, 0xf4, 0x12, 0x84, 0x76, 0x38, 0x0f, 0x84, 0xc8, 0xba, 0xc2, 0x45, 0x43, 0x96, 0x30, 0x40, 0x38, 0x4a,
0x73, 0xd8, 0x10, 0xd3, 0x25, 0x95, 0x72, 0x4d, 0xa5, 0x5c, 0xe5, 0x24, 0x89, 0xa4, 0x5b, 0xb0, 0xad, 0xe4, 0x33, 0x58, 0xe7, 0x4b, 0x23, 0xb5, 0x35, 0x57, 0x15, 0x43, 0xb2, 0x82, 0x18, 0x3b,
0xcc, 0xaa, 0xe6, 0x8c, 0x2c, 0x91, 0x03, 0x5b, 0x15, 0xeb, 0xac, 0x15, 0x98, 0x68, 0x89, 0x23, 0xf1, 0x3d, 0xfa, 0x05, 0x6c, 0x88, 0xe5, 0x92, 0xca, 0xb9, 0xa6, 0x72, 0xae, 0x72, 0x94, 0x44,
0x4d, 0xc4, 0x3d, 0xa5, 0x57, 0xe4, 0xbb, 0xb0, 0xc4, 0xa7, 0x0f, 0xea, 0x58, 0x70, 0x63, 0xde, 0xd6, 0x2d, 0x58, 0x66, 0x4d, 0x73, 0x46, 0x96, 0x28, 0x81, 0xed, 0x8a, 0x75, 0xd6, 0x0b, 0xcc,
0xc4, 0x8d, 0x79, 0x4d, 0x74, 0xee, 0x8e, 0xc2, 0xe2, 0xde, 0xbc, 0x38, 0x8a, 0x7d, 0xb3, 0xa5, 0xb4, 0xc4, 0x13, 0x4d, 0x4c, 0x7b, 0x42, 0xaf, 0xc8, 0xf7, 0x60, 0x89, 0x2f, 0x1f, 0xd4, 0xcb,
0x31, 0x71, 0x4e, 0x29, 0xdb, 0x27, 0x5a, 0x1b, 0x7c, 0xb2, 0xc9, 0x6f, 0xb6, 0x6a, 0xe7, 0x33, 0xe0, 0x91, 0xbd, 0x89, 0x47, 0xf6, 0x9a, 0x18, 0xdc, 0x1d, 0x95, 0x8a, 0xa7, 0xf6, 0xe2, 0x28,
0xc4, 0xb4, 0x38, 0xb3, 0xe6, 0x5f, 0x38, 0x8f, 0x27, 0x5e, 0x40, 0xa5, 0x8a, 0xbc, 0x75, 0x53, 0xf6, 0xcd, 0xb6, 0xc6, 0xc4, 0x39, 0xa5, 0xec, 0x9c, 0x68, 0x6d, 0xf0, 0xc5, 0x26, 0xbf, 0xd9,
0x2c, 0x48, 0x06, 0x94, 0x67, 0x25, 0x76, 0x18, 0xe7, 0x9a, 0x0f, 0x65, 0xc8, 0xb8, 0x85, 0x13, 0xae, 0x9d, 0xcf, 0x30, 0xa5, 0xc5, 0x89, 0x35, 0xff, 0xc2, 0x75, 0x3c, 0xf1, 0x02, 0x2a, 0x15,
0xa3, 0xc1, 0x15, 0x20, 0xd2, 0x98, 0xc1, 0x84, 0xbf, 0x73, 0xfb, 0xb9, 0x64, 0xeb, 0xaf, 0x21, 0xee, 0xad, 0x9b, 0x62, 0x43, 0x32, 0xa0, 0x94, 0xaf, 0x98, 0x00, 0xcf, 0xb5, 0x25, 0xca, 0x2c,
0x37, 0x01, 0x06, 0x12, 0x0c, 0x7d, 0x0f, 0x96, 0xc5, 0x28, 0x44, 0xcc, 0xb4, 0x75, 0x1b, 0xb7, 0x72, 0x0b, 0x17, 0x46, 0x83, 0x2b, 0x4d, 0xa4, 0x69, 0x84, 0x31, 0x8c, 0xe7, 0xf6, 0x0b, 0x49,
0xc8, 0x9b, 0xb2, 0x8d, 0x29, 0x6e, 0x6b, 0x36, 0xf9, 0xb8, 0x68, 0xfc, 0x77, 0x1f, 0x88, 0x1c, 0xd6, 0xdf, 0x40, 0x6a, 0x02, 0x0c, 0x24, 0x08, 0xfa, 0x1e, 0x2c, 0x8b, 0x59, 0x88, 0x88, 0x69,
0x14, 0x2d, 0xa3, 0xd7, 0x5f, 0x96, 0xd1, 0xb2, 0x18, 0xa6, 0x08, 0x64, 0xfc, 0x6e, 0x8e, 0x4b, 0xeb, 0x36, 0x1e, 0x91, 0x37, 0x65, 0x1f, 0x53, 0xd4, 0xd6, 0x6c, 0xf2, 0x79, 0xd1, 0xe8, 0xef,
0x54, 0x82, 0x3a, 0xd0, 0xb4, 0x4e, 0x9c, 0xaf, 0x59, 0x9e, 0x3b, 0xb9, 0x12, 0xac, 0x0e, 0x38, 0x3e, 0x10, 0x39, 0x29, 0x5a, 0x41, 0x6f, 0xbe, 0xaa, 0xa0, 0x65, 0x31, 0x4d, 0x11, 0xc8, 0xf8,
0xa8, 0xef, 0x4e, 0x90, 0xd7, 0x38, 0xae, 0x4e, 0xc2, 0x37, 0xef, 0xba, 0x04, 0x22, 0xd1, 0x1d, 0xbd, 0x1c, 0xe7, 0xb5, 0x04, 0x76, 0xa0, 0x69, 0xaa, 0x38, 0x5d, 0xb3, 0x3c, 0x77, 0x72, 0x25,
0xa8, 0xcd, 0xe6, 0x27, 0x13, 0x67, 0xc4, 0x49, 0x0a, 0x3c, 0x17, 0x0e, 0x42, 0x82, 0x37, 0xa0, 0x48, 0x1d, 0x70, 0x50, 0xdf, 0x9d, 0x20, 0xad, 0x71, 0x5c, 0x1d, 0x85, 0x1f, 0xde, 0x75, 0x09,
0x2e, 0xe6, 0x3a, 0xa7, 0x28, 0x22, 0x45, 0x4d, 0xc0, 0x90, 0x04, 0x85, 0x03, 0xea, 0x23, 0xb3, 0x44, 0xa4, 0x3b, 0x50, 0x9b, 0xcd, 0x4f, 0x26, 0xce, 0x88, 0xa3, 0x14, 0x78, 0x29, 0x1c, 0x84,
0xab, 0x9b, 0xf8, 0xdb, 0xd8, 0x86, 0xd5, 0x78, 0xa5, 0x85, 0xe4, 0x72, 0x1f, 0x2a, 0x82, 0x93, 0x08, 0x6f, 0x41, 0x5d, 0xac, 0x75, 0x8e, 0x51, 0x44, 0x8c, 0x9a, 0x80, 0x21, 0x0a, 0x32, 0x07,
0x4a, 0x95, 0xed, 0x62, 0xbc, 0x37, 0x4c, 0x85, 0x37, 0xfe, 0x6d, 0x09, 0x56, 0x64, 0x1f, 0xb1, 0xd4, 0x47, 0x62, 0x57, 0x37, 0xf1, 0xb7, 0xb1, 0x0d, 0xab, 0xf1, 0x46, 0x0b, 0xce, 0xe5, 0x3e,
0xc1, 0x1e, 0xcc, 0xa7, 0x53, 0xdb, 0xcf, 0x60, 0xd1, 0xb9, 0x17, 0xb3, 0xe8, 0x7c, 0x8a, 0x45, 0x54, 0x04, 0x25, 0x95, 0x6a, 0xde, 0xc5, 0xf8, 0x68, 0x98, 0x2a, 0xdd, 0xf8, 0x37, 0x25, 0x58,
0xc7, 0x15, 0x72, 0x9c, 0xc3, 0xc7, 0x15, 0x72, 0x6c, 0x76, 0x71, 0x35, 0x80, 0x6e, 0x19, 0x6a, 0x91, 0x63, 0xc4, 0x26, 0x7b, 0x30, 0x9f, 0x4e, 0x6d, 0x3f, 0x83, 0x44, 0xe7, 0x5e, 0x4e, 0xa2,
0x08, 0xf0, 0x90, 0x5b, 0xa0, 0x52, 0x1b, 0x4a, 0x29, 0x63, 0x43, 0xd1, 0xb7, 0x83, 0x85, 0xc4, 0xf3, 0x29, 0x12, 0x1d, 0x57, 0xe2, 0x71, 0x0a, 0x1f, 0x57, 0xe2, 0xb1, 0xd5, 0xc5, 0x55, 0x07,
0x76, 0xf0, 0x06, 0xf0, 0x69, 0x2c, 0xe7, 0x63, 0x99, 0x6b, 0x06, 0x10, 0x26, 0x26, 0xe4, 0x3b, 0xba, 0x9d, 0xa9, 0x21, 0xc0, 0x43, 0x6e, 0xcf, 0x4a, 0x1d, 0x28, 0xa5, 0x8c, 0x03, 0x45, 0x3f,
0xb0, 0x94, 0xe4, 0xc0, 0x9c, 0xd5, 0x2f, 0x66, 0xf0, 0x5f, 0x67, 0x4a, 0x51, 0xa8, 0xd1, 0x88, 0x0e, 0x16, 0x12, 0xc7, 0xc1, 0x5b, 0xc0, 0x97, 0xb1, 0x5c, 0x8f, 0x65, 0xae, 0x4d, 0x40, 0x98,
0xab, 0x82, 0xff, 0x3a, 0x53, 0x7a, 0x80, 0x18, 0x49, 0xdf, 0x01, 0xe0, 0x65, 0xe3, 0x32, 0x06, 0x58, 0x90, 0xef, 0xc1, 0x52, 0x92, 0x02, 0x73, 0x52, 0xbf, 0x98, 0x41, 0x7f, 0x9d, 0x29, 0x45,
0x5c, 0xc6, 0x6f, 0x27, 0x66, 0xa6, 0xd6, 0xeb, 0x5b, 0xec, 0x63, 0xee, 0x53, 0x5c, 0xd7, 0x55, 0xa6, 0x46, 0x43, 0xae, 0x0a, 0xfa, 0xeb, 0x4c, 0xe9, 0x01, 0xa6, 0x48, 0xfc, 0x0e, 0x00, 0xaf,
0x4c, 0x89, 0x4b, 0xfa, 0x53, 0x58, 0xf4, 0x66, 0xd4, 0xb5, 0x22, 0x2e, 0x58, 0xc3, 0xac, 0x9a, 0x1b, 0xb7, 0x31, 0xe0, 0x36, 0x7e, 0x37, 0xb1, 0x32, 0xb5, 0x51, 0xdf, 0x62, 0x1f, 0x73, 0x9f,
0x22, 0xab, 0xae, 0x84, 0x9b, 0x0d, 0x46, 0xa7, 0x3e, 0xc9, 0xe7, 0xbc, 0x93, 0xa9, 0x96, 0xb2, 0xe2, 0xbe, 0xae, 0x62, 0x4e, 0xdc, 0xd2, 0x9f, 0xc1, 0xa2, 0x37, 0xa3, 0xae, 0x15, 0x51, 0xc1,
0x7e, 0x4d, 0xca, 0x45, 0x24, 0x8c, 0x92, 0x7e, 0x84, 0x4a, 0x2f, 0x6f, 0x32, 0xe7, 0x66, 0xa6, 0x1a, 0x16, 0xd5, 0x14, 0x45, 0x75, 0x25, 0xdc, 0x6c, 0x30, 0x3c, 0xf5, 0x49, 0xbe, 0xe0, 0x83,
0x06, 0xce, 0x23, 0xa9, 0x77, 0x37, 0x15, 0xc6, 0xd4, 0xa9, 0x8c, 0x5f, 0xcf, 0x41, 0x4d, 0x6b, 0x4c, 0xb5, 0x9c, 0xf5, 0x6b, 0x72, 0x2e, 0x22, 0x62, 0x94, 0xf5, 0x63, 0x54, 0x94, 0x79, 0x93,
0x03, 0x59, 0x83, 0xe5, 0x9d, 0x7e, 0xff, 0xa8, 0x63, 0xb6, 0x87, 0xdd, 0x2f, 0x3a, 0xd6, 0xce, 0x39, 0x37, 0x4d, 0x35, 0x70, 0x1d, 0x49, 0x5d, 0xbd, 0xa9, 0x52, 0x4c, 0x1d, 0xcb, 0xf8, 0x8d,
0x41, 0x7f, 0xd0, 0x69, 0xde, 0x60, 0xe0, 0x83, 0xfe, 0x4e, 0xfb, 0xc0, 0xda, 0xeb, 0x9b, 0x3b, 0x1c, 0xd4, 0xb4, 0x3e, 0x90, 0x35, 0x58, 0xde, 0xe9, 0xf7, 0x8f, 0x3a, 0x66, 0x7b, 0xd8, 0x7d,
0x12, 0x9c, 0x23, 0xeb, 0x40, 0xcc, 0xce, 0x61, 0x7f, 0xd8, 0x89, 0xc1, 0xf3, 0xa4, 0x09, 0xf5, 0xda, 0xb1, 0x76, 0x0e, 0xfa, 0x83, 0x4e, 0xf3, 0x06, 0x03, 0x1f, 0xf4, 0x77, 0xda, 0x07, 0xd6,
0x6d, 0xb3, 0xd3, 0xde, 0xd9, 0x17, 0x90, 0x02, 0x59, 0x85, 0xe6, 0xde, 0x71, 0x6f, 0xb7, 0xdb, 0x5e, 0xdf, 0xdc, 0x91, 0xe0, 0x1c, 0x59, 0x07, 0x62, 0x76, 0x0e, 0xfb, 0xc3, 0x4e, 0x0c, 0x9e,
0x7b, 0x62, 0xed, 0xb4, 0x7b, 0x3b, 0x9d, 0x83, 0xce, 0x6e, 0xb3, 0x48, 0x1a, 0x50, 0x6d, 0x6f, 0x27, 0x4d, 0xa8, 0x6f, 0x9b, 0x9d, 0xf6, 0xce, 0xbe, 0x80, 0x14, 0xc8, 0x2a, 0x34, 0xf7, 0x8e,
0xb7, 0x7b, 0xbb, 0xfd, 0x5e, 0x67, 0xb7, 0x59, 0x32, 0xfe, 0x28, 0x07, 0x10, 0x55, 0x94, 0xf1, 0x7b, 0xbb, 0xdd, 0xde, 0x63, 0x6b, 0xa7, 0xdd, 0xdb, 0xe9, 0x1c, 0x74, 0x76, 0x9b, 0x45, 0xd2,
0xd5, 0xa8, 0xaa, 0xba, 0x59, 0x77, 0x2d, 0xd5, 0x28, 0xce, 0x57, 0xfd, 0xd8, 0x37, 0x79, 0x08, 0x80, 0x6a, 0x7b, 0xbb, 0xdd, 0xdb, 0xed, 0xf7, 0x3a, 0xbb, 0xcd, 0x92, 0xf1, 0xc7, 0x39, 0x80,
0x65, 0x6f, 0x1e, 0x8e, 0xbc, 0x29, 0x3f, 0x44, 0x2c, 0x3e, 0x6c, 0xa5, 0xd2, 0xf5, 0x39, 0xde, 0xa8, 0xa1, 0x8c, 0xae, 0x46, 0x4d, 0xd5, 0x8d, 0xc4, 0x6b, 0xa9, 0x4e, 0x71, 0xba, 0xea, 0xc7,
0x94, 0x84, 0x31, 0xd3, 0x6d, 0xe1, 0x65, 0xa6, 0xdb, 0xb8, 0x8d, 0x98, 0xcb, 0x75, 0x9a, 0x8d, 0xbe, 0xc9, 0x43, 0x28, 0x7b, 0xf3, 0x70, 0xe4, 0x4d, 0xb9, 0x10, 0xb1, 0xf8, 0xb0, 0x95, 0xca,
0xf8, 0x36, 0x40, 0xf0, 0x9c, 0xd2, 0x19, 0x6a, 0xcd, 0xc4, 0x2a, 0xa8, 0x22, 0x64, 0xc8, 0xce, 0xd7, 0xe7, 0xe9, 0xa6, 0x44, 0x8c, 0x19, 0x82, 0x0b, 0xaf, 0x32, 0x04, 0xc7, 0x2d, 0xce, 0x9c,
0x98, 0xff, 0x31, 0x07, 0x6b, 0x38, 0x97, 0xc6, 0x49, 0x26, 0x76, 0x17, 0x6a, 0x23, 0xcf, 0x9b, 0xaf, 0xd3, 0x2c, 0xce, 0xb7, 0x01, 0x82, 0x17, 0x94, 0xce, 0x50, 0xd3, 0x26, 0x76, 0x41, 0x15,
0x51, 0x26, 0x54, 0x2b, 0x79, 0x4d, 0x07, 0x31, 0x06, 0xc5, 0x19, 0xf2, 0xa9, 0xe7, 0x8f, 0xa8, 0x21, 0x43, 0x26, 0x97, 0xfe, 0x87, 0x1c, 0xac, 0xe1, 0x5a, 0x1a, 0x27, 0x89, 0xd8, 0x5d, 0xa8,
0xe0, 0x61, 0x80, 0xa0, 0x3d, 0x06, 0x61, 0x6b, 0x48, 0x2c, 0x42, 0x4e, 0xc1, 0x59, 0x58, 0x8d, 0x8d, 0x3c, 0x6f, 0x46, 0x19, 0x53, 0xad, 0xf8, 0x35, 0x1d, 0xc4, 0x08, 0x14, 0x27, 0xc8, 0xa7,
0xc3, 0x38, 0xc9, 0x3a, 0x2c, 0x9c, 0xf8, 0xd4, 0x1e, 0x9d, 0x0b, 0xee, 0x25, 0xbe, 0xc8, 0xb7, 0x9e, 0x3f, 0xa2, 0x82, 0x86, 0x01, 0x82, 0xf6, 0x18, 0x84, 0xed, 0x21, 0xb1, 0x09, 0x39, 0x06,
0x23, 0xed, 0xe1, 0x88, 0xad, 0x89, 0x09, 0xe5, 0x95, 0xaf, 0x98, 0x4b, 0x02, 0xbe, 0x23, 0xc0, 0x27, 0x61, 0x35, 0x0e, 0xe3, 0x28, 0xeb, 0xb0, 0x70, 0xe2, 0x53, 0x7b, 0x74, 0x2e, 0xa8, 0x97,
0x6c, 0x9f, 0xb7, 0x4f, 0x6c, 0x77, 0xec, 0xb9, 0x74, 0x2c, 0xce, 0xf2, 0x11, 0xc0, 0x38, 0x82, 0xf8, 0x22, 0xdf, 0x8e, 0x34, 0x8e, 0x23, 0xb6, 0x27, 0x26, 0x94, 0x37, 0xbe, 0x62, 0x2e, 0x09,
0xf5, 0x64, 0xfb, 0x04, 0xbf, 0xfb, 0x44, 0xe3, 0x77, 0xfc, 0xe8, 0xbb, 0x79, 0xfd, 0x1a, 0xd3, 0xf8, 0x8e, 0x00, 0xb3, 0x73, 0xde, 0x3e, 0xb1, 0xdd, 0xb1, 0xe7, 0xd2, 0xb1, 0x90, 0xff, 0x23,
0x78, 0xdf, 0x7f, 0x2a, 0x42, 0x91, 0x1d, 0x78, 0xae, 0x3d, 0x1b, 0xe9, 0x67, 0xdb, 0x42, 0xca, 0x80, 0x71, 0x04, 0xeb, 0xc9, 0xfe, 0x09, 0x7a, 0xf7, 0xa9, 0x46, 0xef, 0xb8, 0x50, 0xbc, 0x79,
0xa0, 0x8f, 0x4a, 0x4a, 0x2e, 0x80, 0x89, 0xc1, 0x42, 0x08, 0x0a, 0x5e, 0x0a, 0xed, 0xd3, 0xd1, 0xfd, 0x1e, 0xd3, 0x68, 0xdf, 0x7f, 0x2c, 0x42, 0x91, 0x09, 0x3c, 0xd7, 0xca, 0x46, 0xba, 0x6c,
0x85, 0x3c, 0xb3, 0x20, 0xc4, 0xa4, 0xa3, 0x0b, 0x54, 0x5a, 0xd8, 0x21, 0x4f, 0xcb, 0xf9, 0x55, 0x5b, 0x48, 0xb9, 0x07, 0xa0, 0x62, 0x93, 0x33, 0x60, 0x62, 0xb2, 0x10, 0x82, 0x8c, 0x97, 0x4a,
0x39, 0xb0, 0x43, 0x4c, 0x29, 0x50, 0x98, 0xae, 0xac, 0x50, 0x98, 0xaa, 0x05, 0x65, 0xc7, 0x3d, 0xf6, 0xe9, 0xe8, 0x42, 0xca, 0x2c, 0x08, 0x31, 0xe9, 0xe8, 0x02, 0x15, 0x1d, 0x76, 0xc8, 0xf3,
0xf1, 0xe6, 0xae, 0x54, 0x11, 0xc9, 0x4f, 0xf4, 0x1f, 0x40, 0x4e, 0xca, 0xb6, 0x76, 0xce, 0x8d, 0x72, 0x7a, 0x55, 0x0e, 0xec, 0x10, 0x73, 0x8a, 0x24, 0xcc, 0x57, 0x56, 0x49, 0x98, 0xab, 0x05,
0x2a, 0x0c, 0x30, 0x64, 0x9b, 0xfb, 0x87, 0x50, 0x0d, 0xae, 0xdc, 0x91, 0xce, 0x83, 0x56, 0x45, 0x65, 0xc7, 0x3d, 0xf1, 0xe6, 0xae, 0x54, 0x2b, 0xc9, 0x4f, 0xf4, 0x46, 0x40, 0x4a, 0xca, 0x8e,
0xff, 0xb0, 0xd6, 0x6f, 0x0d, 0xae, 0xdc, 0x11, 0xce, 0xf8, 0x4a, 0x20, 0x7e, 0x91, 0x47, 0x50, 0x76, 0x4e, 0x8d, 0x2a, 0x0c, 0x30, 0x64, 0x87, 0xfb, 0x47, 0x50, 0x0d, 0xae, 0xdc, 0x91, 0x4e,
0x51, 0x16, 0x37, 0xbe, 0x83, 0xdc, 0xd4, 0x53, 0x48, 0x33, 0x1b, 0xd7, 0xb7, 0x29, 0x52, 0xf2, 0x83, 0x56, 0xc5, 0xf8, 0xb0, 0xde, 0x6f, 0x0d, 0xae, 0xdc, 0x11, 0xae, 0xf8, 0x4a, 0x20, 0x7e,
0x01, 0x2c, 0xa0, 0xe6, 0x3d, 0x68, 0xd5, 0x31, 0x91, 0x3c, 0xf0, 0xb2, 0x6a, 0xa0, 0xe9, 0x9e, 0x91, 0x47, 0x50, 0x51, 0x56, 0x3a, 0x7e, 0x82, 0xdc, 0xd4, 0x73, 0x48, 0xd3, 0x1c, 0xd7, 0xd1,
0x8e, 0xd1, 0xfe, 0x65, 0x0a, 0x32, 0xd6, 0x4d, 0xa7, 0x13, 0x7b, 0x26, 0xf4, 0xe0, 0x0d, 0x6e, 0x29, 0x54, 0xf2, 0x21, 0x2c, 0xa0, 0xb6, 0x3e, 0x68, 0xd5, 0x31, 0x93, 0x14, 0x78, 0x59, 0x33,
0x01, 0x67, 0x10, 0xae, 0x04, 0xbf, 0x0b, 0x75, 0xb4, 0x66, 0x22, 0x8d, 0xcb, 0xe5, 0xd0, 0x82, 0xd0, 0x11, 0x80, 0x8e, 0xd1, 0x66, 0x66, 0x0a, 0x34, 0x36, 0x4c, 0xa7, 0x13, 0x7b, 0x26, 0x74,
0x09, 0x0c, 0xb6, 0x37, 0xb1, 0x67, 0xbd, 0x60, 0xf3, 0x29, 0x34, 0x62, 0x95, 0xd1, 0xd5, 0x61, 0xe7, 0x0d, 0x6e, 0x4f, 0x67, 0x10, 0xae, 0x38, 0xbf, 0x0b, 0x75, 0xb4, 0x80, 0x22, 0x8e, 0xcb,
0x0d, 0xae, 0x0e, 0x7b, 0x4b, 0x57, 0x87, 0x45, 0x5b, 0xa1, 0x48, 0xa6, 0xab, 0xc7, 0x8e, 0xa0, 0xf9, 0xd0, 0x82, 0x09, 0x0c, 0xb6, 0x37, 0xb1, 0x67, 0xbd, 0x60, 0xf3, 0x09, 0x34, 0x62, 0x8d,
0x22, 0xfb, 0x82, 0xf1, 0x9c, 0xe3, 0xde, 0xd3, 0x5e, 0xff, 0xcb, 0x9e, 0x35, 0xf8, 0xaa, 0xb7, 0xd1, 0x55, 0x68, 0x0d, 0xae, 0x42, 0x7b, 0x47, 0x57, 0xa1, 0x45, 0x47, 0xa1, 0xc8, 0xa6, 0xab,
0xd3, 0xbc, 0x41, 0x96, 0xa0, 0xd6, 0xde, 0x41, 0x36, 0x86, 0x80, 0x1c, 0x23, 0x39, 0x6a, 0x0f, 0xd4, 0x8e, 0xa0, 0x22, 0xc7, 0x82, 0xd1, 0x9c, 0xe3, 0xde, 0x93, 0x5e, 0xff, 0xab, 0x9e, 0x35,
0x06, 0x0a, 0x92, 0x67, 0x24, 0x47, 0xdd, 0x5e, 0xaf, 0xb3, 0xcb, 0x01, 0x05, 0x63, 0x0f, 0x9a, 0x78, 0xd6, 0xdb, 0x69, 0xde, 0x20, 0x4b, 0x50, 0x6b, 0xef, 0x20, 0x19, 0x43, 0x40, 0x8e, 0xa1,
0xc9, 0xb6, 0xb3, 0x59, 0x1e, 0x4a, 0x98, 0xb0, 0x31, 0x46, 0x80, 0xc8, 0x92, 0x91, 0xd7, 0x2c, 0x1c, 0xb5, 0x07, 0x03, 0x05, 0xc9, 0x33, 0x94, 0xa3, 0x6e, 0xaf, 0xd7, 0xd9, 0xe5, 0x80, 0x82,
0x19, 0xc6, 0x23, 0x68, 0xb2, 0x9d, 0x9e, 0x75, 0xbe, 0xee, 0x60, 0x30, 0x61, 0xb2, 0xb8, 0x6e, 0xb1, 0x07, 0xcd, 0x64, 0xdf, 0xd9, 0x2a, 0x0f, 0x25, 0x4c, 0xd8, 0x25, 0x23, 0x40, 0x64, 0xfd,
0x67, 0xac, 0x98, 0x35, 0x0e, 0xc3, 0xa2, 0x8c, 0x4f, 0x60, 0x59, 0x4b, 0x16, 0x69, 0x89, 0x98, 0xc8, 0x6b, 0xd6, 0x0f, 0xe3, 0x11, 0x34, 0xd9, 0x49, 0xcf, 0x06, 0x5f, 0x77, 0x57, 0x98, 0x30,
0xf4, 0x90, 0xd4, 0x12, 0xe1, 0xc9, 0x9f, 0x63, 0x8c, 0x0d, 0x58, 0x63, 0x9f, 0x9d, 0x0b, 0xea, 0x5e, 0x5c, 0xb7, 0x4d, 0x56, 0xcc, 0x1a, 0x87, 0x61, 0x55, 0xc6, 0xa7, 0xb0, 0xac, 0x65, 0x8b,
0x86, 0x83, 0xf9, 0x09, 0xf7, 0x4b, 0x71, 0x3c, 0xd7, 0xf8, 0x95, 0x1c, 0x54, 0x15, 0xe6, 0xfa, 0xf4, 0x47, 0x8c, 0x7b, 0x48, 0xea, 0x8f, 0x50, 0xf2, 0xe7, 0x29, 0xc6, 0x06, 0xac, 0xb1, 0xcf,
0x65, 0xb3, 0x25, 0x14, 0x4a, 0x9c, 0x4f, 0x6e, 0x6a, 0x25, 0x60, 0xc2, 0x2d, 0xfc, 0x1b, 0x53, 0xce, 0x05, 0x75, 0xc3, 0xc1, 0xfc, 0x84, 0x7b, 0xb9, 0x38, 0x9e, 0x6b, 0xfc, 0x6a, 0x0e, 0xaa,
0x2c, 0x55, 0x15, 0x08, 0x3b, 0xb1, 0xd3, 0x31, 0xad, 0x7e, 0xef, 0xa0, 0xdb, 0x63, 0xbb, 0x05, 0x2a, 0xe5, 0xfa, 0x6d, 0xb3, 0x25, 0x54, 0x4d, 0x9c, 0x4e, 0x6e, 0x6a, 0x35, 0x60, 0xc6, 0x2d,
0xeb, 0x67, 0x04, 0xec, 0xed, 0x21, 0x24, 0x67, 0x34, 0x61, 0xf1, 0x09, 0x0d, 0xbb, 0xee, 0xa9, 0xfc, 0x1b, 0xa9, 0x9c, 0x8c, 0x2d, 0xa8, 0x2a, 0x10, 0x0e, 0x62, 0xa7, 0x63, 0x5a, 0xfd, 0xde,
0x27, 0x3a, 0xc3, 0xf8, 0xb5, 0x05, 0x58, 0x52, 0xa0, 0x48, 0x31, 0x75, 0x41, 0xfd, 0xc0, 0xf1, 0x41, 0xb7, 0xc7, 0x4e, 0x0b, 0x36, 0xce, 0x08, 0xd8, 0xdb, 0x43, 0x48, 0xce, 0x68, 0xc2, 0xe2,
0x5c, 0x9c, 0x38, 0x55, 0x53, 0x7e, 0x32, 0x7e, 0x27, 0x8e, 0x6d, 0x28, 0x77, 0xac, 0x22, 0x56, 0x63, 0x1a, 0x76, 0xdd, 0x53, 0x4f, 0x0c, 0x86, 0xf1, 0xeb, 0x0b, 0xb0, 0xa4, 0x40, 0x91, 0x62,
0x1c, 0xf4, 0x50, 0xe8, 0x78, 0x07, 0x96, 0x9c, 0x31, 0x75, 0x43, 0x27, 0xbc, 0xb2, 0x62, 0xf6, 0xea, 0x82, 0xfa, 0x81, 0xe3, 0xb9, 0xb8, 0x70, 0xaa, 0xa6, 0xfc, 0x64, 0xf4, 0x4e, 0x88, 0x6d,
0x81, 0x45, 0x09, 0x16, 0x82, 0xc7, 0x2a, 0x94, 0xec, 0x89, 0x63, 0x4b, 0x7f, 0x1f, 0xfe, 0xc1, 0xc8, 0x77, 0xac, 0x62, 0xaa, 0x10, 0xf4, 0x90, 0xe9, 0x78, 0x0f, 0x96, 0x9c, 0x31, 0x75, 0x43,
0xa0, 0x23, 0x6f, 0xe2, 0xf9, 0x78, 0x90, 0xa9, 0x9a, 0xfc, 0x83, 0x3c, 0x80, 0x55, 0x76, 0xa8, 0x27, 0xbc, 0xb2, 0x62, 0x36, 0x85, 0x45, 0x09, 0x16, 0x8c, 0xc7, 0x2a, 0x94, 0xec, 0x89, 0x63,
0xd2, 0x0d, 0x5a, 0xc8, 0xb2, 0xb8, 0xa9, 0x82, 0xb8, 0xf3, 0xe9, 0x51, 0x64, 0xd4, 0x62, 0x18, 0x4b, 0xef, 0x21, 0xfe, 0xc1, 0xa0, 0x23, 0x6f, 0xe2, 0xf9, 0x28, 0xc8, 0x54, 0x4d, 0xfe, 0x41,
0x26, 0x6e, 0xb0, 0x14, 0x42, 0xbe, 0x54, 0x09, 0xb8, 0xa2, 0x64, 0xd9, 0x9d, 0x4f, 0xdb, 0x88, 0x1e, 0xc0, 0x2a, 0x13, 0xaa, 0x74, 0x23, 0x18, 0x92, 0x2c, 0x6e, 0xde, 0x20, 0xee, 0x7c, 0x7a,
0x51, 0xf4, 0x0f, 0x61, 0x8d, 0xd1, 0x2b, 0x89, 0x54, 0xa5, 0x58, 0xc2, 0x14, 0x2c, 0xb3, 0xae, 0x14, 0x19, 0xc2, 0x58, 0x0a, 0x63, 0x37, 0x58, 0x0e, 0xc1, 0x5f, 0xaa, 0x0c, 0x5c, 0x51, 0xb2,
0xc0, 0xa9, 0x34, 0xb7, 0xa0, 0xca, 0x6b, 0xc5, 0xa6, 0x84, 0xb0, 0x7c, 0x61, 0x55, 0xa8, 0x1f, 0xec, 0xce, 0xa7, 0x6d, 0x4c, 0x51, 0xf8, 0x0f, 0x61, 0x8d, 0xe1, 0x2b, 0x8e, 0x54, 0xe5, 0x58,
0xa4, 0x5c, 0x73, 0xb8, 0x66, 0x20, 0xe9, 0x9a, 0xa3, 0x39, 0xf7, 0x54, 0x92, 0xce, 0x3d, 0x0f, 0xc2, 0x1c, 0xac, 0xb0, 0xae, 0x48, 0x53, 0x79, 0x6e, 0x41, 0x95, 0xb7, 0x8a, 0x2d, 0x09, 0x61,
0x61, 0xed, 0x84, 0xcd, 0xd1, 0x73, 0x6a, 0x8f, 0xa9, 0x6f, 0x45, 0x33, 0x9f, 0x9f, 0x3f, 0x57, 0x2d, 0xc3, 0xa6, 0x50, 0x3f, 0x48, 0x39, 0xfa, 0x70, 0xcd, 0x40, 0xd2, 0xd1, 0x47, 0x73, 0x15,
0x18, 0x72, 0x1f, 0x71, 0x6a, 0xa1, 0x30, 0xd1, 0x90, 0x71, 0x22, 0x3a, 0xb6, 0x42, 0xcf, 0x42, 0xaa, 0x24, 0x5d, 0x85, 0x1e, 0xc2, 0xda, 0x09, 0x5b, 0xa3, 0xe7, 0xd4, 0x1e, 0x53, 0xdf, 0x8a,
0x89, 0x51, 0xa8, 0x60, 0x1b, 0x1c, 0x3c, 0xf4, 0x76, 0x18, 0x30, 0x4e, 0x77, 0xe6, 0xdb, 0xb3, 0x56, 0x3e, 0x97, 0x3f, 0x57, 0x58, 0xe2, 0x3e, 0xa6, 0xa9, 0x8d, 0xc2, 0x58, 0x43, 0x46, 0x89,
0x73, 0x71, 0x3a, 0x54, 0x74, 0x4f, 0x18, 0x90, 0xbc, 0x06, 0x65, 0xb6, 0x26, 0x5c, 0xca, 0x3d, 0xe8, 0xd8, 0x0a, 0x3d, 0x0b, 0x39, 0x46, 0xa1, 0xb6, 0x6d, 0x70, 0xf0, 0xd0, 0xdb, 0x61, 0xc0,
0x1d, 0xf8, 0xb9, 0x4b, 0x82, 0xc8, 0x5b, 0xb0, 0x80, 0x65, 0x04, 0xad, 0x26, 0x2e, 0x88, 0x7a, 0x38, 0xde, 0x99, 0x6f, 0xcf, 0xce, 0x85, 0x74, 0xa8, 0xf0, 0x1e, 0x33, 0x20, 0x79, 0x03, 0xca,
0xb4, 0x77, 0x38, 0xae, 0x29, 0x70, 0x4c, 0xfe, 0x9e, 0xfb, 0x0e, 0x67, 0x6c, 0x55, 0x13, 0x7f, 0x6c, 0x4f, 0xb8, 0x94, 0x7b, 0x47, 0x70, 0xb9, 0x4b, 0x82, 0xc8, 0x3b, 0xb0, 0x80, 0x75, 0x04,
0x93, 0xef, 0x69, 0x5c, 0x72, 0x05, 0xd3, 0xbe, 0x25, 0xd2, 0x26, 0xa6, 0xe2, 0x75, 0x0c, 0xf3, 0xad, 0x26, 0x6e, 0x88, 0x7a, 0x74, 0x76, 0x38, 0xae, 0x29, 0xd2, 0x18, 0xff, 0x3d, 0xf7, 0x1d,
0x1b, 0x65, 0x5f, 0xdf, 0x2f, 0x56, 0x6a, 0xcd, 0xba, 0xd1, 0x42, 0x8f, 0x24, 0x93, 0x8e, 0xbc, 0x4e, 0xd8, 0xaa, 0x26, 0xfe, 0x26, 0xdf, 0xd7, 0xa8, 0xe4, 0x0a, 0xe6, 0x7d, 0x47, 0xe4, 0x4d,
0x0b, 0xea, 0x5f, 0xc5, 0xd6, 0x48, 0x0e, 0x36, 0x52, 0xa8, 0xc8, 0x6b, 0xc1, 0x17, 0x70, 0x6b, 0x2c, 0xc5, 0xeb, 0x08, 0xe6, 0x37, 0x4a, 0xbe, 0x7e, 0x50, 0xac, 0xd4, 0x9a, 0x75, 0xa3, 0x85,
0xea, 0x8d, 0xa5, 0x94, 0x50, 0x97, 0xc0, 0x43, 0x6f, 0xcc, 0xa4, 0x99, 0x65, 0x45, 0x74, 0xea, 0xfe, 0x4d, 0x26, 0x1d, 0x79, 0x17, 0xd4, 0xbf, 0x8a, 0xed, 0x91, 0x1c, 0x6c, 0xa4, 0x92, 0x22,
0xb8, 0x4e, 0x70, 0x4e, 0xc7, 0x42, 0x58, 0x68, 0x4a, 0xc4, 0x9e, 0x80, 0x33, 0x91, 0x7c, 0xe6, 0x4f, 0x07, 0x5f, 0xc0, 0xad, 0xa9, 0x37, 0x96, 0x5c, 0x42, 0x5d, 0x02, 0x0f, 0xbd, 0x31, 0xe3,
0x7b, 0x67, 0x6a, 0xef, 0xcc, 0x99, 0xea, 0xdb, 0xf8, 0x14, 0x4a, 0x7c, 0x04, 0xd9, 0x42, 0xc1, 0x66, 0x96, 0x15, 0xd2, 0xa9, 0xe3, 0x3a, 0xc1, 0x39, 0x1d, 0x0b, 0x66, 0xa1, 0x29, 0x13, 0xf6,
0xf1, 0xcd, 0x89, 0x85, 0x82, 0xd0, 0x16, 0x94, 0x5d, 0x1a, 0x3e, 0xf7, 0xfc, 0x67, 0xd2, 0xca, 0x04, 0x9c, 0xb1, 0xe4, 0x33, 0xdf, 0x3b, 0x53, 0x67, 0x67, 0xce, 0x54, 0xdf, 0xc6, 0x67, 0x50,
0x27, 0x3e, 0x8d, 0x1f, 0xa3, 0x96, 0x55, 0xb9, 0x96, 0x71, 0x6d, 0x04, 0x9b, 0xc2, 0x7c, 0x0a, 0xe2, 0x33, 0xc8, 0x36, 0x0a, 0xce, 0x6f, 0x4e, 0x6c, 0x14, 0x84, 0xb6, 0xa0, 0xec, 0xd2, 0xf0,
0x06, 0xe7, 0xb6, 0x50, 0xfc, 0x56, 0x10, 0x30, 0x38, 0xb7, 0x53, 0x53, 0x38, 0x9f, 0xf6, 0x2e, 0x85, 0xe7, 0x3f, 0x97, 0x1a, 0x68, 0xf1, 0x69, 0xfc, 0x18, 0xb5, 0xac, 0xca, 0x51, 0x8d, 0x6b,
0x7b, 0x0b, 0x16, 0xa5, 0x33, 0x5b, 0x60, 0x4d, 0xe8, 0x69, 0x28, 0x96, 0x64, 0x5d, 0x78, 0xb2, 0x23, 0xd8, 0x12, 0xe6, 0x4b, 0x30, 0x38, 0xb7, 0x85, 0xe2, 0xb7, 0x82, 0x80, 0xc1, 0xb9, 0x9d,
0x05, 0x07, 0xf4, 0x34, 0x34, 0x0e, 0x61, 0x59, 0x2c, 0x9a, 0xfe, 0x8c, 0xca, 0xa2, 0x3f, 0xcb, 0x5a, 0xc2, 0xf9, 0xb4, 0xaf, 0xda, 0x3b, 0xb0, 0x28, 0x5d, 0xe3, 0x02, 0x6b, 0x42, 0x4f, 0x43,
0x3a, 0x26, 0xd5, 0x1e, 0xae, 0xc4, 0xe5, 0x0f, 0x2e, 0xe9, 0xc5, 0xce, 0x4e, 0xc6, 0x0f, 0x22, 0xb1, 0x25, 0xeb, 0xc2, 0x2f, 0x2e, 0x38, 0xa0, 0xa7, 0xa1, 0x71, 0x08, 0xcb, 0x62, 0xd3, 0xf4,
0x95, 0x22, 0x93, 0x4e, 0x44, 0x7e, 0xe2, 0xb0, 0x22, 0x8d, 0xa3, 0xd2, 0x01, 0x43, 0x1d, 0x89, 0x67, 0x54, 0x56, 0xfd, 0x79, 0x96, 0x98, 0x54, 0x7b, 0xb8, 0x12, 0xe7, 0x3f, 0x38, 0xa7, 0x17,
0x9c, 0x31, 0xeb, 0x9d, 0x60, 0x3e, 0x1a, 0x49, 0x27, 0xc3, 0x8a, 0x29, 0x3f, 0x8d, 0xff, 0x95, 0x93, 0x9d, 0x8c, 0x1f, 0x46, 0x2a, 0x45, 0xc6, 0x9d, 0x88, 0xf2, 0x84, 0xb0, 0x22, 0x0d, 0xaa,
0x83, 0x15, 0xcc, 0x4c, 0x1e, 0xf3, 0xc4, 0x4e, 0xf1, 0x13, 0x57, 0x92, 0x8d, 0x8f, 0x2e, 0x12, 0xd2, 0x69, 0x43, 0x89, 0x44, 0xce, 0x98, 0x8d, 0x4e, 0x30, 0x1f, 0x8d, 0xa4, 0xcb, 0x62, 0xc5,
0xf2, 0x8f, 0x97, 0x5b, 0x77, 0x92, 0x96, 0x9b, 0x62, 0xa6, 0xe5, 0xe6, 0xdb, 0xd0, 0x1c, 0xd3, 0x94, 0x9f, 0xc6, 0xff, 0xcc, 0xc1, 0x0a, 0x16, 0x26, 0xc5, 0x3c, 0x71, 0x52, 0xfc, 0xc4, 0x8d,
0x89, 0x83, 0xd3, 0x49, 0x4a, 0x59, 0x5c, 0xac, 0x5d, 0x92, 0x70, 0xa9, 0x7a, 0x48, 0x99, 0x8b, 0x64, 0xf3, 0xa3, 0xb3, 0x84, 0xfc, 0xe3, 0xd5, 0x16, 0xa1, 0xa4, 0xb5, 0xa7, 0x98, 0x69, 0xed,
0x16, 0xd2, 0xa6, 0xc4, 0xbf, 0x9a, 0x83, 0x65, 0x2e, 0xe8, 0xa1, 0xc2, 0x47, 0x74, 0xe8, 0x63, 0xf9, 0x36, 0x34, 0xc7, 0x74, 0xe2, 0xe0, 0x72, 0x92, 0x5c, 0x16, 0x67, 0x6b, 0x97, 0x24, 0x5c,
0xa9, 0xd9, 0x10, 0x6c, 0x57, 0xb4, 0x3d, 0x12, 0x80, 0x10, 0xca, 0x89, 0xf7, 0x6f, 0x08, 0x8d, 0xaa, 0x1e, 0x52, 0x26, 0xa6, 0x85, 0xb4, 0xf9, 0xf1, 0xaf, 0xe6, 0x60, 0x99, 0x33, 0x7a, 0xa8,
0x87, 0x80, 0x92, 0xef, 0xe0, 0x11, 0xd6, 0xb5, 0x10, 0x28, 0x04, 0xf8, 0x9b, 0x19, 0xa2, 0xa5, 0xf0, 0x11, 0x03, 0xfa, 0xa5, 0xd4, 0x6c, 0x08, 0xb2, 0x2b, 0xfa, 0x1e, 0x31, 0x40, 0x08, 0xe5,
0x4a, 0xce, 0xce, 0xb7, 0x2e, 0x82, 0xb6, 0x2b, 0xb0, 0xc0, 0xd5, 0x67, 0xc6, 0x1e, 0x34, 0x62, 0xc8, 0xfb, 0x37, 0x84, 0xc6, 0x43, 0x40, 0xc9, 0x77, 0x51, 0x84, 0x75, 0x2d, 0x04, 0x0a, 0x06,
0xc5, 0xc4, 0x4c, 0x44, 0x75, 0x6e, 0x22, 0x4a, 0xd9, 0xaf, 0xf3, 0x69, 0xfb, 0xf5, 0x15, 0xac, 0xfe, 0x66, 0x06, 0x6b, 0xa9, 0xb2, 0x33, 0xf9, 0xd6, 0x45, 0xd0, 0x76, 0x05, 0x16, 0xb8, 0xfa,
0x98, 0xd4, 0x1e, 0x5f, 0xed, 0x79, 0xfe, 0x51, 0x70, 0x12, 0xee, 0x71, 0xe9, 0x99, 0xed, 0x55, 0xcc, 0xd8, 0x83, 0x46, 0xac, 0x9a, 0x98, 0x59, 0xa9, 0xce, 0xcd, 0x4a, 0x29, 0x9b, 0x77, 0x3e,
0xca, 0x63, 0x25, 0x66, 0x87, 0x91, 0xb6, 0x79, 0xd9, 0x89, 0xdf, 0x82, 0xc5, 0xc8, 0xb5, 0x45, 0x6d, 0xf3, 0xbe, 0x82, 0x15, 0x93, 0xda, 0xe3, 0xab, 0x3d, 0xcf, 0x3f, 0x0a, 0x4e, 0xc2, 0x3d,
0xd3, 0xd8, 0x37, 0x94, 0x77, 0x0b, 0x0a, 0x5d, 0x04, 0x8a, 0xb3, 0xe0, 0x24, 0x14, 0x3a, 0x7b, 0xce, 0x3d, 0xb3, 0xb3, 0x4a, 0x79, 0xb9, 0xc4, 0xec, 0x30, 0xd2, 0x9e, 0x2f, 0x07, 0xf1, 0x5b,
0xfc, 0x6d, 0xfc, 0xe3, 0x12, 0x10, 0x36, 0xeb, 0x13, 0x13, 0x2b, 0x35, 0x2c, 0xb9, 0xb4, 0x15, 0xb0, 0x18, 0xb9, 0xc3, 0x68, 0x1a, 0xfb, 0x86, 0xf2, 0x88, 0x41, 0xa6, 0x8b, 0x40, 0x71, 0x16,
0x2f, 0xe1, 0xb8, 0x93, 0x4f, 0x39, 0xee, 0x3c, 0x00, 0xa2, 0x11, 0x48, 0x7f, 0xa2, 0x82, 0xf2, 0x9c, 0x84, 0x42, 0x67, 0x8f, 0xbf, 0x8d, 0x7f, 0x54, 0x02, 0xc2, 0x56, 0x7d, 0x62, 0x61, 0xa5,
0x27, 0x6a, 0x46, 0xb4, 0xc2, 0x9d, 0xe8, 0x01, 0xac, 0x8a, 0xe3, 0x4a, 0xbc, 0x39, 0x38, 0xcd, 0xa6, 0x25, 0x97, 0xb6, 0xfc, 0x25, 0x9c, 0x7d, 0xf2, 0x29, 0x67, 0x9f, 0x07, 0x40, 0x34, 0x04,
0x4c, 0xc2, 0xcf, 0x2d, 0xb1, 0x36, 0x49, 0xa7, 0x1d, 0xa9, 0x06, 0x2f, 0x70, 0xa7, 0x1d, 0xa9, 0xe9, 0x83, 0x54, 0x50, 0x3e, 0x48, 0xcd, 0x08, 0x57, 0xb8, 0x20, 0x3d, 0x80, 0x55, 0x21, 0xae,
0xad, 0xd2, 0x26, 0xf3, 0xc2, 0x4b, 0x27, 0x73, 0x39, 0x73, 0x32, 0x6b, 0xda, 0xcb, 0x4a, 0x5c, 0xc4, 0xbb, 0x83, 0xcb, 0xcc, 0x24, 0x5c, 0x6e, 0x89, 0xf5, 0x49, 0x3a, 0xfa, 0x48, 0x35, 0x78,
0x7b, 0x99, 0xd2, 0xc3, 0x73, 0xf9, 0x3c, 0xa6, 0x87, 0xbf, 0x07, 0x4d, 0xa9, 0xc9, 0x52, 0x3a, 0x81, 0x3b, 0xfa, 0x48, 0x6d, 0x95, 0xb6, 0x98, 0x17, 0x5e, 0xb9, 0x98, 0xcb, 0x99, 0x8b, 0x59,
0x52, 0xe1, 0xcd, 0x21, 0x94, 0x55, 0x52, 0x4b, 0x1a, 0x33, 0x1a, 0xd6, 0x5e, 0xc5, 0x7a, 0x59, 0xd3, 0x5e, 0x56, 0xe2, 0xda, 0xcb, 0x94, 0x1e, 0x9e, 0xf3, 0xe7, 0x31, 0x3d, 0xfc, 0x3d, 0x68,
0xcf, 0xb6, 0x5e, 0xa6, 0x75, 0x7e, 0x8d, 0x0c, 0x9d, 0xdf, 0xa3, 0xc8, 0x59, 0x23, 0x38, 0x77, 0x4a, 0x4d, 0x96, 0xd2, 0x91, 0x0a, 0x0f, 0x10, 0xa1, 0xac, 0x92, 0x5a, 0xd2, 0x98, 0xa1, 0xb1,
0xa6, 0x28, 0x48, 0x45, 0xde, 0xa6, 0xa2, 0x93, 0x07, 0xe7, 0xce, 0xd4, 0x94, 0x6e, 0x53, 0xec, 0xf6, 0x3a, 0x16, 0xcf, 0x7a, 0xb6, 0xc5, 0x33, 0xad, 0xf3, 0x6b, 0x64, 0xe8, 0xfc, 0x1e, 0x45,
0x83, 0xec, 0xc0, 0x1d, 0xd1, 0x9e, 0x0c, 0x8f, 0x27, 0xde, 0x0b, 0x4b, 0x38, 0x55, 0x36, 0x39, 0x0e, 0x1e, 0xc1, 0xb9, 0x33, 0x45, 0x46, 0x2a, 0xf2, 0x50, 0x15, 0x83, 0x3c, 0x38, 0x77, 0xa6,
0xd9, 0x61, 0xc2, 0xf9, 0x29, 0xd1, 0x29, 0xd2, 0x5f, 0x26, 0xe0, 0x8a, 0x63, 0xd9, 0x29, 0x87, 0xa6, 0x74, 0xb5, 0x62, 0x1f, 0x64, 0x07, 0xee, 0x88, 0xfe, 0x64, 0x78, 0x49, 0xf1, 0x51, 0x58,
0xdc, 0x61, 0x06, 0xd9, 0x03, 0x23, 0x11, 0x4a, 0xc5, 0xe0, 0x02, 0xe5, 0xae, 0x86, 0x59, 0x9b, 0xc2, 0xa5, 0xb2, 0xc9, 0xd1, 0x0e, 0x13, 0x0e, 0x53, 0x89, 0x41, 0x91, 0x3e, 0x36, 0x01, 0x57,
0xda, 0x97, 0x07, 0xa8, 0x34, 0x0c, 0x2e, 0x8c, 0x3f, 0xc9, 0x41, 0x93, 0x4d, 0xe1, 0x18, 0x77, 0x1c, 0xcb, 0x41, 0x39, 0xe4, 0x4e, 0x36, 0x48, 0x1e, 0x18, 0x8a, 0x50, 0x2a, 0x06, 0x17, 0xc8,
0xf8, 0x1c, 0x90, 0xdf, 0xbd, 0x22, 0x73, 0xa8, 0x31, 0x5a, 0xc9, 0x1b, 0x3e, 0x05, 0x5c, 0xec, 0x77, 0x35, 0xcc, 0xda, 0xd4, 0xbe, 0x3c, 0x40, 0xa5, 0x61, 0x70, 0x61, 0xfc, 0x69, 0x0e, 0x9a,
0x96, 0x37, 0xa3, 0xae, 0x60, 0x0d, 0xad, 0x38, 0x6b, 0x88, 0xb6, 0x89, 0xfd, 0x1b, 0xfc, 0xd4, 0x6c, 0x09, 0xc7, 0xa8, 0xc3, 0x17, 0x80, 0xf4, 0xee, 0x35, 0x89, 0x43, 0x8d, 0xe1, 0x4a, 0xda,
0xc9, 0x20, 0xe4, 0x73, 0xa8, 0xb2, 0x35, 0x85, 0x93, 0x57, 0xf8, 0x73, 0x6f, 0x2a, 0x4d, 0x42, 0xf0, 0x19, 0xe0, 0x66, 0xb7, 0xbc, 0x19, 0x75, 0x05, 0x69, 0x68, 0xc5, 0x49, 0x43, 0x74, 0x4c,
0x6a, 0x79, 0xb3, 0xa4, 0x33, 0xf1, 0x99, 0xe5, 0x0e, 0x55, 0xcc, 0x70, 0x87, 0xd2, 0x78, 0xcf, 0xec, 0xdf, 0xe0, 0x52, 0x27, 0x83, 0x90, 0x2f, 0xa0, 0xca, 0xf6, 0x14, 0x2e, 0x5e, 0xe1, 0x1d,
0x3e, 0xc0, 0x53, 0x7a, 0xc5, 0x3a, 0x21, 0xf4, 0x7c, 0x26, 0xab, 0xb1, 0x25, 0x76, 0x6a, 0x4f, 0xbe, 0xa9, 0x34, 0x09, 0xa9, 0xed, 0xcd, 0xb2, 0xce, 0xc4, 0x67, 0x96, 0x0b, 0x55, 0x31, 0xc3,
0x1d, 0xa1, 0xcd, 0x2c, 0x99, 0xd5, 0x67, 0xf4, 0x6a, 0x0f, 0x01, 0x6c, 0x6e, 0x31, 0x74, 0xc4, 0x85, 0x4a, 0xa3, 0x3d, 0xfb, 0x00, 0x4f, 0xe8, 0x15, 0x1b, 0x84, 0xd0, 0xf3, 0x19, 0xaf, 0xc6,
0x80, 0x4a, 0x66, 0xe5, 0x19, 0xbd, 0xe2, 0xdc, 0xc7, 0x82, 0xc6, 0x53, 0x7a, 0xb5, 0x4b, 0xf9, 0xb6, 0xd8, 0xa9, 0x3d, 0x75, 0x84, 0x36, 0xb3, 0x64, 0x56, 0x9f, 0xd3, 0xab, 0x3d, 0x04, 0xb0,
0x61, 0xc0, 0xf3, 0x59, 0xa7, 0xfb, 0xf6, 0x73, 0x26, 0xfd, 0xc7, 0xdc, 0x75, 0x6a, 0xbe, 0xfd, 0xb5, 0xc5, 0x92, 0x23, 0x02, 0x54, 0x32, 0x2b, 0xcf, 0xe9, 0x15, 0xa7, 0x3e, 0x16, 0x34, 0x9e,
0xfc, 0x29, 0xbd, 0x92, 0xae, 0x43, 0x65, 0x86, 0x9f, 0x78, 0x23, 0x21, 0xbe, 0x48, 0x05, 0x52, 0xd0, 0xab, 0x5d, 0xca, 0x85, 0x01, 0xcf, 0x67, 0x83, 0xee, 0xdb, 0x2f, 0x18, 0xf7, 0x1f, 0x73,
0x54, 0x29, 0x73, 0xe1, 0x19, 0xfe, 0x36, 0xfe, 0x38, 0x07, 0x0d, 0x56, 0x7f, 0xdc, 0x79, 0x70, 0xf1, 0xa9, 0xf9, 0xf6, 0x8b, 0x27, 0xf4, 0x4a, 0xba, 0x1b, 0x95, 0x59, 0xfa, 0xc4, 0x1b, 0x09,
0x16, 0x09, 0xff, 0xdf, 0x5c, 0xe4, 0xff, 0xfb, 0x50, 0x30, 0x64, 0xbe, 0x8d, 0xe5, 0xaf, 0xdf, 0xf6, 0x45, 0x2a, 0x90, 0xa2, 0x46, 0x99, 0x0b, 0xcf, 0xf1, 0xb7, 0xf1, 0x27, 0x39, 0x68, 0xb0,
0xc6, 0x70, 0x6c, 0xf8, 0x1e, 0xf6, 0x21, 0x54, 0xf9, 0xc4, 0x60, 0xec, 0xa7, 0x10, 0x1b, 0xe0, 0xf6, 0xe3, 0xc9, 0x83, 0xab, 0x48, 0xf8, 0x0c, 0xe7, 0x22, 0x9f, 0xe1, 0x87, 0x82, 0x20, 0xf3,
0x58, 0x83, 0xcc, 0x0a, 0x92, 0x3d, 0xe5, 0xbe, 0x84, 0x9a, 0xae, 0x9e, 0x77, 0x71, 0xd5, 0x57, 0x63, 0x2c, 0x7f, 0xfd, 0x31, 0x86, 0x73, 0xc3, 0xcf, 0xb0, 0x8f, 0xa0, 0xca, 0x17, 0x06, 0x23,
0x1a, 0xfa, 0x8c, 0x61, 0x28, 0x5d, 0xe3, 0x4b, 0xa8, 0x2b, 0xc2, 0x17, 0x92, 0x8a, 0x70, 0xc3, 0x3f, 0x85, 0xd8, 0x04, 0xc7, 0x3a, 0x64, 0x56, 0x10, 0xed, 0x09, 0xf7, 0x3f, 0xd4, 0x74, 0xf5,
0x85, 0x0a, 0x1b, 0x6a, 0x6c, 0x6c, 0x46, 0xa6, 0xb9, 0xac, 0x4c, 0x99, 0xb0, 0x63, 0xb3, 0xfd, 0x7c, 0x88, 0xab, 0xbe, 0xd2, 0xd0, 0x67, 0x4c, 0x43, 0xe9, 0x1a, 0xff, 0x43, 0x5d, 0x11, 0xbe,
0x8c, 0xf1, 0xe8, 0xbc, 0x10, 0x76, 0xec, 0x80, 0xb2, 0x8c, 0x58, 0xc5, 0x5d, 0xcf, 0x42, 0xcd, 0x90, 0x54, 0x84, 0x1b, 0x2e, 0x54, 0xd8, 0x54, 0x63, 0x67, 0x33, 0x0a, 0xcd, 0x65, 0x15, 0xca,
0xb2, 0xd0, 0xb9, 0x56, 0xcc, 0xaa, 0xeb, 0x1d, 0x71, 0x80, 0xf1, 0x17, 0x72, 0x50, 0xd3, 0xd6, 0x98, 0x1d, 0x9b, 0x9d, 0x67, 0x8c, 0x46, 0xe7, 0x05, 0xb3, 0x63, 0x07, 0x94, 0x15, 0xc4, 0x1a,
0x2c, 0x9a, 0x1a, 0x54, 0x77, 0xf2, 0x05, 0x1e, 0x5f, 0x01, 0xb1, 0xf1, 0xd8, 0xbf, 0x61, 0x36, 0xee, 0x7a, 0x16, 0x6a, 0x96, 0x85, 0xce, 0xb5, 0x62, 0x56, 0x5d, 0xef, 0x88, 0x03, 0x8c, 0xbf,
0x46, 0xb1, 0x01, 0xda, 0x12, 0x53, 0x19, 0x53, 0xe6, 0x63, 0xfa, 0x2d, 0xd9, 0x2e, 0x39, 0x7f, 0x90, 0x83, 0x9a, 0xb6, 0x67, 0xd1, 0xd4, 0xa0, 0x86, 0x93, 0x6f, 0xf0, 0xf8, 0x0e, 0x88, 0xcd,
0xd9, 0xef, 0xed, 0x05, 0x28, 0x32, 0x52, 0xe3, 0x31, 0x2c, 0x6b, 0xd5, 0xe0, 0xfa, 0x9f, 0x57, 0xc7, 0xfe, 0x0d, 0xb3, 0x31, 0x8a, 0x4d, 0xd0, 0x96, 0x58, 0xca, 0x98, 0x33, 0x1f, 0xd3, 0x6f,
0xed, 0x00, 0xe3, 0xe7, 0x55, 0x62, 0x56, 0x06, 0xb7, 0xdd, 0x4b, 0xb7, 0x4d, 0x3a, 0xe6, 0xfd, 0xc9, 0x7e, 0xc9, 0xf5, 0xcb, 0x7e, 0x6f, 0x2f, 0x40, 0x91, 0xa1, 0x1a, 0x5f, 0xc2, 0xb2, 0xd6,
0x22, 0xdc, 0x43, 0x39, 0x08, 0x7b, 0xe6, 0x15, 0x3d, 0x09, 0x8d, 0x5f, 0xce, 0xc1, 0x8a, 0x96, 0x0c, 0xae, 0xff, 0x79, 0xdd, 0x01, 0x30, 0x7e, 0x41, 0x65, 0x66, 0x75, 0x70, 0xdb, 0xbd, 0x74,
0xfd, 0x9e, 0xe3, 0xda, 0x13, 0xe7, 0xc7, 0xb8, 0x8d, 0x05, 0xce, 0x99, 0x9b, 0x28, 0x80, 0x83, 0xf5, 0xa4, 0x63, 0x3e, 0x2e, 0xc2, 0xa5, 0x94, 0x83, 0x70, 0x64, 0x5e, 0xd3, 0xfb, 0xd0, 0xf8,
0xbe, 0x4e, 0x01, 0xe4, 0x2e, 0xd4, 0xb9, 0x9f, 0x38, 0xbf, 0x6b, 0x20, 0xb6, 0x59, 0x40, 0x98, 0x95, 0x1c, 0xac, 0x68, 0xc5, 0xef, 0x39, 0xae, 0x3d, 0x71, 0x7e, 0x8c, 0xc7, 0x58, 0xe0, 0x9c,
0x69, 0x3f, 0x1f, 0x5e, 0x1a, 0x7f, 0x2d, 0x0f, 0xab, 0xa2, 0x0a, 0xe8, 0xce, 0xef, 0x30, 0x51, 0xb9, 0x89, 0x0a, 0x38, 0xe8, 0xeb, 0x54, 0x40, 0xee, 0x42, 0x9d, 0xfb, 0x96, 0xf3, 0x9b, 0x0b,
0xf7, 0x30, 0x38, 0x23, 0x9f, 0x43, 0x83, 0x75, 0x9f, 0xe5, 0xd3, 0x33, 0x27, 0x08, 0xa9, 0x74, 0xe2, 0x98, 0x05, 0x84, 0x99, 0xf6, 0x8b, 0xe1, 0xa5, 0xf1, 0xd7, 0xf2, 0xb0, 0x2a, 0x9a, 0x80,
0x2b, 0xc8, 0xe0, 0xc6, 0x4c, 0x92, 0x61, 0xa4, 0xa6, 0xa0, 0x24, 0x8f, 0xa1, 0x86, 0x49, 0xb9, 0x57, 0x00, 0x1c, 0xc6, 0xea, 0x1e, 0x06, 0x67, 0xe4, 0x0b, 0x68, 0xb0, 0xe1, 0xb3, 0x7c, 0x7a,
0x0a, 0x4e, 0x8c, 0x55, 0x2b, 0x9d, 0x90, 0x8f, 0xc5, 0xfe, 0x0d, 0x13, 0x82, 0x68, 0x64, 0x1e, 0xe6, 0x04, 0x21, 0x95, 0x6e, 0x05, 0x19, 0xd4, 0x98, 0x71, 0x32, 0x0c, 0xd5, 0x14, 0x98, 0xe4,
0x43, 0x0d, 0x87, 0xf9, 0x02, 0xfb, 0x3a, 0xc1, 0xec, 0x52, 0x63, 0xc1, 0x12, 0xcf, 0xa2, 0x91, 0x4b, 0xa8, 0x61, 0x56, 0xae, 0x82, 0x13, 0x73, 0xd5, 0x4a, 0x67, 0xe4, 0x73, 0xb1, 0x7f, 0xc3,
0x69, 0x43, 0x83, 0xb3, 0x3b, 0xd1, 0x93, 0xc2, 0x07, 0x78, 0x33, 0x9d, 0x5c, 0xf6, 0x35, 0xab, 0x84, 0x20, 0x9a, 0x99, 0x2f, 0xa1, 0x86, 0xd3, 0x7c, 0x81, 0x63, 0x9d, 0x20, 0x76, 0xa9, 0xb9,
0xfc, 0x4c, 0xfb, 0xde, 0xae, 0x42, 0x39, 0xf4, 0x9d, 0xb3, 0x33, 0xea, 0x1b, 0xeb, 0xaa, 0x6b, 0x60, 0x99, 0x67, 0xd1, 0xcc, 0xb4, 0xa1, 0xc1, 0xc9, 0x9d, 0x18, 0x49, 0xe1, 0x37, 0xbc, 0x99,
0x18, 0x1f, 0xa7, 0x83, 0x90, 0xce, 0xd8, 0x19, 0xc6, 0xf8, 0xe7, 0x39, 0xa8, 0x09, 0xce, 0xfc, 0xce, 0x2e, 0xc7, 0x9a, 0x35, 0x7e, 0xa6, 0x7d, 0x6f, 0x57, 0xa1, 0x1c, 0xfa, 0xce, 0xd9, 0x19,
0x13, 0x7b, 0x2c, 0x6c, 0x26, 0x94, 0xb5, 0x55, 0x4d, 0x37, 0xfb, 0x0e, 0x2c, 0x4d, 0xd9, 0x81, 0xf5, 0x8d, 0x75, 0x35, 0x34, 0x8c, 0x8e, 0xd3, 0x41, 0x48, 0x67, 0x4c, 0x86, 0x31, 0xfe, 0x59,
0xcb, 0x09, 0xaf, 0xe2, 0xee, 0x0a, 0x8b, 0x12, 0x2c, 0xce, 0x12, 0x5b, 0xb0, 0x82, 0x47, 0x8b, 0x0e, 0x6a, 0x82, 0x32, 0xff, 0xc4, 0x1e, 0x0b, 0x9b, 0x09, 0x65, 0x6d, 0x55, 0xd3, 0xcd, 0xbe,
0xc0, 0x0a, 0x9d, 0x89, 0x25, 0x91, 0xe2, 0x4e, 0xcb, 0x32, 0x47, 0x0d, 0x9d, 0xc9, 0xa1, 0x40, 0x07, 0x4b, 0x53, 0x26, 0x70, 0x39, 0xe1, 0x55, 0xdc, 0x5d, 0x61, 0x51, 0x82, 0x85, 0x2c, 0xb1,
0x30, 0x09, 0x3b, 0x08, 0xed, 0x33, 0x2a, 0xb8, 0x03, 0xff, 0x60, 0x87, 0xb8, 0x84, 0x2e, 0x40, 0x05, 0x2b, 0x28, 0x5a, 0x04, 0x56, 0xe8, 0x4c, 0x2c, 0x99, 0x28, 0x6e, 0xc8, 0x2c, 0xf3, 0xa4,
0x1e, 0xe2, 0xfe, 0xcf, 0x32, 0x6c, 0xa4, 0x50, 0xe2, 0x10, 0xa7, 0xac, 0xc3, 0x13, 0x67, 0x7a, 0xa1, 0x33, 0x39, 0x14, 0x09, 0x8c, 0xc3, 0x0e, 0x42, 0xfb, 0x8c, 0x0a, 0xea, 0xc0, 0x3f, 0x98,
0xe2, 0x29, 0xeb, 0x44, 0x4e, 0xb3, 0x0e, 0x1f, 0x30, 0x8c, 0xb4, 0x4e, 0x50, 0x58, 0x93, 0x53, 0x10, 0x97, 0xd0, 0x05, 0x48, 0x21, 0xee, 0x7f, 0x2f, 0xc3, 0x46, 0x2a, 0x49, 0x08, 0x71, 0xca,
0x16, 0xcd, 0x0b, 0x4a, 0x5d, 0x90, 0xc7, 0xc3, 0xec, 0x87, 0xf1, 0x6d, 0x30, 0x59, 0x9c, 0x84, 0x3a, 0x3c, 0x71, 0xa6, 0x27, 0x9e, 0xb2, 0x4e, 0xe4, 0x34, 0xeb, 0xf0, 0x01, 0x4b, 0x91, 0xd6,
0xeb, 0x72, 0xe1, 0xca, 0x2c, 0x05, 0x0b, 0xc8, 0x9f, 0x85, 0x96, 0x5a, 0x19, 0xe2, 0x6c, 0xa3, 0x09, 0x0a, 0x6b, 0x72, 0xc9, 0xa2, 0x79, 0x41, 0xa9, 0x0b, 0xf2, 0x28, 0xcc, 0x7e, 0x14, 0x3f,
0xe9, 0x3e, 0x58, 0x49, 0xef, 0xbd, 0xa4, 0xa4, 0x98, 0xde, 0x17, 0x45, 0xaf, 0x75, 0xb9, 0xa8, 0x06, 0x93, 0xd5, 0x49, 0xb8, 0xce, 0x17, 0xae, 0xcc, 0x52, 0xb0, 0x80, 0xfc, 0xff, 0xd0, 0x52,
0x78, 0x86, 0xaa, 0xac, 0x0b, 0x78, 0x5d, 0x96, 0x85, 0x67, 0x95, 0x74, 0x89, 0xc5, 0x57, 0x6a, 0x3b, 0x43, 0xc8, 0x36, 0x9a, 0xee, 0x83, 0xd5, 0xf4, 0x9d, 0x57, 0xd4, 0x14, 0xd3, 0xfb, 0x22,
0x1b, 0xea, 0xb4, 0x63, 0xc5, 0x9a, 0xb7, 0x44, 0xc6, 0x0a, 0xa5, 0x97, 0x7b, 0x0e, 0xeb, 0xcf, 0xeb, 0xb5, 0x2e, 0x37, 0x15, 0x2f, 0x50, 0xd5, 0x75, 0x01, 0x6f, 0xca, 0xba, 0x50, 0x56, 0x49,
0x6d, 0x27, 0x94, 0x6d, 0xd4, 0x54, 0x2f, 0x25, 0x2c, 0xef, 0xe1, 0x4b, 0xca, 0xfb, 0x92, 0x27, 0xd7, 0x58, 0x7c, 0xad, 0xbe, 0xa1, 0x4e, 0x3b, 0x56, 0xad, 0x79, 0x4b, 0x14, 0xac, 0x92, 0xf4,
0x8e, 0x9d, 0xde, 0x56, 0x9f, 0xa7, 0x81, 0xc1, 0xe6, 0xdf, 0x29, 0xc0, 0x62, 0x3c, 0x17, 0xc6, 0x7a, 0xcf, 0x61, 0xfd, 0x85, 0xed, 0x84, 0xb2, 0x8f, 0x9a, 0xea, 0xa5, 0x84, 0xf5, 0x3d, 0x7c,
0x7a, 0xc4, 0x76, 0x25, 0x05, 0x69, 0x71, 0x02, 0x10, 0x96, 0xb3, 0x1e, 0x17, 0xa0, 0xd3, 0x36, 0x45, 0x7d, 0x5f, 0xf1, 0xcc, 0x31, 0xe9, 0x6d, 0xf5, 0x45, 0x1a, 0x18, 0x6c, 0xfe, 0xed, 0x02,
0xbd, 0x7c, 0x86, 0x4d, 0x4f, 0x37, 0xa5, 0x15, 0x5e, 0xe6, 0x59, 0x51, 0x7c, 0x25, 0xcf, 0x8a, 0x2c, 0xc6, 0x4b, 0x61, 0xa4, 0x47, 0x1c, 0x57, 0x92, 0x91, 0x16, 0x12, 0x80, 0xb0, 0x9c, 0xf5,
0x52, 0x96, 0x67, 0xc5, 0x47, 0xd7, 0x9a, 0xe2, 0xb9, 0x42, 0x3c, 0xd3, 0x0c, 0xff, 0xe8, 0x7a, 0x38, 0x03, 0x9d, 0xb6, 0xe9, 0xe5, 0x33, 0x6c, 0x7a, 0xba, 0x29, 0xad, 0xf0, 0x2a, 0xcf, 0x8a,
0x33, 0x3c, 0xd7, 0x95, 0x5f, 0x67, 0x82, 0xd7, 0x1c, 0x08, 0x2a, 0xd7, 0x18, 0xc0, 0x34, 0x97, 0xe2, 0x6b, 0x79, 0x56, 0x94, 0xb2, 0x3c, 0x2b, 0x3e, 0xbe, 0xd6, 0x14, 0xcf, 0x15, 0xe2, 0x99,
0x82, 0x0c, 0x13, 0x7c, 0xf5, 0x6b, 0x98, 0xe0, 0x37, 0xff, 0x38, 0x07, 0x24, 0xbd, 0x3a, 0xc8, 0x66, 0xf8, 0x47, 0xd7, 0x9b, 0xe1, 0xb9, 0xae, 0xfc, 0x3a, 0x13, 0xbc, 0xe6, 0x40, 0x50, 0xb9,
0x13, 0x6e, 0x2e, 0x75, 0xe9, 0x44, 0x70, 0xee, 0xf7, 0x5f, 0x6d, 0x85, 0xc9, 0x09, 0x21, 0x53, 0xc6, 0x00, 0xa6, 0xb9, 0x14, 0x64, 0x98, 0xe0, 0xab, 0x5f, 0xc3, 0x04, 0xbf, 0xf9, 0x27, 0x39,
0x93, 0x0f, 0x60, 0x45, 0xbf, 0x79, 0xa7, 0xab, 0x36, 0x1a, 0x26, 0xd1, 0x51, 0x91, 0x92, 0x4e, 0x20, 0xe9, 0xdd, 0x41, 0x1e, 0x73, 0x73, 0xa9, 0x4b, 0x27, 0x82, 0x72, 0x7f, 0xf0, 0x7a, 0x3b,
0x73, 0x63, 0x29, 0xbe, 0xd4, 0x8d, 0xa5, 0xf4, 0x52, 0x37, 0x96, 0x85, 0xb8, 0x1b, 0xcb, 0xe6, 0x4c, 0x2e, 0x08, 0x99, 0x9b, 0x7c, 0x08, 0x2b, 0xfa, 0x3d, 0x3e, 0x5d, 0xb5, 0xd1, 0x30, 0x89,
0xbf, 0xca, 0xc1, 0x4a, 0xc6, 0x24, 0xfe, 0xe6, 0xda, 0xcc, 0xe6, 0x5e, 0x8c, 0xad, 0xe5, 0xc5, 0x9e, 0x14, 0x29, 0xe9, 0x34, 0x37, 0x96, 0xe2, 0x2b, 0xdd, 0x58, 0x4a, 0xaf, 0x74, 0x63, 0x59,
0xdc, 0xd3, 0x39, 0xda, 0x81, 0x54, 0xec, 0xb2, 0xa1, 0x08, 0xc4, 0x4e, 0x75, 0xff, 0x65, 0xdc, 0x88, 0xbb, 0xb1, 0x6c, 0xfe, 0xcb, 0x1c, 0xac, 0x64, 0x2c, 0xe2, 0x6f, 0xae, 0xcf, 0x6c, 0xed,
0x25, 0x4a, 0x61, 0xea, 0xc9, 0x37, 0xff, 0x6e, 0x1e, 0x6a, 0x1a, 0x92, 0xf5, 0x22, 0x9f, 0xb2, 0xc5, 0xc8, 0x5a, 0x5e, 0xac, 0x3d, 0x9d, 0xa2, 0x1d, 0x48, 0xc5, 0x2e, 0x9b, 0x8a, 0x40, 0x9c,
0x9a, 0x83, 0x27, 0x97, 0x2d, 0x51, 0x31, 0x83, 0xd7, 0x04, 0x70, 0x72, 0x22, 0x9e, 0x2f, 0x2e, 0x54, 0xf7, 0x5f, 0x45, 0x5d, 0xa2, 0x1c, 0xa6, 0x9e, 0x7d, 0xf3, 0xef, 0xe4, 0xa1, 0xa6, 0x25,
0x21, 0x48, 0x22, 0xc1, 0x16, 0xac, 0x48, 0x53, 0x36, 0x8d, 0x1c, 0xe0, 0xc5, 0x5e, 0x23, 0xbc, 0xb2, 0x51, 0xe4, 0x4b, 0x56, 0x73, 0x0a, 0xe5, 0xbc, 0x25, 0x2a, 0x66, 0xf0, 0x6a, 0x01, 0x2e,
0x12, 0x44, 0x25, 0x91, 0xfe, 0x03, 0x79, 0xce, 0x8d, 0xc6, 0x4e, 0x33, 0x0d, 0x2e, 0x0b, 0x7f, 0x4e, 0x4c, 0xe7, 0x9b, 0x4b, 0x30, 0x92, 0x88, 0xb0, 0x05, 0x2b, 0xd2, 0x94, 0x4d, 0x23, 0xa7,
0x08, 0x31, 0x88, 0x6c, 0x9e, 0x7f, 0x08, 0x6b, 0xca, 0x21, 0x22, 0x96, 0x82, 0x1b, 0xa0, 0x88, 0x79, 0x71, 0xd6, 0x08, 0xaf, 0x04, 0xd1, 0x48, 0xc4, 0xff, 0x50, 0xca, 0xb9, 0xd1, 0xdc, 0x69,
0x74, 0x7c, 0xd0, 0x92, 0x7c, 0x0f, 0x6e, 0x27, 0xea, 0x94, 0x48, 0xca, 0x35, 0x2d, 0x37, 0x63, 0xa6, 0xc1, 0x65, 0xe1, 0x0f, 0x21, 0x26, 0x91, 0xad, 0xf3, 0x8f, 0x60, 0x4d, 0x39, 0x44, 0xc4,
0xb5, 0xd3, 0x73, 0xd8, 0xfc, 0x73, 0xd0, 0x88, 0x31, 0xca, 0x6f, 0x6e, 0xc8, 0x93, 0xca, 0x30, 0x72, 0x70, 0x03, 0x14, 0x91, 0x8e, 0x0f, 0x5a, 0x96, 0xef, 0xc3, 0xed, 0x44, 0x9b, 0x12, 0x59,
0xde, 0xa3, 0xba, 0x32, 0x6c, 0xf3, 0x7f, 0x14, 0x80, 0xa4, 0x79, 0xf5, 0x4f, 0xb3, 0x0a, 0xe9, 0xb9, 0xa6, 0xe5, 0x66, 0xac, 0x75, 0x7a, 0x09, 0x9b, 0x7f, 0x0e, 0x1a, 0x31, 0x42, 0xf9, 0xcd,
0x89, 0x59, 0xc8, 0x98, 0x98, 0xff, 0xdf, 0xe4, 0x87, 0x48, 0x27, 0xab, 0xf9, 0x23, 0xf0, 0xc5, 0x4d, 0x79, 0x52, 0x19, 0xc6, 0x47, 0x54, 0x57, 0x86, 0x6d, 0xfe, 0xf7, 0x02, 0x90, 0x34, 0xad,
0xd9, 0x54, 0x08, 0x59, 0x8b, 0x4f, 0x93, 0x5e, 0x5b, 0x95, 0xd8, 0xe5, 0x51, 0x4d, 0x80, 0x4a, 0xfe, 0x69, 0x36, 0x21, 0xbd, 0x30, 0x0b, 0x19, 0x0b, 0xf3, 0xff, 0x19, 0xff, 0x10, 0xe9, 0x64,
0x38, 0x6f, 0x1d, 0xc3, 0x82, 0xed, 0x8e, 0xce, 0x3d, 0x5f, 0xf0, 0xc1, 0x9f, 0xf9, 0xda, 0xdb, 0x35, 0x7f, 0x04, 0xbe, 0x39, 0x9b, 0x2a, 0x41, 0xb6, 0xe2, 0xb3, 0xa4, 0xd7, 0x56, 0x25, 0x76,
0xe7, 0x56, 0x1b, 0xd3, 0xa3, 0xd4, 0x66, 0x8a, 0xcc, 0x8c, 0x0f, 0xa1, 0xa6, 0x81, 0x49, 0x15, 0xe1, 0x54, 0x63, 0xa0, 0x12, 0xce, 0x5b, 0xc7, 0xb0, 0x60, 0xbb, 0xa3, 0x73, 0xcf, 0x17, 0x74,
0x4a, 0x07, 0xdd, 0xc3, 0xed, 0x7e, 0xf3, 0x06, 0x69, 0x40, 0xd5, 0xec, 0xec, 0xf4, 0xbf, 0xe8, 0xf0, 0x67, 0xbe, 0xf6, 0xf1, 0xb9, 0xd5, 0xc6, 0xfc, 0xc8, 0xb5, 0x99, 0xa2, 0x30, 0xe3, 0x23,
0x98, 0x9d, 0xdd, 0x66, 0x8e, 0x54, 0xa0, 0x78, 0xd0, 0x1f, 0x0c, 0x9b, 0x79, 0x63, 0x13, 0x5a, 0xa8, 0x69, 0x60, 0x52, 0x85, 0xd2, 0x41, 0xf7, 0x70, 0xbb, 0xdf, 0xbc, 0x41, 0x1a, 0x50, 0x35,
0x22, 0xc7, 0xb4, 0x75, 0xea, 0x37, 0x8b, 0x4a, 0xa7, 0x8a, 0x48, 0x71, 0xc8, 0xff, 0x08, 0xea, 0x3b, 0x3b, 0xfd, 0xa7, 0x1d, 0xb3, 0xb3, 0xdb, 0xcc, 0x91, 0x0a, 0x14, 0x0f, 0xfa, 0x83, 0x61,
0xba, 0x78, 0x23, 0x66, 0x44, 0xc2, 0x25, 0x86, 0x1d, 0xef, 0x3d, 0x8d, 0x57, 0xef, 0x00, 0x77, 0x33, 0x6f, 0x6c, 0x42, 0x4b, 0x94, 0x98, 0xb6, 0x4e, 0xfd, 0x56, 0x51, 0xe9, 0x54, 0x31, 0x51,
0x88, 0x18, 0xab, 0x64, 0xf9, 0x98, 0xdc, 0x9a, 0x61, 0x59, 0xc6, 0xf3, 0x51, 0x6c, 0x1a, 0xfe, 0x08, 0xf9, 0x1f, 0x43, 0x5d, 0x67, 0x6f, 0xc4, 0x8a, 0x48, 0xb8, 0xc4, 0x30, 0xf1, 0xde, 0xd3,
0x19, 0x58, 0x8c, 0x5b, 0x62, 0x04, 0x47, 0xca, 0x3a, 0xb2, 0xb2, 0xd4, 0x31, 0xd3, 0x0c, 0xf9, 0x68, 0xf5, 0x0e, 0x70, 0x87, 0x88, 0xb1, 0xca, 0x96, 0x8f, 0xf1, 0xad, 0x19, 0x96, 0x65, 0x94,
0x1e, 0x34, 0x93, 0x96, 0x1c, 0x21, 0x3c, 0x5f, 0x93, 0x7e, 0xc9, 0x89, 0x1b, 0x77, 0xc8, 0x3e, 0x8f, 0x62, 0xcb, 0xf0, 0xff, 0x83, 0xc5, 0xb8, 0x25, 0x46, 0x50, 0xa4, 0x2c, 0x91, 0x95, 0xe5,
0xac, 0x66, 0x09, 0x78, 0x38, 0x3f, 0xae, 0x57, 0x73, 0x90, 0xb4, 0x10, 0x47, 0x3e, 0x13, 0x16, 0x8e, 0x99, 0x66, 0xc8, 0xf7, 0xa1, 0x99, 0xb4, 0xe4, 0x08, 0xe6, 0xf9, 0x9a, 0xfc, 0x4b, 0x4e,
0xbd, 0x12, 0x0e, 0xff, 0x5b, 0xf1, 0xf2, 0xb5, 0xce, 0xde, 0xe2, 0xff, 0x34, 0xdb, 0xde, 0x05, 0xdc, 0xb8, 0x43, 0xf6, 0x61, 0x35, 0x8b, 0xc1, 0xc3, 0xf5, 0x71, 0xbd, 0x9a, 0x83, 0xa4, 0x99,
0x40, 0x04, 0x23, 0x4d, 0xa8, 0xf7, 0x8f, 0x3a, 0x3d, 0x6b, 0x67, 0xbf, 0xdd, 0xeb, 0x75, 0x0e, 0x38, 0xf2, 0xb9, 0xb0, 0xe8, 0x95, 0x70, 0xfa, 0xdf, 0x89, 0xd7, 0xaf, 0x0d, 0xf6, 0x16, 0xff,
0x9a, 0x37, 0x08, 0x81, 0x45, 0xf4, 0xea, 0xd8, 0x55, 0xb0, 0x1c, 0x83, 0x09, 0x53, 0xab, 0x84, 0xa7, 0xd9, 0xf6, 0x2e, 0x00, 0x22, 0x18, 0x69, 0x42, 0xbd, 0x7f, 0xd4, 0xe9, 0x59, 0x3b, 0xfb,
0xe5, 0xc9, 0x2a, 0x34, 0xbb, 0xbd, 0x04, 0xb4, 0x40, 0x5a, 0xb0, 0x7a, 0xd4, 0xe1, 0x8e, 0x20, 0xed, 0x5e, 0xaf, 0x73, 0xd0, 0xbc, 0x41, 0x08, 0x2c, 0xa2, 0x57, 0xc7, 0xae, 0x82, 0xe5, 0x18,
0xb1, 0x7c, 0x8b, 0xec, 0xd0, 0x20, 0x9a, 0xcb, 0x0e, 0x0d, 0x5f, 0xda, 0x93, 0x09, 0x0d, 0xc5, 0x4c, 0x98, 0x5a, 0x25, 0x2c, 0x4f, 0x56, 0xa1, 0xd9, 0xed, 0x25, 0xa0, 0x05, 0xd2, 0x82, 0xd5,
0x3a, 0x90, 0xb2, 0xf4, 0x5f, 0xcf, 0xc1, 0x5a, 0x02, 0x11, 0x99, 0x43, 0xb8, 0x24, 0x1d, 0x97, 0xa3, 0x0e, 0x77, 0x04, 0x89, 0x95, 0x5b, 0x64, 0x42, 0x83, 0xe8, 0xae, 0x11, 0xc2, 0xea, 0x57,
0xa1, 0xeb, 0x08, 0x94, 0xab, 0xe9, 0x5d, 0x58, 0x56, 0xda, 0xb4, 0xc4, 0xae, 0xd4, 0x54, 0x08, 0xf6, 0x64, 0x42, 0xc3, 0x36, 0x77, 0x64, 0x97, 0xdb, 0xe1, 0x7d, 0x58, 0x56, 0xea, 0xb0, 0x04,
0x49, 0xfc, 0x01, 0xac, 0x68, 0x4a, 0xb9, 0x04, 0xaf, 0x20, 0x1a, 0x4a, 0x24, 0x30, 0xb6, 0x60, 0xb7, 0xdc, 0x54, 0x09, 0x12, 0xf9, 0x43, 0x58, 0xd1, 0xb4, 0x6a, 0x89, 0x53, 0x88, 0x68, 0x49,
0x41, 0x28, 0x2f, 0x9b, 0x50, 0x90, 0x37, 0x72, 0x8a, 0x26, 0xfb, 0x49, 0x08, 0x14, 0xa7, 0x91, 0x22, 0x03, 0x13, 0x55, 0x78, 0xad, 0x02, 0x20, 0x39, 0xf8, 0x3f, 0xcc, 0xc3, 0x5a, 0x22, 0x21,
0x3f, 0x31, 0xfe, 0x36, 0x36, 0xd4, 0xdd, 0xba, 0x44, 0x2b, 0x7f, 0xb9, 0x08, 0xeb, 0x49, 0x8c, 0x32, 0xc2, 0x70, 0xfe, 0x3d, 0xde, 0x96, 0x3a, 0x02, 0x5f, 0xda, 0xe8, 0xfc, 0xd7, 0x6b, 0x74,
0xf2, 0xb0, 0x2f, 0xc7, 0x1a, 0xc8, 0x0d, 0x63, 0x02, 0x44, 0x3e, 0x4e, 0xcc, 0x9e, 0x58, 0x13, 0xe1, 0xba, 0x46, 0x93, 0x67, 0xb0, 0x24, 0xbc, 0xfd, 0x35, 0x1e, 0x8f, 0xd1, 0x88, 0x07, 0x62,
0x91, 0x54, 0x9f, 0x29, 0xb2, 0xa1, 0x0f, 0x93, 0x32, 0x22, 0x9f, 0xf2, 0x0d, 0x79, 0xab, 0x00, 0xca, 0x33, 0x5b, 0xbe, 0x15, 0x1f, 0x58, 0x6e, 0xe5, 0x5a, 0xb4, 0x63, 0xc0, 0xcd, 0x5f, 0x82,
0xdb, 0x94, 0x10, 0x19, 0x3f, 0x4e, 0x89, 0x8c, 0xc5, 0xac, 0x44, 0x09, 0x09, 0xb2, 0x03, 0x1b, 0x95, 0x0c, 0xb4, 0x8c, 0x3b, 0x2f, 0x1f, 0xc5, 0x2d, 0x5e, 0xb7, 0x62, 0x35, 0xc7, 0x8b, 0xd0,
0x91, 0xe7, 0x6c, 0xbc, 0xcc, 0x52, 0x56, 0xf2, 0x35, 0x45, 0x7d, 0xa0, 0x17, 0xfe, 0x04, 0x5a, 0xad, 0xf7, 0x5b, 0xb0, 0x20, 0xb4, 0xbd, 0x4d, 0x28, 0xc8, 0x6b, 0x4f, 0x45, 0x93, 0xfd, 0x24,
0x51, 0x36, 0x89, 0x6a, 0x2c, 0x64, 0xe5, 0xb3, 0xae, 0xc8, 0xcd, 0x58, 0x7d, 0xbe, 0x0f, 0x9b, 0x04, 0x8a, 0xd3, 0xc8, 0x01, 0x1b, 0x7f, 0x1b, 0x1b, 0xea, 0x02, 0x63, 0x62, 0x82, 0x7e, 0xa5,
0xb1, 0xfe, 0x8a, 0x57, 0xa9, 0x9c, 0x95, 0xd5, 0x86, 0xd6, 0x81, 0xb1, 0x4a, 0x1d, 0xc0, 0xad, 0x08, 0xeb, 0xc9, 0x14, 0x75, 0x25, 0xa1, 0x1c, 0x9b, 0x1b, 0x6e, 0x49, 0x14, 0x20, 0xf2, 0x49,
0x58, 0x5e, 0x89, 0x7a, 0x55, 0xb2, 0x32, 0x6b, 0x69, 0x99, 0xc5, 0x6a, 0x66, 0xfc, 0xf6, 0x02, 0x62, 0xbb, 0xc5, 0x66, 0x07, 0x51, 0xf5, 0xad, 0x25, 0x87, 0xfc, 0x61, 0x92, 0xa9, 0xe6, 0x34,
0x90, 0x1f, 0xcc, 0xa9, 0x7f, 0x85, 0x37, 0x6e, 0x83, 0x97, 0x5d, 0x09, 0x90, 0x8a, 0xb7, 0xfc, 0xa2, 0x21, 0x2f, 0x68, 0x60, 0x9f, 0x12, 0x3c, 0xf6, 0x27, 0x29, 0x1e, 0xbb, 0x98, 0x95, 0x29,
0x2b, 0x5d, 0xbc, 0xcf, 0xba, 0xf8, 0x5e, 0x7c, 0xf9, 0xc5, 0xf7, 0xd2, 0xcb, 0x2e, 0xbe, 0xbf, 0xc1, 0x72, 0x77, 0x60, 0x23, 0x72, 0x35, 0x8e, 0xd7, 0x59, 0xca, 0xca, 0xbe, 0xa6, 0xb0, 0x0f,
0x09, 0x0d, 0xe7, 0xcc, 0xf5, 0xd8, 0xbe, 0xc6, 0x8e, 0x35, 0x41, 0x6b, 0xe1, 0x6e, 0xe1, 0x5e, 0xf4, 0xca, 0x1f, 0x43, 0x2b, 0x2a, 0x26, 0xd1, 0x8c, 0x85, 0xac, 0x72, 0xd6, 0x15, 0xba, 0x19,
0xdd, 0xac, 0x0b, 0x20, 0x3b, 0xd4, 0x04, 0xe4, 0x71, 0x44, 0x44, 0xc7, 0x67, 0x18, 0xfc, 0x41, 0x6b, 0xcf, 0x0f, 0x60, 0x33, 0x36, 0x5e, 0xf1, 0x26, 0x95, 0xb3, 0x8a, 0xda, 0xd0, 0x06, 0x30,
0xdf, 0xd1, 0x3a, 0xe3, 0x33, 0x2a, 0xf4, 0x8c, 0x38, 0x61, 0x65, 0x62, 0x06, 0x0f, 0xc8, 0x5b, 0xd6, 0xa8, 0x03, 0xb8, 0x15, 0x2b, 0x2b, 0xd1, 0xae, 0x4a, 0x56, 0x61, 0x2d, 0xad, 0xb0, 0x58,
0xb0, 0x18, 0x78, 0x73, 0x76, 0x4a, 0x94, 0xdd, 0xc0, 0xcd, 0xd7, 0x75, 0x0e, 0x3d, 0x92, 0xce, 0xcb, 0x8c, 0xdf, 0x59, 0x00, 0xf2, 0xc3, 0x39, 0xf5, 0xaf, 0xf0, 0x5a, 0x73, 0xf0, 0xaa, 0x3b,
0x0c, 0x2b, 0xf3, 0x80, 0x5a, 0x53, 0x27, 0x08, 0x98, 0xac, 0x3d, 0xf2, 0xdc, 0xd0, 0xf7, 0x26, 0x14, 0x52, 0x53, 0x99, 0x7f, 0xad, 0xe8, 0x06, 0x59, 0xd1, 0x05, 0x8a, 0xaf, 0x8e, 0x2e, 0x50,
0xc2, 0x22, 0xbd, 0x3c, 0x0f, 0xe8, 0x21, 0xc7, 0xec, 0x70, 0x04, 0xf9, 0x38, 0xaa, 0xd2, 0xcc, 0x7a, 0x55, 0x74, 0x81, 0xb7, 0xa1, 0xe1, 0x9c, 0xb9, 0x1e, 0x63, 0x04, 0x98, 0x1c, 0x18, 0xb4,
0x76, 0xfc, 0xa0, 0x05, 0x58, 0x25, 0xd9, 0x52, 0x3c, 0x8c, 0xd9, 0x8e, 0xaf, 0xea, 0xc2, 0x3e, 0x16, 0xee, 0x16, 0xee, 0xd5, 0xcd, 0xba, 0x00, 0x32, 0x29, 0x30, 0x20, 0x5f, 0x46, 0x48, 0x74,
0x82, 0xc4, 0x85, 0xfc, 0x5a, 0xf2, 0x42, 0xfe, 0x2f, 0x65, 0x5f, 0xc8, 0xe7, 0x5e, 0x79, 0x0f, 0x7c, 0x86, 0xb1, 0x37, 0x74, 0x16, 0xa0, 0x33, 0x3e, 0xa3, 0x42, 0x31, 0x8b, 0x0b, 0x56, 0x66,
0x44, 0xd6, 0xe9, 0x21, 0xfe, 0x5a, 0xf7, 0xf2, 0xd3, 0x71, 0x06, 0x16, 0xbf, 0x4e, 0x9c, 0x81, 0x66, 0xf0, 0x80, 0xbc, 0x03, 0x8b, 0x81, 0x37, 0x67, 0x62, 0xb5, 0x1c, 0x06, 0x6e, 0xef, 0xaf,
0xa5, 0xac, 0x38, 0x03, 0x1f, 0x42, 0x0d, 0xaf, 0x77, 0x5b, 0xe7, 0xe8, 0x9b, 0xcb, 0x2d, 0xec, 0x73, 0xe8, 0x91, 0xf4, 0xfe, 0x58, 0x99, 0x07, 0xd4, 0x9a, 0x3a, 0x41, 0xc0, 0x84, 0x93, 0x91,
0x4d, 0xfd, 0xfe, 0xf7, 0xbe, 0xe3, 0x86, 0x26, 0xf8, 0xf2, 0x67, 0x90, 0xbe, 0xf2, 0xbf, 0xfc, 0xe7, 0x86, 0xbe, 0x37, 0x11, 0x26, 0xfc, 0xe5, 0x79, 0x40, 0x0f, 0x79, 0xca, 0x0e, 0x4f, 0x20,
0x4a, 0x57, 0xfe, 0xbf, 0x99, 0xfb, 0xfc, 0xe2, 0x1a, 0xfa, 0x16, 0x54, 0xe4, 0x38, 0x31, 0x66, 0x9f, 0x44, 0x4d, 0x9a, 0xd9, 0x8e, 0x1f, 0xb4, 0x00, 0x9b, 0x24, 0x7b, 0x8a, 0xd2, 0xab, 0xed,
0x7b, 0xea, 0x7b, 0x53, 0x69, 0xad, 0x63, 0xbf, 0xc9, 0x22, 0xe4, 0x43, 0x4f, 0x24, 0xce, 0x87, 0xf8, 0xaa, 0x2d, 0xec, 0x23, 0x48, 0x44, 0x3d, 0xa8, 0x25, 0xa3, 0x1e, 0xfc, 0x72, 0x76, 0xd4,
0x9e, 0xf1, 0x0b, 0x50, 0xd3, 0xa6, 0x1a, 0x79, 0x83, 0xab, 0xa9, 0xd9, 0x41, 0x5b, 0x1c, 0x14, 0x83, 0x46, 0x8c, 0x98, 0xa5, 0xa7, 0xf8, 0x6b, 0x05, 0x3f, 0x48, 0x07, 0x73, 0x58, 0xfc, 0x3a,
0x78, 0x2f, 0x56, 0x05, 0xb4, 0x3b, 0x66, 0x9b, 0xc7, 0xd8, 0xf1, 0x29, 0x06, 0xe7, 0xb0, 0x7c, 0xc1, 0x1c, 0x96, 0xb2, 0x82, 0x39, 0x7c, 0x04, 0x35, 0xbc, 0x43, 0x6f, 0x9d, 0xa3, 0x33, 0x33,
0x7a, 0x41, 0xfd, 0x40, 0x5a, 0x59, 0x9b, 0x0a, 0x61, 0x72, 0xb8, 0xf1, 0x8b, 0xb0, 0x12, 0x1b, 0x77, 0x49, 0x68, 0xea, 0x97, 0xec, 0xf7, 0x1d, 0x37, 0x34, 0xc1, 0x97, 0x3f, 0x83, 0x74, 0x5c,
0x5b, 0xc1, 0xbe, 0xdf, 0x82, 0x05, 0xec, 0x37, 0xe9, 0xca, 0x13, 0xbf, 0x57, 0x2f, 0x70, 0x18, 0x85, 0xe5, 0xd7, 0x8a, 0xab, 0xf0, 0xcd, 0x04, 0x4d, 0x10, 0x77, 0xfd, 0xb7, 0xa0, 0x22, 0xe7,
0x88, 0x84, 0x1b, 0x88, 0xad, 0x99, 0xef, 0x9d, 0x60, 0x21, 0x39, 0xb3, 0x26, 0x60, 0x47, 0xbe, 0x89, 0x11, 0xdb, 0x53, 0xdf, 0x9b, 0x4a, 0xf3, 0x26, 0xfb, 0x4d, 0x16, 0x21, 0x1f, 0x7a, 0x22,
0x77, 0x62, 0xfc, 0x87, 0x02, 0x14, 0xf6, 0xbd, 0x99, 0xee, 0xcf, 0x9b, 0x4b, 0xf9, 0xf3, 0x0a, 0x73, 0x3e, 0xf4, 0x8c, 0x5f, 0x84, 0x9a, 0xb6, 0xd4, 0xc8, 0x5b, 0x5c, 0xaf, 0xef, 0xd2, 0x89,
0xed, 0x81, 0xa5, 0xb4, 0x03, 0xe2, 0x00, 0x86, 0x26, 0x4f, 0xa9, 0x21, 0xb8, 0x07, 0x8b, 0x8c, 0x54, 0xfb, 0xf2, 0x51, 0xac, 0x0a, 0x68, 0x77, 0xcc, 0xce, 0xbd, 0xb1, 0xe3, 0x53, 0x8c, 0x80,
0x4f, 0x84, 0x9e, 0x25, 0xee, 0xd1, 0xf0, 0x1d, 0x8e, 0x2f, 0x3e, 0x7b, 0x1a, 0x0e, 0xbd, 0x3d, 0x62, 0xf9, 0xf4, 0x82, 0xfa, 0x81, 0x34, 0x4b, 0x37, 0x55, 0x82, 0xc9, 0xe1, 0xc6, 0x2f, 0xc1,
0x0e, 0x27, 0xab, 0x50, 0x50, 0x67, 0x51, 0x44, 0xb3, 0x4f, 0xb2, 0x0e, 0x0b, 0x78, 0xff, 0x47, 0x4a, 0x6c, 0x6e, 0x05, 0xf9, 0x7e, 0x07, 0x16, 0x70, 0xdc, 0xa4, 0xef, 0x53, 0x3c, 0x78, 0x81,
0x5e, 0xc2, 0x16, 0x5f, 0xe4, 0x7d, 0x58, 0x89, 0xe7, 0xcb, 0x59, 0x91, 0x10, 0x74, 0xf5, 0x8c, 0x48, 0xc3, 0x38, 0x30, 0xdc, 0xa2, 0x6e, 0xcd, 0x7c, 0xef, 0x04, 0x2b, 0xc9, 0x99, 0x35, 0x01,
0x91, 0x27, 0xdd, 0x04, 0xc6, 0x47, 0xa2, 0x6b, 0xd8, 0x05, 0xb3, 0x7c, 0x4a, 0x29, 0xa2, 0x34, 0x3b, 0xf2, 0xbd, 0x13, 0xe3, 0xdf, 0x17, 0xa0, 0xb0, 0xef, 0xcd, 0x74, 0x07, 0xe8, 0x5c, 0xca,
0xa6, 0x57, 0x89, 0x31, 0xbd, 0x3b, 0x50, 0x0b, 0x27, 0x17, 0xd6, 0xcc, 0xbe, 0x9a, 0x78, 0xb6, 0x01, 0x5a, 0xa8, 0x5b, 0x2c, 0xa5, 0x4e, 0x11, 0x12, 0x2b, 0xda, 0x88, 0xa5, 0x4a, 0xe5, 0x1e,
0xbc, 0xf4, 0x07, 0xe1, 0xe4, 0xe2, 0x88, 0x43, 0xc8, 0x07, 0x00, 0xd3, 0xd9, 0x4c, 0xac, 0x3d, 0x2c, 0x32, 0x3a, 0x11, 0x7a, 0x96, 0xb8, 0x78, 0xc4, 0x0f, 0x67, 0xbe, 0xf9, 0xec, 0x69, 0x38,
0x34, 0xcf, 0x45, 0x53, 0xf9, 0xf0, 0xe8, 0x88, 0x4f, 0x39, 0xb3, 0x3a, 0x9d, 0xcd, 0xf8, 0x4f, 0xf4, 0xf6, 0x38, 0x9c, 0xac, 0x42, 0x41, 0x09, 0xef, 0x98, 0xcc, 0x3e, 0xc9, 0x3a, 0x2c, 0xe0,
0xb2, 0x0b, 0x8b, 0x99, 0x01, 0x34, 0x6e, 0xcb, 0x5b, 0x12, 0xde, 0x6c, 0x2b, 0x63, 0x71, 0x36, 0x85, 0x29, 0x79, 0xd3, 0x5d, 0x7c, 0x91, 0x0f, 0x60, 0x25, 0x5e, 0x2e, 0x27, 0x45, 0x42, 0x32,
0x46, 0x3a, 0x6c, 0xf3, 0x7b, 0x40, 0xfe, 0x94, 0x31, 0x2a, 0x86, 0x50, 0x55, 0xf5, 0x4b, 0x45, 0xd0, 0x0b, 0x46, 0x9a, 0x74, 0x13, 0x18, 0x1d, 0x89, 0xee, 0xba, 0x17, 0xcc, 0xf2, 0x29, 0xa5,
0xc6, 0xa8, 0xa5, 0x22, 0x63, 0x30, 0xbe, 0xc8, 0xa5, 0x1f, 0xc5, 0xf2, 0x41, 0x13, 0x7f, 0xc4, 0x98, 0xa4, 0x11, 0xbd, 0x4a, 0x8c, 0xe8, 0xdd, 0x81, 0x5a, 0x38, 0xb9, 0xb0, 0x66, 0xf6, 0xd5,
0xfd, 0x22, 0xe3, 0x3f, 0xe7, 0xa0, 0xc4, 0xe3, 0x4d, 0xbc, 0x0d, 0x4b, 0x9c, 0x5e, 0xf9, 0x46, 0xc4, 0xb3, 0xe5, 0xcd, 0x4a, 0x08, 0x27, 0x17, 0x47, 0x1c, 0x42, 0x3e, 0x04, 0x98, 0xce, 0x66,
0x0b, 0x07, 0x16, 0x2e, 0x44, 0x0d, 0x85, 0x5b, 0x34, 0x5b, 0x16, 0x5a, 0x98, 0x9e, 0x48, 0x8c, 0x62, 0xef, 0xa1, 0x3d, 0x33, 0x5a, 0xca, 0x87, 0x47, 0x47, 0x7c, 0xc9, 0x99, 0xd5, 0xe9, 0x6c,
0xd0, 0x42, 0xf5, 0xdc, 0x81, 0xaa, 0x2a, 0x5a, 0x9b, 0x3a, 0x15, 0x59, 0x32, 0x79, 0x1d, 0x8a, 0xc6, 0x7f, 0x92, 0x5d, 0x58, 0xcc, 0x8c, 0x52, 0x72, 0x5b, 0x5e, 0x2b, 0xf1, 0x66, 0x5b, 0x19,
0xe7, 0xde, 0x4c, 0xaa, 0xf1, 0x20, 0xea, 0x49, 0x13, 0xe1, 0x51, 0x5d, 0x58, 0x19, 0xd1, 0xbd, 0x9b, 0xb3, 0x31, 0xd2, 0x61, 0x9b, 0xdf, 0x07, 0xf2, 0x67, 0x0c, 0x04, 0x32, 0x84, 0xaa, 0x6a,
0xa7, 0x82, 0xa8, 0x0b, 0x2b, 0x44, 0xde, 0xc2, 0x4f, 0xb4, 0x71, 0x21, 0xa3, 0x8d, 0xc7, 0xb0, 0x5f, 0x2a, 0xfc, 0x48, 0x2d, 0x15, 0x7e, 0x84, 0xd1, 0x45, 0xce, 0xb8, 0x29, 0x92, 0x0f, 0x1a,
0xc4, 0xf8, 0x80, 0xe6, 0x45, 0x73, 0xfd, 0xa6, 0xf9, 0x6d, 0x26, 0xae, 0x8f, 0x26, 0xf3, 0x31, 0xe7, 0x26, 0x2e, 0x64, 0x19, 0xff, 0x29, 0x07, 0x25, 0x1e, 0xd4, 0xe3, 0x5d, 0x58, 0xe2, 0xf8,
0xd5, 0x15, 0xa9, 0xe8, 0xe8, 0x2a, 0xe0, 0xf2, 0x98, 0x64, 0xfc, 0x76, 0x8e, 0xf3, 0x17, 0x96, 0xca, 0x99, 0x5c, 0x78, 0xfc, 0x70, 0xfe, 0x6f, 0x28, 0xfc, 0xc8, 0xd9, 0xb6, 0xd0, 0xa2, 0x24,
0x2f, 0xb9, 0x07, 0x45, 0x57, 0x7a, 0xdc, 0x44, 0x42, 0xb9, 0xba, 0x23, 0xc8, 0xe8, 0x4c, 0xa4, 0x45, 0x6c, 0x84, 0x16, 0x29, 0xe9, 0x0e, 0x54, 0x55, 0xd5, 0xda, 0xd2, 0xa9, 0xc8, 0x9a, 0xc9,
0x60, 0x43, 0x87, 0x7e, 0x2a, 0x7a, 0xee, 0x0d, 0xb3, 0xe6, 0xce, 0xa7, 0x4a, 0x0f, 0xf9, 0x2d, 0x9b, 0x50, 0x3c, 0xf7, 0x66, 0x52, 0xef, 0x09, 0xd1, 0x48, 0x9a, 0x08, 0x8f, 0xda, 0xc2, 0xea,
0xd9, 0xac, 0x84, 0x0e, 0x8f, 0xb7, 0x5e, 0x2d, 0xd3, 0x2d, 0xcd, 0x63, 0xb6, 0x18, 0xdb, 0x31, 0x88, 0x2e, 0x8a, 0x15, 0x44, 0x5b, 0x58, 0x25, 0x32, 0xd4, 0x41, 0xa2, 0x8f, 0x0b, 0x19, 0x7d,
0xa5, 0x48, 0x3f, 0x3e, 0xa3, 0x9a, 0xa7, 0xec, 0xef, 0xe5, 0xa1, 0x11, 0xab, 0x11, 0xba, 0x0c, 0x3c, 0x86, 0x25, 0x46, 0x07, 0x34, 0xb7, 0xa3, 0xeb, 0x0f, 0xcd, 0x6f, 0x33, 0xf9, 0x66, 0x34,
0xb3, 0x0d, 0x80, 0xdb, 0x19, 0xc5, 0x78, 0xa3, 0x67, 0xa6, 0x38, 0x75, 0x69, 0xfd, 0x94, 0x8f, 0x99, 0x8f, 0xa9, 0xae, 0x79, 0x46, 0xcf, 0x60, 0x01, 0x97, 0x72, 0xa5, 0xf1, 0x3b, 0x39, 0x4e,
0xf5, 0x93, 0x72, 0x99, 0x2b, 0xe8, 0x2e, 0x73, 0x0f, 0xa0, 0x1a, 0x85, 0x67, 0x8a, 0x57, 0x89, 0x5f, 0x58, 0xb9, 0xe4, 0x1e, 0x14, 0x5d, 0xe9, 0xa2, 0x14, 0x49, 0x31, 0xea, 0x52, 0x25, 0xc3,
0x95, 0x27, 0x6f, 0x4a, 0x46, 0x44, 0x91, 0x93, 0x5d, 0x49, 0x77, 0xb2, 0xfb, 0xae, 0xe6, 0x93, 0x33, 0x11, 0x83, 0x4d, 0x1d, 0x3a, 0xf6, 0xe8, 0xa5, 0x37, 0xcc, 0x9a, 0x3b, 0x9f, 0x2a, 0xc5,
0xb5, 0x80, 0xd9, 0x18, 0x59, 0x3d, 0xfa, 0x53, 0xf1, 0xc8, 0x32, 0x1e, 0x43, 0x4d, 0xab, 0xbc, 0xed, 0xb7, 0x64, 0xb7, 0x12, 0x4a, 0x4f, 0xde, 0x7b, 0xb5, 0x4d, 0xb7, 0x34, 0x17, 0xe3, 0x62,
0xee, 0xd7, 0x94, 0x8b, 0xf9, 0x35, 0xa9, 0xbb, 0xd5, 0xf9, 0xe8, 0x6e, 0xb5, 0xf1, 0xab, 0x79, 0xec, 0xc4, 0x94, 0x32, 0xd0, 0xf8, 0x8c, 0x6a, 0xae, 0xc5, 0xbf, 0x9f, 0x87, 0x46, 0xac, 0x45,
0x68, 0xb0, 0xf5, 0xe5, 0xb8, 0x67, 0x47, 0xde, 0xc4, 0x19, 0xa1, 0xdd, 0x51, 0xad, 0x30, 0x21, 0xe8, 0x63, 0xcd, 0x0e, 0x00, 0x6e, 0x98, 0x15, 0xf3, 0x8d, 0xae, 0xac, 0x42, 0x4c, 0xd5, 0xc6,
0x68, 0xc9, 0x75, 0x26, 0x96, 0x18, 0x97, 0xb3, 0xf4, 0x80, 0x20, 0x9c, 0x49, 0xab, 0x80, 0x20, 0x29, 0x1f, 0x1b, 0x27, 0xe5, 0x63, 0x58, 0xd0, 0x7d, 0x0c, 0x1f, 0x40, 0x35, 0x8a, 0x8e, 0x15,
0x06, 0x34, 0x18, 0x63, 0x44, 0x0b, 0x62, 0x14, 0xe4, 0xc9, 0xac, 0x9d, 0x52, 0xba, 0x6d, 0x07, 0x6f, 0x12, 0xab, 0x4f, 0x5e, 0x2d, 0x8d, 0x90, 0x22, 0xaf, 0xc4, 0x92, 0xee, 0x95, 0xf8, 0x3d,
0x9c, 0x43, 0xbe, 0x0f, 0x2b, 0x8c, 0x06, 0x6f, 0xfb, 0x4f, 0x9d, 0xc9, 0xc4, 0x89, 0x2e, 0x1a, 0xcd, 0x89, 0x6d, 0x01, 0x8b, 0x31, 0xb2, 0x46, 0xf4, 0xa7, 0xe2, 0xc2, 0x66, 0x7c, 0x09, 0x35,
0x16, 0xcc, 0xe6, 0x29, 0xa5, 0xa6, 0x1d, 0xd2, 0x43, 0x86, 0x10, 0x31, 0xa1, 0x2a, 0x63, 0x27, 0xad, 0xf1, 0xba, 0x23, 0x58, 0x2e, 0xe6, 0x08, 0xa6, 0x2e, 0xb0, 0xe7, 0xa3, 0x0b, 0xec, 0xc6,
0xb0, 0x4f, 0x22, 0xc7, 0x6e, 0xf5, 0x2d, 0x0d, 0xf3, 0x91, 0xef, 0x83, 0xf0, 0xdb, 0x11, 0xa1, 0xaf, 0xe5, 0xa1, 0xc1, 0xf6, 0x97, 0xe3, 0x9e, 0x1d, 0x79, 0x13, 0x67, 0x84, 0x86, 0x5a, 0xb5,
0x2e, 0x30, 0x7d, 0x62, 0x26, 0x95, 0x93, 0x33, 0xc9, 0xf8, 0x47, 0x79, 0xa8, 0x69, 0xd3, 0xf2, 0xc3, 0x04, 0xa3, 0x25, 0xf7, 0x99, 0xd8, 0x62, 0x9c, 0xcf, 0xd2, 0xa3, 0xae, 0x70, 0x22, 0xad,
0x55, 0x76, 0xd7, 0xdb, 0x29, 0x3b, 0x71, 0x55, 0x37, 0x09, 0xbf, 0x19, 0x2f, 0xb2, 0xa0, 0x6e, 0xa2, 0xae, 0x18, 0xd0, 0x60, 0x84, 0x11, 0x4d, 0xae, 0x51, 0x24, 0x2d, 0xb3, 0x76, 0x4a, 0xe9,
0xa3, 0xe9, 0x13, 0xf8, 0x16, 0x54, 0xd9, 0xaa, 0xfb, 0x10, 0xf5, 0xe9, 0x22, 0x26, 0x1b, 0x02, 0xb6, 0x1d, 0x70, 0x0a, 0xf9, 0x01, 0xac, 0x30, 0x1c, 0x0c, 0xa9, 0x30, 0x75, 0x26, 0x13, 0x27,
0x8e, 0xe6, 0x27, 0x12, 0xf9, 0x10, 0x91, 0xa5, 0x08, 0xf9, 0x90, 0x21, 0x5f, 0x74, 0x1b, 0xe5, 0xba, 0x99, 0x59, 0x30, 0x9b, 0xa7, 0x94, 0x9a, 0x76, 0x48, 0x0f, 0x59, 0x82, 0x08, 0xbc, 0x55,
0x53, 0xa8, 0x8b, 0x5c, 0x71, 0x4c, 0xc5, 0xb1, 0x60, 0x55, 0xdb, 0xb9, 0xd5, 0x78, 0x9b, 0x35, 0x19, 0x3b, 0x81, 0x7d, 0x12, 0x79, 0xc2, 0xab, 0x6f, 0xe9, 0xc9, 0x10, 0x39, 0x8b, 0x08, 0x47,
0x5e, 0x1c, 0x1f, 0x7c, 0x91, 0xf0, 0xa1, 0x4c, 0x58, 0x79, 0x59, 0xc2, 0x87, 0xfc, 0xc3, 0xd8, 0x27, 0x11, 0x4f, 0x04, 0xf3, 0x27, 0x56, 0x52, 0x39, 0xb9, 0x92, 0x8c, 0x7f, 0x98, 0x87, 0x9a,
0x53, 0x17, 0x7c, 0xd0, 0x1b, 0x52, 0xf2, 0xb1, 0x0f, 0x60, 0x45, 0xb2, 0xab, 0xb9, 0x6b, 0xbb, 0xb6, 0x2c, 0x5f, 0xe7, 0x74, 0xbd, 0x9d, 0x32, 0xac, 0x57, 0x75, 0x1b, 0xfa, 0xdb, 0xf1, 0x2a,
0xae, 0x37, 0x77, 0x47, 0x54, 0x5e, 0x76, 0x26, 0x02, 0x75, 0x1c, 0x61, 0x8c, 0xb1, 0x0a, 0x23, 0x0b, 0xea, 0xfa, 0x9e, 0xbe, 0x80, 0x6f, 0x41, 0x95, 0xed, 0xba, 0x8f, 0xd0, 0x00, 0x21, 0x42,
0xc2, 0xbd, 0x2a, 0xef, 0x43, 0x89, 0xcb, 0xe5, 0x5c, 0xf8, 0xc8, 0x66, 0x5c, 0x9c, 0x84, 0xdc, 0xe2, 0x21, 0xe0, 0x68, 0x7e, 0x22, 0x13, 0x1f, 0x62, 0x62, 0x29, 0x4a, 0x7c, 0xc8, 0x12, 0x5f,
0x83, 0x12, 0x17, 0xcf, 0xf3, 0xd7, 0x32, 0x1b, 0x4e, 0x60, 0xb4, 0x81, 0xb0, 0x84, 0x87, 0x34, 0x76, 0x7d, 0xe7, 0x33, 0xa8, 0x8b, 0x52, 0x71, 0x4e, 0x85, 0x58, 0xb0, 0xaa, 0x9d, 0xdc, 0x6a,
0xf4, 0x9d, 0x51, 0x10, 0xdd, 0xa3, 0x2e, 0x85, 0x57, 0x33, 0x51, 0x56, 0xa4, 0x86, 0x8f, 0x28, 0xbe, 0xcd, 0x1a, 0xaf, 0x8e, 0x4f, 0xbe, 0xc8, 0xf8, 0x50, 0x66, 0xac, 0xbc, 0x2a, 0xe3, 0x43,
0x51, 0xe1, 0xc0, 0x69, 0xd8, 0xc6, 0xb4, 0x12, 0xcb, 0x43, 0x88, 0x4b, 0x13, 0x58, 0x3f, 0xa1, 0xfe, 0x61, 0xec, 0xa9, 0x1b, 0x51, 0xe8, 0x3e, 0x2a, 0xe9, 0xd8, 0x87, 0xb0, 0x22, 0xc9, 0xd5,
0xe1, 0x73, 0x4a, 0x5d, 0x97, 0x09, 0x43, 0x23, 0xea, 0x86, 0xbe, 0x3d, 0x61, 0x83, 0xc4, 0x5b, 0xdc, 0xb5, 0x5d, 0xd7, 0x9b, 0xbb, 0x23, 0x2a, 0x6f, 0x87, 0x13, 0x91, 0x74, 0x1c, 0xa5, 0x18,
0xf0, 0x28, 0x95, 0x6b, 0xa4, 0xd0, 0xda, 0x8e, 0x12, 0xee, 0xa8, 0x74, 0x9c, 0x77, 0xac, 0x9d, 0x63, 0x15, 0xab, 0x85, 0xbb, 0xa1, 0xde, 0x87, 0x12, 0xe7, 0xcb, 0x39, 0xf3, 0x91, 0x4d, 0xb8,
0x64, 0xe1, 0x36, 0x7f, 0x1e, 0x36, 0xaf, 0x4f, 0x94, 0x11, 0xb5, 0xe1, 0x5e, 0x9c, 0xab, 0x28, 0x38, 0x0a, 0xb9, 0x07, 0x25, 0xce, 0x9e, 0xe7, 0xaf, 0x25, 0x36, 0x1c, 0xc1, 0x68, 0x03, 0x61,
0xa3, 0xee, 0xc4, 0xb3, 0x43, 0x5e, 0x1b, 0x9d, 0xb3, 0xf4, 0xa0, 0xa6, 0x61, 0xa2, 0xbd, 0x3f, 0x19, 0x0f, 0x69, 0xe8, 0x3b, 0xa3, 0x20, 0xba, 0x78, 0x5e, 0x0a, 0xaf, 0x66, 0xa2, 0xae, 0xc8,
0x87, 0xc2, 0x1d, 0xff, 0x60, 0x3b, 0x92, 0xeb, 0xf9, 0x53, 0x34, 0xa2, 0x8e, 0xad, 0x28, 0xf7, 0x6e, 0x11, 0x61, 0xa2, 0x86, 0x86, 0xe3, 0xb0, 0x83, 0x69, 0x25, 0x56, 0x86, 0x60, 0x97, 0x26,
0x9c, 0xb9, 0x14, 0xc1, 0xd1, 0xef, 0xc6, 0xd8, 0x82, 0x25, 0x94, 0xec, 0xb5, 0x8d, 0xee, 0x45, 0xb0, 0x7e, 0x42, 0xc3, 0x17, 0x94, 0xba, 0x2e, 0x63, 0x86, 0x46, 0xd4, 0x0d, 0x7d, 0x7b, 0xc2,
0xc2, 0xa0, 0xb1, 0x0a, 0xa4, 0xc7, 0x79, 0x97, 0xee, 0x61, 0xfa, 0x07, 0x05, 0xa8, 0x69, 0x60, 0x26, 0x89, 0xf7, 0xe0, 0x51, 0xaa, 0xd4, 0x48, 0x03, 0xb8, 0x1d, 0x65, 0xdc, 0x51, 0xf9, 0x38,
0xb6, 0x1b, 0xa1, 0x5b, 0xae, 0x35, 0x76, 0xec, 0x29, 0x95, 0x16, 0xeb, 0x86, 0xd9, 0x40, 0xe8, 0xed, 0x58, 0x3b, 0xc9, 0x4a, 0xdb, 0xfc, 0x05, 0xd8, 0xbc, 0x3e, 0x53, 0x86, 0x9a, 0xe0, 0x5e,
0xae, 0x00, 0xb2, 0xbd, 0xd8, 0xbe, 0x38, 0xb3, 0xbc, 0x79, 0x68, 0x8d, 0xe9, 0x99, 0x4f, 0x65, 0x9c, 0xaa, 0x28, 0x2b, 0xf8, 0xc4, 0xb3, 0x43, 0xde, 0x1a, 0x9d, 0xb2, 0xf4, 0xa0, 0xa6, 0xa5,
0x2d, 0xeb, 0xf6, 0xc5, 0x59, 0x7f, 0x1e, 0xee, 0x22, 0x4c, 0xc6, 0xcd, 0xd1, 0xa8, 0x0a, 0x2a, 0x44, 0x67, 0x7f, 0x0e, 0x99, 0x3b, 0xfe, 0xc1, 0x4e, 0x24, 0xd7, 0xf3, 0xa7, 0x68, 0x75, 0x1e,
0x6e, 0x4e, 0x44, 0x25, 0xdc, 0x99, 0xf9, 0xcc, 0x2c, 0x2a, 0x77, 0x66, 0x7e, 0x5a, 0x4c, 0x6e, 0x5b, 0x51, 0xe9, 0x39, 0x73, 0x29, 0x82, 0xa3, 0xa3, 0x92, 0xb1, 0x05, 0x4b, 0xc8, 0xd9, 0x6b,
0xa0, 0xa5, 0xf4, 0x06, 0xfa, 0x31, 0xac, 0xf3, 0x0d, 0x54, 0xb0, 0x66, 0x2b, 0xb1, 0x92, 0x57, 0x07, 0xdd, 0xcb, 0x98, 0x41, 0x63, 0x15, 0x48, 0x8f, 0xd3, 0x2e, 0xdd, 0x25, 0xf7, 0x0f, 0x0b,
0x11, 0x2b, 0x1a, 0xa9, 0x89, 0xbd, 0x4d, 0xd6, 0x02, 0xc9, 0x96, 0x02, 0xe7, 0xc7, 0x9c, 0x91, 0x50, 0xd3, 0xc0, 0xec, 0x34, 0x42, 0x3f, 0x66, 0x6b, 0xec, 0xd8, 0x53, 0x2a, 0x4d, 0xfc, 0x0d,
0xe5, 0x4c, 0xd6, 0x32, 0x91, 0xf9, 0xc0, 0xf9, 0x31, 0x95, 0x71, 0x7b, 0x62, 0x94, 0xe2, 0xae, 0xb3, 0x81, 0xd0, 0x5d, 0x01, 0x64, 0x67, 0xb1, 0x7d, 0x71, 0x66, 0x79, 0xf3, 0xd0, 0x1a, 0xd3,
0xd9, 0xd4, 0x71, 0x93, 0x94, 0xf6, 0x65, 0x9c, 0xb2, 0x2a, 0x28, 0xed, 0x4b, 0x9d, 0xf2, 0x11, 0x33, 0x9f, 0xca, 0x56, 0xd6, 0xed, 0x8b, 0xb3, 0xfe, 0x3c, 0xdc, 0x45, 0x98, 0x0c, 0x4e, 0xa4,
0x6c, 0x4c, 0xe9, 0xd8, 0xb1, 0xe3, 0xd9, 0x5a, 0x91, 0xe0, 0xb6, 0xca, 0xd1, 0x5a, 0x9a, 0x01, 0x61, 0x15, 0x54, 0x70, 0xa2, 0x08, 0x4b, 0xf8, 0x7f, 0xf3, 0x95, 0x59, 0x54, 0xfe, 0xdf, 0x5c,
0x3f, 0xb8, 0xb3, 0xde, 0xf8, 0xb1, 0x37, 0x3d, 0x71, 0xb8, 0xcc, 0xc2, 0x3d, 0xca, 0x8a, 0xe6, 0x5a, 0x4c, 0x1e, 0xa0, 0xa5, 0xf4, 0x01, 0xfa, 0x09, 0xac, 0xf3, 0x03, 0x54, 0x90, 0x66, 0x2b,
0xa2, 0x3b, 0x9f, 0xfe, 0x10, 0xc1, 0x2c, 0x49, 0x60, 0x34, 0xa0, 0x36, 0x08, 0xbd, 0x99, 0x1c, 0xb1, 0x93, 0x57, 0x31, 0x55, 0x74, 0x52, 0x63, 0x7b, 0x9b, 0xac, 0x07, 0x92, 0x2c, 0x05, 0xce,
0xe6, 0x45, 0xa8, 0xf3, 0x4f, 0x11, 0x27, 0xe0, 0x16, 0xdc, 0x44, 0x96, 0x30, 0xf4, 0x66, 0xde, 0x8f, 0x39, 0x21, 0xcb, 0x99, 0xac, 0x67, 0xa2, 0xf0, 0x81, 0xf3, 0x63, 0x2a, 0x83, 0x23, 0xc5,
0xc4, 0x3b, 0xbb, 0x8a, 0x29, 0x65, 0xff, 0x45, 0x0e, 0x56, 0x62, 0x58, 0xc1, 0x5e, 0x3f, 0xe6, 0x30, 0xc5, 0xe5, 0xbc, 0xa9, 0xe3, 0x26, 0x31, 0xed, 0xcb, 0x38, 0x66, 0x55, 0x60, 0xda, 0x97,
0xfc, 0x4c, 0xdd, 0x31, 0xce, 0xc5, 0x2e, 0x98, 0xb1, 0xf1, 0xe2, 0x84, 0x9c, 0x99, 0xc9, 0x7b, 0x3a, 0xe6, 0x23, 0xd8, 0x98, 0xd2, 0xb1, 0x63, 0xc7, 0x8b, 0xb5, 0x22, 0xc6, 0x6d, 0x95, 0x27,
0xc7, 0xed, 0x28, 0x28, 0x96, 0x4c, 0xc8, 0x59, 0x4a, 0x2b, 0xcd, 0x52, 0x44, 0x7a, 0x19, 0x2e, 0x6b, 0x79, 0x06, 0x5c, 0x70, 0x67, 0xa3, 0xf1, 0x63, 0x6f, 0x7a, 0xe2, 0x70, 0x9e, 0x85, 0xbb,
0x4b, 0x66, 0xf1, 0x33, 0xe2, 0x3e, 0xe0, 0x58, 0x34, 0xb9, 0x10, 0xbf, 0x31, 0xa4, 0x2b, 0x70, 0xe0, 0x15, 0xcd, 0x45, 0x77, 0x3e, 0xfd, 0x79, 0x04, 0xb3, 0x2c, 0x81, 0xd1, 0x80, 0xda, 0x20,
0x65, 0x0d, 0x22, 0xad, 0x6e, 0x60, 0xfc, 0x4e, 0x1e, 0x20, 0xaa, 0x1d, 0xde, 0x59, 0x52, 0x72, 0xf4, 0x66, 0x72, 0x9a, 0x17, 0xa1, 0xce, 0x3f, 0x45, 0x60, 0x85, 0x5b, 0x70, 0x13, 0x49, 0xc2,
0x4b, 0x0e, 0x9d, 0xc3, 0x35, 0x19, 0xe5, 0x0d, 0xa8, 0xab, 0x7b, 0x04, 0x91, 0x24, 0x54, 0x93, 0xd0, 0x9b, 0x79, 0x13, 0xef, 0xec, 0x2a, 0xa6, 0xc5, 0xfe, 0xe7, 0x39, 0x58, 0x89, 0xa5, 0x0a,
0x30, 0x26, 0x0e, 0xbd, 0x0b, 0x4b, 0x67, 0x13, 0xef, 0x04, 0x25, 0x56, 0x21, 0xb7, 0xa0, 0x4b, 0xf2, 0xfa, 0x09, 0xa7, 0x67, 0xea, 0x52, 0x76, 0x2e, 0x76, 0x23, 0x8f, 0xcd, 0x17, 0x47, 0xe4,
0x08, 0xee, 0x47, 0x8b, 0x1c, 0xa5, 0xc2, 0xda, 0x29, 0xd9, 0xa9, 0x98, 0x79, 0xdd, 0x20, 0x26, 0xc4, 0x4c, 0x5e, 0xd4, 0x6e, 0x47, 0x91, 0xc7, 0x64, 0x46, 0x4e, 0x52, 0x5a, 0x69, 0x92, 0x22,
0x09, 0x3d, 0x4e, 0x49, 0x42, 0x77, 0x52, 0x9d, 0xfb, 0xd3, 0x11, 0x83, 0xfe, 0x72, 0x5e, 0xb9, 0xf2, 0xcb, 0x98, 0x64, 0xb2, 0x88, 0x9f, 0x11, 0x17, 0x28, 0xc7, 0xa2, 0xcb, 0x85, 0xf8, 0x15,
0x4e, 0x47, 0xe3, 0xf2, 0xe2, 0xc3, 0xe6, 0x4f, 0xe2, 0xe8, 0xf5, 0x22, 0xcb, 0xf5, 0x63, 0x58, 0x2b, 0x5d, 0xe3, 0x2d, 0x5b, 0x10, 0xa9, 0xc1, 0x03, 0xe3, 0x77, 0xf3, 0x00, 0x51, 0xeb, 0xf0,
0xf4, 0xf9, 0x16, 0x29, 0xf7, 0xcf, 0xe2, 0x0b, 0xf6, 0xcf, 0x86, 0x1f, 0x93, 0xbb, 0xbe, 0x0d, 0x92, 0x97, 0xe2, 0x5b, 0x72, 0xe8, 0x4d, 0xaf, 0xf1, 0x28, 0x6f, 0x41, 0x5d, 0x5d, 0xbc, 0x88,
0x4d, 0x7b, 0x7c, 0x41, 0xfd, 0xd0, 0x41, 0x43, 0x10, 0x4a, 0xeb, 0xc2, 0x51, 0x59, 0x83, 0xa3, 0x38, 0xa1, 0x9a, 0x84, 0x31, 0x76, 0xe8, 0x7d, 0x58, 0x3a, 0x9b, 0x78, 0x27, 0xc8, 0xb1, 0x0a,
0x58, 0xfc, 0x0e, 0x2c, 0x89, 0x48, 0x1a, 0x8a, 0x52, 0x84, 0x8b, 0x8c, 0xc0, 0x8c, 0xd0, 0xf8, 0xbe, 0x05, 0x7d, 0x68, 0xf0, 0x3c, 0x5a, 0xe4, 0x49, 0x2a, 0x76, 0xa0, 0xe2, 0x9d, 0x8a, 0x99,
0x07, 0xd2, 0x57, 0x3b, 0x3e, 0xd7, 0x5e, 0xdc, 0x2b, 0x7a, 0x0b, 0xf3, 0x69, 0xdb, 0xbc, 0x98, 0xf7, 0x33, 0x62, 0x9c, 0xd0, 0x97, 0x29, 0x4e, 0xe8, 0x4e, 0x6a, 0x70, 0x7f, 0x3a, 0x6c, 0xd0,
0xd6, 0xc2, 0xbe, 0x24, 0xb8, 0x23, 0x07, 0x0a, 0xeb, 0x52, 0xbc, 0x5b, 0x8b, 0xaf, 0xd2, 0xad, 0x5f, 0xce, 0x2b, 0x5f, 0xf3, 0x68, 0x5e, 0x5e, 0x2e, 0x6c, 0xfe, 0x24, 0x9e, 0x71, 0x2f, 0x33,
0xc6, 0xbf, 0xcc, 0x41, 0x79, 0xdf, 0x9b, 0xed, 0x3b, 0xfc, 0xc6, 0x0f, 0x2e, 0x5a, 0x65, 0xfe, 0xf5, 0x7f, 0x09, 0x8b, 0x3e, 0x3f, 0x22, 0xe5, 0xf9, 0x59, 0x7c, 0xc9, 0xf9, 0xd9, 0xf0, 0x63,
0x5c, 0x60, 0x9f, 0xe8, 0x95, 0xf6, 0x82, 0x9b, 0xc0, 0x99, 0x42, 0x67, 0x23, 0x2e, 0x74, 0x7e, 0x7c, 0xd7, 0xb7, 0xa1, 0x69, 0x8f, 0x2f, 0xa8, 0x1f, 0x3a, 0x68, 0x39, 0x43, 0x6e, 0x5d, 0x78,
0x17, 0x6e, 0xa1, 0x75, 0xd9, 0xf7, 0x66, 0x9e, 0xcf, 0x18, 0x87, 0x3d, 0xe1, 0xc2, 0xa7, 0xe7, 0x76, 0x6b, 0x70, 0x64, 0x8b, 0xdf, 0x83, 0x25, 0x11, 0x7a, 0x44, 0x61, 0x8a, 0x98, 0x9c, 0x11,
0x86, 0xe7, 0x92, 0x93, 0xdf, 0x3c, 0xa5, 0xf4, 0x48, 0xa3, 0x38, 0x54, 0x04, 0x18, 0x05, 0x60, 0x98, 0x21, 0x1a, 0x7f, 0x5f, 0x3a, 0xb7, 0xc7, 0xd7, 0xda, 0xcb, 0x47, 0x45, 0xef, 0x61, 0x3e,
0x12, 0x5e, 0x58, 0x5c, 0x5f, 0x20, 0xa4, 0x63, 0xce, 0xdf, 0x97, 0x18, 0xa2, 0x83, 0x70, 0x94, 0xed, 0xcc, 0x20, 0x96, 0xb5, 0x30, 0xc8, 0x09, 0xea, 0xc8, 0x81, 0xc2, 0x1c, 0x17, 0x1f, 0xd6,
0x8f, 0x8d, 0xcf, 0xa0, 0xaa, 0x54, 0x4f, 0xe4, 0x5d, 0xa8, 0x9e, 0x7b, 0x33, 0xa1, 0x9f, 0xca, 0xe2, 0xeb, 0x0c, 0xab, 0xf1, 0x2f, 0x72, 0x50, 0xde, 0xf7, 0x66, 0xfb, 0x0e, 0xbf, 0x22, 0x85,
0xc5, 0x6e, 0x4b, 0x8b, 0x56, 0x9b, 0x95, 0x73, 0xfe, 0x23, 0x30, 0xfe, 0x6f, 0x19, 0xca, 0x5d, 0x9b, 0x56, 0xd9, 0x8b, 0x17, 0xd8, 0x27, 0xba, 0xf1, 0xbd, 0xe4, 0xea, 0x74, 0x26, 0xd3, 0xd9,
0xf7, 0xc2, 0x73, 0x46, 0xe8, 0xc5, 0x3d, 0xa5, 0x53, 0x4f, 0x06, 0xfa, 0x61, 0xbf, 0xd1, 0x71, 0x88, 0x33, 0x9d, 0xdf, 0x83, 0x5b, 0x68, 0x8e, 0xf7, 0xbd, 0x99, 0xe7, 0x33, 0xc2, 0x61, 0x4f,
0x30, 0x8a, 0xe8, 0x58, 0x10, 0x8e, 0x83, 0x2a, 0x96, 0xe3, 0x1a, 0x2c, 0xf8, 0x7a, 0x48, 0xc6, 0x38, 0xf3, 0xe9, 0xb9, 0xe1, 0xb9, 0xa4, 0xe4, 0x37, 0x4f, 0x29, 0x3d, 0xd2, 0x30, 0x0e, 0x15,
0x92, 0x8f, 0x77, 0x64, 0xd4, 0xee, 0x5d, 0xd2, 0x02, 0x36, 0xb1, 0xbc, 0xb8, 0xe3, 0x2c, 0x76, 0x02, 0x86, 0x4d, 0x98, 0x84, 0x17, 0x16, 0xd7, 0x17, 0x08, 0xee, 0x98, 0xd3, 0xf7, 0x25, 0x96,
0x19, 0xbf, 0xc9, 0x5f, 0x45, 0x08, 0x76, 0xd8, 0x6b, 0x50, 0x16, 0x5a, 0x68, 0x7e, 0x55, 0x92, 0xd0, 0x41, 0x38, 0xf2, 0xc7, 0xc6, 0xe7, 0x50, 0x55, 0xaa, 0x27, 0xf2, 0x3e, 0x54, 0xcf, 0xbd,
0xeb, 0xee, 0x05, 0x08, 0x67, 0x83, 0x4f, 0xb9, 0x77, 0x80, 0x12, 0xab, 0x0b, 0x66, 0x5d, 0x02, 0x99, 0xd0, 0x4f, 0xe5, 0x62, 0xd7, 0xcb, 0x45, 0xaf, 0xcd, 0xca, 0x39, 0xff, 0x11, 0x18, 0xff,
0x77, 0x6d, 0xee, 0x9a, 0xcd, 0xe9, 0x39, 0x09, 0xdf, 0x86, 0x80, 0x83, 0x90, 0x20, 0x23, 0xf8, 0xa7, 0x0c, 0xe5, 0xae, 0x7b, 0xe1, 0x39, 0x23, 0x74, 0x7b, 0x9f, 0xd2, 0xa9, 0x27, 0xa3, 0x29,
0x69, 0x35, 0x33, 0xf8, 0x29, 0xba, 0xf2, 0x2b, 0x9e, 0xcf, 0x9b, 0x08, 0x3c, 0x9e, 0xa5, 0x06, 0xb1, 0xdf, 0xe8, 0x69, 0x19, 0x85, 0xcd, 0x2c, 0x08, 0x4f, 0x4b, 0x15, 0x30, 0x73, 0x0d, 0x16,
0x97, 0x11, 0x85, 0x85, 0x86, 0x87, 0x07, 0xb9, 0x90, 0x1a, 0x9e, 0x37, 0xa1, 0x71, 0x6a, 0x4f, 0x7c, 0x3d, 0xee, 0x65, 0xc9, 0xc7, 0x4b, 0x45, 0xea, 0xf4, 0x2e, 0x69, 0x51, 0xb1, 0x58, 0x59,
0x26, 0x27, 0xf6, 0xe8, 0x19, 0x57, 0x4c, 0xd4, 0xb9, 0x2e, 0x56, 0x02, 0x51, 0x33, 0x71, 0x07, 0xdc, 0xd3, 0x18, 0x87, 0x8c, 0x87, 0x3e, 0xa8, 0x22, 0x04, 0x07, 0xec, 0x0d, 0x28, 0x0b, 0x2d,
0x6a, 0xda, 0x28, 0xa3, 0xc7, 0x72, 0xd1, 0x84, 0x68, 0x7c, 0x93, 0xfa, 0xc6, 0xc5, 0x57, 0xd0, 0x34, 0xbf, 0x5b, 0xca, 0x75, 0xf7, 0x02, 0x84, 0xab, 0xc1, 0xa7, 0xdc, 0x9d, 0x42, 0xb1, 0xd5,
0x37, 0x6a, 0x9e, 0xdb, 0x4b, 0x71, 0xcf, 0xed, 0x5b, 0xc8, 0xdb, 0x85, 0x3f, 0x6c, 0x93, 0x07, 0x05, 0xb3, 0x2e, 0x81, 0xbb, 0x36, 0xf7, 0x65, 0xe7, 0xf8, 0x1c, 0x85, 0x1f, 0x43, 0xc0, 0x41,
0x4f, 0xb4, 0xc7, 0x63, 0x1e, 0x76, 0xe6, 0x0d, 0xa8, 0x8b, 0xce, 0xe3, 0xf8, 0x65, 0xe1, 0xfa, 0x88, 0x90, 0x11, 0x61, 0xb6, 0x9a, 0x19, 0x61, 0x16, 0xef, 0x3e, 0x28, 0x9a, 0xcf, 0xbb, 0x08,
0x8e, 0x30, 0x4e, 0x72, 0x9b, 0x2b, 0xcd, 0x67, 0xb6, 0x33, 0xc6, 0x8b, 0x49, 0xc2, 0xbe, 0x62, 0x3c, 0x68, 0xa8, 0x06, 0x97, 0x01, 0x9d, 0x85, 0x86, 0x87, 0x47, 0x05, 0x91, 0x1a, 0x9e, 0xb7,
0x4f, 0xc3, 0x23, 0xdb, 0x41, 0x4f, 0x40, 0x89, 0xc6, 0xbd, 0x7a, 0x85, 0xf7, 0xbf, 0x40, 0x0f, 0xa1, 0x71, 0x6a, 0x4f, 0x26, 0x27, 0xf6, 0xe8, 0x39, 0x57, 0x4c, 0xd4, 0xb9, 0x2e, 0x56, 0x02,
0x78, 0x08, 0x17, 0x45, 0x31, 0x55, 0x51, 0x2a, 0xcc, 0x9a, 0x20, 0xc1, 0x79, 0xf0, 0x21, 0x3a, 0x51, 0x33, 0x71, 0x07, 0x6a, 0xda, 0x2c, 0xa3, 0x8b, 0x77, 0xd1, 0x84, 0x68, 0x7e, 0x93, 0xfa,
0x90, 0x85, 0x14, 0xe3, 0x50, 0x2c, 0x3e, 0xbc, 0xa5, 0xfc, 0x5a, 0x70, 0x96, 0xca, 0xff, 0xdc, 0xc6, 0xc5, 0xd7, 0xd0, 0x37, 0x6a, 0xae, 0xee, 0x4b, 0x71, 0x57, 0xf7, 0x5b, 0x48, 0xdb, 0x85,
0xee, 0xca, 0x29, 0x99, 0xa8, 0xc9, 0xcd, 0xbf, 0xeb, 0x31, 0x69, 0x5c, 0x90, 0xa2, 0xf9, 0x97, 0x03, 0x71, 0x93, 0x47, 0xa8, 0xb4, 0xc7, 0x63, 0x1e, 0xa7, 0xe7, 0x2d, 0xa8, 0x8b, 0xc1, 0xe3,
0x13, 0x90, 0xcf, 0xb4, 0x3d, 0xa4, 0x85, 0xc4, 0xaf, 0x25, 0xf2, 0xbf, 0xee, 0x2a, 0xe8, 0x6d, 0xe9, 0xcb, 0xe2, 0xae, 0x00, 0xc2, 0x38, 0xca, 0x6d, 0xae, 0x34, 0x9f, 0xd9, 0xce, 0x18, 0x6f,
0x00, 0x27, 0x60, 0x7b, 0x5e, 0x40, 0xdd, 0x31, 0x86, 0x93, 0xa8, 0x98, 0x55, 0x27, 0x78, 0xca, 0x72, 0x09, 0xfb, 0x8a, 0x3d, 0x0d, 0x8f, 0x6c, 0x07, 0x5d, 0x27, 0x65, 0x32, 0x9e, 0xd5, 0x2b,
0x01, 0x29, 0x2d, 0xd4, 0x66, 0x3a, 0x3e, 0xeb, 0x37, 0xba, 0x05, 0xb5, 0xa1, 0xae, 0xf7, 0x04, 0x7c, 0xfc, 0x45, 0xf2, 0x80, 0xc7, 0xbc, 0x51, 0x18, 0x53, 0x15, 0xd6, 0xc3, 0xac, 0x09, 0x14,
0xa9, 0x40, 0xb1, 0x7f, 0xd4, 0xe9, 0x35, 0x6f, 0x90, 0x1a, 0x94, 0x07, 0x9d, 0xe1, 0xf0, 0x00, 0x5c, 0x07, 0x1f, 0xa1, 0xc7, 0x5d, 0x48, 0x31, 0x70, 0xc7, 0xa2, 0x32, 0x2f, 0x89, 0x55, 0x2a,
0xed, 0xcc, 0x75, 0xa8, 0xa8, 0xfb, 0xe4, 0x79, 0xf6, 0xd5, 0xde, 0xd9, 0xe9, 0x1c, 0x0d, 0x3b, 0xff, 0x73, 0x43, 0x35, 0xc7, 0x64, 0xac, 0x26, 0xb7, 0x97, 0xaf, 0xc7, 0xb8, 0x71, 0x81, 0x8a,
0xbb, 0xcd, 0xc2, 0xf7, 0x8b, 0x95, 0x7c, 0xb3, 0x60, 0xfc, 0xef, 0x02, 0xd4, 0xb4, 0x8e, 0x7a, 0xf6, 0x72, 0x8e, 0x40, 0x3e, 0xd7, 0xce, 0x90, 0x16, 0x22, 0xbf, 0x91, 0x28, 0xff, 0xba, 0xbb,
0x31, 0xbf, 0x8e, 0x47, 0x2e, 0xca, 0x27, 0x23, 0x17, 0xe9, 0x46, 0x15, 0x11, 0xdd, 0x49, 0x1a, 0xb3, 0xb7, 0x01, 0x9c, 0x80, 0x9d, 0x79, 0x01, 0x75, 0xc7, 0x18, 0x7f, 0xa3, 0x62, 0x56, 0x9d,
0x55, 0xde, 0x84, 0x86, 0x08, 0xed, 0xa8, 0x79, 0x0b, 0x94, 0xcc, 0x3a, 0x07, 0x0a, 0x6e, 0x8e, 0xe0, 0x09, 0x07, 0xa4, 0xb4, 0x50, 0x9b, 0xe9, 0x20, 0xb8, 0xdf, 0xe8, 0x11, 0xd4, 0x86, 0xba,
0xd1, 0x29, 0x90, 0x08, 0xef, 0xfd, 0x96, 0xc4, 0xfc, 0x41, 0x10, 0xde, 0xfc, 0xc5, 0x6b, 0xdb, 0x3e, 0x12, 0xa4, 0x02, 0xc5, 0xfe, 0x51, 0xa7, 0xd7, 0xbc, 0x41, 0x6a, 0x50, 0x1e, 0x74, 0x86,
0x81, 0x37, 0xb9, 0xa0, 0x9c, 0x82, 0x8b, 0xb0, 0x35, 0x01, 0x1b, 0x8a, 0xc8, 0x1f, 0x82, 0x65, 0xc3, 0x03, 0x34, 0xcc, 0xd7, 0xa1, 0xa2, 0x2e, 0xe0, 0xe7, 0xd9, 0x57, 0x7b, 0x67, 0xa7, 0x73,
0x6a, 0xe1, 0x11, 0x4a, 0x66, 0x9d, 0x03, 0x45, 0x41, 0xef, 0xcb, 0x39, 0xc6, 0x7d, 0xa7, 0x36, 0x34, 0xec, 0xec, 0x36, 0x0b, 0x3f, 0x28, 0x56, 0xf2, 0xcd, 0x82, 0xf1, 0xbf, 0x0a, 0x50, 0xd3,
0xd2, 0x13, 0x26, 0x36, 0xbf, 0x0e, 0x52, 0x7a, 0xcf, 0x2a, 0xce, 0x9d, 0x6f, 0xa5, 0xd3, 0xbd, 0x06, 0xea, 0xe5, 0xf4, 0x3a, 0x1e, 0xea, 0x29, 0x9f, 0x0c, 0xf5, 0xa4, 0x1b, 0x55, 0x44, 0x38,
0x5c, 0xff, 0x49, 0xde, 0x05, 0x32, 0x9d, 0xcd, 0xac, 0x0c, 0x8d, 0x64, 0xd1, 0x5c, 0x9a, 0xce, 0x2c, 0x69, 0x54, 0x79, 0x1b, 0x1a, 0x22, 0x7e, 0xa6, 0xe6, 0x5e, 0x51, 0x32, 0xeb, 0x1c, 0x28,
0x66, 0x43, 0x4d, 0x61, 0x47, 0x5e, 0x83, 0x82, 0x3d, 0x9d, 0x21, 0x6b, 0x89, 0xb4, 0x83, 0xed, 0xa8, 0x39, 0x86, 0xf3, 0x40, 0x24, 0xbc, 0x28, 0x5d, 0x12, 0xeb, 0x07, 0x41, 0x78, 0x55, 0x1a,
0xc3, 0x23, 0x93, 0x81, 0xbf, 0x01, 0x55, 0xea, 0x6f, 0xe4, 0xa0, 0xd0, 0x3e, 0x3c, 0x42, 0x46, 0xef, 0xb9, 0x07, 0xde, 0xe4, 0x82, 0x72, 0x0c, 0xce, 0xc2, 0xd6, 0x04, 0x6c, 0x28, 0x42, 0xa5,
0xef, 0x79, 0xa1, 0x15, 0x9c, 0xdb, 0x22, 0x38, 0x19, 0x63, 0xf4, 0x9e, 0x17, 0x0e, 0x18, 0x80, 0x08, 0x92, 0xa9, 0xc5, 0x93, 0x28, 0x99, 0x75, 0x0e, 0x14, 0x15, 0x7d, 0x20, 0xd7, 0x18, 0x77,
0x31, 0xfa, 0x80, 0x86, 0x91, 0x0f, 0x70, 0x29, 0xa0, 0x21, 0x77, 0x08, 0x1f, 0x9d, 0x3b, 0x93, 0x36, 0xdb, 0x48, 0x2f, 0x98, 0xd8, 0xfa, 0x3a, 0x48, 0xe9, 0x3d, 0xab, 0xb8, 0x76, 0xbe, 0x95,
0x71, 0x2c, 0x46, 0x25, 0x20, 0x88, 0xcf, 0x08, 0x02, 0x45, 0x6d, 0x7b, 0xc0, 0xdf, 0xfc, 0x22, 0xce, 0xf7, 0x6a, 0xfd, 0x27, 0x79, 0x1f, 0xc8, 0x74, 0x36, 0xb3, 0x32, 0x34, 0x92, 0x45, 0x73,
0x9d, 0xd8, 0x51, 0xb8, 0x9b, 0xb9, 0xfa, 0x36, 0xfe, 0x4a, 0x0e, 0x48, 0x9b, 0x71, 0x24, 0xec, 0x69, 0x3a, 0x9b, 0x0d, 0x35, 0x85, 0x1d, 0x79, 0x03, 0x0a, 0xf6, 0x74, 0x86, 0xa4, 0x25, 0xd2,
0x50, 0x75, 0xd2, 0x8d, 0xf6, 0x99, 0x9c, 0xbe, 0xcf, 0x64, 0xb0, 0xf3, 0x7c, 0x26, 0x3b, 0x7f, 0x0e, 0xb6, 0x0f, 0x8f, 0x4c, 0x06, 0xfe, 0x06, 0x54, 0xa9, 0xbf, 0x99, 0x83, 0x42, 0xfb, 0xf0,
0x19, 0xe3, 0x8b, 0x2d, 0xdd, 0xe5, 0xd4, 0xd2, 0x35, 0xf6, 0xa0, 0x76, 0xa4, 0x85, 0x0c, 0xbe, 0x08, 0x09, 0xbd, 0xe7, 0x85, 0x56, 0x70, 0x6e, 0x8b, 0x68, 0x6e, 0x8c, 0xd0, 0x7b, 0x5e, 0x38,
0xcb, 0x76, 0x45, 0x19, 0x2c, 0x98, 0xef, 0x97, 0x5c, 0xab, 0xeb, 0x8b, 0x18, 0xc1, 0x5a, 0x85, 0x60, 0x00, 0x46, 0xe8, 0x03, 0x1a, 0x46, 0x4e, 0xd3, 0xa5, 0x80, 0x86, 0xdc, 0x83, 0x7e, 0x74,
0xf3, 0x5a, 0x85, 0x8d, 0xbf, 0x9d, 0xe3, 0x81, 0xf3, 0x54, 0xfb, 0xa2, 0x28, 0xc5, 0xd2, 0x38, 0xee, 0x4c, 0xc6, 0xb1, 0x40, 0xa0, 0x80, 0x20, 0xbe, 0x22, 0x08, 0x14, 0xb5, 0xe3, 0x01, 0x7f,
0x1a, 0x85, 0x65, 0xa9, 0x49, 0xf3, 0xa7, 0x88, 0xa8, 0x82, 0xb5, 0xb7, 0xbc, 0xd3, 0xd3, 0x80, 0xf3, 0x9b, 0x87, 0xe2, 0x44, 0xe1, 0x7e, 0xf9, 0xea, 0xdb, 0xf8, 0x2b, 0x39, 0x20, 0x6d, 0x46,
0x4a, 0x97, 0xa9, 0x1a, 0xc2, 0xfa, 0x08, 0x92, 0xc7, 0x1f, 0x76, 0xc6, 0x72, 0x78, 0xfe, 0x81, 0x91, 0x70, 0x40, 0x95, 0xa4, 0x1b, 0x9d, 0x33, 0x39, 0xfd, 0x9c, 0xc9, 0x20, 0xe7, 0xf9, 0x4c,
0xf0, 0x93, 0x62, 0xc7, 0x9f, 0x43, 0xfb, 0x52, 0x94, 0x1a, 0xb0, 0x11, 0x10, 0x16, 0x1a, 0x19, 0x72, 0xfe, 0x2a, 0xc2, 0x17, 0xdb, 0xba, 0xcb, 0xa9, 0xad, 0x6b, 0xec, 0x41, 0xed, 0x48, 0x8b,
0x96, 0x40, 0x7d, 0x1b, 0x7f, 0x43, 0x44, 0x8e, 0x49, 0x0e, 0xc1, 0x7d, 0xa8, 0xa8, 0x5c, 0xe3, 0xcb, 0x7c, 0x97, 0x9d, 0x8a, 0x32, 0x22, 0x33, 0x3f, 0x2f, 0xb9, 0x56, 0xd7, 0x17, 0x81, 0x98,
0x52, 0x85, 0xa4, 0x54, 0x78, 0x26, 0xbb, 0xa0, 0x3a, 0x2a, 0x56, 0x63, 0xce, 0x2d, 0xd0, 0xca, 0xb5, 0x06, 0xe7, 0xb5, 0x06, 0x1b, 0x7f, 0x2b, 0xc7, 0xa3, 0x13, 0xaa, 0xfe, 0x45, 0xa1, 0xa0,
0xd6, 0xd5, 0x6a, 0xfd, 0x1e, 0x90, 0x53, 0xc7, 0x4f, 0x12, 0x73, 0xee, 0xd1, 0x44, 0x8c, 0x46, 0xa5, 0x71, 0x34, 0x8a, 0x63, 0x53, 0x93, 0xe6, 0x4f, 0x11, 0x82, 0x06, 0x5b, 0x6f, 0x79, 0xa7,
0x6d, 0x1c, 0xc3, 0x8a, 0x64, 0x7b, 0xda, 0x99, 0x2c, 0x3e, 0xbe, 0xb9, 0x97, 0x6c, 0x6c, 0xf9, 0xa7, 0x01, 0x95, 0x3e, 0x66, 0x35, 0x84, 0xf5, 0x11, 0x24, 0xc5, 0x1f, 0x26, 0x63, 0x39, 0xbc,
0xd4, 0xc6, 0x66, 0xfc, 0x7a, 0x09, 0xca, 0x32, 0x42, 0x77, 0x56, 0xc8, 0xe8, 0x6a, 0x3c, 0x64, 0xfc, 0x40, 0x38, 0x96, 0x31, 0xf1, 0xe7, 0xd0, 0xbe, 0x14, 0xb5, 0x06, 0x6c, 0x06, 0x84, 0x85,
0x74, 0x2b, 0x16, 0x90, 0x12, 0x87, 0x5e, 0xc8, 0x38, 0xef, 0x24, 0xc5, 0x14, 0xcd, 0x5a, 0x14, 0x46, 0xc6, 0x71, 0x50, 0xdf, 0xc6, 0x5f, 0x17, 0xa1, 0x76, 0x92, 0x53, 0x70, 0x1f, 0x2a, 0xaa,
0x13, 0x55, 0x84, 0xb5, 0xa8, 0x14, 0xb7, 0x16, 0x65, 0x85, 0xd1, 0xe6, 0xe2, 0x76, 0x2a, 0x8c, 0xd4, 0x38, 0x57, 0x21, 0x31, 0x55, 0x3a, 0xe3, 0x5d, 0x50, 0x1d, 0x15, 0x6b, 0x31, 0xa7, 0x16,
0xf6, 0x2d, 0xe0, 0xb2, 0x93, 0xe6, 0x2b, 0x5a, 0x41, 0x80, 0x08, 0xad, 0xa1, 0x89, 0x5a, 0x95, 0x68, 0x65, 0xeb, 0x6a, 0xad, 0xfe, 0x0e, 0x90, 0x53, 0xc7, 0x4f, 0x22, 0x73, 0xea, 0xd1, 0xc4,
0xa4, 0xa8, 0xf5, 0xca, 0x62, 0xd0, 0xc7, 0xb0, 0xc0, 0xa3, 0x50, 0x89, 0x30, 0x0b, 0x72, 0xb3, 0x14, 0x0d, 0xdb, 0x38, 0x86, 0x15, 0x49, 0xf6, 0x34, 0x99, 0x2c, 0x3e, 0xbf, 0xb9, 0x57, 0x1c,
0x14, 0x7d, 0x25, 0xff, 0xf3, 0x2b, 0x48, 0xa6, 0xa0, 0xd5, 0xa3, 0xae, 0xd6, 0x62, 0x51, 0x57, 0x6c, 0xf9, 0xd4, 0xc1, 0x66, 0xfc, 0x46, 0x09, 0xca, 0x32, 0x0c, 0x7a, 0x56, 0x5c, 0xee, 0x6a,
0x75, 0x2b, 0x56, 0x3d, 0x6e, 0xc5, 0xba, 0x07, 0x4d, 0xd5, 0x71, 0xa8, 0x13, 0x76, 0x03, 0x71, 0x3c, 0x2e, 0x77, 0x2b, 0x16, 0xf5, 0x13, 0xa7, 0x5e, 0xf0, 0x38, 0xef, 0x25, 0xd9, 0x14, 0xcd,
0xa3, 0x7a, 0x51, 0xc2, 0x19, 0x7b, 0xef, 0x05, 0xd1, 0x66, 0xbf, 0x18, 0xdb, 0xec, 0x19, 0xf3, 0x5a, 0x14, 0x63, 0x55, 0x84, 0xb5, 0xa8, 0x14, 0xb7, 0x16, 0x65, 0xc5, 0x2a, 0xe7, 0xec, 0x76,
0x6d, 0x87, 0x21, 0x9d, 0xce, 0x42, 0xb9, 0xd9, 0x6b, 0x91, 0xcb, 0xf9, 0xc8, 0xf3, 0x2b, 0x5a, 0x2a, 0x56, 0xf9, 0x2d, 0xe0, 0xbc, 0x93, 0xe6, 0x5c, 0x5b, 0x41, 0x80, 0x88, 0x45, 0xa2, 0xb1,
0x72, 0x78, 0xf9, 0xec, 0xd8, 0x86, 0xc5, 0x53, 0xdb, 0x99, 0xcc, 0x7d, 0x6a, 0xf9, 0xd4, 0x0e, 0x5a, 0x95, 0x24, 0xab, 0xf5, 0xda, 0x6c, 0xd0, 0x27, 0xb0, 0xc0, 0xc3, 0x76, 0x89, 0xb8, 0x14,
0x3c, 0x17, 0xf9, 0x43, 0x24, 0x77, 0x88, 0x26, 0xee, 0x71, 0x1a, 0x13, 0x49, 0xcc, 0xc6, 0xa9, 0xf2, 0xb0, 0x14, 0x63, 0x25, 0xff, 0xf3, 0x3b, 0x5b, 0xa6, 0xc0, 0xd5, 0x43, 0xdb, 0xd6, 0x62,
0xfe, 0x89, 0x17, 0x22, 0xf5, 0x9e, 0x60, 0x7b, 0xb0, 0x08, 0xb6, 0xc0, 0x5d, 0xbf, 0xba, 0x3d, 0xa1, 0x6d, 0x75, 0x2b, 0x56, 0x3d, 0x6e, 0xc5, 0xba, 0x07, 0x4d, 0x35, 0x70, 0xa8, 0x13, 0x76,
0x6b, 0xef, 0xa0, 0xfb, 0x64, 0x7f, 0xd8, 0xcc, 0xb1, 0xcf, 0xc1, 0xf1, 0xce, 0x4e, 0xa7, 0xb3, 0x03, 0x71, 0x05, 0x7d, 0x51, 0xc2, 0x19, 0x79, 0xef, 0x05, 0xd1, 0x61, 0xbf, 0x18, 0x3b, 0xec,
0x8b, 0x7b, 0x32, 0xc0, 0xc2, 0x5e, 0xbb, 0x7b, 0x20, 0x76, 0xe4, 0x62, 0xb3, 0x64, 0xfc, 0x41, 0x19, 0xf1, 0x6d, 0x87, 0x21, 0x9d, 0xce, 0x42, 0x79, 0xd8, 0x6b, 0xe1, 0xe1, 0xf9, 0xcc, 0xf3,
0x1e, 0x6a, 0x5a, 0x6b, 0x30, 0x8c, 0x0a, 0xff, 0xc9, 0xf8, 0x6f, 0x59, 0x84, 0x51, 0xe1, 0x90, 0x3b, 0x6d, 0x72, 0x7a, 0xf9, 0xea, 0xd8, 0x86, 0xc5, 0x53, 0xdb, 0x99, 0xcc, 0x7d, 0x6a, 0xf9,
0xee, 0x98, 0x3c, 0x52, 0x63, 0xc4, 0xa3, 0xbf, 0xdc, 0x4e, 0x77, 0xc8, 0x96, 0xdc, 0xd1, 0xb4, 0xd4, 0x0e, 0x3c, 0x17, 0xe9, 0x43, 0xc4, 0x77, 0x88, 0x2e, 0xee, 0x71, 0x1c, 0x13, 0x51, 0xcc,
0x41, 0x52, 0x21, 0xcc, 0xf3, 0xd7, 0x86, 0x30, 0x27, 0x6f, 0xc3, 0x92, 0x2c, 0x59, 0x8e, 0x89, 0xc6, 0xa9, 0xfe, 0x89, 0x37, 0x48, 0xf5, 0x91, 0x60, 0x67, 0xb0, 0x88, 0x4e, 0xc1, 0x7d, 0xe5,
0xb0, 0xbe, 0x08, 0xb0, 0x18, 0x92, 0xb7, 0x45, 0x24, 0x1a, 0xb1, 0x2d, 0x33, 0xba, 0xa2, 0x74, 0xba, 0x3d, 0x6b, 0xef, 0xa0, 0xfb, 0x78, 0x7f, 0xd8, 0xcc, 0xb1, 0xcf, 0xc1, 0xf1, 0xce, 0x4e,
0x91, 0x56, 0x3b, 0x33, 0x0e, 0x5d, 0x59, 0x74, 0x9c, 0xf0, 0x96, 0x50, 0x02, 0x8e, 0xe8, 0x4e, 0xa7, 0xb3, 0x8b, 0x67, 0x32, 0xc0, 0xc2, 0x5e, 0xbb, 0x7b, 0x20, 0x4e, 0xe4, 0x62, 0xb3, 0x64,
0x89, 0x8e, 0xed, 0x11, 0x0b, 0x89, 0x3d, 0xe2, 0x13, 0x80, 0xa8, 0x3d, 0xf1, 0xde, 0xbd, 0x11, 0xfc, 0x61, 0x1e, 0x6a, 0x5a, 0x6f, 0x30, 0xee, 0x0c, 0xff, 0xc9, 0xe8, 0x6f, 0x59, 0xc4, 0x9d,
0xef, 0xdd, 0x9c, 0xd6, 0xbb, 0x79, 0xe3, 0xef, 0x0b, 0xce, 0x26, 0x86, 0x4a, 0xe9, 0x62, 0xdf, 0xe1, 0x90, 0xee, 0x98, 0x3c, 0x52, 0x73, 0xc4, 0xc3, 0xe5, 0xdc, 0x4e, 0x0f, 0xc8, 0x96, 0x3c,
0x07, 0xa9, 0x1d, 0xb6, 0xf0, 0x4a, 0xc5, 0x6c, 0x42, 0x43, 0x79, 0x5f, 0x7c, 0x59, 0x60, 0xba, 0xd1, 0xb4, 0x49, 0x52, 0x71, 0xe2, 0xf3, 0xd7, 0xc6, 0x89, 0x27, 0xef, 0xc2, 0x92, 0xac, 0x59,
0x0a, 0x91, 0xe2, 0xc4, 0xf9, 0x34, 0x27, 0x7e, 0x03, 0xea, 0x18, 0xda, 0x50, 0x14, 0x24, 0xe3, 0xce, 0x89, 0xb0, 0xbe, 0x08, 0xb0, 0x98, 0x92, 0x77, 0x45, 0xe8, 0x1e, 0x71, 0x2c, 0x33, 0xbc,
0x04, 0x4f, 0xed, 0x4b, 0x59, 0x76, 0x8c, 0x05, 0x17, 0x13, 0x2c, 0xf8, 0x6f, 0xe6, 0x78, 0x1c, 0xa2, 0xf4, 0x29, 0x57, 0x27, 0x33, 0x4e, 0x5d, 0x59, 0x0c, 0x9c, 0xf0, 0x96, 0x50, 0x0c, 0x8e,
0xac, 0xa8, 0xa2, 0x11, 0x0f, 0x56, 0x79, 0xc6, 0x79, 0xb0, 0x20, 0x35, 0x15, 0xfe, 0x1a, 0xbe, 0x18, 0x4e, 0x99, 0x1c, 0x3b, 0x23, 0x16, 0x12, 0x67, 0xc4, 0xa7, 0x00, 0x51, 0x7f, 0xe2, 0xa3,
0x9a, 0xcf, 0xe6, 0xab, 0xd9, 0x1c, 0xbb, 0x90, 0xc9, 0xb1, 0x8d, 0x4b, 0x68, 0xed, 0x52, 0xd6, 0x7b, 0x23, 0x3e, 0xba, 0x39, 0x6d, 0x74, 0xf3, 0xc6, 0xdf, 0x13, 0x94, 0x4d, 0x4c, 0x95, 0xd2,
0x15, 0xed, 0xc9, 0x24, 0xd9, 0x97, 0x0f, 0x60, 0x95, 0x0d, 0x21, 0xba, 0x8a, 0x70, 0x8c, 0xbe, 0xc5, 0x7e, 0x00, 0x52, 0x3b, 0x6c, 0xe1, 0x1d, 0x94, 0xd9, 0x84, 0x86, 0xf2, 0x82, 0xfd, 0xb2,
0xa3, 0x11, 0x8e, 0x93, 0x89, 0x70, 0x63, 0xbb, 0x0f, 0xcb, 0x22, 0x05, 0x2e, 0x5a, 0x3d, 0xe8, 0x48, 0xe9, 0xaa, 0x84, 0x14, 0x25, 0xce, 0xa7, 0x29, 0xf1, 0x5b, 0x50, 0xc7, 0x58, 0x90, 0xa2,
0xd8, 0x12, 0x47, 0xa0, 0xc7, 0x26, 0xa3, 0x35, 0x6e, 0xc1, 0xcd, 0x8c, 0x92, 0x85, 0xd2, 0xee, 0x22, 0x19, 0x8c, 0x79, 0x6a, 0x5f, 0xca, 0xba, 0x63, 0x24, 0xb8, 0x98, 0x20, 0xc1, 0x7f, 0x23,
0x37, 0x72, 0xb0, 0xd6, 0xe6, 0xc1, 0x75, 0xbe, 0xb1, 0xeb, 0xe2, 0x9f, 0xc3, 0x4d, 0x75, 0xfb, 0xc7, 0x03, 0x87, 0x45, 0x0d, 0x8d, 0x68, 0xb0, 0x2a, 0x33, 0x4e, 0x83, 0x05, 0xaa, 0xa9, 0xd2,
0x42, 0xbb, 0x35, 0xaa, 0x57, 0x52, 0x5e, 0xdc, 0xd0, 0xee, 0x1c, 0x61, 0x5d, 0x5b, 0xb0, 0x9e, 0xaf, 0xa1, 0xab, 0xf9, 0x6c, 0xba, 0x9a, 0x4d, 0xb1, 0x0b, 0x99, 0x14, 0xdb, 0xb8, 0x84, 0xd6,
0xac, 0x8d, 0xa8, 0xe8, 0x1e, 0x2c, 0xef, 0xd2, 0x93, 0xf9, 0xd9, 0x01, 0xbd, 0x88, 0xea, 0x48, 0x2e, 0x65, 0x43, 0xd1, 0x9e, 0x4c, 0x92, 0x63, 0xf9, 0x00, 0x56, 0xd9, 0x14, 0xa2, 0xab, 0x08,
0xa0, 0x18, 0x9c, 0x7b, 0xcf, 0x45, 0x47, 0xe1, 0x6f, 0x74, 0xcf, 0x66, 0x34, 0x56, 0x30, 0xa3, 0x4f, 0xd1, 0x4f, 0x34, 0xc2, 0xd3, 0x64, 0x26, 0x3c, 0xd8, 0xee, 0xc3, 0xb2, 0xc8, 0x81, 0x9b,
0x23, 0x69, 0xf4, 0x41, 0xc8, 0x60, 0x46, 0x47, 0xc6, 0x23, 0x20, 0x7a, 0x3e, 0x62, 0x8e, 0xb0, 0x56, 0x8f, 0xd2, 0xb6, 0xc4, 0x13, 0xd0, 0xc5, 0x95, 0xe1, 0x1a, 0xb7, 0xe0, 0x66, 0x46, 0xcd,
0x33, 0xf0, 0xfc, 0xc4, 0x0a, 0xae, 0x82, 0x90, 0x4e, 0xe5, 0xcd, 0x69, 0x08, 0xe6, 0x27, 0x03, 0x42, 0x69, 0xf7, 0x9b, 0x39, 0x58, 0x6b, 0xf3, 0x68, 0x44, 0xdf, 0xd8, 0xfd, 0xfa, 0x2f, 0xe0,
0x0e, 0x31, 0xde, 0x81, 0xfa, 0x91, 0x7d, 0x65, 0xd2, 0x1f, 0x89, 0xcb, 0xc7, 0x1b, 0x50, 0x9e, 0xa6, 0xba, 0xae, 0xa2, 0x5d, 0xb3, 0xd5, 0x1b, 0x29, 0x6f, 0xba, 0x68, 0x97, 0xb4, 0xb0, 0xad,
0xd9, 0x57, 0x6c, 0x23, 0x50, 0xf6, 0x5f, 0x44, 0x1b, 0xbf, 0x53, 0x84, 0x05, 0x4e, 0x49, 0xee, 0x2d, 0x58, 0x4f, 0xb6, 0x46, 0x34, 0x74, 0x0f, 0x96, 0x77, 0xe9, 0xc9, 0xfc, 0xec, 0x80, 0x5e,
0xf2, 0xd7, 0x4d, 0x1c, 0x17, 0x19, 0xb1, 0xdc, 0x12, 0x35, 0x50, 0x6a, 0xd7, 0xcc, 0xa7, 0x77, 0x44, 0x6d, 0x24, 0x50, 0x0c, 0xce, 0xbd, 0x17, 0x62, 0xa0, 0xf0, 0x37, 0xfa, 0xb3, 0x33, 0x1c,
0x4d, 0xa1, 0xac, 0x96, 0x91, 0x1b, 0xa5, 0xa5, 0xce, 0x9d, 0x4f, 0x65, 0xb8, 0xc6, 0x78, 0x28, 0x2b, 0x98, 0xd1, 0x91, 0x34, 0xfa, 0x20, 0x64, 0x30, 0xa3, 0x23, 0xe3, 0x11, 0x10, 0xbd, 0x1c,
0x99, 0x62, 0xf4, 0x2a, 0x0e, 0x0f, 0xa3, 0x11, 0xf7, 0xa5, 0x88, 0x4e, 0xda, 0xbc, 0x76, 0x52, 0xb1, 0x46, 0x98, 0x0c, 0x3c, 0x3f, 0xb1, 0x82, 0xab, 0x20, 0xa4, 0x53, 0x79, 0xd5, 0x1c, 0x82,
0x18, 0x10, 0x1b, 0xa6, 0x0e, 0xca, 0x3c, 0xce, 0x97, 0xe5, 0xcd, 0xfc, 0xf8, 0x71, 0x3e, 0x75, 0xf9, 0xc9, 0x80, 0x43, 0x8c, 0xf7, 0xa0, 0x7e, 0x64, 0x5f, 0x99, 0xf4, 0x47, 0xe2, 0xb6, 0xf6,
0x6c, 0xaf, 0xbc, 0xfc, 0xd8, 0xce, 0xb5, 0xd8, 0x2f, 0x38, 0xb6, 0xc3, 0x2b, 0x1c, 0xdb, 0x5f, 0x06, 0x94, 0x67, 0xf6, 0x15, 0x3b, 0x08, 0x94, 0xfd, 0x17, 0x93, 0x8d, 0xdf, 0x2d, 0xc2, 0x02,
0xc1, 0x8f, 0xe1, 0x26, 0x54, 0x50, 0xc2, 0xd3, 0xf6, 0x4f, 0x26, 0xd9, 0xb1, 0xfd, 0xf3, 0x53, 0xc7, 0x24, 0x77, 0xf9, 0x13, 0x32, 0x8e, 0x8b, 0x84, 0x58, 0x1e, 0x89, 0x1a, 0x28, 0x75, 0x6a,
0xed, 0x60, 0xcb, 0x9d, 0xa8, 0xb4, 0x0d, 0xcc, 0xa4, 0x3f, 0xfa, 0xe9, 0x28, 0x46, 0xbf, 0x82, 0xe6, 0xd3, 0xa7, 0xa6, 0x50, 0x56, 0xcb, 0x50, 0x97, 0xd2, 0x52, 0xe7, 0xce, 0xa7, 0x32, 0xbe,
0xb2, 0x80, 0xb2, 0x09, 0xed, 0xda, 0x53, 0x19, 0x9f, 0x18, 0x7f, 0xb3, 0x6e, 0xc3, 0x88, 0x9d, 0x65, 0x3c, 0xf6, 0x4e, 0x31, 0x7a, 0x94, 0x88, 0xc7, 0x1d, 0x89, 0xfb, 0x52, 0x44, 0x92, 0x36,
0x3f, 0x9a, 0x3b, 0x3e, 0x1d, 0xcb, 0xb8, 0x81, 0x0e, 0x72, 0x0f, 0x06, 0x61, 0x0d, 0x64, 0x87, 0x6f, 0x9d, 0x64, 0x06, 0xc4, 0x81, 0xa9, 0x83, 0x32, 0xc5, 0xf9, 0xb2, 0x0c, 0x65, 0x10, 0x17,
0x6c, 0x57, 0x3e, 0x6c, 0x50, 0x31, 0xcb, 0x4e, 0xf0, 0x94, 0x7d, 0x1a, 0x04, 0x9a, 0x18, 0xd9, 0xe7, 0x53, 0x62, 0x7b, 0xe5, 0xd5, 0x62, 0x3b, 0xd7, 0x62, 0xbf, 0x44, 0x6c, 0x87, 0xd7, 0x10,
0x7d, 0xe6, 0xf9, 0x52, 0x3c, 0x31, 0x7e, 0x37, 0x07, 0x4d, 0xb1, 0xba, 0x14, 0x4e, 0x3f, 0xc0, 0xdb, 0x5f, 0xc3, 0x8f, 0xe1, 0x26, 0x54, 0x90, 0xc3, 0xd3, 0xce, 0x4f, 0xc6, 0xd9, 0xb1, 0xf3,
0x96, 0xae, 0xf3, 0xf9, 0x79, 0x71, 0x14, 0x40, 0x03, 0x1a, 0xa8, 0xda, 0x53, 0xb2, 0x0a, 0x57, 0xf3, 0x33, 0x4d, 0xb0, 0xe5, 0x4e, 0x54, 0xda, 0x01, 0x66, 0xd2, 0x1f, 0xfd, 0x74, 0x14, 0xa3,
0x4d, 0xd6, 0x18, 0x70, 0x4f, 0xc8, 0x2b, 0xaf, 0x43, 0x4d, 0x5e, 0x1e, 0x99, 0x3a, 0x13, 0xf9, 0xcf, 0xa0, 0x2c, 0xa0, 0x6c, 0x41, 0xbb, 0xf6, 0x54, 0x06, 0x74, 0xc6, 0xdf, 0x6c, 0xd8, 0x30,
0x00, 0x16, 0xbf, 0x3d, 0x72, 0xe8, 0x4c, 0xa4, 0xa8, 0xe3, 0xdb, 0x22, 0x5a, 0x44, 0x0e, 0x45, 0xc4, 0xe9, 0x8f, 0xe6, 0x8e, 0x4f, 0xc7, 0x32, 0xd0, 0xa2, 0x83, 0xd4, 0x83, 0x41, 0x58, 0x07,
0x1d, 0xd3, 0x0e, 0xa9, 0xf1, 0xfb, 0x39, 0x58, 0xd6, 0x9a, 0x22, 0xd6, 0xed, 0x77, 0xa0, 0xae, 0x99, 0x90, 0xed, 0xca, 0xd7, 0x23, 0x2a, 0x66, 0xd9, 0x09, 0x9e, 0xb0, 0x4f, 0x83, 0x40, 0x13,
0x1e, 0x9c, 0xa0, 0x4a, 0xc6, 0xde, 0x88, 0xf3, 0xa8, 0x28, 0x59, 0x6d, 0xa4, 0x20, 0x01, 0xab, 0xc3, 0xe7, 0xcf, 0x3c, 0x5f, 0xb2, 0x27, 0xc6, 0xef, 0xe5, 0xa0, 0x29, 0x76, 0x97, 0x4a, 0xd3,
0xcc, 0xd8, 0xbe, 0xe2, 0x37, 0x1c, 0xe6, 0x53, 0x79, 0x2e, 0x1f, 0xdb, 0x57, 0x7b, 0x94, 0x0e, 0x05, 0xd8, 0xd2, 0x75, 0x3e, 0x3f, 0x2f, 0x0f, 0x9b, 0x68, 0x40, 0x03, 0x55, 0x7b, 0x8a, 0x57,
0xe6, 0x53, 0x72, 0x17, 0xea, 0xcf, 0x29, 0x7d, 0xa6, 0x08, 0x38, 0x63, 0x07, 0x06, 0x13, 0x14, 0xe1, 0xaa, 0xc9, 0x1a, 0x03, 0xee, 0x09, 0x7e, 0xe5, 0x4d, 0xa8, 0xc9, 0xdb, 0x36, 0x53, 0x67,
0x06, 0x34, 0xa6, 0x9e, 0x1b, 0x9e, 0x2b, 0x12, 0x71, 0xbe, 0x40, 0x20, 0xa7, 0x31, 0xfe, 0x75, 0x22, 0xdf, 0x1f, 0xe3, 0xd7, 0x6d, 0x0e, 0x9d, 0x89, 0x64, 0x75, 0x7c, 0x5b, 0x84, 0xd7, 0xc8,
0x1e, 0x56, 0xb8, 0x02, 0x59, 0x98, 0x11, 0x04, 0xeb, 0x6a, 0xc1, 0x02, 0xd7, 0xea, 0x73, 0xe6, 0x21, 0xab, 0x63, 0xda, 0x21, 0x35, 0xfe, 0x20, 0x07, 0xcb, 0x5a, 0x57, 0xc4, 0xbe, 0xfd, 0x2e,
0xb5, 0x7f, 0xc3, 0x14, 0xdf, 0xe4, 0xe3, 0x57, 0x54, 0x7a, 0xcb, 0x40, 0x13, 0xd7, 0x74, 0x7f, 0xd4, 0xd5, 0xab, 0x1e, 0x54, 0xf1, 0xd8, 0x1b, 0x71, 0x1a, 0x15, 0x65, 0xab, 0x8d, 0x14, 0x24,
0x21, 0xdd, 0xfd, 0xd7, 0x77, 0x6f, 0x96, 0x53, 0x41, 0x29, 0xcb, 0xa9, 0xe0, 0x55, 0x4c, 0xf9, 0x60, 0x8d, 0x19, 0xdb, 0x57, 0xfc, 0x4a, 0xc8, 0x7c, 0x2a, 0xe5, 0xf2, 0xb1, 0x7d, 0xb5, 0x47,
0xa9, 0x50, 0x07, 0xe5, 0x74, 0xc8, 0xe1, 0x47, 0xb0, 0x11, 0xa3, 0x41, 0x6e, 0xed, 0x9c, 0x3a, 0xe9, 0x60, 0x3e, 0x25, 0x77, 0xa1, 0xfe, 0x82, 0xd2, 0xe7, 0x0a, 0x81, 0x13, 0x76, 0x60, 0x30,
0x2a, 0xee, 0xfd, 0xaa, 0x46, 0x3d, 0x90, 0xb8, 0xed, 0x32, 0x94, 0x82, 0x91, 0x37, 0xa3, 0xc6, 0x81, 0x61, 0x40, 0x63, 0xea, 0xb9, 0xe1, 0xb9, 0x42, 0x11, 0xf2, 0x05, 0x02, 0x39, 0x8e, 0xf1,
0x3a, 0xac, 0xc6, 0x7b, 0x55, 0x6c, 0x13, 0xbf, 0x95, 0x83, 0xd6, 0x5e, 0x14, 0xbb, 0xd9, 0x09, 0xaf, 0xf2, 0xb0, 0xc2, 0x15, 0xc8, 0xc2, 0x8c, 0x20, 0x48, 0x57, 0x0b, 0x16, 0xb8, 0x56, 0x9f,
0x42, 0xcf, 0x57, 0x4f, 0x0a, 0xdc, 0x06, 0xe0, 0x8f, 0x71, 0xa1, 0x1a, 0x44, 0x04, 0xdd, 0x42, 0x13, 0xaf, 0xfd, 0x1b, 0xa6, 0xf8, 0x26, 0x9f, 0xbc, 0xa6, 0xd2, 0x5b, 0x46, 0xe6, 0xb8, 0x66,
0x08, 0x2a, 0x41, 0x6e, 0x42, 0x85, 0xba, 0x63, 0x8e, 0xe4, 0xb3, 0xa1, 0x4c, 0xdd, 0xb1, 0x54, 0xf8, 0x0b, 0xe9, 0xe1, 0xbf, 0x7e, 0x78, 0xb3, 0x9c, 0x0a, 0x4a, 0x59, 0x4e, 0x05, 0xaf, 0x63,
0xa1, 0xa4, 0x36, 0xf9, 0x46, 0x5c, 0x7c, 0x11, 0xe1, 0x63, 0x58, 0xef, 0xd0, 0x0b, 0x14, 0x36, 0xca, 0x4f, 0xc5, 0x86, 0x28, 0xa7, 0x63, 0x34, 0x3f, 0x82, 0x8d, 0x18, 0x0e, 0x52, 0x6b, 0xe7,
0x8a, 0x2a, 0x7c, 0xcc, 0xa1, 0x7d, 0x89, 0xde, 0xf1, 0x81, 0xf1, 0x0f, 0xf3, 0xb0, 0x14, 0xd5, 0xd4, 0x51, 0x8f, 0x0b, 0xac, 0x6a, 0xd8, 0x03, 0x99, 0xb6, 0x5d, 0x86, 0x52, 0x30, 0xf2, 0x66,
0x8f, 0x07, 0xd0, 0xba, 0x9b, 0x0a, 0x05, 0x26, 0xfc, 0xa1, 0x14, 0x0f, 0xbf, 0x2b, 0xa6, 0x84, 0xe8, 0x87, 0x1e, 0x1f, 0x55, 0x71, 0x4c, 0xfc, 0x76, 0x0e, 0x5a, 0x7b, 0x51, 0xb0, 0x6b, 0x27,
0xc3, 0x4e, 0x6b, 0x9a, 0x6a, 0xbd, 0xc2, 0x17, 0x68, 0xd7, 0x25, 0x06, 0xd4, 0x24, 0x85, 0x37, 0x08, 0x3d, 0x5f, 0xbd, 0xdb, 0x70, 0x1b, 0x80, 0xbf, 0x85, 0x86, 0x6a, 0x10, 0x11, 0xa5, 0x0c,
0x0f, 0xb5, 0x50, 0xc9, 0x55, 0x4e, 0xd2, 0x9f, 0x87, 0xec, 0x78, 0x6d, 0x4f, 0x99, 0xb4, 0x22, 0x21, 0xa8, 0x04, 0xb9, 0x09, 0x15, 0xea, 0x8e, 0x79, 0x22, 0x5f, 0x0d, 0x65, 0xea, 0x8e, 0xa5,
0x0e, 0xb8, 0x25, 0x7b, 0x1a, 0x76, 0xf1, 0xd5, 0x37, 0x06, 0x66, 0xc9, 0xf8, 0x60, 0x32, 0x2a, 0x0a, 0x25, 0x75, 0xc8, 0x37, 0xe2, 0xec, 0x8b, 0x88, 0xb7, 0xc3, 0x46, 0x87, 0x5e, 0x20, 0xb3,
0x46, 0xdf, 0xe4, 0xa7, 0x2d, 0x3e, 0x7a, 0x78, 0xd2, 0xd2, 0x8f, 0x22, 0xfc, 0x15, 0x1a, 0x75, 0x51, 0x54, 0xf1, 0x76, 0x0e, 0xed, 0x4b, 0xbc, 0x4e, 0x10, 0x18, 0xff, 0x20, 0x0f, 0x4b, 0x51,
0x14, 0x79, 0x1d, 0x6a, 0x3c, 0xf3, 0x28, 0xba, 0x05, 0xc6, 0x2d, 0x0c, 0xbb, 0x2e, 0xe2, 0x85, 0xfb, 0x78, 0xc4, 0xb1, 0xbb, 0xa9, 0xd8, 0x69, 0xc2, 0x1f, 0x4a, 0xd1, 0xf0, 0xbb, 0x62, 0x49,
0x9a, 0xd3, 0x9b, 0xc7, 0x34, 0x37, 0xc0, 0x8b, 0x92, 0x4f, 0x77, 0xa9, 0x16, 0x5b, 0xca, 0x08, 0x38, 0x4c, 0x5a, 0xd3, 0x54, 0xeb, 0x15, 0xbe, 0x41, 0xbb, 0x2e, 0x31, 0xa0, 0x26, 0x31, 0xbc,
0x59, 0x53, 0xb0, 0x5e, 0xc0, 0xa4, 0x95, 0x9b, 0x19, 0xa3, 0x2b, 0x98, 0xc1, 0x0e, 0x68, 0x81, 0x79, 0xa8, 0xc5, 0x96, 0xae, 0x72, 0x94, 0xfe, 0x3c, 0x64, 0xe2, 0xb5, 0x3d, 0x65, 0xdc, 0x8a,
0xbe, 0xe5, 0x20, 0x70, 0x8e, 0xb0, 0x2e, 0xb9, 0x6f, 0xbc, 0xeb, 0xcd, 0xe6, 0x69, 0x1c, 0x10, 0x10, 0x70, 0x4b, 0xf6, 0x34, 0xec, 0xe2, 0xa3, 0x7b, 0x0c, 0xcc, 0xb2, 0xf1, 0xc9, 0x64, 0x58,
0x9d, 0xc2, 0xf9, 0x40, 0xc7, 0xc2, 0xb0, 0xa0, 0x4c, 0xc7, 0x47, 0x9b, 0x1f, 0x80, 0x8f, 0x60, 0x0c, 0xbf, 0xc9, 0xa5, 0x2d, 0x3e, 0x7b, 0x28, 0x69, 0xe9, 0xa2, 0x08, 0x7f, 0xea, 0x47, 0x89,
0xb3, 0x73, 0xc9, 0x18, 0x8b, 0x72, 0xac, 0x1f, 0x3d, 0x9b, 0x4b, 0xfb, 0x68, 0xc2, 0xca, 0x92, 0x22, 0x6f, 0x42, 0x8d, 0x17, 0x1e, 0x85, 0x03, 0xc1, 0x40, 0x8f, 0x61, 0xd7, 0xc5, 0x74, 0xa1,
0x7b, 0x25, 0x2b, 0xcb, 0x98, 0x07, 0x3f, 0x50, 0x79, 0xfd, 0x24, 0x99, 0x70, 0xfd, 0x92, 0xed, 0xe6, 0xf4, 0xe6, 0x31, 0xcd, 0x0d, 0xf0, 0xaa, 0xe4, 0xfb, 0x68, 0xaa, 0xc7, 0x96, 0x32, 0x42,
0x5a, 0x27, 0x98, 0x85, 0x8c, 0xb5, 0xc2, 0x40, 0x3c, 0x53, 0x23, 0x80, 0xa5, 0xc3, 0xf9, 0x24, 0xd6, 0x14, 0xac, 0x17, 0x30, 0x6e, 0xe5, 0x66, 0xc6, 0xec, 0x0a, 0x62, 0xb0, 0x03, 0x5a, 0x64,
0x74, 0x76, 0x14, 0x88, 0x7c, 0x2c, 0xd2, 0x60, 0x39, 0xb2, 0xd7, 0x32, 0x0b, 0x02, 0x55, 0x10, 0x74, 0x39, 0x09, 0x9c, 0x22, 0xac, 0x4b, 0xea, 0x1b, 0x1f, 0x7a, 0xb3, 0x79, 0x1a, 0x07, 0x44,
0x76, 0xd6, 0x94, 0x65, 0x64, 0xa5, 0xcb, 0x5b, 0x9a, 0xc6, 0x4b, 0x30, 0x6e, 0xc2, 0x46, 0xf4, 0x52, 0x38, 0x9f, 0xe8, 0x58, 0xdc, 0x1a, 0xe4, 0xe9, 0xf8, 0x6c, 0x73, 0x01, 0xf8, 0x08, 0x36,
0xc5, 0xbb, 0x4d, 0xee, 0x48, 0x7f, 0x2b, 0xc7, 0x6f, 0xec, 0x70, 0xdc, 0xc0, 0xb5, 0x67, 0xc1, 0x3b, 0x97, 0x8c, 0xb0, 0x28, 0xc7, 0xfa, 0xd1, 0xf3, 0xb9, 0xb4, 0x8f, 0x26, 0xac, 0x2c, 0xb9,
0xb9, 0x17, 0x92, 0x0e, 0xac, 0x04, 0x8e, 0x7b, 0x36, 0xa1, 0x7a, 0xf6, 0x81, 0xe8, 0x84, 0xb5, 0xd7, 0xb2, 0xb2, 0x8c, 0x79, 0xb4, 0x08, 0x55, 0xd6, 0x4f, 0x52, 0x08, 0xd7, 0x2f, 0xd9, 0xae,
0x78, 0xdd, 0x78, 0xd2, 0xc0, 0x5c, 0xe6, 0x29, 0xa2, 0xdc, 0x02, 0xb2, 0x7d, 0x5d, 0x25, 0xa3, 0x75, 0x82, 0x45, 0xc8, 0xe0, 0x34, 0x0c, 0xc4, 0x0b, 0x35, 0x02, 0x58, 0x3a, 0x9c, 0x4f, 0x42,
0x69, 0x91, 0xe8, 0x8d, 0x74, 0xe5, 0xbb, 0xb0, 0x18, 0x2f, 0x88, 0x7c, 0x2a, 0x62, 0x86, 0x44, 0x67, 0x47, 0x81, 0xc8, 0x27, 0x22, 0x0f, 0xd6, 0x23, 0x47, 0x2d, 0xb3, 0x22, 0x50, 0x15, 0xe1,
0xb5, 0x2a, 0x24, 0x22, 0x26, 0x44, 0x13, 0xa2, 0x16, 0xf5, 0x7d, 0x60, 0xfc, 0xa5, 0x1c, 0xb4, 0x60, 0x4d, 0x59, 0x41, 0x56, 0xba, 0xbe, 0xa5, 0x69, 0xbc, 0x06, 0xe3, 0x26, 0x6c, 0x44, 0x5f,
0x4c, 0xca, 0x66, 0xae, 0x56, 0x4b, 0x39, 0x67, 0xbe, 0x93, 0xca, 0xf5, 0xfa, 0xb6, 0xca, 0x50, 0x7c, 0xd8, 0xe4, 0x89, 0xf4, 0x37, 0x73, 0xfc, 0x8a, 0x13, 0x4f, 0x1b, 0xb8, 0xf6, 0x2c, 0x38,
0x24, 0xb2, 0x46, 0xef, 0x5d, 0x3b, 0x18, 0xfb, 0x37, 0x52, 0x2d, 0xda, 0xae, 0xc0, 0x02, 0x27, 0xf7, 0x42, 0xd2, 0x81, 0x95, 0xc0, 0x71, 0xcf, 0x26, 0x54, 0x2f, 0x3e, 0x10, 0x83, 0xb0, 0x16,
0x31, 0x36, 0x60, 0x4d, 0xd4, 0x47, 0xd6, 0x25, 0x32, 0xe8, 0xc7, 0x4a, 0x8c, 0x19, 0xf4, 0x37, 0x6f, 0x1b, 0xcf, 0x1a, 0x98, 0xcb, 0x3c, 0x47, 0x54, 0x5a, 0x40, 0xb6, 0xaf, 0x6b, 0x64, 0xb4,
0xa1, 0xc5, 0xaf, 0xf6, 0xeb, 0x8d, 0x10, 0x09, 0x77, 0x81, 0x1c, 0xda, 0x23, 0xdb, 0xf7, 0x3c, 0x2c, 0x12, 0xa3, 0x91, 0x6e, 0x7c, 0x17, 0x16, 0xe3, 0x15, 0x91, 0xcf, 0x44, 0x90, 0x95, 0xa8,
0xf7, 0x88, 0xfa, 0xc2, 0x65, 0x1e, 0x05, 0x51, 0xb4, 0x77, 0x4b, 0x89, 0x99, 0x7f, 0xc9, 0x18, 0x55, 0x85, 0x44, 0x88, 0x89, 0x68, 0x41, 0xd4, 0xa2, 0xb1, 0x0f, 0x8c, 0xbf, 0x94, 0x83, 0x96,
0xf2, 0x9e, 0x2b, 0x3d, 0x04, 0xf9, 0x97, 0xe1, 0xc3, 0xca, 0xb6, 0xfd, 0x8c, 0xca, 0x9c, 0x64, 0x49, 0xd9, 0xca, 0xd5, 0x5a, 0x29, 0xd7, 0xcc, 0x77, 0x53, 0xa5, 0x5e, 0xdf, 0x57, 0x19, 0xbb,
0x17, 0x3d, 0x86, 0xda, 0x4c, 0x65, 0x2a, 0xfb, 0x5d, 0x86, 0x63, 0x4a, 0x17, 0x6b, 0xea, 0xd4, 0x45, 0xb6, 0xe8, 0x3b, 0xd7, 0x4e, 0xc6, 0xfe, 0x8d, 0x54, 0x8f, 0xb6, 0x2b, 0xb0, 0xc0, 0x51,
0x8c, 0x4b, 0xa1, 0xc2, 0x16, 0x03, 0x9c, 0x8c, 0xe5, 0x9e, 0xcf, 0x40, 0x4f, 0xe9, 0x55, 0x77, 0x8c, 0x0d, 0x58, 0x13, 0xed, 0x91, 0x6d, 0x89, 0x0c, 0xfa, 0xb1, 0x1a, 0x63, 0x06, 0xfd, 0x4d,
0x6c, 0x3c, 0x84, 0xd5, 0x78, 0x99, 0x82, 0xb5, 0x6c, 0x42, 0x65, 0x2a, 0x60, 0xa2, 0xf6, 0xea, 0x68, 0xf1, 0x58, 0x08, 0x7a, 0x27, 0x44, 0xc6, 0x5d, 0x20, 0x87, 0xf6, 0xc8, 0xf6, 0x3d, 0xcf,
0x9b, 0x9d, 0x59, 0xd8, 0xb9, 0x53, 0xa6, 0xe9, 0xee, 0xaa, 0x5b, 0xfa, 0x8f, 0x61, 0x23, 0x85, 0x3d, 0xa2, 0xbe, 0x70, 0x99, 0x47, 0x46, 0x14, 0xed, 0xdd, 0x92, 0x63, 0xe6, 0x5f, 0x32, 0xe8,
0x11, 0x19, 0xde, 0x85, 0xba, 0x56, 0x11, 0xde, 0x8c, 0xa2, 0x09, 0xaa, 0x26, 0x81, 0xf1, 0x39, 0xbe, 0xe7, 0x4a, 0x0f, 0x41, 0xfe, 0x65, 0xf8, 0xb0, 0xb2, 0x6d, 0x3f, 0xa7, 0xb2, 0x24, 0x39,
0x6c, 0xf0, 0x63, 0x5b, 0x94, 0x5c, 0x76, 0x41, 0xa2, 0x15, 0xb9, 0x64, 0x2b, 0x3e, 0x96, 0x67, 0x44, 0x5f, 0x42, 0x6d, 0xa6, 0x0a, 0x95, 0xe3, 0x2e, 0xe3, 0x57, 0xa5, 0xab, 0x35, 0x75, 0x6c,
0x4d, 0x3d, 0x69, 0x14, 0x0e, 0x71, 0x8c, 0x38, 0xe9, 0xe4, 0x25, 0x3f, 0x8d, 0x63, 0x58, 0x4f, 0x46, 0xa5, 0x50, 0x61, 0x8b, 0x11, 0x61, 0xc6, 0xf2, 0xcc, 0x67, 0xa0, 0x27, 0xf4, 0xaa, 0x3b,
0x77, 0x1f, 0xab, 0xff, 0x9f, 0xaa, 0xcb, 0x65, 0xf7, 0x44, 0x68, 0xd5, 0x3d, 0xff, 0x25, 0xc7, 0x36, 0x1e, 0xc2, 0x6a, 0xbc, 0x4e, 0x41, 0x5a, 0x36, 0xa1, 0x32, 0x15, 0x30, 0xd1, 0x7a, 0xf5,
0xfb, 0x27, 0x86, 0x12, 0xd5, 0x1c, 0x03, 0x99, 0xd2, 0xf0, 0xdc, 0x1b, 0x5b, 0xe9, 0x92, 0x1f, 0xcd, 0x64, 0x16, 0x26, 0x77, 0xca, 0x3c, 0xdd, 0x5d, 0x15, 0xd6, 0xe0, 0x4b, 0xd8, 0x48, 0xa5,
0x29, 0x1f, 0xb3, 0xcc, 0xb4, 0x5b, 0x87, 0x98, 0x50, 0xc3, 0x88, 0xdb, 0x0e, 0xd3, 0x24, 0x7c, 0x88, 0x02, 0xef, 0x42, 0x5d, 0x6b, 0x08, 0xef, 0x46, 0xd1, 0x04, 0xd5, 0x92, 0xc0, 0xf8, 0x02,
0x73, 0x04, 0xeb, 0xd9, 0xc4, 0x19, 0x9e, 0x59, 0x1f, 0xc5, 0xe5, 0xf9, 0xdb, 0xd7, 0x36, 0x9f, 0x36, 0xb8, 0xd8, 0x16, 0x65, 0x97, 0x43, 0x90, 0xe8, 0x45, 0x2e, 0xd9, 0x8b, 0x4f, 0xa4, 0xac,
0x55, 0x4b, 0x17, 0xef, 0x7f, 0xa7, 0x02, 0x65, 0xa1, 0xaa, 0x21, 0x5b, 0x50, 0x1c, 0x49, 0x2f, 0xa9, 0x67, 0x8d, 0xe2, 0x47, 0x8e, 0x31, 0x4d, 0x3a, 0x79, 0xc9, 0x4f, 0xe3, 0x18, 0xd6, 0xd3,
0xdf, 0x28, 0x24, 0xa6, 0xc0, 0xca, 0xff, 0x3b, 0xe8, 0xeb, 0xcb, 0xe8, 0xc8, 0x63, 0x58, 0x8c, 0xc3, 0xc7, 0xda, 0xff, 0x67, 0x1a, 0x72, 0x39, 0x3c, 0x51, 0xb2, 0x1a, 0x9e, 0xff, 0x9c, 0xe3,
0x3b, 0xba, 0x24, 0x42, 0xd7, 0xc4, 0x3d, 0x54, 0x1a, 0xa3, 0x84, 0x13, 0x41, 0x35, 0x92, 0xc1, 0xe3, 0x13, 0x4b, 0x12, 0xcd, 0x1c, 0x03, 0x99, 0xd2, 0xf0, 0xdc, 0x1b, 0x5b, 0xe9, 0x9a, 0x1f,
0xb8, 0x68, 0x5a, 0x39, 0xd7, 0x84, 0x34, 0xcf, 0x65, 0xc7, 0xba, 0xe0, 0xdc, 0xb6, 0x1e, 0x3e, 0x29, 0x1f, 0xb3, 0xcc, 0xbc, 0x5b, 0x87, 0x98, 0x51, 0x4b, 0x11, 0xb7, 0x1d, 0xa6, 0x49, 0xf8,
0xfa, 0x44, 0x18, 0x15, 0x6a, 0x08, 0x1c, 0x9c, 0xdb, 0x0f, 0x1f, 0x7d, 0x92, 0x3c, 0xb0, 0x89, 0xe6, 0x08, 0xd6, 0xb3, 0x91, 0x33, 0x3c, 0xb3, 0x3e, 0x8e, 0xf3, 0xf3, 0xb7, 0xaf, 0xed, 0x3e,
0xc8, 0x35, 0xda, 0x81, 0x6d, 0x15, 0x4a, 0x3c, 0xd0, 0x3e, 0x77, 0xd7, 0xe4, 0x1f, 0x52, 0x9d, 0x6b, 0x96, 0xce, 0xde, 0xff, 0x6e, 0x05, 0xca, 0x42, 0x55, 0x43, 0xb6, 0xa0, 0x38, 0x92, 0x5e,
0x31, 0xf7, 0xa9, 0x25, 0x2e, 0xd6, 0xf0, 0x5d, 0x94, 0x3f, 0x70, 0x46, 0x04, 0x6e, 0x80, 0x28, 0xbe, 0x51, 0x0c, 0x51, 0x91, 0x2a, 0xff, 0xef, 0xa0, 0xaf, 0x2f, 0xc3, 0x23, 0x5f, 0xc2, 0x62,
0xae, 0x4e, 0x5c, 0x87, 0x85, 0xf3, 0xe8, 0xe5, 0x84, 0x86, 0x29, 0xbe, 0x8c, 0xff, 0x59, 0x82, 0xdc, 0xd1, 0x25, 0x11, 0xeb, 0x27, 0xee, 0xa1, 0xd2, 0x18, 0x25, 0x9c, 0x08, 0xaa, 0x11, 0x0f,
0x9a, 0xd6, 0x29, 0xa4, 0x0e, 0x15, 0xb3, 0x33, 0xe8, 0x98, 0x5f, 0x74, 0x76, 0x9b, 0x37, 0xc8, 0xc6, 0x59, 0xd3, 0xca, 0xb9, 0xc6, 0xa4, 0x79, 0x2e, 0x13, 0xeb, 0x82, 0x73, 0xdb, 0x7a, 0xf8,
0x3d, 0x78, 0xab, 0xdb, 0xdb, 0xe9, 0x9b, 0x66, 0x67, 0x67, 0x68, 0xf5, 0x4d, 0x4b, 0x46, 0x6a, 0xe8, 0x53, 0x61, 0x54, 0xa8, 0x21, 0x70, 0x70, 0x6e, 0x3f, 0x7c, 0xf4, 0x69, 0x52, 0x60, 0x13,
0x3d, 0x6a, 0x7f, 0x75, 0xd8, 0xe9, 0x0d, 0xad, 0xdd, 0xce, 0xb0, 0xdd, 0x3d, 0x18, 0x34, 0x73, 0xa1, 0x7e, 0x34, 0x81, 0x6d, 0x15, 0x4a, 0xfc, 0x65, 0x02, 0xee, 0xae, 0xc9, 0x3f, 0xa4, 0x3a,
0xe4, 0x35, 0x68, 0x45, 0x94, 0x12, 0xdd, 0x3e, 0xec, 0x1f, 0xf7, 0x86, 0xcd, 0x3c, 0xb9, 0x03, 0x63, 0xee, 0x53, 0x4b, 0x5c, 0xac, 0xe1, 0xa7, 0x28, 0x7f, 0x45, 0x8e, 0x88, 0xb4, 0x01, 0x26,
0xb7, 0xf6, 0xba, 0xbd, 0xf6, 0x81, 0x15, 0xd1, 0xec, 0x1c, 0x0c, 0xbf, 0xb0, 0x3a, 0x3f, 0x77, 0x71, 0x75, 0xe2, 0x3a, 0x2c, 0x9c, 0x47, 0x4f, 0x4d, 0x34, 0x4c, 0xf1, 0x65, 0xfc, 0x8f, 0x12,
0xd4, 0x35, 0xbf, 0x6a, 0x16, 0xb2, 0x08, 0xf6, 0x87, 0x07, 0x3b, 0x32, 0x87, 0x22, 0xb9, 0x09, 0xd4, 0xb4, 0x41, 0x21, 0x75, 0xa8, 0x98, 0x9d, 0x41, 0xc7, 0x7c, 0xda, 0xd9, 0x6d, 0xde, 0x20,
0x6b, 0x9c, 0x80, 0x27, 0xb1, 0x86, 0xfd, 0xbe, 0x35, 0xe8, 0xf7, 0x7b, 0xcd, 0x12, 0x59, 0x86, 0xf7, 0xe0, 0x9d, 0x6e, 0x6f, 0xa7, 0x6f, 0x9a, 0x9d, 0x9d, 0xa1, 0xd5, 0x37, 0x2d, 0x19, 0xda,
0x46, 0xb7, 0xf7, 0x45, 0xfb, 0xa0, 0xbb, 0x6b, 0x99, 0x9d, 0xf6, 0xc1, 0x61, 0x73, 0x81, 0xac, 0xf6, 0xa8, 0xfd, 0xec, 0xb0, 0xd3, 0x1b, 0x5a, 0xbb, 0x9d, 0x61, 0xbb, 0x7b, 0x30, 0x68, 0xe6,
0xc0, 0x52, 0x92, 0xae, 0xcc, 0xb2, 0x90, 0x74, 0xfd, 0x5e, 0xb7, 0xdf, 0xb3, 0xbe, 0xe8, 0x98, 0xc8, 0x1b, 0xd0, 0x8a, 0x30, 0x65, 0x72, 0xfb, 0xb0, 0x7f, 0xdc, 0x1b, 0x36, 0xf3, 0xe4, 0x0e,
0x83, 0x6e, 0xbf, 0xd7, 0xac, 0x90, 0x75, 0x20, 0x71, 0xd4, 0xfe, 0x61, 0x7b, 0xa7, 0x59, 0x25, 0xdc, 0xda, 0xeb, 0xf6, 0xda, 0x07, 0x56, 0x84, 0xb3, 0x73, 0x30, 0x7c, 0x6a, 0x75, 0x7e, 0xee,
0x6b, 0xb0, 0x1c, 0x87, 0x3f, 0xed, 0x7c, 0xd5, 0x04, 0xd2, 0x82, 0x55, 0x5e, 0x31, 0x6b, 0xbb, 0xa8, 0x6b, 0x3e, 0x6b, 0x16, 0xb2, 0x10, 0xf6, 0x87, 0x07, 0x3b, 0xb2, 0x84, 0x22, 0xb9, 0x09,
0x73, 0xd0, 0xff, 0xd2, 0x3a, 0xec, 0xf6, 0xba, 0x87, 0xc7, 0x87, 0xcd, 0x1a, 0xc6, 0xcb, 0xee, 0x6b, 0x1c, 0x81, 0x67, 0xb1, 0x86, 0xfd, 0xbe, 0x35, 0xe8, 0xf7, 0x7b, 0xcd, 0x12, 0x59, 0x86,
0x74, 0xac, 0x6e, 0x6f, 0x70, 0xbc, 0xb7, 0xd7, 0xdd, 0xe9, 0x76, 0x7a, 0xc3, 0x66, 0x9d, 0x97, 0x46, 0xb7, 0xf7, 0xb4, 0x7d, 0xd0, 0xdd, 0xb5, 0xcc, 0x4e, 0xfb, 0xe0, 0xb0, 0xb9, 0x40, 0x56,
0x9c, 0xd5, 0xf0, 0x06, 0x4b, 0x20, 0xae, 0x52, 0x5a, 0xbb, 0xdd, 0x41, 0x7b, 0xfb, 0xa0, 0xb3, 0x60, 0x29, 0x89, 0x57, 0x66, 0x45, 0x48, 0xbc, 0x7e, 0xaf, 0xdb, 0xef, 0x59, 0x4f, 0x3b, 0xe6,
0xdb, 0x5c, 0x24, 0xb7, 0xe1, 0xe6, 0xb0, 0x73, 0x78, 0xd4, 0x37, 0xdb, 0xe6, 0x57, 0xf2, 0xaa, 0xa0, 0xdb, 0xef, 0x35, 0x2b, 0x64, 0x1d, 0x48, 0x3c, 0x69, 0xff, 0xb0, 0xbd, 0xd3, 0xac, 0x92,
0xa5, 0xb5, 0xd7, 0xee, 0x1e, 0x1c, 0x9b, 0x9d, 0xe6, 0x12, 0x79, 0x03, 0x6e, 0x9b, 0x9d, 0x1f, 0x35, 0x58, 0x8e, 0xc3, 0x9f, 0x74, 0x9e, 0x35, 0x81, 0xb4, 0x60, 0x95, 0x37, 0xcc, 0xda, 0xee,
0x1c, 0x77, 0xcd, 0xce, 0xae, 0xd5, 0xeb, 0xef, 0x76, 0xac, 0xbd, 0x4e, 0x7b, 0x78, 0x6c, 0x76, 0x1c, 0xf4, 0xbf, 0xb2, 0x0e, 0xbb, 0xbd, 0xee, 0xe1, 0xf1, 0x61, 0xb3, 0x86, 0x01, 0xc6, 0x3b,
0xac, 0xc3, 0xee, 0x60, 0xd0, 0xed, 0x3d, 0x69, 0x36, 0xc9, 0x5b, 0x70, 0x57, 0x91, 0xa8, 0x0c, 0x1d, 0xab, 0xdb, 0x1b, 0x1c, 0xef, 0xed, 0x75, 0x77, 0xba, 0x9d, 0xde, 0xb0, 0x59, 0xe7, 0x35,
0x12, 0x54, 0xcb, 0xac, 0x7d, 0x72, 0x48, 0x7b, 0x9d, 0x9f, 0x1b, 0x5a, 0x47, 0x9d, 0x8e, 0xd9, 0x67, 0x75, 0xbc, 0xc1, 0x32, 0x88, 0xbb, 0xa7, 0xd6, 0x6e, 0x77, 0xd0, 0xde, 0x3e, 0xe8, 0xec,
0x24, 0x64, 0x13, 0xd6, 0xa3, 0xe2, 0x79, 0x01, 0xa2, 0xec, 0x15, 0x86, 0x3b, 0xea, 0x98, 0x87, 0x36, 0x17, 0xc9, 0x6d, 0xb8, 0x39, 0xec, 0x1c, 0x1e, 0xf5, 0xcd, 0xb6, 0xf9, 0x4c, 0xde, 0x4d,
0xed, 0x1e, 0x1b, 0xe0, 0x18, 0x6e, 0x95, 0x55, 0x3b, 0xc2, 0x25, 0xab, 0xbd, 0x46, 0x08, 0x2c, 0xb5, 0xf6, 0xda, 0xdd, 0x83, 0x63, 0xb3, 0xd3, 0x5c, 0x22, 0x6f, 0xc1, 0x6d, 0xb3, 0xf3, 0xc3,
0x6a, 0xa3, 0xb2, 0xd7, 0x36, 0x9b, 0xeb, 0x64, 0x09, 0x6a, 0x87, 0x47, 0x47, 0xd6, 0xb0, 0x7b, 0xe3, 0xae, 0xd9, 0xd9, 0xb5, 0x7a, 0xfd, 0xdd, 0x8e, 0xb5, 0xd7, 0x69, 0x0f, 0x8f, 0xcd, 0x8e,
0xd8, 0xe9, 0x1f, 0x0f, 0x9b, 0x1b, 0xe9, 0x51, 0x3a, 0x6a, 0x7f, 0x75, 0xd0, 0x6f, 0xef, 0x36, 0x75, 0xd8, 0x1d, 0x0c, 0xba, 0xbd, 0xc7, 0xcd, 0x26, 0x79, 0x07, 0xee, 0x2a, 0x14, 0x55, 0x40,
0x5b, 0x64, 0x0d, 0x9a, 0xdd, 0xde, 0xb0, 0x63, 0xb2, 0x69, 0x20, 0x73, 0xfd, 0xaf, 0x65, 0xb2, 0x02, 0x6b, 0x99, 0xf5, 0x4f, 0x4e, 0x69, 0xaf, 0xf3, 0x73, 0x43, 0xeb, 0xa8, 0xd3, 0x31, 0x9b,
0x0a, 0x4b, 0xb2, 0x11, 0x12, 0xfa, 0x87, 0x65, 0xb2, 0x01, 0xe4, 0xb8, 0x67, 0x76, 0xda, 0xbb, 0x84, 0x6c, 0xc2, 0x7a, 0x54, 0x3d, 0xaf, 0x40, 0xd4, 0xbd, 0xc2, 0xd2, 0x8e, 0x3a, 0xe6, 0x61,
0xac, 0x4f, 0x15, 0xe2, 0xbf, 0x95, 0x85, 0x79, 0xf9, 0x77, 0x0b, 0x4a, 0x0e, 0x8c, 0x1c, 0xcc, 0xbb, 0xc7, 0x26, 0x38, 0x96, 0xb6, 0xca, 0x9a, 0x1d, 0xa5, 0x25, 0x9b, 0xbd, 0x46, 0x08, 0x2c,
0xe2, 0xaf, 0x20, 0xd5, 0xb5, 0xd7, 0x8b, 0x5e, 0xf6, 0xea, 0xa5, 0x76, 0xb8, 0x2f, 0xa4, 0x0e, 0x6a, 0xb3, 0xb2, 0xd7, 0x36, 0x9b, 0xeb, 0x64, 0x09, 0x6a, 0x87, 0x47, 0x47, 0xd6, 0xb0, 0x7b,
0xf7, 0x29, 0xed, 0x51, 0x43, 0x3f, 0x79, 0xbc, 0x09, 0x8d, 0x29, 0x7f, 0x11, 0x49, 0x3c, 0xa9, 0xd8, 0xe9, 0x1f, 0x0f, 0x9b, 0x1b, 0xe9, 0x59, 0x3a, 0x6a, 0x3f, 0x3b, 0xe8, 0xb7, 0x77, 0x9b,
0x01, 0xc2, 0xdb, 0x92, 0x03, 0xf9, 0x7b, 0x1a, 0xa9, 0x67, 0x1f, 0x4b, 0xe9, 0x67, 0x1f, 0xb3, 0x2d, 0xb2, 0x06, 0xcd, 0x6e, 0x6f, 0xd8, 0x31, 0xd9, 0x32, 0x90, 0xa5, 0xfe, 0x97, 0x32, 0x59,
0x4e, 0x98, 0x0b, 0x59, 0x27, 0xcc, 0xfb, 0xb0, 0xcc, 0xb9, 0x96, 0xe3, 0x3a, 0x53, 0xa9, 0xb7, 0x85, 0x25, 0xd9, 0x09, 0x09, 0xfd, 0xa3, 0x32, 0xd9, 0x00, 0x72, 0xdc, 0x33, 0x3b, 0xed, 0x5d,
0x11, 0x8f, 0x28, 0x22, 0xf7, 0xe2, 0x70, 0x79, 0xa0, 0x95, 0x87, 0x5e, 0xc1, 0x5d, 0xca, 0xe2, 0x36, 0xa6, 0x2a, 0xe1, 0xbf, 0x96, 0x85, 0x79, 0xf9, 0xf7, 0x0a, 0x8a, 0x0f, 0x8c, 0x1c, 0xcc,
0xbc, 0x1b, 0x3b, 0xeb, 0x72, 0xa6, 0xa2, 0xce, 0xba, 0xaa, 0x04, 0xfb, 0x32, 0x2a, 0xa1, 0xa6, 0xe2, 0xcf, 0x46, 0xd5, 0xb5, 0xe7, 0x9e, 0x5e, 0xf5, 0xb4, 0xa8, 0x26, 0xdc, 0x17, 0x52, 0xc2,
0x95, 0xc0, 0xe1, 0x58, 0xc2, 0x7d, 0x58, 0xa6, 0x97, 0xa1, 0x6f, 0x5b, 0xde, 0xcc, 0xfe, 0xd1, 0x7d, 0x4a, 0x7b, 0xd4, 0xd0, 0x25, 0x8f, 0xb7, 0xa1, 0x31, 0xe5, 0x4f, 0x48, 0x89, 0x37, 0x48,
0x1c, 0x5d, 0x64, 0x6c, 0xd4, 0x22, 0xd5, 0xcd, 0x25, 0x44, 0xf4, 0x11, 0xbe, 0x6b, 0x87, 0xb6, 0x40, 0x78, 0x5b, 0x72, 0x20, 0x7f, 0x80, 0x24, 0xf5, 0xb6, 0x66, 0x29, 0xfd, 0xb6, 0x66, 0x96,
0xf1, 0x0b, 0x00, 0x6a, 0xc3, 0xc5, 0xc7, 0x28, 0x5d, 0x4f, 0xde, 0xa9, 0xad, 0x9b, 0xfc, 0x03, 0x84, 0xb9, 0x90, 0x25, 0x61, 0xde, 0x87, 0x65, 0x4e, 0xb5, 0x1c, 0xd7, 0x99, 0x4a, 0xbd, 0x8d,
0xc7, 0x31, 0xf4, 0x7c, 0xfb, 0x8c, 0x76, 0xa5, 0x55, 0x38, 0x02, 0x90, 0x5b, 0x50, 0xf0, 0x66, 0x78, 0xa9, 0x12, 0xa9, 0x17, 0x87, 0x4b, 0x81, 0x56, 0x0a, 0xbd, 0x82, 0xba, 0x94, 0x85, 0xbc,
0xd2, 0x17, 0xb1, 0x2a, 0x63, 0xc4, 0xcf, 0x4c, 0x06, 0x35, 0x3e, 0x81, 0x7c, 0x7f, 0x76, 0xad, 0x1b, 0x93, 0x75, 0x39, 0x51, 0x51, 0xb2, 0xae, 0xaa, 0xc1, 0xbe, 0x8c, 0x6a, 0xa8, 0x69, 0x35,
0x14, 0xd5, 0x82, 0xb2, 0x7c, 0x0b, 0x3a, 0x8f, 0xfe, 0x87, 0xf2, 0xf3, 0xfe, 0x9f, 0x87, 0x9a, 0x70, 0x38, 0xd6, 0x70, 0x1f, 0x96, 0xe9, 0x65, 0xe8, 0xdb, 0x96, 0x37, 0xb3, 0x7f, 0x34, 0x47,
0xf6, 0x88, 0x17, 0xd9, 0x80, 0x95, 0x2f, 0xbb, 0xc3, 0x5e, 0x67, 0x30, 0xb0, 0x8e, 0x8e, 0xb7, 0x17, 0x19, 0x1b, 0xb5, 0x48, 0x75, 0x73, 0x09, 0x13, 0xfa, 0x08, 0xdf, 0xb5, 0x43, 0xdb, 0xf8,
0x9f, 0x76, 0xbe, 0xb2, 0xf6, 0xdb, 0x83, 0xfd, 0xe6, 0x0d, 0xc6, 0x66, 0x7a, 0x9d, 0xc1, 0xb0, 0x45, 0x00, 0x75, 0xe0, 0xe2, 0x8b, 0x9f, 0xae, 0x27, 0xef, 0xd4, 0xd6, 0x4d, 0xfe, 0x81, 0xf3,
0xb3, 0x1b, 0x83, 0xe7, 0xc8, 0xeb, 0xb0, 0x79, 0xdc, 0x3b, 0x1e, 0x74, 0x76, 0xad, 0xac, 0x74, 0x18, 0x7a, 0xbe, 0x7d, 0x46, 0xbb, 0xd2, 0x2a, 0x1c, 0x01, 0xc8, 0x2d, 0x28, 0x78, 0x33, 0xe9,
0x79, 0xb6, 0xae, 0x04, 0x3e, 0x23, 0x79, 0xe1, 0xfe, 0x2f, 0xc2, 0x62, 0x3c, 0x4e, 0x0a, 0x01, 0x8b, 0x58, 0x95, 0x41, 0xf5, 0x67, 0x26, 0x83, 0x1a, 0x9f, 0x42, 0xbe, 0x3f, 0xbb, 0x96, 0x8b,
0x58, 0x38, 0xe8, 0x3c, 0x69, 0xef, 0x7c, 0xc5, 0xdf, 0x00, 0x18, 0x0c, 0xdb, 0xc3, 0xee, 0x8e, 0xc2, 0x07, 0xce, 0xf8, 0xab, 0x06, 0x79, 0xf4, 0x3f, 0x94, 0x9f, 0xf7, 0xff, 0x3c, 0xd4, 0xb4,
0x25, 0x62, 0xfe, 0x33, 0x1e, 0x96, 0x23, 0x35, 0x28, 0xb7, 0x7b, 0x3b, 0xfb, 0x7d, 0x73, 0xd0, 0xf7, 0xd0, 0xc8, 0x06, 0xac, 0x7c, 0xd5, 0x1d, 0xf6, 0x3a, 0x83, 0x81, 0x75, 0x74, 0xbc, 0xfd,
0xcc, 0x93, 0xd7, 0x60, 0x43, 0x2e, 0xa1, 0x9d, 0xfe, 0xe1, 0x61, 0x77, 0x88, 0xec, 0x7b, 0xf8, 0xa4, 0xf3, 0xcc, 0xda, 0x6f, 0x0f, 0xf6, 0x9b, 0x37, 0x18, 0x99, 0xe9, 0x75, 0x06, 0xc3, 0xce,
0xd5, 0x11, 0x5b, 0x31, 0xf7, 0x6d, 0xa8, 0x46, 0xcf, 0x15, 0x20, 0x4b, 0xec, 0x0e, 0xbb, 0xed, 0x6e, 0x0c, 0x9e, 0x23, 0x6f, 0xc2, 0xe6, 0x71, 0xef, 0x78, 0xd0, 0xd9, 0xb5, 0xb2, 0xf2, 0xe5,
0x61, 0xb4, 0x1f, 0x34, 0x6f, 0x30, 0x8e, 0x1b, 0x81, 0xf1, 0xcd, 0x81, 0x66, 0x8e, 0x5f, 0x25, 0xd9, 0xbe, 0x12, 0xe9, 0x19, 0xd9, 0x0b, 0xf7, 0x7f, 0x09, 0x16, 0xe3, 0x81, 0x65, 0x08, 0xc0,
0x97, 0x40, 0x5e, 0x7a, 0x33, 0xcf, 0xd8, 0x40, 0x04, 0xdd, 0xee, 0x0f, 0x59, 0x13, 0x7e, 0x09, 0xc2, 0x41, 0xe7, 0x71, 0x7b, 0xe7, 0x19, 0x7f, 0x34, 0x61, 0x30, 0x6c, 0x0f, 0xbb, 0x3b, 0x96,
0x16, 0xe3, 0xaf, 0x02, 0x90, 0x26, 0xd4, 0x59, 0xf9, 0x5a, 0x11, 0x00, 0x0b, 0xbc, 0xc6, 0xcd, 0x78, 0x24, 0x81, 0xd1, 0xb0, 0x1c, 0xa9, 0x41, 0xb9, 0xdd, 0xdb, 0xd9, 0xef, 0x9b, 0x83, 0x66,
0x1c, 0xe7, 0xf9, 0x3b, 0xfd, 0xc3, 0x6e, 0xef, 0x09, 0x6e, 0x14, 0xcd, 0x3c, 0x03, 0xf5, 0x8f, 0x9e, 0xbc, 0x01, 0x1b, 0x72, 0x0b, 0xed, 0xf4, 0x0f, 0x0f, 0xbb, 0x43, 0x24, 0xdf, 0xc3, 0x67,
0x87, 0x4f, 0xfa, 0x0a, 0x54, 0x60, 0x29, 0x78, 0x73, 0x9a, 0xc5, 0xfb, 0x3f, 0x82, 0xe5, 0xd4, 0x47, 0x6c, 0xc7, 0xdc, 0xb7, 0xa1, 0x1a, 0xbd, 0xef, 0x80, 0x24, 0xb1, 0x3b, 0xec, 0xb6, 0x87,
0xfb, 0x01, 0xac, 0xd6, 0xfd, 0xe3, 0xe1, 0x4e, 0xff, 0x50, 0x2f, 0xa7, 0x06, 0xe5, 0x9d, 0x83, 0xd1, 0x79, 0xd0, 0xbc, 0xc1, 0x28, 0x6e, 0x04, 0xc6, 0x47, 0x1a, 0x9a, 0x39, 0x7e, 0xf7, 0x5e,
0x76, 0xf7, 0x10, 0x0d, 0x35, 0x0d, 0xa8, 0x1e, 0xf7, 0xe4, 0x67, 0x3e, 0xfe, 0xf2, 0x41, 0x81, 0x02, 0x79, 0xed, 0xcd, 0x3c, 0x23, 0x03, 0x11, 0x74, 0xbb, 0x3f, 0x64, 0x5d, 0xf8, 0x65, 0x58,
0x71, 0xaf, 0xbd, 0xae, 0x39, 0x18, 0x5a, 0x83, 0x61, 0xfb, 0x49, 0xa7, 0x59, 0x64, 0x69, 0x25, 0x8c, 0x3f, 0xa3, 0x40, 0x9a, 0x50, 0x67, 0xf5, 0x6b, 0x55, 0x00, 0x2c, 0xf0, 0x16, 0x37, 0x73,
0x2b, 0x2b, 0xdd, 0xff, 0x1c, 0x16, 0xe3, 0x8e, 0xf3, 0x71, 0xfb, 0xdb, 0x26, 0xac, 0x6f, 0x77, 0x9c, 0xe6, 0xef, 0xf4, 0x0f, 0xbb, 0xbd, 0xc7, 0x78, 0x50, 0x34, 0xf3, 0x0c, 0xd4, 0x3f, 0x1e,
0x86, 0x5f, 0x76, 0x3a, 0x3d, 0x1c, 0xf2, 0x9d, 0x4e, 0x6f, 0x68, 0xb6, 0x0f, 0xba, 0xc3, 0xaf, 0x3e, 0xee, 0x2b, 0x50, 0x81, 0xe5, 0xe0, 0xdd, 0x69, 0x16, 0xef, 0xff, 0x08, 0x96, 0x53, 0x0f,
0x9a, 0xb9, 0xfb, 0x8f, 0xa1, 0x99, 0x74, 0xfa, 0x88, 0x79, 0xc9, 0xbc, 0xc8, 0x9d, 0xe6, 0xfe, 0x2e, 0xb0, 0x56, 0xf7, 0x8f, 0x87, 0x3b, 0xfd, 0x43, 0xbd, 0x9e, 0x1a, 0x94, 0x77, 0x0e, 0xda,
0xbf, 0xcb, 0xc1, 0x6a, 0x96, 0x79, 0x90, 0x4d, 0x4c, 0xc1, 0x08, 0xd9, 0x4e, 0x39, 0xe8, 0xf7, 0xdd, 0x43, 0x34, 0xd4, 0x34, 0xa0, 0x7a, 0xdc, 0x93, 0x9f, 0xf9, 0xf8, 0x53, 0x11, 0x05, 0x46,
0xac, 0x5e, 0x1f, 0x23, 0x7f, 0x6f, 0xc2, 0x7a, 0x02, 0x21, 0x5b, 0x91, 0x23, 0xb7, 0x60, 0x23, 0xbd, 0xf6, 0xba, 0xe6, 0x60, 0x68, 0x0d, 0x86, 0xed, 0xc7, 0x9d, 0x66, 0x91, 0xe5, 0x95, 0xa4,
0x95, 0xc8, 0x32, 0xfb, 0xc7, 0x38, 0x96, 0x2d, 0x58, 0x4d, 0x20, 0x3b, 0xa6, 0xd9, 0x37, 0x9b, 0xac, 0x74, 0xff, 0x0b, 0x58, 0x8c, 0x3b, 0xce, 0xc7, 0xed, 0x6f, 0x9b, 0xb0, 0xbe, 0xdd, 0x19,
0x05, 0xf2, 0x1e, 0xdc, 0x4b, 0x60, 0xd2, 0xf2, 0x81, 0x14, 0x1f, 0x8a, 0xe4, 0x1d, 0x78, 0x33, 0x7e, 0xd5, 0xe9, 0xf4, 0x70, 0xca, 0x77, 0x3a, 0xbd, 0xa1, 0xd9, 0x3e, 0xe8, 0x0e, 0x9f, 0x35,
0x45, 0x1d, 0x6d, 0xa1, 0xd6, 0x76, 0xfb, 0x80, 0x35, 0xaf, 0x59, 0xba, 0xff, 0xfb, 0x45, 0x80, 0x73, 0xf7, 0xbf, 0x84, 0x66, 0xd2, 0xe9, 0x23, 0xe6, 0x25, 0xf3, 0x32, 0x77, 0x9a, 0xfb, 0xff,
0xe8, 0x66, 0x2a, 0x2b, 0x7f, 0xb7, 0x3d, 0x6c, 0x1f, 0xf4, 0xd9, 0x9a, 0x31, 0xfb, 0x43, 0x96, 0x36, 0x07, 0xab, 0x59, 0xe6, 0x41, 0xb6, 0x30, 0x05, 0x21, 0x64, 0x27, 0xe5, 0xa0, 0xdf, 0xb3,
0xbb, 0xd9, 0xf9, 0x41, 0xf3, 0x46, 0x26, 0xa6, 0x7f, 0xc4, 0x1a, 0xb4, 0x01, 0x2b, 0x7c, 0xfe, 0x7a, 0x7d, 0x0c, 0x95, 0xbe, 0x09, 0xeb, 0x89, 0x04, 0xd9, 0x8b, 0x1c, 0xb9, 0x05, 0x1b, 0xa9,
0x1d, 0xb0, 0x66, 0xb0, 0xe9, 0xc2, 0x83, 0xc8, 0x33, 0x21, 0xe4, 0xf8, 0x68, 0xcf, 0xec, 0xf7, 0x4c, 0x96, 0xd9, 0x3f, 0xc6, 0xb9, 0x6c, 0xc1, 0x6a, 0x22, 0xb1, 0x63, 0x9a, 0x7d, 0xb3, 0x59,
0x86, 0xd6, 0x60, 0xff, 0x78, 0xb8, 0x8b, 0x31, 0xe9, 0x77, 0xcc, 0xee, 0x11, 0xcf, 0xb3, 0xf8, 0x20, 0xdf, 0x81, 0x7b, 0x89, 0x94, 0x34, 0x7f, 0x20, 0xd9, 0x87, 0x22, 0x79, 0x0f, 0xde, 0x4e,
0x22, 0x02, 0x96, 0x75, 0x89, 0x2d, 0xf0, 0x27, 0xfd, 0xc1, 0xa0, 0x7b, 0x64, 0xfd, 0xe0, 0xb8, 0x61, 0x47, 0x47, 0xa8, 0xb5, 0xdd, 0x3e, 0x60, 0xdd, 0x6b, 0x96, 0xee, 0xff, 0x41, 0x11, 0x20,
0x63, 0x76, 0x3b, 0x03, 0x4c, 0xb8, 0x90, 0x01, 0x67, 0xf4, 0x65, 0x36, 0x67, 0x87, 0x07, 0x5f, 0xba, 0x99, 0xca, 0xea, 0xdf, 0x6d, 0x0f, 0xdb, 0x07, 0x7d, 0xb6, 0x67, 0xcc, 0xfe, 0x90, 0x95,
0x88, 0x8d, 0x8e, 0x91, 0x56, 0xe2, 0x20, 0x46, 0x55, 0x65, 0xa3, 0xc3, 0x36, 0xe7, 0x8c, 0x9c, 0x6e, 0x76, 0x7e, 0xd8, 0xbc, 0x91, 0x99, 0xd2, 0x3f, 0x62, 0x1d, 0xda, 0x80, 0x15, 0xbe, 0xfe,
0xe1, 0x1a, 0x1c, 0x4b, 0x57, 0x63, 0x5b, 0x69, 0x6a, 0xe5, 0x63, 0xb2, 0x7a, 0x36, 0x8a, 0xa5, 0x0e, 0x58, 0x37, 0xd8, 0x72, 0xe1, 0x51, 0xf7, 0x19, 0x13, 0x72, 0x7c, 0xb4, 0x67, 0xf6, 0x7b,
0x42, 0x89, 0x44, 0xc9, 0x6f, 0xbb, 0xbb, 0x26, 0x26, 0x58, 0x4c, 0x41, 0x19, 0xed, 0x12, 0x9b, 0x43, 0x6b, 0xb0, 0x7f, 0x3c, 0xdc, 0xc5, 0x20, 0xfe, 0x3b, 0x66, 0xf7, 0x88, 0x97, 0x59, 0x7c,
0x84, 0x6c, 0xf7, 0x66, 0x24, 0x4d, 0xf9, 0xc1, 0x30, 0xcb, 0xac, 0xc5, 0x5f, 0x1e, 0x1f, 0x6e, 0x19, 0x02, 0x2b, 0xba, 0xc4, 0x36, 0xf8, 0xe3, 0xfe, 0x60, 0xd0, 0x3d, 0xb2, 0x7e, 0x78, 0xdc,
0xf7, 0xa5, 0x18, 0xc0, 0xeb, 0x4b, 0x32, 0xe0, 0x8c, 0x7e, 0x05, 0x83, 0xfe, 0x73, 0x76, 0x84, 0x31, 0xbb, 0x9d, 0x01, 0x66, 0x5c, 0xc8, 0x80, 0x33, 0xfc, 0x32, 0x5b, 0xb3, 0xc3, 0x83, 0xa7,
0x84, 0xab, 0x3a, 0x80, 0x51, 0xac, 0x31, 0x26, 0x28, 0x01, 0x3f, 0xec, 0x98, 0x7d, 0x8b, 0xc9, 0xe2, 0xa0, 0x63, 0xa8, 0x95, 0x38, 0x88, 0x61, 0x55, 0xd9, 0xec, 0xb0, 0xc3, 0x39, 0xa3, 0x64,
0x59, 0x28, 0x23, 0x32, 0xfa, 0xf5, 0xeb, 0xd1, 0x2c, 0xf5, 0xc6, 0xc3, 0x7f, 0xf6, 0x06, 0x54, 0xb8, 0x26, 0x8d, 0xe5, 0xab, 0xb1, 0xa3, 0x34, 0xb5, 0xf3, 0x31, 0x5b, 0x3d, 0x3b, 0x89, 0xe5,
0xd5, 0x8d, 0x19, 0xf2, 0x7d, 0x68, 0xc4, 0xe2, 0x51, 0x10, 0x69, 0x94, 0xc8, 0x0a, 0x5f, 0xb1, 0x42, 0x8e, 0x44, 0xf1, 0x6f, 0xbb, 0xbb, 0x26, 0x66, 0x58, 0x4c, 0x41, 0x19, 0xee, 0x12, 0x5b,
0xf9, 0x5a, 0x36, 0x52, 0x9c, 0xa3, 0x0e, 0x35, 0xc5, 0x05, 0xcf, 0xec, 0xb5, 0xa4, 0x32, 0x21, 0x84, 0xec, 0xf4, 0x66, 0x28, 0x4d, 0xf9, 0xc1, 0x52, 0x96, 0x59, 0x8f, 0xbf, 0x3a, 0x3e, 0xdc,
0x96, 0xdb, 0xed, 0x6b, 0xb0, 0x22, 0xbb, 0xa7, 0x18, 0x5f, 0x1f, 0xe3, 0x11, 0x8a, 0xed, 0x85, 0xee, 0x4b, 0x36, 0x80, 0xb7, 0x97, 0x64, 0xc0, 0x19, 0xfe, 0x0a, 0xbe, 0x92, 0xc0, 0xc9, 0x11,
0xdc, 0x8e, 0x82, 0x9d, 0xeb, 0x70, 0x99, 0xa1, 0x3c, 0x26, 0x6a, 0xb8, 0x5d, 0x1a, 0xda, 0xce, 0x22, 0xae, 0xea, 0x00, 0x86, 0xb1, 0xc6, 0x88, 0xa0, 0x04, 0xfc, 0x7c, 0xc7, 0xec, 0x5b, 0x8c,
0x24, 0x20, 0xbb, 0x50, 0xd3, 0x9e, 0x9f, 0x25, 0x37, 0xaf, 0x7d, 0x2b, 0x77, 0x73, 0x33, 0x0b, 0xcf, 0x42, 0x1e, 0x91, 0xe1, 0xaf, 0x5f, 0x9f, 0xcc, 0x72, 0x6f, 0x3c, 0xfc, 0xa7, 0x6f, 0x41,
0x25, 0xaa, 0xf4, 0x5d, 0xa8, 0xaa, 0xe7, 0x37, 0xc9, 0x86, 0xf6, 0x3c, 0xac, 0xfe, 0x6c, 0xe9, 0x55, 0xdd, 0x98, 0x21, 0x3f, 0x80, 0x46, 0x2c, 0x20, 0x05, 0xb9, 0x95, 0x1d, 0xa6, 0x02, 0xa5,
0x66, 0x2b, 0x8d, 0x10, 0xe9, 0x77, 0xa1, 0xa6, 0xbd, 0xa2, 0xa9, 0x6a, 0x91, 0x7e, 0xa9, 0x53, 0xa8, 0xcd, 0x37, 0x5e, 0x16, 0xc3, 0x82, 0x1c, 0x6a, 0x8a, 0x0b, 0x5e, 0xd8, 0x1b, 0x49, 0x65,
0xd5, 0x22, 0xeb, 0xd1, 0xcd, 0x03, 0x58, 0x13, 0xea, 0x91, 0x13, 0xfa, 0x75, 0xba, 0x87, 0xa4, 0x42, 0xac, 0xb4, 0xdb, 0xd7, 0xa4, 0x8a, 0xe2, 0x9e, 0xe0, 0x83, 0x04, 0x18, 0xc0, 0x51, 0x1c,
0xbb, 0xe7, 0x41, 0x8e, 0x3c, 0x86, 0x8a, 0x7c, 0xa1, 0x95, 0xac, 0x67, 0xbf, 0x78, 0xbb, 0xb9, 0x2f, 0xe4, 0x76, 0x14, 0x1d, 0x5e, 0x87, 0xcb, 0x02, 0xa5, 0x98, 0xa8, 0xa5, 0xed, 0xd2, 0xd0,
0x91, 0x82, 0x8b, 0xaa, 0xb4, 0x01, 0xa2, 0xf7, 0x39, 0x89, 0x6c, 0x78, 0xea, 0xbd, 0x4f, 0x35, 0x76, 0x26, 0x01, 0xd9, 0x85, 0x9a, 0xf6, 0xc6, 0x2f, 0xb9, 0x79, 0xed, 0x83, 0xc4, 0x9b, 0x9b,
0x32, 0x19, 0x8f, 0x79, 0xee, 0x42, 0x4d, 0x7b, 0x8a, 0x53, 0xf5, 0x49, 0xfa, 0x19, 0x4f, 0xd5, 0x59, 0x49, 0xa2, 0x49, 0xdf, 0x83, 0xaa, 0x7a, 0xe3, 0x94, 0x6c, 0x68, 0x6f, 0xf0, 0xea, 0x6f,
0x27, 0x59, 0x2f, 0x77, 0x7e, 0x1f, 0x1a, 0xb1, 0x37, 0x35, 0xd5, 0x3c, 0xce, 0x7a, 0xb1, 0x53, 0xc3, 0x6e, 0xb6, 0xd2, 0x09, 0x22, 0xff, 0x2e, 0xd4, 0xb4, 0x07, 0x49, 0x55, 0x2b, 0xd2, 0xcf,
0xcd, 0xe3, 0xec, 0x67, 0x38, 0x77, 0xa1, 0xa6, 0xbd, 0x73, 0xa9, 0x6a, 0x94, 0x7e, 0x6c, 0x53, 0xa1, 0xaa, 0x56, 0x64, 0xbd, 0x5f, 0x7a, 0x00, 0x6b, 0x42, 0x3d, 0x72, 0x42, 0xbf, 0xce, 0xf0,
0xd5, 0x28, 0xe3, 0x59, 0x4c, 0xb6, 0x1a, 0xe2, 0x8f, 0x5c, 0xaa, 0xd5, 0x90, 0xf9, 0x5a, 0xa6, 0x90, 0xf4, 0xf0, 0x3c, 0xc8, 0x91, 0x2f, 0xa1, 0x22, 0x9f, 0xc1, 0x25, 0xeb, 0xd9, 0xcf, 0x0a,
0x5a, 0x0d, 0xd9, 0x2f, 0x63, 0xb2, 0xa9, 0xa7, 0x1e, 0xd6, 0x20, 0x1b, 0x31, 0xad, 0x44, 0xf4, 0x6f, 0x6e, 0xa4, 0xe0, 0xa2, 0x29, 0x6d, 0x80, 0xe8, 0x41, 0x53, 0x22, 0x3b, 0x9e, 0x7a, 0x3a,
0x42, 0x87, 0x9a, 0x7a, 0xe9, 0x37, 0x38, 0x9e, 0xc0, 0x8a, 0x9a, 0x34, 0xea, 0x59, 0x8c, 0x40, 0x55, 0xcd, 0x4c, 0xc6, 0xeb, 0xa7, 0xbb, 0x50, 0xd3, 0xde, 0x2e, 0x55, 0x63, 0x92, 0x7e, 0xf7,
0xd5, 0x29, 0xf3, 0xf1, 0x8d, 0xcd, 0x66, 0x12, 0xfb, 0x20, 0x47, 0x3e, 0x83, 0xb2, 0x78, 0x6b, 0x54, 0x8d, 0x49, 0xd6, 0x53, 0xa7, 0x3f, 0x80, 0x46, 0xec, 0x11, 0x52, 0xb5, 0x8e, 0xb3, 0x9e,
0x80, 0xac, 0x25, 0xdf, 0x1e, 0xe0, 0x95, 0x58, 0xcf, 0x7e, 0x92, 0x80, 0x1c, 0xe1, 0x82, 0xd6, 0x38, 0x55, 0xeb, 0x38, 0xfb, 0xdd, 0xd2, 0x5d, 0xa8, 0x69, 0x0f, 0x83, 0xaa, 0x16, 0xa5, 0x5f,
0x1f, 0x03, 0xd0, 0x67, 0x6c, 0xc6, 0xfb, 0x01, 0x9b, 0xaf, 0x5f, 0x87, 0x8e, 0x72, 0x4c, 0x3e, 0x27, 0x55, 0x2d, 0xca, 0x78, 0x47, 0x94, 0xed, 0x86, 0xf8, 0xab, 0xa0, 0x6a, 0x37, 0x64, 0x3e,
0x60, 0x71, 0xfb, 0xba, 0x38, 0x51, 0xf1, 0x1c, 0xaf, 0x0b, 0x68, 0xf9, 0x04, 0xea, 0xfa, 0x03, 0x2f, 0xaa, 0x76, 0x43, 0xf6, 0x53, 0xa2, 0x6c, 0xe9, 0xa9, 0x97, 0x48, 0xc8, 0x46, 0x4c, 0x2b,
0x67, 0x44, 0x5f, 0x87, 0xc9, 0xbc, 0x6e, 0x65, 0xe2, 0x44, 0x46, 0x5f, 0xc0, 0xba, 0xea, 0x6f, 0x11, 0x3d, 0x69, 0xa2, 0x96, 0x5e, 0xfa, 0xd1, 0x92, 0xc7, 0xb0, 0xa2, 0x16, 0x8d, 0x7a, 0x47,
0x3d, 0x68, 0x51, 0x40, 0xee, 0x64, 0x84, 0x32, 0x8a, 0xf5, 0xfa, 0xcd, 0x6b, 0x63, 0x1d, 0x3d, 0x24, 0x50, 0x6d, 0xca, 0x7c, 0xad, 0x64, 0xb3, 0x99, 0x4c, 0x7d, 0x90, 0x23, 0x9f, 0x43, 0x59,
0xc8, 0x21, 0x93, 0x8d, 0xbd, 0x49, 0x14, 0x31, 0xd9, 0xac, 0xa7, 0x98, 0x22, 0x26, 0x9b, 0xfd, 0x3c, 0xce, 0x40, 0xd6, 0x92, 0x8f, 0x35, 0xf0, 0x46, 0xac, 0x67, 0xbf, 0xe1, 0x40, 0x8e, 0x70,
0x90, 0x51, 0x1b, 0x96, 0xb4, 0xa0, 0x4b, 0x83, 0x2b, 0x77, 0xa4, 0xe6, 0x7b, 0x3a, 0xfa, 0xfa, 0x43, 0xeb, 0xaf, 0x27, 0xe8, 0x2b, 0x36, 0xe3, 0xc1, 0x85, 0xcd, 0x37, 0xaf, 0x4b, 0x8e, 0x4a,
0x66, 0x96, 0x92, 0x9e, 0xec, 0x40, 0x4d, 0x8f, 0xdb, 0xf4, 0x82, 0xe4, 0x1b, 0x1a, 0x4a, 0x0f, 0x4c, 0xbe, 0xf8, 0x71, 0xfb, 0xba, 0xc0, 0x5a, 0xf1, 0x12, 0xaf, 0x8b, 0x00, 0xfa, 0x18, 0xea,
0x8a, 0xfd, 0x20, 0x47, 0x0e, 0xa0, 0x99, 0x8c, 0xb2, 0xaa, 0x96, 0x70, 0x56, 0x64, 0xda, 0xcd, 0xfa, 0x8b, 0x70, 0x44, 0xdf, 0x87, 0xc9, 0xb2, 0x6e, 0x65, 0xa6, 0x89, 0x82, 0x9e, 0xc2, 0xba,
0x04, 0x32, 0x16, 0x9b, 0x95, 0xcd, 0x8b, 0xd8, 0xab, 0xff, 0x9e, 0x9f, 0xdc, 0x8a, 0x38, 0x5c, 0x1a, 0x6f, 0x3d, 0xca, 0x53, 0x40, 0xee, 0x64, 0xc4, 0x7e, 0x8a, 0x8d, 0xfa, 0xcd, 0x6b, 0x83,
0x76, 0x83, 0xca, 0x2d, 0x81, 0xc5, 0x6a, 0xdf, 0xcb, 0x3d, 0xc8, 0x91, 0x3d, 0xa8, 0xc7, 0x82, 0x43, 0x3d, 0xc8, 0x21, 0x91, 0x8d, 0x3d, 0xe2, 0x14, 0x11, 0xd9, 0xac, 0xb7, 0xab, 0x22, 0x22,
0x0c, 0xc6, 0x2e, 0x6f, 0x25, 0x9a, 0xd9, 0xd2, 0x71, 0x89, 0x76, 0x1e, 0xc2, 0x62, 0xdc, 0xe9, 0x9b, 0xfd, 0xf2, 0x53, 0x1b, 0x96, 0xb4, 0x28, 0x55, 0x83, 0x2b, 0x77, 0xa4, 0xd6, 0x7b, 0x3a,
0x44, 0x55, 0x2c, 0xd3, 0x33, 0x46, 0x0d, 0x5f, 0xb6, 0xa7, 0x0a, 0xf9, 0x59, 0xa8, 0x31, 0x9e, 0x5c, 0xfd, 0x66, 0x96, 0x92, 0x9e, 0xec, 0x40, 0x4d, 0x0f, 0x74, 0xf5, 0x92, 0xec, 0x1b, 0x5a,
0x2c, 0x3d, 0x23, 0x89, 0xc6, 0xa7, 0x93, 0x63, 0xc6, 0x61, 0x42, 0x6b, 0x5e, 0xf8, 0x8b, 0xf9, 0x92, 0x1e, 0x45, 0xfc, 0x41, 0x8e, 0x1c, 0x40, 0x33, 0x19, 0x96, 0x56, 0x6d, 0xe1, 0xac, 0x50,
0x1c, 0xb6, 0xeb, 0x3b, 0xfc, 0x31, 0x74, 0xe9, 0x1c, 0xc7, 0xc6, 0xff, 0x55, 0x33, 0x21, 0x7b, 0xbe, 0x9b, 0x89, 0xc4, 0x58, 0x30, 0x5b, 0xb6, 0x2e, 0x44, 0xd5, 0xfc, 0xfd, 0x55, 0xcf, 0x4f,
0xbc, 0xf0, 0xa1, 0xc7, 0x63, 0x32, 0xdc, 0xd4, 0x68, 0x04, 0xec, 0xd5, 0xea, 0xd0, 0xe6, 0x75, 0x1e, 0x45, 0x1c, 0x2e, 0x87, 0x41, 0x95, 0x96, 0x48, 0xc5, 0x66, 0xdf, 0xcb, 0x3d, 0xc8, 0x91,
0x10, 0x69, 0x62, 0x73, 0xf0, 0x15, 0xf3, 0x22, 0x9f, 0x02, 0x44, 0x4e, 0xc9, 0x24, 0xe1, 0xf7, 0x3d, 0xa8, 0xc7, 0xa2, 0x32, 0xc6, 0x2e, 0x6f, 0x25, 0xba, 0xd9, 0xd2, 0xd3, 0x12, 0xfd, 0x3c,
0xaa, 0x16, 0x54, 0x86, 0xdf, 0x72, 0x87, 0xaf, 0x77, 0xe5, 0x78, 0xab, 0x6f, 0xc9, 0x71, 0x1f, 0x84, 0xc5, 0xb8, 0xd3, 0x89, 0x6a, 0x58, 0xa6, 0x67, 0x8c, 0x9a, 0xbe, 0x6c, 0x4f, 0x15, 0xf2,
0xe0, 0xd8, 0x96, 0x9c, 0xcc, 0xe6, 0x23, 0x68, 0x1c, 0x78, 0xde, 0xb3, 0xf9, 0x4c, 0x5d, 0xd5, 0xb3, 0x50, 0x63, 0x34, 0x59, 0x7a, 0x46, 0x12, 0x8d, 0x4e, 0x27, 0xe7, 0x8c, 0xc3, 0x84, 0xd6,
0x89, 0xbb, 0x7d, 0xed, 0xdb, 0xc1, 0xf9, 0x66, 0xa2, 0x5a, 0xa4, 0x0d, 0xcb, 0x8a, 0x45, 0x44, 0xbc, 0xf0, 0x17, 0xf3, 0x39, 0xec, 0xd7, 0x77, 0xf9, 0x8b, 0xf3, 0xd2, 0x39, 0x8e, 0xcd, 0xff,
0x9e, 0xbf, 0x71, 0xa2, 0x18, 0x63, 0x48, 0x64, 0xf0, 0x20, 0x47, 0x1e, 0x42, 0x7d, 0x97, 0x8e, 0xeb, 0x16, 0x42, 0xf6, 0x78, 0xe5, 0x43, 0x8f, 0xc7, 0x64, 0xb8, 0xa9, 0xe1, 0x08, 0xd8, 0xeb,
0x30, 0x6e, 0x0c, 0xba, 0x01, 0xad, 0xc4, 0x5c, 0x4a, 0xb8, 0xff, 0xd0, 0x66, 0x23, 0x06, 0x94, 0xb5, 0xa1, 0xcd, 0xdb, 0x20, 0xf2, 0xc4, 0xd6, 0xe0, 0x6b, 0x96, 0x45, 0x3e, 0x03, 0x88, 0x9c,
0x2c, 0x2e, 0x72, 0x74, 0xd3, 0xf7, 0x8c, 0xb8, 0xb7, 0x58, 0x8c, 0xc5, 0xa5, 0x9c, 0xdd, 0xbe, 0x92, 0x49, 0xc2, 0xef, 0x55, 0x6d, 0xa8, 0x0c, 0xbf, 0xe5, 0x0e, 0xdf, 0xef, 0xca, 0xf1, 0x56,
0x80, 0xe5, 0x94, 0xb3, 0x97, 0xe2, 0x6e, 0xd7, 0x39, 0xa0, 0x6d, 0xde, 0xbd, 0x9e, 0x40, 0xe4, 0x3f, 0x92, 0xe3, 0x3e, 0xc0, 0xb1, 0x23, 0x39, 0x59, 0xcc, 0xc7, 0xd0, 0x38, 0xf0, 0xbc, 0xe7,
0xfb, 0x3d, 0x68, 0xf0, 0x18, 0xe9, 0x27, 0x94, 0xdf, 0xfb, 0x4e, 0x44, 0xc0, 0xd3, 0x2f, 0x95, 0xf3, 0x99, 0xba, 0xaa, 0x13, 0x77, 0xfb, 0xda, 0xb7, 0x83, 0xf3, 0xcd, 0x44, 0xb3, 0x48, 0x1b,
0x27, 0x59, 0x12, 0x4f, 0xf0, 0x04, 0x5f, 0x6b, 0xd2, 0x6e, 0x55, 0xab, 0x71, 0x4d, 0xdf, 0xf4, 0x96, 0x15, 0x89, 0x88, 0x3c, 0x7f, 0xe3, 0x48, 0x31, 0xc2, 0x90, 0x28, 0xe0, 0x41, 0x8e, 0x3c,
0x56, 0xe3, 0x9a, 0x75, 0x81, 0xfb, 0x73, 0xa8, 0x3d, 0xa1, 0xa1, 0xbc, 0xa7, 0xac, 0xe4, 0xa3, 0x84, 0xfa, 0x2e, 0x1d, 0x61, 0xdc, 0x18, 0x74, 0x03, 0x5a, 0x89, 0xb9, 0x94, 0x70, 0xff, 0xa1,
0xc4, 0xc5, 0xe5, 0xcd, 0x8c, 0xdb, 0xe5, 0xe4, 0x13, 0x4c, 0xaa, 0x62, 0x6e, 0xac, 0x6b, 0xa5, 0xcd, 0x46, 0x0c, 0x28, 0x49, 0x5c, 0xe4, 0xe8, 0xa6, 0x9f, 0x19, 0x71, 0x6f, 0xb1, 0x18, 0x89,
0xe8, 0x49, 0x97, 0x12, 0x70, 0x26, 0x7d, 0x68, 0x91, 0x77, 0x54, 0xc5, 0xd3, 0x91, 0x96, 0x54, 0x4b, 0x39, 0xbb, 0x3d, 0x85, 0xe5, 0x94, 0xb3, 0x97, 0xa2, 0x6e, 0xd7, 0x39, 0xa0, 0x6d, 0xde,
0xc5, 0xb3, 0x02, 0xf5, 0xfc, 0x2c, 0xef, 0x01, 0xed, 0x66, 0x74, 0x24, 0x82, 0x25, 0x2f, 0x51, 0xbd, 0x1e, 0x41, 0x94, 0xfb, 0x7d, 0x68, 0xf0, 0xa0, 0xf2, 0x27, 0x94, 0xdf, 0xfb, 0x4e, 0x84,
0xab, 0xea, 0xeb, 0xe4, 0x8f, 0x00, 0x06, 0xa1, 0x37, 0xdb, 0xb5, 0xe9, 0xd4, 0x73, 0x23, 0x9e, 0x0c, 0xd4, 0x2f, 0x95, 0x27, 0x49, 0x12, 0xcf, 0xf0, 0x18, 0x9f, 0xb7, 0xd2, 0x6e, 0x55, 0xab,
0x10, 0xdd, 0xc9, 0x8d, 0x16, 0xa2, 0x76, 0x31, 0x97, 0x7c, 0xa9, 0xc9, 0xa6, 0xb1, 0x21, 0x91, 0x79, 0x4d, 0xdf, 0xf4, 0x56, 0xf3, 0x9a, 0x75, 0x81, 0xfb, 0x0b, 0xa8, 0x3d, 0xa6, 0xa1, 0xbc,
0xc3, 0x7e, 0xed, 0xb5, 0x5d, 0xd5, 0x9c, 0x8c, 0xab, 0xbb, 0xc8, 0x24, 0x20, 0xf2, 0xa5, 0x53, 0xa7, 0xac, 0xf8, 0xa3, 0xc4, 0xc5, 0xe5, 0xcd, 0x8c, 0xdb, 0xe5, 0xe4, 0x53, 0xcc, 0xaa, 0x62,
0x92, 0x66, 0xca, 0x4d, 0x4f, 0xad, 0xf5, 0x0c, 0xc7, 0xbb, 0xef, 0x42, 0x35, 0x72, 0x42, 0xda, 0x6e, 0xac, 0x6b, 0xb5, 0xe8, 0x59, 0x97, 0x12, 0x70, 0xc6, 0x7d, 0x68, 0x91, 0x77, 0x54, 0xc3,
0x88, 0xc2, 0x80, 0xc5, 0x5c, 0x96, 0x14, 0xf7, 0x4e, 0x3b, 0x00, 0xf5, 0x60, 0x85, 0x57, 0x47, 0xd3, 0x91, 0x96, 0x54, 0xc3, 0xb3, 0x02, 0xf5, 0xfc, 0x2c, 0x1f, 0x01, 0xed, 0x66, 0x74, 0xc4,
0x6d, 0x7f, 0x78, 0x57, 0x53, 0x3d, 0x36, 0x96, 0xf6, 0xbc, 0x51, 0xeb, 0x27, 0xcb, 0x7f, 0x84, 0x82, 0x25, 0x2f, 0x51, 0xab, 0xe6, 0xeb, 0xe8, 0x8f, 0x00, 0x06, 0xa1, 0x37, 0xdb, 0xb5, 0xe9,
0xad, 0x9f, 0x94, 0x83, 0x81, 0x5a, 0x3f, 0xd7, 0x39, 0x96, 0xa8, 0xf5, 0x73, 0xbd, 0x6f, 0x42, 0xd4, 0x73, 0x23, 0x9a, 0x10, 0xdd, 0xc9, 0x8d, 0x36, 0xa2, 0x76, 0x31, 0x97, 0x7c, 0xa5, 0xf1,
0x0f, 0x56, 0x32, 0x5c, 0x05, 0xc8, 0x1b, 0xf2, 0x60, 0x73, 0xad, 0x1b, 0xc1, 0x66, 0xa6, 0x49, 0xa6, 0xb1, 0x29, 0x91, 0xd3, 0x7e, 0xed, 0xb5, 0x5d, 0xd5, 0x9d, 0x8c, 0xab, 0xbb, 0x48, 0x24,
0x99, 0x0c, 0x61, 0x83, 0xa7, 0x69, 0x4f, 0x26, 0x09, 0xcb, 0xf4, 0xeb, 0x5a, 0x82, 0x0c, 0x6b, 0x20, 0xf2, 0xa5, 0x53, 0x9c, 0x66, 0xca, 0x4d, 0x4f, 0xed, 0xf5, 0x0c, 0xc7, 0xbb, 0xef, 0x41,
0x7b, 0x4c, 0x94, 0x49, 0x58, 0xdc, 0x7b, 0xd0, 0x4c, 0x1a, 0x75, 0xc9, 0xf5, 0xe4, 0x9b, 0x77, 0x35, 0x72, 0x42, 0xda, 0x88, 0xc2, 0x80, 0xc5, 0x5c, 0x96, 0x14, 0xf5, 0x4e, 0x3b, 0x00, 0xf5,
0x62, 0x22, 0x7b, 0xda, 0x10, 0x4c, 0xbe, 0x50, 0xa6, 0xe5, 0x44, 0x1d, 0xef, 0x44, 0x8f, 0x66, 0x60, 0x85, 0x37, 0x47, 0x1d, 0x7f, 0x78, 0x57, 0x53, 0xbd, 0xce, 0x96, 0xf6, 0xbc, 0x51, 0xfb,
0x66, 0x1a, 0xc2, 0xd5, 0x69, 0x20, 0xd3, 0x32, 0x4d, 0x7e, 0x0e, 0x36, 0x92, 0x33, 0x5a, 0xe6, 0x27, 0xcb, 0x7f, 0x84, 0xed, 0x9f, 0x94, 0x83, 0x81, 0xda, 0x3f, 0xd7, 0x39, 0x96, 0xa8, 0xfd,
0x7c, 0x37, 0xab, 0xbb, 0xae, 0x15, 0xe5, 0xe2, 0x0d, 0x7a, 0x90, 0x63, 0x8c, 0x58, 0x37, 0x00, 0x73, 0xbd, 0x6f, 0x42, 0x0f, 0x56, 0x32, 0x5c, 0x05, 0xc8, 0x5b, 0x52, 0xb0, 0xb9, 0xd6, 0x8d,
0xab, 0x89, 0x94, 0x61, 0x89, 0x56, 0x13, 0x29, 0xd3, 0x62, 0x7c, 0x04, 0x4b, 0x09, 0xdb, 0xaf, 0x60, 0x33, 0xd3, 0xa4, 0x4c, 0x86, 0xb0, 0xc1, 0xf3, 0xb4, 0x27, 0x93, 0x84, 0x65, 0xfa, 0x4d,
0x12, 0x83, 0xb3, 0xad, 0xc5, 0x4a, 0x0c, 0xbe, 0xce, 0x64, 0x3c, 0x80, 0x66, 0xd2, 0xaa, 0xab, 0x2d, 0x43, 0x86, 0xb5, 0x3d, 0xc6, 0xca, 0x24, 0x2c, 0xee, 0x3d, 0x68, 0x26, 0x8d, 0xba, 0xe4,
0xc6, 0xfa, 0x1a, 0x4b, 0xf1, 0xe6, 0x9d, 0x6b, 0xf1, 0xf1, 0x6a, 0x6a, 0xf6, 0xcf, 0x58, 0x35, 0x7a, 0xf4, 0xcd, 0x3b, 0x31, 0x96, 0x3d, 0x6d, 0x08, 0x26, 0x4f, 0x95, 0x69, 0x39, 0xd1, 0xc6,
0xd3, 0x56, 0xdb, 0x58, 0x35, 0x33, 0xac, 0xaf, 0xdb, 0xef, 0xfc, 0xf0, 0x5b, 0x67, 0x4e, 0x78, 0x3b, 0xd1, 0x2b, 0xa3, 0x99, 0x86, 0x70, 0x25, 0x0d, 0x64, 0x5a, 0xa6, 0xc9, 0xcf, 0xc1, 0x46,
0x3e, 0x3f, 0xd9, 0x1a, 0x79, 0xd3, 0x0f, 0x26, 0x52, 0xab, 0x21, 0x02, 0x29, 0x7c, 0x30, 0x71, 0x72, 0x45, 0xcb, 0x92, 0xef, 0x66, 0x0d, 0xd7, 0xb5, 0xac, 0x5c, 0xbc, 0x43, 0x0f, 0x72, 0x8c,
0xc7, 0x1f, 0x60, 0x06, 0x27, 0x0b, 0x33, 0xdf, 0x0b, 0xbd, 0x8f, 0xfe, 0x5f, 0x00, 0x00, 0x00, 0x10, 0xeb, 0x06, 0x60, 0xb5, 0x90, 0x32, 0x2c, 0xd1, 0x6a, 0x21, 0x65, 0x5a, 0x8c, 0x8f, 0x60,
0xff, 0xff, 0x39, 0x9e, 0x83, 0x60, 0x81, 0x93, 0x00, 0x00, 0x29, 0x61, 0xfb, 0x55, 0x6c, 0x70, 0xb6, 0xb5, 0x58, 0xb1, 0xc1, 0xd7, 0x99, 0x8c, 0x07, 0xd0,
0x4c, 0x5a, 0x75, 0xd5, 0x5c, 0x5f, 0x63, 0x29, 0xde, 0xbc, 0x73, 0x6d, 0x7a, 0xbc, 0x99, 0x9a,
0xfd, 0x33, 0xd6, 0xcc, 0xb4, 0xd5, 0x36, 0xd6, 0xcc, 0x0c, 0xeb, 0xeb, 0xf6, 0x7b, 0x3f, 0xff,
0xad, 0x33, 0x27, 0x3c, 0x9f, 0x9f, 0x6c, 0x8d, 0xbc, 0xe9, 0x87, 0x13, 0xa9, 0xd5, 0x10, 0x81,
0x14, 0x3e, 0x9c, 0xb8, 0xe3, 0x0f, 0xb1, 0x80, 0x93, 0x85, 0x99, 0xef, 0x85, 0xde, 0xc7, 0xff,
0x37, 0x00, 0x00, 0xff, 0xff, 0xe1, 0xea, 0x86, 0x7c, 0x00, 0x95, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -582,6 +582,9 @@ message GetTransactionsRequest {
default to this option. default to this option.
*/ */
int32 end_height = 2; int32 end_height = 2;
// An optional filter to only include transactions relevant to an account.
string account = 3;
} }
message TransactionDetails { message TransactionDetails {
@ -990,6 +993,9 @@ message ListUnspentRequest {
// The maximum number of confirmations to be included. // The maximum number of confirmations to be included.
int32 max_confs = 2; int32 max_confs = 2;
// An optional filter to only include outputs belonging to an account.
string account = 3;
} }
message ListUnspentResponse { message ListUnspentResponse {
// A list of utxos // A list of utxos
@ -1010,8 +1016,14 @@ enum AddressType {
} }
message NewAddressRequest { message NewAddressRequest {
// The address type // The type of address to generate.
AddressType type = 1; AddressType type = 1;
/*
The name of the account to generate a new address for. If empty, the
default wallet account is used.
*/
string account = 2;
} }
message NewAddressResponse { message NewAddressResponse {
// The newly generated wallet address // The newly generated wallet address
@ -2242,8 +2254,17 @@ message ChannelEventUpdate {
UpdateType type = 5; UpdateType type = 5;
} }
message WalletAccountBalance {
// The confirmed balance of the account (with >= 1 confirmations).
int64 confirmed_balance = 1;
// The unconfirmed balance of the account (with 0 confirmations).
int64 unconfirmed_balance = 2;
}
message WalletBalanceRequest { message WalletBalanceRequest {
} }
message WalletBalanceResponse { message WalletBalanceResponse {
// The balance of the wallet // The balance of the wallet
int64 total_balance = 1; int64 total_balance = 1;
@ -2253,6 +2274,9 @@ message WalletBalanceResponse {
// The unconfirmed balance of a wallet(with 0 confirmations) // The unconfirmed balance of a wallet(with 0 confirmations)
int64 unconfirmed_balance = 3; int64 unconfirmed_balance = 3;
// A mapping of each wallet account's name to its balance.
map<string, WalletAccountBalance> account_balance = 4;
} }
message Amount { message Amount {

@ -1547,7 +1547,7 @@
"parameters": [ "parameters": [
{ {
"name": "type", "name": "type",
"description": "The address type.", "description": "The type of address to generate.",
"in": "query", "in": "query",
"required": false, "required": false,
"type": "string", "type": "string",
@ -1558,6 +1558,13 @@
"UNUSED_NESTED_PUBKEY_HASH" "UNUSED_NESTED_PUBKEY_HASH"
], ],
"default": "WITNESS_PUBKEY_HASH" "default": "WITNESS_PUBKEY_HASH"
},
{
"name": "account",
"description": "The name of the account to generate a new address for. If empty, the\ndefault wallet account is used.",
"in": "query",
"required": false,
"type": "string"
} }
], ],
"tags": [ "tags": [
@ -1955,6 +1962,13 @@
"required": false, "required": false,
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
},
{
"name": "account",
"description": "An optional filter to only include transactions relevant to an account.",
"in": "query",
"required": false,
"type": "string"
} }
], ],
"tags": [ "tags": [
@ -2103,6 +2117,13 @@
"required": false, "required": false,
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
},
{
"name": "account",
"description": "An optional filter to only include transactions relevant to an account.",
"in": "query",
"required": false,
"type": "string"
} }
], ],
"tags": [ "tags": [
@ -2145,6 +2166,13 @@
"required": false, "required": false,
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
},
{
"name": "account",
"description": "An optional filter to only include outputs belonging to an account.",
"in": "query",
"required": false,
"type": "string"
} }
], ],
"tags": [ "tags": [
@ -5742,6 +5770,21 @@
} }
} }
}, },
"lnrpcWalletAccountBalance": {
"type": "object",
"properties": {
"confirmed_balance": {
"type": "string",
"format": "int64",
"description": "The confirmed balance of the account (with \u003e= 1 confirmations)."
},
"unconfirmed_balance": {
"type": "string",
"format": "int64",
"description": "The unconfirmed balance of the account (with 0 confirmations)."
}
}
},
"lnrpcWalletBalanceResponse": { "lnrpcWalletBalanceResponse": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -5759,6 +5802,13 @@
"type": "string", "type": "string",
"format": "int64", "format": "int64",
"title": "The unconfirmed balance of a wallet(with 0 confirmations)" "title": "The unconfirmed balance of a wallet(with 0 confirmations)"
},
"account_balance": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/lnrpcWalletAccountBalance"
},
"description": "A mapping of each wallet account's name to its balance."
} }
} }
}, },

@ -26,6 +26,37 @@ var _ = math.Inf
// proto package needs to be updated. // proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type AddressType int32
const (
AddressType_UNKNOWN AddressType = 0
AddressType_WITNESS_PUBKEY_HASH AddressType = 1
AddressType_NESTED_WITNESS_PUBKEY_HASH AddressType = 2
AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH AddressType = 3
)
var AddressType_name = map[int32]string{
0: "UNKNOWN",
1: "WITNESS_PUBKEY_HASH",
2: "NESTED_WITNESS_PUBKEY_HASH",
3: "HYBRID_NESTED_WITNESS_PUBKEY_HASH",
}
var AddressType_value = map[string]int32{
"UNKNOWN": 0,
"WITNESS_PUBKEY_HASH": 1,
"NESTED_WITNESS_PUBKEY_HASH": 2,
"HYBRID_NESTED_WITNESS_PUBKEY_HASH": 3,
}
func (x AddressType) String() string {
return proto.EnumName(AddressType_name, int32(x))
}
func (AddressType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{0}
}
type WitnessType int32 type WitnessType int32
const ( const (
@ -131,7 +162,7 @@ func (x WitnessType) String() string {
} }
func (WitnessType) EnumDescriptor() ([]byte, []int) { func (WitnessType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{0} return fileDescriptor_6cc6942ac78249e5, []int{1}
} }
type ListUnspentRequest struct { type ListUnspentRequest struct {
@ -139,6 +170,8 @@ type ListUnspentRequest struct {
MinConfs int32 `protobuf:"varint,1,opt,name=min_confs,json=minConfs,proto3" json:"min_confs,omitempty"` MinConfs int32 `protobuf:"varint,1,opt,name=min_confs,json=minConfs,proto3" json:"min_confs,omitempty"`
// The maximum number of confirmations to be included. // The maximum number of confirmations to be included.
MaxConfs int32 `protobuf:"varint,2,opt,name=max_confs,json=maxConfs,proto3" json:"max_confs,omitempty"` MaxConfs int32 `protobuf:"varint,2,opt,name=max_confs,json=maxConfs,proto3" json:"max_confs,omitempty"`
// An optional filter to only include outputs belonging to an account.
Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -183,6 +216,13 @@ func (m *ListUnspentRequest) GetMaxConfs() int32 {
return 0 return 0
} }
func (m *ListUnspentRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
type ListUnspentResponse struct { type ListUnspentResponse struct {
// A list of utxos satisfying the specified number of confirmations. // A list of utxos satisfying the specified number of confirmations.
Utxos []*lnrpc.Utxo `protobuf:"bytes,1,rep,name=utxos,proto3" json:"utxos,omitempty"` Utxos []*lnrpc.Utxo `protobuf:"bytes,1,rep,name=utxos,proto3" json:"utxos,omitempty"`
@ -460,6 +500,10 @@ func (m *KeyReq) GetKeyFamily() int32 {
} }
type AddrRequest struct { type AddrRequest struct {
//
//The name of the account to retrieve the next address of. If empty, the
//default wallet account is used.
Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -490,6 +534,13 @@ func (m *AddrRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_AddrRequest proto.InternalMessageInfo var xxx_messageInfo_AddrRequest proto.InternalMessageInfo
func (m *AddrRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
type AddrResponse struct { type AddrResponse struct {
// //
//The address encoded using a bech32 format. //The address encoded using a bech32 format.
@ -531,6 +582,405 @@ func (m *AddrResponse) GetAddr() string {
return "" return ""
} }
type Account struct {
// The name used to identify the account.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
//
//The type of addresses the account supports.
//AddressType | External Branch | Internal Branch
//---------------------------------------------------------------------
//WITNESS_PUBKEY_HASH | P2WPKH | P2WPKH
//NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | NP2WPKH
//HYBRID_NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | P2WPKH
AddressType AddressType `protobuf:"varint,2,opt,name=address_type,json=addressType,proto3,enum=walletrpc.AddressType" json:"address_type,omitempty"`
//
//The public key backing the account that all keys are derived from
//represented as an extended key. This will always be empty for the default
//imported account in which single public keys are imported into.
ExtendedPublicKey string `protobuf:"bytes,3,opt,name=extended_public_key,json=extendedPublicKey,proto3" json:"extended_public_key,omitempty"`
//
//The fingerprint of the root key from which the account public key was
//derived from. This will always be zero for the default imported account in
//which single public keys are imported into.
MasterKeyFingerprint uint32 `protobuf:"varint,4,opt,name=master_key_fingerprint,json=masterKeyFingerprint,proto3" json:"master_key_fingerprint,omitempty"`
//
//The derivation path corresponding to the account public key. This will
//always be empty for the default imported account in which single public keys
//are imported into.
DerivationPath string `protobuf:"bytes,5,opt,name=derivation_path,json=derivationPath,proto3" json:"derivation_path,omitempty"`
//
//The number of keys derived from the external branch of the account public
//key. This will always be zero for the default imported account in which
//single public keys are imported into.
ExternalKeyCount uint32 `protobuf:"varint,6,opt,name=external_key_count,json=externalKeyCount,proto3" json:"external_key_count,omitempty"`
//
//The number of keys derived from the internal branch of the account public
//key. This will always be zero for the default imported account in which
//single public keys are imported into.
InternalKeyCount uint32 `protobuf:"varint,7,opt,name=internal_key_count,json=internalKeyCount,proto3" json:"internal_key_count,omitempty"`
// Whether the wallet stores private keys for the account.
WatchOnly bool `protobuf:"varint,8,opt,name=watch_only,json=watchOnly,proto3" json:"watch_only,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Account) Reset() { *m = Account{} }
func (m *Account) String() string { return proto.CompactTextString(m) }
func (*Account) ProtoMessage() {}
func (*Account) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{9}
}
func (m *Account) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Account.Unmarshal(m, b)
}
func (m *Account) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Account.Marshal(b, m, deterministic)
}
func (m *Account) XXX_Merge(src proto.Message) {
xxx_messageInfo_Account.Merge(m, src)
}
func (m *Account) XXX_Size() int {
return xxx_messageInfo_Account.Size(m)
}
func (m *Account) XXX_DiscardUnknown() {
xxx_messageInfo_Account.DiscardUnknown(m)
}
var xxx_messageInfo_Account proto.InternalMessageInfo
func (m *Account) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Account) GetAddressType() AddressType {
if m != nil {
return m.AddressType
}
return AddressType_UNKNOWN
}
func (m *Account) GetExtendedPublicKey() string {
if m != nil {
return m.ExtendedPublicKey
}
return ""
}
func (m *Account) GetMasterKeyFingerprint() uint32 {
if m != nil {
return m.MasterKeyFingerprint
}
return 0
}
func (m *Account) GetDerivationPath() string {
if m != nil {
return m.DerivationPath
}
return ""
}
func (m *Account) GetExternalKeyCount() uint32 {
if m != nil {
return m.ExternalKeyCount
}
return 0
}
func (m *Account) GetInternalKeyCount() uint32 {
if m != nil {
return m.InternalKeyCount
}
return 0
}
func (m *Account) GetWatchOnly() bool {
if m != nil {
return m.WatchOnly
}
return false
}
type ListAccountsRequest struct {
// An optional filter to only return accounts matching this name.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// An optional filter to only return accounts matching this address type.
AddressType AddressType `protobuf:"varint,2,opt,name=address_type,json=addressType,proto3,enum=walletrpc.AddressType" json:"address_type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListAccountsRequest) Reset() { *m = ListAccountsRequest{} }
func (m *ListAccountsRequest) String() string { return proto.CompactTextString(m) }
func (*ListAccountsRequest) ProtoMessage() {}
func (*ListAccountsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{10}
}
func (m *ListAccountsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListAccountsRequest.Unmarshal(m, b)
}
func (m *ListAccountsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListAccountsRequest.Marshal(b, m, deterministic)
}
func (m *ListAccountsRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListAccountsRequest.Merge(m, src)
}
func (m *ListAccountsRequest) XXX_Size() int {
return xxx_messageInfo_ListAccountsRequest.Size(m)
}
func (m *ListAccountsRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ListAccountsRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ListAccountsRequest proto.InternalMessageInfo
func (m *ListAccountsRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *ListAccountsRequest) GetAddressType() AddressType {
if m != nil {
return m.AddressType
}
return AddressType_UNKNOWN
}
type ListAccountsResponse struct {
Accounts []*Account `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListAccountsResponse) Reset() { *m = ListAccountsResponse{} }
func (m *ListAccountsResponse) String() string { return proto.CompactTextString(m) }
func (*ListAccountsResponse) ProtoMessage() {}
func (*ListAccountsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{11}
}
func (m *ListAccountsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListAccountsResponse.Unmarshal(m, b)
}
func (m *ListAccountsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListAccountsResponse.Marshal(b, m, deterministic)
}
func (m *ListAccountsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListAccountsResponse.Merge(m, src)
}
func (m *ListAccountsResponse) XXX_Size() int {
return xxx_messageInfo_ListAccountsResponse.Size(m)
}
func (m *ListAccountsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ListAccountsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ListAccountsResponse proto.InternalMessageInfo
func (m *ListAccountsResponse) GetAccounts() []*Account {
if m != nil {
return m.Accounts
}
return nil
}
type ImportAccountRequest struct {
// A name to identify the account with.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
//
//A public key that corresponds to a wallet account represented as an extended
//key. It must conform to a derivation path of the form
//m/purpose'/coin_type'/account'.
ExtendedPublicKey string `protobuf:"bytes,2,opt,name=extended_public_key,json=extendedPublicKey,proto3" json:"extended_public_key,omitempty"`
//
//The fingerprint of the root key (also known as the key with derivation path
//m/) from which the account public key was derived from. This may be required
//by some hardware wallets for proper identification and signing.
MasterKeyFingerprint uint32 `protobuf:"varint,3,opt,name=master_key_fingerprint,json=masterKeyFingerprint,proto3" json:"master_key_fingerprint,omitempty"`
//
//An address type is only required when the extended account public key has a
//legacy version (xpub, tpub, etc.), such that the wallet cannot detect what
//address scheme it belongs to.
AddressType AddressType `protobuf:"varint,4,opt,name=address_type,json=addressType,proto3,enum=walletrpc.AddressType" json:"address_type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ImportAccountRequest) Reset() { *m = ImportAccountRequest{} }
func (m *ImportAccountRequest) String() string { return proto.CompactTextString(m) }
func (*ImportAccountRequest) ProtoMessage() {}
func (*ImportAccountRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{12}
}
func (m *ImportAccountRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ImportAccountRequest.Unmarshal(m, b)
}
func (m *ImportAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ImportAccountRequest.Marshal(b, m, deterministic)
}
func (m *ImportAccountRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ImportAccountRequest.Merge(m, src)
}
func (m *ImportAccountRequest) XXX_Size() int {
return xxx_messageInfo_ImportAccountRequest.Size(m)
}
func (m *ImportAccountRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ImportAccountRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ImportAccountRequest proto.InternalMessageInfo
func (m *ImportAccountRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *ImportAccountRequest) GetExtendedPublicKey() string {
if m != nil {
return m.ExtendedPublicKey
}
return ""
}
func (m *ImportAccountRequest) GetMasterKeyFingerprint() uint32 {
if m != nil {
return m.MasterKeyFingerprint
}
return 0
}
func (m *ImportAccountRequest) GetAddressType() AddressType {
if m != nil {
return m.AddressType
}
return AddressType_UNKNOWN
}
type ImportAccountResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ImportAccountResponse) Reset() { *m = ImportAccountResponse{} }
func (m *ImportAccountResponse) String() string { return proto.CompactTextString(m) }
func (*ImportAccountResponse) ProtoMessage() {}
func (*ImportAccountResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{13}
}
func (m *ImportAccountResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ImportAccountResponse.Unmarshal(m, b)
}
func (m *ImportAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ImportAccountResponse.Marshal(b, m, deterministic)
}
func (m *ImportAccountResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ImportAccountResponse.Merge(m, src)
}
func (m *ImportAccountResponse) XXX_Size() int {
return xxx_messageInfo_ImportAccountResponse.Size(m)
}
func (m *ImportAccountResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ImportAccountResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ImportAccountResponse proto.InternalMessageInfo
type ImportPublicKeyRequest struct {
// A compressed public key represented as raw bytes.
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// The type of address that will be generated from the public key.
AddressType AddressType `protobuf:"varint,2,opt,name=address_type,json=addressType,proto3,enum=walletrpc.AddressType" json:"address_type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ImportPublicKeyRequest) Reset() { *m = ImportPublicKeyRequest{} }
func (m *ImportPublicKeyRequest) String() string { return proto.CompactTextString(m) }
func (*ImportPublicKeyRequest) ProtoMessage() {}
func (*ImportPublicKeyRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{14}
}
func (m *ImportPublicKeyRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ImportPublicKeyRequest.Unmarshal(m, b)
}
func (m *ImportPublicKeyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ImportPublicKeyRequest.Marshal(b, m, deterministic)
}
func (m *ImportPublicKeyRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ImportPublicKeyRequest.Merge(m, src)
}
func (m *ImportPublicKeyRequest) XXX_Size() int {
return xxx_messageInfo_ImportPublicKeyRequest.Size(m)
}
func (m *ImportPublicKeyRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ImportPublicKeyRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ImportPublicKeyRequest proto.InternalMessageInfo
func (m *ImportPublicKeyRequest) GetPublicKey() []byte {
if m != nil {
return m.PublicKey
}
return nil
}
func (m *ImportPublicKeyRequest) GetAddressType() AddressType {
if m != nil {
return m.AddressType
}
return AddressType_UNKNOWN
}
type ImportPublicKeyResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ImportPublicKeyResponse) Reset() { *m = ImportPublicKeyResponse{} }
func (m *ImportPublicKeyResponse) String() string { return proto.CompactTextString(m) }
func (*ImportPublicKeyResponse) ProtoMessage() {}
func (*ImportPublicKeyResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{15}
}
func (m *ImportPublicKeyResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ImportPublicKeyResponse.Unmarshal(m, b)
}
func (m *ImportPublicKeyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ImportPublicKeyResponse.Marshal(b, m, deterministic)
}
func (m *ImportPublicKeyResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ImportPublicKeyResponse.Merge(m, src)
}
func (m *ImportPublicKeyResponse) XXX_Size() int {
return xxx_messageInfo_ImportPublicKeyResponse.Size(m)
}
func (m *ImportPublicKeyResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ImportPublicKeyResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ImportPublicKeyResponse proto.InternalMessageInfo
type Transaction struct { type Transaction struct {
// //
//The raw serialized transaction. //The raw serialized transaction.
@ -547,7 +997,7 @@ func (m *Transaction) Reset() { *m = Transaction{} }
func (m *Transaction) String() string { return proto.CompactTextString(m) } func (m *Transaction) String() string { return proto.CompactTextString(m) }
func (*Transaction) ProtoMessage() {} func (*Transaction) ProtoMessage() {}
func (*Transaction) Descriptor() ([]byte, []int) { func (*Transaction) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{9} return fileDescriptor_6cc6942ac78249e5, []int{16}
} }
func (m *Transaction) XXX_Unmarshal(b []byte) error { func (m *Transaction) XXX_Unmarshal(b []byte) error {
@ -599,7 +1049,7 @@ func (m *PublishResponse) Reset() { *m = PublishResponse{} }
func (m *PublishResponse) String() string { return proto.CompactTextString(m) } func (m *PublishResponse) String() string { return proto.CompactTextString(m) }
func (*PublishResponse) ProtoMessage() {} func (*PublishResponse) ProtoMessage() {}
func (*PublishResponse) Descriptor() ([]byte, []int) { func (*PublishResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{10} return fileDescriptor_6cc6942ac78249e5, []int{17}
} }
func (m *PublishResponse) XXX_Unmarshal(b []byte) error { func (m *PublishResponse) XXX_Unmarshal(b []byte) error {
@ -651,7 +1101,7 @@ func (m *SendOutputsRequest) Reset() { *m = SendOutputsRequest{} }
func (m *SendOutputsRequest) String() string { return proto.CompactTextString(m) } func (m *SendOutputsRequest) String() string { return proto.CompactTextString(m) }
func (*SendOutputsRequest) ProtoMessage() {} func (*SendOutputsRequest) ProtoMessage() {}
func (*SendOutputsRequest) Descriptor() ([]byte, []int) { func (*SendOutputsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{11} return fileDescriptor_6cc6942ac78249e5, []int{18}
} }
func (m *SendOutputsRequest) XXX_Unmarshal(b []byte) error { func (m *SendOutputsRequest) XXX_Unmarshal(b []byte) error {
@ -720,7 +1170,7 @@ func (m *SendOutputsResponse) Reset() { *m = SendOutputsResponse{} }
func (m *SendOutputsResponse) String() string { return proto.CompactTextString(m) } func (m *SendOutputsResponse) String() string { return proto.CompactTextString(m) }
func (*SendOutputsResponse) ProtoMessage() {} func (*SendOutputsResponse) ProtoMessage() {}
func (*SendOutputsResponse) Descriptor() ([]byte, []int) { func (*SendOutputsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{12} return fileDescriptor_6cc6942ac78249e5, []int{19}
} }
func (m *SendOutputsResponse) XXX_Unmarshal(b []byte) error { func (m *SendOutputsResponse) XXX_Unmarshal(b []byte) error {
@ -761,7 +1211,7 @@ func (m *EstimateFeeRequest) Reset() { *m = EstimateFeeRequest{} }
func (m *EstimateFeeRequest) String() string { return proto.CompactTextString(m) } func (m *EstimateFeeRequest) String() string { return proto.CompactTextString(m) }
func (*EstimateFeeRequest) ProtoMessage() {} func (*EstimateFeeRequest) ProtoMessage() {}
func (*EstimateFeeRequest) Descriptor() ([]byte, []int) { func (*EstimateFeeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{13} return fileDescriptor_6cc6942ac78249e5, []int{20}
} }
func (m *EstimateFeeRequest) XXX_Unmarshal(b []byte) error { func (m *EstimateFeeRequest) XXX_Unmarshal(b []byte) error {
@ -803,7 +1253,7 @@ func (m *EstimateFeeResponse) Reset() { *m = EstimateFeeResponse{} }
func (m *EstimateFeeResponse) String() string { return proto.CompactTextString(m) } func (m *EstimateFeeResponse) String() string { return proto.CompactTextString(m) }
func (*EstimateFeeResponse) ProtoMessage() {} func (*EstimateFeeResponse) ProtoMessage() {}
func (*EstimateFeeResponse) Descriptor() ([]byte, []int) { func (*EstimateFeeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{14} return fileDescriptor_6cc6942ac78249e5, []int{21}
} }
func (m *EstimateFeeResponse) XXX_Unmarshal(b []byte) error { func (m *EstimateFeeResponse) XXX_Unmarshal(b []byte) error {
@ -875,7 +1325,7 @@ func (m *PendingSweep) Reset() { *m = PendingSweep{} }
func (m *PendingSweep) String() string { return proto.CompactTextString(m) } func (m *PendingSweep) String() string { return proto.CompactTextString(m) }
func (*PendingSweep) ProtoMessage() {} func (*PendingSweep) ProtoMessage() {}
func (*PendingSweep) Descriptor() ([]byte, []int) { func (*PendingSweep) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{15} return fileDescriptor_6cc6942ac78249e5, []int{22}
} }
func (m *PendingSweep) XXX_Unmarshal(b []byte) error { func (m *PendingSweep) XXX_Unmarshal(b []byte) error {
@ -985,7 +1435,7 @@ func (m *PendingSweepsRequest) Reset() { *m = PendingSweepsRequest{} }
func (m *PendingSweepsRequest) String() string { return proto.CompactTextString(m) } func (m *PendingSweepsRequest) String() string { return proto.CompactTextString(m) }
func (*PendingSweepsRequest) ProtoMessage() {} func (*PendingSweepsRequest) ProtoMessage() {}
func (*PendingSweepsRequest) Descriptor() ([]byte, []int) { func (*PendingSweepsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{16} return fileDescriptor_6cc6942ac78249e5, []int{23}
} }
func (m *PendingSweepsRequest) XXX_Unmarshal(b []byte) error { func (m *PendingSweepsRequest) XXX_Unmarshal(b []byte) error {
@ -1019,7 +1469,7 @@ func (m *PendingSweepsResponse) Reset() { *m = PendingSweepsResponse{} }
func (m *PendingSweepsResponse) String() string { return proto.CompactTextString(m) } func (m *PendingSweepsResponse) String() string { return proto.CompactTextString(m) }
func (*PendingSweepsResponse) ProtoMessage() {} func (*PendingSweepsResponse) ProtoMessage() {}
func (*PendingSweepsResponse) Descriptor() ([]byte, []int) { func (*PendingSweepsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{17} return fileDescriptor_6cc6942ac78249e5, []int{24}
} }
func (m *PendingSweepsResponse) XXX_Unmarshal(b []byte) error { func (m *PendingSweepsResponse) XXX_Unmarshal(b []byte) error {
@ -1074,7 +1524,7 @@ func (m *BumpFeeRequest) Reset() { *m = BumpFeeRequest{} }
func (m *BumpFeeRequest) String() string { return proto.CompactTextString(m) } func (m *BumpFeeRequest) String() string { return proto.CompactTextString(m) }
func (*BumpFeeRequest) ProtoMessage() {} func (*BumpFeeRequest) ProtoMessage() {}
func (*BumpFeeRequest) Descriptor() ([]byte, []int) { func (*BumpFeeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{18} return fileDescriptor_6cc6942ac78249e5, []int{25}
} }
func (m *BumpFeeRequest) XXX_Unmarshal(b []byte) error { func (m *BumpFeeRequest) XXX_Unmarshal(b []byte) error {
@ -1141,7 +1591,7 @@ func (m *BumpFeeResponse) Reset() { *m = BumpFeeResponse{} }
func (m *BumpFeeResponse) String() string { return proto.CompactTextString(m) } func (m *BumpFeeResponse) String() string { return proto.CompactTextString(m) }
func (*BumpFeeResponse) ProtoMessage() {} func (*BumpFeeResponse) ProtoMessage() {}
func (*BumpFeeResponse) Descriptor() ([]byte, []int) { func (*BumpFeeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{19} return fileDescriptor_6cc6942ac78249e5, []int{26}
} }
func (m *BumpFeeResponse) XXX_Unmarshal(b []byte) error { func (m *BumpFeeResponse) XXX_Unmarshal(b []byte) error {
@ -1177,7 +1627,7 @@ func (m *ListSweepsRequest) Reset() { *m = ListSweepsRequest{} }
func (m *ListSweepsRequest) String() string { return proto.CompactTextString(m) } func (m *ListSweepsRequest) String() string { return proto.CompactTextString(m) }
func (*ListSweepsRequest) ProtoMessage() {} func (*ListSweepsRequest) ProtoMessage() {}
func (*ListSweepsRequest) Descriptor() ([]byte, []int) { func (*ListSweepsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{20} return fileDescriptor_6cc6942ac78249e5, []int{27}
} }
func (m *ListSweepsRequest) XXX_Unmarshal(b []byte) error { func (m *ListSweepsRequest) XXX_Unmarshal(b []byte) error {
@ -1219,7 +1669,7 @@ func (m *ListSweepsResponse) Reset() { *m = ListSweepsResponse{} }
func (m *ListSweepsResponse) String() string { return proto.CompactTextString(m) } func (m *ListSweepsResponse) String() string { return proto.CompactTextString(m) }
func (*ListSweepsResponse) ProtoMessage() {} func (*ListSweepsResponse) ProtoMessage() {}
func (*ListSweepsResponse) Descriptor() ([]byte, []int) { func (*ListSweepsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{21} return fileDescriptor_6cc6942ac78249e5, []int{28}
} }
func (m *ListSweepsResponse) XXX_Unmarshal(b []byte) error { func (m *ListSweepsResponse) XXX_Unmarshal(b []byte) error {
@ -1300,7 +1750,7 @@ func (m *ListSweepsResponse_TransactionIDs) Reset() { *m = ListSweepsRes
func (m *ListSweepsResponse_TransactionIDs) String() string { return proto.CompactTextString(m) } func (m *ListSweepsResponse_TransactionIDs) String() string { return proto.CompactTextString(m) }
func (*ListSweepsResponse_TransactionIDs) ProtoMessage() {} func (*ListSweepsResponse_TransactionIDs) ProtoMessage() {}
func (*ListSweepsResponse_TransactionIDs) Descriptor() ([]byte, []int) { func (*ListSweepsResponse_TransactionIDs) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{21, 0} return fileDescriptor_6cc6942ac78249e5, []int{28, 0}
} }
func (m *ListSweepsResponse_TransactionIDs) XXX_Unmarshal(b []byte) error { func (m *ListSweepsResponse_TransactionIDs) XXX_Unmarshal(b []byte) error {
@ -1344,7 +1794,7 @@ func (m *LabelTransactionRequest) Reset() { *m = LabelTransactionRequest
func (m *LabelTransactionRequest) String() string { return proto.CompactTextString(m) } func (m *LabelTransactionRequest) String() string { return proto.CompactTextString(m) }
func (*LabelTransactionRequest) ProtoMessage() {} func (*LabelTransactionRequest) ProtoMessage() {}
func (*LabelTransactionRequest) Descriptor() ([]byte, []int) { func (*LabelTransactionRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{22} return fileDescriptor_6cc6942ac78249e5, []int{29}
} }
func (m *LabelTransactionRequest) XXX_Unmarshal(b []byte) error { func (m *LabelTransactionRequest) XXX_Unmarshal(b []byte) error {
@ -1396,7 +1846,7 @@ func (m *LabelTransactionResponse) Reset() { *m = LabelTransactionRespon
func (m *LabelTransactionResponse) String() string { return proto.CompactTextString(m) } func (m *LabelTransactionResponse) String() string { return proto.CompactTextString(m) }
func (*LabelTransactionResponse) ProtoMessage() {} func (*LabelTransactionResponse) ProtoMessage() {}
func (*LabelTransactionResponse) Descriptor() ([]byte, []int) { func (*LabelTransactionResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{23} return fileDescriptor_6cc6942ac78249e5, []int{30}
} }
func (m *LabelTransactionResponse) XXX_Unmarshal(b []byte) error { func (m *LabelTransactionResponse) XXX_Unmarshal(b []byte) error {
@ -1426,6 +1876,10 @@ type FundPsbtRequest struct {
// *FundPsbtRequest_TargetConf // *FundPsbtRequest_TargetConf
// *FundPsbtRequest_SatPerVbyte // *FundPsbtRequest_SatPerVbyte
Fees isFundPsbtRequest_Fees `protobuf_oneof:"fees"` Fees isFundPsbtRequest_Fees `protobuf_oneof:"fees"`
//
//The name of the account to fund the PSBT with. If empty, the default wallet
//account is used.
Account string `protobuf:"bytes,5,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -1435,7 +1889,7 @@ func (m *FundPsbtRequest) Reset() { *m = FundPsbtRequest{} }
func (m *FundPsbtRequest) String() string { return proto.CompactTextString(m) } func (m *FundPsbtRequest) String() string { return proto.CompactTextString(m) }
func (*FundPsbtRequest) ProtoMessage() {} func (*FundPsbtRequest) ProtoMessage() {}
func (*FundPsbtRequest) Descriptor() ([]byte, []int) { func (*FundPsbtRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{24} return fileDescriptor_6cc6942ac78249e5, []int{31}
} }
func (m *FundPsbtRequest) XXX_Unmarshal(b []byte) error { func (m *FundPsbtRequest) XXX_Unmarshal(b []byte) error {
@ -1530,6 +1984,13 @@ func (m *FundPsbtRequest) GetSatPerVbyte() uint64 {
return 0 return 0
} }
func (m *FundPsbtRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
// XXX_OneofWrappers is for the internal use of the proto package. // XXX_OneofWrappers is for the internal use of the proto package.
func (*FundPsbtRequest) XXX_OneofWrappers() []interface{} { func (*FundPsbtRequest) XXX_OneofWrappers() []interface{} {
return []interface{}{ return []interface{}{
@ -1560,7 +2021,7 @@ func (m *FundPsbtResponse) Reset() { *m = FundPsbtResponse{} }
func (m *FundPsbtResponse) String() string { return proto.CompactTextString(m) } func (m *FundPsbtResponse) String() string { return proto.CompactTextString(m) }
func (*FundPsbtResponse) ProtoMessage() {} func (*FundPsbtResponse) ProtoMessage() {}
func (*FundPsbtResponse) Descriptor() ([]byte, []int) { func (*FundPsbtResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{25} return fileDescriptor_6cc6942ac78249e5, []int{32}
} }
func (m *FundPsbtResponse) XXX_Unmarshal(b []byte) error { func (m *FundPsbtResponse) XXX_Unmarshal(b []byte) error {
@ -1624,7 +2085,7 @@ func (m *TxTemplate) Reset() { *m = TxTemplate{} }
func (m *TxTemplate) String() string { return proto.CompactTextString(m) } func (m *TxTemplate) String() string { return proto.CompactTextString(m) }
func (*TxTemplate) ProtoMessage() {} func (*TxTemplate) ProtoMessage() {}
func (*TxTemplate) Descriptor() ([]byte, []int) { func (*TxTemplate) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{26} return fileDescriptor_6cc6942ac78249e5, []int{33}
} }
func (m *TxTemplate) XXX_Unmarshal(b []byte) error { func (m *TxTemplate) XXX_Unmarshal(b []byte) error {
@ -1677,7 +2138,7 @@ func (m *UtxoLease) Reset() { *m = UtxoLease{} }
func (m *UtxoLease) String() string { return proto.CompactTextString(m) } func (m *UtxoLease) String() string { return proto.CompactTextString(m) }
func (*UtxoLease) ProtoMessage() {} func (*UtxoLease) ProtoMessage() {}
func (*UtxoLease) Descriptor() ([]byte, []int) { func (*UtxoLease) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{27} return fileDescriptor_6cc6942ac78249e5, []int{34}
} }
func (m *UtxoLease) XXX_Unmarshal(b []byte) error { func (m *UtxoLease) XXX_Unmarshal(b []byte) error {
@ -1725,6 +2186,10 @@ type FinalizePsbtRequest struct {
//required inputs, outputs, UTXO data and partial signatures of all other //required inputs, outputs, UTXO data and partial signatures of all other
//signers. //signers.
FundedPsbt []byte `protobuf:"bytes,1,opt,name=funded_psbt,json=fundedPsbt,proto3" json:"funded_psbt,omitempty"` FundedPsbt []byte `protobuf:"bytes,1,opt,name=funded_psbt,json=fundedPsbt,proto3" json:"funded_psbt,omitempty"`
//
//The name of the account to finalize the PSBT with. If empty, the default
//wallet account is used.
Account string `protobuf:"bytes,5,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -1734,7 +2199,7 @@ func (m *FinalizePsbtRequest) Reset() { *m = FinalizePsbtRequest{} }
func (m *FinalizePsbtRequest) String() string { return proto.CompactTextString(m) } func (m *FinalizePsbtRequest) String() string { return proto.CompactTextString(m) }
func (*FinalizePsbtRequest) ProtoMessage() {} func (*FinalizePsbtRequest) ProtoMessage() {}
func (*FinalizePsbtRequest) Descriptor() ([]byte, []int) { func (*FinalizePsbtRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{28} return fileDescriptor_6cc6942ac78249e5, []int{35}
} }
func (m *FinalizePsbtRequest) XXX_Unmarshal(b []byte) error { func (m *FinalizePsbtRequest) XXX_Unmarshal(b []byte) error {
@ -1762,6 +2227,13 @@ func (m *FinalizePsbtRequest) GetFundedPsbt() []byte {
return nil return nil
} }
func (m *FinalizePsbtRequest) GetAccount() string {
if m != nil {
return m.Account
}
return ""
}
type FinalizePsbtResponse struct { type FinalizePsbtResponse struct {
// The fully signed and finalized transaction in PSBT format. // The fully signed and finalized transaction in PSBT format.
SignedPsbt []byte `protobuf:"bytes,1,opt,name=signed_psbt,json=signedPsbt,proto3" json:"signed_psbt,omitempty"` SignedPsbt []byte `protobuf:"bytes,1,opt,name=signed_psbt,json=signedPsbt,proto3" json:"signed_psbt,omitempty"`
@ -1776,7 +2248,7 @@ func (m *FinalizePsbtResponse) Reset() { *m = FinalizePsbtResponse{} }
func (m *FinalizePsbtResponse) String() string { return proto.CompactTextString(m) } func (m *FinalizePsbtResponse) String() string { return proto.CompactTextString(m) }
func (*FinalizePsbtResponse) ProtoMessage() {} func (*FinalizePsbtResponse) ProtoMessage() {}
func (*FinalizePsbtResponse) Descriptor() ([]byte, []int) { func (*FinalizePsbtResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{29} return fileDescriptor_6cc6942ac78249e5, []int{36}
} }
func (m *FinalizePsbtResponse) XXX_Unmarshal(b []byte) error { func (m *FinalizePsbtResponse) XXX_Unmarshal(b []byte) error {
@ -1821,7 +2293,7 @@ func (m *ListLeasesRequest) Reset() { *m = ListLeasesRequest{} }
func (m *ListLeasesRequest) String() string { return proto.CompactTextString(m) } func (m *ListLeasesRequest) String() string { return proto.CompactTextString(m) }
func (*ListLeasesRequest) ProtoMessage() {} func (*ListLeasesRequest) ProtoMessage() {}
func (*ListLeasesRequest) Descriptor() ([]byte, []int) { func (*ListLeasesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{30} return fileDescriptor_6cc6942ac78249e5, []int{37}
} }
func (m *ListLeasesRequest) XXX_Unmarshal(b []byte) error { func (m *ListLeasesRequest) XXX_Unmarshal(b []byte) error {
@ -1854,7 +2326,7 @@ func (m *ListLeasesResponse) Reset() { *m = ListLeasesResponse{} }
func (m *ListLeasesResponse) String() string { return proto.CompactTextString(m) } func (m *ListLeasesResponse) String() string { return proto.CompactTextString(m) }
func (*ListLeasesResponse) ProtoMessage() {} func (*ListLeasesResponse) ProtoMessage() {}
func (*ListLeasesResponse) Descriptor() ([]byte, []int) { func (*ListLeasesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_6cc6942ac78249e5, []int{31} return fileDescriptor_6cc6942ac78249e5, []int{38}
} }
func (m *ListLeasesResponse) XXX_Unmarshal(b []byte) error { func (m *ListLeasesResponse) XXX_Unmarshal(b []byte) error {
@ -1883,6 +2355,7 @@ func (m *ListLeasesResponse) GetLockedUtxos() []*UtxoLease {
} }
func init() { func init() {
proto.RegisterEnum("walletrpc.AddressType", AddressType_name, AddressType_value)
proto.RegisterEnum("walletrpc.WitnessType", WitnessType_name, WitnessType_value) proto.RegisterEnum("walletrpc.WitnessType", WitnessType_name, WitnessType_value)
proto.RegisterType((*ListUnspentRequest)(nil), "walletrpc.ListUnspentRequest") proto.RegisterType((*ListUnspentRequest)(nil), "walletrpc.ListUnspentRequest")
proto.RegisterType((*ListUnspentResponse)(nil), "walletrpc.ListUnspentResponse") proto.RegisterType((*ListUnspentResponse)(nil), "walletrpc.ListUnspentResponse")
@ -1893,6 +2366,13 @@ func init() {
proto.RegisterType((*KeyReq)(nil), "walletrpc.KeyReq") proto.RegisterType((*KeyReq)(nil), "walletrpc.KeyReq")
proto.RegisterType((*AddrRequest)(nil), "walletrpc.AddrRequest") proto.RegisterType((*AddrRequest)(nil), "walletrpc.AddrRequest")
proto.RegisterType((*AddrResponse)(nil), "walletrpc.AddrResponse") proto.RegisterType((*AddrResponse)(nil), "walletrpc.AddrResponse")
proto.RegisterType((*Account)(nil), "walletrpc.Account")
proto.RegisterType((*ListAccountsRequest)(nil), "walletrpc.ListAccountsRequest")
proto.RegisterType((*ListAccountsResponse)(nil), "walletrpc.ListAccountsResponse")
proto.RegisterType((*ImportAccountRequest)(nil), "walletrpc.ImportAccountRequest")
proto.RegisterType((*ImportAccountResponse)(nil), "walletrpc.ImportAccountResponse")
proto.RegisterType((*ImportPublicKeyRequest)(nil), "walletrpc.ImportPublicKeyRequest")
proto.RegisterType((*ImportPublicKeyResponse)(nil), "walletrpc.ImportPublicKeyResponse")
proto.RegisterType((*Transaction)(nil), "walletrpc.Transaction") proto.RegisterType((*Transaction)(nil), "walletrpc.Transaction")
proto.RegisterType((*PublishResponse)(nil), "walletrpc.PublishResponse") proto.RegisterType((*PublishResponse)(nil), "walletrpc.PublishResponse")
proto.RegisterType((*SendOutputsRequest)(nil), "walletrpc.SendOutputsRequest") proto.RegisterType((*SendOutputsRequest)(nil), "walletrpc.SendOutputsRequest")
@ -1923,125 +2403,148 @@ func init() {
func init() { proto.RegisterFile("walletrpc/walletkit.proto", fileDescriptor_6cc6942ac78249e5) } func init() { proto.RegisterFile("walletrpc/walletkit.proto", fileDescriptor_6cc6942ac78249e5) }
var fileDescriptor_6cc6942ac78249e5 = []byte{ var fileDescriptor_6cc6942ac78249e5 = []byte{
// 1887 bytes of a gzipped FileDescriptorProto // 2249 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x5f, 0x73, 0xe2, 0xc8, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x5f, 0x73, 0xe2, 0xc8,
0x11, 0x5f, 0xfe, 0x98, 0x85, 0x16, 0xd8, 0x78, 0xc0, 0x6b, 0x96, 0xf5, 0x9e, 0xbd, 0xba, 0x24, 0x11, 0x5f, 0x01, 0xb6, 0xa1, 0x01, 0x1b, 0x0f, 0xf8, 0xcf, 0xb2, 0xde, 0xb3, 0x57, 0x97, 0x64,
0xe7, 0xe4, 0xee, 0x70, 0xc5, 0x57, 0x7b, 0xb7, 0xb7, 0x49, 0xa5, 0x62, 0x63, 0xb9, 0x70, 0x81, 0x9d, 0xbb, 0x3d, 0x5c, 0xd9, 0xcb, 0xe6, 0x76, 0x37, 0xa9, 0x54, 0x6c, 0x8c, 0x0b, 0x17, 0xd8,
0xc1, 0x11, 0x78, 0x5d, 0x9b, 0x3c, 0xa8, 0x04, 0x1a, 0xdb, 0x2a, 0x83, 0xa4, 0x93, 0x06, 0x03, 0x38, 0x02, 0xaf, 0xb3, 0xc9, 0x83, 0x4a, 0x46, 0x63, 0xa3, 0x32, 0x48, 0x3a, 0x69, 0x30, 0x70,
0x79, 0xba, 0xaf, 0x91, 0xaa, 0x7c, 0x87, 0x7b, 0xc8, 0x6b, 0x2a, 0x9f, 0x2c, 0x0f, 0xa9, 0xf9, 0x4f, 0xf7, 0x35, 0x52, 0x95, 0xef, 0x90, 0xaa, 0x3c, 0xa7, 0xf2, 0x9e, 0xca, 0xb7, 0xc8, 0xe7,
0x83, 0x34, 0x12, 0xf8, 0x2e, 0xa9, 0xdc, 0x93, 0x51, 0xff, 0xba, 0x7b, 0xfa, 0xdf, 0x4c, 0x77, 0xc8, 0x43, 0x6a, 0xfe, 0x48, 0x1a, 0x09, 0xec, 0xbb, 0xab, 0xbb, 0x27, 0xa3, 0xfe, 0xf5, 0xf4,
0x1b, 0x5e, 0xce, 0xcc, 0xf1, 0x18, 0x13, 0xdf, 0x1b, 0x1d, 0xf1, 0x5f, 0x0f, 0x36, 0x69, 0x78, 0xf4, 0xf4, 0x9f, 0xe9, 0xee, 0x31, 0x3c, 0x9d, 0x18, 0xc3, 0x21, 0x26, 0x9e, 0xdb, 0x3f, 0xe0,
0xbe, 0x4b, 0x5c, 0x54, 0x08, 0xa1, 0x7a, 0xc1, 0xf7, 0x46, 0x9c, 0x5a, 0xaf, 0x06, 0xf6, 0x9d, 0xbf, 0xee, 0x2c, 0x52, 0x73, 0x3d, 0x87, 0x38, 0x28, 0x17, 0x42, 0xd5, 0x9c, 0xe7, 0xf6, 0x39,
0x43, 0xd9, 0xe9, 0x5f, 0xec, 0x73, 0xaa, 0xda, 0x05, 0xd4, 0xb1, 0x03, 0x72, 0xed, 0x04, 0x1e, 0xb5, 0x5a, 0xf1, 0xad, 0x5b, 0x9b, 0xb2, 0xd3, 0xbf, 0xd8, 0xe3, 0x54, 0x75, 0x00, 0xa8, 0x6d,
0x76, 0x88, 0x8e, 0xbf, 0x9b, 0xe2, 0x80, 0xa0, 0x57, 0x50, 0x98, 0xd8, 0x8e, 0x31, 0x72, 0x9d, 0xf9, 0xe4, 0xd2, 0xf6, 0x5d, 0x6c, 0x13, 0x0d, 0x7f, 0x3d, 0xc6, 0x3e, 0x41, 0xcf, 0x20, 0x37,
0xdb, 0xa0, 0x96, 0x3a, 0x48, 0x1d, 0x6e, 0xe8, 0xf9, 0x89, 0xed, 0x34, 0xe9, 0x37, 0x03, 0xcd, 0xb2, 0x6c, 0xbd, 0xef, 0xd8, 0x37, 0xfe, 0xb6, 0xb2, 0xa7, 0xec, 0x2f, 0x69, 0xd9, 0x91, 0x65,
0xb9, 0x00, 0xd3, 0x02, 0x34, 0xe7, 0x0c, 0x54, 0xdf, 0x41, 0x25, 0xa6, 0x2f, 0xf0, 0x5c, 0x27, 0xd7, 0xe9, 0x37, 0x03, 0x8d, 0xa9, 0x00, 0x53, 0x02, 0x34, 0xa6, 0x1c, 0xdc, 0x86, 0x15, 0xa3,
0xc0, 0xe8, 0x0d, 0x6c, 0x4c, 0xc9, 0xdc, 0xa5, 0xca, 0x32, 0x87, 0xca, 0xb1, 0xd2, 0x18, 0x53, 0xdf, 0x77, 0xc6, 0x36, 0xd9, 0x4e, 0xef, 0x29, 0xfb, 0x39, 0x2d, 0xf8, 0x54, 0xdf, 0x42, 0x39,
0x53, 0x1a, 0xd7, 0x64, 0xee, 0xea, 0x1c, 0x51, 0xbf, 0x4f, 0x01, 0xea, 0x60, 0x33, 0xc0, 0xbd, 0xb6, 0x93, 0xef, 0x3a, 0xb6, 0x8f, 0xd1, 0x0b, 0x58, 0x1a, 0x93, 0xa9, 0x43, 0xb7, 0x49, 0xef,
0x29, 0xf1, 0xa6, 0xa1, 0x29, 0x9b, 0x90, 0xb6, 0x2d, 0x66, 0x43, 0x51, 0x4f, 0xdb, 0x16, 0xfa, 0xe7, 0x5f, 0xe7, 0x6b, 0x43, 0xaa, 0x64, 0xed, 0x92, 0x4c, 0x1d, 0x8d, 0x23, 0xea, 0xb7, 0x0a,
0x1c, 0xf2, 0xee, 0x94, 0x78, 0xae, 0xed, 0x10, 0x76, 0xb8, 0x72, 0xbc, 0x25, 0x94, 0xf5, 0xa6, 0xa0, 0x36, 0x36, 0x7c, 0xdc, 0x19, 0x13, 0x77, 0x1c, 0x2a, 0xb9, 0x0a, 0x29, 0xcb, 0x64, 0xda,
0xe4, 0x8a, 0x92, 0xf5, 0x90, 0x01, 0x7d, 0x09, 0x08, 0xcf, 0x3d, 0xdb, 0x37, 0x89, 0xed, 0x3a, 0x15, 0xb4, 0x94, 0x65, 0xa2, 0xcf, 0x21, 0xeb, 0x8c, 0x89, 0xeb, 0x58, 0x36, 0x61, 0x6a, 0xe5,
0x46, 0x80, 0x47, 0xae, 0x63, 0x05, 0xb5, 0xcc, 0x41, 0xea, 0x30, 0xab, 0x6f, 0x47, 0x48, 0x9f, 0x5f, 0xaf, 0x09, 0x61, 0x9d, 0x31, 0xb9, 0xa0, 0x64, 0x2d, 0x64, 0x40, 0x5f, 0x00, 0xc2, 0x53,
0x03, 0xea, 0x5b, 0xa8, 0xc4, 0x2c, 0x10, 0xc6, 0x7f, 0x02, 0x10, 0xf1, 0x32, 0x53, 0xb2, 0xba, 0xd7, 0xf2, 0x0c, 0x62, 0x39, 0xb6, 0xee, 0xe3, 0xbe, 0x63, 0x9b, 0x3e, 0x53, 0x39, 0xa3, 0xad,
0x44, 0x51, 0xfb, 0x50, 0xd5, 0xf1, 0xf8, 0xe7, 0x35, 0x5d, 0xdd, 0x85, 0x9d, 0x84, 0x52, 0x6e, 0x47, 0x48, 0x97, 0x03, 0xea, 0x1b, 0x28, 0xc7, 0x34, 0x10, 0xca, 0x7f, 0x02, 0x10, 0xf1, 0x32,
0x8d, 0xfa, 0x27, 0xc8, 0xb5, 0xf1, 0x42, 0xc7, 0xdf, 0xa1, 0x43, 0x28, 0x3f, 0xe0, 0x85, 0x71, 0x55, 0x32, 0x9a, 0x44, 0x51, 0xbb, 0x50, 0xd1, 0xf0, 0xf0, 0xa7, 0x55, 0x5d, 0xdd, 0x82, 0x8d,
0x6b, 0x3b, 0x77, 0xd8, 0x37, 0x3c, 0x9f, 0xea, 0xe5, 0xc9, 0xda, 0x7c, 0xc0, 0x8b, 0x73, 0x46, 0x84, 0x50, 0xae, 0x8d, 0xfa, 0x47, 0x58, 0x6e, 0xe1, 0x99, 0x86, 0xbf, 0x46, 0xfb, 0x50, 0xba,
0xbe, 0xa2, 0x54, 0xf4, 0x1a, 0x80, 0x71, 0x9a, 0x13, 0x7b, 0xbc, 0x10, 0x39, 0x2b, 0x50, 0x1e, 0xc3, 0x33, 0xfd, 0xc6, 0xb2, 0x6f, 0xb1, 0xa7, 0xbb, 0x1e, 0x95, 0xcb, 0xdd, 0xb8, 0x7a, 0x87,
0x46, 0x50, 0x4b, 0xa0, 0x9c, 0x58, 0x96, 0x2f, 0xec, 0x56, 0x55, 0x28, 0xf2, 0x4f, 0xe1, 0x3f, 0x67, 0x27, 0x8c, 0x7c, 0x41, 0xa9, 0xe8, 0x39, 0x00, 0xe3, 0x34, 0x46, 0xd6, 0x70, 0x26, 0xbc,
0x82, 0xac, 0x69, 0x59, 0x3e, 0xd3, 0x5d, 0xd0, 0xd9, 0x6f, 0xf5, 0x3d, 0x28, 0x03, 0xdf, 0x74, 0x99, 0xa3, 0x3c, 0x8c, 0xa0, 0xbe, 0x84, 0xfc, 0xa1, 0x69, 0x7a, 0x81, 0xde, 0x92, 0x77, 0x95,
0x02, 0x73, 0x44, 0x43, 0x80, 0x76, 0x20, 0x47, 0xe6, 0xc6, 0x3d, 0x9e, 0x0b, 0x77, 0x37, 0xc8, 0xb8, 0x77, 0x55, 0x28, 0x70, 0x46, 0x61, 0x19, 0x04, 0x19, 0xc3, 0x34, 0x3d, 0xc1, 0xc6, 0x7e,
0xbc, 0x85, 0xe7, 0xa8, 0x0a, 0x1b, 0x63, 0x73, 0x88, 0xc7, 0xec, 0xc8, 0x82, 0xce, 0x3f, 0xd4, 0xab, 0xff, 0x4d, 0xc1, 0xca, 0x21, 0xe7, 0xa7, 0xb8, 0x6d, 0x8c, 0x70, 0x80, 0xd3, 0xdf, 0xe8,
0xaf, 0x61, 0xeb, 0x6a, 0x3a, 0x1c, 0xdb, 0xc1, 0x7d, 0x78, 0xc4, 0xa7, 0x50, 0xf2, 0x38, 0xc9, 0x1d, 0x14, 0x28, 0x1f, 0xf6, 0x7d, 0x9d, 0xcc, 0x5c, 0xcc, 0xb4, 0x59, 0x7d, 0xbd, 0x59, 0x0b,
0xc0, 0xbe, 0xef, 0x2e, 0xcf, 0x2a, 0x0a, 0xa2, 0x46, 0x69, 0xea, 0x3f, 0x53, 0x80, 0xfa, 0xd8, 0xc3, 0xb9, 0x76, 0xc8, 0xe1, 0xde, 0xcc, 0xc5, 0x5a, 0xde, 0x88, 0x3e, 0x50, 0x0d, 0xca, 0x78,
0xb1, 0x78, 0x40, 0x82, 0x65, 0x98, 0xf7, 0x00, 0x02, 0x93, 0x18, 0x1e, 0xf6, 0x8d, 0x87, 0x19, 0x4a, 0xb0, 0x6d, 0x62, 0x53, 0x77, 0xc7, 0xd7, 0x43, 0xab, 0xaf, 0xdf, 0xe1, 0x99, 0x08, 0xc1,
0x13, 0xcc, 0xe8, 0xf9, 0xc0, 0x24, 0x57, 0xd8, 0x6f, 0xcf, 0xd0, 0x21, 0x3c, 0x77, 0x39, 0x7f, 0xf5, 0x00, 0xba, 0x60, 0x48, 0x0b, 0xcf, 0xd0, 0xaf, 0x61, 0x73, 0x64, 0xf8, 0x04, 0x7b, 0x7a,
0x2d, 0xcd, 0x6a, 0x6f, 0xb3, 0x21, 0x2e, 0x42, 0x63, 0x30, 0xef, 0x4d, 0x89, 0xbe, 0x84, 0x23, 0x64, 0x27, 0x6e, 0xa6, 0xcc, 0x9e, 0xb2, 0x5f, 0xd4, 0x2a, 0x1c, 0x6d, 0x05, 0xc6, 0x62, 0x18,
0x63, 0x33, 0x92, 0xb1, 0xf1, 0xab, 0x90, 0x4d, 0x5c, 0x85, 0xcf, 0x61, 0x9b, 0xd6, 0xb9, 0x65, 0x7a, 0x09, 0x6b, 0x26, 0xf6, 0xac, 0x7b, 0x1e, 0x34, 0xae, 0x41, 0x06, 0xdb, 0x4b, 0x6c, 0x87,
0x4c, 0x1d, 0xca, 0x60, 0xfb, 0x13, 0x6c, 0xd5, 0x36, 0x0e, 0x52, 0x87, 0x79, 0xbd, 0xcc, 0x80, 0xd5, 0x88, 0x7c, 0x61, 0x90, 0x01, 0x7a, 0x45, 0xa3, 0x8b, 0x60, 0xcf, 0x36, 0x86, 0x6c, 0x03,
0xeb, 0x88, 0xae, 0x7e, 0x01, 0x95, 0x98, 0xf5, 0xc2, 0xf5, 0x1d, 0xc8, 0xf9, 0xe6, 0xcc, 0x20, 0x6e, 0xb2, 0x65, 0x26, 0xba, 0x14, 0x20, 0x2d, 0x3c, 0xab, 0x33, 0x5b, 0xbc, 0x02, 0x64, 0xd9,
0x61, 0xe8, 0x7c, 0x73, 0x36, 0x98, 0xab, 0x6f, 0x01, 0x69, 0x01, 0xb1, 0x27, 0x26, 0xc1, 0xe7, 0x73, 0xdc, 0x2b, 0x9c, 0x3b, 0x40, 0x42, 0xee, 0xe7, 0x00, 0x13, 0x83, 0xf4, 0x07, 0xba, 0x63,
0x18, 0x2f, 0x7d, 0xdd, 0x07, 0x85, 0x2a, 0x34, 0x88, 0xe9, 0xdf, 0xe1, 0x65, 0xb6, 0x81, 0x92, 0x0f, 0x67, 0xdb, 0xd9, 0x3d, 0x65, 0x3f, 0xab, 0xe5, 0x18, 0xa5, 0x63, 0x0f, 0x67, 0xaa, 0xc9,
0x06, 0x8c, 0xa2, 0x7e, 0x05, 0x95, 0x98, 0x98, 0x38, 0xe4, 0x47, 0x63, 0xa4, 0xfe, 0x3b, 0x03, 0xd3, 0x4c, 0xd8, 0xd9, 0x0f, 0x3c, 0xf7, 0xd3, 0xda, 0x5b, 0x3d, 0x81, 0x4a, 0x7c, 0x17, 0xe1,
0xc5, 0x2b, 0xec, 0x58, 0xb6, 0x73, 0xd7, 0x9f, 0x61, 0xec, 0xc5, 0x2a, 0x35, 0xf5, 0x53, 0x97, 0xf6, 0x1a, 0x64, 0x45, 0x44, 0x04, 0x09, 0x8d, 0x64, 0x71, 0x1c, 0xd2, 0x42, 0x1e, 0xf5, 0x3f,
0xec, 0x5b, 0x28, 0xce, 0x6c, 0xe2, 0xe0, 0x20, 0x30, 0xc8, 0xc2, 0xc3, 0x2c, 0xd7, 0x9b, 0xc7, 0x0a, 0x54, 0x4e, 0x47, 0xae, 0xe3, 0x05, 0xa2, 0x1e, 0xd3, 0xf7, 0x01, 0x27, 0xa7, 0x7e, 0xb8,
0x2f, 0x1a, 0xe1, 0x2b, 0xd4, 0xb8, 0xe1, 0xf0, 0x60, 0xe1, 0x61, 0x5d, 0x99, 0x45, 0x1f, 0xb4, 0x93, 0xd3, 0x8f, 0x38, 0x39, 0x69, 0x95, 0xcc, 0xf7, 0xb7, 0xca, 0x16, 0x6c, 0x24, 0x0e, 0x23,
0x2e, 0xcd, 0x89, 0x3b, 0x75, 0x88, 0x11, 0x98, 0x84, 0xc5, 0xbd, 0xa4, 0x17, 0x38, 0xa5, 0x6f, 0x32, 0xd3, 0x83, 0x4d, 0x0e, 0x84, 0xca, 0x05, 0xe7, 0x7c, 0x0e, 0x20, 0x1d, 0x85, 0xdf, 0x08,
0x12, 0xf4, 0x0b, 0x28, 0x2e, 0xad, 0x1e, 0x2e, 0x08, 0x66, 0xe1, 0x2f, 0x9d, 0xa6, 0x6b, 0x29, 0x39, 0x37, 0x3c, 0xc2, 0x8f, 0x70, 0xd1, 0x53, 0xd8, 0x9a, 0xdb, 0x53, 0xa8, 0xf3, 0x1e, 0xf2,
0x1d, 0xb8, 0xed, 0xa7, 0x0b, 0x82, 0xe9, 0x25, 0x1f, 0xfa, 0xae, 0x69, 0x8d, 0xcc, 0x80, 0x18, 0x3d, 0xcf, 0xb0, 0x7d, 0xa3, 0x4f, 0x23, 0x16, 0x6d, 0xc0, 0x32, 0x99, 0xea, 0x03, 0x3c, 0x15,
0x26, 0x21, 0x78, 0xe2, 0x91, 0x80, 0x65, 0xa1, 0xa4, 0x6f, 0x87, 0xc8, 0x89, 0x00, 0xd0, 0x31, 0xfb, 0x2f, 0x91, 0x69, 0x13, 0x4f, 0x51, 0x05, 0x96, 0x86, 0xc6, 0x35, 0x1e, 0x0a, 0x03, 0xf3,
0xec, 0x38, 0x78, 0x4e, 0x8c, 0x48, 0xe6, 0x1e, 0xdb, 0x77, 0xf7, 0xa4, 0x96, 0x63, 0x12, 0x15, 0x0f, 0xf5, 0x37, 0xb0, 0xc6, 0x04, 0xfa, 0x83, 0xd0, 0xe9, 0x9f, 0x42, 0xd1, 0xe5, 0x24, 0x1d,
0x0a, 0x9e, 0x2e, 0xb1, 0x16, 0x83, 0xa8, 0x8c, 0xcf, 0x33, 0x80, 0x2d, 0x43, 0x4e, 0x40, 0x9e, 0x7b, 0x9e, 0x13, 0x24, 0x7d, 0x41, 0x10, 0x1b, 0x94, 0xa6, 0xfe, 0x53, 0x01, 0xd4, 0xc5, 0xb6,
0xcb, 0x84, 0x60, 0x33, 0xcc, 0x04, 0xfa, 0x06, 0x5e, 0x44, 0x32, 0x31, 0x37, 0x0a, 0xa1, 0x1b, 0xc9, 0xef, 0xac, 0x30, 0x2e, 0x77, 0x00, 0x7c, 0x83, 0xe8, 0x2e, 0x75, 0xd2, 0x84, 0x2d, 0x4c,
0x91, 0x60, 0x3f, 0xf2, 0x47, 0x85, 0xd2, 0x92, 0xfd, 0x91, 0xf1, 0x03, 0x7b, 0x71, 0x14, 0xee, 0x6b, 0x59, 0xdf, 0x20, 0x17, 0xd8, 0x6b, 0x4d, 0xd0, 0x3e, 0xac, 0x38, 0x9c, 0x7f, 0x3b, 0xc5,
0xf2, 0x07, 0x4a, 0x42, 0x6f, 0x61, 0x77, 0x55, 0x39, 0xe7, 0x56, 0x18, 0x77, 0x35, 0xa1, 0x99, 0xa2, 0x69, 0xb5, 0x26, 0xaa, 0x58, 0xad, 0x37, 0xed, 0x8c, 0x89, 0x16, 0xc0, 0x91, 0xb2, 0x69,
0x8b, 0x55, 0x61, 0xe3, 0xd6, 0xf5, 0x47, 0xb8, 0xf6, 0x9c, 0xd5, 0x28, 0xff, 0x50, 0x5f, 0x40, 0x49, 0xd9, 0x78, 0x1d, 0xcb, 0x24, 0xea, 0xd8, 0xe7, 0xb0, 0x4e, 0x4b, 0x91, 0xa9, 0x8f, 0x6d,
0x55, 0xce, 0xfe, 0xf2, 0x62, 0xa9, 0x37, 0xb0, 0x93, 0xa0, 0x8b, 0x6a, 0xfa, 0x03, 0x6c, 0x7a, 0xca, 0x60, 0x79, 0x23, 0x6c, 0xb2, 0x7c, 0xce, 0x6a, 0x25, 0x06, 0x5c, 0x46, 0x74, 0xf5, 0x15,
0x1c, 0x30, 0x02, 0x86, 0x88, 0x67, 0x7d, 0x57, 0xca, 0xb9, 0x2c, 0xa9, 0x97, 0x3c, 0x59, 0x8f, 0x94, 0x63, 0xda, 0x8b, 0xa3, 0x6f, 0xc0, 0xb2, 0x67, 0x4c, 0x74, 0x12, 0x9a, 0xce, 0x33, 0x26,
0xfa, 0xaf, 0x14, 0x6c, 0x9e, 0x4e, 0x27, 0x9e, 0x54, 0xd8, 0xff, 0x53, 0xc5, 0xed, 0x83, 0xc2, 0xbd, 0xa9, 0xfa, 0x06, 0x50, 0xc3, 0x27, 0xd6, 0xc8, 0x20, 0xf8, 0x04, 0xe3, 0xe0, 0xac, 0xbb,
0xe3, 0xcf, 0x72, 0xc1, 0x0a, 0xae, 0xa4, 0x03, 0x27, 0xd1, 0x0c, 0xac, 0x14, 0x4e, 0x66, 0x6d, 0x90, 0xa7, 0x02, 0x75, 0x62, 0x78, 0xb7, 0x38, 0xb8, 0x90, 0x81, 0x92, 0x7a, 0x8c, 0xa2, 0x7e,
0xe1, 0x84, 0xd1, 0xc8, 0x4a, 0xd1, 0x58, 0x0d, 0xff, 0xc6, 0x4a, 0xf8, 0xd5, 0x6d, 0xd8, 0x0a, 0x09, 0xe5, 0xd8, 0x32, 0xb1, 0xc9, 0xa3, 0x36, 0x52, 0xff, 0x97, 0x86, 0xc2, 0x05, 0xb6, 0x4d,
0xed, 0x17, 0xcf, 0xf2, 0x97, 0xb0, 0x4d, 0x1b, 0x5f, 0x2c, 0x82, 0xa8, 0x06, 0xcf, 0x1f, 0xb1, 0xcb, 0xbe, 0xed, 0x4e, 0x30, 0x76, 0x63, 0xc5, 0x44, 0xf9, 0xae, 0x3a, 0xf8, 0x0e, 0x0a, 0x13,
0x3f, 0x74, 0x03, 0xcc, 0x9c, 0xca, 0xeb, 0xcb, 0x4f, 0xf5, 0xfb, 0x34, 0x6f, 0xbc, 0x89, 0xc8, 0x8b, 0xd8, 0x8f, 0x04, 0xd8, 0x15, 0x87, 0x79, 0x80, 0x4d, 0xa2, 0x0f, 0x1a, 0xba, 0xc6, 0x88,
0x76, 0xa0, 0x42, 0xa2, 0x67, 0xd5, 0xb0, 0x30, 0x31, 0xed, 0x71, 0x20, 0x22, 0xf2, 0x52, 0x44, 0x86, 0xb9, 0xee, 0x1b, 0x41, 0x4a, 0xe5, 0x38, 0xa5, 0x6b, 0x10, 0xf4, 0x33, 0x28, 0x04, 0x5a,
0x44, 0x7a, 0x78, 0xcf, 0x38, 0x43, 0xeb, 0x99, 0x8e, 0xc8, 0x0a, 0x15, 0xdd, 0xc0, 0x96, 0xac, 0x5f, 0xcf, 0x08, 0xcf, 0xa3, 0xe2, 0x51, 0x6a, 0x5b, 0xd1, 0x80, 0xeb, 0x7e, 0x34, 0x23, 0x98,
0xcd, 0xb6, 0x02, 0xd1, 0x77, 0xbe, 0x90, 0x12, 0xb5, 0x6a, 0x85, 0x7c, 0xc0, 0xc5, 0x19, 0x55, 0xd6, 0xe1, 0x6b, 0xcf, 0x31, 0xcc, 0xbe, 0xe1, 0x13, 0xdd, 0x20, 0x04, 0x8f, 0x5c, 0xe2, 0x33,
0xbe, 0x29, 0xa9, 0xb9, 0xb0, 0x82, 0xfa, 0xb7, 0xb0, 0x19, 0xe7, 0x41, 0x9f, 0xad, 0x1e, 0x45, 0x2f, 0x14, 0xb5, 0xf5, 0x10, 0x39, 0x14, 0x00, 0x7a, 0x0d, 0x1b, 0x36, 0x9e, 0x12, 0x3d, 0x5a,
0x6b, 0xa2, 0x90, 0x14, 0x3d, 0xcd, 0x43, 0x8e, 0xd7, 0x8c, 0x6a, 0xc2, 0x6e, 0x87, 0x3e, 0xb1, 0x33, 0xc0, 0xd6, 0xed, 0x20, 0xb8, 0x5b, 0xcb, 0x14, 0x3c, 0x0a, 0xb0, 0x26, 0x83, 0xe8, 0x1a,
0x92, 0xa6, 0x65, 0xdc, 0x10, 0x64, 0xc9, 0x3c, 0xec, 0x9d, 0xec, 0xf7, 0xfa, 0x5e, 0x82, 0xf6, 0x8f, 0x7b, 0x00, 0x9b, 0xba, 0xec, 0x80, 0x2c, 0x5f, 0x13, 0x82, 0xf5, 0xd0, 0x13, 0xe8, 0x2b,
0xa0, 0xe0, 0x3e, 0x62, 0x7f, 0xe6, 0xdb, 0x22, 0xcd, 0x79, 0x3d, 0x22, 0xa8, 0x75, 0xa8, 0xad, 0xd8, 0x8c, 0xd6, 0xc4, 0x8e, 0x91, 0x0b, 0x8f, 0x11, 0x2d, 0xec, 0x46, 0xe7, 0x51, 0xa1, 0x18,
0x1e, 0x21, 0x12, 0xf6, 0x43, 0x0a, 0xb6, 0xce, 0xa7, 0x8e, 0x75, 0x15, 0x0c, 0xc3, 0x8e, 0x5d, 0xb0, 0xdf, 0x33, 0x7e, 0x60, 0x4d, 0x41, 0x9e, 0x1f, 0xf9, 0x03, 0x25, 0xa1, 0x37, 0xb0, 0x35,
0x85, 0xac, 0x17, 0x0c, 0x79, 0x05, 0x16, 0x5b, 0xcf, 0x74, 0xf6, 0x85, 0x7e, 0x0d, 0x19, 0xdf, 0x2f, 0x9c, 0x73, 0xe7, 0x19, 0x77, 0x25, 0x21, 0x99, 0x2f, 0xab, 0xc0, 0xd2, 0x8d, 0xe3, 0xf5,
0x9c, 0x89, 0xd0, 0xed, 0x48, 0xa1, 0x1b, 0xcc, 0x07, 0x78, 0xe2, 0x8d, 0x4d, 0x82, 0x5b, 0xcf, 0x31, 0xab, 0x0c, 0x59, 0x8d, 0x7f, 0xa8, 0x9b, 0x50, 0x91, 0xbd, 0x1f, 0x24, 0x96, 0x7a, 0x05,
0x74, 0xca, 0x83, 0xde, 0xc4, 0x2b, 0x93, 0xd5, 0x5d, 0x2b, 0x95, 0xa8, 0xcd, 0x44, 0x7d, 0xd1, 0x1b, 0x09, 0xba, 0x88, 0xa6, 0xdf, 0xc3, 0xaa, 0xcb, 0x01, 0xdd, 0x67, 0x88, 0xb8, 0xa8, 0xb7,
0xea, 0xcb, 0xb6, 0x52, 0xb1, 0x0a, 0x3b, 0x05, 0xc8, 0x13, 0xa1, 0xfb, 0x34, 0x07, 0xd9, 0x5b, 0x24, 0x9f, 0xcb, 0x2b, 0xb5, 0xa2, 0x2b, 0xcb, 0x51, 0xff, 0xa5, 0xc0, 0xea, 0xd1, 0x78, 0xe4,
0x8c, 0x03, 0xf5, 0xef, 0x29, 0x28, 0x47, 0x16, 0x8b, 0x8a, 0xd9, 0x07, 0xe5, 0x76, 0xea, 0x58, 0x4a, 0x81, 0xfd, 0x83, 0x22, 0x6e, 0x17, 0xf2, 0xdc, 0xfe, 0xcc, 0x17, 0x2c, 0xe0, 0x8a, 0x1a,
0xd8, 0x32, 0x22, 0xcb, 0x75, 0xe0, 0x24, 0xca, 0x88, 0x1a, 0x50, 0x19, 0xdd, 0x9b, 0xce, 0x1d, 0x70, 0x12, 0xf5, 0xc0, 0x5c, 0xe0, 0xa4, 0x17, 0x06, 0x4e, 0x68, 0x8d, 0x8c, 0x64, 0x8d, 0x79,
0x36, 0x78, 0xa3, 0x33, 0x6c, 0xc7, 0xc2, 0x73, 0x31, 0x04, 0x6c, 0x73, 0x88, 0xf7, 0xa4, 0x0b, 0xf3, 0x2f, 0xcd, 0x99, 0x5f, 0x5d, 0x87, 0xb5, 0x50, 0x7f, 0x71, 0x21, 0x7e, 0x01, 0xeb, 0xb4,
0x0a, 0xa0, 0x6f, 0xa0, 0x38, 0x76, 0x47, 0x0f, 0xd8, 0x32, 0xf8, 0xc4, 0x96, 0x61, 0x57, 0xbb, 0x9c, 0xc5, 0x2c, 0x48, 0x9b, 0x9d, 0x7b, 0xec, 0x5d, 0x3b, 0x3e, 0xaf, 0x42, 0x59, 0x2d, 0xf8,
0x2a, 0xb9, 0x4d, 0xa7, 0x36, 0x36, 0x27, 0xe9, 0x0a, 0xe7, 0xbc, 0x66, 0x03, 0xdc, 0x0f, 0x29, 0x54, 0xbf, 0x4d, 0xf1, 0xae, 0x39, 0x61, 0xd9, 0x36, 0x94, 0x49, 0x74, 0xad, 0xea, 0x26, 0x26,
0x80, 0x28, 0x22, 0xe8, 0x33, 0xc8, 0xd9, 0x0e, 0xeb, 0xbb, 0xfc, 0x71, 0x58, 0xb9, 0xcf, 0x02, 0x86, 0x35, 0xf4, 0x85, 0x45, 0x9e, 0x0a, 0x8b, 0x48, 0x17, 0xef, 0x31, 0x67, 0x68, 0x3e, 0xd1,
0x46, 0xbf, 0x4f, 0x76, 0x68, 0x75, 0x6d, 0x88, 0x1b, 0xa2, 0x71, 0x6a, 0x0e, 0xf1, 0x17, 0x61, 0x10, 0x99, 0xa3, 0xa2, 0x2b, 0x58, 0x93, 0xa5, 0x59, 0xa6, 0x2f, 0x5a, 0xc3, 0x57, 0x92, 0xa3,
0xd7, 0xae, 0xbf, 0x87, 0xa2, 0x0c, 0xa0, 0x32, 0x64, 0x1e, 0xf0, 0x42, 0xcc, 0x0f, 0xf4, 0x27, 0xe6, 0xb5, 0x90, 0x37, 0x38, 0x3d, 0xa6, 0xc2, 0x57, 0x25, 0x31, 0xa7, 0xa6, 0x5f, 0x7d, 0x07,
0x2d, 0x9c, 0x47, 0x73, 0x3c, 0xe5, 0x8d, 0x29, 0xab, 0xf3, 0x8f, 0xf7, 0xe9, 0x77, 0x29, 0xf5, 0xab, 0x71, 0x1e, 0xda, 0xd7, 0x24, 0xb7, 0xa2, 0x31, 0x91, 0x4b, 0x2e, 0x3d, 0xca, 0xc2, 0x32,
0x1e, 0x0a, 0xa1, 0x2f, 0xff, 0xdf, 0xa0, 0x19, 0x1f, 0x11, 0x33, 0x2b, 0x23, 0xe2, 0xd7, 0x50, 0x8f, 0x19, 0xd5, 0x80, 0xad, 0x36, 0xbd, 0x62, 0x25, 0x49, 0x52, 0xe9, 0x26, 0xd3, 0xb0, 0xbd,
0x39, 0xb7, 0x1d, 0x73, 0x6c, 0xff, 0x15, 0xcb, 0xf5, 0xf6, 0x53, 0xc9, 0x53, 0x3f, 0x42, 0x35, 0x65, 0xbf, 0x17, 0xd7, 0x12, 0xb4, 0x03, 0x39, 0xe7, 0x1e, 0x7b, 0x13, 0xcf, 0x12, 0x6e, 0xce,
0x2e, 0x17, 0x65, 0x9d, 0x8d, 0xf1, 0x71, 0x41, 0x4e, 0x62, 0x59, 0x3f, 0x80, 0x22, 0x9d, 0x2a, 0x6a, 0x11, 0x41, 0xad, 0xc2, 0xf6, 0xfc, 0x16, 0xc2, 0x61, 0xff, 0x56, 0x60, 0xed, 0x64, 0x6c,
0x6e, 0xa9, 0x30, 0x9d, 0x2d, 0xd2, 0x9c, 0xc3, 0x37, 0x67, 0x4c, 0xdf, 0x60, 0xae, 0x56, 0xf8, 0x9b, 0x17, 0xfe, 0x75, 0xd8, 0x32, 0x54, 0x20, 0xe3, 0xfa, 0xd7, 0x3c, 0x02, 0x0b, 0xcd, 0x27,
0x83, 0xc5, 0x9c, 0x0f, 0x9f, 0xfc, 0x4b, 0xfe, 0x2a, 0x2d, 0x89, 0xe2, 0xb4, 0x64, 0x49, 0xa4, 0x1a, 0xfb, 0x42, 0xbf, 0x84, 0xb4, 0x67, 0x4c, 0x84, 0xe9, 0x36, 0x24, 0xd3, 0xf5, 0xa6, 0x3d,
0xfe, 0xcb, 0x92, 0xf8, 0xcd, 0xdf, 0x32, 0xa0, 0x48, 0xcd, 0x1f, 0x55, 0x60, 0xeb, 0xba, 0xdb, 0x3c, 0x72, 0x87, 0x06, 0xc1, 0xcd, 0x27, 0x1a, 0xe5, 0x41, 0x2f, 0xe2, 0x91, 0xc9, 0xe2, 0xae,
0xee, 0xf6, 0x6e, 0xba, 0xc6, 0xcd, 0xc5, 0xa0, 0xab, 0xf5, 0xfb, 0xe5, 0x67, 0xa8, 0x06, 0xd5, 0xa9, 0x24, 0x62, 0x33, 0x11, 0x5f, 0x34, 0xfa, 0x32, 0x4d, 0x25, 0x9e, 0xe0, 0x52, 0x9b, 0xbc,
0x66, 0xef, 0xf2, 0xf2, 0x62, 0x70, 0xa9, 0x75, 0x07, 0xc6, 0xe0, 0xe2, 0x52, 0x33, 0x3a, 0xbd, 0x14, 0x6b, 0x93, 0x8f, 0x00, 0xb2, 0x44, 0xec, 0x7a, 0xb4, 0x0c, 0x99, 0x1b, 0x8c, 0x7d, 0xf5,
0x66, 0xbb, 0x9c, 0x42, 0xbb, 0x50, 0x91, 0x90, 0x6e, 0xcf, 0x38, 0xd3, 0x3a, 0x27, 0x1f, 0xcb, 0x6f, 0x0a, 0x94, 0xa2, 0xb3, 0x88, 0x58, 0xda, 0x85, 0xfc, 0xcd, 0x98, 0x77, 0x3a, 0xe1, 0x99,
0x69, 0xb4, 0x03, 0xdb, 0x12, 0xa0, 0x6b, 0x1f, 0x7a, 0x6d, 0xad, 0x9c, 0xa1, 0xfc, 0xad, 0x41, 0x34, 0xe0, 0x24, 0xca, 0x48, 0x9b, 0xa1, 0xfe, 0xc0, 0xb0, 0x6f, 0xb1, 0xce, 0x4b, 0xa0, 0x6e,
0xa7, 0x69, 0xf4, 0xce, 0xcf, 0x35, 0x5d, 0x3b, 0x5b, 0x02, 0x59, 0x7a, 0x04, 0x03, 0x4e, 0x9a, 0xd9, 0x26, 0x9e, 0x8a, 0x0e, 0x7e, 0x9d, 0x43, 0xbc, 0x5a, 0x9d, 0x52, 0x00, 0x7d, 0x05, 0x85,
0x4d, 0xed, 0x6a, 0x10, 0x21, 0x1b, 0xe8, 0x97, 0xf0, 0x26, 0x26, 0x42, 0x8f, 0xef, 0x5d, 0x0f, 0xa1, 0xd3, 0xbf, 0xc3, 0xa6, 0xce, 0xc7, 0xad, 0x34, 0x4b, 0xfa, 0x8a, 0x64, 0x10, 0x3a, 0x72,
0x8c, 0xbe, 0xd6, 0xec, 0x75, 0xcf, 0x8c, 0x8e, 0xf6, 0x41, 0xeb, 0x94, 0x73, 0xe8, 0x57, 0xa0, 0xb1, 0x21, 0x47, 0xcb, 0x73, 0xce, 0x4b, 0x36, 0x7d, 0xfd, 0x5d, 0x01, 0x88, 0x6c, 0x85, 0x5e,
0xc6, 0x15, 0xf4, 0xaf, 0x9b, 0x4d, 0xad, 0xdf, 0x8f, 0xf3, 0x3d, 0x47, 0xfb, 0xf0, 0x2a, 0x61, 0xc2, 0xb2, 0x65, 0xb3, 0x8a, 0xcc, 0xaf, 0x8d, 0xb9, 0x4c, 0x17, 0x30, 0xfa, 0x5d, 0xb2, 0x76,
0xc1, 0x65, 0x6f, 0xa0, 0x2d, 0xb5, 0x96, 0xf3, 0xe8, 0x00, 0xf6, 0x92, 0x96, 0x30, 0x0e, 0xa1, 0xab, 0x0b, 0x8d, 0x5f, 0x13, 0x25, 0xb5, 0x61, 0x13, 0x6f, 0x16, 0xd6, 0xf3, 0xea, 0x7b, 0x28,
0xaf, 0x5c, 0x40, 0x7b, 0x50, 0x63, 0x1c, 0xb2, 0xe6, 0xa5, 0xbd, 0x80, 0xaa, 0x50, 0x16, 0x91, 0xc8, 0x00, 0x2a, 0x41, 0x3a, 0x68, 0x90, 0x72, 0x1a, 0xfd, 0x49, 0x43, 0xea, 0xde, 0x18, 0x8e,
0x33, 0xda, 0xda, 0x47, 0xa3, 0x75, 0xd2, 0x6f, 0x95, 0x15, 0xf4, 0x0a, 0x76, 0xbb, 0x5a, 0x9f, 0x79, 0xc9, 0xca, 0x68, 0xfc, 0xe3, 0x7d, 0xea, 0xad, 0xa2, 0x0e, 0x20, 0x17, 0x9e, 0xe5, 0xc7,
0xaa, 0x5b, 0x01, 0x8b, 0x89, 0x60, 0x9d, 0x74, 0x9b, 0xad, 0x9e, 0x5e, 0x2e, 0x1d, 0xff, 0xa3, 0x4d, 0x89, 0xf1, 0xf9, 0x2e, 0x3d, 0x37, 0xdf, 0x5d, 0x40, 0xf9, 0xc4, 0xb2, 0x8d, 0xa1, 0xf5,
0x00, 0x85, 0x1b, 0x96, 0xc0, 0xb6, 0x4d, 0x50, 0x07, 0x14, 0x69, 0x6f, 0x43, 0xaf, 0x13, 0x0d, 0x0d, 0x96, 0x23, 0xf1, 0x3b, 0x9d, 0xf7, 0x60, 0x80, 0xa8, 0x1f, 0xa1, 0x12, 0x97, 0x18, 0xc5,
0x22, 0xbe, 0x1f, 0xd6, 0x3f, 0x79, 0x0a, 0x0e, 0xdb, 0x98, 0x22, 0x2d, 0x52, 0x71, 0x6d, 0x2b, 0x03, 0x9b, 0xdb, 0xe3, 0x22, 0x39, 0x89, 0x89, 0xdc, 0x83, 0x02, 0xed, 0x44, 0x6e, 0xe8, 0x62,
0x7b, 0x52, 0x5c, 0xdb, 0x9a, 0xfd, 0x4b, 0x87, 0x52, 0x6c, 0x15, 0x42, 0xfb, 0x92, 0xc0, 0xba, 0xda, 0x8f, 0xa4, 0x38, 0x87, 0x67, 0x4c, 0x98, 0xbc, 0xde, 0x54, 0x2d, 0xf3, 0x4b, 0x8e, 0x99,
0xcd, 0xab, 0x7e, 0xf0, 0x34, 0x83, 0xd0, 0x79, 0x01, 0x10, 0x15, 0x3a, 0xda, 0x4b, 0xf8, 0x13, 0x25, 0x2c, 0x13, 0x67, 0xfc, 0x26, 0x0b, 0x88, 0x62, 0xb7, 0x64, 0xb0, 0x28, 0xdf, 0x33, 0x58,
0xbb, 0x14, 0xf5, 0xd7, 0x4f, 0xa0, 0x42, 0xd5, 0x7b, 0x28, 0x9d, 0x61, 0xdf, 0x7e, 0xc4, 0x5d, 0x3e, 0xfb, 0x86, 0xcf, 0x8b, 0x41, 0x8b, 0x90, 0x87, 0x95, 0xcb, 0xf3, 0xd6, 0x79, 0xe7, 0xea,
0x3c, 0x27, 0x6d, 0xbc, 0x40, 0xdb, 0x12, 0x3f, 0x5f, 0xd5, 0xea, 0x2f, 0xc2, 0xa5, 0xa3, 0x8d, 0xbc, 0xf4, 0x04, 0x6d, 0x41, 0xf9, 0xea, 0xb4, 0x77, 0xde, 0xe8, 0x76, 0xf5, 0x8b, 0xcb, 0xa3,
0x17, 0x67, 0x38, 0x18, 0xf9, 0xb6, 0x47, 0x5c, 0x1f, 0xbd, 0x83, 0x02, 0x97, 0xa5, 0x72, 0x15, 0x56, 0xe3, 0xa3, 0xde, 0x3c, 0xec, 0x36, 0x4b, 0x0a, 0xfa, 0x04, 0xaa, 0xe7, 0x8d, 0x6e, 0xaf,
0x99, 0xa9, 0xe3, 0x8e, 0x4c, 0xe2, 0xfa, 0x4f, 0x4a, 0xfe, 0x0e, 0xf2, 0xf4, 0x3c, 0xba, 0xa8, 0x71, 0xac, 0x2f, 0xc2, 0x53, 0xe8, 0xe7, 0xf0, 0xa2, 0xf9, 0xf1, 0x48, 0x3b, 0x3d, 0xd6, 0x1f,
0x21, 0x79, 0xd6, 0x96, 0x16, 0xb9, 0xfa, 0xee, 0x0a, 0x5d, 0x98, 0xdc, 0x02, 0x24, 0x36, 0x30, 0x61, 0x4b, 0x7f, 0xf6, 0xd7, 0x34, 0xe4, 0xa5, 0x66, 0x05, 0x95, 0x61, 0x4d, 0x6c, 0x1e, 0x2c,
0x79, 0x89, 0x93, 0xd5, 0x48, 0xf4, 0x7a, 0x5d, 0x1e, 0xeb, 0x12, 0x8b, 0x5b, 0x07, 0x14, 0x69, 0x28, 0x3d, 0x41, 0xdb, 0x50, 0xa9, 0x77, 0xce, 0xce, 0x4e, 0x7b, 0x67, 0x8d, 0xf3, 0x9e, 0xde,
0xa9, 0x89, 0x65, 0x7a, 0x75, 0x55, 0x8b, 0x65, 0x7a, 0xdd, 0x2e, 0xd4, 0x01, 0x45, 0xda, 0x5e, 0x3b, 0x3d, 0x6b, 0xe8, 0xed, 0x4e, 0xbd, 0x55, 0x52, 0xa8, 0x7a, 0x12, 0x72, 0xde, 0xd1, 0x8f,
0x62, 0xda, 0x56, 0x97, 0xa1, 0x98, 0xb6, 0x75, 0x4b, 0x8f, 0x0e, 0xa5, 0xd8, 0xfc, 0x1a, 0xab, 0x1b, 0xed, 0xc3, 0x8f, 0xa5, 0x14, 0xda, 0x80, 0x75, 0x09, 0xd0, 0x1a, 0x1f, 0x3a, 0xad, 0x46,
0x9b, 0x75, 0x13, 0x6f, 0xac, 0x6e, 0xd6, 0x8f, 0xbe, 0x7f, 0x84, 0xe7, 0x62, 0xf2, 0x43, 0x2f, 0x29, 0x4d, 0xf9, 0x9b, 0xbd, 0x76, 0x5d, 0xef, 0x9c, 0x9c, 0x34, 0xb4, 0xc6, 0x71, 0x00, 0x64,
0x25, 0xe6, 0xf8, 0x34, 0x1b, 0x8b, 0x58, 0x62, 0x50, 0x5c, 0x56, 0x9e, 0x30, 0x69, 0xef, 0x89, 0xe8, 0x16, 0x0c, 0x38, 0xac, 0xd7, 0x1b, 0x17, 0xbd, 0x08, 0x59, 0x62, 0x07, 0x91, 0x97, 0xd0,
0x49, 0x6c, 0x7d, 0xe5, 0x25, 0x8c, 0xf9, 0x0b, 0x94, 0x93, 0xe3, 0x0d, 0x92, 0x9b, 0xe7, 0x13, 0xed, 0x3b, 0x97, 0x3d, 0xbd, 0xdb, 0xa8, 0x77, 0xce, 0x8f, 0xf5, 0x76, 0xe3, 0x43, 0xa3, 0x5d,
0xe3, 0x55, 0xfd, 0xd3, 0x1f, 0xe5, 0x11, 0xca, 0x9b, 0x90, 0x5f, 0x0e, 0x1b, 0x48, 0xf6, 0x27, 0x5a, 0x46, 0xbf, 0x00, 0x35, 0x2e, 0xa0, 0x7b, 0x59, 0xaf, 0xd3, 0xf3, 0xc6, 0xf8, 0x56, 0xd0,
0x31, 0x33, 0xd5, 0x5f, 0xad, 0xc5, 0x84, 0x92, 0x1e, 0x14, 0xe5, 0xfe, 0x85, 0xe4, 0x94, 0xad, 0x2e, 0x3c, 0x4b, 0x68, 0x70, 0xd6, 0xe9, 0x35, 0x02, 0xa9, 0xa5, 0x2c, 0xda, 0x83, 0x9d, 0xa4,
0x69, 0x88, 0xf5, 0xfd, 0x27, 0x71, 0xae, 0xf0, 0xf4, 0xb7, 0x7f, 0x3e, 0xba, 0xb3, 0xc9, 0xfd, 0x26, 0x8c, 0x43, 0xc8, 0x2b, 0xe5, 0xd0, 0x0e, 0x6c, 0x33, 0x0e, 0x59, 0x72, 0xa0, 0x2f, 0xa0,
0x74, 0xd8, 0x18, 0xb9, 0x93, 0xa3, 0x31, 0xdd, 0xce, 0x1c, 0xdb, 0xb9, 0x73, 0x30, 0x99, 0xb9, 0x0a, 0x94, 0x02, 0x53, 0x87, 0x76, 0xce, 0xa3, 0x67, 0xb0, 0x95, 0xf0, 0x43, 0x08, 0x16, 0x12,
0xfe, 0xc3, 0xd1, 0xd8, 0xb1, 0x8e, 0x58, 0x93, 0x3e, 0x0a, 0xf5, 0x0c, 0x73, 0xec, 0x3f, 0x5d, 0xc6, 0x3a, 0x3c, 0xaf, 0x37, 0x3b, 0x5a, 0xa9, 0xf8, 0xfa, 0x1f, 0x79, 0xc8, 0x5d, 0xb1, 0xe0,
0x5f, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x20, 0xb6, 0x46, 0x32, 0x13, 0x00, 0x00, 0x69, 0x59, 0x04, 0xb5, 0x21, 0x2f, 0x3d, 0x05, 0xa1, 0xe7, 0x89, 0x82, 0x16, 0x7f, 0x8c, 0xaa,
0x7e, 0xf2, 0x10, 0x1c, 0x96, 0xdd, 0xbc, 0xf4, 0x36, 0x13, 0x97, 0x36, 0xf7, 0xf4, 0x12, 0x97,
0xb6, 0xe0, 0x49, 0x47, 0x83, 0x62, 0xec, 0x75, 0x05, 0xed, 0x4a, 0x0b, 0x16, 0x3d, 0xe6, 0x54,
0xf7, 0x1e, 0x66, 0x10, 0x32, 0x4f, 0x01, 0xa2, 0x24, 0x43, 0x3b, 0x89, 0xf3, 0xc4, 0x12, 0xb2,
0xfa, 0xfc, 0x01, 0x54, 0x88, 0x7a, 0x0f, 0xc5, 0x63, 0xec, 0x59, 0xf7, 0xf8, 0x1c, 0x4f, 0x09,
0x9d, 0x10, 0xd7, 0x25, 0x7e, 0x3e, 0x57, 0x56, 0x37, 0xc3, 0x21, 0xa9, 0x85, 0x67, 0xc7, 0xd8,
0xef, 0x7b, 0x96, 0x4b, 0x1c, 0x0f, 0xbd, 0x85, 0x1c, 0x5f, 0x4b, 0xd7, 0x95, 0x65, 0xa6, 0xb6,
0xd3, 0x37, 0x88, 0xe3, 0x3d, 0xb8, 0xf2, 0xb7, 0x90, 0xa5, 0xfb, 0xd1, 0xd4, 0x46, 0xc9, 0xe1,
0x33, 0x50, 0x7c, 0x6b, 0x8e, 0x2e, 0x54, 0xee, 0x40, 0x41, 0x7e, 0x2b, 0x40, 0x49, 0x7f, 0x26,
0x9e, 0x2a, 0xaa, 0xbb, 0x0f, 0xe2, 0x91, 0x8b, 0x62, 0x63, 0x76, 0xcc, 0x45, 0x8b, 0x5e, 0x13,
0x62, 0x2e, 0x5a, 0x38, 0xa1, 0xa3, 0x3f, 0xc1, 0x5a, 0x62, 0x5a, 0x46, 0x2f, 0xe6, 0x16, 0x25,
0xa7, 0xf7, 0xaa, 0xfa, 0x18, 0x8b, 0x90, 0xdc, 0x04, 0x24, 0x06, 0x66, 0x79, 0xe6, 0x96, 0xad,
0x28, 0xd1, 0xab, 0x55, 0xb9, 0x0b, 0x4f, 0xcc, 0xd9, 0x6d, 0xc8, 0x4b, 0x33, 0x68, 0x2c, 0xd0,
0xe7, 0x27, 0xeb, 0x58, 0xa0, 0x2f, 0x1a, 0x5d, 0xdb, 0x90, 0x97, 0x86, 0xcd, 0x98, 0xb4, 0xf9,
0xd9, 0x35, 0x26, 0x6d, 0xd1, 0x8c, 0xaa, 0x41, 0x31, 0x36, 0x6e, 0xc4, 0x7c, 0xb2, 0x68, 0x40,
0x89, 0xf9, 0x64, 0xf1, 0xa4, 0xf2, 0x07, 0x58, 0x11, 0x8d, 0x3a, 0x7a, 0x2a, 0x31, 0xc7, 0x87,
0x8f, 0x98, 0xc5, 0x12, 0x7d, 0x7d, 0x90, 0x78, 0x42, 0xa5, 0x9d, 0x07, 0x1a, 0xe7, 0xc5, 0x89,
0x97, 0x50, 0xe6, 0x2f, 0x50, 0x4a, 0x76, 0xa3, 0x48, 0x76, 0xff, 0x03, 0xdd, 0x70, 0xf5, 0xd3,
0x47, 0x79, 0x84, 0xf0, 0x3a, 0x64, 0x83, 0x0e, 0x10, 0xc9, 0xe7, 0x49, 0xb4, 0xb8, 0xd5, 0x67,
0x0b, 0xb1, 0x28, 0xcf, 0xe4, 0xd6, 0x21, 0x96, 0x67, 0x0b, 0xba, 0x94, 0x58, 0x9e, 0x2d, 0xea,
0x39, 0x8e, 0x7e, 0xf5, 0xe7, 0x83, 0x5b, 0x8b, 0x0c, 0xc6, 0xd7, 0xb5, 0xbe, 0x33, 0x3a, 0x18,
0xd2, 0x61, 0xda, 0xb6, 0xec, 0x5b, 0x1b, 0x93, 0x89, 0xe3, 0xdd, 0x1d, 0x0c, 0x6d, 0xf3, 0x80,
0x75, 0x4e, 0x07, 0xa1, 0x9c, 0xeb, 0x65, 0xf6, 0x5f, 0x85, 0x2f, 0xff, 0x1f, 0x00, 0x00, 0xff,
0xff, 0x0a, 0xc3, 0xd3, 0xee, 0x9e, 0x18, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -2088,6 +2591,43 @@ type WalletKitClient interface {
//NextAddr returns the next unused address within the wallet. //NextAddr returns the next unused address within the wallet.
NextAddr(ctx context.Context, in *AddrRequest, opts ...grpc.CallOption) (*AddrResponse, error) NextAddr(ctx context.Context, in *AddrRequest, opts ...grpc.CallOption) (*AddrResponse, error)
// //
//ListAccounts retrieves all accounts belonging to the wallet by default. A
//name and key scope filter can be provided to filter through all of the
//wallet accounts and return only those matching.
ListAccounts(ctx context.Context, in *ListAccountsRequest, opts ...grpc.CallOption) (*ListAccountsResponse, error)
//
//ImportAccount imports an account backed by an account extended public key.
//The master key fingerprint denotes the fingerprint of the root key
//corresponding to the account public key (also known as the key with
//derivation path m/). This may be required by some hardware wallets for
//proper identification and signing.
//
//The address type can usually be inferred from the key's version, but may be
//required for certain keys to map them into the proper scope.
//
//For BIP-0044 keys, an address type must be specified as we intend to not
//support importing BIP-0044 keys into the wallet using the legacy
//pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will force
//the standard BIP-0049 derivation scheme, while a witness address type will
//force the standard BIP-0084 derivation scheme.
//
//For BIP-0049 keys, an address type must also be specified to make a
//distinction between the standard BIP-0049 address schema (nested witness
//pubkeys everywhere) and our own BIP-0049Plus address schema (nested pubkeys
//externally, witness pubkeys internally).
//
//NOTE: Events (deposits/spends) for keys derived from an account will only be
//detected by lnd if they happen after the import. Rescans to detect past
//events will be supported later on.
ImportAccount(ctx context.Context, in *ImportAccountRequest, opts ...grpc.CallOption) (*ImportAccountResponse, error)
//
//ImportPublicKey imports a public key as watch-only into the wallet.
//
//NOTE: Events (deposits/spends) for a key will only be detected by lnd if
//they happen after the import. Rescans to detect past events will be
//supported later on.
ImportPublicKey(ctx context.Context, in *ImportPublicKeyRequest, opts ...grpc.CallOption) (*ImportPublicKeyResponse, error)
//
//PublishTransaction attempts to publish the passed transaction to the //PublishTransaction attempts to publish the passed transaction to the
//network. Once this returns without an error, the wallet will continually //network. Once this returns without an error, the wallet will continually
//attempt to re-broadcast the transaction on start up, until it enters the //attempt to re-broadcast the transaction on start up, until it enters the
@ -2257,6 +2797,33 @@ func (c *walletKitClient) NextAddr(ctx context.Context, in *AddrRequest, opts ..
return out, nil return out, nil
} }
func (c *walletKitClient) ListAccounts(ctx context.Context, in *ListAccountsRequest, opts ...grpc.CallOption) (*ListAccountsResponse, error) {
out := new(ListAccountsResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/ListAccounts", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *walletKitClient) ImportAccount(ctx context.Context, in *ImportAccountRequest, opts ...grpc.CallOption) (*ImportAccountResponse, error) {
out := new(ImportAccountResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/ImportAccount", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *walletKitClient) ImportPublicKey(ctx context.Context, in *ImportPublicKeyRequest, opts ...grpc.CallOption) (*ImportPublicKeyResponse, error) {
out := new(ImportPublicKeyResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/ImportPublicKey", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *walletKitClient) PublishTransaction(ctx context.Context, in *Transaction, opts ...grpc.CallOption) (*PublishResponse, error) { func (c *walletKitClient) PublishTransaction(ctx context.Context, in *Transaction, opts ...grpc.CallOption) (*PublishResponse, error) {
out := new(PublishResponse) out := new(PublishResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/PublishTransaction", in, out, opts...) err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/PublishTransaction", in, out, opts...)
@ -2372,6 +2939,43 @@ type WalletKitServer interface {
//NextAddr returns the next unused address within the wallet. //NextAddr returns the next unused address within the wallet.
NextAddr(context.Context, *AddrRequest) (*AddrResponse, error) NextAddr(context.Context, *AddrRequest) (*AddrResponse, error)
// //
//ListAccounts retrieves all accounts belonging to the wallet by default. A
//name and key scope filter can be provided to filter through all of the
//wallet accounts and return only those matching.
ListAccounts(context.Context, *ListAccountsRequest) (*ListAccountsResponse, error)
//
//ImportAccount imports an account backed by an account extended public key.
//The master key fingerprint denotes the fingerprint of the root key
//corresponding to the account public key (also known as the key with
//derivation path m/). This may be required by some hardware wallets for
//proper identification and signing.
//
//The address type can usually be inferred from the key's version, but may be
//required for certain keys to map them into the proper scope.
//
//For BIP-0044 keys, an address type must be specified as we intend to not
//support importing BIP-0044 keys into the wallet using the legacy
//pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will force
//the standard BIP-0049 derivation scheme, while a witness address type will
//force the standard BIP-0084 derivation scheme.
//
//For BIP-0049 keys, an address type must also be specified to make a
//distinction between the standard BIP-0049 address schema (nested witness
//pubkeys everywhere) and our own BIP-0049Plus address schema (nested pubkeys
//externally, witness pubkeys internally).
//
//NOTE: Events (deposits/spends) for keys derived from an account will only be
//detected by lnd if they happen after the import. Rescans to detect past
//events will be supported later on.
ImportAccount(context.Context, *ImportAccountRequest) (*ImportAccountResponse, error)
//
//ImportPublicKey imports a public key as watch-only into the wallet.
//
//NOTE: Events (deposits/spends) for a key will only be detected by lnd if
//they happen after the import. Rescans to detect past events will be
//supported later on.
ImportPublicKey(context.Context, *ImportPublicKeyRequest) (*ImportPublicKeyResponse, error)
//
//PublishTransaction attempts to publish the passed transaction to the //PublishTransaction attempts to publish the passed transaction to the
//network. Once this returns without an error, the wallet will continually //network. Once this returns without an error, the wallet will continually
//attempt to re-broadcast the transaction on start up, until it enters the //attempt to re-broadcast the transaction on start up, until it enters the
@ -2495,6 +3099,15 @@ func (*UnimplementedWalletKitServer) DeriveKey(ctx context.Context, req *signrpc
func (*UnimplementedWalletKitServer) NextAddr(ctx context.Context, req *AddrRequest) (*AddrResponse, error) { func (*UnimplementedWalletKitServer) NextAddr(ctx context.Context, req *AddrRequest) (*AddrResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NextAddr not implemented") return nil, status.Errorf(codes.Unimplemented, "method NextAddr not implemented")
} }
func (*UnimplementedWalletKitServer) ListAccounts(ctx context.Context, req *ListAccountsRequest) (*ListAccountsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListAccounts not implemented")
}
func (*UnimplementedWalletKitServer) ImportAccount(ctx context.Context, req *ImportAccountRequest) (*ImportAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportAccount not implemented")
}
func (*UnimplementedWalletKitServer) ImportPublicKey(ctx context.Context, req *ImportPublicKeyRequest) (*ImportPublicKeyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportPublicKey not implemented")
}
func (*UnimplementedWalletKitServer) PublishTransaction(ctx context.Context, req *Transaction) (*PublishResponse, error) { func (*UnimplementedWalletKitServer) PublishTransaction(ctx context.Context, req *Transaction) (*PublishResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method PublishTransaction not implemented") return nil, status.Errorf(codes.Unimplemented, "method PublishTransaction not implemented")
} }
@ -2653,6 +3266,60 @@ func _WalletKit_NextAddr_Handler(srv interface{}, ctx context.Context, dec func(
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _WalletKit_ListAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListAccountsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WalletKitServer).ListAccounts(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/walletrpc.WalletKit/ListAccounts",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WalletKitServer).ListAccounts(ctx, req.(*ListAccountsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WalletKit_ImportAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ImportAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WalletKitServer).ImportAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/walletrpc.WalletKit/ImportAccount",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WalletKitServer).ImportAccount(ctx, req.(*ImportAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WalletKit_ImportPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ImportPublicKeyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WalletKitServer).ImportPublicKey(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/walletrpc.WalletKit/ImportPublicKey",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WalletKitServer).ImportPublicKey(ctx, req.(*ImportPublicKeyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WalletKit_PublishTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _WalletKit_PublishTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Transaction) in := new(Transaction)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -2847,6 +3514,18 @@ var _WalletKit_serviceDesc = grpc.ServiceDesc{
MethodName: "NextAddr", MethodName: "NextAddr",
Handler: _WalletKit_NextAddr_Handler, Handler: _WalletKit_NextAddr_Handler,
}, },
{
MethodName: "ListAccounts",
Handler: _WalletKit_ListAccounts_Handler,
},
{
MethodName: "ImportAccount",
Handler: _WalletKit_ImportAccount_Handler,
},
{
MethodName: "ImportPublicKey",
Handler: _WalletKit_ImportPublicKey_Handler,
},
{ {
MethodName: "PublishTransaction", MethodName: "PublishTransaction",
Handler: _WalletKit_PublishTransaction_Handler, Handler: _WalletKit_PublishTransaction_Handler,

@ -253,6 +253,107 @@ func local_request_WalletKit_NextAddr_0(ctx context.Context, marshaler runtime.M
} }
var (
filter_WalletKit_ListAccounts_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WalletKit_ListAccounts_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAccountsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WalletKit_ListAccounts_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListAccounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WalletKit_ListAccounts_0(ctx context.Context, marshaler runtime.Marshaler, server WalletKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAccountsRequest
var metadata runtime.ServerMetadata
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_WalletKit_ListAccounts_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListAccounts(ctx, &protoReq)
return msg, metadata, err
}
func request_WalletKit_ImportAccount_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ImportAccountRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ImportAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WalletKit_ImportAccount_0(ctx context.Context, marshaler runtime.Marshaler, server WalletKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ImportAccountRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ImportAccount(ctx, &protoReq)
return msg, metadata, err
}
func request_WalletKit_ImportPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ImportPublicKeyRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ImportPublicKey(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WalletKit_ImportPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, server WalletKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ImportPublicKeyRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ImportPublicKey(ctx, &protoReq)
return msg, metadata, err
}
func request_WalletKit_PublishTransaction_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { func request_WalletKit_PublishTransaction_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq Transaction var protoReq Transaction
var metadata runtime.ServerMetadata var metadata runtime.ServerMetadata
@ -707,6 +808,66 @@ func RegisterWalletKitHandlerServer(ctx context.Context, mux *runtime.ServeMux,
}) })
mux.Handle("GET", pattern_WalletKit_ListAccounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WalletKit_ListAccounts_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_ListAccounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_ImportAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WalletKit_ImportAccount_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_ImportAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_ImportPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WalletKit_ImportPublicKey_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_ImportPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_PublishTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle("POST", pattern_WalletKit_PublishTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
@ -1068,6 +1229,66 @@ func RegisterWalletKitHandlerClient(ctx context.Context, mux *runtime.ServeMux,
}) })
mux.Handle("GET", pattern_WalletKit_ListAccounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WalletKit_ListAccounts_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_ListAccounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_ImportAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WalletKit_ImportAccount_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_ImportAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_ImportPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WalletKit_ImportPublicKey_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_ImportPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_PublishTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle("POST", pattern_WalletKit_PublishTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
@ -1266,6 +1487,12 @@ var (
pattern_WalletKit_NextAddr_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v2", "wallet", "address", "next"}, "", runtime.AssumeColonVerbOpt(true))) pattern_WalletKit_NextAddr_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v2", "wallet", "address", "next"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_WalletKit_ListAccounts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "accounts"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_WalletKit_ImportAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v2", "wallet", "accounts", "import"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_WalletKit_ImportPublicKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v2", "wallet", "key", "import"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_WalletKit_PublishTransaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "tx"}, "", runtime.AssumeColonVerbOpt(true))) pattern_WalletKit_PublishTransaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "tx"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_WalletKit_SendOutputs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "send"}, "", runtime.AssumeColonVerbOpt(true))) pattern_WalletKit_SendOutputs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "send"}, "", runtime.AssumeColonVerbOpt(true)))
@ -1300,6 +1527,12 @@ var (
forward_WalletKit_NextAddr_0 = runtime.ForwardResponseMessage forward_WalletKit_NextAddr_0 = runtime.ForwardResponseMessage
forward_WalletKit_ListAccounts_0 = runtime.ForwardResponseMessage
forward_WalletKit_ImportAccount_0 = runtime.ForwardResponseMessage
forward_WalletKit_ImportPublicKey_0 = runtime.ForwardResponseMessage
forward_WalletKit_PublishTransaction_0 = runtime.ForwardResponseMessage forward_WalletKit_PublishTransaction_0 = runtime.ForwardResponseMessage
forward_WalletKit_SendOutputs_0 = runtime.ForwardResponseMessage forward_WalletKit_SendOutputs_0 = runtime.ForwardResponseMessage

@ -55,6 +55,50 @@ service WalletKit {
*/ */
rpc NextAddr (AddrRequest) returns (AddrResponse); rpc NextAddr (AddrRequest) returns (AddrResponse);
/*
ListAccounts retrieves all accounts belonging to the wallet by default. A
name and key scope filter can be provided to filter through all of the
wallet accounts and return only those matching.
*/
rpc ListAccounts (ListAccountsRequest) returns (ListAccountsResponse);
/*
ImportAccount imports an account backed by an account extended public key.
The master key fingerprint denotes the fingerprint of the root key
corresponding to the account public key (also known as the key with
derivation path m/). This may be required by some hardware wallets for
proper identification and signing.
The address type can usually be inferred from the key's version, but may be
required for certain keys to map them into the proper scope.
For BIP-0044 keys, an address type must be specified as we intend to not
support importing BIP-0044 keys into the wallet using the legacy
pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will force
the standard BIP-0049 derivation scheme, while a witness address type will
force the standard BIP-0084 derivation scheme.
For BIP-0049 keys, an address type must also be specified to make a
distinction between the standard BIP-0049 address schema (nested witness
pubkeys everywhere) and our own BIP-0049Plus address schema (nested pubkeys
externally, witness pubkeys internally).
NOTE: Events (deposits/spends) for keys derived from an account will only be
detected by lnd if they happen after the import. Rescans to detect past
events will be supported later on.
*/
rpc ImportAccount (ImportAccountRequest) returns (ImportAccountResponse);
/*
ImportPublicKey imports a public key as watch-only into the wallet.
NOTE: Events (deposits/spends) for a key will only be detected by lnd if
they happen after the import. Rescans to detect past events will be
supported later on.
*/
rpc ImportPublicKey (ImportPublicKeyRequest)
returns (ImportPublicKeyResponse);
/* /*
PublishTransaction attempts to publish the passed transaction to the PublishTransaction attempts to publish the passed transaction to the
network. Once this returns without an error, the wallet will continually network. Once this returns without an error, the wallet will continually
@ -178,6 +222,9 @@ message ListUnspentRequest {
// The maximum number of confirmations to be included. // The maximum number of confirmations to be included.
int32 max_confs = 2; int32 max_confs = 2;
// An optional filter to only include outputs belonging to an account.
string account = 3;
} }
message ListUnspentResponse { message ListUnspentResponse {
@ -234,7 +281,11 @@ message KeyReq {
} }
message AddrRequest { message AddrRequest {
// No fields, as we always give out a p2wkh address. /*
The name of the account to retrieve the next address of. If empty, the
default wallet account is used.
*/
string account = 1;
} }
message AddrResponse { message AddrResponse {
/* /*
@ -243,6 +294,113 @@ message AddrResponse {
string addr = 1; string addr = 1;
} }
enum AddressType {
UNKNOWN = 0;
WITNESS_PUBKEY_HASH = 1;
NESTED_WITNESS_PUBKEY_HASH = 2;
HYBRID_NESTED_WITNESS_PUBKEY_HASH = 3;
}
message Account {
// The name used to identify the account.
string name = 1;
/*
The type of addresses the account supports.
AddressType | External Branch | Internal Branch
---------------------------------------------------------------------
WITNESS_PUBKEY_HASH | P2WPKH | P2WPKH
NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | NP2WPKH
HYBRID_NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | P2WPKH
*/
AddressType address_type = 2;
/*
The public key backing the account that all keys are derived from
represented as an extended key. This will always be empty for the default
imported account in which single public keys are imported into.
*/
string extended_public_key = 3;
/*
The fingerprint of the root key from which the account public key was
derived from. This will always be zero for the default imported account in
which single public keys are imported into.
*/
uint32 master_key_fingerprint = 4;
/*
The derivation path corresponding to the account public key. This will
always be empty for the default imported account in which single public keys
are imported into.
*/
string derivation_path = 5;
/*
The number of keys derived from the external branch of the account public
key. This will always be zero for the default imported account in which
single public keys are imported into.
*/
uint32 external_key_count = 6;
/*
The number of keys derived from the internal branch of the account public
key. This will always be zero for the default imported account in which
single public keys are imported into.
*/
uint32 internal_key_count = 7;
// Whether the wallet stores private keys for the account.
bool watch_only = 8;
}
message ListAccountsRequest {
// An optional filter to only return accounts matching this name.
string name = 1;
// An optional filter to only return accounts matching this address type.
AddressType address_type = 2;
}
message ListAccountsResponse {
repeated Account accounts = 1;
}
message ImportAccountRequest {
// A name to identify the account with.
string name = 1;
/*
A public key that corresponds to a wallet account represented as an extended
key. It must conform to a derivation path of the form
m/purpose'/coin_type'/account'.
*/
string extended_public_key = 2;
/*
The fingerprint of the root key (also known as the key with derivation path
m/) from which the account public key was derived from. This may be required
by some hardware wallets for proper identification and signing.
*/
uint32 master_key_fingerprint = 3;
/*
An address type is only required when the extended account public key has a
legacy version (xpub, tpub, etc.), such that the wallet cannot detect what
address scheme it belongs to.
*/
AddressType address_type = 4;
}
message ImportAccountResponse {
}
message ImportPublicKeyRequest {
// A compressed public key represented as raw bytes.
bytes public_key = 1;
// The type of address that will be generated from the public key.
AddressType address_type = 2;
}
message ImportPublicKeyResponse {
}
message Transaction { message Transaction {
/* /*
The raw serialized transaction. The raw serialized transaction.
@ -560,6 +718,12 @@ message FundPsbtRequest {
*/ */
uint64 sat_per_vbyte = 4; uint64 sat_per_vbyte = 4;
} }
/*
The name of the account to fund the PSBT with. If empty, the default wallet
account is used.
*/
string account = 5;
} }
message FundPsbtResponse { message FundPsbtResponse {
/* /*
@ -619,6 +783,12 @@ message FinalizePsbtRequest {
signers. signers.
*/ */
bytes funded_psbt = 1; bytes funded_psbt = 1;
/*
The name of the account to finalize the PSBT with. If empty, the default
wallet account is used.
*/
string account = 5;
} }
message FinalizePsbtResponse { message FinalizePsbtResponse {
// The fully signed and finalized transaction in PSBT format. // The fully signed and finalized transaction in PSBT format.

@ -11,6 +11,86 @@
"application/json" "application/json"
], ],
"paths": { "paths": {
"/v2/wallet/accounts": {
"get": {
"summary": "ListAccounts retrieves all accounts belonging to the wallet by default. A\nname and key scope filter can be provided to filter through all of the\nwallet accounts and return only those matching.",
"operationId": "ListAccounts",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/walletrpcListAccountsResponse"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "name",
"description": "An optional filter to only return accounts matching this name.",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "address_type",
"description": "An optional filter to only return accounts matching this address type.",
"in": "query",
"required": false,
"type": "string",
"enum": [
"UNKNOWN",
"WITNESS_PUBKEY_HASH",
"NESTED_WITNESS_PUBKEY_HASH",
"HYBRID_NESTED_WITNESS_PUBKEY_HASH"
],
"default": "UNKNOWN"
}
],
"tags": [
"WalletKit"
]
}
},
"/v2/wallet/accounts/import": {
"post": {
"summary": "ImportAccount imports an account backed by an account extended public key.\nThe master key fingerprint denotes the fingerprint of the root key\ncorresponding to the account public key (also known as the key with\nderivation path m/). This may be required by some hardware wallets for\nproper identification and signing.",
"description": "The address type can usually be inferred from the key's version, but may be\nrequired for certain keys to map them into the proper scope.\n\nFor BIP-0044 keys, an address type must be specified as we intend to not\nsupport importing BIP-0044 keys into the wallet using the legacy\npay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will force\nthe standard BIP-0049 derivation scheme, while a witness address type will\nforce the standard BIP-0084 derivation scheme.\n\nFor BIP-0049 keys, an address type must also be specified to make a\ndistinction between the standard BIP-0049 address schema (nested witness\npubkeys everywhere) and our own BIP-0049Plus address schema (nested pubkeys\nexternally, witness pubkeys internally).\n\nNOTE: Events (deposits/spends) for keys derived from an account will only be\ndetected by lnd if they happen after the import. Rescans to detect past\nevents will be supported later on.",
"operationId": "ImportAccount",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/walletrpcImportAccountResponse"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/walletrpcImportAccountRequest"
}
}
],
"tags": [
"WalletKit"
]
}
},
"/v2/wallet/address/next": { "/v2/wallet/address/next": {
"post": { "post": {
"summary": "NextAddr returns the next unused address within the wallet.", "summary": "NextAddr returns the next unused address within the wallet.",
@ -144,6 +224,40 @@
] ]
} }
}, },
"/v2/wallet/key/import": {
"post": {
"summary": "ImportPublicKey imports a public key as watch-only into the wallet.",
"description": "NOTE: Events (deposits/spends) for a key will only be detected by lnd if\nthey happen after the import. Rescans to detect past events will be\nsupported later on.",
"operationId": "ImportPublicKey",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/walletrpcImportPublicKeyResponse"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/walletrpcImportPublicKeyRequest"
}
}
],
"tags": [
"WalletKit"
]
}
},
"/v2/wallet/key/next": { "/v2/wallet/key/next": {
"post": { "post": {
"summary": "DeriveNextKey attempts to derive the *next* key within the key family\n(account in BIP43) specified. This method should return the next external\nchild within this branch.", "summary": "DeriveNextKey attempts to derive the *next* key within the key family\n(account in BIP43) specified. This method should return the next external\nchild within this branch.",
@ -731,8 +845,55 @@
} }
} }
}, },
"walletrpcAccount": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name used to identify the account."
},
"address_type": {
"$ref": "#/definitions/walletrpcAddressType",
"title": "The type of addresses the account supports.\nAddressType | External Branch | Internal Branch\n---------------------------------------------------------------------\nWITNESS_PUBKEY_HASH | P2WPKH | P2WPKH\nNESTED_WITNESS_PUBKEY_HASH | NP2WPKH | NP2WPKH\nHYBRID_NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | P2WPKH"
},
"extended_public_key": {
"type": "string",
"description": "The public key backing the account that all keys are derived from\nrepresented as an extended key. This will always be empty for the default\nimported account in which single public keys are imported into."
},
"master_key_fingerprint": {
"type": "integer",
"format": "int64",
"description": "The fingerprint of the root key from which the account public key was\nderived from. This will always be zero for the default imported account in\nwhich single public keys are imported into."
},
"derivation_path": {
"type": "string",
"description": "The derivation path corresponding to the account public key. This will\nalways be empty for the default imported account in which single public keys\nare imported into."
},
"external_key_count": {
"type": "integer",
"format": "int64",
"description": "The number of keys derived from the external branch of the account public\nkey. This will always be zero for the default imported account in which\nsingle public keys are imported into."
},
"internal_key_count": {
"type": "integer",
"format": "int64",
"description": "The number of keys derived from the internal branch of the account public\nkey. This will always be zero for the default imported account in which\nsingle public keys are imported into."
},
"watch_only": {
"type": "boolean",
"format": "boolean",
"description": "Whether the wallet stores private keys for the account."
}
}
},
"walletrpcAddrRequest": { "walletrpcAddrRequest": {
"type": "object" "type": "object",
"properties": {
"account": {
"type": "string",
"description": "The name of the account to retrieve the next address of. If empty, the\ndefault wallet account is used."
}
}
}, },
"walletrpcAddrResponse": { "walletrpcAddrResponse": {
"type": "object", "type": "object",
@ -743,6 +904,16 @@
} }
} }
}, },
"walletrpcAddressType": {
"type": "string",
"enum": [
"UNKNOWN",
"WITNESS_PUBKEY_HASH",
"NESTED_WITNESS_PUBKEY_HASH",
"HYBRID_NESTED_WITNESS_PUBKEY_HASH"
],
"default": "UNKNOWN"
},
"walletrpcBumpFeeRequest": { "walletrpcBumpFeeRequest": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -792,6 +963,10 @@
"type": "string", "type": "string",
"format": "byte", "format": "byte",
"description": "A PSBT that should be signed and finalized. The PSBT must contain all\nrequired inputs, outputs, UTXO data and partial signatures of all other\nsigners." "description": "A PSBT that should be signed and finalized. The PSBT must contain all\nrequired inputs, outputs, UTXO data and partial signatures of all other\nsigners."
},
"account": {
"type": "string",
"description": "The name of the account to finalize the PSBT with. If empty, the default\nwallet account is used."
} }
} }
}, },
@ -831,6 +1006,10 @@
"type": "string", "type": "string",
"format": "uint64", "format": "uint64",
"description": "The fee rate, expressed in sat/vbyte, that should be used to spend the\ninput with." "description": "The fee rate, expressed in sat/vbyte, that should be used to spend the\ninput with."
},
"account": {
"type": "string",
"description": "The name of the account to fund the PSBT with. If empty, the default wallet\naccount is used."
} }
} }
}, },
@ -856,6 +1035,48 @@
} }
} }
}, },
"walletrpcImportAccountRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A name to identify the account with."
},
"extended_public_key": {
"type": "string",
"description": "A public key that corresponds to a wallet account represented as an extended\nkey. It must conform to a derivation path of the form\nm/purpose'/coin_type'/account'."
},
"master_key_fingerprint": {
"type": "integer",
"format": "int64",
"description": "The fingerprint of the root key (also known as the key with derivation path\nm/) from which the account public key was derived from. This may be required\nby some hardware wallets for proper identification and signing."
},
"address_type": {
"$ref": "#/definitions/walletrpcAddressType",
"description": "An address type is only required when the extended account public key has a\nlegacy version (xpub, tpub, etc.), such that the wallet cannot detect what\naddress scheme it belongs to."
}
}
},
"walletrpcImportAccountResponse": {
"type": "object"
},
"walletrpcImportPublicKeyRequest": {
"type": "object",
"properties": {
"public_key": {
"type": "string",
"format": "byte",
"description": "A compressed public key represented as raw bytes."
},
"address_type": {
"$ref": "#/definitions/walletrpcAddressType",
"description": "The type of address that will be generated from the public key."
}
}
},
"walletrpcImportPublicKeyResponse": {
"type": "object"
},
"walletrpcKeyReq": { "walletrpcKeyReq": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -922,6 +1143,17 @@
} }
} }
}, },
"walletrpcListAccountsResponse": {
"type": "object",
"properties": {
"accounts": {
"type": "array",
"items": {
"$ref": "#/definitions/walletrpcAccount"
}
}
}
},
"walletrpcListLeasesResponse": { "walletrpcListLeasesResponse": {
"type": "object", "type": "object",
"properties": { "properties": {

@ -12,11 +12,14 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcutil/psbt" "github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wtxmgr" "github.com/btcsuite/btcwallet/wtxmgr"
"github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
@ -128,6 +131,18 @@ var (
Entity: "onchain", Entity: "onchain",
Action: "write", Action: "write",
}}, }},
"/walletrpc.WalletKit/ListAccounts": {{
Entity: "onchain",
Action: "read",
}},
"/walletrpc.WalletKit/ImportAccount": {{
Entity: "onchain",
Action: "write",
}},
"/walletrpc.WalletKit/ImportPublicKey": {{
Entity: "onchain",
Action: "write",
}},
} }
// DefaultWalletKitMacFilename is the default name of the wallet kit // DefaultWalletKitMacFilename is the default name of the wallet kit
@ -321,7 +336,9 @@ func (w *WalletKit) ListUnspent(ctx context.Context,
// be shown available to us. // be shown available to us.
var utxos []*lnwallet.Utxo var utxos []*lnwallet.Utxo
err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error { err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error {
utxos, err = w.cfg.Wallet.ListUnspentWitness(minConfs, maxConfs) utxos, err = w.cfg.Wallet.ListUnspentWitness(
minConfs, maxConfs, req.Account,
)
return err return err
}) })
if err != nil { if err != nil {
@ -487,7 +504,14 @@ func (w *WalletKit) DeriveKey(ctx context.Context,
func (w *WalletKit) NextAddr(ctx context.Context, func (w *WalletKit) NextAddr(ctx context.Context,
req *AddrRequest) (*AddrResponse, error) { req *AddrRequest) (*AddrResponse, error) {
addr, err := w.cfg.Wallet.NewAddress(lnwallet.WitnessPubKey, false) account := lnwallet.DefaultAccountName
if req.Account != "" {
account = req.Account
}
addr, err := w.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, account,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -852,9 +876,10 @@ func (w *WalletKit) ListSweeps(ctx context.Context,
// Some of our sweeps could have been replaced by fee, or dropped out // Some of our sweeps could have been replaced by fee, or dropped out
// of the mempool. Here, we lookup our wallet transactions so that we // of the mempool. Here, we lookup our wallet transactions so that we
// can match our list of sweeps against the list of transactions that // can match our list of sweeps against the list of transactions that
// the wallet is still tracking. // the wallet is still tracking. Sweeps are currently always swept to
// the default wallet account.
transactions, err := w.cfg.Wallet.ListTransactionDetails( transactions, err := w.cfg.Wallet.ListTransactionDetails(
0, btcwallet.UnconfirmedHeight, 0, btcwallet.UnconfirmedHeight, lnwallet.DefaultAccountName,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -1050,12 +1075,19 @@ func (w *WalletKit) FundPsbt(_ context.Context,
// UTXOs. // UTXOs.
changeIndex := int32(-1) changeIndex := int32(-1)
err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error { err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error {
// We'll assume the PSBT will be funded by the default account
// unless otherwise specified.
account := lnwallet.DefaultAccountName
if req.Account != "" {
account = req.Account
}
// In case the user did specify inputs, we need to make sure // In case the user did specify inputs, we need to make sure
// they are known to us, still unspent and not yet locked. // they are known to us, still unspent and not yet locked.
if len(packet.UnsignedTx.TxIn) > 0 { if len(packet.UnsignedTx.TxIn) > 0 {
// Get a list of all unspent witness outputs. // Get a list of all unspent witness outputs.
utxos, err := w.cfg.Wallet.ListUnspentWitness( utxos, err := w.cfg.Wallet.ListUnspentWitness(
defaultMinConf, defaultMaxConf, defaultMinConf, defaultMaxConf, account,
) )
if err != nil { if err != nil {
return err return err
@ -1073,7 +1105,9 @@ func (w *WalletKit) FundPsbt(_ context.Context,
// We can now ask the wallet to fund the TX. This will not yet // We can now ask the wallet to fund the TX. This will not yet
// lock any coins but might still change the wallet DB by // lock any coins but might still change the wallet DB by
// generating a new change address. // generating a new change address.
changeIndex, err = w.cfg.Wallet.FundPsbt(packet, feeSatPerKW) changeIndex, err = w.cfg.Wallet.FundPsbt(
packet, feeSatPerKW, account,
)
if err != nil { if err != nil {
return fmt.Errorf("wallet couldn't fund PSBT: %v", err) return fmt.Errorf("wallet couldn't fund PSBT: %v", err)
} }
@ -1148,6 +1182,13 @@ func marshallLeases(locks []*wtxmgr.LockedOutput) []*UtxoLease {
func (w *WalletKit) FinalizePsbt(_ context.Context, func (w *WalletKit) FinalizePsbt(_ context.Context,
req *FinalizePsbtRequest) (*FinalizePsbtResponse, error) { req *FinalizePsbtRequest) (*FinalizePsbtResponse, error) {
// We'll assume the PSBT was funded by the default account unless
// otherwise specified.
account := lnwallet.DefaultAccountName
if req.Account != "" {
account = req.Account
}
// Parse the funded PSBT. No additional checks are required at this // Parse the funded PSBT. No additional checks are required at this
// level as the wallet will perform all of them. // level as the wallet will perform all of them.
packet, err := psbt.NewFromRawBytes( packet, err := psbt.NewFromRawBytes(
@ -1160,7 +1201,7 @@ func (w *WalletKit) FinalizePsbt(_ context.Context,
// Let the wallet do the heavy lifting. This will sign all inputs that // Let the wallet do the heavy lifting. This will sign all inputs that
// we have the UTXO for. If some inputs can't be signed and don't have // we have the UTXO for. If some inputs can't be signed and don't have
// witness data attached, this will fail. // witness data attached, this will fail.
err = w.cfg.Wallet.FinalizePsbt(packet) err = w.cfg.Wallet.FinalizePsbt(packet, account)
if err != nil { if err != nil {
return nil, fmt.Errorf("error finalizing PSBT: %v", err) return nil, fmt.Errorf("error finalizing PSBT: %v", err)
} }
@ -1189,3 +1230,198 @@ func (w *WalletKit) FinalizePsbt(_ context.Context,
RawFinalTx: finalTxBytes.Bytes(), RawFinalTx: finalTxBytes.Bytes(),
}, nil }, nil
} }
// marshalWalletAccount converts the properties of an account into its RPC
// representation.
func marshalWalletAccount(account *waddrmgr.AccountProperties) (*Account, error) {
var addrType AddressType
switch account.KeyScope {
case waddrmgr.KeyScopeBIP0049Plus:
// No address schema present represents the traditional BIP-0049
// address derivation scheme.
if account.AddrSchema == nil {
addrType = AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH
break
}
switch account.AddrSchema {
case &waddrmgr.KeyScopeBIP0049AddrSchema:
addrType = AddressType_NESTED_WITNESS_PUBKEY_HASH
default:
return nil, fmt.Errorf("unsupported address schema %v",
*account.AddrSchema)
}
case waddrmgr.KeyScopeBIP0084:
addrType = AddressType_WITNESS_PUBKEY_HASH
default:
return nil, fmt.Errorf("account %v has unsupported "+
"key scope %v", account.AccountName, account.KeyScope)
}
rpcAccount := &Account{
Name: account.AccountName,
AddressType: addrType,
ExternalKeyCount: account.ExternalKeyCount,
InternalKeyCount: account.InternalKeyCount,
WatchOnly: account.IsWatchOnly,
}
// The remaining fields can only be done on accounts other than the
// default imported one existing within each key scope.
if account.AccountName != waddrmgr.ImportedAddrAccountName {
nonHardenedIndex := account.AccountPubKey.ChildIndex() -
hdkeychain.HardenedKeyStart
rpcAccount.ExtendedPublicKey = account.AccountPubKey.String()
rpcAccount.MasterKeyFingerprint = account.MasterKeyFingerprint
rpcAccount.DerivationPath = fmt.Sprintf("%v/%v'",
account.KeyScope, nonHardenedIndex)
}
return rpcAccount, nil
}
// ListAccounts retrieves all accounts belonging to the wallet by default. A
// name and key scope filter can be provided to filter through all of the wallet
// accounts and return only those matching.
func (w *WalletKit) ListAccounts(ctx context.Context,
req *ListAccountsRequest) (*ListAccountsResponse, error) {
// Map the supported address types into their corresponding key scope.
var keyScopeFilter *waddrmgr.KeyScope
switch req.AddressType {
case AddressType_UNKNOWN:
break
case AddressType_WITNESS_PUBKEY_HASH:
keyScope := waddrmgr.KeyScopeBIP0084
keyScopeFilter = &keyScope
case AddressType_NESTED_WITNESS_PUBKEY_HASH,
AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
keyScope := waddrmgr.KeyScopeBIP0049Plus
keyScopeFilter = &keyScope
default:
return nil, fmt.Errorf("unhandled address type %v", req.AddressType)
}
accounts, err := w.cfg.Wallet.ListAccounts(req.Name, keyScopeFilter)
if err != nil {
return nil, err
}
rpcAccounts := make([]*Account, 0, len(accounts))
for _, account := range accounts {
// Don't include the default imported accounts created by the
// wallet in the response if they don't have any keys imported.
if account.AccountName == waddrmgr.ImportedAddrAccountName &&
account.ImportedKeyCount == 0 {
continue
}
rpcAccount, err := marshalWalletAccount(account)
if err != nil {
return nil, err
}
rpcAccounts = append(rpcAccounts, rpcAccount)
}
return &ListAccountsResponse{Accounts: rpcAccounts}, nil
}
// parseAddrType parses an address type from its RPC representation to a
// *waddrmgr.AddressType.
func parseAddrType(addrType AddressType,
required bool) (*waddrmgr.AddressType, error) {
switch addrType {
case AddressType_UNKNOWN:
if required {
return nil, errors.New("an address type must be specified")
}
return nil, nil
case AddressType_WITNESS_PUBKEY_HASH:
addrTyp := waddrmgr.WitnessPubKey
return &addrTyp, nil
case AddressType_NESTED_WITNESS_PUBKEY_HASH:
addrTyp := waddrmgr.NestedWitnessPubKey
return &addrTyp, nil
case AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
addrTyp := waddrmgr.WitnessPubKey
return &addrTyp, nil
default:
return nil, fmt.Errorf("unhandled address type %v", addrType)
}
}
// ImportAccount imports an account backed by an account extended public key.
// The master key fingerprint denotes the fingerprint of the root key
// corresponding to the account public key (also known as the key with
// derivation path m/). This may be required by some hardware wallets for proper
// identification and signing.
//
// The address type can usually be inferred from the key's version, but may be
// required for certain keys to map them into the proper scope.
//
// For BIP-0044 keys, an address type must be specified as we intend to not
// support importing BIP-0044 keys into the wallet using the legacy
// pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will force
// the standard BIP-0049 derivation scheme, while a witness address type will
// force the standard BIP-0084 derivation scheme.
//
// For BIP-0049 keys, an address type must also be specified to make a
// distinction between the standard BIP-0049 address schema (nested witness
// pubkeys everywhere) and our own BIP-0049Plus address schema (nested pubkeys
// externally, witness pubkeys internally).
func (w *WalletKit) ImportAccount(ctx context.Context,
req *ImportAccountRequest) (*ImportAccountResponse, error) {
accountPubKey, err := hdkeychain.NewKeyFromString(req.ExtendedPublicKey)
if err != nil {
return nil, err
}
addrType, err := parseAddrType(req.AddressType, false)
if err != nil {
return nil, err
}
err = w.cfg.Wallet.ImportAccount(
req.Name, accountPubKey, req.MasterKeyFingerprint, addrType,
)
if err != nil {
return nil, err
}
return &ImportAccountResponse{}, nil
}
// ImportPublicKey imports a single derived public key into the wallet. The
// address type can usually be inferred from the key's version, but in the case
// of legacy versions (xpub, tpub), an address type must be specified as we
// intend to not support importing BIP-44 keys into the wallet using the legacy
// pay-to-pubkey-hash (P2PKH) scheme.
func (w *WalletKit) ImportPublicKey(ctx context.Context,
req *ImportPublicKeyRequest) (*ImportPublicKeyResponse, error) {
pubKey, err := btcec.ParsePubKey(req.PublicKey, btcec.S256())
if err != nil {
return nil, err
}
addrType, err := parseAddrType(req.AddressType, true)
if err != nil {
return nil, err
}
if err := w.cfg.Wallet.ImportPublicKey(pubKey, *addrType); err != nil {
return nil, err
}
return &ImportPublicKeyResponse{}, nil
}

@ -56,12 +56,12 @@ func (b BtcdBackendConfig) GenArgs() []string {
// ConnectMiner is called to establish a connection to the test miner. // ConnectMiner is called to establish a connection to the test miner.
func (b BtcdBackendConfig) ConnectMiner() error { func (b BtcdBackendConfig) ConnectMiner() error {
return b.harness.Node.Node(btcjson.NConnect, b.minerAddr, &temp) return b.harness.Client.Node(btcjson.NConnect, b.minerAddr, &temp)
} }
// DisconnectMiner is called to disconnect the miner. // DisconnectMiner is called to disconnect the miner.
func (b BtcdBackendConfig) DisconnectMiner() error { func (b BtcdBackendConfig) DisconnectMiner() error {
return b.harness.Node.Node(btcjson.NDisconnect, b.minerAddr, &temp) return b.harness.Client.Node(btcjson.NDisconnect, b.minerAddr, &temp)
} }
// Name returns the name of the backend type. // Name returns the name of the backend type.

@ -211,7 +211,7 @@ func (n *NetworkHarness) SetUp(testCase string, lndArgs []string) error {
// We generate several blocks in order to give the outputs created // We generate several blocks in order to give the outputs created
// above a good number of confirmations. // above a good number of confirmations.
if _, err := n.Miner.Node.Generate(10); err != nil { if _, err := n.Miner.Client.Generate(10); err != nil {
return err return err
} }
@ -803,7 +803,7 @@ func (n *NetworkHarness) WaitForTxInMempool(ctx context.Context,
case <-ticker.C: case <-ticker.C:
var err error var err error
mempool, err = n.Miner.Node.GetRawMempool() mempool, err = n.Miner.Client.GetRawMempool()
if err != nil { if err != nil {
return err return err
} }
@ -1383,7 +1383,7 @@ func (n *NetworkHarness) sendCoins(ctx context.Context, amt btcutil.Amount,
// Otherwise, we'll generate 6 new blocks to ensure the output gains a // Otherwise, we'll generate 6 new blocks to ensure the output gains a
// sufficient number of confirmations and wait for the balance to // sufficient number of confirmations and wait for the balance to
// reflect what's expected. // reflect what's expected.
if _, err := n.Miner.Node.Generate(6); err != nil { if _, err := n.Miner.Client.Generate(6); err != nil {
return err return err
} }

@ -176,7 +176,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest,
numBlocks := padCLTV( numBlocks := padCLTV(
uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta), uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta),
) )
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
// Bob's force close transaction should now be found in the mempool. If // Bob's force close transaction should now be found in the mempool. If
@ -189,11 +189,11 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest,
bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint)
require.NoError(t.t, err) require.NoError(t.t, err)
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
closeTx := getSpendingTxInMempool( closeTx := getSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{ t, net.Miner.Client, minerMempoolTimeout, wire.OutPoint{
Hash: *bobFundingTxid, Hash: *bobFundingTxid,
Index: bobChanPoint.OutputIndex, Index: bobChanPoint.OutputIndex,
}, },
@ -258,7 +258,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest,
} }
txes, err := getNTxsFromMempool( txes, err := getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -334,13 +334,13 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest,
// If we then mine additional blocks, Bob can sweep his commitment // If we then mine additional blocks, Bob can sweep his commitment
// output. // output.
_, err = net.Miner.Node.Generate(defaultCSV - 2) _, err = net.Miner.Client.Generate(defaultCSV - 2)
require.NoError(t.t, err) require.NoError(t.t, err)
// Find the commitment sweep. // Find the commitment sweep.
bobCommitSweepHash, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) bobCommitSweepHash, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
bobCommitSweep, err := net.Miner.Node.GetRawTransaction(bobCommitSweepHash) bobCommitSweep, err := net.Miner.Client.GetRawTransaction(bobCommitSweepHash)
require.NoError(t.t, err) require.NoError(t.t, err)
require.Equal( require.Equal(
@ -375,11 +375,11 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest,
_ = mineBlocks(t, net, 2, 1) _ = mineBlocks(t, net, 2, 1)
} }
bobSweep, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) bobSweep, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// Make sure it spends from the second level tx. // Make sure it spends from the second level tx.
secondLevelSweep, err := net.Miner.Node.GetRawTransaction(bobSweep) secondLevelSweep, err := net.Miner.Client.GetRawTransaction(bobSweep)
require.NoError(t.t, err) require.NoError(t.t, err)
// It should be sweeping all the second-level outputs. // It should be sweeping all the second-level outputs.

@ -97,7 +97,7 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
expectedTxes = 2 expectedTxes = 2
} }
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -122,13 +122,13 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry - numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry -
lncfg.DefaultIncomingBroadcastDelta)) lncfg.DefaultIncomingBroadcastDelta))
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
// Carol's commitment transaction should now be in the mempool. If there // Carol's commitment transaction should now be in the mempool. If there
// is an anchor, Carol will sweep that too. // is an anchor, Carol will sweep that too.
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint)
@ -141,7 +141,7 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// Look up the closing transaction. It should be spending from the // Look up the closing transaction. It should be spending from the
// funding transaction, // funding transaction,
closingTx := getSpendingTxInMempool( closingTx := getSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, carolFundingPoint, t, net.Miner.Client, minerMempoolTimeout, carolFundingPoint,
) )
closingTxid := closingTx.TxHash() closingTxid := closingTx.TxHash()
@ -166,7 +166,7 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
expectedTxes = 3 expectedTxes = 3
} }
txes, err := getNTxsFromMempool( txes, err := getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -206,12 +206,12 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// will extract the preimage and broadcast a second level tx to claim // will extract the preimage and broadcast a second level tx to claim
// the HTLC in his (already closed) channel with Alice. // the HTLC in his (already closed) channel with Alice.
bobSecondLvlTx, err := waitForTxInMempool( bobSecondLvlTx, err := waitForTxInMempool(
net.Miner.Node, minerMempoolTimeout, net.Miner.Client, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
// It should spend from the commitment in the channel with Alice. // It should spend from the commitment in the channel with Alice.
tx, err := net.Miner.Node.GetRawTransaction(bobSecondLvlTx) tx, err := net.Miner.Client.GetRawTransaction(bobSecondLvlTx)
require.NoError(t.t, err) require.NoError(t.t, err)
require.Equal( require.Equal(
@ -261,11 +261,11 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// If we then mine 3 additional blocks, Carol's second level tx should // If we then mine 3 additional blocks, Carol's second level tx should
// mature, and she can pull the funds from it with a sweep tx. // mature, and she can pull the funds from it with a sweep tx.
_, err = net.Miner.Node.Generate(carolSecondLevelCSV) _, err = net.Miner.Client.Generate(carolSecondLevelCSV)
require.NoError(t.t, err) require.NoError(t.t, err)
bobSecondLevelCSV -= carolSecondLevelCSV bobSecondLevelCSV -= carolSecondLevelCSV
carolSweep, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) carolSweep, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// Mining one additional block, Bob's second level tx is mature, and he // Mining one additional block, Bob's second level tx is mature, and he
@ -273,11 +273,11 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
block = mineBlocks(t, net, bobSecondLevelCSV, 1)[0] block = mineBlocks(t, net, bobSecondLevelCSV, 1)[0]
assertTxInBlock(t, block, carolSweep) assertTxInBlock(t, block, carolSweep)
bobSweep, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) bobSweep, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// Make sure it spends from the second level tx. // Make sure it spends from the second level tx.
tx, err = net.Miner.Node.GetRawTransaction(bobSweep) tx, err = net.Miner.Client.GetRawTransaction(bobSweep)
require.NoError(t.t, err) require.NoError(t.t, err)
require.Equal( require.Equal(
t.t, *bobSecondLvlTx, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash, t.t, *bobSecondLvlTx, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash,

@ -98,7 +98,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
numBlocks := padCLTV( numBlocks := padCLTV(
uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta), uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta),
) )
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
// Bob's force close transaction should now be found in the mempool. If // Bob's force close transaction should now be found in the mempool. If
@ -111,11 +111,11 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint)
require.NoError(t.t, err) require.NoError(t.t, err)
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
closeTx := getSpendingTxInMempool( closeTx := getSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{ t, net.Miner.Client, minerMempoolTimeout, wire.OutPoint{
Hash: *bobFundingTxid, Hash: *bobFundingTxid,
Index: bobChanPoint.OutputIndex, Index: bobChanPoint.OutputIndex,
}, },
@ -138,7 +138,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
// timeout transaction to be broadcast due to the expiry being reached. // timeout transaction to be broadcast due to the expiry being reached.
// If there are anchors, we also expect Carol's anchor sweep now. // If there are anchors, we also expect Carol's anchor sweep now.
txes, err := getNTxsFromMempool( txes, err := getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -166,7 +166,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
mineBlocks(t, net, defaultCSV-1, expectedTxes) mineBlocks(t, net, defaultCSV-1, expectedTxes)
// Check that the sweep spends from the mined commitment. // Check that the sweep spends from the mined commitment.
txes, err = getNTxsFromMempool(net.Miner.Node, 1, minerMempoolTimeout) txes, err = getNTxsFromMempool(net.Miner.Client, 1, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
assertAllTxesSpendFrom(t, txes, closeTxid) assertAllTxesSpendFrom(t, txes, closeTxid)
@ -193,7 +193,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
// layer sweep due to the CSV on the HTLC timeout output. // layer sweep due to the CSV on the HTLC timeout output.
mineBlocks(t, net, 1, 0) mineBlocks(t, net, 1, 0)
assertSpendingTxInMempool( assertSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{ t, net.Miner.Client, minerMempoolTimeout, wire.OutPoint{
Hash: *htlcTimeout, Hash: *htlcTimeout,
Index: 0, Index: 0,
}, },
@ -218,7 +218,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
// Next, we'll mine a final block that should confirm the second-layer // Next, we'll mine a final block that should confirm the second-layer
// sweeping transaction. // sweeping transaction.
_, err = net.Miner.Node.Generate(1) _, err = net.Miner.Client.Generate(1)
require.NoError(t.t, err) require.NoError(t.t, err)
// Once this transaction has been confirmed, Bob should detect that he // Once this transaction has been confirmed, Bob should detect that he

@ -106,7 +106,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
numBlocks := padCLTV(uint32( numBlocks := padCLTV(uint32(
invoiceReq.CltvExpiry - lncfg.DefaultIncomingBroadcastDelta, invoiceReq.CltvExpiry - lncfg.DefaultIncomingBroadcastDelta,
)) ))
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
// At this point, Carol should broadcast her active commitment // At this point, Carol should broadcast her active commitment
@ -117,7 +117,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
expectedTxes = 2 expectedTxes = 2
} }
_, err = getNTxsFromMempool( _, err = getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -132,7 +132,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// The commitment transaction should be spending from the funding // The commitment transaction should be spending from the funding
// transaction. // transaction.
closingTx := getSpendingTxInMempool( closingTx := getSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, carolFundingPoint, t, net.Miner.Client, minerMempoolTimeout, carolFundingPoint,
) )
closingTxid := closingTx.TxHash() closingTxid := closingTx.TxHash()
@ -154,7 +154,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
expectedTxes = 3 expectedTxes = 3
} }
txes, err := getNTxsFromMempool( txes, err := getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -163,7 +163,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// We'll now mine an additional block which should confirm both the // We'll now mine an additional block which should confirm both the
// second layer transactions. // second layer transactions.
_, err = net.Miner.Node.Generate(1) _, err = net.Miner.Client.Generate(1)
require.NoError(t.t, err) require.NoError(t.t, err)
time.Sleep(time.Second * 4) time.Sleep(time.Second * 4)
@ -197,17 +197,17 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// If we mine 4 additional blocks, then both outputs should now be // If we mine 4 additional blocks, then both outputs should now be
// mature. // mature.
_, err = net.Miner.Node.Generate(defaultCSV) _, err = net.Miner.Client.Generate(defaultCSV)
require.NoError(t.t, err) require.NoError(t.t, err)
// We should have a new transaction in the mempool. // We should have a new transaction in the mempool.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// Finally, if we mine an additional block to confirm these two sweep // Finally, if we mine an additional block to confirm these two sweep
// transactions, Carol should not show a pending channel in her report // transactions, Carol should not show a pending channel in her report
// afterwards. // afterwards.
_, err = net.Miner.Node.Generate(1) _, err = net.Miner.Client.Generate(1)
require.NoError(t.t, err) require.NoError(t.t, err)
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
err = waitForNumChannelPendingForceClose(ctxt, carol, 0, nil) err = waitForNumChannelPendingForceClose(ctxt, carol, 0, nil)

@ -101,7 +101,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// type is of that type). // type is of that type).
if c == commitTypeAnchors { if c == commitTypeAnchors {
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, 1, minerMempoolTimeout, net.Miner.Client, 1, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find bob's anchor commit sweep: %v", t.Fatalf("unable to find bob's anchor commit sweep: %v",
@ -114,12 +114,12 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// containing the commitment tx and the commit sweep tx will be // containing the commitment tx and the commit sweep tx will be
// broadcast immediately before it can be included in a block, so mine // broadcast immediately before it can be included in a block, so mine
// one less than defaultCSV in order to perform mempool assertions. // one less than defaultCSV in order to perform mempool assertions.
_, err = net.Miner.Node.Generate(defaultCSV - 1) _, err = net.Miner.Client.Generate(defaultCSV - 1)
require.NoError(t.t, err) require.NoError(t.t, err)
// Alice should now sweep her funds. // Alice should now sweep her funds.
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, 1, minerMempoolTimeout, net.Miner.Client, 1, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -145,7 +145,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
invoiceReq.CltvExpiry-lncfg.DefaultIncomingBroadcastDelta, invoiceReq.CltvExpiry-lncfg.DefaultIncomingBroadcastDelta,
) - defaultCSV) ) - defaultCSV)
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
expectedTxes := 1 expectedTxes := 1
@ -156,7 +156,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// Carol's commitment transaction should now be in the mempool. If // Carol's commitment transaction should now be in the mempool. If
// there are anchors, Carol also sweeps her anchor. // there are anchors, Carol also sweeps her anchor.
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint)
@ -169,7 +169,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// The closing transaction should be spending from the funding // The closing transaction should be spending from the funding
// transaction. // transaction.
closingTx := getSpendingTxInMempool( closingTx := getSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, carolFundingPoint, t, net.Miner.Client, minerMempoolTimeout, carolFundingPoint,
) )
closingTxid := closingTx.TxHash() closingTxid := closingTx.TxHash()
@ -193,7 +193,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
expectedTxes = 3 expectedTxes = 3
} }
txes, err := getNTxsFromMempool( txes, err := getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -211,12 +211,12 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// will extract the preimage and broadcast a sweep tx to directly claim // will extract the preimage and broadcast a sweep tx to directly claim
// the HTLC in his (already closed) channel with Alice. // the HTLC in his (already closed) channel with Alice.
bobHtlcSweep, err := waitForTxInMempool( bobHtlcSweep, err := waitForTxInMempool(
net.Miner.Node, minerMempoolTimeout, net.Miner.Client, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
// It should spend from the commitment in the channel with Alice. // It should spend from the commitment in the channel with Alice.
tx, err := net.Miner.Node.GetRawTransaction(bobHtlcSweep) tx, err := net.Miner.Client.GetRawTransaction(bobHtlcSweep)
require.NoError(t.t, err) require.NoError(t.t, err)
require.Equal( require.Equal(
t.t, *aliceForceClose, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash, t.t, *aliceForceClose, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash,
@ -238,11 +238,11 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// If we then mine 3 additional blocks, Carol's second level tx will // If we then mine 3 additional blocks, Carol's second level tx will
// mature, and she should pull the funds. // mature, and she should pull the funds.
_, err = net.Miner.Node.Generate(carolSecondLevelCSV) _, err = net.Miner.Client.Generate(carolSecondLevelCSV)
require.NoError(t.t, err) require.NoError(t.t, err)
carolSweep, err := waitForTxInMempool( carolSweep, err := waitForTxInMempool(
net.Miner.Node, minerMempoolTimeout, net.Miner.Client, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)

@ -96,7 +96,7 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
// transaction of Bob's funding output. If there are anchors, mine // transaction of Bob's funding output. If there are anchors, mine
// Carol's anchor sweep too. // Carol's anchor sweep too.
if c == commitTypeAnchors { if c == commitTypeAnchors {
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
} }
@ -104,16 +104,16 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
// expires and the commitment was already mined inside // expires and the commitment was already mined inside
// closeChannelAndAssertType(), so mine one block less than defaultCSV // closeChannelAndAssertType(), so mine one block less than defaultCSV
// in order to perform mempool assertions. // in order to perform mempool assertions.
_, err = net.Miner.Node.Generate(defaultCSV - 1) _, err = net.Miner.Client.Generate(defaultCSV - 1)
require.NoError(t.t, err) require.NoError(t.t, err)
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// We'll now mine enough blocks for the HTLC to expire. After this, Bob // We'll now mine enough blocks for the HTLC to expire. After this, Bob
// should hand off the now expired HTLC output to the utxo nursery. // should hand off the now expired HTLC output to the utxo nursery.
numBlocks := padCLTV(uint32(finalCltvDelta - defaultCSV)) numBlocks := padCLTV(uint32(finalCltvDelta - defaultCSV))
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
// Bob's pending channel report should show that he has a single HTLC // Bob's pending channel report should show that he has a single HTLC
@ -138,7 +138,7 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
// We should also now find a transaction in the mempool, as Bob should // We should also now find a transaction in the mempool, as Bob should
// have broadcast his second layer timeout transaction. // have broadcast his second layer timeout transaction.
timeoutTx, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) timeoutTx, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// Next, we'll mine an additional block. This should serve to confirm // Next, we'll mine an additional block. This should serve to confirm
@ -177,10 +177,10 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
// We'll now mine 4 additional blocks. This should be enough for Bob's // We'll now mine 4 additional blocks. This should be enough for Bob's
// CSV timelock to expire and the sweeping transaction of the HTLC to be // CSV timelock to expire and the sweeping transaction of the HTLC to be
// broadcast. // broadcast.
_, err = net.Miner.Node.Generate(defaultCSV) _, err = net.Miner.Client.Generate(defaultCSV)
require.NoError(t.t, err) require.NoError(t.t, err)
sweepTx, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) sweepTx, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
// We'll then mine a final block which should confirm this second layer // We'll then mine a final block which should confirm this second layer

@ -93,7 +93,7 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
} }
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
require.NoError(t.t, err) require.NoError(t.t, err)
@ -101,7 +101,7 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
// point, Bob should hand off the output to his internal utxo nursery, // point, Bob should hand off the output to his internal utxo nursery,
// which will broadcast a sweep transaction. // which will broadcast a sweep transaction.
numBlocks := padCLTV(finalCltvDelta - 1) numBlocks := padCLTV(finalCltvDelta - 1)
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
require.NoError(t.t, err) require.NoError(t.t, err)
// If we check Bob's pending channel report, it should show that he has // If we check Bob's pending channel report, it should show that he has
@ -126,12 +126,12 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
require.NoError(t.t, err) require.NoError(t.t, err)
// We need to generate an additional block to trigger the sweep. // We need to generate an additional block to trigger the sweep.
_, err = net.Miner.Node.Generate(1) _, err = net.Miner.Client.Generate(1)
require.NoError(t.t, err) require.NoError(t.t, err)
// Bob's sweeping transaction should now be found in the mempool at // Bob's sweeping transaction should now be found in the mempool at
// this point. // this point.
sweepTx, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) sweepTx, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
// If Bob's transaction isn't yet in the mempool, then due to // If Bob's transaction isn't yet in the mempool, then due to
// internal message passing and the low period between blocks // internal message passing and the low period between blocks
@ -141,9 +141,9 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
// we'll fail. // we'll fail.
// TODO(halseth): can we use waitForChannelPendingForceClose to // TODO(halseth): can we use waitForChannelPendingForceClose to
// avoid this hack? // avoid this hack?
_, err = net.Miner.Node.Generate(1) _, err = net.Miner.Client.Generate(1)
require.NoError(t.t, err) require.NoError(t.t, err)
sweepTx, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) sweepTx, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err) require.NoError(t.t, err)
} }

@ -24,7 +24,7 @@ import (
func testCPFP(net *lntest.NetworkHarness, t *harnessTest) { func testCPFP(net *lntest.NetworkHarness, t *harnessTest) {
// Skip this test for neutrino, as it's not aware of mempool // Skip this test for neutrino, as it's not aware of mempool
// transactions. // transactions.
if net.BackendCfg.Name() == "neutrino" { if net.BackendCfg.Name() == lntest.NeutrinoBackendName {
t.Skipf("skipping CPFP test for neutrino backend") t.Skipf("skipping CPFP test for neutrino backend")
} }
@ -58,14 +58,14 @@ func testCPFP(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)
} }
txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("expected one mempool transaction: %v", err) t.Fatalf("expected one mempool transaction: %v", err)
} }
// We'll then extract the raw transaction from the mempool in order to // We'll then extract the raw transaction from the mempool in order to
// determine the index of Bob's output. // determine the index of Bob's output.
tx, err := net.Miner.Node.GetRawTransaction(txid) tx, err := net.Miner.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
t.Fatalf("unable to extract raw transaction from mempool: %v", t.Fatalf("unable to extract raw transaction from mempool: %v",
err) err)
@ -110,7 +110,7 @@ func testCPFP(net *lntest.NetworkHarness, t *harnessTest) {
// We should now expect to see two transactions within the mempool, a // We should now expect to see two transactions within the mempool, a
// parent and its child. // parent and its child.
_, err = waitForNTxsInMempool(net.Miner.Node, 2, minerMempoolTimeout) _, err = waitForNTxsInMempool(net.Miner.Client, 2, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("expected two mempool transactions: %v", err) t.Fatalf("expected two mempool transactions: %v", err)
} }

@ -173,7 +173,7 @@ func testPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest) {
} }
// No transaction should have been published yet. // No transaction should have been published yet.
mempool, err := net.Miner.Node.GetRawMempool() mempool, err := net.Miner.Client.GetRawMempool()
require.NoError(t.t, err) require.NoError(t.t, err)
require.Equal(t.t, 0, len(mempool)) require.Equal(t.t, 0, len(mempool))

@ -190,7 +190,7 @@ func testRestAPI(net *lntest.NetworkHarness, ht *harnessTest) {
run: func(t *testing.T, a, b *lntest.HarnessNode) { run: func(t *testing.T, a, b *lntest.HarnessNode) {
// Find out the current best block so we can subscribe // Find out the current best block so we can subscribe
// to the next one. // to the next one.
hash, height, err := net.Miner.Node.GetBestBlock() hash, height, err := net.Miner.Client.GetBestBlock()
require.Nil(t, err, "get best block") require.Nil(t, err, "get best block")
// Create a new subscription to get block epoch events. // Create a new subscription to get block epoch events.
@ -257,7 +257,7 @@ func testRestAPI(net *lntest.NetworkHarness, ht *harnessTest) {
}() }()
// Mine a block and make sure we get a message for it. // Mine a block and make sure we get a message for it.
blockHashes, err := net.Miner.Node.Generate(1) blockHashes, err := net.Miner.Client.Generate(1)
require.Nil(t, err, "generate blocks") require.Nil(t, err, "generate blocks")
assert.Equal(t, 1, len(blockHashes), "num blocks") assert.Equal(t, 1, len(blockHashes), "num blocks")
select { select {
@ -279,7 +279,7 @@ func testRestAPI(net *lntest.NetworkHarness, ht *harnessTest) {
run: func(t *testing.T, a, b *lntest.HarnessNode) { run: func(t *testing.T, a, b *lntest.HarnessNode) {
// Find out the current best block so we can subscribe // Find out the current best block so we can subscribe
// to the next one. // to the next one.
hash, height, err := net.Miner.Node.GetBestBlock() hash, height, err := net.Miner.Client.GetBestBlock()
require.Nil(t, err, "get best block") require.Nil(t, err, "get best block")
// Create a new subscription to get block epoch events. // Create a new subscription to get block epoch events.
@ -366,7 +366,7 @@ func testRestAPI(net *lntest.NetworkHarness, ht *harnessTest) {
}() }()
// Mine a block and make sure we get a message for it. // Mine a block and make sure we get a message for it.
blockHashes, err := net.Miner.Node.Generate(1) blockHashes, err := net.Miner.Client.Generate(1)
require.Nil(t, err, "generate blocks") require.Nil(t, err, "generate blocks")
assert.Equal(t, 1, len(blockHashes), "num blocks") assert.Equal(t, 1, len(blockHashes), "num blocks")
select { select {

@ -479,7 +479,7 @@ func cleanupForceClose(t *harnessTest, net *lntest.NetworkHarness,
// //
// The commit sweep resolver is able to broadcast the sweep tx up to // The commit sweep resolver is able to broadcast the sweep tx up to
// one block before the CSV elapses, so wait until defaulCSV-1. // one block before the CSV elapses, so wait until defaulCSV-1.
_, err = net.Miner.Node.Generate(defaultCSV - 1) _, err = net.Miner.Client.Generate(defaultCSV - 1)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -812,7 +812,7 @@ func testGetRecoveryInfo(net *lntest.NetworkHarness, t *harnessTest) {
} }
// Wait for Carol to sync to the chain. // Wait for Carol to sync to the chain.
_, minerHeight, err := net.Miner.Node.GetBestBlock() _, minerHeight, err := net.Miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -1088,7 +1088,7 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("unable to send coins to miner: %v", err) t.Fatalf("unable to send coins to miner: %v", err)
} }
txid, err := waitForTxInMempool( txid, err := waitForTxInMempool(
net.Miner.Node, minerMempoolTimeout, net.Miner.Client, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("transaction not found in mempool: %v", err) t.Fatalf("transaction not found in mempool: %v", err)
@ -1536,7 +1536,7 @@ func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
} }
// Make sure the unconfirmed tx is seen in the mempool. // Make sure the unconfirmed tx is seen in the mempool.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("failed to find tx in miner mempool: %v", err) t.Fatalf("failed to find tx in miner mempool: %v", err)
} }
@ -2497,14 +2497,14 @@ func assertMinerBlockHeightDelta(t *harnessTest,
// Ensure the chain lengths are what we expect. // Ensure the chain lengths are what we expect.
var predErr error var predErr error
err := wait.Predicate(func() bool { err := wait.Predicate(func() bool {
_, tempMinerHeight, err := tempMiner.Node.GetBestBlock() _, tempMinerHeight, err := tempMiner.Client.GetBestBlock()
if err != nil { if err != nil {
predErr = fmt.Errorf("unable to get current "+ predErr = fmt.Errorf("unable to get current "+
"blockheight %v", err) "blockheight %v", err)
return false return false
} }
_, minerHeight, err := miner.Node.GetBestBlock() _, minerHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
predErr = fmt.Errorf("unable to get current "+ predErr = fmt.Errorf("unable to get current "+
"blockheight %v", err) "blockheight %v", err)
@ -2531,7 +2531,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// Skip test for neutrino, as we cannot disconnect the miner at will. // Skip test for neutrino, as we cannot disconnect the miner at will.
// TODO(halseth): remove when either can disconnect at will, or restart // TODO(halseth): remove when either can disconnect at will, or restart
// node with connection to new miner. // node with connection to new miner.
if net.BackendCfg.Name() == "neutrino" { if net.BackendCfg.Name() == lntest.NeutrinoBackendName {
t.Skipf("skipping reorg test for neutrino backend") t.Skipf("skipping reorg test for neutrino backend")
} }
@ -2562,7 +2562,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// We start by connecting the new miner to our original miner, // We start by connecting the new miner to our original miner,
// such that it will sync to our original chain. // such that it will sync to our original chain.
err = net.Miner.Node.Node( err = net.Miner.Client.Node(
btcjson.NConnect, tempMiner.P2PAddress(), &temp, btcjson.NConnect, tempMiner.P2PAddress(), &temp,
) )
if err != nil { if err != nil {
@ -2578,7 +2578,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// We disconnect the two miners, such that we can mine two different // We disconnect the two miners, such that we can mine two different
// chains and can cause a reorg later. // chains and can cause a reorg later.
err = net.Miner.Node.Node( err = net.Miner.Client.Node(
btcjson.NDisconnect, tempMiner.P2PAddress(), &temp, btcjson.NDisconnect, tempMiner.P2PAddress(), &temp,
) )
if err != nil { if err != nil {
@ -2598,7 +2598,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// Wait for miner to have seen the funding tx. The temporary miner is // Wait for miner to have seen the funding tx. The temporary miner is
// disconnected, and won't see the transaction. // disconnected, and won't see the transaction.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("failed to find funding tx in mempool: %v", err) t.Fatalf("failed to find funding tx in mempool: %v", err)
} }
@ -2620,7 +2620,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// open. // open.
block := mineBlocks(t, net, 10, 1)[0] block := mineBlocks(t, net, 10, 1)[0]
assertTxInBlock(t, block, fundingTxID) assertTxInBlock(t, block, fundingTxID)
if _, err := tempMiner.Node.Generate(15); err != nil { if _, err := tempMiner.Client.Generate(15); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -2629,7 +2629,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 5) assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 5)
// Wait for Alice to sync to the original miner's chain. // Wait for Alice to sync to the original miner's chain.
_, minerHeight, err := net.Miner.Node.GetBestBlock() _, minerHeight, err := net.Miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -2690,7 +2690,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// Connecting to the temporary miner should now cause our original // Connecting to the temporary miner should now cause our original
// chain to be re-orged out. // chain to be re-orged out.
err = net.Miner.Node.Node( err = net.Miner.Client.Node(
btcjson.NConnect, tempMiner.P2PAddress(), &temp, btcjson.NConnect, tempMiner.P2PAddress(), &temp,
) )
if err != nil { if err != nil {
@ -2707,7 +2707,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// Now we disconnect the two miners, and connect our original miner to // Now we disconnect the two miners, and connect our original miner to
// our chain backend once again. // our chain backend once again.
err = net.Miner.Node.Node( err = net.Miner.Client.Node(
btcjson.NDisconnect, tempMiner.P2PAddress(), &temp, btcjson.NDisconnect, tempMiner.P2PAddress(), &temp,
) )
if err != nil { if err != nil {
@ -2721,7 +2721,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// This should have caused a reorg, and Alice should sync to the longer // This should have caused a reorg, and Alice should sync to the longer
// chain, where the funding transaction is not confirmed. // chain, where the funding transaction is not confirmed.
_, tempMinerHeight, err := tempMiner.Node.GetBestBlock() _, tempMinerHeight, err := tempMiner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -3001,7 +3001,7 @@ func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) {
assertTxInBlock(t, block, fundingTxID) assertTxInBlock(t, block, fundingTxID)
// Get the height that our transaction confirmed at. // Get the height that our transaction confirmed at.
_, height, err := net.Miner.Node.GetBestBlock() _, height, err := net.Miner.Client.GetBestBlock()
require.NoError(t.t, err, "could not get best block") require.NoError(t.t, err, "could not get best block")
// Restart both nodes to test that the appropriate state has been // Restart both nodes to test that the appropriate state has been
@ -3022,7 +3022,7 @@ func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) {
// Next, mine enough blocks s.t the channel will open with a single // Next, mine enough blocks s.t the channel will open with a single
// additional block mined. // additional block mined.
if _, err := net.Miner.Node.Generate(3); err != nil { if _, err := net.Miner.Client.Generate(3); err != nil {
t.Fatalf("unable to mine blocks: %v", err) t.Fatalf("unable to mine blocks: %v", err)
} }
@ -3042,7 +3042,7 @@ func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) {
assertNumOpenChannelsPending(ctxt, t, net.Alice, carol, 1) assertNumOpenChannelsPending(ctxt, t, net.Alice, carol, 1)
// Finally, mine the last block which should mark the channel as open. // Finally, mine the last block which should mark the channel as open.
if _, err := net.Miner.Node.Generate(1); err != nil { if _, err := net.Miner.Client.Generate(1); err != nil {
t.Fatalf("unable to mine blocks: %v", err) t.Fatalf("unable to mine blocks: %v", err)
} }
@ -3699,7 +3699,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Fetch starting height of this test so we can compute the block // Fetch starting height of this test so we can compute the block
// heights we expect certain events to take place. // heights we expect certain events to take place.
_, curHeight, err := net.Miner.Node.GetBestBlock() _, curHeight, err := net.Miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get best block height") t.Fatalf("unable to get best block height")
} }
@ -3807,7 +3807,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
} }
sweepTxns, err := getNTxsFromMempool( sweepTxns, err := getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("failed to find commitment in miner mempool: %v", err) t.Fatalf("failed to find commitment in miner mempool: %v", err)
@ -3819,7 +3819,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
utx := btcutil.NewTx(tx) utx := btcutil.NewTx(tx)
totalWeight += blockchain.GetTransactionWeight(utx) totalWeight += blockchain.GetTransactionWeight(utx)
fee, err := getTxFee(net.Miner.Node, tx) fee, err := getTxFee(net.Miner.Client, tx)
require.NoError(t.t, err) require.NoError(t.t, err)
totalFee += int64(fee) totalFee += int64(fee)
} }
@ -3852,7 +3852,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
} }
} }
if _, err := net.Miner.Node.Generate(1); err != nil { if _, err := net.Miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -3921,7 +3921,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// not timelocked. If there are anchors, we also expect Carol's anchor // not timelocked. If there are anchors, we also expect Carol's anchor
// sweep now. // sweep now.
sweepTxns, err = getNTxsFromMempool( sweepTxns, err = getNTxsFromMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("failed to find Carol's sweep in miner mempool: %v", t.Fatalf("failed to find Carol's sweep in miner mempool: %v",
@ -3953,7 +3953,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// For the persistence test, we generate two blocks, then trigger // For the persistence test, we generate two blocks, then trigger
// a restart and then generate the final block that should trigger // a restart and then generate the final block that should trigger
// the creation of the sweep transaction. // the creation of the sweep transaction.
if _, err := net.Miner.Node.Generate(defaultCSV - 2); err != nil { if _, err := net.Miner.Client.Generate(defaultCSV - 2); err != nil {
t.Fatalf("unable to mine blocks: %v", err) t.Fatalf("unable to mine blocks: %v", err)
} }
@ -4026,21 +4026,21 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Generate an additional block, which should cause the CSV delayed // Generate an additional block, which should cause the CSV delayed
// output from the commitment txn to expire. // output from the commitment txn to expire.
if _, err := net.Miner.Node.Generate(1); err != nil { if _, err := net.Miner.Client.Generate(1); err != nil {
t.Fatalf("unable to mine blocks: %v", err) t.Fatalf("unable to mine blocks: %v", err)
} }
// At this point, the CSV will expire in the next block, meaning that // At this point, the CSV will expire in the next block, meaning that
// the sweeping transaction should now be broadcast. So we fetch the // the sweeping transaction should now be broadcast. So we fetch the
// node's mempool to ensure it has been properly broadcast. // node's mempool to ensure it has been properly broadcast.
sweepingTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) sweepingTXID, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("failed to get sweep tx from mempool: %v", err) t.Fatalf("failed to get sweep tx from mempool: %v", err)
} }
// Fetch the sweep transaction, all input it's spending should be from // Fetch the sweep transaction, all input it's spending should be from
// the commitment transaction which was broadcast on-chain. // the commitment transaction which was broadcast on-chain.
sweepTx, err := net.Miner.Node.GetRawTransaction(sweepingTXID) sweepTx, err := net.Miner.Client.GetRawTransaction(sweepingTXID)
if err != nil { if err != nil {
t.Fatalf("unable to fetch sweep tx: %v", err) t.Fatalf("unable to fetch sweep tx: %v", err)
} }
@ -4091,11 +4091,11 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Next, we mine an additional block which should include the sweep // Next, we mine an additional block which should include the sweep
// transaction as the input scripts and the sequence locks on the // transaction as the input scripts and the sequence locks on the
// inputs should be properly met. // inputs should be properly met.
blockHash, err := net.Miner.Node.Generate(1) blockHash, err := net.Miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
block, err := net.Miner.Node.GetBlock(blockHash[0]) block, err := net.Miner.Client.GetBlock(blockHash[0])
if err != nil { if err != nil {
t.Fatalf("unable to get block: %v", err) t.Fatalf("unable to get block: %v", err)
} }
@ -4103,7 +4103,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
assertTxInBlock(t, block, sweepTx.Hash()) assertTxInBlock(t, block, sweepTx.Hash())
// Update current height // Update current height
_, curHeight, err = net.Miner.Node.GetBestBlock() _, curHeight, err = net.Miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get best block height") t.Fatalf("unable to get best block height")
} }
@ -4167,8 +4167,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Advance the blockchain until just before the CLTV expires, nothing // Advance the blockchain until just before the CLTV expires, nothing
// exciting should have happened during this time. // exciting should have happened during this time.
blockHash, err = net.Miner.Node.Generate(cltvHeightDelta) if _, err := net.Miner.Client.Generate(cltvHeightDelta); err != nil {
if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -4233,8 +4232,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Now, generate the block which will cause Alice to broadcast the // Now, generate the block which will cause Alice to broadcast the
// presigned htlc timeout txns. // presigned htlc timeout txns.
blockHash, err = net.Miner.Node.Generate(1) if _, err = net.Miner.Client.Generate(1); err != nil {
if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -4250,7 +4248,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Wait for them all to show up in the mempool. // Wait for them all to show up in the mempool.
htlcTxIDs, err := waitForNTxsInMempool( htlcTxIDs, err := waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find htlc timeout txns in mempool: %v", err) t.Fatalf("unable to find htlc timeout txns in mempool: %v", err)
@ -4279,7 +4277,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// on-chain. In case of an anchor type channel, we expect one // on-chain. In case of an anchor type channel, we expect one
// extra input that is not spending from the commitment, that // extra input that is not spending from the commitment, that
// is added for fees. // is added for fees.
htlcTx, err := net.Miner.Node.GetRawTransaction(htlcTxID) htlcTx, err := net.Miner.Client.GetRawTransaction(htlcTxID)
if err != nil { if err != nil {
t.Fatalf("unable to fetch sweep tx: %v", err) t.Fatalf("unable to fetch sweep tx: %v", err)
} }
@ -4376,8 +4374,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Generate a block that mines the htlc timeout txns. Doing so now // Generate a block that mines the htlc timeout txns. Doing so now
// activates the 2nd-stage CSV delayed outputs. // activates the 2nd-stage CSV delayed outputs.
blockHash, err = net.Miner.Node.Generate(1) if _, err = net.Miner.Client.Generate(1); err != nil {
if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -4395,7 +4392,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
numBlocks = defaultCSV - 2 numBlocks = defaultCSV - 2
} }
_, err = net.Miner.Node.Generate(numBlocks) _, err = net.Miner.Client.Generate(numBlocks)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -4449,21 +4446,20 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
// Generate a block that causes Alice to sweep the htlc outputs in the // Generate a block that causes Alice to sweep the htlc outputs in the
// kindergarten bucket. // kindergarten bucket.
blockHash, err = net.Miner.Node.Generate(1) if _, err := net.Miner.Client.Generate(1); err != nil {
if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
// Wait for the single sweep txn to appear in the mempool. // Wait for the single sweep txn to appear in the mempool.
htlcSweepTxID, err := waitForTxInMempool( htlcSweepTxID, err := waitForTxInMempool(
net.Miner.Node, minerMempoolTimeout, net.Miner.Client, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("failed to get sweep tx from mempool: %v", err) t.Fatalf("failed to get sweep tx from mempool: %v", err)
} }
// Fetch the htlc sweep transaction from the mempool. // Fetch the htlc sweep transaction from the mempool.
htlcSweepTx, err := net.Miner.Node.GetRawTransaction(htlcSweepTxID) htlcSweepTx, err := net.Miner.Client.GetRawTransaction(htlcSweepTxID)
if err != nil { if err != nil {
t.Fatalf("unable to fetch sweep tx: %v", err) t.Fatalf("unable to fetch sweep tx: %v", err)
} }
@ -4650,7 +4646,7 @@ func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
for _, tx := range sweepTxns { for _, tx := range sweepTxns {
txHash := tx.TxHash() txHash := tx.TxHash()
sweepTx, err := net.Miner.Node.GetRawTransaction(&txHash) sweepTx, err := net.Miner.Client.GetRawTransaction(&txHash)
require.NoError(t.t, err) require.NoError(t.t, err)
// We expect our commitment sweep to have a single input, and, // We expect our commitment sweep to have a single input, and,
@ -5963,7 +5959,7 @@ func testSingleHopSendToRouteCase(net *lntest.NetworkHarness, t *harnessTest,
// Assert Carol and Dave are synced to the chain before proceeding, to // Assert Carol and Dave are synced to the chain before proceeding, to
// ensure the queried route will have a valid final CLTV once the HTLC // ensure the queried route will have a valid final CLTV once the HTLC
// reaches Dave. // reaches Dave.
_, minerHeight, err := net.Miner.Node.GetBestBlock() _, minerHeight, err := net.Miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get best height: %v", err) t.Fatalf("unable to get best height: %v", err)
} }
@ -8251,26 +8247,26 @@ func testFailingChannel(net *lntest.NetworkHarness, t *harnessTest) {
} }
// Carol will use the correct preimage to resolve the HTLC on-chain. // Carol will use the correct preimage to resolve the HTLC on-chain.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's resolve tx in mempool: %v", err) t.Fatalf("unable to find Carol's resolve tx in mempool: %v", err)
} }
// Mine enough blocks for Alice to sweep her funds from the force // Mine enough blocks for Alice to sweep her funds from the force
// closed channel. // closed channel.
_, err = net.Miner.Node.Generate(defaultCSV - 1) _, err = net.Miner.Client.Generate(defaultCSV - 1)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
// Wait for the sweeping tx to be broadcast. // Wait for the sweeping tx to be broadcast.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Alice's sweep tx in mempool: %v", err) t.Fatalf("unable to find Alice's sweep tx in mempool: %v", err)
} }
// Mine the sweep. // Mine the sweep.
_, err = net.Miner.Node.Generate(1) _, err = net.Miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -8476,7 +8472,7 @@ func testGarbageCollectLinkNodes(net *lntest.NetworkHarness, t *harnessTest) {
// We'll need to mine some blocks in order to mark the channel fully // We'll need to mine some blocks in order to mark the channel fully
// closed. // closed.
_, err = net.Miner.Node.Generate(chainreg.DefaultBitcoinTimeLockDelta - defaultCSV) _, err = net.Miner.Client.Generate(chainreg.DefaultBitcoinTimeLockDelta - defaultCSV)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
@ -8734,7 +8730,7 @@ func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) {
// Wait for Bob's breach transaction to show up in the mempool to ensure // Wait for Bob's breach transaction to show up in the mempool to ensure
// that Carol's node has started waiting for confirmations. // that Carol's node has started waiting for confirmations.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Bob's breach tx in mempool: %v", err) t.Fatalf("unable to find Bob's breach tx in mempool: %v", err)
} }
@ -8763,7 +8759,7 @@ func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) {
// Query the mempool for Carol's justice transaction, this should be // Query the mempool for Carol's justice transaction, this should be
// broadcast as Bob's contract breaching transaction gets confirmed // broadcast as Bob's contract breaching transaction gets confirmed
// above. // above.
justiceTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) justiceTXID, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's justice tx in mempool: %v", err) t.Fatalf("unable to find Carol's justice tx in mempool: %v", err)
} }
@ -8772,7 +8768,7 @@ func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) {
// Query for the mempool transaction found above. Then assert that all // Query for the mempool transaction found above. Then assert that all
// the inputs of this transaction are spending outputs generated by // the inputs of this transaction are spending outputs generated by
// Bob's breach transaction above. // Bob's breach transaction above.
justiceTx, err := net.Miner.Node.GetRawTransaction(justiceTXID) justiceTx, err := net.Miner.Client.GetRawTransaction(justiceTXID)
if err != nil { if err != nil {
t.Fatalf("unable to query for justice tx: %v", err) t.Fatalf("unable to query for justice tx: %v", err)
} }
@ -8988,7 +8984,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness
// Query the mempool for the breaching closing transaction, this should // Query the mempool for the breaching closing transaction, this should
// be broadcast by Carol when she force closes the channel above. // be broadcast by Carol when she force closes the channel above.
txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's force close tx in mempool: %v", t.Fatalf("unable to find Carol's force close tx in mempool: %v",
err) err)
@ -9020,7 +9016,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness
// Query the mempool for Dave's justice transaction, this should be // Query the mempool for Dave's justice transaction, this should be
// broadcast as Carol's contract breaching transaction gets confirmed // broadcast as Carol's contract breaching transaction gets confirmed
// above. // above.
justiceTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) justiceTXID, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Dave's justice tx in mempool: %v", t.Fatalf("unable to find Dave's justice tx in mempool: %v",
err) err)
@ -9030,7 +9026,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness
// Query for the mempool transaction found above. Then assert that all // Query for the mempool transaction found above. Then assert that all
// the inputs of this transaction are spending outputs generated by // the inputs of this transaction are spending outputs generated by
// Carol's breach transaction above. // Carol's breach transaction above.
justiceTx, err := net.Miner.Node.GetRawTransaction(justiceTXID) justiceTx, err := net.Miner.Client.GetRawTransaction(justiceTXID)
if err != nil { if err != nil {
t.Fatalf("unable to query for justice tx: %v", err) t.Fatalf("unable to query for justice tx: %v", err)
} }
@ -9318,7 +9314,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
// Query the mempool for the breaching closing transaction, this should // Query the mempool for the breaching closing transaction, this should
// be broadcast by Carol when she force closes the channel above. // be broadcast by Carol when she force closes the channel above.
txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's force close tx in mempool: %v", t.Fatalf("unable to find Carol's force close tx in mempool: %v",
err) err)
@ -9360,7 +9356,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
var justiceTxid *chainhash.Hash var justiceTxid *chainhash.Hash
errNotFound := errors.New("justice tx not found") errNotFound := errors.New("justice tx not found")
findJusticeTx := func() (*chainhash.Hash, error) { findJusticeTx := func() (*chainhash.Hash, error) {
mempool, err := net.Miner.Node.GetRawMempool() mempool, err := net.Miner.Client.GetRawMempool()
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get mempool from "+ return nil, fmt.Errorf("unable to get mempool from "+
"miner: %v", err) "miner: %v", err)
@ -9369,7 +9365,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
for _, txid := range mempool { for _, txid := range mempool {
// Check that the justice tx has the appropriate number // Check that the justice tx has the appropriate number
// of inputs. // of inputs.
tx, err := net.Miner.Node.GetRawTransaction(txid) tx, err := net.Miner.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to query for "+ return nil, fmt.Errorf("unable to query for "+
"txs: %v", err) "txs: %v", err)
@ -9418,7 +9414,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
t.Fatalf(predErr.Error()) t.Fatalf(predErr.Error())
} }
justiceTx, err := net.Miner.Node.GetRawTransaction(justiceTxid) justiceTx, err := net.Miner.Client.GetRawTransaction(justiceTxid)
if err != nil { if err != nil {
t.Fatalf("unable to query for justice tx: %v", err) t.Fatalf("unable to query for justice tx: %v", err)
} }
@ -9426,7 +9422,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
// isSecondLevelSpend checks that the passed secondLevelTxid is a // isSecondLevelSpend checks that the passed secondLevelTxid is a
// potentitial second level spend spending from the commit tx. // potentitial second level spend spending from the commit tx.
isSecondLevelSpend := func(commitTxid, secondLevelTxid *chainhash.Hash) bool { isSecondLevelSpend := func(commitTxid, secondLevelTxid *chainhash.Hash) bool {
secondLevel, err := net.Miner.Node.GetRawTransaction( secondLevel, err := net.Miner.Client.GetRawTransaction(
secondLevelTxid) secondLevelTxid)
if err != nil { if err != nil {
t.Fatalf("unable to query for tx: %v", err) t.Fatalf("unable to query for tx: %v", err)
@ -9785,7 +9781,7 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(
// Query the mempool for the breaching closing transaction, this should // Query the mempool for the breaching closing transaction, this should
// be broadcast by Carol when she force closes the channel above. // be broadcast by Carol when she force closes the channel above.
txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's force close tx in mempool: %v", t.Fatalf("unable to find Carol's force close tx in mempool: %v",
err) err)
@ -9810,7 +9806,7 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(
// Query the mempool for Dave's justice transaction, this should be // Query the mempool for Dave's justice transaction, this should be
// broadcast as Carol's contract breaching transaction gets confirmed // broadcast as Carol's contract breaching transaction gets confirmed
// above. // above.
justiceTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) justiceTXID, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Dave's justice tx in mempool: %v", t.Fatalf("unable to find Dave's justice tx in mempool: %v",
err) err)
@ -9820,7 +9816,7 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(
// Query for the mempool transaction found above. Then assert that all // Query for the mempool transaction found above. Then assert that all
// the inputs of this transaction are spending outputs generated by // the inputs of this transaction are spending outputs generated by
// Carol's breach transaction above. // Carol's breach transaction above.
justiceTx, err := net.Miner.Node.GetRawTransaction(justiceTXID) justiceTx, err := net.Miner.Client.GetRawTransaction(justiceTXID)
if err != nil { if err != nil {
t.Fatalf("unable to query for justice tx: %v", err) t.Fatalf("unable to query for justice tx: %v", err)
} }
@ -10006,7 +10002,7 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
expectedTxes = 2 expectedTxes = 2
} }
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's force close tx in mempool: %v", t.Fatalf("unable to find Carol's force close tx in mempool: %v",
@ -10035,7 +10031,7 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
// We also expect Dave to sweep his anchor, if present. // We also expect Dave to sweep his anchor, if present.
_, err = waitForNTxsInMempool( _, err = waitForNTxsInMempool(
net.Miner.Node, expectedTxes, minerMempoolTimeout, net.Miner.Client, expectedTxes, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find Dave's sweep tx in mempool: %v", err) t.Fatalf("unable to find Dave's sweep tx in mempool: %v", err)
@ -10078,7 +10074,7 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
// take that into account. // take that into account.
mineBlocks(t, net, defaultCSV-1-1, 0) mineBlocks(t, net, defaultCSV-1-1, 0)
carolSweep, err := waitForTxInMempool( carolSweep, err := waitForTxInMempool(
net.Miner.Node, minerMempoolTimeout, net.Miner.Client, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's sweep tx in mempool: %v", err) t.Fatalf("unable to find Carol's sweep tx in mempool: %v", err)
@ -10368,7 +10364,7 @@ func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) {
// Mine enough blocks for Carol to sweep her funds. // Mine enough blocks for Carol to sweep her funds.
mineBlocks(t, net, defaultCSV-1, 0) mineBlocks(t, net, defaultCSV-1, 0)
carolSweep, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) carolSweep, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Carol's sweep tx in mempool: %v", err) t.Fatalf("unable to find Carol's sweep tx in mempool: %v", err)
} }
@ -10401,7 +10397,7 @@ func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) {
} }
// Dave should sweep his funds. // Dave should sweep his funds.
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
if err != nil { if err != nil {
t.Fatalf("unable to find Dave's sweep tx in mempool: %v", err) t.Fatalf("unable to find Dave's sweep tx in mempool: %v", err)
} }
@ -10873,7 +10869,7 @@ func testGraphTopologyNtfns(net *lntest.NetworkHarness, t *harnessTest, pinned b
} }
} }
_, blockHeight, err := net.Miner.Node.GetBestBlock() _, blockHeight, err := net.Miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current blockheight %v", err) t.Fatalf("unable to get current blockheight %v", err)
} }
@ -14920,7 +14916,7 @@ func TestLightningNetworkDaemon(t *testing.T) {
// Set up miner and connect chain backend to it. // Set up miner and connect chain backend to it.
require.NoError(t, miner.SetUp(true, 50)) require.NoError(t, miner.SetUp(true, 50))
require.NoError(t, miner.Node.NotifyNewTransactions(false)) require.NoError(t, miner.Client.NotifyNewTransactions(false))
require.NoError(t, chainBackend.ConnectMiner(), "connect miner") require.NoError(t, chainBackend.ConnectMiner(), "connect miner")
// Now we can set up our test harness (LND instance), with the chain // Now we can set up our test harness (LND instance), with the chain
@ -14955,7 +14951,7 @@ func TestLightningNetworkDaemon(t *testing.T) {
// Next mine enough blocks in order for segwit and the CSV package // Next mine enough blocks in order for segwit and the CSV package
// soft-fork to activate on SimNet. // soft-fork to activate on SimNet.
numBlocks := harnessNetParams.MinerConfirmationWindow * 2 numBlocks := harnessNetParams.MinerConfirmationWindow * 2
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Client.Generate(numBlocks); err != nil {
ht.Fatalf("unable to generate blocks: %v", err) ht.Fatalf("unable to generate blocks: %v", err)
} }

@ -294,4 +294,12 @@ var allTestCases = []*testCase{
name: "stateless init", name: "stateless init",
test: testStatelessInit, test: testStatelessInit,
}, },
{
name: "wallet import account",
test: testWalletImportAccount,
},
{
name: "wallet import pubkey",
test: testWalletImportPubKey,
},
} }

@ -0,0 +1,866 @@
package itest
import (
"bytes"
"context"
"crypto/rand"
"fmt"
"math"
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/stretchr/testify/require"
)
const (
defaultAccount = lnwallet.DefaultAccountName
defaultImportedAccount = waddrmgr.ImportedAddrAccountName
)
// walletToLNAddrType maps walletrpc.AddressType to lnrpc.AddressType.
func walletToLNAddrType(t *testing.T, addrType walletrpc.AddressType) lnrpc.AddressType {
switch addrType {
case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
return lnrpc.AddressType_NESTED_PUBKEY_HASH
case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
return lnrpc.AddressType_WITNESS_PUBKEY_HASH
default:
t.Fatalf("unhandled addr type %v", addrType)
return 0
}
}
// newExternalAddr generates a new external address of an imported account for a
// pair of nodes, where one acts as the funder and the other as the signer.
func newExternalAddr(t *testing.T, funder, signer *lntest.HarnessNode,
importedAccount string, addrType walletrpc.AddressType) string {
// We'll generate a new address for Carol from Dave's node to receive
// and fund a new channel.
ctxb := context.Background()
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
funderResp, err := funder.NewAddress(ctxt, &lnrpc.NewAddressRequest{
Type: walletToLNAddrType(t, addrType),
Account: importedAccount,
})
require.NoError(t, err)
// Carol also needs to generate the address for the sake of this test to
// be able to sign the channel funding input.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
signerResp, err := signer.NewAddress(ctxt, &lnrpc.NewAddressRequest{
Type: walletToLNAddrType(t, addrType),
})
require.NoError(t, err)
// Sanity check that the generated addresses match.
require.Equal(t, funderResp.Address, signerResp.Address)
assertExternalAddrType(t, funderResp.Address, addrType)
return funderResp.Address
}
// assertExternalAddrType asserts that an external address generated for an
// imported account is of the expected type.
func assertExternalAddrType(t *testing.T, addrStr string,
accountAddrType walletrpc.AddressType) {
addr, err := btcutil.DecodeAddress(addrStr, harnessNetParams)
require.NoError(t, err)
switch accountAddrType {
case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
require.IsType(t, addr, &btcutil.AddressWitnessPubKeyHash{})
case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
require.IsType(t, addr, &btcutil.AddressScriptHash{})
default:
t.Fatalf("unsupported account addr type %v", accountAddrType)
}
}
// assertOutputScriptType asserts that a transaction's output, indicated by the
// output with the given amount, has a script of the expected type. This assumes
// all transaction outputs have unique amounts.
func assertOutputScriptType(t *testing.T, expType txscript.ScriptClass,
tx *wire.MsgTx, outputAmt int64) {
for _, txOut := range tx.TxOut {
if txOut.Value != outputAmt {
continue
}
pkScript, err := txscript.ParsePkScript(txOut.PkScript)
require.NoError(t, err)
require.Equal(t, expType, pkScript.Class())
return
}
// No output with the given amount was found.
t.Fatalf("output with amount %v not found in transaction %v", outputAmt,
spew.Sdump(tx))
}
// assertAccountBalance asserts that the unconfirmed and confirmed balance for
// the given account is satisfied by the WalletBalance and ListUnspent RPCs. The
// unconfirmed balance is not checked for neutrino nodes.
func assertAccountBalance(t *testing.T, node *lntest.HarnessNode, account string,
confirmedBalance, unconfirmedBalance int64) {
err := wait.NoError(func() error {
balanceResp, err := node.WalletBalance(
context.Background(), &lnrpc.WalletBalanceRequest{},
)
if err != nil {
return err
}
require.Contains(t, balanceResp.AccountBalance, account)
accountBalance := balanceResp.AccountBalance[account]
// Check confirmed balance.
if accountBalance.ConfirmedBalance != confirmedBalance {
return fmt.Errorf("expected confirmed balance %v, "+
"got %v", confirmedBalance,
accountBalance.ConfirmedBalance)
}
listUtxosReq := &lnrpc.ListUnspentRequest{
MinConfs: 1,
MaxConfs: math.MaxInt32,
Account: account,
}
confirmedUtxosResp, err := node.ListUnspent(
context.Background(), listUtxosReq,
)
if err != nil {
return err
}
var totalConfirmedVal int64
for _, utxo := range confirmedUtxosResp.Utxos {
totalConfirmedVal += utxo.AmountSat
}
if totalConfirmedVal != confirmedBalance {
return fmt.Errorf("expected total confirmed utxo "+
"balance %v, got %v", confirmedBalance,
totalConfirmedVal)
}
// Skip unconfirmed balance checks for neutrino nodes.
if node.Cfg.BackendCfg.Name() == lntest.NeutrinoBackendName {
return nil
}
// Check unconfirmed balance.
if accountBalance.UnconfirmedBalance != unconfirmedBalance {
return fmt.Errorf("expected unconfirmed balance %v, "+
"got %v", unconfirmedBalance,
accountBalance.UnconfirmedBalance)
}
listUtxosReq.MinConfs = 0
listUtxosReq.MaxConfs = 0
unconfirmedUtxosResp, err := node.ListUnspent(
context.Background(), listUtxosReq,
)
require.NoError(t, err)
var totalUnconfirmedVal int64
for _, utxo := range unconfirmedUtxosResp.Utxos {
totalUnconfirmedVal += utxo.AmountSat
}
if totalUnconfirmedVal != unconfirmedBalance {
return fmt.Errorf("expected total unconfirmed utxo "+
"balance %v, got %v", unconfirmedBalance,
totalUnconfirmedVal)
}
return nil
}, defaultTimeout)
require.NoError(t, err)
}
// psbtSendFromImportedAccount attempts to fund a PSBT from the given imported
// account, originating from the source node to the destination.
func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
signer *lntest.HarnessNode, account string,
accountAddrType walletrpc.AddressType) {
ctxb := context.Background()
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balanceResp, err := srcNode.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
require.NoError(t.t, err)
require.Contains(t.t, balanceResp.AccountBalance, account)
confBalance := balanceResp.AccountBalance[account].ConfirmedBalance
destAmt := confBalance - 10000
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
destAddrResp, err := destNode.NewAddress(ctxt, &lnrpc.NewAddressRequest{
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
})
require.NoError(t.t, err)
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
fundReq := &walletrpc.FundPsbtRequest{
Template: &walletrpc.FundPsbtRequest_Raw{
Raw: &walletrpc.TxTemplate{
Outputs: map[string]uint64{
destAddrResp.Address: uint64(destAmt),
},
},
},
Fees: &walletrpc.FundPsbtRequest_SatPerVbyte{
SatPerVbyte: 1,
},
Account: account,
}
fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq)
require.NoError(t.t, err)
// Have Carol sign the PSBT input since Dave doesn't have any private
// key information.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
finalizeReq := &walletrpc.FinalizePsbtRequest{
FundedPsbt: fundResp.FundedPsbt,
}
finalizeResp, err := signer.WalletKitClient.FinalizePsbt(ctxt, finalizeReq)
require.NoError(t.t, err)
// With the PSBT signed, we can broadcast the resulting transaction.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
publishReq := &walletrpc.Transaction{
TxHex: finalizeResp.RawFinalTx,
}
_, err = srcNode.WalletKitClient.PublishTransaction(ctxt, publishReq)
require.NoError(t.t, err)
// Carol's balance from Dave's perspective should update accordingly.
var (
expTxFee int64
expChangeScriptType txscript.ScriptClass
)
switch accountAddrType {
case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
expTxFee = 141
expChangeScriptType = txscript.WitnessV0PubKeyHashTy
case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH:
if account != defaultImportedAccount {
expTxFee = 165
expChangeScriptType = txscript.ScriptHashTy
break
}
// Spends from the default NP2WKH imported account have the same
// fee rate as the hybrid address type since a NP2WKH input is
// spent and a P2WKH change output is created.
fallthrough
case walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
expTxFee = 164
expChangeScriptType = txscript.WitnessV0PubKeyHashTy
default:
t.Fatalf("unsupported addr type %v", accountAddrType)
}
changeUtxoAmt := confBalance - destAmt - expTxFee
// If the transaction was created from the default imported account,
// then any change produced is moved to the default wallet account.
accountWithBalance := account
if account == defaultImportedAccount {
accountWithBalance = defaultAccount
}
assertAccountBalance(t.t, srcNode, accountWithBalance, 0, changeUtxoAmt)
_ = mineBlocks(t, t.lndHarness, 1, 1)
assertAccountBalance(t.t, srcNode, accountWithBalance, changeUtxoAmt, 0)
// Finally, assert that the transaction has the expected change address
// type based on the account.
var tx wire.MsgTx
err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
require.NoError(t.t, err)
assertOutputScriptType(t.t, expChangeScriptType, &tx, changeUtxoAmt)
}
// fundChanAndCloseFromImportedAccount attempts to a fund a channel from the
// given imported account, originating from the source node to the destination
// node. To ensure the channel is operational before closing it, a test payment
// is made. Several balance assertions are made along the way for the sake of
// correctness.
func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
signer *lntest.HarnessNode, account string,
accountAddrType walletrpc.AddressType, utxoAmt, chanSize int64) {
ctxb := context.Background()
// Retrieve the current confirmed balance to make some assertions later
// on.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balanceResp, err := srcNode.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
require.NoError(t.t, err)
require.Contains(t.t, balanceResp.AccountBalance, account)
accountConfBalance := balanceResp.
AccountBalance[account].ConfirmedBalance
defaultAccountConfBalance := balanceResp.
AccountBalance[defaultAccount].ConfirmedBalance
// Now, start the channel funding process. We'll need to connect both
// nodes first.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
err = t.lndHarness.EnsureConnected(ctxt, srcNode, destNode)
require.NoError(t.t, err)
// The source node will then fund the channel through a PSBT shim.
var pendingChanID [32]byte
_, err = rand.Read(pendingChanID[:])
require.NoError(t.t, err)
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates, rawPsbt, err := openChannelPsbt(
ctxt, srcNode, destNode, lntest.OpenChannelParams{
Amt: btcutil.Amount(chanSize),
FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{
PsbtShim: &lnrpc.PsbtShim{
PendingChanId: pendingChanID[:],
},
},
},
},
)
require.NoError(t.t, err)
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
fundReq := &walletrpc.FundPsbtRequest{
Template: &walletrpc.FundPsbtRequest_Psbt{
Psbt: rawPsbt,
},
Fees: &walletrpc.FundPsbtRequest_SatPerVbyte{
SatPerVbyte: 1,
},
Account: account,
}
fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq)
require.NoError(t.t, err)
_, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{
PsbtVerify: &lnrpc.FundingPsbtVerify{
PendingChanId: pendingChanID[:],
FundedPsbt: fundResp.FundedPsbt,
},
},
})
require.NoError(t.t, err)
// Now that we have a PSBT to fund the channel, our signer needs to sign
// it.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
finalizeReq := &walletrpc.FinalizePsbtRequest{
FundedPsbt: fundResp.FundedPsbt,
}
finalizeResp, err := signer.WalletKitClient.FinalizePsbt(ctxt, finalizeReq)
require.NoError(t.t, err)
// The source node can then submit the signed PSBT and complete the
// channel funding process.
_, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{
PsbtFinalize: &lnrpc.FundingPsbtFinalize{
PendingChanId: pendingChanID[:],
SignedPsbt: finalizeResp.SignedPsbt,
},
},
})
require.NoError(t.t, err)
// We should receive a notification of the channel funding transaction
// being broadcast.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
require.NoError(t.t, err)
upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
require.True(t.t, ok)
// Mine enough blocks to announce the channel to the network, making
// balance assertions along the way.
var (
expChanTxFee int64
expChangeScriptType txscript.ScriptClass
)
switch accountAddrType {
case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
expChanTxFee = 153
expChangeScriptType = txscript.WitnessV0PubKeyHashTy
case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH:
if account != defaultImportedAccount {
expChanTxFee = 177
expChangeScriptType = txscript.ScriptHashTy
break
}
// Spends from the default NP2WKH imported account have the same
// fee rate as the hybrid address type since a NP2WKH input is
// spent and a P2WKH change output is created.
fallthrough
case walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
expChanTxFee = 176
expChangeScriptType = txscript.WitnessV0PubKeyHashTy
default:
t.Fatalf("unsupported addr type %v", accountAddrType)
}
chanChangeUtxoAmt := utxoAmt - chanSize - expChanTxFee
txHash, err := chainhash.NewHash(upd.ChanPending.Txid)
require.NoError(t.t, err)
// If we're spending from the default imported account, then any change
// outputs produced are moved to the default wallet account, so we
// should expect to see balances there.
var confBalanceAfterChan int64
if account == defaultImportedAccount {
confBalanceAfterChan = defaultAccountConfBalance
assertAccountBalance(t.t, srcNode, account, 0, 0)
assertAccountBalance(
t.t, srcNode, defaultAccount, defaultAccountConfBalance,
chanChangeUtxoAmt,
)
block := mineBlocks(t, t.lndHarness, 6, 1)[0]
assertTxInBlock(t, block, txHash)
confBalanceAfterChan += chanChangeUtxoAmt
assertAccountBalance(t.t, srcNode, account, 0, 0)
assertAccountBalance(
t.t, srcNode, defaultAccount, confBalanceAfterChan, 0,
)
} else {
// Otherwise, all interactions remain within Carol's imported
// account.
confBalanceAfterChan = accountConfBalance - utxoAmt
assertAccountBalance(
t.t, srcNode, account, confBalanceAfterChan,
chanChangeUtxoAmt,
)
block := mineBlocks(t, t.lndHarness, 6, 1)[0]
assertTxInBlock(t, block, txHash)
confBalanceAfterChan += chanChangeUtxoAmt
assertAccountBalance(
t.t, srcNode, account, confBalanceAfterChan, 0,
)
}
// Assert that the transaction has the expected change address type
// based on the account.
var tx wire.MsgTx
err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
require.NoError(t.t, err)
assertOutputScriptType(t.t, expChangeScriptType, &tx, chanChangeUtxoAmt)
// Wait for the channel to be announced by both parties.
chanPoint := &lnrpc.ChannelPoint{
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
FundingTxidBytes: upd.ChanPending.Txid,
},
OutputIndex: upd.ChanPending.OutputIndex,
}
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
err = srcNode.WaitForNetworkChannelOpen(ctxt, chanPoint)
require.NoError(t.t, err)
err = destNode.WaitForNetworkChannelOpen(ctxt, chanPoint)
require.NoError(t.t, err)
// Send a test payment to ensure the channel is operating as normal.
const invoiceAmt = 100000
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
resp, err := destNode.AddInvoice(ctxt, &lnrpc.Invoice{
Memo: "psbt import chan",
Value: invoiceAmt,
})
require.NoError(t.t, err)
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
err = completePaymentRequests(
ctxt, srcNode, srcNode.RouterClient,
[]string{resp.PaymentRequest}, true,
)
require.NoError(t.t, err)
// Now that we've confirmed the opened channel works, we'll close it.
ctxt, cancel = context.WithTimeout(ctxb, channelCloseTimeout)
defer cancel()
closeChannelAndAssert(ctxt, t, t.lndHarness, srcNode, chanPoint, false)
// Since the channel still had funds left on the source node's side,
// they must've been redeemed after the close. Without a pre-negotiated
// close address, the funds will go into the source node's wallet
// instead of the imported account.
const chanCloseTxFee = 9050
balanceFromClosedChan := chanSize - invoiceAmt - chanCloseTxFee
if account == defaultImportedAccount {
assertAccountBalance(t.t, srcNode, account, 0, 0)
assertAccountBalance(
t.t, srcNode, defaultAccount,
confBalanceAfterChan+balanceFromClosedChan, 0,
)
} else {
assertAccountBalance(
t.t, srcNode, account, confBalanceAfterChan, 0,
)
assertAccountBalance(
t.t, srcNode, defaultAccount, balanceFromClosedChan, 0,
)
}
}
// testWalletImportAccount tests that an imported account can fund transactions
// and channels through PSBTs, by having one node (the one with the imported
// account) craft the transactions and another node act as the signer.
func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) {
testCases := []struct {
name string
addrType walletrpc.AddressType
}{
{
name: "standard BIP-0049",
addrType: walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
},
{
name: "lnd BIP-0049 variant",
addrType: walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH,
},
{
name: "standard BIP-0084",
addrType: walletrpc.AddressType_WITNESS_PUBKEY_HASH,
},
}
for _, tc := range testCases {
tc := tc
success := t.t.Run(tc.name, func(tt *testing.T) {
ht := newHarnessTest(tt, net)
ht.RunTestCase(&testCase{
name: tc.name,
test: func(net1 *lntest.NetworkHarness, t1 *harnessTest) {
testWalletImportAccountScenario(
net, t, tc.addrType,
)
},
})
})
if !success {
// Log failure time to help relate the lnd logs to the
// failure.
t.Logf("Failure time: %v", time.Now().Format(
"2006-01-02 15:04:05.000",
))
break
}
}
}
func testWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest,
addrType walletrpc.AddressType) {
ctxb := context.Background()
const utxoAmt int64 = btcutil.SatoshiPerBitcoin
// We'll start our test by having two nodes, Carol and Dave. Carol's
// default wallet account will be imported into Dave's node.
carol, err := net.NewNode("carol", nil)
require.NoError(t.t, err)
defer shutdownAndAssert(net, t, carol)
dave, err := net.NewNode("dave", nil)
require.NoError(t.t, err)
defer shutdownAndAssert(net, t, dave)
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
listReq := &walletrpc.ListAccountsRequest{
Name: "default",
AddressType: addrType,
}
listResp, err := carol.WalletKitClient.ListAccounts(ctxt, listReq)
require.NoError(t.t, err)
require.Equal(t.t, len(listResp.Accounts), 1)
carolAccount := listResp.Accounts[0]
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
const importedAccount = "carol"
importReq := &walletrpc.ImportAccountRequest{
Name: importedAccount,
ExtendedPublicKey: carolAccount.ExtendedPublicKey,
AddressType: addrType,
}
_, err = dave.WalletKitClient.ImportAccount(ctxt, importReq)
require.NoError(t.t, err)
// We'll generate an address for Carol from Dave's node to receive some
// funds.
externalAddr := newExternalAddr(
t.t, dave, carol, importedAccount, addrType,
)
// Send coins to Carol's address and confirm them, making sure the
// balance updates accordingly.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
Addr: externalAddr,
Amount: utxoAmt,
SatPerByte: 1,
})
require.NoError(t.t, err)
assertAccountBalance(t.t, dave, importedAccount, 0, utxoAmt)
_ = mineBlocks(t, net, 1, 1)
assertAccountBalance(t.t, dave, importedAccount, utxoAmt, 0)
// To ensure that Dave can use Carol's account as watch-only, we'll
// construct a PSBT that sends funds to Alice, which we'll then hand
// over to Carol to sign.
psbtSendFromImportedAccount(
t, dave, net.Alice, carol, importedAccount, addrType,
)
// We'll generate a new address for Carol from Dave's node to receive
// and fund a new channel.
externalAddr = newExternalAddr(
t.t, dave, carol, importedAccount, addrType,
)
// Retrieve the current confirmed balance of the imported account for
// some assertions we'll make later on.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balanceResp, err := dave.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
require.NoError(t.t, err)
require.Contains(t.t, balanceResp.AccountBalance, importedAccount)
confBalance := balanceResp.AccountBalance[importedAccount].ConfirmedBalance
// Send coins to Carol's address and confirm them, making sure the
// balance updates accordingly.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
Addr: externalAddr,
Amount: utxoAmt,
SatPerByte: 1,
})
require.NoError(t.t, err)
assertAccountBalance(t.t, dave, importedAccount, confBalance, utxoAmt)
_ = mineBlocks(t, net, 1, 1)
assertAccountBalance(
t.t, dave, importedAccount, confBalance+utxoAmt, 0,
)
// Now that we have enough funds, it's time to fund the channel, make a
// test payment, and close it. This contains several balance assertions
// along the way.
fundChanAndCloseFromImportedAccount(
t, dave, net.Alice, carol, importedAccount, addrType, utxoAmt,
int64(funding.MaxBtcFundingAmount),
)
}
// testWalletImportPubKey tests that an imported public keys can fund
// transactions and channels through PSBTs, by having one node (the one with the
// imported account) craft the transactions and another node act as the signer.
func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) {
testCases := []struct {
name string
addrType walletrpc.AddressType
}{
{
name: "BIP-0049",
addrType: walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
},
{
name: "BIP-0084",
addrType: walletrpc.AddressType_WITNESS_PUBKEY_HASH,
},
}
for _, tc := range testCases {
tc := tc
success := t.t.Run(tc.name, func(tt *testing.T) {
ht := newHarnessTest(tt, net)
ht.RunTestCase(&testCase{
name: tc.name,
test: func(net1 *lntest.NetworkHarness, t1 *harnessTest) {
testWalletImportPubKeyScenario(
net, t, tc.addrType,
)
},
})
})
if !success {
// Log failure time to help relate the lnd logs to the
// failure.
t.Logf("Failure time: %v", time.Now().Format(
"2006-01-02 15:04:05.000",
))
break
}
}
}
func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
addrType walletrpc.AddressType) {
ctxb := context.Background()
const utxoAmt int64 = btcutil.SatoshiPerBitcoin
// We'll start our test by having two nodes, Carol and Dave.
carol, err := net.NewNode("carol", nil)
require.NoError(t.t, err)
defer shutdownAndAssert(net, t, carol)
dave, err := net.NewNode("dave", nil)
require.NoError(t.t, err)
defer shutdownAndAssert(net, t, dave)
// We'll define a helper closure that we'll use throughout the test to
// generate a new address of the given type from Carol's perspective,
// import it into Dave's wallet, and fund it.
importPubKey := func(keyIndex uint32, prevConfBalance, prevUnconfBalance int64) {
// Retrieve Carol's account public key for the corresponding
// address type.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
listReq := &walletrpc.ListAccountsRequest{
Name: "default",
AddressType: addrType,
}
listResp, err := carol.WalletKitClient.ListAccounts(ctxt, listReq)
require.NoError(t.t, err)
require.Equal(t.t, len(listResp.Accounts), 1)
p2wkhAccount := listResp.Accounts[0]
// Derive the external address at the given index.
accountPubKey, err := hdkeychain.NewKeyFromString(
p2wkhAccount.ExtendedPublicKey,
)
require.NoError(t.t, err)
externalAccountExtKey, err := accountPubKey.Derive(0)
require.NoError(t.t, err)
externalAddrExtKey, err := externalAccountExtKey.Derive(keyIndex)
require.NoError(t.t, err)
externalAddrPubKey, err := externalAddrExtKey.ECPubKey()
require.NoError(t.t, err)
// Import the public key into Dave.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
importReq := &walletrpc.ImportPublicKeyRequest{
PublicKey: externalAddrPubKey.SerializeCompressed(),
AddressType: addrType,
}
_, err = dave.WalletKitClient.ImportPublicKey(ctxt, importReq)
require.NoError(t.t, err)
// We'll also generate the same address for Carol, as it'll be
// required later when signing.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
carolAddrResp, err := carol.NewAddress(ctxt, &lnrpc.NewAddressRequest{
Type: walletToLNAddrType(t.t, addrType),
})
require.NoError(t.t, err)
// Send coins to Carol's address and confirm them, making sure
// the balance updates accordingly.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
Addr: carolAddrResp.Address,
Amount: utxoAmt,
SatPerByte: 1,
})
require.NoError(t.t, err)
assertAccountBalance(
t.t, dave, defaultImportedAccount, prevConfBalance,
prevUnconfBalance+utxoAmt,
)
_ = mineBlocks(t, net, 1, 1)
assertAccountBalance(
t.t, dave, defaultImportedAccount,
prevConfBalance+utxoAmt, prevUnconfBalance,
)
}
// We'll have Carol generate a new external address, which we'll import
// into Dave.
importPubKey(0, 0, 0)
// To ensure that Dave can use Carol's public key as watch-only, we'll
// construct a PSBT that sends funds to Alice, which we'll then hand
// over to Carol to sign.
psbtSendFromImportedAccount(
t, dave, net.Alice, carol, defaultImportedAccount, addrType,
)
// We'll now attempt to fund a channel.
//
// We'll have Carol generate another external address, which we'll
// import into Dave again.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balanceResp, err := dave.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
require.NoError(t.t, err)
require.Contains(t.t, balanceResp.AccountBalance, defaultImportedAccount)
confBalance := balanceResp.
AccountBalance[defaultImportedAccount].ConfirmedBalance
importPubKey(1, confBalance, 0)
// Now that we have enough funds, it's time to fund the channel, make a
// test payment, and close it. This contains several balance assertions
// along the way.
fundChanAndCloseFromImportedAccount(
t, dave, net.Alice, carol, defaultImportedAccount, addrType,
utxoAmt, int64(funding.MaxBtcFundingAmount),
)
}

@ -206,7 +206,7 @@ func mineBlocks(t *harnessTest, net *lntest.NetworkHarness,
var err error var err error
if numTxs > 0 { if numTxs > 0 {
txids, err = waitForNTxsInMempool( txids, err = waitForNTxsInMempool(
net.Miner.Node, numTxs, minerMempoolTimeout, net.Miner.Client, numTxs, minerMempoolTimeout,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find txns in mempool: %v", err) t.Fatalf("unable to find txns in mempool: %v", err)
@ -215,13 +215,13 @@ func mineBlocks(t *harnessTest, net *lntest.NetworkHarness,
blocks := make([]*wire.MsgBlock, num) blocks := make([]*wire.MsgBlock, num)
blockHashes, err := net.Miner.Node.Generate(num) blockHashes, err := net.Miner.Client.Generate(num)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
for i, blockHash := range blockHashes { for i, blockHash := range blockHashes {
block, err := net.Miner.Node.GetBlock(blockHash) block, err := net.Miner.Client.GetBlock(blockHash)
if err != nil { if err != nil {
t.Fatalf("unable to get block: %v", err) t.Fatalf("unable to get block: %v", err)
} }

@ -10,7 +10,9 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcutil/psbt" "github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet/txauthor" "github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/btcsuite/btcwallet/wtxmgr" "github.com/btcsuite/btcwallet/wtxmgr"
@ -52,13 +54,14 @@ func (w *WalletController) FetchInputInfo(
} }
// ConfirmedBalance currently returns dummy values. // ConfirmedBalance currently returns dummy values.
func (w *WalletController) ConfirmedBalance(confs int32) (btcutil.Amount, error) { func (w *WalletController) ConfirmedBalance(confs int32,
_ string) (btcutil.Amount, error) {
return 0, nil return 0, nil
} }
// NewAddress is called to get new addresses for delivery, change etc. // NewAddress is called to get new addresses for delivery, change etc.
func (w *WalletController) NewAddress(addrType lnwallet.AddressType, func (w *WalletController) NewAddress(addrType lnwallet.AddressType,
change bool) (btcutil.Address, error) { change bool, _ string) (btcutil.Address, error) {
addr, _ := btcutil.NewAddressPubKey( addr, _ := btcutil.NewAddressPubKey(
w.RootKey.PubKey().SerializeCompressed(), &chaincfg.MainNetParams, w.RootKey.PubKey().SerializeCompressed(), &chaincfg.MainNetParams,
@ -67,8 +70,8 @@ func (w *WalletController) NewAddress(addrType lnwallet.AddressType,
} }
// LastUnusedAddress currently returns dummy values. // LastUnusedAddress currently returns dummy values.
func (w *WalletController) LastUnusedAddress(addrType lnwallet.AddressType) ( func (w *WalletController) LastUnusedAddress(addrType lnwallet.AddressType,
btcutil.Address, error) { _ string) (btcutil.Address, error) {
return nil, nil return nil, nil
} }
@ -77,6 +80,24 @@ func (w *WalletController) IsOurAddress(a btcutil.Address) bool {
return false return false
} }
// ListAccounts currently returns a dummy value.
func (w *WalletController) ListAccounts(_ string,
_ *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties, error) {
return nil, nil
}
// ImportAccount currently returns a dummy value.
func (w *WalletController) ImportAccount(string, *hdkeychain.ExtendedKey,
uint32, *waddrmgr.AddressType) error {
return nil
}
// ImportPublicKey currently returns a dummy value.
func (w *WalletController) ImportPublicKey(*btcec.PublicKey,
waddrmgr.AddressType) error {
return nil
}
// SendOutputs currently returns dummy values. // SendOutputs currently returns dummy values.
func (w *WalletController) SendOutputs(outputs []*wire.TxOut, func (w *WalletController) SendOutputs(outputs []*wire.TxOut,
_ chainfee.SatPerKWeight, _ int32, _ string) (*wire.MsgTx, error) { _ chainfee.SatPerKWeight, _ int32, _ string) (*wire.MsgTx, error) {
@ -94,7 +115,7 @@ func (w *WalletController) CreateSimpleTx(outputs []*wire.TxOut,
// ListUnspentWitness is called by the wallet when doing coin selection. We just // ListUnspentWitness is called by the wallet when doing coin selection. We just
// need one unspent for the funding transaction. // need one unspent for the funding transaction.
func (w *WalletController) ListUnspentWitness(minconfirms, func (w *WalletController) ListUnspentWitness(minconfirms,
maxconfirms int32) ([]*lnwallet.Utxo, error) { maxconfirms int32, _ string) ([]*lnwallet.Utxo, error) {
// If the mock already has a list of utxos, return it. // If the mock already has a list of utxos, return it.
if w.Utxos != nil { if w.Utxos != nil {
@ -119,7 +140,7 @@ func (w *WalletController) ListUnspentWitness(minconfirms,
// ListTransactionDetails currently returns dummy values. // ListTransactionDetails currently returns dummy values.
func (w *WalletController) ListTransactionDetails(_, func (w *WalletController) ListTransactionDetails(_,
_ int32) ([]*lnwallet.TransactionDetail, error) { _ int32, _ string) ([]*lnwallet.TransactionDetail, error) {
return nil, nil return nil, nil
} }
@ -148,13 +169,13 @@ func (w *WalletController) ListLeasedOutputs() ([]*wtxmgr.LockedOutput, error) {
// FundPsbt currently does nothing. // FundPsbt currently does nothing.
func (w *WalletController) FundPsbt(_ *psbt.Packet, func (w *WalletController) FundPsbt(_ *psbt.Packet,
_ chainfee.SatPerKWeight) (int32, error) { _ chainfee.SatPerKWeight, _ string) (int32, error) {
return 0, nil return 0, nil
} }
// FinalizePsbt currently does nothing. // FinalizePsbt currently does nothing.
func (w *WalletController) FinalizePsbt(_ *psbt.Packet) error { func (w *WalletController) FinalizePsbt(_ *psbt.Packet, _ string) error {
return nil return nil
} }

@ -39,7 +39,7 @@ func (b NeutrinoBackendConfig) DisconnectMiner() error {
// Name returns the name of the backend type. // Name returns the name of the backend type.
func (b NeutrinoBackendConfig) Name() string { func (b NeutrinoBackendConfig) Name() string {
return "neutrino" return NeutrinoBackendName
} }
// NewBackend starts and returns a NeutrinoBackendConfig for the node. // NewBackend starts and returns a NeutrinoBackendConfig for the node.

@ -57,6 +57,9 @@ const (
// listenerFormat is the format string that is used to generate local // listenerFormat is the format string that is used to generate local
// listener addresses. // listener addresses.
listenerFormat = "127.0.0.1:%d" listenerFormat = "127.0.0.1:%d"
// NeutrinoBackendName is the name of the neutrino backend.
NeutrinoBackendName = "neutrino"
) )
var ( var (

@ -3,16 +3,19 @@ package btcwallet
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"math" "math"
"sync" "sync"
"time" "time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcutil/psbt" "github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/chain" "github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/waddrmgr"
@ -28,6 +31,7 @@ import (
const ( const (
defaultAccount = uint32(waddrmgr.DefaultAccountNum) defaultAccount = uint32(waddrmgr.DefaultAccountNum)
importedAccount = uint32(waddrmgr.ImportedAddrAccount)
// UnconfirmedHeight is the special case end height that is used to // UnconfirmedHeight is the special case end height that is used to
// obtain unconfirmed transactions from ListTransactionDetails. // obtain unconfirmed transactions from ListTransactionDetails.
@ -46,6 +50,11 @@ var (
ExternalAddrType: waddrmgr.WitnessPubKey, ExternalAddrType: waddrmgr.WitnessPubKey,
InternalAddrType: waddrmgr.WitnessPubKey, InternalAddrType: waddrmgr.WitnessPubKey,
} }
// errNoImportedAddrGen is an error returned when a new address is
// requested for the default imported account within the wallet.
errNoImportedAddrGen = errors.New("addresses cannot be generated for " +
"the default imported account")
) )
// BtcWallet is an implementation of the lnwallet.WalletController interface // BtcWallet is an implementation of the lnwallet.WalletController interface
@ -216,13 +225,19 @@ func (b *BtcWallet) Stop() error {
// ConfirmedBalance returns the sum of all the wallet's unspent outputs that // ConfirmedBalance returns the sum of all the wallet's unspent outputs that
// have at least confs confirmations. If confs is set to zero, then all unspent // have at least confs confirmations. If confs is set to zero, then all unspent
// outputs, including those currently in the mempool will be included in the // outputs, including those currently in the mempool will be included in the
// final sum. // final sum. The account parameter serves as a filter to retrieve the balance
// for a specific account. When empty, the confirmed balance of all wallet
// accounts is returned.
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) ConfirmedBalance(confs int32) (btcutil.Amount, error) { func (b *BtcWallet) ConfirmedBalance(confs int32,
accountFilter string) (btcutil.Amount, error) {
var balance btcutil.Amount var balance btcutil.Amount
witnessOutputs, err := b.ListUnspentWitness(confs, math.MaxInt32) witnessOutputs, err := b.ListUnspentWitness(
confs, math.MaxInt32, accountFilter,
)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -237,12 +252,22 @@ func (b *BtcWallet) ConfirmedBalance(confs int32) (btcutil.Amount, error) {
// NewAddress returns the next external or internal address for the wallet // NewAddress returns the next external or internal address for the wallet
// dictated by the value of the `change` parameter. If change is true, then an // dictated by the value of the `change` parameter. If change is true, then an
// internal address will be returned, otherwise an external address should be // internal address will be returned, otherwise an external address should be
// returned. // returned. The account parameter must be non-empty as it determines which
// account the address should be generated from.
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool) (btcutil.Address, error) { func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool,
var keyScope waddrmgr.KeyScope accountName string) (btcutil.Address, error) {
var (
keyScope waddrmgr.KeyScope
account uint32
)
switch accountName {
case waddrmgr.ImportedAddrAccountName:
return nil, errNoImportedAddrGen
case lnwallet.DefaultAccountName:
switch t { switch t {
case lnwallet.WitnessPubKey: case lnwallet.WitnessPubKey:
keyScope = waddrmgr.KeyScopeBIP0084 keyScope = waddrmgr.KeyScopeBIP0084
@ -251,12 +276,20 @@ func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool) (btcutil.Add
default: default:
return nil, fmt.Errorf("unknown address type") return nil, fmt.Errorf("unknown address type")
} }
account = defaultAccount
if change { default:
return b.wallet.NewChangeAddress(defaultAccount, keyScope) var err error
keyScope, account, err = b.wallet.LookupAccount(accountName)
if err != nil {
return nil, err
}
} }
return b.wallet.NewAddress(defaultAccount, keyScope) if change {
return b.wallet.NewChangeAddress(account, keyScope)
}
return b.wallet.NewAddress(account, keyScope)
} }
// LastUnusedAddress returns the last *unused* address known by the wallet. An // LastUnusedAddress returns the last *unused* address known by the wallet. An
@ -264,12 +297,20 @@ func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool) (btcutil.Add
// UIs in order to continually show the "freshest" address without having to // UIs in order to continually show the "freshest" address without having to
// worry about "address inflation" caused by continual refreshing. Similar to // worry about "address inflation" caused by continual refreshing. Similar to
// NewAddress it can derive a specified address type, and also optionally a // NewAddress it can derive a specified address type, and also optionally a
// change address. // change address. The account parameter must be non-empty as it determines
func (b *BtcWallet) LastUnusedAddress(addrType lnwallet.AddressType) ( // which account the address should be generated from.
btcutil.Address, error) { func (b *BtcWallet) LastUnusedAddress(addrType lnwallet.AddressType,
accountName string) (btcutil.Address, error) {
var keyScope waddrmgr.KeyScope var (
keyScope waddrmgr.KeyScope
account uint32
)
switch accountName {
case waddrmgr.ImportedAddrAccountName:
return nil, errNoImportedAddrGen
case lnwallet.DefaultAccountName:
switch addrType { switch addrType {
case lnwallet.WitnessPubKey: case lnwallet.WitnessPubKey:
keyScope = waddrmgr.KeyScopeBIP0084 keyScope = waddrmgr.KeyScopeBIP0084
@ -278,8 +319,17 @@ func (b *BtcWallet) LastUnusedAddress(addrType lnwallet.AddressType) (
default: default:
return nil, fmt.Errorf("unknown address type") return nil, fmt.Errorf("unknown address type")
} }
account = defaultAccount
return b.wallet.CurrentAddress(defaultAccount, keyScope) default:
var err error
keyScope, account, err = b.wallet.LookupAccount(accountName)
if err != nil {
return nil, err
}
}
return b.wallet.CurrentAddress(account, keyScope)
} }
// IsOurAddress checks if the passed address belongs to this wallet // IsOurAddress checks if the passed address belongs to this wallet
@ -290,6 +340,142 @@ func (b *BtcWallet) IsOurAddress(a btcutil.Address) bool {
return result && (err == nil) return result && (err == nil)
} }
// ListAccounts retrieves all accounts belonging to the wallet by default. A
// name and key scope filter can be provided to filter through all of the wallet
// accounts and return only those matching.
//
// This is a part of the WalletController interface.
func (b *BtcWallet) ListAccounts(name string,
keyScope *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties, error) {
var res []*waddrmgr.AccountProperties
switch {
// If both the name and key scope filters were provided, we'll return
// the existing account matching those.
case name != "" && keyScope != nil:
account, err := b.wallet.AccountPropertiesByName(*keyScope, name)
if err != nil {
return nil, err
}
res = append(res, account)
// Only the name filter was provided.
case name != "" && keyScope == nil:
// If the name corresponds to the default or imported accounts,
// we'll return them for both of our supported key scopes.
if name == lnwallet.DefaultAccountName ||
name == waddrmgr.ImportedAddrAccountName {
a1, err := b.wallet.AccountPropertiesByName(
waddrmgr.KeyScopeBIP0049Plus, name,
)
if err != nil {
return nil, err
}
res = append(res, a1)
a2, err := b.wallet.AccountPropertiesByName(
waddrmgr.KeyScopeBIP0084, name,
)
if err != nil {
return nil, err
}
res = append(res, a2)
break
}
// Otherwise, we'll retrieve the single account that's mapped by
// the given name.
scope, acctNum, err := b.wallet.LookupAccount(name)
if err != nil {
return nil, err
}
account, err := b.wallet.AccountProperties(scope, acctNum)
if err != nil {
return nil, err
}
res = append(res, account)
// Only the key scope filter was provided, so we'll return all accounts
// matching it.
case name == "" && keyScope != nil:
accounts, err := b.wallet.Accounts(*keyScope)
if err != nil {
return nil, err
}
for _, account := range accounts.Accounts {
account := account
res = append(res, &account.AccountProperties)
}
// Neither of the filters were provided, so return all accounts for our
// supported key scopes.
case name == "" && keyScope == nil:
accounts, err := b.wallet.Accounts(waddrmgr.KeyScopeBIP0049Plus)
if err != nil {
return nil, err
}
for _, account := range accounts.Accounts {
account := account
res = append(res, &account.AccountProperties)
}
accounts, err = b.wallet.Accounts(waddrmgr.KeyScopeBIP0084)
if err != nil {
return nil, err
}
for _, account := range accounts.Accounts {
account := account
res = append(res, &account.AccountProperties)
}
}
return res, nil
}
// ImportAccount imports an account backed by an account extended public key.
// The master key fingerprint denotes the fingerprint of the root key
// corresponding to the account public key (also known as the key with
// derivation path m/). This may be required by some hardware wallets for proper
// identification and signing.
//
// The address type can usually be inferred from the key's version, but may be
// required for certain keys to map them into the proper scope.
//
// For BIP-0044 keys, an address type must be specified as we intend to not
// support importing BIP-0044 keys into the wallet using the legacy
// pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will force
// the standard BIP-0049 derivation scheme, while a witness address type will
// force the standard BIP-0084 derivation scheme.
//
// For BIP-0049 keys, an address type must also be specified to make a
// distinction between the standard BIP-0049 address schema (nested witness
// pubkeys everywhere) and our own BIP-0049Plus address schema (nested pubkeys
// externally, witness pubkeys internally).
//
// This is a part of the WalletController interface.
func (b *BtcWallet) ImportAccount(name string, accountPubKey *hdkeychain.ExtendedKey,
masterKeyFingerprint uint32, addrType *waddrmgr.AddressType) error {
_, err := b.wallet.ImportAccount(
name, accountPubKey, masterKeyFingerprint, addrType,
)
return err
}
// ImportPublicKey imports a single derived public key into the wallet. The
// address type can usually be inferred from the key's version, but in the case
// of legacy versions (xpub, tpub), an address type must be specified as we
// intend to not support importing BIP-44 keys into the wallet using the legacy
// pay-to-pubkey-hash (P2PKH) scheme.
//
// This is a part of the WalletController interface.
func (b *BtcWallet) ImportPublicKey(pubKey *btcec.PublicKey,
addrType waddrmgr.AddressType) error {
return b.wallet.ImportPublicKey(pubKey, addrType)
}
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying out to // SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying out to
// the specified outputs. In the case the wallet has insufficient funds, or the // the specified outputs. In the case the wallet has insufficient funds, or the
// outputs are non-standard, a non-nil error will be returned. // outputs are non-standard, a non-nil error will be returned.
@ -315,7 +501,7 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
} }
return b.wallet.SendOutputs( return b.wallet.SendOutputs(
outputs, defaultAccount, minconf, feeSatPerKB, label, outputs, nil, defaultAccount, minconf, feeSatPerKB, label,
) )
} }
@ -357,7 +543,9 @@ func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
} }
} }
return b.wallet.CreateSimpleTx(defaultAccount, outputs, 1, feeSatPerKB, dryRun) return b.wallet.CreateSimpleTx(
nil, defaultAccount, outputs, 1, feeSatPerKB, dryRun,
)
} }
// LockOutpoint marks an outpoint as locked meaning it will no longer be deemed // LockOutpoint marks an outpoint as locked meaning it will no longer be deemed
@ -419,16 +607,25 @@ func (b *BtcWallet) ReleaseOutput(id wtxmgr.LockID, op wire.OutPoint) error {
return b.wallet.ReleaseOutput(id, op) return b.wallet.ReleaseOutput(id, op)
} }
// ListUnspentWitness returns a slice of all the unspent outputs the wallet // ListUnspentWitness returns all unspent outputs which are version 0 witness
// controls which pay to witness programs either directly or indirectly. // programs. The 'minconfirms' and 'maxconfirms' parameters indicate the minimum
// and maximum number of confirmations an output needs in order to be returned
// by this method. Passing -1 as 'minconfirms' indicates that even unconfirmed
// outputs should be returned. Using MaxInt32 as 'maxconfirms' implies returning
// all outputs with at least 'minconfirms'. The account parameter serves as a
// filter to retrieve the unspent outputs for a specific account. When empty,
// the unspent outputs of all wallet accounts are returned.
// //
// NOTE: This method requires the global coin selection lock to be held. // NOTE: This method requires the global coin selection lock to be held.
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) ListUnspentWitness(minConfs, maxConfs int32) ( func (b *BtcWallet) ListUnspentWitness(minConfs, maxConfs int32,
[]*lnwallet.Utxo, error) { accountFilter string) ([]*lnwallet.Utxo, error) {
// First, grab all the unfiltered currently unspent outputs. // First, grab all the unfiltered currently unspent outputs.
unspentOutputs, err := b.wallet.ListUnspent(minConfs, maxConfs, nil) unspentOutputs, err := b.wallet.ListUnspent(
minConfs, maxConfs, accountFilter,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -646,14 +843,18 @@ func unminedTransactionsToDetail(
return txDetail, nil return txDetail, nil
} }
// ListTransactionDetails returns a list of all transactions which are // ListTransactionDetails returns a list of all transactions which are relevant
// relevant to the wallet. It takes inclusive start and end height to allow // to the wallet over [startHeight;endHeight]. If start height is greater than
// paginated queries. Unconfirmed transactions can be included in the query // end height, the transactions will be retrieved in reverse order. To include
// by providing endHeight = UnconfirmedHeight (= -1). // unconfirmed transactions, endHeight should be set to the special value -1.
// This will return transactions from the tip of the chain until the start
// height (inclusive) and unconfirmed transactions. The account parameter serves
// as a filter to retrieve the transactions relevant to a specific account. When
// empty, transactions of all wallet accounts are returned.
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) ListTransactionDetails(startHeight, func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
endHeight int32) ([]*lnwallet.TransactionDetail, error) { accountFilter string) ([]*lnwallet.TransactionDetail, error) {
// Grab the best block the wallet knows of, we'll use this to calculate // Grab the best block the wallet knows of, we'll use this to calculate
// # of confirmations shortly below. // # of confirmations shortly below.
@ -663,7 +864,7 @@ func (b *BtcWallet) ListTransactionDetails(startHeight,
// We'll attempt to find all transactions from start to end height. // We'll attempt to find all transactions from start to end height.
start := base.NewBlockIdentifierFromHeight(startHeight) start := base.NewBlockIdentifierFromHeight(startHeight)
stop := base.NewBlockIdentifierFromHeight(endHeight) stop := base.NewBlockIdentifierFromHeight(endHeight)
txns, err := b.wallet.GetTransactions(start, stop, nil) txns, err := b.wallet.GetTransactions(start, stop, accountFilter, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -696,49 +897,99 @@ func (b *BtcWallet) ListTransactionDetails(startHeight,
return txDetails, nil return txDetails, nil
} }
// FundPsbt creates a fully populated PSBT packet that contains enough // FundPsbt creates a fully populated PSBT packet that contains enough inputs to
// inputs to fund the outputs specified in the passed in packet with the // fund the outputs specified in the passed in packet with the specified fee
// specified fee rate. If there is change left, a change output from the // rate. If there is change left, a change output from the internal wallet is
// internal wallet is added and the index of the change output is returned. // added and the index of the change output is returned. Otherwise no additional
// Otherwise no additional output is created and the index -1 is returned. // output is created and the index -1 is returned.
// //
// NOTE: If the packet doesn't contain any inputs, coin selection is // NOTE: If the packet doesn't contain any inputs, coin selection is performed
// performed automatically. If the packet does contain any inputs, it is // automatically. The account parameter must be non-empty as it determines which
// assumed that full coin selection happened externally and no // set of coins are eligible for coin selection. If the packet does contain any
// additional inputs are added. If the specified inputs aren't enough to // inputs, it is assumed that full coin selection happened externally and no
// fund the outputs with the given fee rate, an error is returned. // additional inputs are added. If the specified inputs aren't enough to fund
// No lock lease is acquired for any of the selected/validated inputs. // the outputs with the given fee rate, an error is returned. No lock lease is
// It is in the caller's responsibility to lock the inputs before // acquired for any of the selected/validated inputs. It is in the caller's
// handing them out. // responsibility to lock the inputs before handing them out.
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) FundPsbt(packet *psbt.Packet, func (b *BtcWallet) FundPsbt(packet *psbt.Packet,
feeRate chainfee.SatPerKWeight) (int32, error) { feeRate chainfee.SatPerKWeight, accountName string) (int32, error) {
// The fee rate is passed in using units of sat/kw, so we'll convert // The fee rate is passed in using units of sat/kw, so we'll convert
// this to sat/KB as the CreateSimpleTx method requires this unit. // this to sat/KB as the CreateSimpleTx method requires this unit.
feeSatPerKB := btcutil.Amount(feeRate.FeePerKVByte()) feeSatPerKB := btcutil.Amount(feeRate.FeePerKVByte())
// Let the wallet handle coin selection and/or fee estimation based on var (
// the partial TX information in the packet. keyScope *waddrmgr.KeyScope
return b.wallet.FundPsbt(packet, defaultAccount, feeSatPerKB) accountNum uint32
)
switch accountName {
// If the default/imported account name was specified, we'll provide a
// nil key scope to FundPsbt, allowing it to select inputs from both key
// scopes (NP2WKH, P2WKH).
case lnwallet.DefaultAccountName:
accountNum = defaultAccount
case waddrmgr.ImportedAddrAccountName:
accountNum = importedAccount
// Otherwise, map the account name to its key scope and internal account
// number to only select inputs from said account.
default:
scope, account, err := b.wallet.LookupAccount(accountName)
if err != nil {
return 0, err
}
keyScope = &scope
accountNum = account
} }
// FinalizePsbt expects a partial transaction with all inputs and // Let the wallet handle coin selection and/or fee estimation based on
// outputs fully declared and tries to sign all inputs that belong to // the partial TX information in the packet.
// the wallet. Lnd must be the last signer of the transaction. That return b.wallet.FundPsbt(packet, keyScope, accountNum, feeSatPerKB)
// means, if there are any unsigned non-witness inputs or inputs without }
// UTXO information attached or inputs without witness data that do not
// belong to lnd's wallet, this method will fail. If no error is // FinalizePsbt expects a partial transaction with all inputs and outputs fully
// returned, the PSBT is ready to be extracted and the final TX within // declared and tries to sign all inputs that belong to the specified account.
// to be broadcast. // Lnd must be the last signer of the transaction. That means, if there are any
// unsigned non-witness inputs or inputs without UTXO information attached or
// inputs without witness data that do not belong to lnd's wallet, this method
// will fail. If no error is returned, the PSBT is ready to be extracted and the
// final TX within to be broadcast.
// //
// NOTE: This method does NOT publish the transaction after it's been // NOTE: This method does NOT publish the transaction after it's been
// finalized successfully. // finalized successfully.
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) FinalizePsbt(packet *psbt.Packet) error { func (b *BtcWallet) FinalizePsbt(packet *psbt.Packet, accountName string) error {
return b.wallet.FinalizePsbt(packet) var (
keyScope *waddrmgr.KeyScope
accountNum uint32
)
switch accountName {
// If the default/imported account name was specified, we'll provide a
// nil key scope to FundPsbt, allowing it to sign inputs from both key
// scopes (NP2WKH, P2WKH).
case lnwallet.DefaultAccountName:
accountNum = defaultAccount
case waddrmgr.ImportedAddrAccountName:
accountNum = importedAccount
// Otherwise, map the account name to its key scope and internal account
// number to determine if the inputs belonging to this account should be
// signed.
default:
scope, account, err := b.wallet.LookupAccount(accountName)
if err != nil {
return err
}
keyScope = &scope
accountNum = account
}
return b.wallet.FinalizePsbt(keyScope, accountNum, packet)
} }
// txSubscriptionClient encapsulates the transaction notification client from // txSubscriptionClient encapsulates the transaction notification client from

@ -21,7 +21,7 @@ import (
// //
// This is a part of the WalletController interface. // This is a part of the WalletController interface.
func (b *BtcWallet) FetchInputInfo(prevOut *wire.OutPoint) (*lnwallet.Utxo, error) { func (b *BtcWallet) FetchInputInfo(prevOut *wire.OutPoint) (*lnwallet.Utxo, error) {
_, txOut, confirmations, err := b.wallet.FetchInputInfo(prevOut) _, txOut, _, confirmations, err := b.wallet.FetchInputInfo(prevOut)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,9 +51,10 @@ func deriveFromKeyLoc(scopedMgr *waddrmgr.ScopedKeyManager,
keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) { keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) {
path := waddrmgr.DerivationPath{ path := waddrmgr.DerivationPath{
InternalAccount: uint32(keyLoc.Family),
Account: uint32(keyLoc.Family), Account: uint32(keyLoc.Family),
Branch: 0, Branch: 0,
Index: uint32(keyLoc.Index), Index: keyLoc.Index,
} }
addr, err := scopedMgr.DeriveFromKeyPath(addrmgrNs, path) addr, err := scopedMgr.DeriveFromKeyPath(addrmgrNs, path)
if err != nil { if err != nil {

@ -10,13 +10,21 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcutil/psbt" "github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet/txauthor" "github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/btcsuite/btcwallet/wtxmgr" "github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
) )
const (
// DefaultAccountName is the name for the default account used to manage
// on-chain funds within the wallet.
DefaultAccountName = "default"
)
// AddressType is an enum-like type which denotes the possible address types // AddressType is an enum-like type which denotes the possible address types
// WalletController supports. // WalletController supports.
type AddressType uint8 type AddressType uint8
@ -153,20 +161,24 @@ type WalletController interface {
// ConfirmedBalance returns the sum of all the wallet's unspent outputs // ConfirmedBalance returns the sum of all the wallet's unspent outputs
// that have at least confs confirmations. If confs is set to zero, // that have at least confs confirmations. If confs is set to zero,
// then all unspent outputs, including those currently in the mempool // then all unspent outputs, including those currently in the mempool
// will be included in the final sum. // will be included in the final sum. The account parameter serves as a
// filter to retrieve the balance for a specific account. When empty,
// the confirmed balance of all wallet accounts is returned.
// //
// NOTE: Only witness outputs should be included in the computation of // NOTE: Only witness outputs should be included in the computation of
// the total spendable balance of the wallet. We require this as only // the total spendable balance of the wallet. We require this as only
// witness inputs can be used for funding channels. // witness inputs can be used for funding channels.
ConfirmedBalance(confs int32) (btcutil.Amount, error) ConfirmedBalance(confs int32, accountFilter string) (btcutil.Amount, error)
// NewAddress returns the next external or internal address for the // NewAddress returns the next external or internal address for the
// wallet dictated by the value of the `change` parameter. If change is // wallet dictated by the value of the `change` parameter. If change is
// true, then an internal address should be used, otherwise an external // true, then an internal address should be used, otherwise an external
// address should be returned. The type of address returned is dictated // address should be returned. The type of address returned is dictated
// by the wallet's capabilities, and may be of type: p2sh, p2wkh, // by the wallet's capabilities, and may be of type: p2sh, p2wkh,
// p2wsh, etc. // p2wsh, etc. The account parameter must be non-empty as it determines
NewAddress(addrType AddressType, change bool) (btcutil.Address, error) // which account the address should be generated from.
NewAddress(addrType AddressType, change bool,
account string) (btcutil.Address, error)
// LastUnusedAddress returns the last *unused* address known by the // LastUnusedAddress returns the last *unused* address known by the
// wallet. An address is unused if it hasn't received any payments. // wallet. An address is unused if it hasn't received any payments.
@ -174,11 +186,48 @@ type WalletController interface {
// "freshest" address without having to worry about "address inflation" // "freshest" address without having to worry about "address inflation"
// caused by continual refreshing. Similar to NewAddress it can derive // caused by continual refreshing. Similar to NewAddress it can derive
// a specified address type. By default, this is a non-change address. // a specified address type. By default, this is a non-change address.
LastUnusedAddress(addrType AddressType) (btcutil.Address, error) // The account parameter must be non-empty as it determines which
// account the address should be generated from.
LastUnusedAddress(addrType AddressType,
account string) (btcutil.Address, error)
// IsOurAddress checks if the passed address belongs to this wallet // IsOurAddress checks if the passed address belongs to this wallet
IsOurAddress(a btcutil.Address) bool IsOurAddress(a btcutil.Address) bool
// ListAccounts retrieves all accounts belonging to the wallet by
// default. A name and key scope filter can be provided to filter
// through all of the wallet accounts and return only those matching.
ListAccounts(string, *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties, error)
// ImportAccount imports an account backed by an account extended public
// key. The master key fingerprint denotes the fingerprint of the root
// key corresponding to the account public key (also known as the key
// with derivation path m/). This may be required by some hardware
// wallets for proper identification and signing.
//
// The address type can usually be inferred from the key's version, but
// may be required for certain keys to map them into the proper scope.
//
// For BIP-0044 keys, an address type must be specified as we intend to
// not support importing BIP-0044 keys into the wallet using the legacy
// pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will
// force the standard BIP-0049 derivation scheme, while a witness
// address type will force the standard BIP-0084 derivation scheme.
//
// For BIP-0049 keys, an address type must also be specified to make a
// distinction between the standard BIP-0049 address schema (nested
// witness pubkeys everywhere) and our own BIP-0049Plus address schema
// (nested pubkeys externally, witness pubkeys internally).
ImportAccount(name string, accountPubKey *hdkeychain.ExtendedKey,
masterKeyFingerprint uint32, addrType *waddrmgr.AddressType) error
// ImportPublicKey imports a single derived public key into the wallet.
// The address type can usually be inferred from the key's version, but
// in the case of legacy versions (xpub, tpub), an address type must be
// specified as we intend to not support importing BIP-44 keys into the
// wallet using the legacy pay-to-pubkey-hash (P2PKH) scheme.
ImportPublicKey(pubKey *btcec.PublicKey, addrType waddrmgr.AddressType) error
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying // SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying
// out to the specified outputs. In the case the wallet has insufficient // out to the specified outputs. In the case the wallet has insufficient
// funds, or the outputs are non-standard, an error should be returned. // funds, or the outputs are non-standard, an error should be returned.
@ -210,10 +259,13 @@ type WalletController interface {
// needs in order to be returned by this method. Passing -1 as // needs in order to be returned by this method. Passing -1 as
// 'minconfirms' indicates that even unconfirmed outputs should be // 'minconfirms' indicates that even unconfirmed outputs should be
// returned. Using MaxInt32 as 'maxconfirms' implies returning all // returned. Using MaxInt32 as 'maxconfirms' implies returning all
// outputs with at least 'minconfirms'. // outputs with at least 'minconfirms'. The account parameter serves as
// a filter to retrieve the unspent outputs for a specific account.
// When empty, the unspent outputs of all wallet accounts are returned.
// //
// NOTE: This method requires the global coin selection lock to be held. // NOTE: This method requires the global coin selection lock to be held.
ListUnspentWitness(minconfirms, maxconfirms int32) ([]*Utxo, error) ListUnspentWitness(minconfirms, maxconfirms int32,
accountFilter string) ([]*Utxo, error)
// ListTransactionDetails returns a list of all transactions which are // ListTransactionDetails returns a list of all transactions which are
// relevant to the wallet over [startHeight;endHeight]. If start height // relevant to the wallet over [startHeight;endHeight]. If start height
@ -221,9 +273,11 @@ type WalletController interface {
// reverse order. To include unconfirmed transactions, endHeight should // reverse order. To include unconfirmed transactions, endHeight should
// be set to the special value -1. This will return transactions from // be set to the special value -1. This will return transactions from
// the tip of the chain until the start height (inclusive) and // the tip of the chain until the start height (inclusive) and
// unconfirmed transactions. // unconfirmed transactions. The account parameter serves as a filter to
ListTransactionDetails(startHeight, // retrieve the transactions relevant to a specific account. When
endHeight int32) ([]*TransactionDetail, error) // empty, transactions of all wallet accounts are returned.
ListTransactionDetails(startHeight, endHeight int32,
accountFilter string) ([]*TransactionDetail, error)
// LockOutpoint marks an outpoint as locked meaning it will no longer // LockOutpoint marks an outpoint as locked meaning it will no longer
// be deemed as eligible for coin selection. Locking outputs are // be deemed as eligible for coin selection. Locking outputs are
@ -286,28 +340,29 @@ type WalletController interface {
// is returned. // is returned.
// //
// NOTE: If the packet doesn't contain any inputs, coin selection is // NOTE: If the packet doesn't contain any inputs, coin selection is
// performed automatically. If the packet does contain any inputs, it is // performed automatically. The account parameter must be non-empty as
// assumed that full coin selection happened externally and no // it determines which set of coins are eligible for coin selection. If
// additional inputs are added. If the specified inputs aren't enough to // the packet does contain any inputs, it is assumed that full coin
// fund the outputs with the given fee rate, an error is returned. // selection happened externally and no additional inputs are added. If
// No lock lease is acquired for any of the selected/validated inputs. // the specified inputs aren't enough to fund the outputs with the given
// It is in the caller's responsibility to lock the inputs before // fee rate, an error is returned. No lock lease is acquired for any of
// handing them out. // the selected/validated inputs. It is in the caller's responsibility
FundPsbt(packet *psbt.Packet, feeRate chainfee.SatPerKWeight) (int32, // to lock the inputs before handing them out.
error) FundPsbt(packet *psbt.Packet, feeRate chainfee.SatPerKWeight,
account string) (int32, error)
// FinalizePsbt expects a partial transaction with all inputs and // FinalizePsbt expects a partial transaction with all inputs and
// outputs fully declared and tries to sign all inputs that belong to // outputs fully declared and tries to sign all inputs that belong to
// the wallet. Lnd must be the last signer of the transaction. That // the specified account. Lnd must be the last signer of the
// means, if there are any unsigned non-witness inputs or inputs without // transaction. That means, if there are any unsigned non-witness inputs
// UTXO information attached or inputs without witness data that do not // or inputs without UTXO information attached or inputs without witness
// belong to lnd's wallet, this method will fail. If no error is // data that do not belong to lnd's wallet, this method will fail. If no
// returned, the PSBT is ready to be extracted and the final TX within // error is returned, the PSBT is ready to be extracted and the final TX
// to be broadcast. // within to be broadcast.
// //
// NOTE: This method does NOT publish the transaction after it's been // NOTE: This method does NOT publish the transaction after it's been
// finalized successfully. // finalized successfully.
FinalizePsbt(packet *psbt.Packet) error FinalizePsbt(packet *psbt.Packet, account string) error
// SubscribeTransactions returns a TransactionSubscription client which // SubscribeTransactions returns a TransactionSubscription client which
// is capable of receiving async notifications as new transactions // is capable of receiving async notifications as new transactions

@ -101,7 +101,7 @@ var (
func assertProperBalance(t *testing.T, lw *lnwallet.LightningWallet, func assertProperBalance(t *testing.T, lw *lnwallet.LightningWallet,
numConfirms int32, amount float64) { numConfirms int32, amount float64) {
balance, err := lw.ConfirmedBalance(numConfirms) balance, err := lw.ConfirmedBalance(numConfirms, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to query for balance: %v", err) t.Fatalf("unable to query for balance: %v", err)
} }
@ -130,13 +130,13 @@ func mineAndAssertTxInBlock(t *testing.T, miner *rpctest.Harness,
} }
// We'll mined a block to confirm it. // We'll mined a block to confirm it.
blockHashes, err := miner.Node.Generate(1) blockHashes, err := miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate new block: %v", err) t.Fatalf("unable to generate new block: %v", err)
} }
// Finally, we'll check it was actually mined in this block. // Finally, we'll check it was actually mined in this block.
block, err := miner.Node.GetBlock(blockHashes[0]) block, err := miner.Client.GetBlock(blockHashes[0])
if err != nil { if err != nil {
t.Fatalf("unable to get block %v: %v", blockHashes[0], err) t.Fatalf("unable to get block %v: %v", blockHashes[0], err)
} }
@ -157,7 +157,7 @@ func newPkScript(t *testing.T, w *lnwallet.LightningWallet,
t.Helper() t.Helper()
addr, err := w.NewAddress(addrType, false) addr, err := w.NewAddress(addrType, false, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to create new address: %v", err) t.Fatalf("unable to create new address: %v", err)
} }
@ -208,7 +208,7 @@ func assertTxInWallet(t *testing.T, w *lnwallet.LightningWallet,
// We'll fetch all of our transaction and go through each one until // We'll fetch all of our transaction and go through each one until
// finding the expected transaction with its expected confirmation // finding the expected transaction with its expected confirmation
// status. // status.
txs, err := w.ListTransactionDetails(0, btcwallet.UnconfirmedHeight) txs, err := w.ListTransactionDetails(0, btcwallet.UnconfirmedHeight, "")
if err != nil { if err != nil {
t.Fatalf("unable to retrieve transactions: %v", err) t.Fatalf("unable to retrieve transactions: %v", err)
} }
@ -248,7 +248,7 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
if err != nil { if err != nil {
return fmt.Errorf("unable to create amt: %v", err) return fmt.Errorf("unable to create amt: %v", err)
} }
expectedBalance, err := w.ConfirmedBalance(1) expectedBalance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
return err return err
} }
@ -256,7 +256,10 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
addrs := make([]btcutil.Address, 0, numOutputs) addrs := make([]btcutil.Address, 0, numOutputs)
for i := 0; i < numOutputs; i++ { for i := 0; i < numOutputs; i++ {
// Grab a fresh address from the wallet to house this output. // Grab a fresh address from the wallet to house this output.
walletAddr, err := w.NewAddress(lnwallet.WitnessPubKey, false) walletAddr, err := w.NewAddress(
lnwallet.WitnessPubKey, false,
lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
return err return err
} }
@ -282,7 +285,7 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
// Generate 10 blocks with the mining node, this should mine all // Generate 10 blocks with the mining node, this should mine all
// numOutputs transactions created above. We generate 10 blocks here // numOutputs transactions created above. We generate 10 blocks here
// in order to give all the outputs a "sufficient" number of confirmations. // in order to give all the outputs a "sufficient" number of confirmations.
if _, err := miner.Node.Generate(10); err != nil { if _, err := miner.Client.Generate(10); err != nil {
return err return err
} }
@ -291,7 +294,7 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
timeout := time.After(30 * time.Second) timeout := time.After(30 * time.Second)
for range ticker.C { for range ticker.C {
balance, err := w.ConfirmedBalance(1) balance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
return err return err
} }
@ -380,7 +383,7 @@ func testGetRecoveryInfo(miner *rpctest.Harness,
// Generate 5 blocks and check the recovery process again. // Generate 5 blocks and check the recovery process again.
const numBlocksMined = 5 const numBlocksMined = 5
_, err = miner.Node.Generate(numBlocksMined) _, err = miner.Client.Generate(numBlocksMined)
require.NoError(t, err, "unable to mine blocks") require.NoError(t, err, "unable to mine blocks")
// Check the recovery process. Once synced, the progress should be 1. // Check the recovery process. Once synced, the progress should be 1.
@ -591,11 +594,11 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
blockHashes, err := miner.Node.Generate(1) blockHashes, err := miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
block, err := miner.Node.GetBlock(blockHashes[0]) block, err := miner.Client.GetBlock(blockHashes[0])
if err != nil { if err != nil {
t.Fatalf("unable to find block: %v", err) t.Fatalf("unable to find block: %v", err)
} }
@ -1091,11 +1094,11 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
blockHashes, err := miner.Node.Generate(1) blockHashes, err := miner.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
block, err := miner.Node.GetBlock(blockHashes[0]) block, err := miner.Client.GetBlock(blockHashes[0])
if err != nil { if err != nil {
t.Fatalf("unable to find block: %v", err) t.Fatalf("unable to find block: %v", err)
} }
@ -1138,7 +1141,10 @@ func testListTransactionDetails(miner *rpctest.Harness,
const outputAmt = btcutil.SatoshiPerBitcoin const outputAmt = btcutil.SatoshiPerBitcoin
txids := make(map[chainhash.Hash]struct{}) txids := make(map[chainhash.Hash]struct{})
for i := 0; i < numTxns; i++ { for i := 0; i < numTxns; i++ {
addr, err := alice.NewAddress(lnwallet.WitnessPubKey, false) addr, err := alice.NewAddress(
lnwallet.WitnessPubKey, false,
lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
t.Fatalf("unable to create new address: %v", err) t.Fatalf("unable to create new address: %v", err)
} }
@ -1159,14 +1165,14 @@ func testListTransactionDetails(miner *rpctest.Harness,
} }
// Get the miner's current best block height before we mine blocks. // Get the miner's current best block height before we mine blocks.
_, startHeight, err := miner.Node.GetBestBlock() _, startHeight, err := miner.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("cannot get best block: %v", err) t.Fatalf("cannot get best block: %v", err)
} }
// Generate 10 blocks to mine all the transactions created above. // Generate 10 blocks to mine all the transactions created above.
const numBlocksMined = 10 const numBlocksMined = 10
blocks, err := miner.Node.Generate(numBlocksMined) blocks, err := miner.Client.Generate(numBlocksMined)
if err != nil { if err != nil {
t.Fatalf("unable to mine blocks: %v", err) t.Fatalf("unable to mine blocks: %v", err)
} }
@ -1185,7 +1191,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
t.Fatalf("Couldn't sync Alice's wallet: %v", err) t.Fatalf("Couldn't sync Alice's wallet: %v", err)
} }
txDetails, err := alice.ListTransactionDetails( txDetails, err := alice.ListTransactionDetails(
startHeight, chainTip, startHeight, chainTip, "",
) )
if err != nil { if err != nil {
t.Fatalf("unable to fetch tx details: %v", err) t.Fatalf("unable to fetch tx details: %v", err)
@ -1299,7 +1305,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
// with a confirmation height of 0, indicating that it has not been // with a confirmation height of 0, indicating that it has not been
// mined yet. // mined yet.
txDetails, err = alice.ListTransactionDetails( txDetails, err = alice.ListTransactionDetails(
chainTip, btcwallet.UnconfirmedHeight, chainTip, btcwallet.UnconfirmedHeight, "",
) )
if err != nil { if err != nil {
t.Fatalf("unable to fetch tx details: %v", err) t.Fatalf("unable to fetch tx details: %v", err)
@ -1339,7 +1345,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
// Generate one block for our transaction to confirm in. // Generate one block for our transaction to confirm in.
var numBlocks int32 = 1 var numBlocks int32 = 1
burnBlock, err := miner.Node.Generate(uint32(numBlocks)) burnBlock, err := miner.Client.Generate(uint32(numBlocks))
if err != nil { if err != nil {
t.Fatalf("unable to mine block: %v", err) t.Fatalf("unable to mine block: %v", err)
} }
@ -1355,9 +1361,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("Couldn't sync Alice's wallet: %v", err) t.Fatalf("Couldn't sync Alice's wallet: %v", err)
} }
txDetails, err = alice.ListTransactionDetails( txDetails, err = alice.ListTransactionDetails(chainTip, chainTip, "")
chainTip, chainTip,
)
if err != nil { if err != nil {
t.Fatalf("unable to fetch tx details: %v", err) t.Fatalf("unable to fetch tx details: %v", err)
} }
@ -1392,7 +1396,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
// Generate a block which has no wallet transactions in it. // Generate a block which has no wallet transactions in it.
chainTip += numBlocks chainTip += numBlocks
_, err = miner.Node.Generate(uint32(numBlocks)) _, err = miner.Client.Generate(uint32(numBlocks))
if err != nil { if err != nil {
t.Fatalf("unable to mine block: %v", err) t.Fatalf("unable to mine block: %v", err)
} }
@ -1404,9 +1408,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
// Query for transactions only in the latest block. We do not expect // Query for transactions only in the latest block. We do not expect
// any transactions to be returned. // any transactions to be returned.
txDetails, err = alice.ListTransactionDetails( txDetails, err = alice.ListTransactionDetails(chainTip, chainTip, "")
chainTip, chainTip,
)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@ -1465,7 +1467,10 @@ func testTransactionSubscriptions(miner *rpctest.Harness,
// Next, fetch a fresh address from the wallet, create 3 new outputs // Next, fetch a fresh address from the wallet, create 3 new outputs
// with the pkScript. // with the pkScript.
for i := 0; i < numTxns; i++ { for i := 0; i < numTxns; i++ {
addr, err := alice.NewAddress(lnwallet.WitnessPubKey, false) addr, err := alice.NewAddress(
lnwallet.WitnessPubKey, false,
lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
t.Fatalf("unable to create new address: %v", err) t.Fatalf("unable to create new address: %v", err)
} }
@ -1524,7 +1529,7 @@ func testTransactionSubscriptions(miner *rpctest.Harness,
// Next mine a single block, all the transactions generated above // Next mine a single block, all the transactions generated above
// should be included. // should be included.
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -1607,12 +1612,12 @@ func mineAndAssert(r *rpctest.Harness, tx *wire.MsgTx) error {
return fmt.Errorf("tx not relayed to miner: %v", err) return fmt.Errorf("tx not relayed to miner: %v", err)
} }
blockHashes, err := r.Node.Generate(1) blockHashes, err := r.Client.Generate(1)
if err != nil { if err != nil {
return fmt.Errorf("unable to generate block: %v", err) return fmt.Errorf("unable to generate block: %v", err)
} }
block, err := r.Node.GetBlock(blockHashes[0]) block, err := r.Client.GetBlock(blockHashes[0])
if err != nil { if err != nil {
return fmt.Errorf("unable to find block: %v", err) return fmt.Errorf("unable to find block: %v", err)
} }
@ -1803,7 +1808,7 @@ func testPublishTransaction(r *rpctest.Harness,
} }
// Mine the transaction. // Mine the transaction.
if _, err := r.Node.Generate(1); err != nil { if _, err := r.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -2126,7 +2131,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
// reorganization that doesn't invalidate any existing transactions or // reorganization that doesn't invalidate any existing transactions or
// create any new non-coinbase transactions. We'll then check if it's // create any new non-coinbase transactions. We'll then check if it's
// the same after the empty reorg. // the same after the empty reorg.
_, err := r.Node.Generate(5) _, err := r.Client.Generate(5)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks on passed node: %v", err) t.Fatalf("unable to generate blocks on passed node: %v", err)
} }
@ -2168,7 +2173,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
if err != nil { if err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, err = r.Node.Generate(50) _, err = r.Client.Generate(50)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks on passed node: %v", err) t.Fatalf("unable to generate blocks on passed node: %v", err)
} }
@ -2180,7 +2185,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
} }
// Get the original balance. // Get the original balance.
origBalance, err := w.ConfirmedBalance(1) origBalance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to query for balance: %v", err) t.Fatalf("unable to query for balance: %v", err)
} }
@ -2196,7 +2201,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
t.Fatalf("unable to set up mining node: %v", err) t.Fatalf("unable to set up mining node: %v", err)
} }
defer r2.TearDown() defer r2.TearDown()
newBalance, err := w.ConfirmedBalance(1) newBalance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to query for balance: %v", err) t.Fatalf("unable to query for balance: %v", err)
} }
@ -2207,7 +2212,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
// Step 2: connect the miner to the passed miner and wait for // Step 2: connect the miner to the passed miner and wait for
// synchronization. // synchronization.
err = r2.Node.AddNode(r.P2PAddress(), rpcclient.ANAdd) err = r2.Client.AddNode(r.P2PAddress(), rpcclient.ANAdd)
if err != nil { if err != nil {
t.Fatalf("unable to connect mining nodes together: %v", err) t.Fatalf("unable to connect mining nodes together: %v", err)
} }
@ -2232,12 +2237,12 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
t.Fatalf("timeout waiting for miner disconnect") t.Fatalf("timeout waiting for miner disconnect")
default: default:
} }
err = r2.Node.AddNode(r.P2PAddress(), rpcclient.ANRemove) err = r2.Client.AddNode(r.P2PAddress(), rpcclient.ANRemove)
if err != nil { if err != nil {
t.Fatalf("unable to disconnect mining nodes: %v", t.Fatalf("unable to disconnect mining nodes: %v",
err) err)
} }
peers, err = r2.Node.GetPeerInfo() peers, err = r2.Client.GetPeerInfo()
if err != nil { if err != nil {
t.Fatalf("unable to get peer info: %v", err) t.Fatalf("unable to get peer info: %v", err)
} }
@ -2249,19 +2254,19 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
} }
} }
} }
_, err = r.Node.Generate(2) _, err = r.Client.Generate(2)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks on passed node: %v", t.Fatalf("unable to generate blocks on passed node: %v",
err) err)
} }
_, err = r2.Node.Generate(3) _, err = r2.Client.Generate(3)
if err != nil { if err != nil {
t.Fatalf("unable to generate blocks on created node: %v", t.Fatalf("unable to generate blocks on created node: %v",
err) err)
} }
// Step 5: Reconnect the miners and wait for them to synchronize. // Step 5: Reconnect the miners and wait for them to synchronize.
err = r2.Node.AddNode(r.P2PAddress(), rpcclient.ANAdd) err = r2.Client.AddNode(r.P2PAddress(), rpcclient.ANAdd)
if err != nil { if err != nil {
switch err := err.(type) { switch err := err.(type) {
case *btcjson.RPCError: case *btcjson.RPCError:
@ -2288,7 +2293,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
} }
// Now we check that the wallet balance stays the same. // Now we check that the wallet balance stays the same.
newBalance, err = w.ConfirmedBalance(1) newBalance, err = w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to query for balance: %v", err) t.Fatalf("unable to query for balance: %v", err)
} }
@ -2311,7 +2316,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
// Assuming a balance of 80 BTC and a transaction fee of 2500 sat/kw, // Assuming a balance of 80 BTC and a transaction fee of 2500 sat/kw,
// we'll craft the following transaction so that Alice doesn't have any // we'll craft the following transaction so that Alice doesn't have any
// UTXOs left. // UTXOs left.
aliceBalance, err := alice.ConfirmedBalance(0) aliceBalance, err := alice.ConfirmedBalance(0, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to retrieve alice's balance: %v", err) t.Fatalf("unable to retrieve alice's balance: %v", err)
} }
@ -2336,7 +2341,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
// With the transaction sent and confirmed, Alice's balance should now // With the transaction sent and confirmed, Alice's balance should now
// be 0. // be 0.
aliceBalance, err = alice.ConfirmedBalance(0) aliceBalance, err = alice.ConfirmedBalance(0, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to retrieve alice's balance: %v", err) t.Fatalf("unable to retrieve alice's balance: %v", err)
} }
@ -2392,7 +2397,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
// First we will empty out bob's wallet, sending the entire balance // First we will empty out bob's wallet, sending the entire balance
// to alice. // to alice.
bobBalance, err := bob.ConfirmedBalance(0) bobBalance, err := bob.ConfirmedBalance(0, lnwallet.DefaultAccountName)
if err != nil { if err != nil {
t.Fatalf("unable to retrieve bob's balance: %v", err) t.Fatalf("unable to retrieve bob's balance: %v", err)
} }
@ -2455,7 +2460,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
if err := waitForWalletSync(miner, alice); err != nil { if err := waitForWalletSync(miner, alice); err != nil {
@ -2483,7 +2488,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
func testLastUnusedAddr(miner *rpctest.Harness, func testLastUnusedAddr(miner *rpctest.Harness,
alice, bob *lnwallet.LightningWallet, t *testing.T) { alice, bob *lnwallet.LightningWallet, t *testing.T) {
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Client.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -2493,11 +2498,15 @@ func testLastUnusedAddr(miner *rpctest.Harness,
lnwallet.WitnessPubKey, lnwallet.NestedWitnessPubKey, lnwallet.WitnessPubKey, lnwallet.NestedWitnessPubKey,
} }
for _, addrType := range addrTypes { for _, addrType := range addrTypes {
addr1, err := alice.LastUnusedAddress(addrType) addr1, err := alice.LastUnusedAddress(
addrType, lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
t.Fatalf("unable to get addr: %v", err) t.Fatalf("unable to get addr: %v", err)
} }
addr2, err := alice.LastUnusedAddress(addrType) addr2, err := alice.LastUnusedAddress(
addrType, lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
t.Fatalf("unable to get addr: %v", err) t.Fatalf("unable to get addr: %v", err)
} }
@ -2523,7 +2532,9 @@ func testLastUnusedAddr(miner *rpctest.Harness,
// If we make a new address, then it should be brand new, as // If we make a new address, then it should be brand new, as
// the prior address has been used. // the prior address has been used.
addr3, err := alice.LastUnusedAddress(addrType) addr3, err := alice.LastUnusedAddress(
addrType, lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
t.Fatalf("unable to get addr: %v", err) t.Fatalf("unable to get addr: %v", err)
} }
@ -2895,7 +2906,7 @@ func waitForMempoolTx(r *rpctest.Harness, txid *chainhash.Hash) error {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Check for the harness' knowledge of the txid // Check for the harness' knowledge of the txid
tx, err = r.Node.GetRawTransaction(txid) tx, err = r.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
switch e := err.(type) { switch e := err.(type) {
case *btcjson.RPCError: case *btcjson.RPCError:
@ -2931,7 +2942,7 @@ func waitForWalletSync(r *rpctest.Harness, w *lnwallet.LightningWallet) error {
// Check whether the chain source of the wallet is caught up to // Check whether the chain source of the wallet is caught up to
// the harness it's supposed to be catching up to. // the harness it's supposed to be catching up to.
bestHash, bestHeight, err = r.Node.GetBestBlock() bestHash, bestHeight, err = r.Client.GetBestBlock()
if err != nil { if err != nil {
return err return err
} }
@ -2997,7 +3008,10 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness,
MinConfs: 1, MinConfs: 1,
FeeRate: 253, FeeRate: 253,
ChangeAddr: func() (btcutil.Address, error) { ChangeAddr: func() (btcutil.Address, error) {
return alice.NewAddress(lnwallet.WitnessPubKey, true) return alice.NewAddress(
lnwallet.WitnessPubKey, true,
lnwallet.DefaultAccountName,
)
}, },
}) })
if err != nil { if err != nil {
@ -3042,7 +3056,10 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness,
MinConfs: 1, MinConfs: 1,
FeeRate: 253, FeeRate: 253,
ChangeAddr: func() (btcutil.Address, error) { ChangeAddr: func() (btcutil.Address, error) {
return bob.NewAddress(lnwallet.WitnessPubKey, true) return bob.NewAddress(
lnwallet.WitnessPubKey, true,
lnwallet.DefaultAccountName,
)
}, },
}) })
if err != nil { if err != nil {
@ -3107,7 +3124,7 @@ func TestLightningWallet(t *testing.T, targetBackEnd string) {
// Next mine enough blocks in order for segwit and the CSV package // Next mine enough blocks in order for segwit and the CSV package
// soft-fork to activate on RegNet. // soft-fork to activate on RegNet.
numBlocks := netParams.MinerConfirmationWindow * 2 numBlocks := netParams.MinerConfirmationWindow * 2
if _, err := miningNode.Node.Generate(numBlocks); err != nil { if _, err := miningNode.Client.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }

@ -396,14 +396,33 @@ func (l *LightningWallet) Shutdown() error {
return nil return nil
} }
// ConfirmedBalance returns the current confirmed balance of the wallet. This // ConfirmedBalance returns the current confirmed balance of a wallet account.
// methods wraps the interal WalletController method so we're able to properly // This methods wraps the internal WalletController method so we're able to
// hold the coin select mutex while we compute the balance. // properly hold the coin select mutex while we compute the balance.
func (l *LightningWallet) ConfirmedBalance(confs int32) (btcutil.Amount, error) { func (l *LightningWallet) ConfirmedBalance(confs int32,
account string) (btcutil.Amount, error) {
l.coinSelectMtx.Lock() l.coinSelectMtx.Lock()
defer l.coinSelectMtx.Unlock() defer l.coinSelectMtx.Unlock()
return l.WalletController.ConfirmedBalance(confs) return l.WalletController.ConfirmedBalance(confs, account)
}
// ListUnspentWitnessFromDefaultAccount returns all unspent outputs from the
// default wallet account which are version 0 witness programs. The 'minConfs'
// and 'maxConfs' parameters indicate the minimum and maximum number of
// confirmations an output needs in order to be returned by this method. Passing
// -1 as 'minConfs' indicates that even unconfirmed outputs should be returned.
// Using MaxInt32 as 'maxConfs' implies returning all outputs with at least
// 'minConfs'.
//
// NOTE: This method requires the global coin selection lock to be held.
func (l *LightningWallet) ListUnspentWitnessFromDefaultAccount(
minConfs, maxConfs int32) ([]*Utxo, error) {
return l.WalletController.ListUnspentWitness(
minConfs, maxConfs, DefaultAccountName,
)
} }
// LockedOutpoints returns a list of all currently locked outpoint. // LockedOutpoints returns a list of all currently locked outpoint.
@ -722,7 +741,9 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
SubtractFees: req.SubtractFees, SubtractFees: req.SubtractFees,
FeeRate: req.FundingFeePerKw, FeeRate: req.FundingFeePerKw,
ChangeAddr: func() (btcutil.Address, error) { ChangeAddr: func() (btcutil.Address, error) {
return l.NewAddress(WitnessPubKey, true) return l.NewAddress(
WitnessPubKey, true, DefaultAccountName,
)
}, },
} }
fundingIntent, err = req.ChanFunder.ProvisionChannel( fundingIntent, err = req.ChanFunder.ProvisionChannel(
@ -920,8 +941,12 @@ func (l *LightningWallet) currentNumAnchorChans() (int, error) {
func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint, func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
out []*wire.TxOut, numAnchorChans int) (btcutil.Amount, error) { out []*wire.TxOut, numAnchorChans int) (btcutil.Amount, error) {
// Get all unspent coins in the wallet. // Get all unspent coins in the wallet. We only care about those part of
witnessOutputs, err := l.ListUnspentWitness(0, math.MaxInt32) // the wallet's default account as we know we can readily sign for those
// at any time.
witnessOutputs, err := l.ListUnspentWitnessFromDefaultAccount(
0, math.MaxInt32,
)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -2020,7 +2045,9 @@ func NewCoinSource(w *LightningWallet) *CoinSource {
func (c *CoinSource) ListCoins(minConfs int32, func (c *CoinSource) ListCoins(minConfs int32,
maxConfs int32) ([]chanfunding.Coin, error) { maxConfs int32) ([]chanfunding.Coin, error) {
utxos, err := c.wallet.ListUnspentWitness(minConfs, maxConfs) utxos, err := c.wallet.ListUnspentWitnessFromDefaultAccount(
minConfs, maxConfs,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -2043,7 +2043,7 @@ func (p *Brontide) ChannelSnapshots() []*channeldb.ChannelSnapshot {
// the case of a cooperative channel close negotiation. // the case of a cooperative channel close negotiation.
func (p *Brontide) genDeliveryScript() ([]byte, error) { func (p *Brontide) genDeliveryScript() ([]byte, error) {
deliveryAddr, err := p.cfg.Wallet.NewAddress( deliveryAddr, err := p.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.WitnessPubKey, false, lnwallet.DefaultAccountName,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -2333,10 +2333,14 @@ func (p *Brontide) fetchActiveChanCloser(chanID lnwire.ChannelID) (
"channel w/ active htlcs") "channel w/ active htlcs")
} }
// We'll create a valid closing state machine in order to respond to the // We'll create a valid closing state machine in order to
// initiated cooperative channel closure. First, we set the delivery // respond to the initiated cooperative channel closure. First,
// script that our funds will be paid out to. If an upfront shutdown script // we set the delivery script that our funds will be paid out
// was set, we will use it. Otherwise, we get a fresh delivery script. // to. If an upfront shutdown script was set, we will use it.
// Otherwise, we get a fresh delivery script.
//
// TODO: Expose option to allow upfront shutdown script from
// watch-only accounts.
deliveryScript := channel.LocalUpfrontShutdownScript() deliveryScript := channel.LocalUpfrontShutdownScript()
if len(deliveryScript) == 0 { if len(deliveryScript) == 0 {
var err error var err error

@ -12,6 +12,7 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tor" "github.com/lightningnetwork/lnd/tor"
) )
@ -180,7 +181,9 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
netParams: netParams, netParams: netParams,
}, },
WalletBalance: func() (btcutil.Amount, error) { WalletBalance: func() (btcutil.Amount, error) {
return svr.cc.Wallet.ConfirmedBalance(cfg.MinConfs) return svr.cc.Wallet.ConfirmedBalance(
cfg.MinConfs, lnwallet.DefaultAccountName,
)
}, },
Graph: autopilot.ChannelGraphFromDatabase(svr.localChanDB.ChannelGraph()), Graph: autopilot.ChannelGraphFromDatabase(svr.localChanDB.ChannelGraph()),
Constraints: atplConstraints, Constraints: atplConstraints,

@ -63,7 +63,7 @@ func waitForMempoolTx(r *rpctest.Harness, txid *chainhash.Hash) error {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Check for the harness' knowledge of the txid // Check for the harness' knowledge of the txid
tx, err = r.Node.GetRawTransaction(txid) tx, err = r.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
switch e := err.(type) { switch e := err.(type) {
case *btcjson.RPCError: case *btcjson.RPCError:
@ -188,12 +188,12 @@ func testFilterBlockNotifications(node *rpctest.Harness,
blockChan := chainView.FilteredBlocks() blockChan := chainView.FilteredBlocks()
// Next we'll mine a block confirming the output generated above. // Next we'll mine a block confirming the output generated above.
newBlockHashes, err := node.Node.Generate(1) newBlockHashes, err := node.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
_, currentHeight, err := node.Node.GetBestBlock() _, currentHeight, err := node.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -211,11 +211,11 @@ func testFilterBlockNotifications(node *rpctest.Harness,
// Now that the block has been mined, we'll fetch the two transactions // Now that the block has been mined, we'll fetch the two transactions
// so we can add them to the filter, and also craft transaction // so we can add them to the filter, and also craft transaction
// spending the outputs we created. // spending the outputs we created.
tx1, err := node.Node.GetRawTransaction(txid1) tx1, err := node.Client.GetRawTransaction(txid1)
if err != nil { if err != nil {
t.Fatalf("unable to fetch transaction: %v", err) t.Fatalf("unable to fetch transaction: %v", err)
} }
tx2, err := node.Node.GetRawTransaction(txid2) tx2, err := node.Client.GetRawTransaction(txid2)
if err != nil { if err != nil {
t.Fatalf("unable to fetch transaction: %v", err) t.Fatalf("unable to fetch transaction: %v", err)
} }
@ -236,7 +236,7 @@ func testFilterBlockNotifications(node *rpctest.Harness,
t.Fatalf("unable to find output: %v", err) t.Fatalf("unable to find output: %v", err)
} }
_, currentHeight, err = node.Node.GetBestBlock() _, currentHeight, err = node.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -264,7 +264,7 @@ func testFilterBlockNotifications(node *rpctest.Harness,
// Now we'll broadcast the first spending transaction and also mine a // Now we'll broadcast the first spending transaction and also mine a
// block which should include it. // block which should include it.
spendTxid1, err := node.Node.SendRawTransaction(spendingTx1, true) spendTxid1, err := node.Client.SendRawTransaction(spendingTx1, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast transaction: %v", err) t.Fatalf("unable to broadcast transaction: %v", err)
} }
@ -272,7 +272,7 @@ func testFilterBlockNotifications(node *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("unable to get spending txid in mempool: %v", err) t.Fatalf("unable to get spending txid in mempool: %v", err)
} }
newBlockHashes, err = node.Node.Generate(1) newBlockHashes, err = node.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -290,7 +290,7 @@ func testFilterBlockNotifications(node *rpctest.Harness,
// Next, mine the second transaction which spends the second output. // Next, mine the second transaction which spends the second output.
// This should also generate a notification. // This should also generate a notification.
spendTxid2, err := node.Node.SendRawTransaction(spendingTx2, true) spendTxid2, err := node.Client.SendRawTransaction(spendingTx2, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast transaction: %v", err) t.Fatalf("unable to broadcast transaction: %v", err)
} }
@ -298,7 +298,7 @@ func testFilterBlockNotifications(node *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("unable to get spending txid in mempool: %v", err) t.Fatalf("unable to get spending txid in mempool: %v", err)
} }
newBlockHashes, err = node.Node.Generate(1) newBlockHashes, err = node.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -328,14 +328,14 @@ func testUpdateFilterBackTrack(node *rpctest.Harness,
} }
// Next we'll mine a block confirming the output generated above. // Next we'll mine a block confirming the output generated above.
initBlockHashes, err := node.Node.Generate(1) initBlockHashes, err := node.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
blockChan := chainView.FilteredBlocks() blockChan := chainView.FilteredBlocks()
_, currentHeight, err := node.Node.GetBestBlock() _, currentHeight, err := node.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -352,7 +352,7 @@ func testUpdateFilterBackTrack(node *rpctest.Harness,
// Next, create a transaction which spends the output created above, // Next, create a transaction which spends the output created above,
// mining the spend into a block. // mining the spend into a block.
tx, err := node.Node.GetRawTransaction(txid) tx, err := node.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
t.Fatalf("unable to fetch transaction: %v", err) t.Fatalf("unable to fetch transaction: %v", err)
} }
@ -364,7 +364,7 @@ func testUpdateFilterBackTrack(node *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("unable to create spending tx: %v", err) t.Fatalf("unable to create spending tx: %v", err)
} }
spendTxid, err := node.Node.SendRawTransaction(spendingTx, true) spendTxid, err := node.Client.SendRawTransaction(spendingTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast transaction: %v", err) t.Fatalf("unable to broadcast transaction: %v", err)
} }
@ -372,7 +372,7 @@ func testUpdateFilterBackTrack(node *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("unable to get spending txid in mempool: %v", err) t.Fatalf("unable to get spending txid in mempool: %v", err)
} }
newBlockHashes, err := node.Node.Generate(1) newBlockHashes, err := node.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
@ -435,12 +435,12 @@ func testFilterSingleBlock(node *rpctest.Harness, chainView FilteredChainView,
blockChan := chainView.FilteredBlocks() blockChan := chainView.FilteredBlocks()
// Next we'll mine a block confirming the output generated above. // Next we'll mine a block confirming the output generated above.
newBlockHashes, err := node.Node.Generate(1) newBlockHashes, err := node.Client.Generate(1)
if err != nil { if err != nil {
t.Fatalf("unable to generate block: %v", err) t.Fatalf("unable to generate block: %v", err)
} }
_, currentHeight, err := node.Node.GetBestBlock() _, currentHeight, err := node.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -455,11 +455,11 @@ func testFilterSingleBlock(node *rpctest.Harness, chainView FilteredChainView,
t.Fatalf("filtered block notification didn't arrive") t.Fatalf("filtered block notification didn't arrive")
} }
tx1, err := node.Node.GetRawTransaction(txid1) tx1, err := node.Client.GetRawTransaction(txid1)
if err != nil { if err != nil {
t.Fatalf("unable to fetch transaction: %v", err) t.Fatalf("unable to fetch transaction: %v", err)
} }
tx2, err := node.Node.GetRawTransaction(txid2) tx2, err := node.Client.GetRawTransaction(txid2)
if err != nil { if err != nil {
t.Fatalf("unable to fetch transaction: %v", err) t.Fatalf("unable to fetch transaction: %v", err)
} }
@ -496,7 +496,7 @@ func testFilterSingleBlock(node *rpctest.Harness, chainView FilteredChainView,
t.Fatalf("filtered block notification didn't arrive") t.Fatalf("filtered block notification didn't arrive")
} }
_, currentHeight, err = node.Node.GetBestBlock() _, currentHeight, err = node.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -579,7 +579,7 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
} }
_, oldHeight, err := reorgNode.Node.GetBestBlock() _, oldHeight, err := reorgNode.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -595,7 +595,7 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
t.Fatalf("unable to join node on blocks: %v", err) t.Fatalf("unable to join node on blocks: %v", err)
} }
_, newHeight, err := reorgNode.Node.GetBestBlock() _, newHeight, err := reorgNode.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -635,21 +635,21 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
// Now we trigger a small reorg, by disconnecting the nodes, mining // Now we trigger a small reorg, by disconnecting the nodes, mining
// a few blocks on each, then connecting them again. // a few blocks on each, then connecting them again.
peers, err := reorgNode.Node.GetPeerInfo() peers, err := reorgNode.Client.GetPeerInfo()
if err != nil { if err != nil {
t.Fatalf("unable to get peer info: %v", err) t.Fatalf("unable to get peer info: %v", err)
} }
numPeers := len(peers) numPeers := len(peers)
// Disconnect the nodes. // Disconnect the nodes.
err = reorgNode.Node.AddNode(node.P2PAddress(), rpcclient.ANRemove) err = reorgNode.Client.AddNode(node.P2PAddress(), rpcclient.ANRemove)
if err != nil { if err != nil {
t.Fatalf("unable to disconnect mining nodes: %v", err) t.Fatalf("unable to disconnect mining nodes: %v", err)
} }
// Wait for disconnection // Wait for disconnection
for { for {
peers, err = reorgNode.Node.GetPeerInfo() peers, err = reorgNode.Client.GetPeerInfo()
if err != nil { if err != nil {
t.Fatalf("unable to get peer info: %v", err) t.Fatalf("unable to get peer info: %v", err)
} }
@ -661,8 +661,12 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
// Mine 10 blocks on the main chain, 5 on the chain that will be // Mine 10 blocks on the main chain, 5 on the chain that will be
// reorged out, // reorged out,
node.Node.Generate(10) if _, err := node.Client.Generate(10); err != nil {
reorgNode.Node.Generate(5) t.Fatalf("unable to generate blocks on main chain: %v", err)
}
if _, err := reorgNode.Client.Generate(5); err != nil {
t.Fatalf("unable to generate blocks on reorged chain: %v", err)
}
// 5 new blocks should get notified. // 5 new blocks should get notified.
for i := uint32(0); i < 5; i++ { for i := uint32(0); i < 5; i++ {
@ -682,7 +686,7 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
} }
} }
_, oldHeight, err = reorgNode.Node.GetBestBlock() _, oldHeight, err = reorgNode.Client.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -695,8 +699,7 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
t.Fatalf("unable to join node on blocks: %v", err) t.Fatalf("unable to join node on blocks: %v", err)
} }
_, newHeight, err = reorgNode.Node.GetBestBlock() if _, _, err := reorgNode.Client.GetBestBlock(); err != nil {
if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }

@ -25,6 +25,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/psbt" "github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet/txauthor" "github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime" proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
@ -1023,7 +1024,7 @@ func (r *rpcServer) ListUnspent(ctx context.Context,
var utxos []*lnwallet.Utxo var utxos []*lnwallet.Utxo
err = r.server.cc.Wallet.WithCoinSelectLock(func() error { err = r.server.cc.Wallet.WithCoinSelectLock(func() error {
utxos, err = r.server.cc.Wallet.ListUnspentWitness( utxos, err = r.server.cc.Wallet.ListUnspentWitness(
minConfs, maxConfs, minConfs, maxConfs, in.Account,
) )
return err return err
}) })
@ -1191,7 +1192,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
sweepTxPkg, err := sweep.CraftSweepAllTx( sweepTxPkg, err := sweep.CraftSweepAllTx(
feePerKw, lnwallet.DefaultDustLimit(), feePerKw, lnwallet.DefaultDustLimit(),
uint32(bestHeight), nil, targetAddr, wallet, uint32(bestHeight), nil, targetAddr, wallet,
wallet.WalletController, wallet.WalletController, wallet, wallet.WalletController,
r.server.cc.FeeEstimator, r.server.cc.Signer, r.server.cc.FeeEstimator, r.server.cc.Signer,
) )
if err != nil { if err != nil {
@ -1225,6 +1226,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
// allowing us to pass the reserved value check. // allowing us to pass the reserved value check.
changeAddr, err := r.server.cc.Wallet.NewAddress( changeAddr, err := r.server.cc.Wallet.NewAddress(
lnwallet.WitnessPubKey, true, lnwallet.WitnessPubKey, true,
lnwallet.DefaultAccountName,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -1242,7 +1244,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
sweepTxPkg, err = sweep.CraftSweepAllTx( sweepTxPkg, err = sweep.CraftSweepAllTx(
feePerKw, lnwallet.DefaultDustLimit(), feePerKw, lnwallet.DefaultDustLimit(),
uint32(bestHeight), outputs, targetAddr, wallet, uint32(bestHeight), outputs, targetAddr, wallet,
wallet.WalletController, wallet.WalletController, wallet, wallet.WalletController,
r.server.cc.FeeEstimator, r.server.cc.Signer, r.server.cc.FeeEstimator, r.server.cc.Signer,
) )
if err != nil { if err != nil {
@ -1372,6 +1374,12 @@ func (r *rpcServer) SendMany(ctx context.Context,
func (r *rpcServer) NewAddress(ctx context.Context, func (r *rpcServer) NewAddress(ctx context.Context,
in *lnrpc.NewAddressRequest) (*lnrpc.NewAddressResponse, error) { in *lnrpc.NewAddressRequest) (*lnrpc.NewAddressResponse, error) {
// Always use the default wallet account unless one was specified.
account := lnwallet.DefaultAccountName
if in.Account != "" {
account = in.Account
}
// Translate the gRPC proto address type to the wallet controller's // Translate the gRPC proto address type to the wallet controller's
// available address types. // available address types.
var ( var (
@ -1381,7 +1389,7 @@ func (r *rpcServer) NewAddress(ctx context.Context,
switch in.Type { switch in.Type {
case lnrpc.AddressType_WITNESS_PUBKEY_HASH: case lnrpc.AddressType_WITNESS_PUBKEY_HASH:
addr, err = r.server.cc.Wallet.NewAddress( addr, err = r.server.cc.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.WitnessPubKey, false, account,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -1389,7 +1397,7 @@ func (r *rpcServer) NewAddress(ctx context.Context,
case lnrpc.AddressType_NESTED_PUBKEY_HASH: case lnrpc.AddressType_NESTED_PUBKEY_HASH:
addr, err = r.server.cc.Wallet.NewAddress( addr, err = r.server.cc.Wallet.NewAddress(
lnwallet.NestedWitnessPubKey, false, lnwallet.NestedWitnessPubKey, false, account,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -1397,7 +1405,7 @@ func (r *rpcServer) NewAddress(ctx context.Context,
case lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH: case lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH:
addr, err = r.server.cc.Wallet.LastUnusedAddress( addr, err = r.server.cc.Wallet.LastUnusedAddress(
lnwallet.WitnessPubKey, lnwallet.WitnessPubKey, account,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -1405,14 +1413,15 @@ func (r *rpcServer) NewAddress(ctx context.Context,
case lnrpc.AddressType_UNUSED_NESTED_PUBKEY_HASH: case lnrpc.AddressType_UNUSED_NESTED_PUBKEY_HASH:
addr, err = r.server.cc.Wallet.LastUnusedAddress( addr, err = r.server.cc.Wallet.LastUnusedAddress(
lnwallet.NestedWitnessPubKey, lnwallet.NestedWitnessPubKey, account,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
rpcsLog.Debugf("[newaddress] type=%v addr=%v", in.Type, addr.String()) rpcsLog.Debugf("[newaddress] account=%v type=%v addr=%v", account,
in.Type, addr.String())
return &lnrpc.NewAddressResponse{Address: addr.String()}, nil return &lnrpc.NewAddressResponse{Address: addr.String()}, nil
} }
@ -2761,30 +2770,80 @@ func (r *rpcServer) SubscribePeerEvents(req *lnrpc.PeerEventSubscription,
func (r *rpcServer) WalletBalance(ctx context.Context, func (r *rpcServer) WalletBalance(ctx context.Context,
in *lnrpc.WalletBalanceRequest) (*lnrpc.WalletBalanceResponse, error) { in *lnrpc.WalletBalanceRequest) (*lnrpc.WalletBalanceResponse, error) {
// Get total balance, from txs that have >= 0 confirmations. // Retrieve all existing wallet accounts. We'll compute the confirmed
totalBal, err := r.server.cc.Wallet.ConfirmedBalance(0) // and unconfirmed balance for each and tally them up.
accounts, err := r.server.cc.Wallet.ListAccounts("", nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get confirmed balance, from txs that have >= 1 confirmations. var totalBalance, confirmedBalance, unconfirmedBalance btcutil.Amount
// TODO(halseth): get both unconfirmed and confirmed balance in one rpcAccountBalances := make(
// call, as this is racy. map[string]*lnrpc.WalletAccountBalance, len(accounts),
confirmedBal, err := r.server.cc.Wallet.ConfirmedBalance(1) )
for _, account := range accounts {
// There are two default accounts, one for NP2WKH outputs and
// another for P2WKH outputs. The balance will be computed for
// both given one call to ConfirmedBalance with the default
// wallet and imported account, so we'll skip the second
// instance to avoid inflating the balance.
switch account.AccountName {
case waddrmgr.ImportedAddrAccountName:
// Omit the imported account from the response unless we
// actually have any keys imported.
if account.ImportedKeyCount == 0 {
continue
}
fallthrough
case lnwallet.DefaultAccountName:
if _, ok := rpcAccountBalances[account.AccountName]; ok {
continue
}
default:
}
// Get total balance, from txs that have >= 0 confirmations.
totalBal, err := r.server.cc.Wallet.ConfirmedBalance(
0, account.AccountName,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
totalBalance += totalBal
// Get confirmed balance, from txs that have >= 1 confirmations.
// TODO(halseth): get both unconfirmed and confirmed balance in
// one call, as this is racy.
confirmedBal, err := r.server.cc.Wallet.ConfirmedBalance(
1, account.AccountName,
)
if err != nil {
return nil, err
}
confirmedBalance += confirmedBal
// Get unconfirmed balance, from txs with 0 confirmations. // Get unconfirmed balance, from txs with 0 confirmations.
unconfirmedBal := totalBal - confirmedBal unconfirmedBal := totalBal - confirmedBal
unconfirmedBalance += unconfirmedBal
rpcsLog.Debugf("[walletbalance] Total balance=%v (confirmed=%v, "+ rpcAccountBalances[account.AccountName] = &lnrpc.WalletAccountBalance{
"unconfirmed=%v)", totalBal, confirmedBal, unconfirmedBal)
return &lnrpc.WalletBalanceResponse{
TotalBalance: int64(totalBal),
ConfirmedBalance: int64(confirmedBal), ConfirmedBalance: int64(confirmedBal),
UnconfirmedBalance: int64(unconfirmedBal), UnconfirmedBalance: int64(unconfirmedBal),
}
}
rpcsLog.Debugf("[walletbalance] Total balance=%v (confirmed=%v, "+
"unconfirmed=%v)", totalBalance, confirmedBalance,
unconfirmedBalance)
return &lnrpc.WalletBalanceResponse{
TotalBalance: int64(totalBalance),
ConfirmedBalance: int64(confirmedBalance),
UnconfirmedBalance: int64(unconfirmedBalance),
AccountBalance: rpcAccountBalances,
}, nil }, nil
} }
@ -4962,7 +5021,7 @@ func (r *rpcServer) GetTransactions(ctx context.Context,
} }
transactions, err := r.server.cc.Wallet.ListTransactionDetails( transactions, err := r.server.cc.Wallet.ListTransactionDetails(
req.StartHeight, endHeight, req.StartHeight, endHeight, req.Account,
) )
if err != nil { if err != nil {
return nil, err return nil, err

@ -3809,7 +3809,9 @@ func newSweepPkScriptGen(
wallet lnwallet.WalletController) func() ([]byte, error) { wallet lnwallet.WalletController) func() ([]byte, error) {
return func() ([]byte, error) { return func() ([]byte, error) {
sweepAddr, err := wallet.NewAddress(lnwallet.WitnessPubKey, false) sweepAddr, err := wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.DefaultAccountName,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -87,7 +87,7 @@ func (b *mockBackend) PublishTransaction(tx *wire.MsgTx, _ string) error {
return err return err
} }
func (b *mockBackend) ListUnspentWitness(minconfirms, maxconfirms int32) ( func (b *mockBackend) ListUnspentWitnessFromDefaultAccount(minconfirms, maxconfirms int32) (
[]*lnwallet.Utxo, error) { []*lnwallet.Utxo, error) {
b.lock.Lock() b.lock.Lock()
defer b.lock.Unlock() defer b.lock.Unlock()

@ -11,12 +11,13 @@ type Wallet interface {
// broadcasts the passed transaction to the Bitcoin network. // broadcasts the passed transaction to the Bitcoin network.
PublishTransaction(tx *wire.MsgTx, label string) error PublishTransaction(tx *wire.MsgTx, label string) error
// ListUnspentWitness returns all unspent outputs which are version 0 // ListUnspentWitnessFromDefaultAccount returns all unspent outputs
// witness programs. The 'minconfirms' and 'maxconfirms' parameters // which are version 0 witness programs from the default wallet account.
// indicate the minimum and maximum number of confirmations an output // The 'minconfirms' and 'maxconfirms' parameters indicate the minimum
// needs in order to be returned by this method. // and maximum number of confirmations an output needs in order to be
ListUnspentWitness(minconfirms, maxconfirms int32) ([]*lnwallet.Utxo, // returned by this method.
error) ListUnspentWitnessFromDefaultAccount(minconfirms, maxconfirms int32) (
[]*lnwallet.Utxo, error)
// WithCoinSelectLock will execute the passed function closure in a // WithCoinSelectLock will execute the passed function closure in a
// synchronized manner preventing any coin selection operations from // synchronized manner preventing any coin selection operations from

@ -333,7 +333,9 @@ func (t *txInputSet) tryAddWalletInputsIfNeeded() error {
// Retrieve wallet utxos. Only consider confirmed utxos to prevent // Retrieve wallet utxos. Only consider confirmed utxos to prevent
// problems around RBF rules for unconfirmed inputs. // problems around RBF rules for unconfirmed inputs.
utxos, err := t.wallet.ListUnspentWitness(1, math.MaxInt32) utxos, err := t.wallet.ListUnspentWitnessFromDefaultAccount(
1, math.MaxInt32,
)
if err != nil { if err != nil {
return err return err
} }

@ -112,7 +112,7 @@ type mockWallet struct {
Wallet Wallet
} }
func (m *mockWallet) ListUnspentWitness(minconfirms, maxconfirms int32) ( func (m *mockWallet) ListUnspentWitnessFromDefaultAccount(minconfirms, maxconfirms int32) (
[]*lnwallet.Utxo, error) { []*lnwallet.Utxo, error) {
return []*lnwallet.Utxo{ return []*lnwallet.Utxo{

@ -99,9 +99,10 @@ func DetermineFeePerKw(feeEstimator chainfee.Estimator,
// UtxoSource is an interface that allows a caller to access a source of UTXOs // UtxoSource is an interface that allows a caller to access a source of UTXOs
// to use when crafting sweep transactions. // to use when crafting sweep transactions.
type UtxoSource interface { type UtxoSource interface {
// ListUnspentWitness returns all UTXOs from the source that have // ListUnspentWitness returns all UTXOs from the default wallet account
// between minConfs and maxConfs number of confirmations. // that have between minConfs and maxConfs number of confirmations.
ListUnspentWitness(minConfs, maxConfs int32) ([]*lnwallet.Utxo, error) ListUnspentWitnessFromDefaultAccount(minConfs, maxConfs int32) (
[]*lnwallet.Utxo, error)
} }
// CoinSelectionLocker is an interface that allows the caller to perform an // CoinSelectionLocker is an interface that allows the caller to perform an
@ -192,7 +193,7 @@ func CraftSweepAllTx(feeRate chainfee.SatPerKWeight, dustLimit btcutil.Amount,
// Now that we can be sure that no other coin selection // Now that we can be sure that no other coin selection
// operations are going on, we can grab a clean snapshot of the // operations are going on, we can grab a clean snapshot of the
// current UTXO state of the wallet. // current UTXO state of the wallet.
utxos, err := utxoSource.ListUnspentWitness( utxos, err := utxoSource.ListUnspentWitnessFromDefaultAccount(
1, math.MaxInt32, 1, math.MaxInt32,
) )
if err != nil { if err != nil {

@ -119,7 +119,7 @@ func newMockUtxoSource(utxos []*lnwallet.Utxo) *mockUtxoSource {
} }
} }
func (m *mockUtxoSource) ListUnspentWitness(minConfs int32, func (m *mockUtxoSource) ListUnspentWitnessFromDefaultAccount(minConfs int32,
maxConfs int32) ([]*lnwallet.Utxo, error) { maxConfs int32) ([]*lnwallet.Utxo, error) {
return m.outputs, nil return m.outputs, nil