From 77262ff699c5791e3dd7a2f4a2c11cdbaeb4b888 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 20:57:30 -0800 Subject: [PATCH 01/13] sweep: rename Estimator to FeeEstimator --- server.go | 2 +- sweep/sweeper.go | 14 +++++++------- sweep/sweeper_test.go | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/server.go b/server.go index c3378839b..31e96c52a 100644 --- a/server.go +++ b/server.go @@ -607,7 +607,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, } s.sweeper = sweep.New(&sweep.UtxoSweeperConfig{ - Estimator: cc.feeEstimator, + FeeEstimator: cc.feeEstimator, GenSweepScript: func() ([]byte, error) { return newSweepPkScript(cc.wallet) }, diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 3829d27e6..2c87ba719 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -85,10 +85,10 @@ type UtxoSweeperConfig struct { // funds can be swept. GenSweepScript func() ([]byte, error) - // Estimator is used when crafting sweep transactions to estimate the - // necessary fee relative to the expected size of the sweep + // FeeEstimator is used when crafting sweep transactions to estimate + // the necessary fee relative to the expected size of the sweep // transaction. - Estimator lnwallet.FeeEstimator + FeeEstimator lnwallet.FeeEstimator // PublishTransaction facilitates the process of broadcasting a signed // transaction to the appropriate network. @@ -198,7 +198,7 @@ func (s *UtxoSweeper) Start() error { // Retrieve relay fee for dust limit calculation. Assume that this will // not change from here on. - s.relayFeePerKW = s.cfg.Estimator.RelayFeePerKW() + s.relayFeePerKW = s.cfg.FeeEstimator.RelayFeePerKW() // Register for block epochs to retry sweeping every block. bestHash, bestHeight, err := s.cfg.ChainIO.GetBestBlock() @@ -407,7 +407,7 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch, // Retrieve fee estimate for input filtering and final // tx fee calculation. - satPerKW, err := s.cfg.Estimator.EstimateFeePerKW( + satPerKW, err := s.cfg.FeeEstimator.EstimateFeePerKW( s.cfg.SweepTxConfTarget, ) if err != nil { @@ -465,7 +465,7 @@ func (s *UtxoSweeper) scheduleSweep(currentHeight int32) error { // Retrieve fee estimate for input filtering and final tx fee // calculation. - satPerKW, err := s.cfg.Estimator.EstimateFeePerKW( + satPerKW, err := s.cfg.FeeEstimator.EstimateFeePerKW( s.cfg.SweepTxConfTarget, ) if err != nil { @@ -753,7 +753,7 @@ func (s *UtxoSweeper) waitForSpend(outpoint wire.OutPoint, func (s *UtxoSweeper) CreateSweepTx(inputs []Input, confTarget uint32, currentBlockHeight uint32) (*wire.MsgTx, error) { - feePerKw, err := s.cfg.Estimator.EstimateFeePerKW(confTarget) + feePerKw, err := s.cfg.FeeEstimator.EstimateFeePerKW(confTarget) if err != nil { return nil, err } diff --git a/sweep/sweeper_test.go b/sweep/sweeper_test.go index 6a59f5dc5..d2204e1d1 100644 --- a/sweep/sweeper_test.go +++ b/sweep/sweeper_test.go @@ -135,7 +135,7 @@ func createSweeperTestContext(t *testing.T) *sweeperTestContext { outputScriptCount++ return script, nil }, - Estimator: estimator, + FeeEstimator: estimator, MaxInputsPerTx: testMaxInputsPerTx, MaxSweepAttempts: testMaxSweepAttempts, NextAttemptDeltaFunc: func(attempts int) int32 { From 73c9c2ee155cfabc326cd05ad215b10a0a1b613c Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 20:44:34 -0800 Subject: [PATCH 02/13] sweep+cnct+nursery+rpc: extract DetermineFeePerKw to func, add FeePreference In this commit, we extract the existing determineFeePerKw method on the RPC server into a new file in the sweep package. Along the way, we consolidate code by introducing a new FeePreference struct, which allows the caller to express their fee preference either in blocks to confirmation, or a direct fee rate. This move takes a small step to father decoupling calls in the main RPC server. --- contractcourt/contract_resolvers.go | 10 +++- rpcserver.go | 91 +++++++++++------------------ sweep/sweeper.go | 4 +- sweep/walletsweep.go | 68 +++++++++++++++++++++ 4 files changed, 112 insertions(+), 61 deletions(-) create mode 100644 sweep/walletsweep.go diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index 6d4609da4..3cc5e4a96 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -476,7 +476,10 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { // TODO: Use time-based sweeper and result chan. var err error h.sweepTx, err = h.Sweeper.CreateSweepTx( - []sweep.Input{&input}, sweepConfTarget, 0, + []sweep.Input{&input}, + sweep.FeePreference{ + ConfTarget: sweepConfTarget, + }, 0, ) if err != nil { return nil, err @@ -1270,7 +1273,10 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { // // TODO: Use time-based sweeper and result chan. c.sweepTx, err = c.Sweeper.CreateSweepTx( - []sweep.Input{&input}, sweepConfTarget, 0, + []sweep.Input{&input}, + sweep.FeePreference{ + ConfTarget: sweepConfTarget, + }, 0, ) if err != nil { return nil, err diff --git a/rpcserver.go b/rpcserver.go index 4254ae5da..dfd3e8905 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -39,6 +39,7 @@ import ( "github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/signal" + "github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/zpay32" "github.com/tv42/zbase32" "golang.org/x/net/context" @@ -637,53 +638,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64, } txHash := tx.TxHash() - return &txHash, err -} - -// determineFeePerKw will determine the fee in sat/kw that should be paid given -// an estimator, a confirmation target, and a manual value for sat/byte. A value -// is chosen based on the two free parameters as one, or both of them can be -// zero. -func determineFeePerKw(feeEstimator lnwallet.FeeEstimator, targetConf int32, - feePerByte int64) (lnwallet.SatPerKWeight, error) { - - switch { - // If the target number of confirmations is set, then we'll use that to - // consult our fee estimator for an adequate fee. - case targetConf != 0: - feePerKw, err := feeEstimator.EstimateFeePerKW( - uint32(targetConf), - ) - if err != nil { - return 0, fmt.Errorf("unable to query fee "+ - "estimator: %v", err) - } - - return feePerKw, nil - - // If a manual sat/byte fee rate is set, then we'll use that directly. - // We'll need to convert it to sat/kw as this is what we use internally. - case feePerByte != 0: - feePerKW := lnwallet.SatPerKVByte(feePerByte * 1000).FeePerKWeight() - if feePerKW < lnwallet.FeePerKwFloor { - rpcsLog.Infof("Manual fee rate input of %d sat/kw is "+ - "too low, using %d sat/kw instead", feePerKW, - lnwallet.FeePerKwFloor) - feePerKW = lnwallet.FeePerKwFloor - } - return feePerKW, nil - - // Otherwise, we'll attempt a relaxed confirmation target for the - // transaction - default: - feePerKw, err := feeEstimator.EstimateFeePerKW(6) - if err != nil { - return 0, fmt.Errorf("unable to query fee estimator: "+ - "%v", err) - } - - return feePerKw, nil - } + return &txHash, nil } // ListUnspent returns useful information about each unspent output owned by @@ -803,8 +758,12 @@ func (r *rpcServer) SendCoins(ctx context.Context, // Based on the passed fee related parameters, we'll determine an // appropriate fee rate for this transaction. - feePerKw, err := determineFeePerKw( - r.server.cc.feeEstimator, in.TargetConf, in.SatPerByte, + satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight() + feePerKw, err := sweep.DetermineFeePerKw( + r.server.cc.feeEstimator, sweep.FeePreference{ + ConfTarget: uint32(in.TargetConf), + FeeRate: satPerKw, + }, ) if err != nil { return nil, err @@ -831,8 +790,12 @@ func (r *rpcServer) SendMany(ctx context.Context, // Based on the passed fee related parameters, we'll determine an // appropriate fee rate for this transaction. - feePerKw, err := determineFeePerKw( - r.server.cc.feeEstimator, in.TargetConf, in.SatPerByte, + satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight() + feePerKw, err := sweep.DetermineFeePerKw( + r.server.cc.feeEstimator, sweep.FeePreference{ + ConfTarget: uint32(in.TargetConf), + FeeRate: satPerKw, + }, ) if err != nil { return nil, err @@ -1167,8 +1130,12 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest, // Based on the passed fee related parameters, we'll determine an // appropriate fee rate for the funding transaction. - feeRate, err := determineFeePerKw( - r.server.cc.feeEstimator, in.TargetConf, in.SatPerByte, + satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight() + feeRate, err := sweep.DetermineFeePerKw( + r.server.cc.feeEstimator, sweep.FeePreference{ + ConfTarget: uint32(in.TargetConf), + FeeRate: satPerKw, + }, ) if err != nil { return err @@ -1314,8 +1281,12 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context, // Based on the passed fee related parameters, we'll determine an // appropriate fee rate for the funding transaction. - feeRate, err := determineFeePerKw( - r.server.cc.feeEstimator, in.TargetConf, in.SatPerByte, + satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight() + feeRate, err := sweep.DetermineFeePerKw( + r.server.cc.feeEstimator, sweep.FeePreference{ + ConfTarget: uint32(in.TargetConf), + FeeRate: satPerKw, + }, ) if err != nil { return nil, err @@ -1503,8 +1474,14 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest, // Based on the passed fee related parameters, we'll determine // an appropriate fee rate for the cooperative closure // transaction. - feeRate, err := determineFeePerKw( - r.server.cc.feeEstimator, in.TargetConf, in.SatPerByte, + satPerKw := lnwallet.SatPerKVByte( + in.SatPerByte * 1000, + ).FeePerKWeight() + feeRate, err := sweep.DetermineFeePerKw( + r.server.cc.feeEstimator, sweep.FeePreference{ + ConfTarget: uint32(in.TargetConf), + FeeRate: satPerKw, + }, ) if err != nil { return err diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 2c87ba719..61cb1a222 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -750,10 +750,10 @@ func (s *UtxoSweeper) waitForSpend(outpoint wire.OutPoint, // - Make handling re-orgs easier. // - Thwart future possible fee sniping attempts. // - Make us blend in with the bitcoind wallet. -func (s *UtxoSweeper) CreateSweepTx(inputs []Input, confTarget uint32, +func (s *UtxoSweeper) CreateSweepTx(inputs []Input, feePref FeePreference, currentBlockHeight uint32) (*wire.MsgTx, error) { - feePerKw, err := s.cfg.FeeEstimator.EstimateFeePerKW(confTarget) + feePerKw, err := DetermineFeePerKw(s.cfg.FeeEstimator, feePref) if err != nil { return nil, err } diff --git a/sweep/walletsweep.go b/sweep/walletsweep.go new file mode 100644 index 000000000..24417cbec --- /dev/null +++ b/sweep/walletsweep.go @@ -0,0 +1,68 @@ +package sweep + +import ( + "fmt" + + "github.com/lightningnetwork/lnd/lnwallet" +) + +// FeePreference allows callers to express their time value for inclusion of a +// transaction into a block via either a confirmation target, or a fee rate. +type FeePreference struct { + // ConfTarget if non-zero, signals a fee preference expressed in the + // number of desired blocks between first broadcast, and confirmation. + ConfTarget uint32 + + // FeeRate if non-zero, signals a fee pre fence expressed in the fee + // rate expressed in sat/kw for a particular transaction. + FeeRate lnwallet.SatPerKWeight +} + +// DetermineFeePerKw will determine the fee in sat/kw that should be paid given +// an estimator, a confirmation target, and a manual value for sat/byte. A +// value is chosen based on the two free parameters as one, or both of them can +// be zero. +func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator, + feePref FeePreference) (lnwallet.SatPerKWeight, error) { + + switch { + // If the target number of confirmations is set, then we'll use that to + // consult our fee estimator for an adequate fee. + case feePref.ConfTarget != 0: + feePerKw, err := feeEstimator.EstimateFeePerKW( + uint32(feePref.ConfTarget), + ) + if err != nil { + return 0, fmt.Errorf("unable to query fee "+ + "estimator: %v", err) + } + + return feePerKw, nil + + // If a manual sat/byte fee rate is set, then we'll use that directly. + // We'll need to convert it to sat/kw as this is what we use + // internally. + case feePref.FeeRate != 0: + feePerKW := feePref.FeeRate + if feePerKW < lnwallet.FeePerKwFloor { + log.Infof("Manual fee rate input of %d sat/kw is "+ + "too low, using %d sat/kw instead", feePerKW, + lnwallet.FeePerKwFloor) + + feePerKW = lnwallet.FeePerKwFloor + } + + return feePerKW, nil + + // Otherwise, we'll attempt a relaxed confirmation target for the + // transaction + default: + feePerKw, err := feeEstimator.EstimateFeePerKW(6) + if err != nil { + return 0, fmt.Errorf("unable to query fee estimator: "+ + "%v", err) + } + + return feePerKw, nil + } +} From bd9ebbd5afe0f3b29aa0332a0c1818ff819b04bc Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 20:46:51 -0800 Subject: [PATCH 03/13] lnwallet: add more godoc to InputScript rename ScriptSig field to SigScript --- lnwallet/btcwallet/signer.go | 17 ++++++++++------- lnwallet/interface.go | 2 +- lnwallet/reservation.go | 12 ++++++++---- lnwallet/test_utils.go | 8 +++++--- lnwallet/wallet.go | 10 +++++----- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/lnwallet/btcwallet/signer.go b/lnwallet/btcwallet/signer.go index 21f095922..f45308561 100644 --- a/lnwallet/btcwallet/signer.go +++ b/lnwallet/btcwallet/signer.go @@ -180,9 +180,10 @@ func (b *BtcWallet) SignOutputRaw(tx *wire.MsgTx, // TODO(roasbeef): generate sighash midstate if not present? amt := signDesc.Output.Value - sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes, - signDesc.InputIndex, amt, witnessScript, signDesc.HashType, - privKey) + sig, err := txscript.RawTxInWitnessSignature( + tx, signDesc.SigHashes, signDesc.InputIndex, amt, + witnessScript, signDesc.HashType, privKey, + ) if err != nil { return nil, err } @@ -227,8 +228,9 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx, // spend the p2sh output. The sigScript will contain only a // single push of the p2wkh witness program corresponding to // the matching public key of this address. - p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, - b.netParams) + p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash( + pubKeyHash, b.netParams, + ) if err != nil { return nil, err } @@ -244,7 +246,7 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx, return nil, err } - inputScript.ScriptSig = sigScript + inputScript.SigScript = sigScript // Otherwise, this is a regular p2wkh output, so we include the // witness program itself as the subscript to generate the proper @@ -267,7 +269,8 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx, // TODO(roasbeef): adhere to passed HashType witnessScript, err := txscript.WitnessSignature(tx, signDesc.SigHashes, signDesc.InputIndex, signDesc.Output.Value, witnessProgram, - signDesc.HashType, privKey, true) + signDesc.HashType, privKey, true, + ) if err != nil { return nil, err } diff --git a/lnwallet/interface.go b/lnwallet/interface.go index 62cd0fa39..efe8b6192 100644 --- a/lnwallet/interface.go +++ b/lnwallet/interface.go @@ -127,7 +127,7 @@ type TransactionSubscription interface { type WalletController interface { // FetchInputInfo queries for the WalletController's knowledge of the // passed outpoint. If the base wallet determines this output is under - // its control, then the original txout should be returned. Otherwise, + // its control, then the original txout should be returned. Otherwise, // a non-nil error value of ErrNotMine should be returned instead. FetchInputInfo(prevOut *wire.OutPoint) (*wire.TxOut, error) diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 62bd449db..c7adf19da 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -50,11 +50,15 @@ func (c *ChannelContribution) toChanConfig() channeldb.ChannelConfig { } // InputScript represents any script inputs required to redeem a previous -// output. This struct is used rather than just a witness, or scripSig in -// order to accommodate nested p2sh which utilizes both types of input scripts. +// output. This struct is used rather than just a witness, or scripSig in order +// to accommodate nested p2sh which utilizes both types of input scripts. type InputScript struct { - Witness [][]byte - ScriptSig []byte + // Witness is the full witness stack required to unlock this output. + Witness wire.TxWitness + + // SigScript will only be populated if this is an input script sweeping + // a nested p2sh output. + SigScript []byte } // ChannelReservation represents an intent to open a lightning payment channel diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index db2cbb108..5c006c281 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -438,13 +438,15 @@ func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, signDesc *SignDescriptor "address %v", addresses[0]) } - scriptSig, err := txscript.SignatureScript(tx, signDesc.InputIndex, - signDesc.Output.PkScript, txscript.SigHashAll, privKey, true) + sigScript, err := txscript.SignatureScript( + tx, signDesc.InputIndex, signDesc.Output.PkScript, + txscript.SigHashAll, privKey, true, + ) if err != nil { return nil, err } - return &InputScript{ScriptSig: scriptSig}, nil + return &InputScript{SigScript: sigScript}, nil case txscript.WitnessV0PubKeyHashTy: privKey := m.findKey(addresses[0].ScriptAddress(), signDesc.SingleTweak, diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 4784efeab..6f7863dc5 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -747,14 +747,15 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) { signDesc.Output = info signDesc.InputIndex = i - inputScript, err := l.Cfg.Signer.ComputeInputScript(fundingTx, - &signDesc) + inputScript, err := l.Cfg.Signer.ComputeInputScript( + fundingTx, &signDesc, + ) if err != nil { req.err <- err return } - txIn.SignatureScript = inputScript.ScriptSig + txIn.SignatureScript = inputScript.SigScript txIn.Witness = inputScript.Witness pendingReservation.ourFundingInputScripts = append( pendingReservation.ourFundingInputScripts, @@ -958,7 +959,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs if len(inputScripts) != 0 && len(txin.Witness) == 0 { // Attach the input scripts so we can verify it below. txin.Witness = inputScripts[sigIndex].Witness - txin.SignatureScript = inputScripts[sigIndex].ScriptSig + txin.SignatureScript = inputScripts[sigIndex].SigScript // Fetch the alleged previous output along with the // pkscript referenced by this input. @@ -1256,7 +1257,6 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // selection is successful/possible, then the selected coins are available // within the passed contribution's inputs. If necessary, a change address will // also be generated. -// TODO(roasbeef): remove hardcoded fees. func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight, amt btcutil.Amount, minConfs int32, contribution *ChannelContribution) error { From c18e166e032966bc09e7a30acef49bc5eed8b5f0 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 20:48:41 -0800 Subject: [PATCH 04/13] lnwallet+sweep: extend the WitnessGenerator type to return an InputScript In this commit, we extend the WitnessGenerator type to now return an InputScript. This allows it to be more encompassing, as now callers can expect a sigScript to be populated if the input being swept requires a sigScript field. Along the way, we've also renamed input.BuildWitness to input.CraftInputScript. We also take a step towards allowing the sweeper to sweep transactions for n2pwkh outputs. We do so by modifying the BuiltWitness method to instead return an InputScript. Additionally, when populating inputs if a sigScript is present, it will now be populated. --- breacharbiter.go | 13 +++--- lnwallet/witnessgen.go | 98 +++++++++++++++++++++++++++++++++++------- sweep/input.go | 52 +++++++++++++--------- sweep/txgenerator.go | 16 ++++--- 4 files changed, 132 insertions(+), 47 deletions(-) diff --git a/breacharbiter.go b/breacharbiter.go index 45c4bafc1..269a7b124 100644 --- a/breacharbiter.go +++ b/breacharbiter.go @@ -807,13 +807,13 @@ func (bo *breachedOutput) SignDesc() *lnwallet.SignDescriptor { return &bo.signDesc } -// BuildWitness computes a valid witness that allows us to spend from the +// CraftInputScript computes a valid witness that allows us to spend from the // breached output. It does so by first generating and memoizing the witness // generation function, which parameterized primarily by the witness type and // sign descriptor. The method then returns the witness computed by invoking // this function on the first and subsequent calls. -func (bo *breachedOutput) BuildWitness(signer lnwallet.Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) ([][]byte, error) { +func (bo *breachedOutput) CraftInputScript(signer lnwallet.Signer, txn *wire.MsgTx, + hashCache *txscript.TxSigHashes, txinIdx int) (*lnwallet.InputScript, error) { // First, we ensure that the witness generation function has been // initialized for this breached output. @@ -1082,15 +1082,16 @@ func (b *breachArbiter) sweepSpendableOutputsTxn(txWeight int64, // First, we construct a valid witness for this outpoint and // transaction using the SpendableOutput's witness generation // function. - witness, err := so.BuildWitness(b.cfg.Signer, txn, hashCache, - idx) + inputScript, err := so.CraftInputScript( + b.cfg.Signer, txn, hashCache, idx, + ) if err != nil { return err } // Then, we add the witness to the transaction at the // appropriate txin index. - txn.TxIn[idx].Witness = witness + txn.TxIn[idx].Witness = inputScript.Witness return nil } diff --git a/lnwallet/witnessgen.go b/lnwallet/witnessgen.go index 00c3fab09..f2ff9236c 100644 --- a/lnwallet/witnessgen.go +++ b/lnwallet/witnessgen.go @@ -110,18 +110,22 @@ func (wt WitnessType) String() string { } // WitnessGenerator represents a function which is able to generate the final -// witness for a particular public key script. This function acts as an -// abstraction layer, hiding the details of the underlying script. +// witness for a particular public key script. Additionally, if required, this +// function will also return the sigScript for spending nested P2SH witness +// outputs. This function acts as an abstraction layer, hiding the details of +// the underlying script. type WitnessGenerator func(tx *wire.MsgTx, hc *txscript.TxSigHashes, - inputIndex int) ([][]byte, error) + inputIndex int) (*InputScript, error) -// GenWitnessFunc will return a WitnessGenerator function that an output -// uses to generate the witness for a sweep transaction. +// GenWitnessFunc will return a WitnessGenerator function that an output uses +// to generate the witness and optionally the sigScript for a sweep +// transaction. The sigScript will be generated if the witness type warrants +// one for spending, such as the NestedWitnessKeyHash witness type. func (wt WitnessType) GenWitnessFunc(signer Signer, descriptor *SignDescriptor) WitnessGenerator { return func(tx *wire.MsgTx, hc *txscript.TxSigHashes, - inputIndex int) ([][]byte, error) { + inputIndex int) (*InputScript, error) { desc := descriptor desc.SigHashes = hc @@ -129,34 +133,98 @@ func (wt WitnessType) GenWitnessFunc(signer Signer, switch wt { case CommitmentTimeLock: - return CommitSpendTimeout(signer, desc, tx) + witness, err := CommitSpendTimeout(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case CommitmentNoDelay: - return CommitSpendNoDelay(signer, desc, tx) + witness, err := CommitSpendNoDelay(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case CommitmentRevoke: - return CommitSpendRevoke(signer, desc, tx) + witness, err := CommitSpendRevoke(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case HtlcOfferedRevoke: - return ReceiverHtlcSpendRevoke(signer, desc, tx) + witness, err := ReceiverHtlcSpendRevoke(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case HtlcAcceptedRevoke: - return SenderHtlcSpendRevoke(signer, desc, tx) + witness, err := SenderHtlcSpendRevoke(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case HtlcOfferedTimeoutSecondLevel: - return HtlcSecondLevelSpend(signer, desc, tx) + witness, err := HtlcSecondLevelSpend(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case HtlcAcceptedSuccessSecondLevel: - return HtlcSecondLevelSpend(signer, desc, tx) + witness, err := HtlcSecondLevelSpend(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case HtlcOfferedRemoteTimeout: // We pass in a value of -1 for the timeout, as we // expect the caller to have already set the lock time // value. - return receiverHtlcSpendTimeout(signer, desc, tx, -1) + witness, err := receiverHtlcSpendTimeout(signer, desc, tx, -1) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil case HtlcSecondLevelRevoke: - return htlcSpendRevoke(signer, desc, tx) + witness, err := htlcSpendRevoke(signer, desc, tx) + if err != nil { + return nil, err + } + + return &InputScript{ + Witness: witness, + }, nil + default: return nil, fmt.Errorf("unknown witness type: %v", wt) diff --git a/sweep/input.go b/sweep/input.go index 57ee79393..57a954df7 100644 --- a/sweep/input.go +++ b/sweep/input.go @@ -6,7 +6,10 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" ) -// Input contains all data needed to construct a sweep tx input. +// Input represents an abstract UTXO which is to be spent using a sweeping +// transaction. The method provided give the caller all information needed to +// construct a valid input within a sweeping transaction to sweep this +// lingering UTXO. type Input interface { // Outpoint returns the reference to the output being spent, used to // construct the corresponding transaction input. @@ -21,12 +24,14 @@ type Input interface { // that spends this output. SignDesc() *lnwallet.SignDescriptor - // BuildWitness returns a valid witness allowing this output to be - // spent, the witness should be attached to the transaction at the - // location determined by the given `txinIdx`. - BuildWitness(signer lnwallet.Signer, txn *wire.MsgTx, + // CraftInputScript returns a valid set of input scripts allowing this + // output to be spent. The returns input scripts should target the + // input at location txIndex within the passed transaction. The input + // scripts generated by this method support spending p2wkh, p2wsh, and + // also nested p2sh outputs. + CraftInputScript(signer lnwallet.Signer, txn *wire.MsgTx, hashCache *txscript.TxSigHashes, - txinIdx int) ([][]byte, error) + txinIdx int) (*lnwallet.InputScript, error) // BlocksToMaturity returns the relative timelock, as a number of // blocks, that must be built on top of the confirmation height before @@ -91,12 +96,12 @@ func MakeBaseInput(outpoint *wire.OutPoint, witnessType lnwallet.WitnessType, } } -// BuildWitness computes a valid witness that allows us to spend from the -// breached output. It does so by generating the witness generation function, -// which is parameterized primarily by the witness type and sign descriptor. -// The method then returns the witness computed by invoking this function. -func (bi *BaseInput) BuildWitness(signer lnwallet.Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) ([][]byte, error) { +// CraftInputScript returns a valid set of input scripts allowing this output +// to be spent. The returns input scripts should target the input at location +// txIndex within the passed transaction. The input scripts generated by this +// method support spending p2wkh, p2wsh, and also nested p2sh outputs. +func (bi *BaseInput) CraftInputScript(signer lnwallet.Signer, txn *wire.MsgTx, + hashCache *txscript.TxSigHashes, txinIdx int) (*lnwallet.InputScript, error) { witnessFunc := bi.witnessType.GenWitnessFunc( signer, bi.SignDesc(), @@ -138,20 +143,27 @@ func MakeHtlcSucceedInput(outpoint *wire.OutPoint, } } -// BuildWitness computes a valid witness that allows us to spend from the -// breached output. For HtlcSpendInput it will need to make the preimage part -// of the witness. -func (h *HtlcSucceedInput) BuildWitness(signer lnwallet.Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) ([][]byte, error) { +// CraftInputScript returns a valid set of input scripts allowing this output +// to be spent. The returns input scripts should target the input at location +// txIndex within the passed transaction. The input scripts generated by this +// method support spending p2wkh, p2wsh, and also nested p2sh outputs. +func (h *HtlcSucceedInput) CraftInputScript(signer lnwallet.Signer, txn *wire.MsgTx, + hashCache *txscript.TxSigHashes, txinIdx int) (*lnwallet.InputScript, error) { desc := h.signDesc desc.SigHashes = hashCache desc.InputIndex = txinIdx - return lnwallet.SenderHtlcSpendRedeem( - signer, &desc, txn, - h.preimage, + witness, err := lnwallet.SenderHtlcSpendRedeem( + signer, &desc, txn, h.preimage, ) + if err != nil { + return nil, err + } + + return &lnwallet.InputScript{ + Witness: witness, + }, nil } // BlocksToMaturity returns the relative timelock, as a number of blocks, that diff --git a/sweep/txgenerator.go b/sweep/txgenerator.go index e173706a2..e4ec37dfe 100644 --- a/sweep/txgenerator.go +++ b/sweep/txgenerator.go @@ -216,25 +216,29 @@ func createSweepTx(inputs []Input, outputPkScript []byte, hashCache := txscript.NewTxSigHashes(sweepTx) - // With all the inputs in place, use each output's unique witness + // With all the inputs in place, use each output's unique input script // function to generate the final witness required for spending. - addWitness := func(idx int, tso Input) error { - witness, err := tso.BuildWitness( + addInputScript := func(idx int, tso Input) error { + inputScript, err := tso.CraftInputScript( signer, sweepTx, hashCache, idx, ) if err != nil { return err } - sweepTx.TxIn[idx].Witness = witness + sweepTx.TxIn[idx].Witness = inputScript.Witness + + if len(inputScript.SigScript) != 0 { + sweepTx.TxIn[idx].SignatureScript = inputScript.SigScript + } return nil } - // Finally we'll attach a valid witness to each csv and cltv input + // Finally we'll attach a valid input script to each csv and cltv input // within the sweeping transaction. for i, input := range inputs { - if err := addWitness(i, input); err != nil { + if err := addInputScript(i, input); err != nil { return nil, err } } From 40f0dbb5e6572452a3e6b8221bb3b75c595767af Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 20:51:58 -0800 Subject: [PATCH 05/13] lnwallet: add witness generation functions for p2wkh and np2wkh types --- lnwallet/witnessgen.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lnwallet/witnessgen.go b/lnwallet/witnessgen.go index f2ff9236c..732836b56 100644 --- a/lnwallet/witnessgen.go +++ b/lnwallet/witnessgen.go @@ -69,6 +69,16 @@ const ( // broadcast a revoked commitment, but then also immediately attempt to // go to the second level to claim the HTLC. HtlcSecondLevelRevoke WitnessType = 9 + + // WitnessKeyHash is a witness type that allows us to spend a regular + // p2wkh output that's sent to an output which is under complete + // control of the backing wallet. + WitnessKeyHash WitnessType = 10 + + // NestedWitnessKeyHash is a witness type that allows us to sweep an + // output that sends to a nested P2SH script that pays to a key solely + // under our control. The witness generated needs to include the + NestedWitnessKeyHash WitnessType = 11 ) // Stirng returns a human readable version of the target WitnessType. @@ -225,6 +235,10 @@ func (wt WitnessType) GenWitnessFunc(signer Signer, Witness: witness, }, nil + case WitnessKeyHash: + fallthrough + case NestedWitnessKeyHash: + return signer.ComputeInputScript(tx, desc) default: return nil, fmt.Errorf("unknown witness type: %v", wt) From 4ad175c16d7c470528aa7a9fcc0136044985e2eb Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Dec 2018 20:28:03 -0600 Subject: [PATCH 06/13] sweep: update getInputWitnessSizeUpperBound to be aware of nested p2sh In this commit, we update the `getInputWitnessSizeUpperBound` and all its callers to be aware of nested p2sh witness inputs. We do so by adding another bool which is true if the output is a nested p2sh output. If so, then in order to properly estimate the total weight, the caller needs to factor in the non-witness data of the additional sigScript data push. --- sweep/sweeper_test.go | 4 +++- sweep/txgenerator.go | 55 ++++++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/sweep/sweeper_test.go b/sweep/sweeper_test.go index d2204e1d1..abce18b5a 100644 --- a/sweep/sweeper_test.go +++ b/sweep/sweeper_test.go @@ -10,6 +10,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" + "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" @@ -376,7 +377,8 @@ func TestNegativeInput(t *testing.T) { if !testTxIns(&sweepTx1, []*wire.OutPoint{ largeInput.OutPoint(), positiveInput.OutPoint(), }) { - t.Fatal("Tx does not contain expected inputs") + t.Fatalf("Tx does not contain expected inputs: %v", + spew.Sdump(sweepTx1)) } ctx.backend.mine() diff --git a/sweep/txgenerator.go b/sweep/txgenerator.go index e4ec37dfe..3cf60d6b8 100644 --- a/sweep/txgenerator.go +++ b/sweep/txgenerator.go @@ -55,7 +55,7 @@ func generateInputPartitionings(sweepableInputs []Input, // on the signature length, which is not known yet at this point. yields := make(map[wire.OutPoint]int64) for _, input := range sweepableInputs { - size, err := getInputWitnessSizeUpperBound(input) + size, _, err := getInputWitnessSizeUpperBound(input) if err != nil { return nil, fmt.Errorf( "failed adding input weight: %v", err) @@ -125,10 +125,14 @@ func getPositiveYieldInputs(sweepableInputs []Input, maxInputs int, for idx, input := range sweepableInputs { // Can ignore error, because it has already been checked when // calculating the yields. - size, _ := getInputWitnessSizeUpperBound(input) + size, isNestedP2SH, _ := getInputWitnessSizeUpperBound(input) // Keep a running weight estimate of the input set. - weightEstimate.AddWitnessInput(size) + if isNestedP2SH { + weightEstimate.AddNestedP2WSHInput(size) + } else { + weightEstimate.AddWitnessInput(size) + } newTotal := total + btcutil.Amount(input.SignDesc().Output.Value) @@ -247,45 +251,54 @@ func createSweepTx(inputs []Input, outputPkScript []byte, } // getInputWitnessSizeUpperBound returns the maximum length of the witness for -// the given input if it would be included in a tx. -func getInputWitnessSizeUpperBound(input Input) (int, error) { +// the given input if it would be included in a tx. We also return if the +// output itself is a nested p2sh output, if so then we need to take into +// account the extra sigScript data size. +func getInputWitnessSizeUpperBound(input Input) (int, bool, error) { switch input.WitnessType() { - // Outputs on a remote commitment transaction that pay directly - // to us. + // Outputs on a remote commitment transaction that pay directly to us. + case lnwallet.WitnessKeyHash: + fallthrough case lnwallet.CommitmentNoDelay: - return lnwallet.P2WKHWitnessSize, nil + return lnwallet.P2WKHWitnessSize, false, nil // Outputs on a past commitment transaction that pay directly // to us. case lnwallet.CommitmentTimeLock: - return lnwallet.ToLocalTimeoutWitnessSize, nil + return lnwallet.ToLocalTimeoutWitnessSize, false, nil // Outgoing second layer HTLC's that have confirmed within the // chain, and the output they produced is now mature enough to // sweep. case lnwallet.HtlcOfferedTimeoutSecondLevel: - return lnwallet.ToLocalTimeoutWitnessSize, nil + return lnwallet.ToLocalTimeoutWitnessSize, false, nil // Incoming second layer HTLC's that have confirmed within the // chain, and the output they produced is now mature enough to // sweep. case lnwallet.HtlcAcceptedSuccessSecondLevel: - return lnwallet.ToLocalTimeoutWitnessSize, nil + return lnwallet.ToLocalTimeoutWitnessSize, false, nil // An HTLC on the commitment transaction of the remote party, // that has had its absolute timelock expire. case lnwallet.HtlcOfferedRemoteTimeout: - return lnwallet.AcceptedHtlcTimeoutWitnessSize, nil + return lnwallet.AcceptedHtlcTimeoutWitnessSize, false, nil // An HTLC on the commitment transaction of the remote party, // that can be swept with the preimage. case lnwallet.HtlcAcceptedRemoteSuccess: - return lnwallet.OfferedHtlcSuccessWitnessSize, nil + return lnwallet.OfferedHtlcSuccessWitnessSize, false, nil + // A nested P2SH input that has a p2wkh witness script. We'll mark this + // as nested P2SH so the caller can estimate the weight properly + // including the sigScript. + case lnwallet.NestedWitnessKeyHash: + return lnwallet.P2WKHWitnessSize, true, nil } - return 0, fmt.Errorf("unexpected witness type: %v", input.WitnessType()) + return 0, false, fmt.Errorf("unexpected witness type: %v", + input.WitnessType()) } // getWeightEstimate returns a weight estimate for the given inputs. @@ -312,7 +325,10 @@ func getWeightEstimate(inputs []Input) ([]Input, int64, int, int) { for i := range inputs { input := inputs[i] - size, err := getInputWitnessSizeUpperBound(input) + // For fee estimation purposes, we'll now attempt to obtain an + // upper bound on the weight this input will add when fully + // populated. + size, isNestedP2SH, err := getInputWitnessSizeUpperBound(input) if err != nil { log.Warn(err) @@ -320,7 +336,14 @@ func getWeightEstimate(inputs []Input) ([]Input, int64, int, int) { // given. continue } - weightEstimate.AddWitnessInput(size) + + // If this is a nested P2SH input, then we'll need to factor in + // the additional data push within the sigScript. + if isNestedP2SH { + weightEstimate.AddNestedP2WSHInput(size) + } else { + weightEstimate.AddWitnessInput(size) + } switch input.WitnessType() { case lnwallet.CommitmentTimeLock, From 9c29e6182640bc901f0b7a1efc4648433deae307 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 20:59:40 -0800 Subject: [PATCH 07/13] sweep: add new CraftSweepAllTx method to fully withdrawal from a wallet In this commit, we add a new function, CraftSweepAllTx. This function allows callers to craft a transaction which sweeps ALL outputs from the wallet to a single target address. It can either be used for UTXO consolidation (at the cost of privacy by co-mingling inputs), or simply to sweep all funds out of a wallet for various reasons. In an attempt to ensure this method is loosely coupled and testable, for all behavior structs, we create brand new interface to accept. This ensures that we only rely on the minimal number of methods needed to perform our duty. --- sweep/walletsweep.go | 205 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/sweep/walletsweep.go b/sweep/walletsweep.go index 24417cbec..34ba74bab 100644 --- a/sweep/walletsweep.go +++ b/sweep/walletsweep.go @@ -2,7 +2,11 @@ package sweep import ( "fmt" + "math" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/lnwallet" ) @@ -66,3 +70,204 @@ func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator, return feePerKw, nil } } + +// UtxoSource is an interface that allows a caller to access a source of UTXOs +// to use when crafting sweep transactions. +type UtxoSource interface { + // ListUnspentWitness returns all UTXOs from the source that have + // between minConfs and maxConfs number of confirmations. + ListUnspentWitness(minConfs, maxConfs int32) ([]*lnwallet.Utxo, error) + + // FetchInputInfo returns the matching output for an outpoint. If the + // outpoint doesn't belong to this UTXO source, then an error should be + // returned. + FetchInputInfo(*wire.OutPoint) (*wire.TxOut, error) +} + +// CoinSelectionLocker is an interface that allows the caller to perform an +// operation, which is synchronized with all coin selection attempts. This can +// be used when an operation requires that all coin selection operations cease +// forward progress. Think of this as an exclusive lock on coin selection +// operations. +type CoinSelectionLocker interface { + // WithCoinSelectLock will execute the passed function closure in a + // synchronized manner preventing any coin selection operations from + // proceeding while the closure if executing. This can be seen as the + // ability to execute a function closure under an exclusive coin + // selection lock. + WithCoinSelectLock(func() error) error +} + +// OutpointLocker allows a caller to lock/unlock an outpoint. When locked, the +// outpoints shouldn't be used for any sort of channel funding of coin +// selection. Locked outpoints are not expect to be persisted between restarts. +type OutpointLocker interface { + // LockOutpoint locks a target outpoint, rendering it unusable for coin + // selection. + LockOutpoint(o wire.OutPoint) + + // UnlockOutpoint unlocks a target outpoint, allowing it to be used for + // coin selection once again. + UnlockOutpoint(o wire.OutPoint) +} + +// WalletSweepPackage is a package that gives the caller the ability to sweep +// ALL funds from a wallet in a single transaction. We also package a function +// closure that allows one to abort the operation. +type WalletSweepPackage struct { + // SweepTx is a fully signed, and valid transaction that is broadcast, + // will sweep ALL confirmed coins in the wallet with a single + // transaction. + SweepTx *wire.MsgTx + + // CancelSweepAttempt allows the caller to cancel the sweep attempt. + // + // NOTE: If the sweeping transaction isn't or cannot be broadcast, then + // this closure MUST be called, otherwise all selected utxos will be + // unable to be used. + CancelSweepAttempt func() +} + +// CraftSweepAllTx attempts to craft a WalletSweepPackage which will allow the +// caller to sweep ALL outputs within the wallet to a single UTXO, as specified +// by the delivery address. The sweep transaction will be crafted with the +// target fee rate, and will use the utxoSource and outpointLocker as sources +// for wallet funds. +func CraftSweepAllTx(feeRate lnwallet.SatPerKWeight, blockHeight uint32, + deliveryAddr btcutil.Address, coinSelectLocker CoinSelectionLocker, + utxoSource UtxoSource, outpointLocker OutpointLocker, + feeEstimator lnwallet.FeeEstimator, + signer lnwallet.Signer) (*WalletSweepPackage, error) { + + // TODO(roasbeef): turn off ATPL as well when available? + + var allOutputs []*lnwallet.Utxo + + // We'll make a function closure up front that allows us to unlock all + // selected outputs to ensure that they become available again in the + // case of an error after the outputs have been locked, but before we + // can actually craft a sweeping transaction. + unlockOutputs := func() { + for _, utxo := range allOutputs { + outpointLocker.UnlockOutpoint(utxo.OutPoint) + } + } + + // Next, we'll use the coinSelectLocker to ensure that no coin + // selection takes place while we fetch and lock all outputs the wallet + // knows of. Otherwise, it may be possible for a new funding flow to + // lock an output while we fetch the set of unspent witnesses. + err := coinSelectLocker.WithCoinSelectLock(func() error { + // Now that we can be sure that no other coin selection + // operations are going on, we can grab a clean snapshot of the + // current UTXO state of the wallet. + utxos, err := utxoSource.ListUnspentWitness( + 1, math.MaxInt32, + ) + if err != nil { + return err + } + + // We'll now lock each UTXO to ensure that other callers don't + // attempt to use these UTXOs in transactions while we're + // crafting out sweep all transaction. + for _, utxo := range utxos { + outpointLocker.LockOutpoint(utxo.OutPoint) + } + + allOutputs = append(allOutputs, utxos...) + + return nil + }) + if err != nil { + // If we failed at all, we'll unlock any outputs selected just + // in case we had any lingering outputs. + unlockOutputs() + + return nil, fmt.Errorf("unable to fetch+lock wallet "+ + "utxos: %v", err) + } + + // Now that we've locked all the potential outputs to sweep, we'll + // assemble an input for each of them, so we can hand it off to the + // sweeper to generate and sign a transaction for us. + var inputsToSweep []Input + for _, output := range allOutputs { + // We'll consult the utxoSource for information concerning this + // outpoint, we'll need to properly populate a signDescriptor + // for this output. + outputInfo, err := utxoSource.FetchInputInfo(&output.OutPoint) + if err != nil { + unlockOutputs() + + return nil, err + } + + // As we'll be signing for outputs under control of the wallet, + // we only need to populate the output value and output script. + // The rest of the items will be populated internally within + // the sweeper via the witness generation function. + signDesc := &lnwallet.SignDescriptor{ + Output: outputInfo, + HashType: txscript.SigHashAll, + } + + pkScript := outputInfo.PkScript + + // Based on the output type, we'll map it to the proper witness + // type so we can generate the set of input scripts needed to + // sweep the output. + var witnessType lnwallet.WitnessType + switch { + + // If this is a p2wkh output, then we'll assume it's a witness + // key hash witness type. + case txscript.IsPayToWitnessPubKeyHash(pkScript): + witnessType = lnwallet.WitnessKeyHash + + // If this is a p2sh output, then as since it's under control + // of the wallet, we'll assume it's a nested p2sh output. + case txscript.IsPayToScriptHash(pkScript): + witnessType = lnwallet.NestedWitnessKeyHash + + // All other output types we count as unknown and will fail to + // sweep. + default: + unlockOutputs() + + return nil, fmt.Errorf("unable to sweep coins, "+ + "unknown script: %x", pkScript[:]) + } + + // Now that we've constructed the items required, we'll make an + // input which can be passed to the sweeper for ultimate + // sweeping. + input := MakeBaseInput(&output.OutPoint, witnessType, signDesc, 0) + inputsToSweep = append(inputsToSweep, &input) + } + + // Next, we'll convert the delivery addr to a pkScript that we can use + // to create the sweep transaction. + deliveryPkScript, err := txscript.PayToAddrScript(deliveryAddr) + if err != nil { + unlockOutputs() + + return nil, err + } + + // Finally, we'll ask the sweeper to craft a sweep transaction which + // respects our fee preference and targets all the UTXOs of the wallet. + sweepTx, err := createSweepTx( + inputsToSweep, deliveryPkScript, blockHeight, feeRate, signer, + ) + if err != nil { + unlockOutputs() + + return nil, err + } + + return &WalletSweepPackage{ + SweepTx: sweepTx, + CancelSweepAttempt: unlockOutputs, + }, nil +} From 4b316d97c8688a2754f1435d21e90a9ccfa94e48 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 21:06:59 -0800 Subject: [PATCH 08/13] lnwallet: add new WithCoinSelectLock method to fix coin select race conditions In this commit, we add a new method WithCoinSelectLock. This method will allow us to fix bugs in the project atm that can arise if a channel funding is attempted (either manually or by autopilot) while a users is attempting to send an on-chain transaction. If this happens concurrently, then both contexts will grab the set of UTXOs and attempt to lock them one by one. However, since they didn't obtain an exclusive snapshot of the UTXO set of the wallet, they may both attempt to lock the same input. We also ensure that calls to SendMany cannot run into this issue by using the WithCoinSelectLock synchronization when attempting to instruct the internal wallet to send payments. --- lnwallet/wallet.go | 11 +++++++++++ rpcserver.go | 19 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 6f7863dc5..2dabf056d 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -1252,6 +1252,17 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { l.limboMtx.Unlock() } +// WithCoinSelectLock will execute the passed function closure in a +// synchronized manner preventing any coin selection operations from proceeding +// while the closure if executing. This can be seen as the ability to execute a +// function closure under an exclusive coin selection lock. +func (l *LightningWallet) WithCoinSelectLock(f func() error) error { + l.coinSelectMtx.Lock() + defer l.coinSelectMtx.Unlock() + + return f() +} + // selectCoinsAndChange performs coin selection in order to obtain witness // outputs which sum to at least 'numCoins' amount of satoshis. If coin // selection is successful/possible, then the selected coins are available diff --git a/rpcserver.go b/rpcserver.go index dfd3e8905..a49fea0a4 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -804,7 +804,24 @@ func (r *rpcServer) SendMany(ctx context.Context, rpcsLog.Infof("[sendmany] outputs=%v, sat/kw=%v", spew.Sdump(in.AddrToAmount), int64(feePerKw)) - txid, err := r.sendCoinsOnChain(in.AddrToAmount, feePerKw) + var txid *chainhash.Hash + + // We'll attempt to send to the target set of outputs, ensuring that we + // synchronize with any other ongoing coin selection attempts which + // happen to also be concurrently executing. + wallet := r.server.cc.wallet + err = wallet.WithCoinSelectLock(func() error { + sendManyTXID, err := r.sendCoinsOnChain( + in.AddrToAmount, feePerKw, + ) + if err != nil { + return err + } + + txid = sendManyTXID + + return nil + }) if err != nil { return nil, err } From 36ff16cce4531752fba3d80ac471c5fcd9848bf2 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 21:07:48 -0800 Subject: [PATCH 09/13] lnrpc: add new SendAll field to SendCoinsRequest --- lnrpc/rpc.pb.go | 1104 ++++++++++++++++++++-------------------- lnrpc/rpc.proto | 7 + lnrpc/rpc.swagger.json | 11 +- 3 files changed, 576 insertions(+), 546 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 3cbefc016..54d0402db 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -49,7 +49,7 @@ func (x AddressType) String() string { return proto.EnumName(AddressType_name, int32(x)) } func (AddressType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{0} + return fileDescriptor_rpc_e66000aa8614d793, []int{0} } type ChannelCloseSummary_ClosureType int32 @@ -84,7 +84,7 @@ func (x ChannelCloseSummary_ClosureType) String() string { return proto.EnumName(ChannelCloseSummary_ClosureType_name, int32(x)) } func (ChannelCloseSummary_ClosureType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{38, 0} + return fileDescriptor_rpc_e66000aa8614d793, []int{38, 0} } type Invoice_InvoiceState int32 @@ -107,7 +107,7 @@ func (x Invoice_InvoiceState) String() string { return proto.EnumName(Invoice_InvoiceState_name, int32(x)) } func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{86, 0} + return fileDescriptor_rpc_e66000aa8614d793, []int{86, 0} } type GenSeedRequest struct { @@ -128,7 +128,7 @@ func (m *GenSeedRequest) Reset() { *m = GenSeedRequest{} } func (m *GenSeedRequest) String() string { return proto.CompactTextString(m) } func (*GenSeedRequest) ProtoMessage() {} func (*GenSeedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{0} + return fileDescriptor_rpc_e66000aa8614d793, []int{0} } func (m *GenSeedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GenSeedRequest.Unmarshal(m, b) @@ -183,7 +183,7 @@ func (m *GenSeedResponse) Reset() { *m = GenSeedResponse{} } func (m *GenSeedResponse) String() string { return proto.CompactTextString(m) } func (*GenSeedResponse) ProtoMessage() {} func (*GenSeedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{1} + return fileDescriptor_rpc_e66000aa8614d793, []int{1} } func (m *GenSeedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GenSeedResponse.Unmarshal(m, b) @@ -248,7 +248,7 @@ func (m *InitWalletRequest) Reset() { *m = InitWalletRequest{} } func (m *InitWalletRequest) String() string { return proto.CompactTextString(m) } func (*InitWalletRequest) ProtoMessage() {} func (*InitWalletRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{2} + return fileDescriptor_rpc_e66000aa8614d793, []int{2} } func (m *InitWalletRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitWalletRequest.Unmarshal(m, b) @@ -306,7 +306,7 @@ func (m *InitWalletResponse) Reset() { *m = InitWalletResponse{} } func (m *InitWalletResponse) String() string { return proto.CompactTextString(m) } func (*InitWalletResponse) ProtoMessage() {} func (*InitWalletResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{3} + return fileDescriptor_rpc_e66000aa8614d793, []int{3} } func (m *InitWalletResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitWalletResponse.Unmarshal(m, b) @@ -348,7 +348,7 @@ func (m *UnlockWalletRequest) Reset() { *m = UnlockWalletRequest{} } func (m *UnlockWalletRequest) String() string { return proto.CompactTextString(m) } func (*UnlockWalletRequest) ProtoMessage() {} func (*UnlockWalletRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{4} + return fileDescriptor_rpc_e66000aa8614d793, []int{4} } func (m *UnlockWalletRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UnlockWalletRequest.Unmarshal(m, b) @@ -392,7 +392,7 @@ func (m *UnlockWalletResponse) Reset() { *m = UnlockWalletResponse{} } func (m *UnlockWalletResponse) String() string { return proto.CompactTextString(m) } func (*UnlockWalletResponse) ProtoMessage() {} func (*UnlockWalletResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{5} + return fileDescriptor_rpc_e66000aa8614d793, []int{5} } func (m *UnlockWalletResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UnlockWalletResponse.Unmarshal(m, b) @@ -430,7 +430,7 @@ func (m *ChangePasswordRequest) Reset() { *m = ChangePasswordRequest{} } func (m *ChangePasswordRequest) String() string { return proto.CompactTextString(m) } func (*ChangePasswordRequest) ProtoMessage() {} func (*ChangePasswordRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{6} + return fileDescriptor_rpc_e66000aa8614d793, []int{6} } func (m *ChangePasswordRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangePasswordRequest.Unmarshal(m, b) @@ -474,7 +474,7 @@ func (m *ChangePasswordResponse) Reset() { *m = ChangePasswordResponse{} func (m *ChangePasswordResponse) String() string { return proto.CompactTextString(m) } func (*ChangePasswordResponse) ProtoMessage() {} func (*ChangePasswordResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{7} + return fileDescriptor_rpc_e66000aa8614d793, []int{7} } func (m *ChangePasswordResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangePasswordResponse.Unmarshal(m, b) @@ -518,7 +518,7 @@ func (m *Utxo) Reset() { *m = Utxo{} } func (m *Utxo) String() string { return proto.CompactTextString(m) } func (*Utxo) ProtoMessage() {} func (*Utxo) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{8} + return fileDescriptor_rpc_e66000aa8614d793, []int{8} } func (m *Utxo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Utxo.Unmarshal(m, b) @@ -606,7 +606,7 @@ func (m *Transaction) Reset() { *m = Transaction{} } func (m *Transaction) String() string { return proto.CompactTextString(m) } func (*Transaction) ProtoMessage() {} func (*Transaction) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{9} + return fileDescriptor_rpc_e66000aa8614d793, []int{9} } func (m *Transaction) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Transaction.Unmarshal(m, b) @@ -692,7 +692,7 @@ func (m *GetTransactionsRequest) Reset() { *m = GetTransactionsRequest{} func (m *GetTransactionsRequest) String() string { return proto.CompactTextString(m) } func (*GetTransactionsRequest) ProtoMessage() {} func (*GetTransactionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{10} + return fileDescriptor_rpc_e66000aa8614d793, []int{10} } func (m *GetTransactionsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTransactionsRequest.Unmarshal(m, b) @@ -724,7 +724,7 @@ func (m *TransactionDetails) Reset() { *m = TransactionDetails{} } func (m *TransactionDetails) String() string { return proto.CompactTextString(m) } func (*TransactionDetails) ProtoMessage() {} func (*TransactionDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{11} + return fileDescriptor_rpc_e66000aa8614d793, []int{11} } func (m *TransactionDetails) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TransactionDetails.Unmarshal(m, b) @@ -765,7 +765,7 @@ func (m *FeeLimit) Reset() { *m = FeeLimit{} } func (m *FeeLimit) String() string { return proto.CompactTextString(m) } func (*FeeLimit) ProtoMessage() {} func (*FeeLimit) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{12} + return fileDescriptor_rpc_e66000aa8614d793, []int{12} } func (m *FeeLimit) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_FeeLimit.Unmarshal(m, b) @@ -921,7 +921,7 @@ func (m *SendRequest) Reset() { *m = SendRequest{} } func (m *SendRequest) String() string { return proto.CompactTextString(m) } func (*SendRequest) ProtoMessage() {} func (*SendRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{13} + return fileDescriptor_rpc_e66000aa8614d793, []int{13} } func (m *SendRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendRequest.Unmarshal(m, b) @@ -1011,7 +1011,7 @@ func (m *SendResponse) Reset() { *m = SendResponse{} } func (m *SendResponse) String() string { return proto.CompactTextString(m) } func (*SendResponse) ProtoMessage() {} func (*SendResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{14} + return fileDescriptor_rpc_e66000aa8614d793, []int{14} } func (m *SendResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendResponse.Unmarshal(m, b) @@ -1075,7 +1075,7 @@ func (m *SendToRouteRequest) Reset() { *m = SendToRouteRequest{} } func (m *SendToRouteRequest) String() string { return proto.CompactTextString(m) } func (*SendToRouteRequest) ProtoMessage() {} func (*SendToRouteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{15} + return fileDescriptor_rpc_e66000aa8614d793, []int{15} } func (m *SendToRouteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendToRouteRequest.Unmarshal(m, b) @@ -1132,7 +1132,7 @@ func (m *ChannelPoint) Reset() { *m = ChannelPoint{} } func (m *ChannelPoint) String() string { return proto.CompactTextString(m) } func (*ChannelPoint) ProtoMessage() {} func (*ChannelPoint) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{16} + return fileDescriptor_rpc_e66000aa8614d793, []int{16} } func (m *ChannelPoint) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelPoint.Unmarshal(m, b) @@ -1276,7 +1276,7 @@ func (m *LightningAddress) Reset() { *m = LightningAddress{} } func (m *LightningAddress) String() string { return proto.CompactTextString(m) } func (*LightningAddress) ProtoMessage() {} func (*LightningAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{17} + return fileDescriptor_rpc_e66000aa8614d793, []int{17} } func (m *LightningAddress) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LightningAddress.Unmarshal(m, b) @@ -1326,7 +1326,7 @@ func (m *SendManyRequest) Reset() { *m = SendManyRequest{} } func (m *SendManyRequest) String() string { return proto.CompactTextString(m) } func (*SendManyRequest) ProtoMessage() {} func (*SendManyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{18} + return fileDescriptor_rpc_e66000aa8614d793, []int{18} } func (m *SendManyRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendManyRequest.Unmarshal(m, b) @@ -1379,7 +1379,7 @@ func (m *SendManyResponse) Reset() { *m = SendManyResponse{} } func (m *SendManyResponse) String() string { return proto.CompactTextString(m) } func (*SendManyResponse) ProtoMessage() {} func (*SendManyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{19} + return fileDescriptor_rpc_e66000aa8614d793, []int{19} } func (m *SendManyResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendManyResponse.Unmarshal(m, b) @@ -1414,7 +1414,12 @@ type SendCoinsRequest struct { // / The target number of blocks that this transaction should be confirmed by. TargetConf int32 `protobuf:"varint,3,opt,name=target_conf,json=targetConf,proto3" json:"target_conf,omitempty"` // / A manual fee rate set in sat/byte that should be used when crafting the transaction. - SatPerByte int64 `protobuf:"varint,5,opt,name=sat_per_byte,json=satPerByte,proto3" json:"sat_per_byte,omitempty"` + SatPerByte int64 `protobuf:"varint,5,opt,name=sat_per_byte,json=satPerByte,proto3" json:"sat_per_byte,omitempty"` + // * + // If set, then the amount field will be ignored, and lnd will attempt to + // send all the coins under control of the internal wallet to the specified + // address. + SendAll bool `protobuf:"varint,6,opt,name=send_all,json=sendAll,proto3" json:"send_all,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1424,7 +1429,7 @@ func (m *SendCoinsRequest) Reset() { *m = SendCoinsRequest{} } func (m *SendCoinsRequest) String() string { return proto.CompactTextString(m) } func (*SendCoinsRequest) ProtoMessage() {} func (*SendCoinsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{20} + return fileDescriptor_rpc_e66000aa8614d793, []int{20} } func (m *SendCoinsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendCoinsRequest.Unmarshal(m, b) @@ -1472,6 +1477,13 @@ func (m *SendCoinsRequest) GetSatPerByte() int64 { return 0 } +func (m *SendCoinsRequest) GetSendAll() bool { + if m != nil { + return m.SendAll + } + return false +} + type SendCoinsResponse struct { // / The transaction ID of the transaction Txid string `protobuf:"bytes,1,opt,name=txid,proto3" json:"txid,omitempty"` @@ -1484,7 +1496,7 @@ func (m *SendCoinsResponse) Reset() { *m = SendCoinsResponse{} } func (m *SendCoinsResponse) String() string { return proto.CompactTextString(m) } func (*SendCoinsResponse) ProtoMessage() {} func (*SendCoinsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{21} + return fileDescriptor_rpc_e66000aa8614d793, []int{21} } func (m *SendCoinsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendCoinsResponse.Unmarshal(m, b) @@ -1525,7 +1537,7 @@ func (m *ListUnspentRequest) Reset() { *m = ListUnspentRequest{} } func (m *ListUnspentRequest) String() string { return proto.CompactTextString(m) } func (*ListUnspentRequest) ProtoMessage() {} func (*ListUnspentRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{22} + return fileDescriptor_rpc_e66000aa8614d793, []int{22} } func (m *ListUnspentRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListUnspentRequest.Unmarshal(m, b) @@ -1571,7 +1583,7 @@ func (m *ListUnspentResponse) Reset() { *m = ListUnspentResponse{} } func (m *ListUnspentResponse) String() string { return proto.CompactTextString(m) } func (*ListUnspentResponse) ProtoMessage() {} func (*ListUnspentResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{23} + return fileDescriptor_rpc_e66000aa8614d793, []int{23} } func (m *ListUnspentResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListUnspentResponse.Unmarshal(m, b) @@ -1610,7 +1622,7 @@ func (m *NewAddressRequest) Reset() { *m = NewAddressRequest{} } func (m *NewAddressRequest) String() string { return proto.CompactTextString(m) } func (*NewAddressRequest) ProtoMessage() {} func (*NewAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{24} + return fileDescriptor_rpc_e66000aa8614d793, []int{24} } func (m *NewAddressRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NewAddressRequest.Unmarshal(m, b) @@ -1649,7 +1661,7 @@ func (m *NewAddressResponse) Reset() { *m = NewAddressResponse{} } func (m *NewAddressResponse) String() string { return proto.CompactTextString(m) } func (*NewAddressResponse) ProtoMessage() {} func (*NewAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{25} + return fileDescriptor_rpc_e66000aa8614d793, []int{25} } func (m *NewAddressResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NewAddressResponse.Unmarshal(m, b) @@ -1688,7 +1700,7 @@ func (m *SignMessageRequest) Reset() { *m = SignMessageRequest{} } func (m *SignMessageRequest) String() string { return proto.CompactTextString(m) } func (*SignMessageRequest) ProtoMessage() {} func (*SignMessageRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{26} + return fileDescriptor_rpc_e66000aa8614d793, []int{26} } func (m *SignMessageRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SignMessageRequest.Unmarshal(m, b) @@ -1727,7 +1739,7 @@ func (m *SignMessageResponse) Reset() { *m = SignMessageResponse{} } func (m *SignMessageResponse) String() string { return proto.CompactTextString(m) } func (*SignMessageResponse) ProtoMessage() {} func (*SignMessageResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{27} + return fileDescriptor_rpc_e66000aa8614d793, []int{27} } func (m *SignMessageResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SignMessageResponse.Unmarshal(m, b) @@ -1768,7 +1780,7 @@ func (m *VerifyMessageRequest) Reset() { *m = VerifyMessageRequest{} } func (m *VerifyMessageRequest) String() string { return proto.CompactTextString(m) } func (*VerifyMessageRequest) ProtoMessage() {} func (*VerifyMessageRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{28} + return fileDescriptor_rpc_e66000aa8614d793, []int{28} } func (m *VerifyMessageRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VerifyMessageRequest.Unmarshal(m, b) @@ -1816,7 +1828,7 @@ func (m *VerifyMessageResponse) Reset() { *m = VerifyMessageResponse{} } func (m *VerifyMessageResponse) String() string { return proto.CompactTextString(m) } func (*VerifyMessageResponse) ProtoMessage() {} func (*VerifyMessageResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{29} + return fileDescriptor_rpc_e66000aa8614d793, []int{29} } func (m *VerifyMessageResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VerifyMessageResponse.Unmarshal(m, b) @@ -1865,7 +1877,7 @@ func (m *ConnectPeerRequest) Reset() { *m = ConnectPeerRequest{} } func (m *ConnectPeerRequest) String() string { return proto.CompactTextString(m) } func (*ConnectPeerRequest) ProtoMessage() {} func (*ConnectPeerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{30} + return fileDescriptor_rpc_e66000aa8614d793, []int{30} } func (m *ConnectPeerRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConnectPeerRequest.Unmarshal(m, b) @@ -1909,7 +1921,7 @@ func (m *ConnectPeerResponse) Reset() { *m = ConnectPeerResponse{} } func (m *ConnectPeerResponse) String() string { return proto.CompactTextString(m) } func (*ConnectPeerResponse) ProtoMessage() {} func (*ConnectPeerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{31} + return fileDescriptor_rpc_e66000aa8614d793, []int{31} } func (m *ConnectPeerResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConnectPeerResponse.Unmarshal(m, b) @@ -1941,7 +1953,7 @@ func (m *DisconnectPeerRequest) Reset() { *m = DisconnectPeerRequest{} } func (m *DisconnectPeerRequest) String() string { return proto.CompactTextString(m) } func (*DisconnectPeerRequest) ProtoMessage() {} func (*DisconnectPeerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{32} + return fileDescriptor_rpc_e66000aa8614d793, []int{32} } func (m *DisconnectPeerRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DisconnectPeerRequest.Unmarshal(m, b) @@ -1978,7 +1990,7 @@ func (m *DisconnectPeerResponse) Reset() { *m = DisconnectPeerResponse{} func (m *DisconnectPeerResponse) String() string { return proto.CompactTextString(m) } func (*DisconnectPeerResponse) ProtoMessage() {} func (*DisconnectPeerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{33} + return fileDescriptor_rpc_e66000aa8614d793, []int{33} } func (m *DisconnectPeerResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DisconnectPeerResponse.Unmarshal(m, b) @@ -2012,7 +2024,7 @@ func (m *HTLC) Reset() { *m = HTLC{} } func (m *HTLC) String() string { return proto.CompactTextString(m) } func (*HTLC) ProtoMessage() {} func (*HTLC) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{34} + return fileDescriptor_rpc_e66000aa8614d793, []int{34} } func (m *HTLC) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HTLC.Unmarshal(m, b) @@ -2124,7 +2136,7 @@ func (m *Channel) Reset() { *m = Channel{} } func (m *Channel) String() string { return proto.CompactTextString(m) } func (*Channel) ProtoMessage() {} func (*Channel) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{35} + return fileDescriptor_rpc_e66000aa8614d793, []int{35} } func (m *Channel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Channel.Unmarshal(m, b) @@ -2277,7 +2289,7 @@ func (m *ListChannelsRequest) Reset() { *m = ListChannelsRequest{} } func (m *ListChannelsRequest) String() string { return proto.CompactTextString(m) } func (*ListChannelsRequest) ProtoMessage() {} func (*ListChannelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{36} + return fileDescriptor_rpc_e66000aa8614d793, []int{36} } func (m *ListChannelsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListChannelsRequest.Unmarshal(m, b) @@ -2337,7 +2349,7 @@ func (m *ListChannelsResponse) Reset() { *m = ListChannelsResponse{} } func (m *ListChannelsResponse) String() string { return proto.CompactTextString(m) } func (*ListChannelsResponse) ProtoMessage() {} func (*ListChannelsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{37} + return fileDescriptor_rpc_e66000aa8614d793, []int{37} } func (m *ListChannelsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListChannelsResponse.Unmarshal(m, b) @@ -2394,7 +2406,7 @@ func (m *ChannelCloseSummary) Reset() { *m = ChannelCloseSummary{} } func (m *ChannelCloseSummary) String() string { return proto.CompactTextString(m) } func (*ChannelCloseSummary) ProtoMessage() {} func (*ChannelCloseSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{38} + return fileDescriptor_rpc_e66000aa8614d793, []int{38} } func (m *ChannelCloseSummary) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelCloseSummary.Unmarshal(m, b) @@ -2500,7 +2512,7 @@ func (m *ClosedChannelsRequest) Reset() { *m = ClosedChannelsRequest{} } func (m *ClosedChannelsRequest) String() string { return proto.CompactTextString(m) } func (*ClosedChannelsRequest) ProtoMessage() {} func (*ClosedChannelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{39} + return fileDescriptor_rpc_e66000aa8614d793, []int{39} } func (m *ClosedChannelsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ClosedChannelsRequest.Unmarshal(m, b) @@ -2573,7 +2585,7 @@ func (m *ClosedChannelsResponse) Reset() { *m = ClosedChannelsResponse{} func (m *ClosedChannelsResponse) String() string { return proto.CompactTextString(m) } func (*ClosedChannelsResponse) ProtoMessage() {} func (*ClosedChannelsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{40} + return fileDescriptor_rpc_e66000aa8614d793, []int{40} } func (m *ClosedChannelsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ClosedChannelsResponse.Unmarshal(m, b) @@ -2626,7 +2638,7 @@ func (m *Peer) Reset() { *m = Peer{} } func (m *Peer) String() string { return proto.CompactTextString(m) } func (*Peer) ProtoMessage() {} func (*Peer) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{41} + return fileDescriptor_rpc_e66000aa8614d793, []int{41} } func (m *Peer) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Peer.Unmarshal(m, b) @@ -2712,7 +2724,7 @@ func (m *ListPeersRequest) Reset() { *m = ListPeersRequest{} } func (m *ListPeersRequest) String() string { return proto.CompactTextString(m) } func (*ListPeersRequest) ProtoMessage() {} func (*ListPeersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{42} + return fileDescriptor_rpc_e66000aa8614d793, []int{42} } func (m *ListPeersRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListPeersRequest.Unmarshal(m, b) @@ -2744,7 +2756,7 @@ func (m *ListPeersResponse) Reset() { *m = ListPeersResponse{} } func (m *ListPeersResponse) String() string { return proto.CompactTextString(m) } func (*ListPeersResponse) ProtoMessage() {} func (*ListPeersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{43} + return fileDescriptor_rpc_e66000aa8614d793, []int{43} } func (m *ListPeersResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListPeersResponse.Unmarshal(m, b) @@ -2781,7 +2793,7 @@ func (m *GetInfoRequest) Reset() { *m = GetInfoRequest{} } func (m *GetInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetInfoRequest) ProtoMessage() {} func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{44} + return fileDescriptor_rpc_e66000aa8614d793, []int{44} } func (m *GetInfoRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetInfoRequest.Unmarshal(m, b) @@ -2841,7 +2853,7 @@ func (m *GetInfoResponse) Reset() { *m = GetInfoResponse{} } func (m *GetInfoResponse) String() string { return proto.CompactTextString(m) } func (*GetInfoResponse) ProtoMessage() {} func (*GetInfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{45} + return fileDescriptor_rpc_e66000aa8614d793, []int{45} } func (m *GetInfoResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetInfoResponse.Unmarshal(m, b) @@ -2961,7 +2973,9 @@ func (m *GetInfoResponse) GetChains() []*Chain { } type Chain struct { - Chain string `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"` + // / The blockchain the node is on (eg bitcoin, litecoin) + Chain string `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"` + // / The network the node is on (eg regtest, testnet, mainnet) Network string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -2972,7 +2986,7 @@ func (m *Chain) Reset() { *m = Chain{} } func (m *Chain) String() string { return proto.CompactTextString(m) } func (*Chain) ProtoMessage() {} func (*Chain) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{46} + return fileDescriptor_rpc_e66000aa8614d793, []int{46} } func (m *Chain) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Chain.Unmarshal(m, b) @@ -3019,7 +3033,7 @@ func (m *ConfirmationUpdate) Reset() { *m = ConfirmationUpdate{} } func (m *ConfirmationUpdate) String() string { return proto.CompactTextString(m) } func (*ConfirmationUpdate) ProtoMessage() {} func (*ConfirmationUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{47} + return fileDescriptor_rpc_e66000aa8614d793, []int{47} } func (m *ConfirmationUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfirmationUpdate.Unmarshal(m, b) @@ -3071,7 +3085,7 @@ func (m *ChannelOpenUpdate) Reset() { *m = ChannelOpenUpdate{} } func (m *ChannelOpenUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelOpenUpdate) ProtoMessage() {} func (*ChannelOpenUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{48} + return fileDescriptor_rpc_e66000aa8614d793, []int{48} } func (m *ChannelOpenUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelOpenUpdate.Unmarshal(m, b) @@ -3110,7 +3124,7 @@ func (m *ChannelCloseUpdate) Reset() { *m = ChannelCloseUpdate{} } func (m *ChannelCloseUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelCloseUpdate) ProtoMessage() {} func (*ChannelCloseUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{49} + return fileDescriptor_rpc_e66000aa8614d793, []int{49} } func (m *ChannelCloseUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelCloseUpdate.Unmarshal(m, b) @@ -3165,7 +3179,7 @@ func (m *CloseChannelRequest) Reset() { *m = CloseChannelRequest{} } func (m *CloseChannelRequest) String() string { return proto.CompactTextString(m) } func (*CloseChannelRequest) ProtoMessage() {} func (*CloseChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{50} + return fileDescriptor_rpc_e66000aa8614d793, []int{50} } func (m *CloseChannelRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CloseChannelRequest.Unmarshal(m, b) @@ -3227,7 +3241,7 @@ func (m *CloseStatusUpdate) Reset() { *m = CloseStatusUpdate{} } func (m *CloseStatusUpdate) String() string { return proto.CompactTextString(m) } func (*CloseStatusUpdate) ProtoMessage() {} func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{51} + return fileDescriptor_rpc_e66000aa8614d793, []int{51} } func (m *CloseStatusUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CloseStatusUpdate.Unmarshal(m, b) @@ -3370,7 +3384,7 @@ func (m *PendingUpdate) Reset() { *m = PendingUpdate{} } func (m *PendingUpdate) String() string { return proto.CompactTextString(m) } func (*PendingUpdate) ProtoMessage() {} func (*PendingUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{52} + return fileDescriptor_rpc_e66000aa8614d793, []int{52} } func (m *PendingUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingUpdate.Unmarshal(m, b) @@ -3436,7 +3450,7 @@ func (m *OpenChannelRequest) Reset() { *m = OpenChannelRequest{} } func (m *OpenChannelRequest) String() string { return proto.CompactTextString(m) } func (*OpenChannelRequest) ProtoMessage() {} func (*OpenChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{53} + return fileDescriptor_rpc_e66000aa8614d793, []int{53} } func (m *OpenChannelRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OpenChannelRequest.Unmarshal(m, b) @@ -3547,7 +3561,7 @@ func (m *OpenStatusUpdate) Reset() { *m = OpenStatusUpdate{} } func (m *OpenStatusUpdate) String() string { return proto.CompactTextString(m) } func (*OpenStatusUpdate) ProtoMessage() {} func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{54} + return fileDescriptor_rpc_e66000aa8614d793, []int{54} } func (m *OpenStatusUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OpenStatusUpdate.Unmarshal(m, b) @@ -3703,7 +3717,7 @@ func (m *PendingHTLC) Reset() { *m = PendingHTLC{} } func (m *PendingHTLC) String() string { return proto.CompactTextString(m) } func (*PendingHTLC) ProtoMessage() {} func (*PendingHTLC) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{55} + return fileDescriptor_rpc_e66000aa8614d793, []int{55} } func (m *PendingHTLC) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingHTLC.Unmarshal(m, b) @@ -3775,7 +3789,7 @@ func (m *PendingChannelsRequest) Reset() { *m = PendingChannelsRequest{} func (m *PendingChannelsRequest) String() string { return proto.CompactTextString(m) } func (*PendingChannelsRequest) ProtoMessage() {} func (*PendingChannelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{56} + return fileDescriptor_rpc_e66000aa8614d793, []int{56} } func (m *PendingChannelsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsRequest.Unmarshal(m, b) @@ -3815,7 +3829,7 @@ func (m *PendingChannelsResponse) Reset() { *m = PendingChannelsResponse func (m *PendingChannelsResponse) String() string { return proto.CompactTextString(m) } func (*PendingChannelsResponse) ProtoMessage() {} func (*PendingChannelsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{57} + return fileDescriptor_rpc_e66000aa8614d793, []int{57} } func (m *PendingChannelsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsResponse.Unmarshal(m, b) @@ -3887,7 +3901,7 @@ func (m *PendingChannelsResponse_PendingChannel) Reset() { func (m *PendingChannelsResponse_PendingChannel) String() string { return proto.CompactTextString(m) } func (*PendingChannelsResponse_PendingChannel) ProtoMessage() {} func (*PendingChannelsResponse_PendingChannel) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{57, 0} + return fileDescriptor_rpc_e66000aa8614d793, []int{57, 0} } func (m *PendingChannelsResponse_PendingChannel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsResponse_PendingChannel.Unmarshal(m, b) @@ -3974,7 +3988,7 @@ func (m *PendingChannelsResponse_PendingOpenChannel) String() string { } func (*PendingChannelsResponse_PendingOpenChannel) ProtoMessage() {} func (*PendingChannelsResponse_PendingOpenChannel) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{57, 1} + return fileDescriptor_rpc_e66000aa8614d793, []int{57, 1} } func (m *PendingChannelsResponse_PendingOpenChannel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsResponse_PendingOpenChannel.Unmarshal(m, b) @@ -4047,7 +4061,7 @@ func (m *PendingChannelsResponse_WaitingCloseChannel) String() string { } func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {} func (*PendingChannelsResponse_WaitingCloseChannel) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{57, 2} + return fileDescriptor_rpc_e66000aa8614d793, []int{57, 2} } func (m *PendingChannelsResponse_WaitingCloseChannel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsResponse_WaitingCloseChannel.Unmarshal(m, b) @@ -4095,7 +4109,7 @@ func (m *PendingChannelsResponse_ClosedChannel) Reset() { *m = PendingCh func (m *PendingChannelsResponse_ClosedChannel) String() string { return proto.CompactTextString(m) } func (*PendingChannelsResponse_ClosedChannel) ProtoMessage() {} func (*PendingChannelsResponse_ClosedChannel) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{57, 3} + return fileDescriptor_rpc_e66000aa8614d793, []int{57, 3} } func (m *PendingChannelsResponse_ClosedChannel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsResponse_ClosedChannel.Unmarshal(m, b) @@ -4159,7 +4173,7 @@ func (m *PendingChannelsResponse_ForceClosedChannel) String() string { } func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {} func (*PendingChannelsResponse_ForceClosedChannel) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{57, 4} + return fileDescriptor_rpc_e66000aa8614d793, []int{57, 4} } func (m *PendingChannelsResponse_ForceClosedChannel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PendingChannelsResponse_ForceClosedChannel.Unmarshal(m, b) @@ -4238,7 +4252,7 @@ func (m *WalletBalanceRequest) Reset() { *m = WalletBalanceRequest{} } func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) } func (*WalletBalanceRequest) ProtoMessage() {} func (*WalletBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{58} + return fileDescriptor_rpc_e66000aa8614d793, []int{58} } func (m *WalletBalanceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_WalletBalanceRequest.Unmarshal(m, b) @@ -4274,7 +4288,7 @@ func (m *WalletBalanceResponse) Reset() { *m = WalletBalanceResponse{} } func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) } func (*WalletBalanceResponse) ProtoMessage() {} func (*WalletBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{59} + return fileDescriptor_rpc_e66000aa8614d793, []int{59} } func (m *WalletBalanceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_WalletBalanceResponse.Unmarshal(m, b) @@ -4325,7 +4339,7 @@ func (m *ChannelBalanceRequest) Reset() { *m = ChannelBalanceRequest{} } func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) } func (*ChannelBalanceRequest) ProtoMessage() {} func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{60} + return fileDescriptor_rpc_e66000aa8614d793, []int{60} } func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelBalanceRequest.Unmarshal(m, b) @@ -4359,7 +4373,7 @@ func (m *ChannelBalanceResponse) Reset() { *m = ChannelBalanceResponse{} func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) } func (*ChannelBalanceResponse) ProtoMessage() {} func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{61} + return fileDescriptor_rpc_e66000aa8614d793, []int{61} } func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelBalanceResponse.Unmarshal(m, b) @@ -4417,7 +4431,7 @@ func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} } func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) } func (*QueryRoutesRequest) ProtoMessage() {} func (*QueryRoutesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{62} + return fileDescriptor_rpc_e66000aa8614d793, []int{62} } func (m *QueryRoutesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryRoutesRequest.Unmarshal(m, b) @@ -4483,7 +4497,7 @@ func (m *QueryRoutesResponse) Reset() { *m = QueryRoutesResponse{} } func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) } func (*QueryRoutesResponse) ProtoMessage() {} func (*QueryRoutesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{63} + return fileDescriptor_rpc_e66000aa8614d793, []int{63} } func (m *QueryRoutesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryRoutesResponse.Unmarshal(m, b) @@ -4535,7 +4549,7 @@ func (m *Hop) Reset() { *m = Hop{} } func (m *Hop) String() string { return proto.CompactTextString(m) } func (*Hop) ProtoMessage() {} func (*Hop) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{64} + return fileDescriptor_rpc_e66000aa8614d793, []int{64} } func (m *Hop) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Hop.Unmarshal(m, b) @@ -4656,7 +4670,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{65} + return fileDescriptor_rpc_e66000aa8614d793, []int{65} } func (m *Route) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Route.Unmarshal(m, b) @@ -4732,7 +4746,7 @@ func (m *NodeInfoRequest) Reset() { *m = NodeInfoRequest{} } func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) } func (*NodeInfoRequest) ProtoMessage() {} func (*NodeInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{66} + return fileDescriptor_rpc_e66000aa8614d793, []int{66} } func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NodeInfoRequest.Unmarshal(m, b) @@ -4777,7 +4791,7 @@ func (m *NodeInfo) Reset() { *m = NodeInfo{} } func (m *NodeInfo) String() string { return proto.CompactTextString(m) } func (*NodeInfo) ProtoMessage() {} func (*NodeInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{67} + return fileDescriptor_rpc_e66000aa8614d793, []int{67} } func (m *NodeInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NodeInfo.Unmarshal(m, b) @@ -4838,7 +4852,7 @@ func (m *LightningNode) Reset() { *m = LightningNode{} } func (m *LightningNode) String() string { return proto.CompactTextString(m) } func (*LightningNode) ProtoMessage() {} func (*LightningNode) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{68} + return fileDescriptor_rpc_e66000aa8614d793, []int{68} } func (m *LightningNode) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LightningNode.Unmarshal(m, b) @@ -4905,7 +4919,7 @@ func (m *NodeAddress) Reset() { *m = NodeAddress{} } func (m *NodeAddress) String() string { return proto.CompactTextString(m) } func (*NodeAddress) ProtoMessage() {} func (*NodeAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{69} + return fileDescriptor_rpc_e66000aa8614d793, []int{69} } func (m *NodeAddress) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NodeAddress.Unmarshal(m, b) @@ -4954,7 +4968,7 @@ func (m *RoutingPolicy) Reset() { *m = RoutingPolicy{} } func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) } func (*RoutingPolicy) ProtoMessage() {} func (*RoutingPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{70} + return fileDescriptor_rpc_e66000aa8614d793, []int{70} } func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RoutingPolicy.Unmarshal(m, b) @@ -5037,7 +5051,7 @@ func (m *ChannelEdge) Reset() { *m = ChannelEdge{} } func (m *ChannelEdge) String() string { return proto.CompactTextString(m) } func (*ChannelEdge) ProtoMessage() {} func (*ChannelEdge) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{71} + return fileDescriptor_rpc_e66000aa8614d793, []int{71} } func (m *ChannelEdge) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelEdge.Unmarshal(m, b) @@ -5128,7 +5142,7 @@ func (m *ChannelGraphRequest) Reset() { *m = ChannelGraphRequest{} } func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) } func (*ChannelGraphRequest) ProtoMessage() {} func (*ChannelGraphRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{72} + return fileDescriptor_rpc_e66000aa8614d793, []int{72} } func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelGraphRequest.Unmarshal(m, b) @@ -5170,7 +5184,7 @@ func (m *ChannelGraph) Reset() { *m = ChannelGraph{} } func (m *ChannelGraph) String() string { return proto.CompactTextString(m) } func (*ChannelGraph) ProtoMessage() {} func (*ChannelGraph) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{73} + return fileDescriptor_rpc_e66000aa8614d793, []int{73} } func (m *ChannelGraph) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelGraph.Unmarshal(m, b) @@ -5219,7 +5233,7 @@ func (m *ChanInfoRequest) Reset() { *m = ChanInfoRequest{} } func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) } func (*ChanInfoRequest) ProtoMessage() {} func (*ChanInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{74} + return fileDescriptor_rpc_e66000aa8614d793, []int{74} } func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChanInfoRequest.Unmarshal(m, b) @@ -5256,7 +5270,7 @@ func (m *NetworkInfoRequest) Reset() { *m = NetworkInfoRequest{} } func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) } func (*NetworkInfoRequest) ProtoMessage() {} func (*NetworkInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{75} + return fileDescriptor_rpc_e66000aa8614d793, []int{75} } func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NetworkInfoRequest.Unmarshal(m, b) @@ -5295,7 +5309,7 @@ func (m *NetworkInfo) Reset() { *m = NetworkInfo{} } func (m *NetworkInfo) String() string { return proto.CompactTextString(m) } func (*NetworkInfo) ProtoMessage() {} func (*NetworkInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{76} + return fileDescriptor_rpc_e66000aa8614d793, []int{76} } func (m *NetworkInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NetworkInfo.Unmarshal(m, b) @@ -5388,7 +5402,7 @@ func (m *StopRequest) Reset() { *m = StopRequest{} } func (m *StopRequest) String() string { return proto.CompactTextString(m) } func (*StopRequest) ProtoMessage() {} func (*StopRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{77} + return fileDescriptor_rpc_e66000aa8614d793, []int{77} } func (m *StopRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopRequest.Unmarshal(m, b) @@ -5418,7 +5432,7 @@ func (m *StopResponse) Reset() { *m = StopResponse{} } func (m *StopResponse) String() string { return proto.CompactTextString(m) } func (*StopResponse) ProtoMessage() {} func (*StopResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{78} + return fileDescriptor_rpc_e66000aa8614d793, []int{78} } func (m *StopResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopResponse.Unmarshal(m, b) @@ -5448,7 +5462,7 @@ func (m *GraphTopologySubscription) Reset() { *m = GraphTopologySubscrip func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) } func (*GraphTopologySubscription) ProtoMessage() {} func (*GraphTopologySubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{79} + return fileDescriptor_rpc_e66000aa8614d793, []int{79} } func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GraphTopologySubscription.Unmarshal(m, b) @@ -5481,7 +5495,7 @@ func (m *GraphTopologyUpdate) Reset() { *m = GraphTopologyUpdate{} } func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) } func (*GraphTopologyUpdate) ProtoMessage() {} func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{80} + return fileDescriptor_rpc_e66000aa8614d793, []int{80} } func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GraphTopologyUpdate.Unmarshal(m, b) @@ -5536,7 +5550,7 @@ func (m *NodeUpdate) Reset() { *m = NodeUpdate{} } func (m *NodeUpdate) String() string { return proto.CompactTextString(m) } func (*NodeUpdate) ProtoMessage() {} func (*NodeUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{81} + return fileDescriptor_rpc_e66000aa8614d793, []int{81} } func (m *NodeUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NodeUpdate.Unmarshal(m, b) @@ -5604,7 +5618,7 @@ func (m *ChannelEdgeUpdate) Reset() { *m = ChannelEdgeUpdate{} } func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelEdgeUpdate) ProtoMessage() {} func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{82} + return fileDescriptor_rpc_e66000aa8614d793, []int{82} } func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelEdgeUpdate.Unmarshal(m, b) @@ -5684,7 +5698,7 @@ func (m *ClosedChannelUpdate) Reset() { *m = ClosedChannelUpdate{} } func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) } func (*ClosedChannelUpdate) ProtoMessage() {} func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{83} + return fileDescriptor_rpc_e66000aa8614d793, []int{83} } func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ClosedChannelUpdate.Unmarshal(m, b) @@ -5754,7 +5768,7 @@ func (m *HopHint) Reset() { *m = HopHint{} } func (m *HopHint) String() string { return proto.CompactTextString(m) } func (*HopHint) ProtoMessage() {} func (*HopHint) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{84} + return fileDescriptor_rpc_e66000aa8614d793, []int{84} } func (m *HopHint) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HopHint.Unmarshal(m, b) @@ -5823,7 +5837,7 @@ func (m *RouteHint) Reset() { *m = RouteHint{} } func (m *RouteHint) String() string { return proto.CompactTextString(m) } func (*RouteHint) ProtoMessage() {} func (*RouteHint) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{85} + return fileDescriptor_rpc_e66000aa8614d793, []int{85} } func (m *RouteHint) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RouteHint.Unmarshal(m, b) @@ -5938,7 +5952,7 @@ func (m *Invoice) Reset() { *m = Invoice{} } func (m *Invoice) String() string { return proto.CompactTextString(m) } func (*Invoice) ProtoMessage() {} func (*Invoice) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{86} + return fileDescriptor_rpc_e66000aa8614d793, []int{86} } func (m *Invoice) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Invoice.Unmarshal(m, b) @@ -6130,7 +6144,7 @@ func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} } func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*AddInvoiceResponse) ProtoMessage() {} func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{87} + return fileDescriptor_rpc_e66000aa8614d793, []int{87} } func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AddInvoiceResponse.Unmarshal(m, b) @@ -6187,7 +6201,7 @@ func (m *PaymentHash) Reset() { *m = PaymentHash{} } func (m *PaymentHash) String() string { return proto.CompactTextString(m) } func (*PaymentHash) ProtoMessage() {} func (*PaymentHash) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{88} + return fileDescriptor_rpc_e66000aa8614d793, []int{88} } func (m *PaymentHash) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaymentHash.Unmarshal(m, b) @@ -6243,7 +6257,7 @@ func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} } func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) } func (*ListInvoiceRequest) ProtoMessage() {} func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{89} + return fileDescriptor_rpc_e66000aa8614d793, []int{89} } func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListInvoiceRequest.Unmarshal(m, b) @@ -6313,7 +6327,7 @@ func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} } func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*ListInvoiceResponse) ProtoMessage() {} func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{90} + return fileDescriptor_rpc_e66000aa8614d793, []int{90} } func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListInvoiceResponse.Unmarshal(m, b) @@ -6376,7 +6390,7 @@ func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} } func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) } func (*InvoiceSubscription) ProtoMessage() {} func (*InvoiceSubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{91} + return fileDescriptor_rpc_e66000aa8614d793, []int{91} } func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceSubscription.Unmarshal(m, b) @@ -6436,7 +6450,7 @@ func (m *Payment) Reset() { *m = Payment{} } func (m *Payment) String() string { return proto.CompactTextString(m) } func (*Payment) ProtoMessage() {} func (*Payment) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{92} + return fileDescriptor_rpc_e66000aa8614d793, []int{92} } func (m *Payment) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Payment.Unmarshal(m, b) @@ -6523,7 +6537,7 @@ func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} } func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*ListPaymentsRequest) ProtoMessage() {} func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{93} + return fileDescriptor_rpc_e66000aa8614d793, []int{93} } func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListPaymentsRequest.Unmarshal(m, b) @@ -6555,7 +6569,7 @@ func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} } func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*ListPaymentsResponse) ProtoMessage() {} func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{94} + return fileDescriptor_rpc_e66000aa8614d793, []int{94} } func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListPaymentsResponse.Unmarshal(m, b) @@ -6592,7 +6606,7 @@ func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsReque func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsRequest) ProtoMessage() {} func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{95} + return fileDescriptor_rpc_e66000aa8614d793, []int{95} } func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DeleteAllPaymentsRequest.Unmarshal(m, b) @@ -6622,7 +6636,7 @@ func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResp func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsResponse) ProtoMessage() {} func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{96} + return fileDescriptor_rpc_e66000aa8614d793, []int{96} } func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DeleteAllPaymentsResponse.Unmarshal(m, b) @@ -6653,7 +6667,7 @@ func (m *AbandonChannelRequest) Reset() { *m = AbandonChannelRequest{} } func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) } func (*AbandonChannelRequest) ProtoMessage() {} func (*AbandonChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{97} + return fileDescriptor_rpc_e66000aa8614d793, []int{97} } func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AbandonChannelRequest.Unmarshal(m, b) @@ -6690,7 +6704,7 @@ func (m *AbandonChannelResponse) Reset() { *m = AbandonChannelResponse{} func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) } func (*AbandonChannelResponse) ProtoMessage() {} func (*AbandonChannelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{98} + return fileDescriptor_rpc_e66000aa8614d793, []int{98} } func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AbandonChannelResponse.Unmarshal(m, b) @@ -6722,7 +6736,7 @@ func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} } func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) } func (*DebugLevelRequest) ProtoMessage() {} func (*DebugLevelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{99} + return fileDescriptor_rpc_e66000aa8614d793, []int{99} } func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DebugLevelRequest.Unmarshal(m, b) @@ -6767,7 +6781,7 @@ func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} } func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) } func (*DebugLevelResponse) ProtoMessage() {} func (*DebugLevelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{100} + return fileDescriptor_rpc_e66000aa8614d793, []int{100} } func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DebugLevelResponse.Unmarshal(m, b) @@ -6806,7 +6820,7 @@ func (m *PayReqString) Reset() { *m = PayReqString{} } func (m *PayReqString) String() string { return proto.CompactTextString(m) } func (*PayReqString) ProtoMessage() {} func (*PayReqString) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{101} + return fileDescriptor_rpc_e66000aa8614d793, []int{101} } func (m *PayReqString) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PayReqString.Unmarshal(m, b) @@ -6853,7 +6867,7 @@ func (m *PayReq) Reset() { *m = PayReq{} } func (m *PayReq) String() string { return proto.CompactTextString(m) } func (*PayReq) ProtoMessage() {} func (*PayReq) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{102} + return fileDescriptor_rpc_e66000aa8614d793, []int{102} } func (m *PayReq) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PayReq.Unmarshal(m, b) @@ -6953,7 +6967,7 @@ func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} } func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) } func (*FeeReportRequest) ProtoMessage() {} func (*FeeReportRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{103} + return fileDescriptor_rpc_e66000aa8614d793, []int{103} } func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_FeeReportRequest.Unmarshal(m, b) @@ -6991,7 +7005,7 @@ func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} } func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) } func (*ChannelFeeReport) ProtoMessage() {} func (*ChannelFeeReport) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{104} + return fileDescriptor_rpc_e66000aa8614d793, []int{104} } func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelFeeReport.Unmarshal(m, b) @@ -7057,7 +7071,7 @@ func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} } func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) } func (*FeeReportResponse) ProtoMessage() {} func (*FeeReportResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{105} + return fileDescriptor_rpc_e66000aa8614d793, []int{105} } func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_FeeReportResponse.Unmarshal(m, b) @@ -7125,7 +7139,7 @@ func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} } func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateRequest) ProtoMessage() {} func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{106} + return fileDescriptor_rpc_e66000aa8614d793, []int{106} } func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PolicyUpdateRequest.Unmarshal(m, b) @@ -7286,7 +7300,7 @@ func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} } func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateResponse) ProtoMessage() {} func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{107} + return fileDescriptor_rpc_e66000aa8614d793, []int{107} } func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PolicyUpdateResponse.Unmarshal(m, b) @@ -7324,7 +7338,7 @@ func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryReque func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryRequest) ProtoMessage() {} func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{108} + return fileDescriptor_rpc_e66000aa8614d793, []int{108} } func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ForwardingHistoryRequest.Unmarshal(m, b) @@ -7396,7 +7410,7 @@ func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} } func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) } func (*ForwardingEvent) ProtoMessage() {} func (*ForwardingEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{109} + return fileDescriptor_rpc_e66000aa8614d793, []int{109} } func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ForwardingEvent.Unmarshal(m, b) @@ -7479,7 +7493,7 @@ func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResp func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryResponse) ProtoMessage() {} func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_rpc_b1b9aa8c9dfaad66, []int{110} + return fileDescriptor_rpc_e66000aa8614d793, []int{110} } func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ForwardingHistoryResponse.Unmarshal(m, b) @@ -9909,428 +9923,430 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ Metadata: "rpc.proto", } -func init() { proto.RegisterFile("rpc.proto", fileDescriptor_rpc_b1b9aa8c9dfaad66) } +func init() { proto.RegisterFile("rpc.proto", fileDescriptor_rpc_e66000aa8614d793) } -var fileDescriptor_rpc_b1b9aa8c9dfaad66 = []byte{ - // 6718 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0x5b, 0x6c, 0x24, 0xd9, - 0x59, 0xff, 0x54, 0xbb, 0xdb, 0xee, 0xfe, 0xba, 0xed, 0x6e, 0x1f, 0xdf, 0x7a, 0x7a, 0x67, 0x67, - 0x67, 0x4f, 0x26, 0x3b, 0x13, 0xff, 0xf7, 0x3f, 0x9e, 0x9d, 0x24, 0xcb, 0x66, 0x17, 0x02, 0x1e, - 0xdb, 0x33, 0x9e, 0xc4, 0x3b, 0xe3, 0x94, 0x67, 0x32, 0x64, 0x03, 0xea, 0x94, 0xbb, 0x8f, 0xdb, - 0x95, 0xe9, 0xae, 0xea, 0x54, 0x55, 0xdb, 0xd3, 0x59, 0x56, 0xe2, 0x26, 0x90, 0x10, 0x11, 0x02, - 0x5e, 0x08, 0x12, 0x42, 0x0a, 0x48, 0x24, 0x8f, 0xbc, 0x44, 0x48, 0xc0, 0x1b, 0x2f, 0x20, 0x21, - 0x84, 0xf2, 0x88, 0xc4, 0x0b, 0xbc, 0x00, 0x82, 0x07, 0x24, 0x1e, 0x78, 0x00, 0xa1, 0xf3, 0x9d, - 0x4b, 0x9d, 0x53, 0x55, 0x3d, 0x9e, 0x5c, 0xe0, 0xc9, 0x7d, 0x7e, 0xe7, 0xab, 0x73, 0xfd, 0x6e, - 0xe7, 0x3b, 0xdf, 0x31, 0xd4, 0xa2, 0x71, 0xef, 0xd6, 0x38, 0x0a, 0x93, 0x90, 0x54, 0x86, 0x41, - 0x34, 0xee, 0x75, 0xae, 0x0c, 0xc2, 0x70, 0x30, 0x64, 0x5b, 0xde, 0xd8, 0xdf, 0xf2, 0x82, 0x20, - 0x4c, 0xbc, 0xc4, 0x0f, 0x83, 0x58, 0x10, 0xd1, 0xaf, 0xc0, 0xd2, 0x7d, 0x16, 0x1c, 0x31, 0xd6, - 0x77, 0xd9, 0xd7, 0x26, 0x2c, 0x4e, 0xc8, 0xff, 0x83, 0x65, 0x8f, 0x7d, 0x9d, 0xb1, 0x7e, 0x77, - 0xec, 0xc5, 0xf1, 0xf8, 0x34, 0xf2, 0x62, 0xd6, 0x76, 0xae, 0x39, 0x37, 0x1b, 0x6e, 0x4b, 0x54, - 0x1c, 0x6a, 0x9c, 0xbc, 0x0e, 0x8d, 0x98, 0x93, 0xb2, 0x20, 0x89, 0xc2, 0xf1, 0xb4, 0x5d, 0x42, - 0xba, 0x3a, 0xc7, 0xf6, 0x04, 0x44, 0x87, 0xd0, 0xd4, 0x3d, 0xc4, 0xe3, 0x30, 0x88, 0x19, 0xb9, - 0x0d, 0xab, 0x3d, 0x7f, 0x7c, 0xca, 0xa2, 0x2e, 0x7e, 0x3c, 0x0a, 0xd8, 0x28, 0x0c, 0xfc, 0x5e, - 0xdb, 0xb9, 0x36, 0x77, 0xb3, 0xe6, 0x12, 0x51, 0xc7, 0xbf, 0x78, 0x5f, 0xd6, 0x90, 0x1b, 0xd0, - 0x64, 0x81, 0xc0, 0x59, 0x1f, 0xbf, 0x92, 0x5d, 0x2d, 0xa5, 0x30, 0xff, 0x80, 0xfe, 0x85, 0x03, - 0xcb, 0x0f, 0x02, 0x3f, 0x79, 0xea, 0x0d, 0x87, 0x2c, 0x51, 0x73, 0xba, 0x01, 0xcd, 0x73, 0x04, - 0x70, 0x4e, 0xe7, 0x61, 0xd4, 0x97, 0x33, 0x5a, 0x12, 0xf0, 0xa1, 0x44, 0x67, 0x8e, 0xac, 0x34, - 0x73, 0x64, 0x85, 0xcb, 0x35, 0x37, 0x63, 0xb9, 0x6e, 0x40, 0x33, 0x62, 0xbd, 0xf0, 0x8c, 0x45, - 0xd3, 0xee, 0xb9, 0x1f, 0xf4, 0xc3, 0xf3, 0x76, 0xf9, 0x9a, 0x73, 0xb3, 0xe2, 0x2e, 0x29, 0xf8, - 0x29, 0xa2, 0x74, 0x15, 0x88, 0x39, 0x0b, 0xb1, 0x6e, 0x74, 0x00, 0x2b, 0x4f, 0x82, 0x61, 0xd8, - 0x7b, 0xf6, 0x03, 0xce, 0xae, 0xa0, 0xfb, 0x52, 0x61, 0xf7, 0xeb, 0xb0, 0x6a, 0x77, 0x24, 0x07, - 0xc0, 0x60, 0x6d, 0xe7, 0xd4, 0x0b, 0x06, 0x4c, 0x35, 0xa9, 0x86, 0xf0, 0x09, 0x68, 0xf5, 0x26, - 0x51, 0xc4, 0x82, 0xdc, 0x18, 0x9a, 0x12, 0xd7, 0x83, 0x78, 0x1d, 0x1a, 0x01, 0x3b, 0x4f, 0xc9, - 0x24, 0xcb, 0x04, 0xec, 0x5c, 0x91, 0xd0, 0x36, 0xac, 0x67, 0xbb, 0x91, 0x03, 0xf8, 0x57, 0x07, - 0xca, 0x4f, 0x92, 0xe7, 0x21, 0xb9, 0x05, 0xe5, 0x64, 0x3a, 0x16, 0x8c, 0xb9, 0x74, 0x87, 0xdc, - 0x42, 0x5e, 0xbf, 0xb5, 0xdd, 0xef, 0x47, 0x2c, 0x8e, 0x1f, 0x4f, 0xc7, 0xcc, 0x6d, 0x78, 0xa2, - 0xd0, 0xe5, 0x74, 0xa4, 0x0d, 0x0b, 0xb2, 0x8c, 0x1d, 0xd6, 0x5c, 0x55, 0x24, 0x57, 0x01, 0xbc, - 0x51, 0x38, 0x09, 0x92, 0x6e, 0xec, 0x25, 0xb8, 0x73, 0x73, 0xae, 0x81, 0x90, 0xeb, 0xb0, 0x18, - 0xf7, 0x22, 0x7f, 0x9c, 0x74, 0xc7, 0x93, 0xe3, 0x67, 0x6c, 0x8a, 0x3b, 0x56, 0x73, 0x6d, 0x90, - 0x6c, 0x41, 0x35, 0x9c, 0x24, 0xe3, 0xd0, 0x0f, 0x92, 0x76, 0xe5, 0x9a, 0x73, 0xb3, 0x7e, 0x67, - 0x45, 0x8e, 0x89, 0xcf, 0x24, 0x60, 0xc3, 0x43, 0x5e, 0xe5, 0x6a, 0x22, 0xde, 0x6c, 0x2f, 0x0c, - 0x4e, 0xfc, 0x68, 0x24, 0xe4, 0xb1, 0x3d, 0x8f, 0x3d, 0xdb, 0x20, 0xfd, 0x66, 0x09, 0xea, 0x8f, - 0x23, 0x2f, 0x88, 0xbd, 0x1e, 0x07, 0xf8, 0x34, 0x92, 0xe7, 0xdd, 0x53, 0x2f, 0x3e, 0xc5, 0x99, - 0xd7, 0x5c, 0x55, 0x24, 0xeb, 0x30, 0x2f, 0x06, 0x8d, 0xf3, 0x9b, 0x73, 0x65, 0x89, 0xbc, 0x09, - 0xcb, 0xc1, 0x64, 0xd4, 0xb5, 0xfb, 0x9a, 0xc3, 0x5d, 0xcf, 0x57, 0xf0, 0xc5, 0x38, 0xe6, 0xfb, - 0x2e, 0xba, 0x10, 0x33, 0x35, 0x10, 0x42, 0xa1, 0x21, 0x4b, 0xcc, 0x1f, 0x9c, 0x8a, 0xa9, 0x56, - 0x5c, 0x0b, 0xe3, 0x6d, 0x24, 0xfe, 0x88, 0x75, 0xe3, 0xc4, 0x1b, 0x8d, 0xe5, 0xb4, 0x0c, 0x04, - 0xeb, 0xc3, 0xc4, 0x1b, 0x76, 0x4f, 0x18, 0x8b, 0xdb, 0x0b, 0xb2, 0x5e, 0x23, 0xe4, 0x0d, 0x58, - 0xea, 0xb3, 0x38, 0xe9, 0xca, 0x0d, 0x62, 0x71, 0xbb, 0x8a, 0xd2, 0x97, 0x41, 0x39, 0x97, 0xdc, - 0x67, 0x89, 0xb1, 0x3a, 0xb1, 0xe4, 0x46, 0x7a, 0x00, 0xc4, 0x80, 0x77, 0x59, 0xe2, 0xf9, 0xc3, - 0x98, 0xbc, 0x0d, 0x8d, 0xc4, 0x20, 0x46, 0x6d, 0x53, 0xd7, 0xac, 0x63, 0x7c, 0xe0, 0x5a, 0x74, - 0xf4, 0x3e, 0x54, 0xef, 0x31, 0x76, 0xe0, 0x8f, 0xfc, 0x84, 0xac, 0x43, 0xe5, 0xc4, 0x7f, 0xce, - 0x04, 0x73, 0xcf, 0xed, 0x5f, 0x72, 0x45, 0x91, 0x74, 0x60, 0x61, 0xcc, 0xa2, 0x1e, 0x53, 0xcb, - 0xbf, 0x7f, 0xc9, 0x55, 0xc0, 0xdd, 0x05, 0xa8, 0x0c, 0xf9, 0xc7, 0xf4, 0xdb, 0x25, 0xa8, 0x1f, - 0xb1, 0x40, 0x0b, 0x0d, 0x81, 0x32, 0x9f, 0x92, 0x14, 0x14, 0xfc, 0x4d, 0x5e, 0x83, 0x3a, 0x4e, - 0x33, 0x4e, 0x22, 0x3f, 0x18, 0x48, 0x5e, 0x05, 0x0e, 0x1d, 0x21, 0x42, 0x5a, 0x30, 0xe7, 0x8d, - 0x14, 0x9f, 0xf2, 0x9f, 0x5c, 0xa0, 0xc6, 0xde, 0x74, 0xc4, 0x65, 0x4f, 0xef, 0x5a, 0xc3, 0xad, - 0x4b, 0x6c, 0x9f, 0x6f, 0xdb, 0x2d, 0x58, 0x31, 0x49, 0x54, 0xeb, 0x15, 0x6c, 0x7d, 0xd9, 0xa0, - 0x94, 0x9d, 0xdc, 0x80, 0xa6, 0xa2, 0x8f, 0xc4, 0x60, 0x71, 0x1f, 0x6b, 0xee, 0x92, 0x84, 0xd5, - 0x14, 0x6e, 0x42, 0xeb, 0xc4, 0x0f, 0xbc, 0x61, 0xb7, 0x37, 0x4c, 0xce, 0xba, 0x7d, 0x36, 0x4c, - 0x3c, 0xdc, 0xd1, 0x8a, 0xbb, 0x84, 0xf8, 0xce, 0x30, 0x39, 0xdb, 0xe5, 0x28, 0x79, 0x13, 0x6a, - 0x27, 0x8c, 0x75, 0x71, 0x25, 0xda, 0x55, 0x94, 0x90, 0xa6, 0x5c, 0x7a, 0xb5, 0xba, 0x6e, 0xf5, - 0x44, 0xfe, 0xa2, 0x7f, 0xe2, 0x40, 0x43, 0x2c, 0x95, 0x34, 0x19, 0xd7, 0x61, 0x51, 0x8d, 0x88, - 0x45, 0x51, 0x18, 0x49, 0xf6, 0xb7, 0x41, 0xb2, 0x09, 0x2d, 0x05, 0x8c, 0x23, 0xe6, 0x8f, 0xbc, - 0x01, 0x93, 0xfa, 0x25, 0x87, 0x93, 0x3b, 0x69, 0x8b, 0x51, 0x38, 0x49, 0x84, 0xd2, 0xae, 0xdf, - 0x69, 0xc8, 0x41, 0xb9, 0x1c, 0x73, 0x6d, 0x12, 0xce, 0xfe, 0x05, 0x4b, 0x6d, 0x61, 0xf4, 0x1b, - 0x0e, 0x10, 0x3e, 0xf4, 0xc7, 0xa1, 0x68, 0x42, 0xae, 0x54, 0x76, 0x97, 0x9c, 0x97, 0xde, 0xa5, - 0xd2, 0xac, 0x5d, 0xba, 0x0e, 0xf3, 0x38, 0x2c, 0x2e, 0xcf, 0x73, 0xb9, 0xa1, 0xcb, 0x3a, 0xfa, - 0x2d, 0x07, 0x1a, 0xa6, 0x0e, 0x22, 0xb7, 0x81, 0x9c, 0x4c, 0x82, 0xbe, 0x1f, 0x0c, 0xba, 0xc9, - 0x73, 0xbf, 0xdf, 0x3d, 0x9e, 0xf2, 0x26, 0x70, 0x3c, 0xfb, 0x97, 0xdc, 0x82, 0x3a, 0xf2, 0x26, - 0xb4, 0x2c, 0x34, 0x4e, 0x22, 0x31, 0xaa, 0xfd, 0x4b, 0x6e, 0xae, 0x86, 0x2f, 0x12, 0xd7, 0x72, - 0x93, 0xa4, 0xeb, 0x07, 0x7d, 0xf6, 0x1c, 0xd7, 0x75, 0xd1, 0xb5, 0xb0, 0xbb, 0x4b, 0xd0, 0x30, - 0xbf, 0xa3, 0x9f, 0x85, 0xd6, 0x01, 0x57, 0x1e, 0x81, 0x1f, 0x0c, 0xa4, 0x12, 0xe7, 0x1a, 0x4d, - 0x6a, 0x5c, 0xb1, 0xd7, 0xb2, 0xc4, 0xc5, 0xe6, 0x34, 0x8c, 0x13, 0xb9, 0x2e, 0xf8, 0x9b, 0xfe, - 0x83, 0x03, 0x4d, 0xbe, 0xe8, 0xef, 0x7b, 0xc1, 0x54, 0xad, 0xf8, 0x01, 0x34, 0x78, 0x53, 0x8f, - 0xc3, 0x6d, 0xa1, 0x17, 0x85, 0xbc, 0xdf, 0x94, 0x8b, 0x94, 0xa1, 0xbe, 0x65, 0x92, 0x72, 0xd7, - 0x65, 0xea, 0x5a, 0x5f, 0x73, 0xc1, 0x4c, 0xbc, 0x68, 0xc0, 0x12, 0xd4, 0x98, 0x52, 0x83, 0x82, - 0x80, 0x76, 0xc2, 0xe0, 0x84, 0x5c, 0x83, 0x46, 0xec, 0x25, 0xdd, 0x31, 0x8b, 0x70, 0xd5, 0x50, - 0xb8, 0xe6, 0x5c, 0x88, 0xbd, 0xe4, 0x90, 0x45, 0x77, 0xa7, 0x09, 0xeb, 0xfc, 0x24, 0x2c, 0xe7, - 0x7a, 0xe1, 0xf2, 0x9c, 0x4e, 0x91, 0xff, 0x24, 0xab, 0x50, 0x39, 0xf3, 0x86, 0x13, 0x26, 0x15, - 0xb9, 0x28, 0xbc, 0x5b, 0x7a, 0xc7, 0xa1, 0x6f, 0x40, 0x2b, 0x1d, 0xb6, 0x14, 0x0c, 0x02, 0x65, - 0xbe, 0x82, 0xb2, 0x01, 0xfc, 0x4d, 0x7f, 0xc1, 0x11, 0x84, 0x3b, 0xa1, 0xaf, 0x95, 0x22, 0x27, - 0xe4, 0xba, 0x53, 0x11, 0xf2, 0xdf, 0x33, 0x8d, 0xc6, 0x0f, 0x3f, 0x59, 0x7a, 0x03, 0x96, 0x8d, - 0x21, 0xbc, 0x60, 0xb0, 0x0f, 0x81, 0x1c, 0xf8, 0x71, 0xf2, 0x24, 0x88, 0xc7, 0x86, 0x62, 0x79, - 0x05, 0x6a, 0x23, 0x3f, 0xc0, 0xee, 0x05, 0x6f, 0x56, 0xdc, 0xea, 0xc8, 0x0f, 0x78, 0xe7, 0x31, - 0x56, 0x7a, 0xcf, 0x65, 0x65, 0x49, 0x56, 0x7a, 0xcf, 0xb1, 0x92, 0xbe, 0x03, 0x2b, 0x56, 0x7b, - 0xb2, 0xeb, 0xd7, 0xa1, 0x32, 0x49, 0x9e, 0x87, 0x4a, 0xed, 0xd7, 0x25, 0x1b, 0x70, 0x67, 0xc2, - 0x15, 0x35, 0xf4, 0x3d, 0x58, 0x7e, 0xc8, 0xce, 0x25, 0xfb, 0xa9, 0x81, 0xbc, 0x71, 0xa1, 0xa3, - 0x81, 0xf5, 0xf4, 0x16, 0x10, 0xf3, 0x63, 0xd9, 0xab, 0xe1, 0x76, 0x38, 0x96, 0xdb, 0x41, 0xdf, - 0x00, 0x72, 0xe4, 0x0f, 0x82, 0xf7, 0x59, 0x1c, 0x7b, 0x03, 0xad, 0x25, 0x5a, 0x30, 0x37, 0x8a, - 0x07, 0x52, 0x39, 0xf0, 0x9f, 0xf4, 0x93, 0xb0, 0x62, 0xd1, 0xc9, 0x86, 0xaf, 0x40, 0x2d, 0xf6, - 0x07, 0x81, 0x97, 0x4c, 0x22, 0x26, 0x9b, 0x4e, 0x01, 0x7a, 0x0f, 0x56, 0xbf, 0xc8, 0x22, 0xff, - 0x64, 0x7a, 0x51, 0xf3, 0x76, 0x3b, 0xa5, 0x6c, 0x3b, 0x7b, 0xb0, 0x96, 0x69, 0x47, 0x76, 0x2f, - 0x78, 0x54, 0xee, 0x64, 0xd5, 0x15, 0x05, 0x43, 0x62, 0x4b, 0xa6, 0xc4, 0xd2, 0x27, 0x40, 0x76, - 0xc2, 0x20, 0x60, 0xbd, 0xe4, 0x90, 0xb1, 0x28, 0x3d, 0x68, 0xa4, 0x0c, 0x59, 0xbf, 0xb3, 0x21, - 0x57, 0x36, 0xab, 0x06, 0x24, 0xa7, 0x12, 0x28, 0x8f, 0x59, 0x34, 0xc2, 0x86, 0xab, 0x2e, 0xfe, - 0xa6, 0x6b, 0xb0, 0x62, 0x35, 0x2b, 0x7d, 0xc4, 0xb7, 0x60, 0x6d, 0xd7, 0x8f, 0x7b, 0xf9, 0x0e, - 0xdb, 0xb0, 0x30, 0x9e, 0x1c, 0x77, 0x53, 0x71, 0x53, 0x45, 0xee, 0x4a, 0x64, 0x3f, 0x91, 0x8d, - 0xfd, 0x8a, 0x03, 0xe5, 0xfd, 0xc7, 0x07, 0x3b, 0xa4, 0x03, 0x55, 0x3f, 0xe8, 0x85, 0x23, 0xae, - 0x91, 0xc5, 0xa4, 0x75, 0x79, 0xa6, 0x18, 0x5d, 0x81, 0x1a, 0x2a, 0x72, 0xee, 0x1d, 0xc9, 0x33, - 0x41, 0x0a, 0x70, 0xcf, 0x8c, 0x3d, 0x1f, 0xfb, 0x11, 0xba, 0x5e, 0xca, 0xa1, 0x2a, 0xa3, 0xb2, - 0xcc, 0x57, 0xd0, 0xff, 0x2e, 0xc3, 0x82, 0x54, 0xe3, 0xd8, 0x5f, 0x2f, 0xf1, 0xcf, 0x98, 0x1c, - 0x89, 0x2c, 0x71, 0x23, 0x19, 0xb1, 0x51, 0x98, 0xb0, 0xae, 0xb5, 0x0d, 0x36, 0x88, 0x9e, 0xa7, - 0x68, 0xa8, 0x2b, 0xfc, 0xd5, 0x39, 0x41, 0x65, 0x81, 0x7c, 0xb1, 0x38, 0xd0, 0xf5, 0xfb, 0x38, - 0xa6, 0xb2, 0xab, 0x8a, 0x7c, 0x25, 0x7a, 0xde, 0xd8, 0xeb, 0xf9, 0xc9, 0x54, 0xca, 0xbd, 0x2e, - 0xf3, 0xb6, 0x87, 0x61, 0xcf, 0x1b, 0x76, 0x8f, 0xbd, 0xa1, 0x17, 0xf4, 0x98, 0xf2, 0x6a, 0x2d, - 0x90, 0x7b, 0x78, 0x72, 0x48, 0x8a, 0x4c, 0x78, 0x81, 0x19, 0x94, 0x7b, 0x8a, 0xbd, 0x70, 0x34, - 0xf2, 0x13, 0xee, 0x18, 0xa2, 0xd3, 0x30, 0xe7, 0x1a, 0x88, 0xf0, 0xa1, 0xb1, 0x74, 0x2e, 0x56, - 0xaf, 0xa6, 0x7c, 0x68, 0x03, 0xe4, 0xad, 0x70, 0xcf, 0x83, 0xeb, 0xaa, 0x67, 0xe7, 0x6d, 0x10, - 0xad, 0xa4, 0x08, 0xdf, 0x87, 0x49, 0x10, 0xb3, 0x24, 0x19, 0xb2, 0xbe, 0x1e, 0x50, 0x1d, 0xc9, - 0xf2, 0x15, 0xe4, 0x36, 0xac, 0x08, 0x5f, 0x35, 0xf6, 0x92, 0x30, 0x3e, 0xf5, 0xe3, 0x6e, 0xcc, - 0xbd, 0xbe, 0x06, 0xd2, 0x17, 0x55, 0x91, 0x77, 0x60, 0x23, 0x03, 0x47, 0xac, 0xc7, 0xfc, 0x33, - 0xd6, 0x6f, 0x2f, 0xe2, 0x57, 0xb3, 0xaa, 0xc9, 0x35, 0xa8, 0x73, 0x17, 0x7d, 0x32, 0xee, 0x7b, - 0xdc, 0x44, 0x2f, 0xe1, 0x3e, 0x98, 0x10, 0x79, 0x0b, 0x16, 0xc7, 0x4c, 0xd8, 0xd1, 0xd3, 0x64, - 0xd8, 0x8b, 0xdb, 0x4d, 0x4b, 0xbb, 0x71, 0xce, 0x75, 0x6d, 0x0a, 0xce, 0x94, 0xbd, 0x18, 0x7d, - 0x35, 0x6f, 0xda, 0x6e, 0x21, 0xbb, 0xa5, 0x00, 0xca, 0x48, 0xe4, 0x9f, 0x79, 0x09, 0x6b, 0x2f, - 0x23, 0x6f, 0xa9, 0x22, 0xfd, 0x7d, 0x47, 0x28, 0x56, 0xc9, 0x84, 0x5a, 0x41, 0xbe, 0x06, 0x75, - 0xc1, 0x7e, 0xdd, 0x30, 0x18, 0x4e, 0x25, 0x47, 0x82, 0x80, 0x1e, 0x05, 0xc3, 0x29, 0xf9, 0x18, - 0x2c, 0xfa, 0x81, 0x49, 0x22, 0x64, 0xb8, 0xa1, 0x40, 0x24, 0x7a, 0x0d, 0xea, 0xe3, 0xc9, 0xf1, - 0xd0, 0xef, 0x09, 0x92, 0x39, 0xd1, 0x8a, 0x80, 0x90, 0x80, 0xfb, 0x4f, 0x62, 0x24, 0x82, 0xa2, - 0x8c, 0x14, 0x75, 0x89, 0x71, 0x12, 0x7a, 0x17, 0x56, 0xed, 0x01, 0x4a, 0x65, 0xb5, 0x09, 0x55, - 0xc9, 0xdb, 0x71, 0xbb, 0x8e, 0xeb, 0xb3, 0x64, 0x9f, 0xcd, 0x5c, 0x5d, 0x4f, 0xbf, 0x5b, 0x86, - 0x15, 0x89, 0xee, 0x0c, 0xc3, 0x98, 0x1d, 0x4d, 0x46, 0x23, 0x2f, 0x2a, 0x10, 0x1a, 0xe7, 0x02, - 0xa1, 0x29, 0xd9, 0x42, 0xc3, 0x59, 0xf9, 0xd4, 0xf3, 0x03, 0xe1, 0xfc, 0x09, 0x89, 0x33, 0x10, - 0x72, 0x13, 0x9a, 0xbd, 0x61, 0x18, 0x0b, 0x87, 0xc8, 0x3c, 0x7d, 0x65, 0xe1, 0xbc, 0x90, 0x57, - 0x8a, 0x84, 0xdc, 0x14, 0xd2, 0xf9, 0x8c, 0x90, 0x52, 0x68, 0xf0, 0x46, 0x99, 0xd2, 0x39, 0x0b, - 0xc2, 0x41, 0x33, 0x31, 0x3e, 0x9e, 0xac, 0x48, 0x08, 0xf9, 0x6b, 0x16, 0x09, 0x04, 0x3f, 0xdc, - 0x71, 0x9d, 0x66, 0x50, 0xd7, 0xa4, 0x40, 0xe4, 0xab, 0xc8, 0x3d, 0x00, 0xd1, 0x17, 0x1a, 0x56, - 0x40, 0xc3, 0xfa, 0x86, 0xbd, 0x23, 0xe6, 0xda, 0xdf, 0xe2, 0x85, 0x49, 0xc4, 0xd0, 0xd8, 0x1a, - 0x5f, 0xd2, 0x5f, 0x73, 0xa0, 0x6e, 0xd4, 0x91, 0x35, 0x58, 0xde, 0x79, 0xf4, 0xe8, 0x70, 0xcf, - 0xdd, 0x7e, 0xfc, 0xe0, 0x8b, 0x7b, 0xdd, 0x9d, 0x83, 0x47, 0x47, 0x7b, 0xad, 0x4b, 0x1c, 0x3e, - 0x78, 0xb4, 0xb3, 0x7d, 0xd0, 0xbd, 0xf7, 0xc8, 0xdd, 0x51, 0xb0, 0x43, 0xd6, 0x81, 0xb8, 0x7b, - 0xef, 0x3f, 0x7a, 0xbc, 0x67, 0xe1, 0x25, 0xd2, 0x82, 0xc6, 0x5d, 0x77, 0x6f, 0x7b, 0x67, 0x5f, - 0x22, 0x73, 0x64, 0x15, 0x5a, 0xf7, 0x9e, 0x3c, 0xdc, 0x7d, 0xf0, 0xf0, 0x7e, 0x77, 0x67, 0xfb, - 0xe1, 0xce, 0xde, 0xc1, 0xde, 0x6e, 0xab, 0x4c, 0x16, 0xa1, 0xb6, 0x7d, 0x77, 0xfb, 0xe1, 0xee, - 0xa3, 0x87, 0x7b, 0xbb, 0xad, 0x0a, 0xfd, 0x7b, 0x07, 0xd6, 0x70, 0xd4, 0xfd, 0xac, 0x80, 0x5c, - 0x83, 0x7a, 0x2f, 0x0c, 0xc7, 0x8c, 0xeb, 0x73, 0xad, 0xb2, 0x4d, 0x88, 0x33, 0xbf, 0x50, 0x90, - 0x27, 0x61, 0xd4, 0x63, 0x52, 0x3e, 0x00, 0xa1, 0x7b, 0x1c, 0xe1, 0xcc, 0x2f, 0xb7, 0x57, 0x50, - 0x08, 0xf1, 0xa8, 0x0b, 0x4c, 0x90, 0xac, 0xc3, 0xfc, 0x71, 0xc4, 0xbc, 0xde, 0xa9, 0x94, 0x0c, - 0x59, 0x22, 0x9f, 0x48, 0x7d, 0xf7, 0x1e, 0x5f, 0xfd, 0x21, 0xeb, 0x23, 0xc7, 0x54, 0xdd, 0xa6, - 0xc4, 0x77, 0x24, 0xcc, 0x35, 0x83, 0x77, 0xec, 0x05, 0xfd, 0x30, 0x60, 0x7d, 0x64, 0x9a, 0xaa, - 0x9b, 0x02, 0xf4, 0x10, 0xd6, 0xb3, 0xf3, 0x93, 0xf2, 0xf5, 0xb6, 0x21, 0x5f, 0xc2, 0xbb, 0xea, - 0xcc, 0xde, 0x4d, 0x43, 0xd6, 0xfe, 0xd9, 0x81, 0x32, 0x37, 0xb6, 0xb3, 0x0d, 0xb3, 0xe9, 0x3f, - 0xcd, 0xe5, 0xc2, 0x36, 0x78, 0x38, 0x11, 0xea, 0x57, 0x98, 0x28, 0x03, 0x49, 0xeb, 0x23, 0xd6, - 0x3b, 0xc3, 0x19, 0xeb, 0x7a, 0x8e, 0x70, 0x01, 0xe1, 0x1e, 0x2c, 0x7e, 0x2d, 0x05, 0x44, 0x95, - 0x55, 0x1d, 0x7e, 0xb9, 0x90, 0xd6, 0xe1, 0x77, 0x6d, 0x58, 0xf0, 0x83, 0xe3, 0x70, 0x12, 0xf4, - 0x51, 0x20, 0xaa, 0xae, 0x2a, 0xf2, 0xe5, 0x1b, 0xa3, 0xa0, 0xfa, 0x23, 0xc5, 0xfe, 0x29, 0x40, - 0x09, 0x3f, 0xe1, 0xc4, 0xe8, 0x5c, 0xe8, 0x38, 0xc5, 0xdb, 0xb0, 0x6c, 0x60, 0xa9, 0xa3, 0x3a, - 0xe6, 0x40, 0xc6, 0x51, 0x45, 0xaf, 0x44, 0xd4, 0xd0, 0x16, 0x2c, 0xdd, 0x67, 0xc9, 0x83, 0xe0, - 0x24, 0x54, 0x2d, 0xfd, 0x51, 0x19, 0x9a, 0x1a, 0x92, 0x0d, 0xdd, 0x84, 0xa6, 0xdf, 0x67, 0x41, - 0xe2, 0x27, 0xd3, 0xae, 0x75, 0x90, 0xca, 0xc2, 0xdc, 0x9b, 0xf3, 0x86, 0xbe, 0xa7, 0x42, 0x63, - 0xa2, 0x40, 0xee, 0xc0, 0x2a, 0x37, 0x35, 0xca, 0x7a, 0xe8, 0x2d, 0x16, 0xe7, 0xb9, 0xc2, 0x3a, - 0xae, 0x0c, 0x38, 0x2e, 0xb5, 0xbd, 0xfe, 0x44, 0x78, 0x35, 0x45, 0x55, 0x7c, 0xd5, 0x44, 0x4b, - 0x7c, 0xca, 0x15, 0x61, 0x8e, 0x34, 0x90, 0x8b, 0x37, 0xcd, 0x0b, 0x55, 0x95, 0x8d, 0x37, 0x19, - 0x31, 0xab, 0x6a, 0x2e, 0x66, 0xc5, 0x55, 0xd9, 0x34, 0xe8, 0xb1, 0x7e, 0x37, 0x09, 0xbb, 0xa8, - 0x72, 0x71, 0x77, 0xaa, 0x6e, 0x16, 0x26, 0x57, 0x60, 0x21, 0x61, 0x71, 0x12, 0xb0, 0x04, 0xb5, - 0x52, 0xf5, 0x6e, 0xa9, 0xed, 0xb8, 0x0a, 0xe2, 0x2e, 0xe8, 0x24, 0xf2, 0xe3, 0x76, 0x03, 0xa3, - 0x51, 0xf8, 0x9b, 0x7c, 0x0a, 0xd6, 0x8e, 0x59, 0x9c, 0x74, 0x4f, 0x99, 0xd7, 0x67, 0x11, 0xee, - 0xb4, 0x08, 0x7b, 0x09, 0xcb, 0x5e, 0x5c, 0xc9, 0x79, 0xe8, 0x8c, 0x45, 0xb1, 0x1f, 0x06, 0x68, - 0xd3, 0x6b, 0xae, 0x2a, 0xf2, 0xf6, 0xf8, 0xe4, 0xb5, 0xbd, 0xd4, 0x2b, 0xd8, 0xc4, 0x89, 0x17, - 0x57, 0x92, 0xeb, 0x30, 0x8f, 0x13, 0x88, 0xdb, 0x2d, 0x2b, 0x10, 0xb0, 0xc3, 0x41, 0x57, 0xd6, - 0x7d, 0xae, 0x5c, 0xad, 0xb7, 0x1a, 0xf4, 0xc7, 0xa0, 0x82, 0x30, 0xdf, 0x74, 0xb1, 0x18, 0x82, - 0x29, 0x44, 0x81, 0x0f, 0x2d, 0x60, 0xc9, 0x79, 0x18, 0x3d, 0x53, 0x71, 0x52, 0x59, 0xa4, 0x5f, - 0x47, 0x27, 0x5e, 0xc7, 0x0a, 0x9f, 0xa0, 0x07, 0xc2, 0x8f, 0x62, 0x62, 0xa9, 0xe3, 0x53, 0x4f, - 0x9e, 0x2b, 0xaa, 0x08, 0x1c, 0x9d, 0x7a, 0x5c, 0x6d, 0x59, 0xbb, 0x27, 0x8e, 0x6a, 0x75, 0xc4, - 0xf6, 0xc5, 0xe6, 0x5d, 0x87, 0x25, 0x15, 0x85, 0x8c, 0xbb, 0x43, 0x76, 0x92, 0xa8, 0x70, 0x41, - 0x30, 0x19, 0xe1, 0x79, 0xee, 0x80, 0x9d, 0x24, 0xf4, 0x21, 0x2c, 0x4b, 0x55, 0xf2, 0x68, 0xcc, - 0x54, 0xd7, 0x9f, 0x29, 0x32, 0xc9, 0x33, 0xe2, 0xae, 0x36, 0x25, 0x75, 0x81, 0x98, 0xaa, 0x49, - 0x36, 0x28, 0xed, 0xa2, 0x0a, 0x4a, 0xc8, 0xe9, 0x58, 0x18, 0x5f, 0x9f, 0x78, 0xd2, 0xeb, 0xa9, - 0x38, 0x72, 0xd5, 0x55, 0x45, 0xfa, 0x6d, 0x07, 0x56, 0xb0, 0x35, 0xe5, 0x54, 0x48, 0xf5, 0xff, - 0xce, 0xf7, 0x31, 0xcc, 0x46, 0xcf, 0x0c, 0xd4, 0xac, 0x42, 0xc5, 0x34, 0x08, 0xa2, 0xf0, 0xfd, - 0x9f, 0xcd, 0xcb, 0xb9, 0xb3, 0xf9, 0xef, 0x38, 0xb0, 0x2c, 0x74, 0x72, 0xe2, 0x25, 0x93, 0x58, - 0x4e, 0xff, 0xc7, 0x61, 0x51, 0x18, 0x57, 0x29, 0xd5, 0x72, 0xa0, 0xab, 0x5a, 0x01, 0x21, 0x2a, - 0x88, 0xf7, 0x2f, 0xb9, 0x36, 0x31, 0x79, 0x0f, 0x1d, 0x9c, 0xa0, 0x8b, 0xa8, 0x8c, 0xa5, 0x5d, - 0x2e, 0x30, 0x03, 0xfa, 0x7b, 0x83, 0xfc, 0x6e, 0x15, 0xe6, 0x85, 0x47, 0x4b, 0xef, 0xc3, 0xa2, - 0xd5, 0x91, 0x15, 0x32, 0x68, 0x88, 0x90, 0x41, 0x2e, 0xc2, 0x54, 0xca, 0x47, 0x98, 0xe8, 0x1f, - 0xcf, 0x01, 0xe1, 0xcc, 0x92, 0xd9, 0x0d, 0xee, 0x52, 0x87, 0x7d, 0xeb, 0x80, 0xd4, 0x70, 0x4d, - 0x88, 0xdc, 0x02, 0x62, 0x14, 0x55, 0x10, 0x4e, 0x58, 0x9f, 0x82, 0x1a, 0xae, 0x26, 0xa5, 0xf1, - 0x96, 0x66, 0x56, 0x1e, 0x05, 0xc5, 0xb2, 0x17, 0xd6, 0x71, 0x03, 0x33, 0x9e, 0xc4, 0xa7, 0x78, - 0xe3, 0x20, 0x8f, 0x50, 0xaa, 0x9c, 0xdd, 0xdf, 0xf9, 0x0b, 0xf7, 0x77, 0x21, 0xbb, 0xbf, 0xa6, - 0x13, 0x5f, 0xb5, 0x9c, 0x78, 0xee, 0x3c, 0x8e, 0xb8, 0xcb, 0x99, 0x0c, 0x7b, 0xdd, 0x11, 0xef, - 0x5d, 0x9e, 0x98, 0x2c, 0x90, 0x6c, 0x42, 0x4b, 0xba, 0x1b, 0xe9, 0x49, 0x01, 0x70, 0x8d, 0x73, - 0x38, 0xd7, 0xdf, 0x69, 0xa0, 0xa6, 0x8e, 0x83, 0x4d, 0x01, 0x7e, 0xb6, 0x8a, 0x39, 0x87, 0x74, - 0x27, 0x81, 0xbc, 0x68, 0x60, 0x7d, 0x3c, 0x2b, 0x55, 0xdd, 0x7c, 0x05, 0xfd, 0x2d, 0x07, 0x5a, - 0x7c, 0xcf, 0x2c, 0xb6, 0x7c, 0x17, 0x50, 0x2a, 0x5e, 0x92, 0x2b, 0x2d, 0x5a, 0xf2, 0x0e, 0xd4, - 0xb0, 0x1c, 0x8e, 0x59, 0x20, 0x79, 0xb2, 0x6d, 0xf3, 0x64, 0xaa, 0x4f, 0xf6, 0x2f, 0xb9, 0x29, - 0xb1, 0xc1, 0x91, 0x7f, 0xe3, 0x40, 0x5d, 0xf6, 0xf2, 0x03, 0x07, 0x02, 0x3a, 0xc6, 0xed, 0x90, - 0xe0, 0xa4, 0xf4, 0x22, 0xe8, 0x26, 0x34, 0x47, 0x5e, 0x32, 0x89, 0xb8, 0x3d, 0xb6, 0x82, 0x00, - 0x59, 0x98, 0x1b, 0x57, 0x54, 0x9d, 0x71, 0x37, 0xf1, 0x87, 0x5d, 0x55, 0x2b, 0xef, 0x60, 0x8a, - 0xaa, 0xb8, 0x06, 0x89, 0x13, 0x6f, 0xc0, 0xa4, 0xdd, 0x14, 0x05, 0xda, 0x86, 0x75, 0x39, 0xa1, - 0x8c, 0xab, 0x4a, 0xff, 0xbc, 0x01, 0x1b, 0xb9, 0x2a, 0x7d, 0x69, 0x2b, 0x4f, 0xb7, 0x43, 0x7f, - 0x74, 0x1c, 0x6a, 0x3f, 0xdf, 0x31, 0x0f, 0xbe, 0x56, 0x15, 0x19, 0xc0, 0x9a, 0x72, 0x10, 0xf8, - 0x9a, 0xa6, 0xc6, 0xac, 0x84, 0x56, 0xea, 0x2d, 0x7b, 0x0b, 0xb3, 0x1d, 0x2a, 0xdc, 0x14, 0xe2, - 0xe2, 0xf6, 0xc8, 0x29, 0xb4, 0xb5, 0x27, 0x22, 0x95, 0xb5, 0xe1, 0xad, 0xf0, 0xbe, 0xde, 0xbc, - 0xa0, 0x2f, 0xcb, 0xb3, 0x75, 0x67, 0xb6, 0x46, 0xa6, 0x70, 0x55, 0xd5, 0xa1, 0x36, 0xce, 0xf7, - 0x57, 0x7e, 0xa9, 0xb9, 0xa1, 0xcf, 0x6e, 0x77, 0x7a, 0x41, 0xc3, 0xe4, 0xab, 0xb0, 0x7e, 0xee, - 0xf9, 0x89, 0x1a, 0x96, 0xe1, 0x1b, 0x54, 0xb0, 0xcb, 0x3b, 0x17, 0x74, 0xf9, 0x54, 0x7c, 0x6c, - 0x99, 0xa8, 0x19, 0x2d, 0x76, 0xfe, 0xca, 0x81, 0x25, 0xbb, 0x1d, 0xce, 0xa6, 0x52, 0xf6, 0x95, - 0x0e, 0x54, 0xde, 0x64, 0x06, 0xce, 0x1f, 0x95, 0x4b, 0x45, 0x47, 0x65, 0xf3, 0x80, 0x3a, 0x77, - 0x51, 0x14, 0xa9, 0xfc, 0x72, 0x51, 0xa4, 0x4a, 0x51, 0x14, 0xa9, 0xf3, 0x1f, 0x0e, 0x90, 0x3c, - 0x2f, 0x91, 0xfb, 0xe2, 0xac, 0x1e, 0xb0, 0xa1, 0x54, 0x29, 0xff, 0xff, 0xe5, 0xf8, 0x51, 0xad, - 0x9d, 0xfa, 0x9a, 0x0b, 0x86, 0x79, 0x89, 0x6a, 0x3a, 0x3b, 0x8b, 0x6e, 0x51, 0x55, 0x26, 0xae, - 0x55, 0xbe, 0x38, 0xae, 0x55, 0xb9, 0x38, 0xae, 0x35, 0x9f, 0x8d, 0x6b, 0x75, 0x7e, 0xd9, 0x81, - 0x95, 0x82, 0x4d, 0xff, 0xd1, 0x4d, 0x9c, 0x6f, 0x93, 0xa5, 0x0b, 0x4a, 0x72, 0x9b, 0x4c, 0xb0, - 0xf3, 0x73, 0xb0, 0x68, 0x31, 0xfa, 0x8f, 0xae, 0xff, 0xac, 0xbf, 0x26, 0xf8, 0xcc, 0xc2, 0x3a, - 0xff, 0x52, 0x02, 0x92, 0x17, 0xb6, 0xff, 0xd3, 0x31, 0xe4, 0xd7, 0x69, 0xae, 0x60, 0x9d, 0xfe, - 0x57, 0xed, 0xc0, 0x9b, 0xb0, 0x2c, 0x33, 0x3c, 0x8c, 0x08, 0x8d, 0xe0, 0x98, 0x7c, 0x05, 0xf7, - 0x58, 0xed, 0xa0, 0x62, 0xd5, 0xba, 0x29, 0x37, 0x8c, 0x61, 0x26, 0xb6, 0x48, 0xd7, 0x61, 0x55, - 0x64, 0x8c, 0xdc, 0x15, 0x4d, 0x29, 0xbb, 0xf2, 0x7b, 0x0e, 0xac, 0x65, 0x2a, 0xd2, 0x7b, 0x5d, - 0x61, 0x3a, 0x6c, 0x7b, 0x62, 0x83, 0x7c, 0xfc, 0xda, 0x4b, 0xc8, 0x70, 0x5b, 0xbe, 0x82, 0xaf, - 0x8f, 0xe1, 0x55, 0x64, 0x56, 0xbd, 0xa8, 0x8a, 0x6e, 0x88, 0xbc, 0x96, 0x80, 0x0d, 0x33, 0x03, - 0x3f, 0x11, 0x99, 0x28, 0x66, 0x45, 0x7a, 0xb3, 0x63, 0x0f, 0x59, 0x15, 0xb9, 0x43, 0x68, 0x99, - 0x29, 0x7b, 0xbc, 0x85, 0x75, 0xf4, 0xbb, 0x0e, 0x90, 0x2f, 0x4c, 0x58, 0x34, 0xc5, 0xbb, 0x5b, - 0x1d, 0x3a, 0xda, 0xc8, 0x06, 0x46, 0xe6, 0xc7, 0x93, 0xe3, 0xcf, 0xb3, 0xa9, 0xca, 0x02, 0x28, - 0xa5, 0x59, 0x00, 0xaf, 0x02, 0xf0, 0x83, 0x94, 0xbe, 0x10, 0x46, 0x47, 0x2c, 0x98, 0x8c, 0x44, - 0x83, 0x85, 0x17, 0xf5, 0xe5, 0x8b, 0x2f, 0xea, 0x2b, 0x17, 0x5d, 0xd4, 0xbf, 0x07, 0x2b, 0xd6, - 0xb8, 0xf5, 0xb6, 0xaa, 0xab, 0x69, 0xe7, 0x05, 0x57, 0xd3, 0xbf, 0x5a, 0x82, 0xb9, 0xfd, 0x70, - 0x6c, 0x86, 0x4d, 0x1d, 0x3b, 0x6c, 0x2a, 0x6d, 0x49, 0x57, 0x9b, 0x0a, 0xa9, 0x62, 0x2c, 0x90, - 0x6c, 0xc2, 0x92, 0x37, 0x4a, 0xf8, 0x39, 0xfe, 0x24, 0x8c, 0xce, 0xbd, 0xa8, 0x2f, 0xf6, 0x1a, - 0x8f, 0xef, 0x99, 0x1a, 0xb2, 0x0a, 0x73, 0x5a, 0xe9, 0x22, 0x01, 0x2f, 0x72, 0xc7, 0x0d, 0xaf, - 0x5c, 0xa6, 0x32, 0x04, 0x21, 0x4b, 0x9c, 0x95, 0xec, 0xef, 0x85, 0xd7, 0x2c, 0x44, 0xa7, 0xa8, - 0x8a, 0xdb, 0x35, 0xbe, 0x7c, 0x48, 0x26, 0x63, 0x47, 0xaa, 0x6c, 0xc6, 0xb9, 0xaa, 0xf6, 0x05, - 0xd4, 0x3f, 0x39, 0x50, 0xc1, 0xb5, 0xe1, 0x6a, 0x40, 0xf0, 0xbe, 0x8e, 0x9c, 0xe2, 0x9a, 0x2c, - 0xba, 0x59, 0x98, 0x50, 0x2b, 0x8f, 0xa6, 0xa4, 0x27, 0x64, 0xe6, 0xd2, 0x5c, 0x83, 0x9a, 0x28, - 0xe9, 0x9c, 0x11, 0x24, 0x49, 0x41, 0x72, 0x15, 0xca, 0xa7, 0xe1, 0x58, 0xf9, 0x2d, 0xa0, 0x2e, - 0x0e, 0xc2, 0xb1, 0x8b, 0x78, 0x3a, 0x1e, 0xde, 0x9e, 0x98, 0x96, 0xb0, 0x46, 0x59, 0x98, 0xdb, - 0x63, 0xdd, 0xac, 0xb9, 0x4c, 0x19, 0x94, 0x6e, 0x42, 0xf3, 0x61, 0xd8, 0x67, 0x46, 0xf8, 0x6a, - 0x26, 0x9f, 0xd3, 0x9f, 0x77, 0xa0, 0xaa, 0x88, 0xc9, 0x4d, 0x28, 0x73, 0x27, 0x23, 0x73, 0x02, - 0xd0, 0x17, 0x86, 0x9c, 0xce, 0x45, 0x0a, 0xae, 0x95, 0x31, 0xaa, 0x90, 0x3a, 0x9c, 0x2a, 0xa6, - 0x90, 0xfa, 0x53, 0x7a, 0xb8, 0x19, 0x37, 0x24, 0x83, 0xd2, 0xef, 0x38, 0xb0, 0x68, 0xf5, 0xc1, - 0xcf, 0x90, 0x43, 0x2f, 0x4e, 0xe4, 0x25, 0x8c, 0xdc, 0x1e, 0x13, 0x32, 0x37, 0xba, 0x64, 0x07, - 0x34, 0x75, 0xa8, 0x6d, 0xce, 0x0c, 0xb5, 0xdd, 0x86, 0x5a, 0x9a, 0xed, 0x54, 0xb6, 0xb4, 0x2d, - 0xef, 0x51, 0x5d, 0x85, 0xa6, 0x44, 0x18, 0xbd, 0x09, 0x87, 0x61, 0x24, 0xa3, 0xff, 0xa2, 0x40, - 0xdf, 0x83, 0xba, 0x41, 0x6f, 0x06, 0x73, 0x1c, 0x2b, 0x98, 0xa3, 0x93, 0x01, 0x4a, 0x69, 0x32, - 0x00, 0xfd, 0x4b, 0x07, 0x16, 0x39, 0x0f, 0xfa, 0xc1, 0xe0, 0x30, 0x1c, 0xfa, 0xbd, 0x29, 0xee, - 0xbd, 0x62, 0x37, 0xa9, 0x33, 0x14, 0x2f, 0xda, 0x30, 0xe7, 0x7a, 0x75, 0x84, 0x94, 0x22, 0xaa, - 0xcb, 0x5c, 0x86, 0xb9, 0x04, 0x1c, 0x7b, 0xb1, 0x14, 0x0b, 0x69, 0xfe, 0x2c, 0x90, 0x4b, 0x1a, - 0x07, 0x22, 0x2f, 0x61, 0xdd, 0x91, 0x3f, 0x1c, 0xfa, 0x82, 0x56, 0x38, 0x47, 0x45, 0x55, 0xbc, - 0xcf, 0xbe, 0x1f, 0x7b, 0xc7, 0x69, 0x44, 0x5b, 0x97, 0xe9, 0x9f, 0x96, 0xa0, 0x2e, 0x15, 0xf7, - 0x5e, 0x7f, 0xc0, 0xe4, 0xf5, 0x0b, 0xba, 0x9f, 0x5a, 0xc9, 0x18, 0x88, 0xaa, 0xb7, 0x1c, 0x56, - 0x03, 0xc9, 0x6e, 0xf9, 0x5c, 0x7e, 0xcb, 0xaf, 0x40, 0x8d, 0xb3, 0xde, 0x5b, 0xe8, 0x19, 0x8b, - 0xab, 0x9b, 0x14, 0x50, 0xb5, 0x77, 0xb0, 0xb6, 0x92, 0xd6, 0x22, 0xf0, 0xc2, 0xcb, 0x9a, 0x77, - 0xa0, 0x21, 0x9b, 0xc1, 0x3d, 0x41, 0x9d, 0x92, 0x32, 0xbf, 0xb5, 0x5f, 0xae, 0x45, 0xa9, 0xbe, - 0xbc, 0xa3, 0xbe, 0xac, 0x5e, 0xf4, 0xa5, 0xa2, 0xa4, 0xf7, 0xf5, 0x1d, 0xd8, 0xfd, 0xc8, 0x1b, - 0x9f, 0x2a, 0x29, 0xbd, 0x0d, 0x2b, 0x7e, 0xd0, 0x1b, 0x4e, 0xfa, 0xac, 0x3b, 0x09, 0xbc, 0x20, - 0x08, 0x27, 0x41, 0x8f, 0xa9, 0x14, 0x80, 0xa2, 0x2a, 0xda, 0xd7, 0xa9, 0x47, 0xd8, 0x10, 0xd9, - 0x84, 0x0a, 0xef, 0x48, 0x59, 0x85, 0x62, 0x11, 0x16, 0x24, 0xe4, 0x26, 0x54, 0x58, 0x7f, 0xc0, - 0xd4, 0x69, 0x91, 0xd8, 0xe7, 0x76, 0xbe, 0xab, 0xae, 0x20, 0xe0, 0x0a, 0x85, 0xa3, 0x19, 0x85, - 0x62, 0x5b, 0x94, 0x79, 0x5e, 0x7c, 0xd0, 0xa7, 0xab, 0x40, 0x1e, 0x0a, 0x19, 0x30, 0xc3, 0xe7, - 0xbf, 0x34, 0x07, 0x75, 0x03, 0xe6, 0xba, 0x61, 0xc0, 0x07, 0xdc, 0xed, 0xfb, 0xde, 0x88, 0x25, - 0x2c, 0x92, 0x7c, 0x9f, 0x41, 0x39, 0x9d, 0x77, 0x36, 0xe8, 0x86, 0x93, 0xa4, 0xdb, 0x67, 0x83, - 0x88, 0x09, 0x23, 0xcf, 0x8d, 0x8e, 0x85, 0x72, 0xba, 0x91, 0xf7, 0xdc, 0xa4, 0x13, 0x1c, 0x94, - 0x41, 0x55, 0x30, 0x5c, 0xac, 0x51, 0x39, 0x0d, 0x86, 0x8b, 0x15, 0xc9, 0x6a, 0xb5, 0x4a, 0x81, - 0x56, 0x7b, 0x1b, 0xd6, 0x85, 0xfe, 0x92, 0x92, 0xde, 0xcd, 0x30, 0xd6, 0x8c, 0x5a, 0xb2, 0x09, - 0x2d, 0x3e, 0x66, 0x25, 0x12, 0xb1, 0xff, 0x75, 0x11, 0x58, 0x72, 0xdc, 0x1c, 0xce, 0x69, 0x31, - 0xc2, 0x63, 0xd2, 0x8a, 0xcb, 0xc1, 0x1c, 0x8e, 0xb4, 0xde, 0x73, 0x9b, 0xb6, 0x26, 0x69, 0x33, - 0x38, 0x5d, 0x84, 0xfa, 0x51, 0x12, 0x8e, 0xd5, 0xa6, 0x2c, 0x41, 0x43, 0x14, 0x65, 0x2a, 0xc6, - 0x2b, 0x70, 0x19, 0xb9, 0xe8, 0x71, 0x38, 0x0e, 0x87, 0xe1, 0x60, 0x7a, 0x34, 0x39, 0x16, 0x39, - 0xb8, 0x7e, 0x18, 0xd0, 0xbf, 0x76, 0x60, 0xc5, 0xaa, 0x95, 0xd1, 0xa3, 0x4f, 0x09, 0x21, 0xd0, - 0x77, 0xe8, 0x82, 0xf1, 0x96, 0x0d, 0xe5, 0x2a, 0x08, 0x45, 0x0c, 0xf0, 0x89, 0xbc, 0x56, 0xdf, - 0x86, 0xa6, 0x1a, 0x99, 0xfa, 0x50, 0x70, 0x61, 0x3b, 0xcf, 0x85, 0xf2, 0xfb, 0x25, 0xf9, 0x81, - 0x6a, 0xe2, 0x27, 0xe4, 0x25, 0x6b, 0x1f, 0xe7, 0xa8, 0xe2, 0x10, 0xfa, 0x62, 0xcc, 0x3c, 0x8d, - 0xa8, 0x11, 0xf4, 0x34, 0x18, 0xd3, 0x5f, 0x77, 0x00, 0xd2, 0xd1, 0xe1, 0xd5, 0x9c, 0x36, 0x10, - 0x22, 0x4d, 0xde, 0x30, 0x06, 0xaf, 0x43, 0x43, 0x5f, 0xe9, 0xa4, 0x36, 0xa7, 0xae, 0x30, 0xee, - 0x30, 0xde, 0x80, 0xe6, 0x60, 0x18, 0x1e, 0xa3, 0xc1, 0xc6, 0xdc, 0x9e, 0x58, 0x26, 0xa4, 0x2c, - 0x09, 0xf8, 0x9e, 0x44, 0x53, 0x03, 0x55, 0x36, 0x0c, 0x14, 0xfd, 0x46, 0x49, 0x47, 0xe0, 0xd3, - 0x39, 0xcf, 0x94, 0x32, 0x72, 0x27, 0xa7, 0x4e, 0x67, 0x04, 0xbc, 0x31, 0xe2, 0x76, 0x78, 0x61, - 0x40, 0xe0, 0x3d, 0x58, 0x8a, 0x84, 0xbe, 0x52, 0xca, 0xac, 0xfc, 0x02, 0x65, 0xb6, 0x18, 0x59, - 0x56, 0xec, 0x13, 0xd0, 0xf2, 0xfa, 0x67, 0x2c, 0x4a, 0x7c, 0x3c, 0x92, 0xa1, 0x0b, 0x21, 0x54, - 0x70, 0xd3, 0xc0, 0xd1, 0xb2, 0xdf, 0x80, 0xa6, 0x4c, 0x02, 0xd2, 0x94, 0x32, 0xef, 0x35, 0x85, - 0x39, 0x21, 0xfd, 0x03, 0x15, 0xec, 0xb7, 0xf7, 0x70, 0xf6, 0x8a, 0x98, 0xb3, 0x2b, 0x65, 0x66, - 0xf7, 0x31, 0x19, 0x78, 0xef, 0xab, 0x73, 0xdf, 0x9c, 0x71, 0x21, 0xdf, 0x97, 0x17, 0x25, 0xf6, - 0x92, 0x96, 0x5f, 0x66, 0x49, 0xe9, 0xf7, 0x1c, 0x58, 0xd8, 0x0f, 0xc7, 0xfb, 0x32, 0x35, 0x01, - 0x05, 0x41, 0x67, 0xdf, 0xa9, 0xe2, 0x0b, 0x92, 0x16, 0x0a, 0x2d, 0xf7, 0x62, 0xd6, 0x72, 0xff, - 0x14, 0xbc, 0x82, 0x51, 0x87, 0x28, 0x1c, 0x87, 0x11, 0x17, 0x46, 0x6f, 0x28, 0xcc, 0x74, 0x18, - 0x24, 0xa7, 0x4a, 0x8d, 0xbd, 0x88, 0x04, 0x8f, 0x77, 0xfc, 0x58, 0x22, 0x9c, 0x6e, 0xe9, 0x69, - 0x08, 0xed, 0x96, 0xaf, 0xa0, 0x9f, 0x81, 0x1a, 0xba, 0xca, 0x38, 0xad, 0x37, 0xa1, 0x76, 0x1a, - 0x8e, 0xbb, 0xa7, 0x7e, 0x90, 0x28, 0xe1, 0x5e, 0x4a, 0x7d, 0xd8, 0x7d, 0x5c, 0x10, 0x4d, 0x40, - 0xff, 0xb3, 0x02, 0x0b, 0x0f, 0x82, 0xb3, 0xd0, 0xef, 0xe1, 0xc5, 0xc2, 0x88, 0x8d, 0x42, 0x95, - 0x8b, 0xc8, 0x7f, 0x93, 0x2b, 0xb0, 0x80, 0xc9, 0x37, 0x63, 0xc1, 0xb4, 0x0d, 0x71, 0x01, 0x28, - 0x21, 0xee, 0x24, 0x44, 0x69, 0x5e, 0xb1, 0x10, 0x1f, 0x03, 0xe1, 0x87, 0x88, 0xc8, 0xcc, 0x0b, - 0x96, 0xa5, 0x34, 0xa1, 0xb3, 0x62, 0x24, 0x74, 0xf2, 0xbe, 0x64, 0x2a, 0x85, 0xb8, 0x6b, 0x17, - 0x7d, 0x49, 0x08, 0x0f, 0x3e, 0x11, 0x13, 0x51, 0x23, 0x74, 0x39, 0x16, 0xe4, 0xc1, 0xc7, 0x04, - 0xb9, 0x5b, 0x22, 0x3e, 0x10, 0x34, 0x42, 0x09, 0x9b, 0x10, 0x77, 0xe1, 0xb2, 0x99, 0xdc, 0x35, - 0xc1, 0xfb, 0x19, 0x98, 0x6b, 0xea, 0x3e, 0xd3, 0x0a, 0x55, 0xcc, 0x03, 0x44, 0xee, 0x74, 0x16, - 0x37, 0x8e, 0x4b, 0x22, 0x4f, 0x4a, 0x1d, 0x97, 0x38, 0xc3, 0x78, 0xc3, 0xe1, 0xb1, 0xd7, 0x7b, - 0x86, 0x89, 0xfa, 0x18, 0xea, 0xaf, 0xb9, 0x36, 0x88, 0x09, 0x11, 0xe9, 0xae, 0xe2, 0x55, 0x69, - 0xd9, 0x35, 0x21, 0x72, 0x07, 0xea, 0x78, 0x44, 0x94, 0xfb, 0xba, 0x84, 0xfb, 0xda, 0x32, 0xcf, - 0x90, 0xb8, 0xb3, 0x26, 0x91, 0x79, 0xe9, 0xd1, 0xb4, 0x2f, 0x3d, 0x84, 0xf2, 0x94, 0x77, 0x45, - 0x2d, 0xec, 0x2d, 0x05, 0xb8, 0x55, 0x95, 0x0b, 0x26, 0x08, 0x96, 0x91, 0xc0, 0xc2, 0xc8, 0x55, - 0xa8, 0xf2, 0xe3, 0xcb, 0xd8, 0xf3, 0xfb, 0x6d, 0xa2, 0x4f, 0x51, 0x1a, 0xe3, 0x6d, 0xa8, 0xdf, - 0x78, 0xa7, 0xb3, 0x82, 0xab, 0x62, 0x61, 0x7c, 0x6d, 0x74, 0x19, 0x85, 0x69, 0x55, 0xec, 0xa8, - 0x05, 0x92, 0xb7, 0x30, 0x62, 0x9f, 0xb0, 0xf6, 0x1a, 0xa6, 0xc5, 0xbc, 0x22, 0xe7, 0x2c, 0x99, - 0x56, 0xfd, 0x3d, 0xe2, 0x24, 0xae, 0xa0, 0xa4, 0x1f, 0x87, 0x86, 0x09, 0x93, 0x2a, 0x94, 0x1f, - 0x1d, 0xee, 0x3d, 0x6c, 0x5d, 0x22, 0x75, 0x58, 0x38, 0xda, 0x7b, 0xfc, 0xf8, 0x60, 0x6f, 0xb7, - 0xe5, 0xd0, 0x04, 0xc8, 0x76, 0xbf, 0x2f, 0x29, 0xf5, 0x41, 0x3d, 0xe5, 0x59, 0xc7, 0xe2, 0xd9, - 0x02, 0xbe, 0x29, 0x15, 0xf3, 0xcd, 0x0b, 0x57, 0x97, 0xee, 0x41, 0xfd, 0xd0, 0x48, 0x71, 0x47, - 0x11, 0x52, 0xc9, 0xed, 0x52, 0xf4, 0x0c, 0xc4, 0x18, 0x4e, 0xc9, 0x1c, 0x0e, 0xfd, 0x43, 0x47, - 0x64, 0x09, 0xeb, 0xe1, 0x8b, 0xbe, 0x29, 0x34, 0x74, 0x38, 0x25, 0x4d, 0x3e, 0xb3, 0x30, 0x4e, - 0x83, 0x43, 0xe9, 0x86, 0x27, 0x27, 0x31, 0x53, 0xa9, 0x22, 0x16, 0xc6, 0x79, 0x9f, 0x7b, 0x51, - 0xdc, 0x23, 0xf1, 0x45, 0x0f, 0xb1, 0x4c, 0x19, 0xc9, 0xe1, 0x5c, 0x93, 0x47, 0xec, 0x8c, 0x45, - 0xb1, 0x4e, 0x92, 0xd1, 0x65, 0x9d, 0x23, 0x97, 0x5d, 0xe5, 0x4d, 0xa8, 0xea, 0x76, 0x6d, 0x25, - 0xa5, 0x28, 0x75, 0x3d, 0x57, 0x86, 0x78, 0xae, 0xb0, 0x06, 0x2d, 0x14, 0x73, 0xbe, 0x82, 0xdc, - 0x02, 0x72, 0xe2, 0x47, 0x59, 0xf2, 0x39, 0x24, 0x2f, 0xa8, 0xa1, 0x4f, 0x61, 0x45, 0x31, 0x8b, - 0xe1, 0x3e, 0xd9, 0x9b, 0xe8, 0x5c, 0x24, 0x22, 0xa5, 0xbc, 0x88, 0xd0, 0xff, 0x72, 0x60, 0x41, - 0xee, 0x74, 0xee, 0x99, 0x84, 0xd8, 0x67, 0x0b, 0x23, 0x6d, 0x2b, 0xcb, 0x1d, 0xe5, 0x49, 0x2a, - 0xc6, 0x9c, 0xea, 0x9b, 0x2b, 0x52, 0x7d, 0x04, 0xca, 0x63, 0x2f, 0x39, 0xc5, 0xd3, 0x72, 0xcd, - 0xc5, 0xdf, 0xa4, 0x25, 0x62, 0x3b, 0x42, 0xcd, 0x62, 0x5c, 0xa7, 0xe8, 0x41, 0x88, 0xb0, 0xe8, - 0xf9, 0x07, 0x21, 0x57, 0xa0, 0x86, 0x03, 0xe8, 0xa6, 0xa1, 0x9b, 0x14, 0xe0, 0x9c, 0x2b, 0x0a, - 0x28, 0xbb, 0x32, 0x17, 0x35, 0x45, 0xe8, 0x9a, 0xd8, 0x79, 0xb9, 0x04, 0xfa, 0x46, 0x4d, 0xe6, - 0x24, 0xa6, 0x70, 0xca, 0x11, 0x72, 0x00, 0x59, 0x8e, 0x90, 0xa4, 0xae, 0xae, 0xa7, 0x1d, 0x68, - 0xef, 0xb2, 0x21, 0x4b, 0xd8, 0xf6, 0x70, 0x98, 0x6d, 0xff, 0x15, 0xb8, 0x5c, 0x50, 0x27, 0x3d, - 0xe6, 0x2f, 0xc0, 0xda, 0xb6, 0xc8, 0xdf, 0xfa, 0x51, 0xe5, 0x24, 0xd0, 0x36, 0xac, 0x67, 0x9b, - 0x94, 0x9d, 0xdd, 0x83, 0xe5, 0x5d, 0x76, 0x3c, 0x19, 0x1c, 0xb0, 0xb3, 0xb4, 0x23, 0x02, 0xe5, - 0xf8, 0x34, 0x3c, 0x97, 0x82, 0x89, 0xbf, 0xc9, 0xab, 0x00, 0x43, 0x4e, 0xd3, 0x8d, 0xc7, 0xac, - 0xa7, 0x72, 0xce, 0x11, 0x39, 0x1a, 0xb3, 0x1e, 0x7d, 0x1b, 0x88, 0xd9, 0x8e, 0x5c, 0x2f, 0x6e, - 0xe9, 0x26, 0xc7, 0xdd, 0x78, 0x1a, 0x27, 0x6c, 0xa4, 0x92, 0xe9, 0x4d, 0x88, 0xde, 0x80, 0xc6, - 0xa1, 0x37, 0x75, 0xd9, 0xd7, 0xe4, 0xeb, 0x98, 0x0d, 0x58, 0x18, 0x7b, 0x53, 0xae, 0xa6, 0x74, - 0x4c, 0x09, 0xab, 0xe9, 0xbf, 0x97, 0x60, 0x5e, 0x50, 0xf2, 0x56, 0xfb, 0x2c, 0x4e, 0xfc, 0x00, - 0x19, 0x4b, 0xb5, 0x6a, 0x40, 0x39, 0x56, 0x2e, 0x15, 0xb0, 0xb2, 0x3c, 0x97, 0xa9, 0xfc, 0x5d, - 0xc9, 0xaf, 0x16, 0xc6, 0x99, 0x2b, 0x4d, 0x0e, 0x12, 0x41, 0x8d, 0x14, 0xc8, 0x84, 0x1f, 0x53, - 0x7b, 0x2a, 0xc6, 0xa7, 0xa4, 0x54, 0x72, 0xae, 0x09, 0x15, 0x5a, 0xed, 0x05, 0xc1, 0xe0, 0x39, - 0xab, 0x9d, 0xb3, 0xce, 0xd5, 0x97, 0xb0, 0xce, 0xe2, 0xb0, 0xf6, 0x22, 0xeb, 0x0c, 0x2f, 0x61, - 0x9d, 0x29, 0x81, 0xd6, 0x3d, 0xc6, 0x5c, 0xc6, 0xfd, 0x3f, 0xc5, 0xbb, 0xdf, 0x74, 0xa0, 0x25, - 0xb9, 0x48, 0xd7, 0x91, 0xd7, 0x2d, 0x3f, 0xb7, 0x30, 0xcb, 0xf6, 0x3a, 0x2c, 0xa2, 0xf7, 0xa9, - 0xe3, 0xac, 0x32, 0x28, 0x6c, 0x81, 0x7c, 0x1e, 0xea, 0x32, 0x6c, 0xe4, 0x0f, 0xe5, 0xa6, 0x98, - 0x90, 0x0a, 0xd5, 0x46, 0x9e, 0x4c, 0x92, 0x71, 0x5c, 0x5d, 0xa6, 0x7f, 0xe6, 0xc0, 0xb2, 0x31, - 0x60, 0xc9, 0x85, 0xef, 0x81, 0x92, 0x06, 0x11, 0x74, 0x15, 0x92, 0xbb, 0x61, 0x8b, 0x4d, 0xfa, - 0x99, 0x45, 0x8c, 0x9b, 0xe9, 0x4d, 0x71, 0x80, 0xf1, 0x64, 0x24, 0x95, 0xa8, 0x09, 0x71, 0x46, - 0x3a, 0x67, 0xec, 0x99, 0x26, 0x11, 0x6a, 0xdc, 0xc2, 0x30, 0x83, 0x83, 0x7b, 0xcd, 0x9a, 0x48, - 0xd8, 0x33, 0x1b, 0xa4, 0x7f, 0xe7, 0xc0, 0x8a, 0x38, 0xfe, 0xc8, 0xc3, 0xa5, 0x7e, 0x02, 0x31, - 0x2f, 0xce, 0x7b, 0x42, 0x22, 0xf7, 0x2f, 0xb9, 0xb2, 0x4c, 0x3e, 0xfd, 0x92, 0x47, 0x36, 0x9d, - 0xb9, 0x33, 0x63, 0x2f, 0xe6, 0x8a, 0xf6, 0xe2, 0x05, 0x2b, 0x5d, 0x14, 0x64, 0xac, 0x14, 0x06, - 0x19, 0xef, 0x2e, 0x40, 0x25, 0xee, 0x85, 0x63, 0x46, 0xd7, 0x61, 0xd5, 0x9e, 0x9c, 0x54, 0x41, - 0xdf, 0x72, 0xa0, 0x7d, 0x4f, 0x04, 0xe3, 0xfd, 0x60, 0xb0, 0xef, 0xc7, 0x49, 0x18, 0xe9, 0xe7, - 0x60, 0x57, 0x01, 0xe2, 0xc4, 0x8b, 0x12, 0x91, 0x9f, 0x29, 0x43, 0x80, 0x29, 0xc2, 0xc7, 0xc8, - 0x82, 0xbe, 0xa8, 0x15, 0x7b, 0xa3, 0xcb, 0x39, 0x1f, 0x42, 0x1e, 0xd0, 0x2c, 0x4b, 0xfc, 0x86, - 0xc8, 0x64, 0xe3, 0xbe, 0x02, 0x3b, 0x43, 0xbd, 0x2e, 0x4e, 0x3e, 0x19, 0x94, 0xfe, 0xad, 0x03, - 0xcd, 0x74, 0x90, 0x7b, 0x1c, 0xb4, 0xb5, 0x83, 0x34, 0xbf, 0xa9, 0x76, 0x50, 0xc1, 0x49, 0x9f, - 0xdb, 0x63, 0x39, 0x36, 0x03, 0x41, 0x89, 0x95, 0xa5, 0x70, 0xa2, 0x1c, 0x1c, 0x13, 0x12, 0x79, - 0x29, 0xdc, 0x13, 0x90, 0x5e, 0x8d, 0x2c, 0x61, 0x7a, 0xed, 0x28, 0xc1, 0xaf, 0xe6, 0xc5, 0xd1, - 0x4f, 0x16, 0x95, 0x29, 0x5d, 0x40, 0x14, 0x4d, 0xa9, 0x79, 0xb1, 0x51, 0x15, 0xeb, 0xa3, 0xca, - 0xf4, 0x37, 0x1c, 0xb8, 0x5c, 0xb0, 0xf0, 0x52, 0x6a, 0x76, 0x61, 0xf9, 0x44, 0x57, 0xaa, 0xc5, - 0x11, 0xa2, 0xb3, 0xae, 0x6e, 0x96, 0xec, 0x05, 0x71, 0xf3, 0x1f, 0x68, 0xbf, 0x48, 0x2c, 0xb7, - 0x95, 0xf9, 0x95, 0xaf, 0xd8, 0xfc, 0x2c, 0xd4, 0x8d, 0x37, 0x5a, 0x64, 0x03, 0x56, 0x9e, 0x3e, - 0x78, 0xfc, 0x70, 0xef, 0xe8, 0xa8, 0x7b, 0xf8, 0xe4, 0xee, 0xe7, 0xf7, 0xbe, 0xd4, 0xdd, 0xdf, - 0x3e, 0xda, 0x6f, 0x5d, 0x22, 0xeb, 0x40, 0x1e, 0xee, 0x1d, 0x3d, 0xde, 0xdb, 0xb5, 0x70, 0xe7, - 0xce, 0x6f, 0xce, 0xc1, 0x92, 0xb8, 0xb1, 0x14, 0x0f, 0xe1, 0x59, 0x44, 0xde, 0x87, 0x05, 0xf9, - 0x8f, 0x0c, 0xc8, 0x9a, 0x1c, 0xb6, 0xfd, 0xaf, 0x13, 0x3a, 0xeb, 0x59, 0x58, 0xf2, 0xe5, 0xca, - 0x2f, 0x7e, 0xef, 0x1f, 0x7f, 0xbb, 0xb4, 0x48, 0xea, 0x5b, 0x67, 0x6f, 0x6d, 0x0d, 0x58, 0x10, - 0xf3, 0x36, 0x7e, 0x06, 0x20, 0x7d, 0xe2, 0x4f, 0xda, 0xda, 0x1f, 0xcc, 0xfc, 0xef, 0x82, 0xce, - 0xe5, 0x82, 0x1a, 0xd9, 0xee, 0x65, 0x6c, 0x77, 0x85, 0x2e, 0xf1, 0x76, 0xfd, 0xc0, 0x4f, 0xc4, - 0x7b, 0xff, 0x77, 0x9d, 0x4d, 0xd2, 0x87, 0x86, 0xf9, 0x82, 0x9f, 0xa8, 0xc0, 0x53, 0xc1, 0xff, - 0x0f, 0xe8, 0xbc, 0x52, 0x58, 0xa7, 0xa2, 0x6e, 0xd8, 0xc7, 0x1a, 0x6d, 0xf1, 0x3e, 0x26, 0x48, - 0x91, 0xf6, 0x32, 0x84, 0x25, 0xfb, 0xa1, 0x3e, 0xb9, 0x62, 0xa8, 0x8c, 0xdc, 0xbf, 0x09, 0xe8, - 0xbc, 0x3a, 0xa3, 0x56, 0xf6, 0xf5, 0x2a, 0xf6, 0xb5, 0x41, 0x09, 0xef, 0xab, 0x87, 0x34, 0xea, - 0xdf, 0x04, 0xbc, 0xeb, 0x6c, 0xde, 0xf9, 0xb7, 0xd7, 0xa0, 0xa6, 0x43, 0xc5, 0xe4, 0xab, 0xb0, - 0x68, 0x5d, 0x29, 0x13, 0x35, 0x8d, 0xa2, 0x1b, 0xe8, 0xce, 0x95, 0xe2, 0x4a, 0xd9, 0xf1, 0x55, - 0xec, 0xb8, 0x4d, 0xd6, 0x79, 0xc7, 0xf2, 0x4e, 0x76, 0x0b, 0x2f, 0xd2, 0x45, 0x56, 0xec, 0x33, - 0x31, 0xcf, 0xf4, 0x1a, 0xd8, 0x9a, 0x67, 0xee, 0xda, 0xd8, 0x9a, 0x67, 0xfe, 0xee, 0x98, 0x5e, - 0xc1, 0xee, 0xd6, 0xc9, 0xaa, 0xd9, 0x9d, 0x0e, 0xe1, 0x32, 0x4c, 0xe5, 0x36, 0xdf, 0xb5, 0x93, - 0x57, 0x35, 0x63, 0x15, 0xbd, 0x77, 0xd7, 0x2c, 0x92, 0x7f, 0xf4, 0x4e, 0xdb, 0xd8, 0x15, 0x21, - 0xb8, 0x7d, 0xe6, 0xb3, 0x76, 0xf2, 0x65, 0xa8, 0xe9, 0x07, 0x9a, 0x64, 0xc3, 0x78, 0x15, 0x6b, - 0xbe, 0x1a, 0xed, 0xb4, 0xf3, 0x15, 0x45, 0x8c, 0x61, 0xb6, 0xcc, 0x19, 0xe3, 0x29, 0xd4, 0x8d, - 0x47, 0x98, 0xe4, 0xb2, 0x0e, 0xf4, 0x67, 0x1f, 0x7a, 0x76, 0x3a, 0x45, 0x55, 0xb2, 0x8b, 0x65, - 0xec, 0xa2, 0x4e, 0x6a, 0xc8, 0x7b, 0xc9, 0xf3, 0x30, 0x26, 0x07, 0xb0, 0x26, 0x0f, 0x2e, 0xc7, - 0xec, 0xfb, 0x59, 0xa2, 0x82, 0x67, 0xfe, 0xb7, 0x1d, 0xf2, 0x1e, 0x54, 0xd5, 0x83, 0x5a, 0xb2, - 0x5e, 0xfc, 0x30, 0xb8, 0xb3, 0x91, 0xc3, 0xa5, 0x5a, 0xfb, 0x12, 0x40, 0xfa, 0xe2, 0x53, 0x0b, - 0x70, 0xee, 0x05, 0xa9, 0xde, 0x9d, 0xfc, 0xf3, 0x50, 0xba, 0x8e, 0x13, 0x6c, 0x11, 0x14, 0xe0, - 0x80, 0x9d, 0xab, 0xc7, 0x0d, 0x5f, 0x81, 0xba, 0xf1, 0xe8, 0x53, 0x2f, 0x5f, 0xfe, 0xc1, 0xa8, - 0x5e, 0xbe, 0x82, 0x37, 0xa2, 0xb4, 0x83, 0xad, 0xaf, 0xd2, 0x26, 0x6f, 0x3d, 0xf6, 0x07, 0xc1, - 0x48, 0x10, 0xf0, 0x0d, 0x3a, 0x85, 0x45, 0xeb, 0x65, 0xa7, 0x96, 0x9e, 0xa2, 0x77, 0xa3, 0x5a, - 0x7a, 0x0a, 0x1f, 0x83, 0x2a, 0x76, 0xa6, 0xcb, 0xbc, 0x9f, 0x33, 0x24, 0x31, 0x7a, 0xfa, 0x00, - 0xea, 0xc6, 0x2b, 0x4d, 0x3d, 0x97, 0xfc, 0x83, 0x50, 0x3d, 0x97, 0xa2, 0x47, 0x9d, 0xab, 0xd8, - 0xc7, 0x12, 0x45, 0x56, 0xc0, 0xb7, 0x01, 0xbc, 0xed, 0xaf, 0xc2, 0x92, 0xfd, 0x6e, 0x53, 0xcb, - 0x65, 0xe1, 0x0b, 0x50, 0x2d, 0x97, 0x33, 0x1e, 0x7b, 0x4a, 0x96, 0xde, 0x5c, 0xd1, 0x9d, 0x6c, - 0x7d, 0x28, 0x2f, 0x6e, 0x3f, 0x22, 0x5f, 0xe0, 0xca, 0x47, 0x3e, 0xd6, 0x20, 0x1b, 0x06, 0xd7, - 0x9a, 0x4f, 0x3a, 0xb4, 0xbc, 0xe4, 0xde, 0x75, 0xd8, 0xcc, 0x2c, 0x5e, 0x37, 0xa0, 0x45, 0xc1, - 0x47, 0x1b, 0x86, 0x45, 0x31, 0xdf, 0x75, 0x18, 0x16, 0xc5, 0x7a, 0xdb, 0x91, 0xb5, 0x28, 0x89, - 0xcf, 0xdb, 0x08, 0xa0, 0x99, 0x49, 0x5f, 0xd2, 0x52, 0x51, 0x9c, 0xef, 0xd9, 0xb9, 0xfa, 0xe2, - 0xac, 0x27, 0x5b, 0x51, 0x29, 0x05, 0xb5, 0xa5, 0xb2, 0x6b, 0x7f, 0x16, 0x1a, 0xe6, 0x7b, 0x3b, - 0x62, 0x8a, 0x72, 0xb6, 0xa7, 0x57, 0x0a, 0xeb, 0xec, 0xcd, 0x25, 0x0d, 0xb3, 0x1b, 0xbe, 0xb9, - 0xf6, 0x83, 0xa3, 0x54, 0xe9, 0x16, 0xbd, 0xb3, 0x4a, 0x95, 0x6e, 0xe1, 0x2b, 0x25, 0xb5, 0xb9, - 0x64, 0xc5, 0x9a, 0x8b, 0x88, 0xb1, 0x93, 0x0f, 0xa0, 0x69, 0xe4, 0x06, 0x1e, 0x4d, 0x83, 0x9e, - 0x66, 0xd4, 0x7c, 0x12, 0x79, 0xa7, 0xc8, 0x2f, 0xa6, 0x1b, 0xd8, 0xfe, 0x32, 0xb5, 0x26, 0xc1, - 0x99, 0x74, 0x07, 0xea, 0x66, 0xde, 0xe1, 0x0b, 0xda, 0xdd, 0x30, 0xaa, 0xcc, 0x1c, 0xe8, 0xdb, - 0x0e, 0xf9, 0x5d, 0x07, 0x1a, 0x56, 0x16, 0x9f, 0x75, 0x93, 0x94, 0x69, 0xa7, 0x6d, 0xd6, 0x99, - 0x0d, 0x51, 0x17, 0x07, 0x79, 0xb0, 0xf9, 0x39, 0x6b, 0x11, 0x3e, 0xb4, 0xce, 0x57, 0xb7, 0xb2, - 0xff, 0xd1, 0xe1, 0xa3, 0x2c, 0x81, 0x99, 0x68, 0xff, 0xd1, 0x6d, 0x87, 0x7c, 0xc7, 0x81, 0x25, - 0x3b, 0x2a, 0xa0, 0xb7, 0xaa, 0x30, 0xfe, 0xa0, 0xb7, 0x6a, 0x46, 0x28, 0xe1, 0x03, 0x1c, 0xe5, - 0xe3, 0x4d, 0xd7, 0x1a, 0xa5, 0x7c, 0x8a, 0xf6, 0xc3, 0x8d, 0x96, 0xbc, 0x2b, 0xfe, 0x07, 0x8b, - 0x0a, 0x55, 0x11, 0x43, 0xbb, 0x67, 0xb7, 0xd7, 0xfc, 0x07, 0x24, 0x37, 0x9d, 0xdb, 0x0e, 0xf9, - 0x8a, 0xf8, 0x27, 0x13, 0xf2, 0x5b, 0xe4, 0x92, 0x97, 0xfd, 0x9e, 0x5e, 0xc7, 0x39, 0x5d, 0xa5, - 0x97, 0xad, 0x39, 0x65, 0xed, 0xe6, 0xb6, 0x18, 0x9d, 0xfc, 0xdf, 0x21, 0xa9, 0xe2, 0xcf, 0xfd, - 0x3f, 0x91, 0xd9, 0x83, 0x1c, 0x89, 0x41, 0x4a, 0x72, 0x8b, 0x95, 0x5f, 0xb2, 0x19, 0xba, 0x89, - 0x63, 0xbd, 0x4e, 0x5f, 0x9b, 0x39, 0xd6, 0x2d, 0x3c, 0xdb, 0xf3, 0x11, 0x1f, 0x02, 0xa4, 0x61, - 0x65, 0x92, 0x09, 0x6b, 0x6a, 0xdb, 0x97, 0x8f, 0x3c, 0xdb, 0xf2, 0xa2, 0xa2, 0x9f, 0xbc, 0xc5, - 0x2f, 0x0b, 0xb5, 0xf2, 0x40, 0x05, 0x44, 0x4d, 0xe7, 0xc1, 0x8e, 0xff, 0x5a, 0xce, 0x43, 0xb6, - 0x7d, 0x4b, 0xa9, 0xe8, 0xe8, 0xea, 0x13, 0x58, 0x3c, 0x08, 0xc3, 0x67, 0x93, 0xb1, 0xbe, 0x06, - 0xb2, 0xc3, 0x6e, 0xfb, 0x5e, 0x7c, 0xda, 0xc9, 0xcc, 0x82, 0x5e, 0xc3, 0xa6, 0x3a, 0xa4, 0x6d, - 0x34, 0xb5, 0xf5, 0x61, 0x1a, 0xb6, 0xfe, 0x88, 0x78, 0xb0, 0xac, 0xdd, 0x12, 0x3d, 0xf0, 0x8e, - 0xdd, 0x8c, 0x19, 0x70, 0xcd, 0x75, 0x61, 0x79, 0xa0, 0x6a, 0xb4, 0x5b, 0xb1, 0x6a, 0xf3, 0xb6, - 0x43, 0x0e, 0xa1, 0xb1, 0xcb, 0x7a, 0x61, 0x9f, 0xc9, 0xd8, 0xd5, 0x4a, 0x3a, 0x70, 0x1d, 0xf4, - 0xea, 0x2c, 0x5a, 0xa0, 0xad, 0xbf, 0xc7, 0xde, 0x34, 0x62, 0x5f, 0xdb, 0xfa, 0x50, 0x46, 0xc5, - 0x3e, 0x52, 0xfa, 0x5b, 0x85, 0x0d, 0x2d, 0xfd, 0x9d, 0x89, 0x33, 0x5a, 0xfa, 0x3b, 0x17, 0x67, - 0xb4, 0x96, 0x5a, 0x85, 0x2d, 0xc9, 0x10, 0x96, 0x73, 0xa1, 0x49, 0xf2, 0x9a, 0xb2, 0xc0, 0x33, - 0x02, 0x9a, 0x9d, 0x6b, 0xb3, 0x09, 0xec, 0xde, 0x36, 0xed, 0xde, 0x8e, 0x60, 0x71, 0x97, 0x89, - 0xc5, 0x12, 0xb9, 0x26, 0x99, 0x37, 0xa8, 0x66, 0x26, 0x4b, 0x56, 0x81, 0x63, 0x9d, 0x6d, 0xa0, - 0x31, 0xd1, 0x83, 0x7c, 0x19, 0xea, 0xf7, 0x59, 0xa2, 0x92, 0x4b, 0xb4, 0x8b, 0x98, 0xc9, 0x36, - 0xe9, 0x14, 0xe4, 0xa6, 0xd8, 0x3c, 0x83, 0xad, 0x6d, 0xb1, 0xfe, 0x80, 0x09, 0xe5, 0xd4, 0xf5, - 0xfb, 0x1f, 0x91, 0x9f, 0xc6, 0xc6, 0x75, 0x76, 0xdb, 0xba, 0x91, 0x93, 0x60, 0x36, 0xde, 0xcc, - 0xe0, 0x45, 0x2d, 0x07, 0x61, 0x9f, 0x19, 0xae, 0x4a, 0x00, 0x75, 0x23, 0x29, 0x53, 0x0b, 0x50, - 0x3e, 0xc1, 0x54, 0x0b, 0x50, 0x41, 0x0e, 0x27, 0xbd, 0x89, 0xfd, 0x50, 0x72, 0x2d, 0xed, 0x47, - 0xe4, 0x6d, 0xa6, 0x3d, 0x6d, 0x7d, 0xe8, 0x8d, 0x92, 0x8f, 0xc8, 0x53, 0x7c, 0x8f, 0x6a, 0x26, - 0xd0, 0xa4, 0x3e, 0x6f, 0x36, 0xd7, 0x46, 0x2f, 0x96, 0x51, 0x65, 0xfb, 0xc1, 0xa2, 0x2b, 0xf4, - 0x68, 0x3e, 0x0d, 0x70, 0x94, 0x84, 0xe3, 0x5d, 0x8f, 0x8d, 0xc2, 0x20, 0xd5, 0xb5, 0x69, 0x92, - 0x48, 0xaa, 0xbf, 0x8c, 0x4c, 0x11, 0xf2, 0xd4, 0x38, 0x24, 0x58, 0xf9, 0x47, 0x8a, 0xb9, 0x66, - 0xe6, 0x91, 0xe8, 0x05, 0x29, 0xc8, 0x25, 0xb9, 0xed, 0x90, 0x6d, 0x80, 0x34, 0x36, 0xad, 0x5d, - 0xfe, 0x5c, 0xd8, 0x5b, 0xab, 0xbd, 0x82, 0x40, 0xf6, 0x21, 0xd4, 0xd2, 0x60, 0xe7, 0x46, 0x9a, - 0x58, 0x6b, 0x85, 0x46, 0xb5, 0x05, 0xcf, 0x85, 0x20, 0x69, 0x0b, 0x97, 0x0a, 0x48, 0x95, 0x2f, - 0x15, 0xc6, 0x15, 0x7d, 0x58, 0x11, 0x03, 0xd4, 0xee, 0x08, 0xa6, 0x3d, 0xa8, 0x99, 0x14, 0x84, - 0x01, 0xb5, 0x34, 0x17, 0x46, 0xd1, 0xac, 0xa8, 0x02, 0xe7, 0x56, 0x91, 0x72, 0xc1, 0x55, 0xf3, - 0x08, 0x96, 0x73, 0x61, 0x1e, 0x2d, 0xd2, 0xb3, 0x22, 0x6f, 0x5a, 0xa4, 0x67, 0x46, 0x88, 0xe8, - 0x1a, 0x76, 0xd9, 0xa4, 0x80, 0x27, 0x95, 0x73, 0x3f, 0xe9, 0x9d, 0xbe, 0xeb, 0x6c, 0xde, 0xbd, - 0xf1, 0xc1, 0xc7, 0x07, 0x7e, 0x72, 0x3a, 0x39, 0xbe, 0xd5, 0x0b, 0x47, 0x5b, 0x43, 0x75, 0xf4, - 0x97, 0xc9, 0x4b, 0x5b, 0xc3, 0xa0, 0xbf, 0x85, 0x2d, 0x1f, 0xcf, 0xe3, 0x3f, 0xb3, 0xfc, 0xe4, - 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xb0, 0xe2, 0xcc, 0xfe, 0x52, 0x00, 0x00, +var fileDescriptor_rpc_e66000aa8614d793 = []byte{ + // 6738 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0x5d, 0x6c, 0x24, 0xd9, + 0x55, 0xff, 0x54, 0xbb, 0xdb, 0xee, 0x3e, 0xdd, 0xb6, 0xdb, 0xd7, 0x5f, 0x3d, 0xbd, 0xb3, 0xb3, + 0xb3, 0x37, 0x93, 0x9d, 0x89, 0xff, 0xfb, 0x1f, 0xcf, 0x4e, 0x92, 0x65, 0xb3, 0x0b, 0x01, 0x8f, + 0xed, 0x19, 0x4f, 0xe2, 0x9d, 0x71, 0xca, 0x33, 0x19, 0xb2, 0x01, 0x75, 0xca, 0xdd, 0xd7, 0xed, + 0xca, 0x54, 0x57, 0x75, 0xaa, 0xaa, 0xed, 0xe9, 0x2c, 0x2b, 0x21, 0x40, 0x20, 0x21, 0x22, 0x04, + 0xbc, 0x10, 0x04, 0x42, 0x0a, 0x48, 0x24, 0x8f, 0xbc, 0x44, 0x48, 0xc0, 0x1b, 0x2f, 0x20, 0x21, + 0x84, 0xf2, 0x88, 0xc4, 0x0b, 0xbc, 0x00, 0x82, 0x07, 0x24, 0x1e, 0x78, 0x00, 0xa1, 0x7b, 0xee, + 0x47, 0xdd, 0x5b, 0x55, 0x1e, 0x4f, 0x3e, 0xe0, 0xc9, 0xbe, 0xbf, 0x7b, 0xea, 0x7e, 0x9e, 0xaf, + 0x7b, 0xee, 0xb9, 0x0d, 0x8d, 0x78, 0xdc, 0xbf, 0x35, 0x8e, 0xa3, 0x34, 0x22, 0xb5, 0x20, 0x8c, + 0xc7, 0xfd, 0xee, 0x95, 0x61, 0x14, 0x0d, 0x03, 0xb6, 0xe9, 0x8d, 0xfd, 0x4d, 0x2f, 0x0c, 0xa3, + 0xd4, 0x4b, 0xfd, 0x28, 0x4c, 0x04, 0x11, 0xfd, 0x0a, 0x2c, 0xdc, 0x67, 0xe1, 0x21, 0x63, 0x03, + 0x97, 0x7d, 0x6d, 0xc2, 0x92, 0x94, 0xfc, 0x3f, 0x58, 0xf2, 0xd8, 0xd7, 0x19, 0x1b, 0xf4, 0xc6, + 0x5e, 0x92, 0x8c, 0x4f, 0x62, 0x2f, 0x61, 0x1d, 0xe7, 0x9a, 0x73, 0xb3, 0xe5, 0xb6, 0x45, 0xc5, + 0x81, 0xc6, 0xc9, 0xeb, 0xd0, 0x4a, 0x38, 0x29, 0x0b, 0xd3, 0x38, 0x1a, 0x4f, 0x3b, 0x15, 0xa4, + 0x6b, 0x72, 0x6c, 0x57, 0x40, 0x34, 0x80, 0x45, 0xdd, 0x43, 0x32, 0x8e, 0xc2, 0x84, 0x91, 0xdb, + 0xb0, 0xd2, 0xf7, 0xc7, 0x27, 0x2c, 0xee, 0xe1, 0xc7, 0xa3, 0x90, 0x8d, 0xa2, 0xd0, 0xef, 0x77, + 0x9c, 0x6b, 0x33, 0x37, 0x1b, 0x2e, 0x11, 0x75, 0xfc, 0x8b, 0xf7, 0x65, 0x0d, 0xb9, 0x01, 0x8b, + 0x2c, 0x14, 0x38, 0x1b, 0xe0, 0x57, 0xb2, 0xab, 0x85, 0x0c, 0xe6, 0x1f, 0xd0, 0xbf, 0x70, 0x60, + 0xe9, 0x41, 0xe8, 0xa7, 0x4f, 0xbd, 0x20, 0x60, 0xa9, 0x9a, 0xd3, 0x0d, 0x58, 0x3c, 0x43, 0x00, + 0xe7, 0x74, 0x16, 0xc5, 0x03, 0x39, 0xa3, 0x05, 0x01, 0x1f, 0x48, 0xf4, 0xdc, 0x91, 0x55, 0xce, + 0x1d, 0x59, 0xe9, 0x72, 0xcd, 0x9c, 0xb3, 0x5c, 0x37, 0x60, 0x31, 0x66, 0xfd, 0xe8, 0x94, 0xc5, + 0xd3, 0xde, 0x99, 0x1f, 0x0e, 0xa2, 0xb3, 0x4e, 0xf5, 0x9a, 0x73, 0xb3, 0xe6, 0x2e, 0x28, 0xf8, + 0x29, 0xa2, 0x74, 0x05, 0x88, 0x39, 0x0b, 0xb1, 0x6e, 0x74, 0x08, 0xcb, 0x4f, 0xc2, 0x20, 0xea, + 0x3f, 0xfb, 0x01, 0x67, 0x57, 0xd2, 0x7d, 0xa5, 0xb4, 0xfb, 0x35, 0x58, 0xb1, 0x3b, 0x92, 0x03, + 0x60, 0xb0, 0xba, 0x7d, 0xe2, 0x85, 0x43, 0xa6, 0x9a, 0x54, 0x43, 0xf8, 0x04, 0xb4, 0xfb, 0x93, + 0x38, 0x66, 0x61, 0x61, 0x0c, 0x8b, 0x12, 0xd7, 0x83, 0x78, 0x1d, 0x5a, 0x21, 0x3b, 0xcb, 0xc8, + 0x24, 0xcb, 0x84, 0xec, 0x4c, 0x91, 0xd0, 0x0e, 0xac, 0xe5, 0xbb, 0x91, 0x03, 0xf8, 0x57, 0x07, + 0xaa, 0x4f, 0xd2, 0xe7, 0x11, 0xb9, 0x05, 0xd5, 0x74, 0x3a, 0x16, 0x8c, 0xb9, 0x70, 0x87, 0xdc, + 0x42, 0x5e, 0xbf, 0xb5, 0x35, 0x18, 0xc4, 0x2c, 0x49, 0x1e, 0x4f, 0xc7, 0xcc, 0x6d, 0x79, 0xa2, + 0xd0, 0xe3, 0x74, 0xa4, 0x03, 0x73, 0xb2, 0x8c, 0x1d, 0x36, 0x5c, 0x55, 0x24, 0x57, 0x01, 0xbc, + 0x51, 0x34, 0x09, 0xd3, 0x5e, 0xe2, 0xa5, 0xb8, 0x73, 0x33, 0xae, 0x81, 0x90, 0xeb, 0x30, 0x9f, + 0xf4, 0x63, 0x7f, 0x9c, 0xf6, 0xc6, 0x93, 0xa3, 0x67, 0x6c, 0x8a, 0x3b, 0xd6, 0x70, 0x6d, 0x90, + 0x6c, 0x42, 0x3d, 0x9a, 0xa4, 0xe3, 0xc8, 0x0f, 0xd3, 0x4e, 0xed, 0x9a, 0x73, 0xb3, 0x79, 0x67, + 0x59, 0x8e, 0x89, 0xcf, 0x24, 0x64, 0xc1, 0x01, 0xaf, 0x72, 0x35, 0x11, 0x6f, 0xb6, 0x1f, 0x85, + 0xc7, 0x7e, 0x3c, 0x12, 0xf2, 0xd8, 0x99, 0xc5, 0x9e, 0x6d, 0x90, 0x7e, 0xb3, 0x02, 0xcd, 0xc7, + 0xb1, 0x17, 0x26, 0x5e, 0x9f, 0x03, 0x7c, 0x1a, 0xe9, 0xf3, 0xde, 0x89, 0x97, 0x9c, 0xe0, 0xcc, + 0x1b, 0xae, 0x2a, 0x92, 0x35, 0x98, 0x15, 0x83, 0xc6, 0xf9, 0xcd, 0xb8, 0xb2, 0x44, 0xde, 0x84, + 0xa5, 0x70, 0x32, 0xea, 0xd9, 0x7d, 0xcd, 0xe0, 0xae, 0x17, 0x2b, 0xf8, 0x62, 0x1c, 0xf1, 0x7d, + 0x17, 0x5d, 0x88, 0x99, 0x1a, 0x08, 0xa1, 0xd0, 0x92, 0x25, 0xe6, 0x0f, 0x4f, 0xc4, 0x54, 0x6b, + 0xae, 0x85, 0xf1, 0x36, 0x52, 0x7f, 0xc4, 0x7a, 0x49, 0xea, 0x8d, 0xc6, 0x72, 0x5a, 0x06, 0x82, + 0xf5, 0x51, 0xea, 0x05, 0xbd, 0x63, 0xc6, 0x92, 0xce, 0x9c, 0xac, 0xd7, 0x08, 0x79, 0x03, 0x16, + 0x06, 0x2c, 0x49, 0x7b, 0x72, 0x83, 0x58, 0xd2, 0xa9, 0xa3, 0xf4, 0xe5, 0x50, 0xce, 0x25, 0xf7, + 0x59, 0x6a, 0xac, 0x4e, 0x22, 0xb9, 0x91, 0xee, 0x03, 0x31, 0xe0, 0x1d, 0x96, 0x7a, 0x7e, 0x90, + 0x90, 0xb7, 0xa1, 0x95, 0x1a, 0xc4, 0xa8, 0x6d, 0x9a, 0x9a, 0x75, 0x8c, 0x0f, 0x5c, 0x8b, 0x8e, + 0xde, 0x87, 0xfa, 0x3d, 0xc6, 0xf6, 0xfd, 0x91, 0x9f, 0x92, 0x35, 0xa8, 0x1d, 0xfb, 0xcf, 0x99, + 0x60, 0xee, 0x99, 0xbd, 0x4b, 0xae, 0x28, 0x92, 0x2e, 0xcc, 0x8d, 0x59, 0xdc, 0x67, 0x6a, 0xf9, + 0xf7, 0x2e, 0xb9, 0x0a, 0xb8, 0x3b, 0x07, 0xb5, 0x80, 0x7f, 0x4c, 0xbf, 0x5d, 0x81, 0xe6, 0x21, + 0x0b, 0xb5, 0xd0, 0x10, 0xa8, 0xf2, 0x29, 0x49, 0x41, 0xc1, 0xff, 0xc9, 0x6b, 0xd0, 0xc4, 0x69, + 0x26, 0x69, 0xec, 0x87, 0x43, 0xc9, 0xab, 0xc0, 0xa1, 0x43, 0x44, 0x48, 0x1b, 0x66, 0xbc, 0x91, + 0xe2, 0x53, 0xfe, 0x2f, 0x17, 0xa8, 0xb1, 0x37, 0x1d, 0x71, 0xd9, 0xd3, 0xbb, 0xd6, 0x72, 0x9b, + 0x12, 0xdb, 0xe3, 0xdb, 0x76, 0x0b, 0x96, 0x4d, 0x12, 0xd5, 0x7a, 0x0d, 0x5b, 0x5f, 0x32, 0x28, + 0x65, 0x27, 0x37, 0x60, 0x51, 0xd1, 0xc7, 0x62, 0xb0, 0xb8, 0x8f, 0x0d, 0x77, 0x41, 0xc2, 0x6a, + 0x0a, 0x37, 0xa1, 0x7d, 0xec, 0x87, 0x5e, 0xd0, 0xeb, 0x07, 0xe9, 0x69, 0x6f, 0xc0, 0x82, 0xd4, + 0xc3, 0x1d, 0xad, 0xb9, 0x0b, 0x88, 0x6f, 0x07, 0xe9, 0xe9, 0x0e, 0x47, 0xc9, 0x9b, 0xd0, 0x38, + 0x66, 0xac, 0x87, 0x2b, 0xd1, 0xa9, 0xa3, 0x84, 0x2c, 0xca, 0xa5, 0x57, 0xab, 0xeb, 0xd6, 0x8f, + 0xe5, 0x7f, 0xf4, 0x4f, 0x1c, 0x68, 0x89, 0xa5, 0x92, 0x26, 0xe3, 0x3a, 0xcc, 0xab, 0x11, 0xb1, + 0x38, 0x8e, 0x62, 0xc9, 0xfe, 0x36, 0x48, 0x36, 0xa0, 0xad, 0x80, 0x71, 0xcc, 0xfc, 0x91, 0x37, + 0x64, 0x52, 0xbf, 0x14, 0x70, 0x72, 0x27, 0x6b, 0x31, 0x8e, 0x26, 0xa9, 0x50, 0xda, 0xcd, 0x3b, + 0x2d, 0x39, 0x28, 0x97, 0x63, 0xae, 0x4d, 0xc2, 0xd9, 0xbf, 0x64, 0xa9, 0x2d, 0x8c, 0x7e, 0xc3, + 0x01, 0xc2, 0x87, 0xfe, 0x38, 0x12, 0x4d, 0xc8, 0x95, 0xca, 0xef, 0x92, 0xf3, 0xd2, 0xbb, 0x54, + 0x39, 0x6f, 0x97, 0xae, 0xc3, 0x2c, 0x0e, 0x8b, 0xcb, 0xf3, 0x4c, 0x61, 0xe8, 0xb2, 0x8e, 0x7e, + 0xcb, 0x81, 0x96, 0xa9, 0x83, 0xc8, 0x6d, 0x20, 0xc7, 0x93, 0x70, 0xe0, 0x87, 0xc3, 0x5e, 0xfa, + 0xdc, 0x1f, 0xf4, 0x8e, 0xa6, 0xbc, 0x09, 0x1c, 0xcf, 0xde, 0x25, 0xb7, 0xa4, 0x8e, 0xbc, 0x09, + 0x6d, 0x0b, 0x4d, 0xd2, 0x58, 0x8c, 0x6a, 0xef, 0x92, 0x5b, 0xa8, 0xe1, 0x8b, 0xc4, 0xb5, 0xdc, + 0x24, 0xed, 0xf9, 0xe1, 0x80, 0x3d, 0xc7, 0x75, 0x9d, 0x77, 0x2d, 0xec, 0xee, 0x02, 0xb4, 0xcc, + 0xef, 0xe8, 0x67, 0xa1, 0xbd, 0xcf, 0x95, 0x47, 0xe8, 0x87, 0x43, 0xa9, 0xc4, 0xb9, 0x46, 0x93, + 0x1a, 0x57, 0xec, 0xb5, 0x2c, 0x71, 0xb1, 0x39, 0x89, 0x92, 0x54, 0xae, 0x0b, 0xfe, 0x4f, 0xff, + 0xc1, 0x81, 0x45, 0xbe, 0xe8, 0xef, 0x7b, 0xe1, 0x54, 0xad, 0xf8, 0x3e, 0xb4, 0x78, 0x53, 0x8f, + 0xa3, 0x2d, 0xa1, 0x17, 0x85, 0xbc, 0xdf, 0x94, 0x8b, 0x94, 0xa3, 0xbe, 0x65, 0x92, 0x72, 0xd7, + 0x65, 0xea, 0x5a, 0x5f, 0x73, 0xc1, 0x4c, 0xbd, 0x78, 0xc8, 0x52, 0xd4, 0x98, 0x52, 0x83, 0x82, + 0x80, 0xb6, 0xa3, 0xf0, 0x98, 0x5c, 0x83, 0x56, 0xe2, 0xa5, 0xbd, 0x31, 0x8b, 0x71, 0xd5, 0x50, + 0xb8, 0x66, 0x5c, 0x48, 0xbc, 0xf4, 0x80, 0xc5, 0x77, 0xa7, 0x29, 0xeb, 0xfe, 0x24, 0x2c, 0x15, + 0x7a, 0xe1, 0xf2, 0x9c, 0x4d, 0x91, 0xff, 0x4b, 0x56, 0xa0, 0x76, 0xea, 0x05, 0x13, 0x26, 0x15, + 0xb9, 0x28, 0xbc, 0x5b, 0x79, 0xc7, 0xa1, 0x6f, 0x40, 0x3b, 0x1b, 0xb6, 0x14, 0x0c, 0x02, 0x55, + 0xbe, 0x82, 0xb2, 0x01, 0xfc, 0x9f, 0xfe, 0xae, 0x23, 0x08, 0xb7, 0x23, 0x5f, 0x2b, 0x45, 0x4e, + 0xc8, 0x75, 0xa7, 0x22, 0xe4, 0xff, 0x9f, 0x6b, 0x34, 0x7e, 0xf8, 0xc9, 0x92, 0xcb, 0x50, 0x4f, + 0x58, 0x38, 0xe8, 0x79, 0x41, 0x80, 0xba, 0xa3, 0xee, 0xce, 0xf1, 0xf2, 0x56, 0x10, 0xd0, 0x1b, + 0xb0, 0x64, 0x8c, 0xee, 0x05, 0xf3, 0x78, 0x08, 0x64, 0xdf, 0x4f, 0xd2, 0x27, 0x61, 0x32, 0x36, + 0x74, 0xce, 0x2b, 0xd0, 0x18, 0xf9, 0x21, 0x8e, 0x4c, 0xb0, 0x6d, 0xcd, 0xad, 0x8f, 0xfc, 0x90, + 0x8f, 0x2b, 0xc1, 0x4a, 0xef, 0xb9, 0xac, 0xac, 0xc8, 0x4a, 0xef, 0x39, 0x56, 0xd2, 0x77, 0x60, + 0xd9, 0x6a, 0x4f, 0x76, 0xfd, 0x3a, 0xd4, 0x26, 0xe9, 0xf3, 0x48, 0x59, 0x84, 0xa6, 0xe4, 0x10, + 0xee, 0x67, 0xb8, 0xa2, 0x86, 0xbe, 0x07, 0x4b, 0x0f, 0xd9, 0x99, 0xe4, 0x4c, 0x35, 0x90, 0x37, + 0x2e, 0xf4, 0x41, 0xb0, 0x9e, 0xde, 0x02, 0x62, 0x7e, 0x2c, 0x7b, 0x35, 0x3c, 0x12, 0xc7, 0xf2, + 0x48, 0xe8, 0x1b, 0x40, 0x0e, 0xfd, 0x61, 0xf8, 0x3e, 0x4b, 0x12, 0x6f, 0xa8, 0x15, 0x48, 0x1b, + 0x66, 0x46, 0xc9, 0x50, 0xea, 0x0d, 0xfe, 0x2f, 0xfd, 0x24, 0x2c, 0x5b, 0x74, 0xb2, 0xe1, 0x2b, + 0xd0, 0x48, 0xfc, 0x61, 0xe8, 0xa5, 0x93, 0x98, 0xc9, 0xa6, 0x33, 0x80, 0xde, 0x83, 0x95, 0x2f, + 0xb2, 0xd8, 0x3f, 0x9e, 0x5e, 0xd4, 0xbc, 0xdd, 0x4e, 0x25, 0xdf, 0xce, 0x2e, 0xac, 0xe6, 0xda, + 0x91, 0xdd, 0x0b, 0xf6, 0x95, 0x3b, 0x59, 0x77, 0x45, 0xc1, 0x10, 0xe6, 0x8a, 0x29, 0xcc, 0xf4, + 0x09, 0x90, 0xed, 0x28, 0x0c, 0x59, 0x3f, 0x3d, 0x60, 0x2c, 0xce, 0xce, 0x20, 0x19, 0xaf, 0x36, + 0xef, 0xac, 0xcb, 0x95, 0xcd, 0x6b, 0x08, 0xc9, 0xc4, 0x04, 0xaa, 0x63, 0x16, 0x8f, 0xb0, 0xe1, + 0xba, 0x8b, 0xff, 0xd3, 0x55, 0x58, 0xb6, 0x9a, 0x95, 0xee, 0xe3, 0x5b, 0xb0, 0xba, 0xe3, 0x27, + 0xfd, 0x62, 0x87, 0x1d, 0x98, 0x1b, 0x4f, 0x8e, 0x7a, 0x99, 0x24, 0xaa, 0x22, 0xf7, 0x32, 0xf2, + 0x9f, 0xc8, 0xc6, 0x7e, 0xd9, 0x81, 0xea, 0xde, 0xe3, 0xfd, 0x6d, 0xd2, 0x85, 0xba, 0x1f, 0xf6, + 0xa3, 0x11, 0x57, 0xd6, 0x62, 0xd2, 0xba, 0x7c, 0xae, 0x84, 0x5d, 0x81, 0x06, 0xea, 0x78, 0xee, + 0x38, 0xc9, 0xe3, 0x42, 0x06, 0x70, 0xa7, 0x8d, 0x3d, 0x1f, 0xfb, 0x31, 0x7a, 0x65, 0xca, 0xd7, + 0xaa, 0xa2, 0x1e, 0x2d, 0x56, 0xd0, 0xff, 0xae, 0xc2, 0x9c, 0xd4, 0xf0, 0xd8, 0x5f, 0x3f, 0xf5, + 0x4f, 0x99, 0x1c, 0x89, 0x2c, 0x71, 0xfb, 0x19, 0xb3, 0x51, 0x94, 0xb2, 0x9e, 0xb5, 0x0d, 0x36, + 0x88, 0x4e, 0xa9, 0x68, 0xa8, 0x27, 0x5c, 0xd9, 0x19, 0x41, 0x65, 0x81, 0x7c, 0xb1, 0x38, 0xd0, + 0xf3, 0x07, 0x38, 0xa6, 0xaa, 0xab, 0x8a, 0x7c, 0x25, 0xfa, 0xde, 0xd8, 0xeb, 0xfb, 0xe9, 0x54, + 0xaa, 0x04, 0x5d, 0xe6, 0x6d, 0x07, 0x51, 0xdf, 0x0b, 0x7a, 0x47, 0x5e, 0xe0, 0x85, 0x7d, 0xa6, + 0x1c, 0x5e, 0x0b, 0xe4, 0xce, 0x9f, 0x1c, 0x92, 0x22, 0x13, 0x0e, 0x62, 0x0e, 0xe5, 0x4e, 0x64, + 0x3f, 0x1a, 0x8d, 0xfc, 0x94, 0xfb, 0x8c, 0xe8, 0x4f, 0xcc, 0xb8, 0x06, 0x22, 0xdc, 0x6b, 0x2c, + 0x9d, 0x89, 0xd5, 0x6b, 0x28, 0xf7, 0xda, 0x00, 0x79, 0x2b, 0xdc, 0x29, 0xe1, 0x6a, 0xec, 0xd9, + 0x59, 0x07, 0x44, 0x2b, 0x19, 0xc2, 0xf7, 0x61, 0x12, 0x26, 0x2c, 0x4d, 0x03, 0x36, 0xd0, 0x03, + 0x6a, 0x22, 0x59, 0xb1, 0x82, 0xdc, 0x86, 0x65, 0xe1, 0xc6, 0x26, 0x5e, 0x1a, 0x25, 0x27, 0x7e, + 0xd2, 0x4b, 0xb8, 0x43, 0xd8, 0x42, 0xfa, 0xb2, 0x2a, 0xf2, 0x0e, 0xac, 0xe7, 0xe0, 0x98, 0xf5, + 0x99, 0x7f, 0xca, 0x06, 0x9d, 0x79, 0xfc, 0xea, 0xbc, 0x6a, 0x72, 0x0d, 0x9a, 0xdc, 0x7b, 0x9f, + 0x8c, 0x07, 0x1e, 0xb7, 0xde, 0x0b, 0xb8, 0x0f, 0x26, 0x44, 0xde, 0x82, 0xf9, 0x31, 0x13, 0x26, + 0xf6, 0x24, 0x0d, 0xfa, 0x49, 0x67, 0xd1, 0xd2, 0x6e, 0x9c, 0x73, 0x5d, 0x9b, 0x82, 0x33, 0x65, + 0x3f, 0x41, 0x37, 0xce, 0x9b, 0x76, 0xda, 0xc8, 0x6e, 0x19, 0x80, 0x32, 0x12, 0xfb, 0xa7, 0x5e, + 0xca, 0x3a, 0x4b, 0x42, 0xa1, 0xcb, 0x22, 0xfd, 0x7d, 0x47, 0x28, 0x56, 0xc9, 0x84, 0x5a, 0x41, + 0xbe, 0x06, 0x4d, 0xc1, 0x7e, 0xbd, 0x28, 0x0c, 0xa6, 0x92, 0x23, 0x41, 0x40, 0x8f, 0xc2, 0x60, + 0x4a, 0x3e, 0x06, 0xf3, 0x7e, 0x68, 0x92, 0x08, 0x19, 0x6e, 0x29, 0x10, 0x89, 0x5e, 0x83, 0xe6, + 0x78, 0x72, 0x14, 0xf8, 0x7d, 0x41, 0x32, 0x23, 0x5a, 0x11, 0x10, 0x12, 0x70, 0xd7, 0x4a, 0x8c, + 0x44, 0x50, 0x54, 0x91, 0xa2, 0x29, 0x31, 0x4e, 0x42, 0xef, 0xc2, 0x8a, 0x3d, 0x40, 0xa9, 0xac, + 0x36, 0xa0, 0x2e, 0x79, 0x3b, 0xe9, 0x34, 0x71, 0x7d, 0x16, 0xec, 0x63, 0x9b, 0xab, 0xeb, 0xe9, + 0x77, 0xab, 0xb0, 0x2c, 0xd1, 0xed, 0x20, 0x4a, 0xd8, 0xe1, 0x64, 0x34, 0xf2, 0xe2, 0x12, 0xa1, + 0x71, 0x2e, 0x10, 0x9a, 0x8a, 0x2d, 0x34, 0x9c, 0x95, 0x4f, 0x3c, 0x3f, 0x14, 0x7e, 0xa1, 0x90, + 0x38, 0x03, 0x21, 0x37, 0x61, 0xb1, 0x1f, 0x44, 0x89, 0xf0, 0x95, 0xcc, 0x83, 0x59, 0x1e, 0x2e, + 0x0a, 0x79, 0xad, 0x4c, 0xc8, 0x4d, 0x21, 0x9d, 0xcd, 0x09, 0x29, 0x85, 0x16, 0x6f, 0x94, 0x29, + 0x9d, 0x33, 0x27, 0x7c, 0x37, 0x13, 0xe3, 0xe3, 0xc9, 0x8b, 0x84, 0x90, 0xbf, 0xc5, 0x32, 0x81, + 0xe0, 0xe7, 0x3e, 0xae, 0xd3, 0x0c, 0xea, 0x86, 0x14, 0x88, 0x62, 0x15, 0xb9, 0x07, 0x20, 0xfa, + 0x42, 0xc3, 0x0a, 0x68, 0x58, 0xdf, 0xb0, 0x77, 0xc4, 0x5c, 0xfb, 0x5b, 0xbc, 0x30, 0x89, 0x19, + 0x1a, 0x5b, 0xe3, 0x4b, 0xfa, 0xab, 0x0e, 0x34, 0x8d, 0x3a, 0xb2, 0x0a, 0x4b, 0xdb, 0x8f, 0x1e, + 0x1d, 0xec, 0xba, 0x5b, 0x8f, 0x1f, 0x7c, 0x71, 0xb7, 0xb7, 0xbd, 0xff, 0xe8, 0x70, 0xb7, 0x7d, + 0x89, 0xc3, 0xfb, 0x8f, 0xb6, 0xb7, 0xf6, 0x7b, 0xf7, 0x1e, 0xb9, 0xdb, 0x0a, 0x76, 0xc8, 0x1a, + 0x10, 0x77, 0xf7, 0xfd, 0x47, 0x8f, 0x77, 0x2d, 0xbc, 0x42, 0xda, 0xd0, 0xba, 0xeb, 0xee, 0x6e, + 0x6d, 0xef, 0x49, 0x64, 0x86, 0xac, 0x40, 0xfb, 0xde, 0x93, 0x87, 0x3b, 0x0f, 0x1e, 0xde, 0xef, + 0x6d, 0x6f, 0x3d, 0xdc, 0xde, 0xdd, 0xdf, 0xdd, 0x69, 0x57, 0xc9, 0x3c, 0x34, 0xb6, 0xee, 0x6e, + 0x3d, 0xdc, 0x79, 0xf4, 0x70, 0x77, 0xa7, 0x5d, 0xa3, 0x7f, 0xef, 0xc0, 0x2a, 0x8e, 0x7a, 0x90, + 0x17, 0x90, 0x6b, 0xd0, 0xec, 0x47, 0xd1, 0x98, 0x71, 0x7d, 0xae, 0x55, 0xb6, 0x09, 0x71, 0xe6, + 0x17, 0x0a, 0xf2, 0x38, 0x8a, 0xfb, 0x4c, 0xca, 0x07, 0x20, 0x74, 0x8f, 0x23, 0x9c, 0xf9, 0xe5, + 0xf6, 0x0a, 0x0a, 0x21, 0x1e, 0x4d, 0x81, 0x09, 0x92, 0x35, 0x98, 0x3d, 0x8a, 0x99, 0xd7, 0x3f, + 0x91, 0x92, 0x21, 0x4b, 0xe4, 0x13, 0x99, 0x5b, 0xdf, 0xe7, 0xab, 0x1f, 0xb0, 0x01, 0x72, 0x4c, + 0xdd, 0x5d, 0x94, 0xf8, 0xb6, 0x84, 0xb9, 0x66, 0xf0, 0x8e, 0xbc, 0x70, 0x10, 0x85, 0x6c, 0x20, + 0xdd, 0xb9, 0x0c, 0xa0, 0x07, 0xb0, 0x96, 0x9f, 0x9f, 0x94, 0xaf, 0xb7, 0x0d, 0xf9, 0x12, 0xde, + 0x55, 0xf7, 0xfc, 0xdd, 0x34, 0x64, 0xed, 0x9f, 0x1d, 0xa8, 0x72, 0x63, 0x7b, 0xbe, 0x61, 0x36, + 0xfd, 0xa7, 0x99, 0x42, 0x44, 0x07, 0xcf, 0x2d, 0x42, 0xfd, 0x0a, 0x13, 0x65, 0x20, 0x59, 0x7d, + 0xcc, 0xfa, 0xa7, 0x38, 0x63, 0x5d, 0xcf, 0x11, 0x2e, 0x20, 0xdc, 0xb9, 0xc5, 0xaf, 0xa5, 0x80, + 0xa8, 0xb2, 0xaa, 0xc3, 0x2f, 0xe7, 0xb2, 0x3a, 0xfc, 0xae, 0x03, 0x73, 0x7e, 0x78, 0x14, 0x4d, + 0xc2, 0x01, 0x0a, 0x44, 0xdd, 0x55, 0x45, 0xbe, 0x7c, 0x63, 0x14, 0x54, 0x7f, 0xa4, 0xd8, 0x3f, + 0x03, 0x28, 0xe1, 0x87, 0x9f, 0x04, 0x9d, 0x0b, 0x1d, 0xc2, 0x78, 0x1b, 0x96, 0x0c, 0x2c, 0x73, + 0x54, 0xc7, 0x1c, 0xc8, 0x39, 0xaa, 0xe8, 0x95, 0x88, 0x1a, 0xda, 0x86, 0x85, 0xfb, 0x2c, 0x7d, + 0x10, 0x1e, 0x47, 0xaa, 0xa5, 0x3f, 0xaa, 0xc2, 0xa2, 0x86, 0x64, 0x43, 0x37, 0x61, 0xd1, 0x1f, + 0xb0, 0x30, 0xf5, 0xd3, 0x69, 0xcf, 0x3a, 0x63, 0xe5, 0x61, 0xee, 0xcd, 0x79, 0x81, 0xef, 0xa9, + 0xa8, 0x99, 0x28, 0x90, 0x3b, 0xb0, 0xc2, 0x4d, 0x8d, 0xb2, 0x1e, 0x7a, 0x8b, 0xc5, 0x51, 0xaf, + 0xb4, 0x8e, 0x2b, 0x03, 0x8e, 0x4b, 0x6d, 0xaf, 0x3f, 0x11, 0x5e, 0x4d, 0x59, 0x15, 0x5f, 0x35, + 0xd1, 0x12, 0x9f, 0x72, 0x4d, 0x98, 0x23, 0x0d, 0x14, 0x42, 0x51, 0xb3, 0x42, 0x55, 0xe5, 0x43, + 0x51, 0x46, 0x38, 0xab, 0x5e, 0x08, 0x67, 0x71, 0x55, 0x36, 0x0d, 0xfb, 0x6c, 0xd0, 0x4b, 0xa3, + 0x1e, 0xaa, 0x5c, 0xdc, 0x9d, 0xba, 0x9b, 0x87, 0xc9, 0x15, 0x98, 0x4b, 0x59, 0x92, 0x86, 0x2c, + 0x45, 0xad, 0x54, 0xbf, 0x5b, 0xe9, 0x38, 0xae, 0x82, 0xb8, 0x0b, 0x3a, 0x89, 0xfd, 0xa4, 0xd3, + 0xc2, 0x40, 0x15, 0xfe, 0x4f, 0x3e, 0x05, 0xab, 0x47, 0x2c, 0x49, 0x7b, 0x27, 0xcc, 0x1b, 0xb0, + 0x18, 0x77, 0x5a, 0x44, 0xc4, 0x84, 0x65, 0x2f, 0xaf, 0xe4, 0x3c, 0x74, 0xca, 0xe2, 0xc4, 0x8f, + 0x42, 0xb4, 0xe9, 0x0d, 0x57, 0x15, 0x79, 0x7b, 0x7c, 0xf2, 0xda, 0x5e, 0xea, 0x15, 0x5c, 0xc4, + 0x89, 0x97, 0x57, 0x92, 0xeb, 0x30, 0x8b, 0x13, 0x48, 0x3a, 0x6d, 0x2b, 0x46, 0xb0, 0xcd, 0x41, + 0x57, 0xd6, 0x7d, 0xae, 0x5a, 0x6f, 0xb6, 0x5b, 0xf4, 0xc7, 0xa0, 0x86, 0x30, 0xdf, 0x74, 0xb1, + 0x18, 0x82, 0x29, 0x44, 0x81, 0x0f, 0x2d, 0x64, 0xe9, 0x59, 0x14, 0x3f, 0x53, 0x21, 0x54, 0x59, + 0xa4, 0x5f, 0x47, 0x27, 0x5e, 0x87, 0x11, 0x9f, 0xa0, 0x07, 0xc2, 0x8f, 0x62, 0x62, 0xa9, 0x93, + 0x13, 0x4f, 0x9e, 0x2b, 0xea, 0x08, 0x1c, 0x9e, 0x78, 0x5c, 0x6d, 0x59, 0xbb, 0x27, 0x8e, 0x6a, + 0x4d, 0xc4, 0xf6, 0xc4, 0xe6, 0x5d, 0x87, 0x05, 0x15, 0xa0, 0x4c, 0x7a, 0x01, 0x3b, 0x4e, 0x55, + 0x24, 0x21, 0x9c, 0x8c, 0xf0, 0x3c, 0xb7, 0xcf, 0x8e, 0x53, 0xfa, 0x10, 0x96, 0xa4, 0x2a, 0x79, + 0x34, 0x66, 0xaa, 0xeb, 0xcf, 0x94, 0x99, 0xe4, 0x73, 0x42, 0xb2, 0x36, 0x25, 0x75, 0x81, 0x98, + 0xaa, 0x49, 0x36, 0x28, 0xed, 0xa2, 0x8a, 0x57, 0xc8, 0xe9, 0x58, 0x18, 0x5f, 0x9f, 0x64, 0xd2, + 0xef, 0xab, 0x10, 0x33, 0x3f, 0xf0, 0x8a, 0x22, 0xfd, 0xb6, 0x03, 0xcb, 0xd8, 0x9a, 0x72, 0x2a, + 0xa4, 0xfa, 0x7f, 0xe7, 0xfb, 0x18, 0x66, 0xab, 0x6f, 0xc6, 0x70, 0x56, 0xa0, 0x66, 0x1a, 0x04, + 0x51, 0xf8, 0xfe, 0x8f, 0xed, 0xd5, 0xfc, 0xb1, 0x9d, 0xfe, 0xb6, 0x03, 0x4b, 0x42, 0x27, 0xa7, + 0x5e, 0x3a, 0x49, 0xe4, 0xf4, 0x7f, 0x1c, 0xe6, 0x85, 0x71, 0x95, 0x52, 0x2d, 0x07, 0xba, 0xa2, + 0x15, 0x10, 0xa2, 0x82, 0x78, 0xef, 0x92, 0x6b, 0x13, 0x93, 0xf7, 0xd0, 0xc1, 0x09, 0x7b, 0x88, + 0xca, 0x30, 0xdb, 0xe5, 0x12, 0x33, 0xa0, 0xbf, 0x37, 0xc8, 0xef, 0xd6, 0x61, 0x56, 0x78, 0xb4, + 0xf4, 0x3e, 0xcc, 0x5b, 0x1d, 0x59, 0x21, 0x83, 0x96, 0x08, 0x19, 0x14, 0x82, 0x4f, 0x95, 0x62, + 0xf0, 0x89, 0xfe, 0xf1, 0x0c, 0x10, 0xce, 0x2c, 0xb9, 0xdd, 0xe0, 0x2e, 0x75, 0x34, 0xb0, 0x0e, + 0x48, 0x2d, 0xd7, 0x84, 0xc8, 0x2d, 0x20, 0x46, 0x51, 0xc5, 0xe7, 0x84, 0xf5, 0x29, 0xa9, 0xe1, + 0x6a, 0x52, 0x1a, 0x6f, 0x69, 0x66, 0xe5, 0x51, 0x50, 0x2c, 0x7b, 0x69, 0x1d, 0x37, 0x30, 0xe3, + 0x49, 0x72, 0x82, 0x97, 0x11, 0xf2, 0x08, 0xa5, 0xca, 0xf9, 0xfd, 0x9d, 0xbd, 0x70, 0x7f, 0xe7, + 0x0a, 0x61, 0x19, 0xc3, 0x89, 0xaf, 0x5b, 0x4e, 0x3c, 0x77, 0x1e, 0x47, 0xdc, 0xe5, 0x4c, 0x83, + 0x7e, 0x6f, 0xc4, 0x7b, 0x97, 0x27, 0x26, 0x0b, 0x24, 0x1b, 0xd0, 0x96, 0xee, 0x46, 0x76, 0x52, + 0x00, 0x5c, 0xe3, 0x02, 0xce, 0xf5, 0x77, 0x16, 0xa8, 0x69, 0xe2, 0x60, 0x33, 0x80, 0x9f, 0xad, + 0x12, 0xce, 0x21, 0xbd, 0x49, 0x28, 0xef, 0x20, 0xd8, 0x00, 0xcf, 0x4a, 0x75, 0xb7, 0x58, 0x41, + 0x7f, 0xd3, 0x81, 0x36, 0xdf, 0x33, 0x8b, 0x2d, 0xdf, 0x05, 0x94, 0x8a, 0x97, 0xe4, 0x4a, 0x8b, + 0x96, 0xbc, 0x03, 0x0d, 0x2c, 0x47, 0x63, 0x16, 0x4a, 0x9e, 0xec, 0xd8, 0x3c, 0x99, 0xe9, 0x93, + 0xbd, 0x4b, 0x6e, 0x46, 0x6c, 0x70, 0xe4, 0xdf, 0x38, 0xd0, 0x94, 0xbd, 0xfc, 0xc0, 0x81, 0x80, + 0xae, 0x71, 0x71, 0x24, 0x38, 0x29, 0xbb, 0x23, 0xba, 0x09, 0x8b, 0x23, 0x2f, 0x9d, 0xc4, 0xdc, + 0x1e, 0x5b, 0x41, 0x80, 0x3c, 0xcc, 0x8d, 0x2b, 0xaa, 0xce, 0xa4, 0x97, 0xfa, 0x41, 0x4f, 0xd5, + 0xca, 0xeb, 0x99, 0xb2, 0x2a, 0xae, 0x41, 0x92, 0xd4, 0x1b, 0x32, 0x69, 0x37, 0x45, 0x81, 0x76, + 0x60, 0x4d, 0x4e, 0x28, 0xe7, 0xaa, 0xd2, 0x3f, 0x6f, 0xc1, 0x7a, 0xa1, 0x4a, 0xdf, 0xe7, 0xca, + 0xd3, 0x6d, 0xe0, 0x8f, 0x8e, 0x22, 0xed, 0xe7, 0x3b, 0xe6, 0xc1, 0xd7, 0xaa, 0x22, 0x43, 0x58, + 0x55, 0x0e, 0x02, 0x5f, 0xd3, 0xcc, 0x98, 0x55, 0xd0, 0x4a, 0xbd, 0x65, 0x6f, 0x61, 0xbe, 0x43, + 0x85, 0x9b, 0x42, 0x5c, 0xde, 0x1e, 0x39, 0x81, 0x8e, 0xf6, 0x44, 0xa4, 0xb2, 0x36, 0xbc, 0x15, + 0xde, 0xd7, 0x9b, 0x17, 0xf4, 0x65, 0x79, 0xb6, 0xee, 0xb9, 0xad, 0x91, 0x29, 0x5c, 0x55, 0x75, + 0xa8, 0x8d, 0x8b, 0xfd, 0x55, 0x5f, 0x6a, 0x6e, 0xe8, 0xb3, 0xdb, 0x9d, 0x5e, 0xd0, 0x30, 0xf9, + 0x2a, 0xac, 0x9d, 0x79, 0x7e, 0xaa, 0x86, 0x65, 0xf8, 0x06, 0x35, 0xec, 0xf2, 0xce, 0x05, 0x5d, + 0x3e, 0x15, 0x1f, 0x5b, 0x26, 0xea, 0x9c, 0x16, 0xbb, 0x7f, 0xe5, 0xc0, 0x82, 0xdd, 0x0e, 0x67, + 0x53, 0x29, 0xfb, 0x4a, 0x07, 0x2a, 0x6f, 0x32, 0x07, 0x17, 0x8f, 0xca, 0x95, 0xb2, 0xa3, 0xb2, + 0x79, 0x40, 0x9d, 0xb9, 0x28, 0x8a, 0x54, 0x7d, 0xb9, 0x28, 0x52, 0xad, 0x2c, 0x8a, 0xd4, 0xfd, + 0x0f, 0x07, 0x48, 0x91, 0x97, 0xc8, 0x7d, 0x71, 0x56, 0x0f, 0x59, 0x20, 0x55, 0xca, 0xff, 0x7f, + 0x39, 0x7e, 0x54, 0x6b, 0xa7, 0xbe, 0xe6, 0x82, 0x61, 0xde, 0xaf, 0x9a, 0xce, 0xce, 0xbc, 0x5b, + 0x56, 0x95, 0x8b, 0x6b, 0x55, 0x2f, 0x8e, 0x6b, 0xd5, 0x2e, 0x8e, 0x6b, 0xcd, 0xe6, 0xe3, 0x5a, + 0xdd, 0x5f, 0x72, 0x60, 0xb9, 0x64, 0xd3, 0x7f, 0x74, 0x13, 0xe7, 0xdb, 0x64, 0xe9, 0x82, 0x8a, + 0xdc, 0x26, 0x13, 0xec, 0xfe, 0x1c, 0xcc, 0x5b, 0x8c, 0xfe, 0xa3, 0xeb, 0x3f, 0xef, 0xaf, 0x09, + 0x3e, 0xb3, 0xb0, 0xee, 0xbf, 0x54, 0x80, 0x14, 0x85, 0xed, 0xff, 0x74, 0x0c, 0xc5, 0x75, 0x9a, + 0x29, 0x59, 0xa7, 0xff, 0x55, 0x3b, 0xf0, 0x26, 0x2c, 0xc9, 0xe4, 0x0f, 0x23, 0x42, 0x23, 0x38, + 0xa6, 0x58, 0xc1, 0x3d, 0x56, 0x3b, 0xa8, 0x58, 0xb7, 0x2e, 0xd1, 0x0d, 0x63, 0x98, 0x8b, 0x2d, + 0xd2, 0x35, 0x58, 0x11, 0xc9, 0x24, 0x77, 0x45, 0x53, 0xca, 0xae, 0xfc, 0x9e, 0x03, 0xab, 0xb9, + 0x8a, 0xec, 0xca, 0x57, 0x98, 0x0e, 0xdb, 0x9e, 0xd8, 0x20, 0x1f, 0xbf, 0xf6, 0x12, 0x72, 0xdc, + 0x56, 0xac, 0xe0, 0xeb, 0x63, 0x78, 0x15, 0xb9, 0x55, 0x2f, 0xab, 0xa2, 0xeb, 0x22, 0xe5, 0x25, + 0x64, 0x41, 0x6e, 0xe0, 0xc7, 0x22, 0x49, 0xc5, 0xac, 0xc8, 0x6e, 0x76, 0xec, 0x21, 0xab, 0x22, + 0x77, 0x08, 0x2d, 0x33, 0x65, 0x8f, 0xb7, 0xb4, 0x8e, 0x7e, 0xd7, 0x01, 0xf2, 0x85, 0x09, 0x8b, + 0xa7, 0x78, 0xad, 0xab, 0x43, 0x47, 0xeb, 0xf9, 0xc0, 0xc8, 0xec, 0x78, 0x72, 0xf4, 0x79, 0x36, + 0x55, 0x09, 0x02, 0x95, 0x2c, 0x41, 0xe0, 0x55, 0x00, 0x7e, 0x90, 0xd2, 0x77, 0xc5, 0xe8, 0x88, + 0x85, 0x93, 0x91, 0x68, 0xb0, 0xf4, 0x0e, 0xbf, 0x7a, 0xf1, 0x1d, 0x7e, 0xed, 0xa2, 0x3b, 0xfc, + 0xf7, 0x60, 0xd9, 0x1a, 0xb7, 0xde, 0x56, 0x75, 0x6b, 0xed, 0xbc, 0xe0, 0xd6, 0xfa, 0x57, 0x2a, + 0x30, 0xb3, 0x17, 0x8d, 0xcd, 0xb0, 0xa9, 0x63, 0x87, 0x4d, 0xa5, 0x2d, 0xe9, 0x69, 0x53, 0x21, + 0x55, 0x8c, 0x05, 0x92, 0x0d, 0x58, 0xf0, 0x46, 0x29, 0x3f, 0xc7, 0x1f, 0x47, 0xf1, 0x99, 0x17, + 0x0f, 0xc4, 0x5e, 0xe3, 0xf1, 0x3d, 0x57, 0x43, 0x56, 0x60, 0x46, 0x2b, 0x5d, 0x24, 0xe0, 0x45, + 0xee, 0xb8, 0xe1, 0x95, 0xcb, 0x54, 0x86, 0x20, 0x64, 0x89, 0xb3, 0x92, 0xfd, 0xbd, 0xf0, 0x9a, + 0x85, 0xe8, 0x94, 0x55, 0x71, 0xbb, 0xc6, 0x97, 0x0f, 0xc9, 0x64, 0xec, 0x48, 0x95, 0xcd, 0x38, + 0x57, 0xdd, 0xbe, 0x80, 0xfa, 0x27, 0x07, 0x6a, 0xb8, 0x36, 0x5c, 0x0d, 0x08, 0xde, 0xd7, 0x91, + 0x53, 0x5c, 0x93, 0x79, 0x37, 0x0f, 0x13, 0x6a, 0xa5, 0xd8, 0x54, 0xf4, 0x84, 0xcc, 0x34, 0x9b, + 0x6b, 0xd0, 0x10, 0x25, 0x9d, 0x4e, 0x82, 0x24, 0x19, 0x48, 0xae, 0x42, 0xf5, 0x24, 0x1a, 0x2b, + 0xbf, 0x05, 0xd4, 0xc5, 0x41, 0x34, 0x76, 0x11, 0xcf, 0xc6, 0xc3, 0xdb, 0x13, 0xd3, 0x12, 0xd6, + 0x28, 0x0f, 0x73, 0x7b, 0xac, 0x9b, 0x35, 0x97, 0x29, 0x87, 0xd2, 0x0d, 0x58, 0x7c, 0x18, 0x0d, + 0x98, 0x11, 0xbe, 0x3a, 0x97, 0xcf, 0xe9, 0xcf, 0x3b, 0x50, 0x57, 0xc4, 0xe4, 0x26, 0x54, 0xb9, + 0x93, 0x91, 0x3b, 0x01, 0xe8, 0x0b, 0x43, 0x4e, 0xe7, 0x22, 0x05, 0xd7, 0xca, 0x18, 0x55, 0xc8, + 0x1c, 0x4e, 0x15, 0x53, 0xc8, 0xfc, 0x29, 0x3d, 0xdc, 0x9c, 0x1b, 0x92, 0x43, 0xe9, 0x77, 0x1c, + 0x98, 0xb7, 0xfa, 0xe0, 0x67, 0xc8, 0xc0, 0x4b, 0x52, 0x79, 0x09, 0x23, 0xb7, 0xc7, 0x84, 0xcc, + 0x8d, 0xae, 0xd8, 0x01, 0x4d, 0x1d, 0x6a, 0x9b, 0x31, 0x43, 0x6d, 0xb7, 0xa1, 0x91, 0x25, 0x42, + 0x55, 0x2d, 0x6d, 0xcb, 0x7b, 0x54, 0x57, 0xa1, 0x19, 0x11, 0x46, 0x6f, 0xa2, 0x20, 0x8a, 0x65, + 0xf4, 0x5f, 0x14, 0xe8, 0x7b, 0xd0, 0x34, 0xe8, 0xcd, 0x60, 0x8e, 0x63, 0x05, 0x73, 0x74, 0x9e, + 0x40, 0x25, 0xcb, 0x13, 0xa0, 0x7f, 0xe9, 0xc0, 0x3c, 0xe7, 0x41, 0x3f, 0x1c, 0x1e, 0x44, 0x81, + 0xdf, 0x9f, 0xe2, 0xde, 0x2b, 0x76, 0x93, 0x3a, 0x43, 0xf1, 0xa2, 0x0d, 0x73, 0xae, 0x57, 0x47, + 0x48, 0x29, 0xa2, 0xba, 0xcc, 0x65, 0x98, 0x4b, 0xc0, 0x91, 0x97, 0x48, 0xb1, 0x90, 0xe6, 0xcf, + 0x02, 0xb9, 0xa4, 0x71, 0x20, 0xf6, 0x52, 0xd6, 0x1b, 0xf9, 0x41, 0xe0, 0x0b, 0x5a, 0xe1, 0x1c, + 0x95, 0x55, 0xf1, 0x3e, 0x07, 0x7e, 0xe2, 0x1d, 0x65, 0x11, 0x6d, 0x5d, 0xa6, 0x7f, 0x5a, 0x81, + 0xa6, 0x54, 0xdc, 0xbb, 0x83, 0x21, 0x93, 0xd7, 0x2f, 0xe8, 0x7e, 0x6a, 0x25, 0x63, 0x20, 0xaa, + 0xde, 0x72, 0x58, 0x0d, 0x24, 0xbf, 0xe5, 0x33, 0xc5, 0x2d, 0xbf, 0x02, 0x0d, 0xce, 0x7a, 0x6f, + 0xa1, 0x67, 0x2c, 0xae, 0x6e, 0x32, 0x40, 0xd5, 0xde, 0xc1, 0xda, 0x5a, 0x56, 0x8b, 0xc0, 0x0b, + 0x2f, 0x6b, 0xde, 0x81, 0x96, 0x6c, 0x06, 0xf7, 0x04, 0x75, 0x4a, 0xc6, 0xfc, 0xd6, 0x7e, 0xb9, + 0x16, 0xa5, 0xfa, 0xf2, 0x8e, 0xfa, 0xb2, 0x7e, 0xd1, 0x97, 0x8a, 0x92, 0xde, 0xd7, 0x77, 0x60, + 0xf7, 0x63, 0x6f, 0x7c, 0xa2, 0xa4, 0xf4, 0x36, 0x2c, 0xfb, 0x61, 0x3f, 0x98, 0x0c, 0x58, 0x6f, + 0x12, 0x7a, 0x61, 0x18, 0x4d, 0xc2, 0x3e, 0x53, 0x29, 0x00, 0x65, 0x55, 0x74, 0xa0, 0xb3, 0x92, + 0xb0, 0x21, 0xb2, 0x01, 0x35, 0xde, 0x91, 0xb2, 0x0a, 0xe5, 0x22, 0x2c, 0x48, 0xc8, 0x4d, 0xa8, + 0xb1, 0xc1, 0x90, 0xa9, 0xd3, 0x22, 0xb1, 0xcf, 0xed, 0x7c, 0x57, 0x5d, 0x41, 0xc0, 0x15, 0x0a, + 0x47, 0x73, 0x0a, 0xc5, 0xb6, 0x28, 0xb3, 0xbc, 0xf8, 0x60, 0x40, 0x57, 0x80, 0x3c, 0x14, 0x32, + 0x60, 0x86, 0xcf, 0x7f, 0x71, 0x06, 0x9a, 0x06, 0xcc, 0x75, 0xc3, 0x90, 0x0f, 0xb8, 0x37, 0xf0, + 0xbd, 0x11, 0x4b, 0x59, 0x2c, 0xf9, 0x3e, 0x87, 0x72, 0x3a, 0xef, 0x74, 0xd8, 0x8b, 0x26, 0x69, + 0x6f, 0xc0, 0x86, 0x31, 0x13, 0x46, 0x9e, 0x1b, 0x1d, 0x0b, 0xe5, 0x74, 0x23, 0xef, 0xb9, 0x49, + 0x27, 0x38, 0x28, 0x87, 0xaa, 0x60, 0xb8, 0x58, 0xa3, 0x6a, 0x16, 0x0c, 0x17, 0x2b, 0x92, 0xd7, + 0x6a, 0xb5, 0x12, 0xad, 0xf6, 0x36, 0xac, 0x09, 0xfd, 0x25, 0x25, 0xbd, 0x97, 0x63, 0xac, 0x73, + 0x6a, 0xc9, 0x06, 0xb4, 0xf9, 0x98, 0x95, 0x48, 0x24, 0xfe, 0xd7, 0x45, 0x60, 0xc9, 0x71, 0x0b, + 0x38, 0xa7, 0xc5, 0x08, 0x8f, 0x49, 0x2b, 0x2e, 0x07, 0x0b, 0x38, 0xd2, 0x7a, 0xcf, 0x6d, 0xda, + 0x86, 0xa4, 0xcd, 0xe1, 0x74, 0x1e, 0x9a, 0x87, 0x69, 0x34, 0x56, 0x9b, 0xb2, 0x00, 0x2d, 0x51, + 0x94, 0xa9, 0x18, 0xaf, 0xc0, 0x65, 0xe4, 0xa2, 0xc7, 0xd1, 0x38, 0x0a, 0xa2, 0xe1, 0xf4, 0x70, + 0x72, 0x24, 0xd2, 0x73, 0xfd, 0x28, 0xa4, 0x7f, 0xed, 0xc0, 0xb2, 0x55, 0x2b, 0xa3, 0x47, 0x9f, + 0x12, 0x42, 0xa0, 0xef, 0xd0, 0x05, 0xe3, 0x2d, 0x19, 0xca, 0x55, 0x10, 0x8a, 0x18, 0xe0, 0x13, + 0x79, 0xad, 0xbe, 0x05, 0x8b, 0x6a, 0x64, 0xea, 0x43, 0xc1, 0x85, 0x9d, 0x22, 0x17, 0xca, 0xef, + 0x17, 0xe4, 0x07, 0xaa, 0x89, 0x9f, 0x90, 0x97, 0xac, 0x03, 0x9c, 0xa3, 0x8a, 0x43, 0xe8, 0x8b, + 0x31, 0xf3, 0x34, 0xa2, 0x46, 0xd0, 0xd7, 0x60, 0x42, 0x7f, 0xcd, 0x01, 0xc8, 0x46, 0x87, 0x57, + 0x73, 0xda, 0x40, 0x88, 0x0c, 0x7a, 0xc3, 0x18, 0xbc, 0x0e, 0x2d, 0x7d, 0xa5, 0x93, 0xd9, 0x9c, + 0xa6, 0xc2, 0xb8, 0xc3, 0x78, 0x03, 0x16, 0x87, 0x41, 0x74, 0x84, 0x06, 0x1b, 0x73, 0x7b, 0x12, + 0x99, 0x90, 0xb2, 0x20, 0xe0, 0x7b, 0x12, 0xcd, 0x0c, 0x54, 0xd5, 0x30, 0x50, 0xf4, 0x1b, 0x15, + 0x1d, 0x81, 0xcf, 0xe6, 0x7c, 0xae, 0x94, 0x91, 0x3b, 0x05, 0x75, 0x7a, 0x4e, 0xc0, 0x1b, 0x23, + 0x6e, 0x07, 0x17, 0x06, 0x04, 0xde, 0x83, 0x85, 0x58, 0xe8, 0x2b, 0xa5, 0xcc, 0xaa, 0x2f, 0x50, + 0x66, 0xf3, 0xb1, 0x65, 0xc5, 0x3e, 0x01, 0x6d, 0x6f, 0x70, 0xca, 0xe2, 0xd4, 0xc7, 0x23, 0x19, + 0xba, 0x10, 0x42, 0x05, 0x2f, 0x1a, 0x38, 0x5a, 0xf6, 0x1b, 0xb0, 0x28, 0x93, 0x80, 0x34, 0xa5, + 0x4c, 0x89, 0xcd, 0x60, 0x4e, 0x48, 0xff, 0x40, 0x05, 0xfb, 0xed, 0x3d, 0x3c, 0x7f, 0x45, 0xcc, + 0xd9, 0x55, 0x72, 0xb3, 0xfb, 0x98, 0x0c, 0xbc, 0x0f, 0xd4, 0xb9, 0x6f, 0xc6, 0xb8, 0x90, 0x1f, + 0xc8, 0x8b, 0x12, 0x7b, 0x49, 0xab, 0x2f, 0xb3, 0xa4, 0xf4, 0x7b, 0x0e, 0xcc, 0xed, 0x45, 0xe3, + 0x3d, 0x99, 0x9a, 0x80, 0x82, 0xa0, 0xb3, 0xef, 0x54, 0xf1, 0x05, 0x49, 0x0b, 0xa5, 0x96, 0x7b, + 0x3e, 0x6f, 0xb9, 0x7f, 0x0a, 0x5e, 0xc1, 0xa8, 0x43, 0x1c, 0x8d, 0xa3, 0x98, 0x0b, 0xa3, 0x17, + 0x08, 0x33, 0x1d, 0x85, 0xe9, 0x89, 0x52, 0x63, 0x2f, 0x22, 0xc1, 0xe3, 0x1d, 0x3f, 0x96, 0x08, + 0xa7, 0x5b, 0x7a, 0x1a, 0x42, 0xbb, 0x15, 0x2b, 0xe8, 0x67, 0xa0, 0x81, 0xae, 0x32, 0x4e, 0xeb, + 0x4d, 0x68, 0x9c, 0x44, 0xe3, 0xde, 0x89, 0x1f, 0xa6, 0x4a, 0xb8, 0x17, 0x32, 0x1f, 0x76, 0x0f, + 0x17, 0x44, 0x13, 0xd0, 0xff, 0xac, 0xc1, 0xdc, 0x83, 0xf0, 0x34, 0xf2, 0xfb, 0x78, 0xb1, 0x30, + 0x62, 0xa3, 0x48, 0xe5, 0x22, 0xf2, 0xff, 0xc9, 0x15, 0x98, 0xc3, 0xe4, 0x9b, 0xb1, 0x60, 0xda, + 0x96, 0xb8, 0x00, 0x94, 0x10, 0x77, 0x12, 0xe2, 0x2c, 0xe5, 0x58, 0x88, 0x8f, 0x81, 0xf0, 0x43, + 0x44, 0x6c, 0xa6, 0x0c, 0xcb, 0x52, 0x96, 0xeb, 0x59, 0x33, 0x72, 0x3d, 0x79, 0x5f, 0x32, 0x95, + 0x42, 0xdc, 0xb5, 0x8b, 0xbe, 0x24, 0x84, 0x07, 0x9f, 0x98, 0x89, 0xa8, 0x11, 0xba, 0x1c, 0x73, + 0xf2, 0xe0, 0x63, 0x82, 0xdc, 0x2d, 0x11, 0x1f, 0x08, 0x1a, 0xa1, 0x84, 0x4d, 0x88, 0xbb, 0x70, + 0xf9, 0x24, 0xef, 0x86, 0xe0, 0xfd, 0x1c, 0xcc, 0x35, 0xf5, 0x80, 0x69, 0x85, 0x2a, 0xe6, 0x01, + 0x22, 0xad, 0x3a, 0x8f, 0x1b, 0xc7, 0x25, 0x91, 0x27, 0xa5, 0x8e, 0x4b, 0x9c, 0x61, 0xbc, 0x20, + 0x38, 0xf2, 0xfa, 0xcf, 0x30, 0x87, 0x1f, 0x43, 0xfd, 0x0d, 0xd7, 0x06, 0x31, 0x21, 0x22, 0xdb, + 0x55, 0xbc, 0x2a, 0xad, 0xba, 0x26, 0x44, 0xee, 0x40, 0x13, 0x8f, 0x88, 0x72, 0x5f, 0x17, 0x70, + 0x5f, 0xdb, 0xe6, 0x19, 0x12, 0x77, 0xd6, 0x24, 0x32, 0x2f, 0x3d, 0x16, 0xed, 0x4b, 0x0f, 0xa1, + 0x3c, 0xe5, 0x5d, 0x51, 0x1b, 0x7b, 0xcb, 0x00, 0x6e, 0x55, 0xe5, 0x82, 0x09, 0x82, 0x25, 0x24, + 0xb0, 0x30, 0x72, 0x15, 0xea, 0xfc, 0xf8, 0x32, 0xf6, 0xfc, 0x41, 0x87, 0xe8, 0x53, 0x94, 0xc6, + 0x78, 0x1b, 0xea, 0x7f, 0xbc, 0xd3, 0x59, 0xc6, 0x55, 0xb1, 0x30, 0xbe, 0x36, 0xba, 0x8c, 0xc2, + 0xb4, 0x22, 0x76, 0xd4, 0x02, 0xc9, 0x5b, 0x18, 0xb1, 0x4f, 0x59, 0x67, 0x15, 0xd3, 0x62, 0x5e, + 0x91, 0x73, 0x96, 0x4c, 0xab, 0xfe, 0x1e, 0x72, 0x12, 0x57, 0x50, 0xd2, 0x8f, 0x43, 0xcb, 0x84, + 0x49, 0x1d, 0xaa, 0x8f, 0x0e, 0x76, 0x1f, 0xb6, 0x2f, 0x91, 0x26, 0xcc, 0x1d, 0xee, 0x3e, 0x7e, + 0xbc, 0xbf, 0xbb, 0xd3, 0x76, 0x68, 0x0a, 0x64, 0x6b, 0x30, 0x90, 0x94, 0xfa, 0xa0, 0x9e, 0xf1, + 0xac, 0x63, 0xf1, 0x6c, 0x09, 0xdf, 0x54, 0xca, 0xf9, 0xe6, 0x85, 0xab, 0x4b, 0x77, 0xa1, 0x79, + 0x60, 0x64, 0xbf, 0xa3, 0x08, 0xa9, 0xbc, 0x77, 0x29, 0x7a, 0x06, 0x62, 0x0c, 0xa7, 0x62, 0x0e, + 0x87, 0xfe, 0xa1, 0x23, 0xb2, 0x84, 0xf5, 0xf0, 0x45, 0xdf, 0x14, 0x5a, 0x3a, 0x9c, 0x92, 0x25, + 0x9f, 0x59, 0x18, 0xa7, 0xc1, 0xa1, 0xf4, 0xa2, 0xe3, 0xe3, 0x84, 0xa9, 0x54, 0x11, 0x0b, 0xe3, + 0xbc, 0xcf, 0xbd, 0x28, 0xee, 0x91, 0xf8, 0xa2, 0x87, 0x44, 0xa6, 0x8c, 0x14, 0x70, 0xae, 0xc9, + 0x63, 0x76, 0xca, 0xe2, 0x44, 0x27, 0xc9, 0xe8, 0xb2, 0xce, 0x91, 0xcb, 0xaf, 0xf2, 0x06, 0xd4, + 0x75, 0xbb, 0xb6, 0x92, 0x52, 0x94, 0xba, 0x9e, 0x2b, 0x43, 0x3c, 0x57, 0x58, 0x83, 0x16, 0x8a, + 0xb9, 0x58, 0x41, 0x6e, 0x01, 0x39, 0xf6, 0xe3, 0x3c, 0xf9, 0x0c, 0x92, 0x97, 0xd4, 0xd0, 0xa7, + 0xb0, 0xac, 0x98, 0xc5, 0x70, 0x9f, 0xec, 0x4d, 0x74, 0x2e, 0x12, 0x91, 0x4a, 0x51, 0x44, 0xe8, + 0x7f, 0x39, 0x30, 0x27, 0x77, 0xba, 0xf0, 0x82, 0x42, 0xec, 0xb3, 0x85, 0x91, 0x8e, 0x95, 0x00, + 0x8f, 0xf2, 0x24, 0x15, 0x63, 0x41, 0xf5, 0xcd, 0x94, 0xa9, 0x3e, 0x02, 0xd5, 0xb1, 0x97, 0x9e, + 0xe0, 0x69, 0xb9, 0xe1, 0xe2, 0xff, 0xa4, 0x2d, 0x62, 0x3b, 0x42, 0xcd, 0x62, 0x5c, 0xa7, 0xec, + 0xad, 0x88, 0xb0, 0xe8, 0xc5, 0xb7, 0x22, 0x57, 0xa0, 0x81, 0x03, 0xe8, 0x65, 0xa1, 0x9b, 0x0c, + 0xe0, 0x9c, 0x2b, 0x0a, 0x28, 0xbb, 0x32, 0x17, 0x35, 0x43, 0xe8, 0xaa, 0xd8, 0x79, 0xb9, 0x04, + 0xfa, 0x46, 0x4d, 0xe6, 0x24, 0x66, 0x70, 0xc6, 0x11, 0x72, 0x00, 0x79, 0x8e, 0x90, 0xa4, 0xae, + 0xae, 0xa7, 0x5d, 0xe8, 0xec, 0xb0, 0x80, 0xa5, 0x6c, 0x2b, 0x08, 0xf2, 0xed, 0xbf, 0x02, 0x97, + 0x4b, 0xea, 0xa4, 0xc7, 0xfc, 0x05, 0x58, 0xdd, 0x12, 0xf9, 0x5b, 0x3f, 0xaa, 0x9c, 0x04, 0xda, + 0x81, 0xb5, 0x7c, 0x93, 0xb2, 0xb3, 0x7b, 0xb0, 0xb4, 0xc3, 0x8e, 0x26, 0xc3, 0x7d, 0x76, 0x9a, + 0x75, 0x44, 0xa0, 0x9a, 0x9c, 0x44, 0x67, 0x52, 0x30, 0xf1, 0x7f, 0xf2, 0x2a, 0x40, 0xc0, 0x69, + 0x7a, 0xc9, 0x98, 0xf5, 0x55, 0xce, 0x39, 0x22, 0x87, 0x63, 0xd6, 0xa7, 0x6f, 0x03, 0x31, 0xdb, + 0x91, 0xeb, 0xc5, 0x2d, 0xdd, 0xe4, 0xa8, 0x97, 0x4c, 0x93, 0x94, 0x8d, 0x54, 0x32, 0xbd, 0x09, + 0xd1, 0x1b, 0xd0, 0x3a, 0xf0, 0xa6, 0x2e, 0xfb, 0x9a, 0x7c, 0x38, 0xb3, 0x0e, 0x73, 0x63, 0x6f, + 0xca, 0xd5, 0x94, 0x8e, 0x29, 0x61, 0x35, 0xfd, 0xf7, 0x0a, 0xcc, 0x0a, 0x4a, 0xde, 0xea, 0x80, + 0x25, 0xa9, 0x1f, 0x22, 0x63, 0xa9, 0x56, 0x0d, 0xa8, 0xc0, 0xca, 0x95, 0x12, 0x56, 0x96, 0xe7, + 0x32, 0x95, 0xbf, 0x2b, 0xf9, 0xd5, 0xc2, 0x38, 0x73, 0x65, 0xc9, 0x41, 0x22, 0xa8, 0x91, 0x01, + 0xb9, 0xf0, 0x63, 0x66, 0x4f, 0xc5, 0xf8, 0x94, 0x94, 0x4a, 0xce, 0x35, 0xa1, 0x52, 0xab, 0x3d, + 0x27, 0x18, 0xbc, 0x60, 0xb5, 0x0b, 0xd6, 0xb9, 0xfe, 0x12, 0xd6, 0x59, 0x1c, 0xd6, 0x5e, 0x64, + 0x9d, 0xe1, 0x25, 0xac, 0x33, 0x25, 0xd0, 0xbe, 0xc7, 0x98, 0xcb, 0xb8, 0xff, 0xa7, 0x78, 0xf7, + 0x9b, 0x0e, 0xb4, 0x25, 0x17, 0xe9, 0x3a, 0xf2, 0xba, 0xe5, 0xe7, 0x96, 0x66, 0xd9, 0x5e, 0x87, + 0x79, 0xf4, 0x3e, 0x75, 0x9c, 0x55, 0x06, 0x85, 0x2d, 0x90, 0xcf, 0x43, 0x5d, 0x86, 0x8d, 0xfc, + 0x40, 0x6e, 0x8a, 0x09, 0xa9, 0x50, 0x6d, 0xec, 0xc9, 0x24, 0x19, 0xc7, 0xd5, 0x65, 0xfa, 0x67, + 0x0e, 0x2c, 0x19, 0x03, 0x96, 0x5c, 0xf8, 0x1e, 0x28, 0x69, 0x10, 0x41, 0x57, 0x21, 0xb9, 0xeb, + 0xb6, 0xd8, 0x64, 0x9f, 0x59, 0xc4, 0xb8, 0x99, 0xde, 0x14, 0x07, 0x98, 0x4c, 0x46, 0x52, 0x89, + 0x9a, 0x10, 0x67, 0xa4, 0x33, 0xc6, 0x9e, 0x69, 0x12, 0xa1, 0xc6, 0x2d, 0x0c, 0x33, 0x38, 0xb8, + 0xd7, 0xac, 0x89, 0x84, 0x3d, 0xb3, 0x41, 0xfa, 0x77, 0x0e, 0x2c, 0x8b, 0xe3, 0x8f, 0x3c, 0x5c, + 0xea, 0x27, 0x10, 0xb3, 0xe2, 0xbc, 0x27, 0x24, 0x72, 0xef, 0x92, 0x2b, 0xcb, 0xe4, 0xd3, 0x2f, + 0x79, 0x64, 0xd3, 0x99, 0x3b, 0xe7, 0xec, 0xc5, 0x4c, 0xd9, 0x5e, 0xbc, 0x60, 0xa5, 0xcb, 0x82, + 0x8c, 0xb5, 0xd2, 0x20, 0xe3, 0xdd, 0x39, 0xa8, 0x25, 0xfd, 0x68, 0xcc, 0xe8, 0x1a, 0xac, 0xd8, + 0x93, 0x93, 0x2a, 0xe8, 0x5b, 0x0e, 0x74, 0xee, 0x89, 0x60, 0xbc, 0x1f, 0x0e, 0xf7, 0xfc, 0x24, + 0x8d, 0x62, 0xfd, 0x52, 0xec, 0x2a, 0x40, 0x92, 0x7a, 0x71, 0x2a, 0xf2, 0x33, 0x65, 0x08, 0x30, + 0x43, 0xf8, 0x18, 0x59, 0x38, 0x10, 0xb5, 0x62, 0x6f, 0x74, 0xb9, 0xe0, 0x43, 0xc8, 0x03, 0x9a, + 0x65, 0x89, 0xdf, 0x10, 0x99, 0x6c, 0xdc, 0x57, 0x60, 0xa7, 0xa8, 0xd7, 0xc5, 0xc9, 0x27, 0x87, + 0xd2, 0xbf, 0x75, 0x60, 0x31, 0x1b, 0xe4, 0x2e, 0x07, 0x6d, 0xed, 0x20, 0xcd, 0x6f, 0xa6, 0x1d, + 0x54, 0x70, 0xd2, 0xe7, 0xf6, 0x58, 0x8e, 0xcd, 0x40, 0x50, 0x62, 0x65, 0x29, 0x9a, 0x28, 0x07, + 0xc7, 0x84, 0x44, 0x5e, 0x0a, 0xf7, 0x04, 0xa4, 0x57, 0x23, 0x4b, 0x98, 0x5e, 0x3b, 0x4a, 0xf1, + 0xab, 0x59, 0x71, 0xf4, 0x93, 0x45, 0x65, 0x4a, 0xe7, 0x10, 0x45, 0x53, 0x6a, 0x5e, 0x6c, 0xd4, + 0xc5, 0xfa, 0xa8, 0x32, 0xfd, 0x75, 0x07, 0x2e, 0x97, 0x2c, 0xbc, 0x94, 0x9a, 0x1d, 0x58, 0x3a, + 0xd6, 0x95, 0x6a, 0x71, 0x84, 0xe8, 0xac, 0xa9, 0x9b, 0x25, 0x7b, 0x41, 0xdc, 0xe2, 0x07, 0xda, + 0x2f, 0x12, 0xcb, 0x6d, 0x65, 0x7e, 0x15, 0x2b, 0x36, 0x3e, 0x0b, 0x4d, 0xe3, 0x8d, 0x16, 0x59, + 0x87, 0xe5, 0xa7, 0x0f, 0x1e, 0x3f, 0xdc, 0x3d, 0x3c, 0xec, 0x1d, 0x3c, 0xb9, 0xfb, 0xf9, 0xdd, + 0x2f, 0xf5, 0xf6, 0xb6, 0x0e, 0xf7, 0xda, 0x97, 0xc8, 0x1a, 0x90, 0x87, 0xbb, 0x87, 0x8f, 0x77, + 0x77, 0x2c, 0xdc, 0xb9, 0xf3, 0x1b, 0x33, 0xb0, 0x20, 0x6e, 0x2c, 0xc5, 0x1b, 0x79, 0x16, 0x93, + 0xf7, 0x61, 0x4e, 0xfe, 0xc6, 0x01, 0x59, 0x95, 0xc3, 0xb6, 0x7f, 0x55, 0xa1, 0xbb, 0x96, 0x87, + 0x25, 0x5f, 0x2e, 0xff, 0xc2, 0xf7, 0xfe, 0xf1, 0xb7, 0x2a, 0xf3, 0xa4, 0xb9, 0x79, 0xfa, 0xd6, + 0xe6, 0x90, 0x85, 0x09, 0x6f, 0xe3, 0x67, 0x00, 0xb2, 0xd7, 0xff, 0xa4, 0xa3, 0xfd, 0xc1, 0xdc, + 0xcf, 0x1a, 0x74, 0x2f, 0x97, 0xd4, 0xc8, 0x76, 0x2f, 0x63, 0xbb, 0xcb, 0x74, 0x81, 0xb7, 0xeb, + 0x87, 0x7e, 0x2a, 0x7e, 0x0a, 0xe0, 0x5d, 0x67, 0x83, 0x0c, 0xa0, 0x65, 0x3e, 0xee, 0x27, 0x2a, + 0xf0, 0x54, 0xf2, 0xd3, 0x02, 0xdd, 0x57, 0x4a, 0xeb, 0x54, 0xd4, 0x0d, 0xfb, 0x58, 0xa5, 0x6d, + 0xde, 0xc7, 0x04, 0x29, 0xb2, 0x5e, 0x02, 0x58, 0xb0, 0xdf, 0xf0, 0x93, 0x2b, 0x86, 0xca, 0x28, + 0xfc, 0x82, 0x40, 0xf7, 0xd5, 0x73, 0x6a, 0x65, 0x5f, 0xaf, 0x62, 0x5f, 0xeb, 0x94, 0xf0, 0xbe, + 0xfa, 0x48, 0xa3, 0x7e, 0x41, 0xe0, 0x5d, 0x67, 0xe3, 0xce, 0xbf, 0xbd, 0x06, 0x0d, 0x1d, 0x2a, + 0x26, 0x5f, 0x85, 0x79, 0xeb, 0x4a, 0x99, 0xa8, 0x69, 0x94, 0xdd, 0x40, 0x77, 0xaf, 0x94, 0x57, + 0xca, 0x8e, 0xaf, 0x62, 0xc7, 0x1d, 0xb2, 0xc6, 0x3b, 0x96, 0x77, 0xb2, 0x9b, 0x78, 0x91, 0x2e, + 0xb2, 0x62, 0x9f, 0x89, 0x79, 0x66, 0xd7, 0xc0, 0xd6, 0x3c, 0x0b, 0xd7, 0xc6, 0xd6, 0x3c, 0x8b, + 0x77, 0xc7, 0xf4, 0x0a, 0x76, 0xb7, 0x46, 0x56, 0xcc, 0xee, 0x74, 0x08, 0x97, 0x61, 0x2a, 0xb7, + 0xf9, 0xe4, 0x9d, 0xbc, 0xaa, 0x19, 0xab, 0xec, 0x29, 0xbc, 0x66, 0x91, 0xe2, 0x7b, 0x78, 0xda, + 0xc1, 0xae, 0x08, 0xc1, 0xed, 0x33, 0x5f, 0xbc, 0x93, 0x2f, 0x43, 0x43, 0x3f, 0xd0, 0x24, 0xeb, + 0xc6, 0x83, 0x59, 0xf3, 0x41, 0x69, 0xb7, 0x53, 0xac, 0x28, 0x63, 0x0c, 0xb3, 0x65, 0xce, 0x18, + 0x4f, 0xa1, 0x69, 0x3c, 0xc2, 0x24, 0x97, 0x75, 0xa0, 0x3f, 0xff, 0xd0, 0xb3, 0xdb, 0x2d, 0xab, + 0x92, 0x5d, 0x2c, 0x61, 0x17, 0x4d, 0xd2, 0x40, 0xde, 0x4b, 0x9f, 0x47, 0x09, 0xd9, 0x87, 0x55, + 0x79, 0x70, 0x39, 0x62, 0xdf, 0xcf, 0x12, 0x95, 0xfc, 0x02, 0xc0, 0x6d, 0x87, 0xbc, 0x07, 0x75, + 0xf5, 0xd6, 0x96, 0xac, 0x95, 0xbf, 0x19, 0xee, 0xae, 0x17, 0x70, 0xa9, 0xd6, 0xbe, 0x04, 0x90, + 0xbd, 0xf8, 0xd4, 0x02, 0x5c, 0x78, 0x41, 0xaa, 0x77, 0xa7, 0xf8, 0x3c, 0x94, 0xae, 0xe1, 0x04, + 0xdb, 0x04, 0x05, 0x38, 0x64, 0x67, 0xea, 0x71, 0xc3, 0x57, 0xa0, 0x69, 0x3c, 0xfa, 0xd4, 0xcb, + 0x57, 0x7c, 0x30, 0xaa, 0x97, 0xaf, 0xe4, 0x8d, 0x28, 0xed, 0x62, 0xeb, 0x2b, 0x74, 0x91, 0xb7, + 0x9e, 0xf8, 0xc3, 0x70, 0x24, 0x08, 0xf8, 0x06, 0x9d, 0xc0, 0xbc, 0xf5, 0xb2, 0x53, 0x4b, 0x4f, + 0xd9, 0xbb, 0x51, 0x2d, 0x3d, 0xa5, 0x8f, 0x41, 0x15, 0x3b, 0xd3, 0x25, 0xde, 0xcf, 0x29, 0x92, + 0x18, 0x3d, 0x7d, 0x00, 0x4d, 0xe3, 0x95, 0xa6, 0x9e, 0x4b, 0xf1, 0x41, 0xa8, 0x9e, 0x4b, 0xd9, + 0xa3, 0xce, 0x15, 0xec, 0x63, 0x81, 0x22, 0x2b, 0xe0, 0xdb, 0x00, 0xde, 0xf6, 0x57, 0x61, 0xc1, + 0x7e, 0xb7, 0xa9, 0xe5, 0xb2, 0xf4, 0x05, 0xa8, 0x96, 0xcb, 0x73, 0x1e, 0x7b, 0x4a, 0x96, 0xde, + 0x58, 0xd6, 0x9d, 0x6c, 0x7e, 0x28, 0x2f, 0x6e, 0x3f, 0x22, 0x5f, 0xe0, 0xca, 0x47, 0x3e, 0xd6, + 0x20, 0xeb, 0x06, 0xd7, 0x9a, 0x4f, 0x3a, 0xb4, 0xbc, 0x14, 0xde, 0x75, 0xd8, 0xcc, 0x2c, 0x5e, + 0x37, 0xa0, 0x45, 0xc1, 0x47, 0x1b, 0x86, 0x45, 0x31, 0xdf, 0x75, 0x18, 0x16, 0xc5, 0x7a, 0xdb, + 0x91, 0xb7, 0x28, 0xa9, 0xcf, 0xdb, 0x08, 0x61, 0x31, 0x97, 0xbe, 0xa4, 0xa5, 0xa2, 0x3c, 0xdf, + 0xb3, 0x7b, 0xf5, 0xc5, 0x59, 0x4f, 0xb6, 0xa2, 0x52, 0x0a, 0x6a, 0x53, 0x65, 0xd7, 0xfe, 0x2c, + 0xb4, 0xcc, 0xf7, 0x76, 0xc4, 0x14, 0xe5, 0x7c, 0x4f, 0xaf, 0x94, 0xd6, 0xd9, 0x9b, 0x4b, 0x5a, + 0x66, 0x37, 0x7c, 0x73, 0xed, 0x07, 0x47, 0x99, 0xd2, 0x2d, 0x7b, 0x67, 0x95, 0x29, 0xdd, 0xd2, + 0x57, 0x4a, 0x6a, 0x73, 0xc9, 0xb2, 0x35, 0x17, 0x11, 0x63, 0x27, 0x1f, 0xc0, 0xa2, 0x91, 0x1b, + 0x78, 0x38, 0x0d, 0xfb, 0x9a, 0x51, 0x8b, 0x49, 0xe4, 0xdd, 0x32, 0xbf, 0x98, 0xae, 0x63, 0xfb, + 0x4b, 0xd4, 0x9a, 0x04, 0x67, 0xd2, 0x6d, 0x68, 0x9a, 0x79, 0x87, 0x2f, 0x68, 0x77, 0xdd, 0xa8, + 0x32, 0x73, 0xa0, 0x6f, 0x3b, 0xe4, 0x77, 0x1c, 0x68, 0x59, 0x59, 0x7c, 0xd6, 0x4d, 0x52, 0xae, + 0x9d, 0x8e, 0x59, 0x67, 0x36, 0x44, 0x5d, 0x1c, 0xe4, 0xfe, 0xc6, 0xe7, 0xac, 0x45, 0xf8, 0xd0, + 0x3a, 0x5f, 0xdd, 0xca, 0xff, 0xd8, 0xc3, 0x47, 0x79, 0x02, 0x33, 0xd1, 0xfe, 0xa3, 0xdb, 0x0e, + 0xf9, 0x8e, 0x03, 0x0b, 0x76, 0x54, 0x40, 0x6f, 0x55, 0x69, 0xfc, 0x41, 0x6f, 0xd5, 0x39, 0xa1, + 0x84, 0x0f, 0x70, 0x94, 0x8f, 0x37, 0x5c, 0x6b, 0x94, 0xf2, 0x29, 0xda, 0x0f, 0x37, 0x5a, 0xf2, + 0xae, 0xf8, 0x79, 0x16, 0x15, 0xaa, 0x22, 0x86, 0x76, 0xcf, 0x6f, 0xaf, 0xf9, 0xdb, 0x24, 0x37, + 0x9d, 0xdb, 0x0e, 0xf9, 0x8a, 0xf8, 0xfd, 0x09, 0xf9, 0x2d, 0x72, 0xc9, 0xcb, 0x7e, 0x4f, 0xaf, + 0xe3, 0x9c, 0xae, 0xd2, 0xcb, 0xd6, 0x9c, 0xf2, 0x76, 0x73, 0x4b, 0x8c, 0x4e, 0xfe, 0xac, 0x48, + 0xa6, 0xf8, 0x0b, 0x3f, 0x35, 0x72, 0xfe, 0x20, 0x47, 0x62, 0x90, 0x92, 0xdc, 0x62, 0xe5, 0x97, + 0x6c, 0x86, 0x6e, 0xe0, 0x58, 0xaf, 0xd3, 0xd7, 0xce, 0x1d, 0xeb, 0x26, 0x9e, 0xed, 0xf9, 0x88, + 0x0f, 0x00, 0xb2, 0xb0, 0x32, 0xc9, 0x85, 0x35, 0xb5, 0xed, 0x2b, 0x46, 0x9e, 0x6d, 0x79, 0x51, + 0xd1, 0x4f, 0xde, 0xe2, 0x97, 0x85, 0x5a, 0x79, 0xa0, 0x02, 0xa2, 0xa6, 0xf3, 0x60, 0xc7, 0x7f, + 0x2d, 0xe7, 0x21, 0xdf, 0xbe, 0xa5, 0x54, 0x74, 0x74, 0xf5, 0x09, 0xcc, 0xef, 0x47, 0xd1, 0xb3, + 0xc9, 0x58, 0x5f, 0x03, 0xd9, 0x61, 0xb7, 0x3d, 0x2f, 0x39, 0xe9, 0xe6, 0x66, 0x41, 0xaf, 0x61, + 0x53, 0x5d, 0xd2, 0x31, 0x9a, 0xda, 0xfc, 0x30, 0x0b, 0x5b, 0x7f, 0x44, 0x3c, 0x58, 0xd2, 0x6e, + 0x89, 0x1e, 0x78, 0xd7, 0x6e, 0xc6, 0x0c, 0xb8, 0x16, 0xba, 0xb0, 0x3c, 0x50, 0x35, 0xda, 0xcd, + 0x44, 0xb5, 0x79, 0xdb, 0x21, 0x07, 0xd0, 0xda, 0x61, 0xfd, 0x68, 0xc0, 0x64, 0xec, 0x6a, 0x39, + 0x1b, 0xb8, 0x0e, 0x7a, 0x75, 0xe7, 0x2d, 0xd0, 0xd6, 0xdf, 0x63, 0x6f, 0x1a, 0xb3, 0xaf, 0x6d, + 0x7e, 0x28, 0xa3, 0x62, 0x1f, 0x29, 0xfd, 0xad, 0xc2, 0x86, 0x96, 0xfe, 0xce, 0xc5, 0x19, 0x2d, + 0xfd, 0x5d, 0x88, 0x33, 0x5a, 0x4b, 0xad, 0xc2, 0x96, 0x24, 0x80, 0xa5, 0x42, 0x68, 0x92, 0xbc, + 0xa6, 0x2c, 0xf0, 0x39, 0x01, 0xcd, 0xee, 0xb5, 0xf3, 0x09, 0xec, 0xde, 0x36, 0xec, 0xde, 0x0e, + 0x61, 0x7e, 0x87, 0x89, 0xc5, 0x12, 0xb9, 0x26, 0xb9, 0x37, 0xa8, 0x66, 0x26, 0x4b, 0x5e, 0x81, + 0x63, 0x9d, 0x6d, 0xa0, 0x31, 0xd1, 0x83, 0x7c, 0x19, 0x9a, 0xf7, 0x59, 0xaa, 0x92, 0x4b, 0xb4, + 0x8b, 0x98, 0xcb, 0x36, 0xe9, 0x96, 0xe4, 0xa6, 0xd8, 0x3c, 0x83, 0xad, 0x6d, 0xb2, 0xc1, 0x90, + 0x09, 0xe5, 0xd4, 0xf3, 0x07, 0x1f, 0x91, 0x9f, 0xc6, 0xc6, 0x75, 0x76, 0xdb, 0x9a, 0x91, 0x93, + 0x60, 0x36, 0xbe, 0x98, 0xc3, 0xcb, 0x5a, 0x0e, 0xa3, 0x01, 0x33, 0x5c, 0x95, 0x10, 0x9a, 0x46, + 0x52, 0xa6, 0x16, 0xa0, 0x62, 0x82, 0xa9, 0x16, 0xa0, 0x92, 0x1c, 0x4e, 0x7a, 0x13, 0xfb, 0xa1, + 0xe4, 0x5a, 0xd6, 0x8f, 0xc8, 0xdb, 0xcc, 0x7a, 0xda, 0xfc, 0xd0, 0x1b, 0xa5, 0x1f, 0x91, 0xa7, + 0xf8, 0x1e, 0xd5, 0x4c, 0xa0, 0xc9, 0x7c, 0xde, 0x7c, 0xae, 0x8d, 0x5e, 0x2c, 0xa3, 0xca, 0xf6, + 0x83, 0x45, 0x57, 0xe8, 0xd1, 0x7c, 0x1a, 0xe0, 0x30, 0x8d, 0xc6, 0x3b, 0x1e, 0x1b, 0x45, 0x61, + 0xa6, 0x6b, 0xb3, 0x24, 0x91, 0x4c, 0x7f, 0x19, 0x99, 0x22, 0xe4, 0xa9, 0x71, 0x48, 0xb0, 0xf2, + 0x8f, 0x14, 0x73, 0x9d, 0x9b, 0x47, 0xa2, 0x17, 0xa4, 0x24, 0x97, 0xe4, 0xb6, 0x43, 0xb6, 0x00, + 0xb2, 0xd8, 0xb4, 0x76, 0xf9, 0x0b, 0x61, 0x6f, 0xad, 0xf6, 0x4a, 0x02, 0xd9, 0x07, 0xd0, 0xc8, + 0x82, 0x9d, 0xeb, 0x59, 0x62, 0xad, 0x15, 0x1a, 0xd5, 0x16, 0xbc, 0x10, 0x82, 0xa4, 0x6d, 0x5c, + 0x2a, 0x20, 0x75, 0xbe, 0x54, 0x18, 0x57, 0xf4, 0x61, 0x59, 0x0c, 0x50, 0xbb, 0x23, 0x98, 0xf6, + 0xa0, 0x66, 0x52, 0x12, 0x06, 0xd4, 0xd2, 0x5c, 0x1a, 0x45, 0xb3, 0xa2, 0x0a, 0x9c, 0x5b, 0x45, + 0xca, 0x05, 0x57, 0xcd, 0x23, 0x58, 0x2a, 0x84, 0x79, 0xb4, 0x48, 0x9f, 0x17, 0x79, 0xd3, 0x22, + 0x7d, 0x6e, 0x84, 0x88, 0xae, 0x62, 0x97, 0x8b, 0x14, 0xf0, 0xa4, 0x72, 0xe6, 0xa7, 0xfd, 0x93, + 0x77, 0x9d, 0x8d, 0xbb, 0x37, 0x3e, 0xf8, 0xf8, 0xd0, 0x4f, 0x4f, 0x26, 0x47, 0xb7, 0xfa, 0xd1, + 0x68, 0x33, 0x50, 0x47, 0x7f, 0x99, 0xbc, 0xb4, 0x19, 0x84, 0x83, 0x4d, 0x6c, 0xf9, 0x68, 0x16, + 0x7f, 0xe7, 0xf2, 0x93, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x2c, 0x41, 0x1a, 0x19, 0x53, + 0x00, 0x00, } diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index 5a6a0e51f..75b93821f 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -837,6 +837,13 @@ message SendCoinsRequest { /// A manual fee rate set in sat/byte that should be used when crafting the transaction. int64 sat_per_byte = 5; + + /** + If set, then the amount field will be ignored, and lnd will attempt to + send all the coins under control of the internal wallet to the specified + address. + */ + bool send_all = 6; } message SendCoinsResponse { /// The transaction ID of the transaction diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index ebaf53658..5ecd1d9e7 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -1288,10 +1288,12 @@ "type": "object", "properties": { "chain": { - "type": "string" + "type": "string", + "title": "/ The blockchain the node is on (eg bitcoin, litecoin)" }, "network": { - "type": "string" + "type": "string", + "title": "/ The network the node is on (eg regtest, testnet, mainnet)" } } }, @@ -2782,6 +2784,11 @@ "type": "string", "format": "int64", "description": "/ A manual fee rate set in sat/byte that should be used when crafting the transaction." + }, + "send_all": { + "type": "boolean", + "format": "boolean", + "description": "*\nIf set, then the amount field will be ignored, and lnd will attempt to\nsend all the coins under control of the internal wallet to the specified\naddress." } } }, From 3a7b9c8367ff9c186f77d3d4163730b8c8866819 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 21:10:32 -0800 Subject: [PATCH 10/13] rpc: implement new feature of sendcoins to sweep all wallet UTXOs In this commit, we implement the new feature which allows sendcoins to sweep all the coins in the wallet. We use the new sweep.CraftSweepAllTx method, and also use WithCoinSelectLock to ensure that we don't trigger any double-spend errors triggered by coin selection race conditions. --- rpcserver.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index a49fea0a4..5664e24d0 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -769,13 +769,89 @@ func (r *rpcServer) SendCoins(ctx context.Context, return nil, err } - rpcsLog.Infof("[sendcoins] addr=%v, amt=%v, sat/kw=%v", in.Addr, - btcutil.Amount(in.Amount), int64(feePerKw)) + rpcsLog.Infof("[sendcoins] addr=%v, amt=%v, sat/kw=%v, sweep_all=%v", + in.Addr, btcutil.Amount(in.Amount), int64(feePerKw), + in.SendAll) - paymentMap := map[string]int64{in.Addr: in.Amount} - txid, err := r.sendCoinsOnChain(paymentMap, feePerKw) - if err != nil { - return nil, err + var txid *chainhash.Hash + + wallet := r.server.cc.wallet + + // If the send all flag is active, then we'll attempt to sweep all the + // coins in the wallet in a single transaction (if possible), + // otherwise, we'll respect the amount, and attempt a regular 2-output + // send. + if in.SendAll { + // At this point, the amount shouldn't be set since we've been + // instructed to sweep all the coins from the wallet. + if in.Amount != 0 { + return nil, fmt.Errorf("amount set while SendAll is " + + "active") + } + + // Additionally, we'll need to convert the sweep address passed + // into a useable struct, and also query for the latest block + // height so we can properly construct the transaction. + sweepAddr, err := btcutil.DecodeAddress( + in.Addr, activeNetParams.Params, + ) + if err != nil { + return nil, err + } + _, bestHeight, err := r.server.cc.chainIO.GetBestBlock() + if err != nil { + return nil, err + } + + // With the sweeper instance created, we can now generate a + // transaction that will sweep ALL outputs from the wallet in a + // single transaction. This will be generated in a concurrent + // safe manner, so no need to worry about locking. + sweepTxPkg, err := sweep.CraftSweepAllTx( + feePerKw, uint32(bestHeight), sweepAddr, wallet, + wallet.WalletController, wallet.WalletController, + r.server.cc.feeEstimator, r.server.cc.signer, + ) + if err != nil { + return nil, err + } + + rpcsLog.Debugf("Sweeping all coins from wallet to addr=%v, "+ + "with tx=%v", in.Addr, spew.Sdump(sweepTxPkg.SweepTx)) + + // As our sweep transaction was created, successfully, we'll + // now attempt to publish it, cancelling the sweep pkg to + // return all outputs if it fails. + err = wallet.PublishTransaction(sweepTxPkg.SweepTx) + if err != nil { + sweepTxPkg.CancelSweepAttempt() + + return nil, fmt.Errorf("unable to broadcast sweep "+ + "transaction: %v", err) + } + + sweepTXID := sweepTxPkg.SweepTx.TxHash() + txid = &sweepTXID + } else { + + // We'll now construct out payment map, and use the wallet's + // coin selection synchronization method to ensure that no coin + // selection (funding, sweep alls, other sends) can proceed + // while we instruct the wallet to send this transaction. + paymentMap := map[string]int64{in.Addr: in.Amount} + err := wallet.WithCoinSelectLock(func() error { + newTXID, err := r.sendCoinsOnChain(paymentMap, feePerKw) + if err != nil { + return err + } + + txid = newTXID + + return nil + }) + if err != nil { + return nil, err + } } rpcsLog.Infof("[sendcoins] spend generated txid: %v", txid.String()) From b2c712fb67ead324bdc77ca6e6524817aee03a88 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Nov 2018 21:11:47 -0800 Subject: [PATCH 11/13] cmd/lncli: add new --sweepall flag to sendcoins In this commit, we add a new flag to the sendcoins command that allows callers to sweep all funds out of the daemon's wallet. This CANNOT be set at the same time that an amount is specified. --- cmd/lncli/commands.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index e1e511b94..228ca6b48 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -161,7 +161,13 @@ var sendCoinsCommand = cli.Command{ Name: "addr", Usage: "the BASE58 encoded bitcoin address to send coins to on-chain", }, - // TODO(roasbeef): switch to BTC on command line? int may not be sufficient + cli.BoolFlag{ + Name: "sweepall", + Usage: "if set, then the amount field will be ignored, " + + "and all the wallet will attempt to sweep all " + + "outputs within the wallet to the target " + + "address", + }, cli.Int64Flag{ Name: "amt", Usage: "the number of bitcoin denominated in satoshis to send", @@ -215,14 +221,18 @@ func sendCoins(ctx *cli.Context) error { amt = ctx.Int64("amt") case args.Present(): amt, err = strconv.ParseInt(args.First(), 10, 64) - default: + case !ctx.Bool("sweepall"): return fmt.Errorf("Amount argument missing") } - if err != nil { return fmt.Errorf("unable to decode amount: %v", err) } + if amt != 0 && ctx.Bool("sweepall") { + return fmt.Errorf("amount cannot be set if attempting to " + + "sweep all coins out of the wallet") + } + ctxb := context.Background() client, cleanUp := getClient(ctx) defer cleanUp() @@ -232,6 +242,7 @@ func sendCoins(ctx *cli.Context) error { Amount: amt, TargetConf: int32(ctx.Int64("conf_target")), SatPerByte: ctx.Int64("sat_per_byte"), + SendAll: ctx.Bool("sweepall"), } txid, err := client.SendCoins(ctxb, req) if err != nil { From eda6ed224fa74d7ebb426944ad0a0043b806a2e6 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Mon, 24 Dec 2018 15:29:55 -0600 Subject: [PATCH 12/13] sweep: add unit tests for TestDetermineFeePerKw and CraftSweepAllTx Along the way we also extend the mockFeeEstimator to be able to return a fee rate for a specified confirmation target. --- sweep/fee_estimator_mock_test.go | 14 +- sweep/walletsweep.go | 17 +- sweep/walletsweep_test.go | 409 +++++++++++++++++++++++++++++++ 3 files changed, 436 insertions(+), 4 deletions(-) create mode 100644 sweep/walletsweep_test.go diff --git a/sweep/fee_estimator_mock_test.go b/sweep/fee_estimator_mock_test.go index 8f3eb44bb..c926f159c 100644 --- a/sweep/fee_estimator_mock_test.go +++ b/sweep/fee_estimator_mock_test.go @@ -1,8 +1,9 @@ package sweep import ( - "github.com/lightningnetwork/lnd/lnwallet" "sync" + + "github.com/lightningnetwork/lnd/lnwallet" ) // mockFeeEstimator implements a mock fee estimator. It closely resembles @@ -13,6 +14,8 @@ type mockFeeEstimator struct { relayFee lnwallet.SatPerKWeight + blocksToFee map[uint32]lnwallet.SatPerKWeight + lock sync.Mutex } @@ -20,8 +23,9 @@ func newMockFeeEstimator(feePerKW, relayFee lnwallet.SatPerKWeight) *mockFeeEstimator { return &mockFeeEstimator{ - feePerKW: feePerKW, - relayFee: relayFee, + feePerKW: feePerKW, + relayFee: relayFee, + blocksToFee: make(map[uint32]lnwallet.SatPerKWeight), } } @@ -41,6 +45,10 @@ func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) ( e.lock.Lock() defer e.lock.Unlock() + if fee, ok := e.blocksToFee[numBlocks]; ok { + return fee, nil + } + return e.feePerKW, nil } diff --git a/sweep/walletsweep.go b/sweep/walletsweep.go index 34ba74bab..1cfe90598 100644 --- a/sweep/walletsweep.go +++ b/sweep/walletsweep.go @@ -10,6 +10,13 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" ) +const ( + // defaultNumBlocksEstimate is the number of blocks that we fall back + // to issuing an estimate for if a fee pre fence doesn't specify an + // explicit conf target or fee rate. + defaultNumBlocksEstimate = 6 +) + // FeePreference allows callers to express their time value for inclusion of a // transaction into a block via either a confirmation target, or a fee rate. type FeePreference struct { @@ -30,6 +37,12 @@ func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator, feePref FeePreference) (lnwallet.SatPerKWeight, error) { switch { + // If both values are set, then we'll return an error as we require a + // strict directive. + case feePref.FeeRate != 0 && feePref.ConfTarget != 0: + return 0, fmt.Errorf("only FeeRate or ConfTarget should " + + "be set for FeePreferences") + // If the target number of confirmations is set, then we'll use that to // consult our fee estimator for an adequate fee. case feePref.ConfTarget != 0: @@ -61,7 +74,9 @@ func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator, // Otherwise, we'll attempt a relaxed confirmation target for the // transaction default: - feePerKw, err := feeEstimator.EstimateFeePerKW(6) + feePerKw, err := feeEstimator.EstimateFeePerKW( + defaultNumBlocksEstimate, + ) if err != nil { return 0, fmt.Errorf("unable to query fee estimator: "+ "%v", err) diff --git a/sweep/walletsweep_test.go b/sweep/walletsweep_test.go new file mode 100644 index 000000000..f8f692dbe --- /dev/null +++ b/sweep/walletsweep_test.go @@ -0,0 +1,409 @@ +package sweep + +import ( + "bytes" + "fmt" + "testing" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/lnwallet" +) + +// TestDetermineFeePerKw tests that given a fee preference, the +// DetermineFeePerKw will properly map it to a concrete fee in sat/kw. +func TestDetermineFeePerKw(t *testing.T) { + t.Parallel() + + defaultFee := lnwallet.SatPerKWeight(999) + relayFee := lnwallet.SatPerKWeight(300) + + feeEstimator := newMockFeeEstimator(defaultFee, relayFee) + + // We'll populate two items in the internal map which is used to query + // a fee based on a confirmation target: the default conf target, and + // an arbitrary conf target. We'll ensure below that both of these are + // properly + feeEstimator.blocksToFee[50] = 300 + feeEstimator.blocksToFee[defaultNumBlocksEstimate] = 1000 + + testCases := []struct { + // feePref is the target fee preference for this case. + feePref FeePreference + + // fee is the value the DetermineFeePerKw should return given + // the FeePreference above + fee lnwallet.SatPerKWeight + + // fail determines if this test case should fail or not. + fail bool + }{ + // A fee rate below the fee rate floor should output the floor. + { + feePref: FeePreference{ + FeeRate: lnwallet.SatPerKWeight(99), + }, + fee: lnwallet.FeePerKwFloor, + }, + + // A fee rate above the floor, should pass through and return + // the target fee rate. + { + feePref: FeePreference{ + FeeRate: 900, + }, + fee: 900, + }, + + // A specified confirmation target should cause the function to + // query the estimator which will return our value specified + // above. + { + feePref: FeePreference{ + ConfTarget: 50, + }, + fee: 300, + }, + + // If the caller doesn't specify any values at all, then we + // should query for the default conf target. + { + feePref: FeePreference{}, + fee: 1000, + }, + + // Both conf target and fee rate are set, we should return with + // an error. + { + feePref: FeePreference{ + ConfTarget: 50, + FeeRate: 90000, + }, + fee: 300, + fail: true, + }, + } + for i, testCase := range testCases { + targetFee, err := DetermineFeePerKw( + feeEstimator, testCase.feePref, + ) + switch { + case testCase.fail && err != nil: + continue + + case testCase.fail && err == nil: + t.Fatalf("expected failure for #%v", i) + + case !testCase.fail && err != nil: + t.Fatalf("unable to estimate fee; %v", err) + } + + if targetFee != testCase.fee { + t.Fatalf("#%v: wrong fee: expected %v got %v", i, + testCase.fee, targetFee) + } + } +} + +type mockUtxoSource struct { + outpoints map[wire.OutPoint]*wire.TxOut + + outputs []*lnwallet.Utxo +} + +func newMockUtxoSource(utxos []*lnwallet.Utxo) *mockUtxoSource { + m := &mockUtxoSource{ + outputs: utxos, + outpoints: make(map[wire.OutPoint]*wire.TxOut), + } + + for _, utxo := range utxos { + m.outpoints[utxo.OutPoint] = &wire.TxOut{ + Value: int64(utxo.Value), + PkScript: utxo.PkScript, + } + } + + return m +} + +func (m *mockUtxoSource) ListUnspentWitness(minConfs int32, + maxConfs int32) ([]*lnwallet.Utxo, error) { + + return m.outputs, nil +} + +func (m *mockUtxoSource) FetchInputInfo(op *wire.OutPoint) (*wire.TxOut, error) { + txOut, ok := m.outpoints[*op] + if !ok { + return nil, fmt.Errorf("no output found") + } + + return txOut, nil +} + +type mockCoinSelectionLocker struct { + fail bool +} + +func (m *mockCoinSelectionLocker) WithCoinSelectLock(f func() error) error { + if err := f(); err != nil { + return err + } + + if m.fail { + return fmt.Errorf("kek") + } + + return nil + +} + +type mockOutpointLocker struct { + lockedOutpoints map[wire.OutPoint]struct{} + + unlockedOutpoints map[wire.OutPoint]struct{} +} + +func newMockOutpointLocker() *mockOutpointLocker { + return &mockOutpointLocker{ + lockedOutpoints: make(map[wire.OutPoint]struct{}), + + unlockedOutpoints: make(map[wire.OutPoint]struct{}), + } +} + +func (m *mockOutpointLocker) LockOutpoint(o wire.OutPoint) { + m.lockedOutpoints[o] = struct{}{} +} +func (m *mockOutpointLocker) UnlockOutpoint(o wire.OutPoint) { + m.unlockedOutpoints[o] = struct{}{} +} + +var sweepScript = []byte{ + 0x0, 0x14, 0x64, 0x3d, 0x8b, 0x15, 0x69, 0x4a, 0x54, + 0x7d, 0x57, 0x33, 0x6e, 0x51, 0xdf, 0xfd, 0x38, 0xe3, + 0xe, 0x6e, 0xf8, 0xef, +} + +var deliveryAddr = func() btcutil.Address { + _, addrs, _, err := txscript.ExtractPkScriptAddrs( + sweepScript, &chaincfg.TestNet3Params, + ) + if err != nil { + panic(err) + } + + return addrs[0] +}() + +var testUtxos = []*lnwallet.Utxo{ + { + // A p2wkh output. + PkScript: []byte{ + 0x0, 0x14, 0x64, 0x3d, 0x8b, 0x15, 0x69, 0x4a, 0x54, + 0x7d, 0x57, 0x33, 0x6e, 0x51, 0xdf, 0xfd, 0x38, 0xe3, + 0xe, 0x6e, 0xf7, 0xef, + }, + Value: 1000, + OutPoint: wire.OutPoint{ + Index: 1, + }, + }, + + { + // A np2wkh output. + PkScript: []byte{ + 0xa9, 0x14, 0x97, 0x17, 0xf7, 0xd1, 0x5f, 0x6f, 0x8b, + 0x7, 0xe3, 0x58, 0x43, 0x19, 0xb9, 0x7e, 0xa9, 0x20, + 0x18, 0xc3, 0x17, 0xd7, 0x87, + }, + Value: 2000, + OutPoint: wire.OutPoint{ + Index: 2, + }, + }, + + // A p2wsh output. + { + PkScript: []byte{ + 0x0, 0x20, 0x70, 0x1a, 0x8d, 0x40, 0x1c, 0x84, 0xfb, 0x13, + 0xe6, 0xba, 0xf1, 0x69, 0xd5, 0x96, 0x84, 0xe2, 0x7a, 0xbd, + 0x9f, 0xa2, 0x16, 0xc8, 0xbc, 0x5b, 0x9f, 0xc6, 0x3d, 0x62, + 0x2f, 0xf8, 0xc5, 0x8c, + }, + Value: 3000, + OutPoint: wire.OutPoint{ + Index: 3, + }, + }, +} + +func assertUtxosLocked(t *testing.T, utxoLocker *mockOutpointLocker, + utxos []*lnwallet.Utxo) { + + t.Helper() + + for _, utxo := range utxos { + if _, ok := utxoLocker.lockedOutpoints[utxo.OutPoint]; !ok { + t.Fatalf("utxo %v was never locked", utxo.OutPoint) + } + } + +} + +func assertNoUtxosUnlocked(t *testing.T, utxoLocker *mockOutpointLocker, + utxos []*lnwallet.Utxo) { + + t.Helper() + + if len(utxoLocker.unlockedOutpoints) != 0 { + t.Fatalf("outputs have been locked, but shouldn't have been") + } +} + +func assertUtxosUnlocked(t *testing.T, utxoLocker *mockOutpointLocker, + utxos []*lnwallet.Utxo) { + + t.Helper() + + for _, utxo := range utxos { + if _, ok := utxoLocker.unlockedOutpoints[utxo.OutPoint]; !ok { + t.Fatalf("utxo %v was never unlocked", utxo.OutPoint) + } + } +} + +func assertUtxosLockedAndUnlocked(t *testing.T, utxoLocker *mockOutpointLocker, + utxos []*lnwallet.Utxo) { + + t.Helper() + + for _, utxo := range utxos { + if _, ok := utxoLocker.lockedOutpoints[utxo.OutPoint]; !ok { + t.Fatalf("utxo %v was never locked", utxo.OutPoint) + } + + if _, ok := utxoLocker.unlockedOutpoints[utxo.OutPoint]; !ok { + t.Fatalf("utxo %v was never unlocked", utxo.OutPoint) + } + } +} + +// TestCraftSweepAllTxCoinSelectFail tests that if coin selection fails, then +// we unlock any outputs we may have locked in the passed closure. +func TestCraftSweepAllTxCoinSelectFail(t *testing.T) { + t.Parallel() + + utxoSource := newMockUtxoSource(testUtxos) + coinSelectLocker := &mockCoinSelectionLocker{ + fail: true, + } + utxoLocker := newMockOutpointLocker() + + _, err := CraftSweepAllTx( + 0, 100, nil, coinSelectLocker, utxoSource, utxoLocker, nil, nil, + ) + + // Since we instructed the coin select locker to fail above, we should + // get an error. + if err == nil { + t.Fatalf("sweep tx should have failed: %v", err) + } + + // At this point, we'll now verify that all outputs were initially + // locked, and then also unlocked due to the failure. + assertUtxosLockedAndUnlocked(t, utxoLocker, testUtxos) +} + +// TestCraftSweepAllTxUnknownWitnessType tests that if one of the inputs we +// encounter is of an unknown witness type, then we fail and unlock any prior +// locked outputs. +func TestCraftSweepAllTxUnknownWitnessType(t *testing.T) { + t.Parallel() + + utxoSource := newMockUtxoSource(testUtxos) + coinSelectLocker := &mockCoinSelectionLocker{} + utxoLocker := newMockOutpointLocker() + + _, err := CraftSweepAllTx( + 0, 100, nil, coinSelectLocker, utxoSource, utxoLocker, nil, nil, + ) + + // Since passed in a p2wsh output, which is unknown, we should fail to + // map the output to a witness type. + if err == nil { + t.Fatalf("sweep tx should have failed: %v", err) + } + + // At this point, we'll now verify that all outputs were initially + // locked, and then also unlocked since we weren't able to find a + // witness type for the last output. + assertUtxosLockedAndUnlocked(t, utxoLocker, testUtxos) +} + +// TestCraftSweepAllTx tests that we'll properly lock all available outputs +// within the wallet, and craft a single sweep transaction that pays to the +// target output. +func TestCraftSweepAllTx(t *testing.T) { + t.Parallel() + + // First, we'll make a mock signer along with a fee estimator, We'll + // use zero fees to we can assert a precise output value. + signer := &mockSigner{} + feeEstimator := newMockFeeEstimator(0, 0) + + // For our UTXO source, we'll pass in all the UTXOs that we know of, + // other than the final one which is of an unknown witness type. + targetUTXOs := testUtxos[:2] + utxoSource := newMockUtxoSource(targetUTXOs) + coinSelectLocker := &mockCoinSelectionLocker{} + utxoLocker := newMockOutpointLocker() + + sweepPkg, err := CraftSweepAllTx( + 0, 100, deliveryAddr, coinSelectLocker, utxoSource, utxoLocker, + feeEstimator, signer, + ) + if err != nil { + t.Fatalf("unable to make sweep tx: %v", err) + } + + // At this point, all of the UTXOs that we made above should be locked + // and none of them unlocked. + assertUtxosLocked(t, utxoLocker, testUtxos[:2]) + assertNoUtxosUnlocked(t, utxoLocker, testUtxos[:2]) + + // Now that we have our sweep transaction, we should find that we have + // a UTXO for each input, and also that our final output value is the + // sum of all our inputs. + sweepTx := sweepPkg.SweepTx + if len(sweepTx.TxIn) != len(targetUTXOs) { + t.Fatalf("expected %v utxo, got %v", len(targetUTXOs), + len(sweepTx.TxIn)) + } + + // We should have a single output that pays to our sweep script + // generated above. + expectedSweepValue := int64(3000) + if len(sweepTx.TxOut) != 1 { + t.Fatalf("should have %v outputs, instead have %v", 1, + len(sweepTx.TxOut)) + } + output := sweepTx.TxOut[0] + switch { + case output.Value != expectedSweepValue: + t.Fatalf("expected %v sweep value, instead got %v", + expectedSweepValue, output.Value) + + case !bytes.Equal(sweepScript, output.PkScript): + t.Fatalf("expected %x sweep script, instead got %x", sweepScript, + output.PkScript) + } + + // If we cancel the sweep attempt, then we should find that all the + // UTXOs within the sweep transaction are now unlocked. + sweepPkg.CancelSweepAttempt() + assertUtxosUnlocked(t, utxoLocker, testUtxos[:2]) +} From e140cbb945e5c5e8ba64bca8cd3e82ef2cdb76f2 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Mon, 24 Dec 2018 16:05:48 -0600 Subject: [PATCH 13/13] test: add integration test for sweeping all coins from wallet --- lnd_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/lnd_test.go b/lnd_test.go index f07cde4a3..4076cc3aa 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -12489,12 +12489,95 @@ func testAbandonChannel(net *lntest.NetworkHarness, t *harnessTest) { cleanupForceClose(t, net, net.Bob, chanPoint) } +// testSweepAllCoins tests that we're able to properly sweep all coins from the +// wallet into a single target address at the specified fee rate. +func testSweepAllCoins(net *lntest.NetworkHarness, t *harnessTest) { + ctxb := context.Background() + + // First, we'll make a new node, ainz who'll we'll use to test wallet + // sweeping. + ainz, err := net.NewNode("Ainz", nil) + if err != nil { + t.Fatalf("unable to create new node: %v", err) + } + defer shutdownAndAssert(net, t, ainz) + + // Next, we'll give Ainz exactly 2 utxos of 1 BTC each, with one of + // them being p2wkh and the other being a n2wpkh address. + ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) + err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, ainz) + if err != nil { + t.Fatalf("unable to send coins to eve: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.SendCoinsNP2WKH(ctxt, btcutil.SatoshiPerBitcoin, ainz) + if err != nil { + t.Fatalf("unable to send coins to eve: %v", err) + } + + // With the two coins above mined, we'll now instruct ainz to sweep all + // the coins to an external address not under its control. + minerAddr, err := net.Miner.NewAddress() + if err != nil { + t.Fatalf("unable to create new miner addr: %v", err) + } + + sweepReq := &lnrpc.SendCoinsRequest{ + Addr: minerAddr.String(), + SendAll: true, + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + _, err = ainz.SendCoins(ctxt, sweepReq) + if err != nil { + t.Fatalf("unable to sweep coins: %v", err) + } + + // We'll mine a block wish should include the sweep transaction we + // generated above. + block := mineBlocks(t, net, 1, 1)[0] + + // The sweep transaction should have exactly two inputs as we only had + // two UTXOs in the wallet. + sweepTx := block.Transactions[1] + if len(sweepTx.TxIn) != 2 { + t.Fatalf("expected 2 inputs instead have %v", len(sweepTx.TxIn)) + } + + // Finally, Ainz should now have no coins at all within his wallet. + balReq := &lnrpc.WalletBalanceRequest{} + resp, err := ainz.WalletBalance(ctxt, balReq) + if err != nil { + t.Fatalf("unable to get ainz's balance: %v", err) + } + switch { + case resp.ConfirmedBalance != 0: + t.Fatalf("expected no confirmed balance, instead have %v", + resp.ConfirmedBalance) + + case resp.UnconfirmedBalance != 0: + t.Fatalf("expected no unconfirmed balance, instead have %v", + resp.UnconfirmedBalance) + } + + // If we try again, but this time specifying an amount, then the call + // should fail. + sweepReq.Amount = 10000 + _, err = ainz.SendCoins(ctxt, sweepReq) + if err == nil { + t.Fatalf("sweep attempt should fail") + } +} + type testCase struct { name string test func(net *lntest.NetworkHarness, t *harnessTest) } var testsCases = []*testCase{ + { + name: "sweep coins", + test: testSweepAllCoins, + }, { name: "onchain fund recovery", test: testOnchainFundRecovery,