Merge pull request #1017 from halseth/contract-court-without-on-chain
Contract court acting on confirmed chain events
This commit is contained in:
commit
86fd9e361e
@ -696,6 +696,22 @@ func (b *breachArbiter) breachObserver(
|
||||
brarLog.Debugf("Breach observer for ChannelPoint(%v) started ",
|
||||
chanPoint)
|
||||
|
||||
gracefullyExit := func() {
|
||||
// Launch a goroutine to cancel out this contract within the
|
||||
// breachArbiter's main goroutine.
|
||||
b.wg.Add(1)
|
||||
go func() {
|
||||
defer b.wg.Done()
|
||||
|
||||
select {
|
||||
case b.settledContracts <- chanPoint:
|
||||
case <-b.quit:
|
||||
}
|
||||
}()
|
||||
|
||||
b.cfg.CloseLink(&chanPoint, htlcswitch.CloseBreach)
|
||||
}
|
||||
|
||||
select {
|
||||
// A read from this channel indicates that the contract has been
|
||||
// settled cooperatively so we exit as our duties are no longer needed.
|
||||
@ -704,36 +720,14 @@ func (b *breachArbiter) breachObserver(
|
||||
|
||||
// The channel has been closed cooperatively, so we're done here.
|
||||
case <-chainEvents.CooperativeClosure:
|
||||
// Launch a goroutine to cancel out this contract within the
|
||||
// breachArbiter's main goroutine.
|
||||
b.wg.Add(1)
|
||||
go func() {
|
||||
defer b.wg.Done()
|
||||
|
||||
select {
|
||||
case b.settledContracts <- chanPoint:
|
||||
case <-b.quit:
|
||||
}
|
||||
}()
|
||||
|
||||
b.cfg.CloseLink(&chanPoint, htlcswitch.CloseBreach)
|
||||
gracefullyExit()
|
||||
|
||||
// The channel has been closed by a normal means: force closing with
|
||||
// the latest commitment transaction.
|
||||
case <-chainEvents.UnilateralClosure:
|
||||
// Launch a goroutine to cancel out this contract within the
|
||||
// breachArbiter's main goroutine.
|
||||
b.wg.Add(1)
|
||||
go func() {
|
||||
defer b.wg.Done()
|
||||
|
||||
select {
|
||||
case b.settledContracts <- chanPoint:
|
||||
case <-b.quit:
|
||||
}
|
||||
}()
|
||||
|
||||
b.cfg.CloseLink(&chanPoint, htlcswitch.CloseBreach)
|
||||
case <-chainEvents.LocalUnilateralClosure:
|
||||
gracefullyExit()
|
||||
case <-chainEvents.RemoteUnilateralClosure:
|
||||
gracefullyExit()
|
||||
|
||||
// A read from this channel indicates that a channel breach has been
|
||||
// detected! So we notify the main coordination goroutine with the
|
||||
|
@ -951,11 +951,12 @@ func TestBreachHandoffSuccess(t *testing.T) {
|
||||
// Instantiate a breach arbiter to handle the breach of alice's channel.
|
||||
alicePoint := alice.ChannelPoint()
|
||||
spendEvents := contractcourt.ChainEventSubscription{
|
||||
UnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
ProcessACK: make(chan error, 1),
|
||||
ChanPoint: *alicePoint,
|
||||
RemoteUnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
LocalUnilateralClosure: make(chan *contractcourt.LocalUnilateralCloseInfo, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
ProcessACK: make(chan error, 1),
|
||||
ChanPoint: *alicePoint,
|
||||
Cancel: func() {
|
||||
},
|
||||
}
|
||||
@ -1039,11 +1040,12 @@ func TestBreachHandoffFail(t *testing.T) {
|
||||
// Instantiate a breach arbiter to handle the breach of alice's channel.
|
||||
alicePoint := alice.ChannelPoint()
|
||||
spendEvents := contractcourt.ChainEventSubscription{
|
||||
UnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
ProcessACK: make(chan error, 1),
|
||||
ChanPoint: *alicePoint,
|
||||
RemoteUnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
LocalUnilateralClosure: make(chan *contractcourt.LocalUnilateralCloseInfo, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
ProcessACK: make(chan error, 1),
|
||||
ChanPoint: *alicePoint,
|
||||
Cancel: func() {
|
||||
},
|
||||
}
|
||||
|
@ -285,6 +285,38 @@ type ChannelCommitment struct {
|
||||
// * lets just walk through
|
||||
}
|
||||
|
||||
// ChannelStatus is used to indicate whether an OpenChannel is in the default
|
||||
// usable state, or a state where it shouldn't be used.
|
||||
type ChannelStatus uint8
|
||||
|
||||
var (
|
||||
// Default is the normal state of an open channel.
|
||||
Default ChannelStatus = 0
|
||||
|
||||
// Borked indicates that the channel has entered an irreconcilable
|
||||
// state, triggered by a state desynchronization or channel breach.
|
||||
// Channels in this state should never be added to the htlc switch.
|
||||
Borked ChannelStatus = 1
|
||||
|
||||
// CommitmentBroadcasted indicates that a commitment for this channel
|
||||
// has been broadcasted.
|
||||
CommitmentBroadcasted ChannelStatus = 2
|
||||
)
|
||||
|
||||
// String returns a human-readable representation of the ChannelStatus.
|
||||
func (c ChannelStatus) String() string {
|
||||
switch c {
|
||||
case Default:
|
||||
return "Default"
|
||||
case Borked:
|
||||
return "Borked"
|
||||
case CommitmentBroadcasted:
|
||||
return "CommitmentBroadcasted"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// OpenChannel encapsulates the persistent and dynamic state of an open channel
|
||||
// with a remote node. An open channel supports several options for on-disk
|
||||
// serialization depending on the exact context. Full (upon channel creation)
|
||||
@ -322,10 +354,9 @@ type OpenChannel struct {
|
||||
// negotiate fees, or close the channel.
|
||||
IsInitiator bool
|
||||
|
||||
// IsBorked indicates that the channel has entered an irreconcilable
|
||||
// state, triggered by a state desynchronization or channel breach.
|
||||
// Channels in this state should never be added to the htlc switch.
|
||||
IsBorked bool
|
||||
// ChanStatus is the current status of this channel. If it is not in
|
||||
// the state Default, it should not be used for forwarding payments.
|
||||
ChanStatus ChannelStatus
|
||||
|
||||
// FundingBroadcastHeight is the height in which the funding
|
||||
// transaction was broadcast. This value can be used by higher level
|
||||
@ -571,6 +602,20 @@ func (c *OpenChannel) MarkBorked() error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
return c.putChanStatus(Borked)
|
||||
}
|
||||
|
||||
// MarkCommitmentBroadcasted marks the channel as a commitment transaction has
|
||||
// been broadcast, either our own or the remote, and we should watch the chain
|
||||
// for it to confirm before taking any further action.
|
||||
func (c *OpenChannel) MarkCommitmentBroadcasted() error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
return c.putChanStatus(CommitmentBroadcasted)
|
||||
}
|
||||
|
||||
func (c *OpenChannel) putChanStatus(status ChannelStatus) error {
|
||||
if err := c.Db.Update(func(tx *bolt.Tx) error {
|
||||
chanBucket, err := updateChanBucket(tx, c.IdentityPub,
|
||||
&c.FundingOutpoint, c.ChainHash)
|
||||
@ -583,14 +628,15 @@ func (c *OpenChannel) MarkBorked() error {
|
||||
return err
|
||||
}
|
||||
|
||||
channel.IsBorked = true
|
||||
channel.ChanStatus = status
|
||||
|
||||
return putOpenChannel(chanBucket, channel)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.IsBorked = true
|
||||
// Update the in-memory representation to keep it in sync with the DB.
|
||||
c.ChanStatus = status
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1478,8 +1524,8 @@ func (c *OpenChannel) FindPreviousState(updateNum uint64) (*ChannelCommitment, e
|
||||
}
|
||||
|
||||
// ClosureType is an enum like structure that details exactly _how_ a channel
|
||||
// was closed. Three closure types are currently possible: cooperative, force,
|
||||
// and breach.
|
||||
// was closed. Three closure types are currently possible: none, cooperative,
|
||||
// local force close, remote force close, and (remote) breach.
|
||||
type ClosureType uint8
|
||||
|
||||
const (
|
||||
@ -1487,21 +1533,25 @@ const (
|
||||
// cooperatively. This means that both channel peers were online and
|
||||
// signed a new transaction paying out the settled balance of the
|
||||
// contract.
|
||||
CooperativeClose ClosureType = iota
|
||||
CooperativeClose ClosureType = 0
|
||||
|
||||
// ForceClose indicates that one peer unilaterally broadcast their
|
||||
// LocalForceClose indicates that we have unilaterally broadcast our
|
||||
// current commitment state on-chain.
|
||||
ForceClose
|
||||
LocalForceClose ClosureType = 1
|
||||
|
||||
// BreachClose indicates that one peer attempted to broadcast a prior
|
||||
// _revoked_ channel state.
|
||||
BreachClose
|
||||
// RemoteForceClose indicates that the remote peer has unilaterally
|
||||
// broadcast their current commitment state on-chain.
|
||||
RemoteForceClose ClosureType = 4
|
||||
|
||||
// BreachClose indicates that the remote peer attempted to broadcast a
|
||||
// prior _revoked_ channel state.
|
||||
BreachClose ClosureType = 2
|
||||
|
||||
// FundingCanceled indicates that the channel never was fully opened
|
||||
// before it was marked as closed in the database. This can happen if
|
||||
// we or the remote fail at some point during the opening workflow, or
|
||||
// we timeout waiting for the funding transaction to be confirmed.
|
||||
FundingCanceled
|
||||
FundingCanceled ClosureType = 3
|
||||
)
|
||||
|
||||
// ChannelCloseSummary contains the final state of a channel at the point it
|
||||
@ -1549,8 +1599,9 @@ type ChannelCloseSummary struct {
|
||||
// outstanding outgoing HTLC's at the time of channel closure.
|
||||
TimeLockedBalance btcutil.Amount
|
||||
|
||||
// CloseType details exactly _how_ the channel was closed. Three
|
||||
// closure types are possible: cooperative, force, and breach.
|
||||
// CloseType details exactly _how_ the channel was closed. Five closure
|
||||
// types are possible: cooperative, local force, remote force, breach
|
||||
// and funding canceled.
|
||||
CloseType ClosureType
|
||||
|
||||
// IsPending indicates whether this channel is in the 'pending close'
|
||||
@ -1804,7 +1855,7 @@ func putChanInfo(chanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||
if err := writeElements(&w,
|
||||
channel.ChanType, channel.ChainHash, channel.FundingOutpoint,
|
||||
channel.ShortChanID, channel.IsPending, channel.IsInitiator,
|
||||
channel.IsBorked, channel.FundingBroadcastHeight,
|
||||
channel.ChanStatus, channel.FundingBroadcastHeight,
|
||||
channel.NumConfsRequired, channel.ChannelFlags,
|
||||
channel.IdentityPub, channel.Capacity, channel.TotalMSatSent,
|
||||
channel.TotalMSatReceived,
|
||||
@ -1912,7 +1963,7 @@ func fetchChanInfo(chanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||
if err := readElements(r,
|
||||
&channel.ChanType, &channel.ChainHash, &channel.FundingOutpoint,
|
||||
&channel.ShortChanID, &channel.IsPending, &channel.IsInitiator,
|
||||
&channel.IsBorked, &channel.FundingBroadcastHeight,
|
||||
&channel.ChanStatus, &channel.FundingBroadcastHeight,
|
||||
&channel.NumConfsRequired, &channel.ChannelFlags,
|
||||
&channel.IdentityPub, &channel.Capacity, &channel.TotalMSatSent,
|
||||
&channel.TotalMSatReceived,
|
||||
|
@ -606,7 +606,7 @@ func TestChannelStateTransition(t *testing.T) {
|
||||
SettledBalance: btcutil.Amount(500),
|
||||
TimeLockedBalance: btcutil.Amount(10000),
|
||||
IsPending: false,
|
||||
CloseType: ForceClose,
|
||||
CloseType: RemoteForceClose,
|
||||
}
|
||||
if err := updatedChannel[0].CloseChannel(closeSummary); err != nil {
|
||||
t.Fatalf("unable to delete updated channel: %v", err)
|
||||
@ -770,7 +770,7 @@ func TestFetchClosedChannels(t *testing.T) {
|
||||
Capacity: state.Capacity,
|
||||
SettledBalance: state.LocalCommitment.LocalBalance.ToSatoshis(),
|
||||
TimeLockedBalance: state.RemoteCommitment.LocalBalance.ToSatoshis() + 10000,
|
||||
CloseType: ForceClose,
|
||||
CloseType: RemoteForceClose,
|
||||
IsPending: true,
|
||||
}
|
||||
if err := state.CloseChannel(summary); err != nil {
|
||||
|
@ -148,10 +148,16 @@ func writeElement(w io.Writer, element interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
case ChannelStatus:
|
||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case ClosureType:
|
||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case lnwire.FundingFlag:
|
||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||
return err
|
||||
@ -321,10 +327,16 @@ func readElement(r io.Reader, element interface{}) error {
|
||||
|
||||
*e = msg
|
||||
|
||||
case *ChannelStatus:
|
||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *ClosureType:
|
||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *lnwire.FundingFlag:
|
||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||
return err
|
||||
|
@ -312,23 +312,60 @@ func (d *DB) fetchNodeChannels(chainBucket *bolt.Bucket) ([]*OpenChannel, error)
|
||||
}
|
||||
|
||||
// FetchAllChannels attempts to retrieve all open channels currently stored
|
||||
// within the database.
|
||||
// within the database, including pending open, fully open and channels waiting
|
||||
// for a closing transaction to confirm.
|
||||
func (d *DB) FetchAllChannels() ([]*OpenChannel, error) {
|
||||
return fetchChannels(d, false)
|
||||
var channels []*OpenChannel
|
||||
|
||||
// TODO(halseth): fetch all in one db tx.
|
||||
openChannels, err := d.FetchAllOpenChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
channels = append(channels, openChannels...)
|
||||
|
||||
pendingChannels, err := d.FetchPendingChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
channels = append(channels, pendingChannels...)
|
||||
|
||||
waitingClose, err := d.FetchWaitingCloseChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
channels = append(channels, waitingClose...)
|
||||
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
// FetchAllOpenChannels will return all channels that have the funding
|
||||
// transaction confirmed, and is not waiting for a closing transaction to be
|
||||
// confirmed.
|
||||
func (d *DB) FetchAllOpenChannels() ([]*OpenChannel, error) {
|
||||
return fetchChannels(d, false, false)
|
||||
}
|
||||
|
||||
// FetchPendingChannels will return channels that have completed the process of
|
||||
// generating and broadcasting funding transactions, but whose funding
|
||||
// transactions have yet to be confirmed on the blockchain.
|
||||
func (d *DB) FetchPendingChannels() ([]*OpenChannel, error) {
|
||||
return fetchChannels(d, true)
|
||||
return fetchChannels(d, true, false)
|
||||
}
|
||||
|
||||
// FetchWaitingCloseChannels will return all channels that have been opened,
|
||||
// but now is waiting for a closing transaction to be confirmed.
|
||||
func (d *DB) FetchWaitingCloseChannels() ([]*OpenChannel, error) {
|
||||
return fetchChannels(d, false, true)
|
||||
}
|
||||
|
||||
// fetchChannels attempts to retrieve channels currently stored in the
|
||||
// database. The pendingOnly parameter determines whether only pending channels
|
||||
// will be returned. If no active channels exist within the network, then
|
||||
// ErrNoActiveChannels is returned.
|
||||
func fetchChannels(d *DB, pendingOnly bool) ([]*OpenChannel, error) {
|
||||
// database. The pending parameter determines whether only pending channels
|
||||
// will be returned, or only open channels will be returned. The waitingClose
|
||||
// parameter determines wheter only channels waiting for a closing transaction
|
||||
// to be confirmed should be returned. If no active channels exist within the
|
||||
// network, then ErrNoActiveChannels is returned.
|
||||
func fetchChannels(d *DB, pending, waitingClose bool) ([]*OpenChannel, error) {
|
||||
var channels []*OpenChannel
|
||||
|
||||
err := d.View(func(tx *bolt.Tx) error {
|
||||
@ -377,23 +414,36 @@ func fetchChannels(d *DB, pendingOnly bool) ([]*OpenChannel, error) {
|
||||
"channel for chain_hash=%x, "+
|
||||
"node_key=%x: %v", chainHash[:], k, err)
|
||||
}
|
||||
// TODO(roasbeef): simplify
|
||||
if pendingOnly {
|
||||
for _, channel := range nodeChans {
|
||||
if channel.IsPending {
|
||||
channels = append(channels, channel)
|
||||
}
|
||||
for _, channel := range nodeChans {
|
||||
if channel.IsPending != pending {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
channels = append(channels, nodeChans...)
|
||||
|
||||
// If the channel is in any other state
|
||||
// than Default, then it means it is
|
||||
// waiting to be closed.
|
||||
channelWaitingClose :=
|
||||
channel.ChanStatus != Default
|
||||
|
||||
// Only include it if we requested
|
||||
// channels with the same waitingClose
|
||||
// status.
|
||||
if channelWaitingClose != waitingClose {
|
||||
continue
|
||||
}
|
||||
|
||||
channels = append(channels, channel)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return channels, err
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
// FetchClosedChannels attempts to fetch all closed channels from the database.
|
||||
|
@ -112,13 +112,19 @@ const (
|
||||
// so yet.
|
||||
StateBroadcastCommit ArbitratorState = 1
|
||||
|
||||
// StateCommitmentBroadcasted is a state that indicates that the
|
||||
// attendant has broadcasted the commitment transaction, and is now
|
||||
// waiting for it to confirm.
|
||||
StateCommitmentBroadcasted ArbitratorState = 6
|
||||
|
||||
// StateContractClosed is a state that indicates the contract has
|
||||
// already been "closed". At this point, we can now examine our active
|
||||
// contracts, in order to create the proper resolver for each one.
|
||||
// already been "closed", meaning the commitment is confirmed on chain.
|
||||
// At this point, we can now examine our active contracts, in order to
|
||||
// create the proper resolver for each one.
|
||||
StateContractClosed ArbitratorState = 2
|
||||
|
||||
// StateWaitingFullResolution is a state that indicates that the
|
||||
// commitment transaction has been broadcast, and the attendant is now
|
||||
// commitment transaction has been confirmed, and the attendant is now
|
||||
// waiting for all unresolved contracts to be fully resolved.
|
||||
StateWaitingFullResolution ArbitratorState = 3
|
||||
|
||||
@ -142,6 +148,9 @@ func (a ArbitratorState) String() string {
|
||||
case StateBroadcastCommit:
|
||||
return "StateBroadcastCommit"
|
||||
|
||||
case StateCommitmentBroadcasted:
|
||||
return "StateCommitmentBroadcasted"
|
||||
|
||||
case StateContractClosed:
|
||||
return "StateContractClosed"
|
||||
|
||||
|
@ -231,14 +231,9 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
|
||||
|
||||
return chanMachine.ForceClose()
|
||||
},
|
||||
CloseChannel: func(summary *channeldb.ChannelCloseSummary) error {
|
||||
log.Tracef("ChannelArbitrator(%v): closing "+
|
||||
"channel", chanPoint)
|
||||
|
||||
return channel.CloseChannel(summary)
|
||||
},
|
||||
ChainArbitratorConfig: c.cfg,
|
||||
ChainEvents: chanEvents,
|
||||
MarkCommitmentBroadcasted: channel.MarkCommitmentBroadcasted,
|
||||
ChainArbitratorConfig: c.cfg,
|
||||
ChainEvents: chanEvents,
|
||||
}
|
||||
|
||||
// The final component needed is an arbitrator log that the arbitrator
|
||||
|
@ -16,6 +16,13 @@ import (
|
||||
"github.com/roasbeef/btcutil"
|
||||
)
|
||||
|
||||
// LocalUnilateralCloseInfo encapsulates all the informnation we need to act
|
||||
// on a local force close that gets confirmed.
|
||||
type LocalUnilateralCloseInfo struct {
|
||||
*chainntnfs.SpendDetail
|
||||
*lnwallet.LocalForceCloseSummary
|
||||
}
|
||||
|
||||
// ChainEventSubscription is a struct that houses a subscription to be notified
|
||||
// for any on-chain events related to a channel. There are three types of
|
||||
// possible on-chain events: a cooperative channel closure, a unilateral
|
||||
@ -25,13 +32,16 @@ type ChainEventSubscription struct {
|
||||
// ChanPoint is that channel that chain events will be dispatched for.
|
||||
ChanPoint wire.OutPoint
|
||||
|
||||
// UnilateralClosure is a channel that will be sent upon in the event that
|
||||
// the remote party broadcasts their latest version of the commitment
|
||||
// transaction.
|
||||
UnilateralClosure chan *lnwallet.UnilateralCloseSummary
|
||||
// RemoteUnilateralClosure is a channel that will be sent upon in the
|
||||
// event that the remote party's commitment transaction is confirmed.
|
||||
RemoteUnilateralClosure chan *lnwallet.UnilateralCloseSummary
|
||||
|
||||
// CooperativeClosure is a signal that will be sent upon once a cooperative
|
||||
// channel closure has been detected.
|
||||
// LocalUnilateralClosure is a channel that will be sent upon in the
|
||||
// event that our commitment transaction is confirmed.
|
||||
LocalUnilateralClosure chan *LocalUnilateralCloseInfo
|
||||
|
||||
// CooperativeClosure is a signal that will be sent upon once a
|
||||
// cooperative channel closure has been detected confirmed.
|
||||
//
|
||||
// TODO(roasbeef): or something else
|
||||
CooperativeClosure chan struct{}
|
||||
@ -180,7 +190,7 @@ func (c *chainWatcher) Start() error {
|
||||
}
|
||||
|
||||
spendNtfn, err := c.notifier.RegisterSpendNtfn(
|
||||
fundingOut, heightHint, true,
|
||||
fundingOut, heightHint, false,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -226,10 +236,11 @@ func (c *chainWatcher) SubscribeChannelEvents(syncDispatch bool) *ChainEventSubs
|
||||
clientID, c.chanState.FundingOutpoint)
|
||||
|
||||
sub := &ChainEventSubscription{
|
||||
ChanPoint: c.chanState.FundingOutpoint,
|
||||
UnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
ChanPoint: c.chanState.FundingOutpoint,
|
||||
RemoteUnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
LocalUnilateralClosure: make(chan *LocalUnilateralCloseInfo, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
Cancel: func() {
|
||||
c.Lock()
|
||||
delete(c.clientSubscriptions, clientID)
|
||||
@ -240,6 +251,30 @@ func (c *chainWatcher) SubscribeChannelEvents(syncDispatch bool) *ChainEventSubs
|
||||
|
||||
if syncDispatch {
|
||||
sub.ProcessACK = make(chan error, 1)
|
||||
|
||||
// If this client is syncDispatch, we cannot safely delete it
|
||||
// from our list of clients. This is because of a potential
|
||||
// race at shutdown, where the client shuts down and calls
|
||||
// Cancel(). In this case we must make sure the ChainWatcher
|
||||
// doesn't think it has successfully handed off a contract
|
||||
// breach to the client. We start a goroutine that will send an
|
||||
// error on the ProcessACK channel until the ChainWatcher is
|
||||
// shutdown.
|
||||
sub.Cancel = func() {
|
||||
c.wg.Add(1)
|
||||
go func() {
|
||||
defer c.wg.Done()
|
||||
|
||||
err := fmt.Errorf("cancelled")
|
||||
for {
|
||||
select {
|
||||
case sub.ProcessACK <- err:
|
||||
case <-c.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
@ -307,6 +342,13 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
|
||||
&commitmentHash,
|
||||
)
|
||||
if isOurCommitment {
|
||||
if err := c.dispatchLocalForceClose(
|
||||
commitSpend, *localCommit,
|
||||
); err != nil {
|
||||
log.Errorf("unable to handle local"+
|
||||
"close for chan_point=%v: %v",
|
||||
c.chanState.FundingOutpoint, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -349,7 +391,7 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
|
||||
// has a fail crash _after_ accepting the new state,
|
||||
// but _before_ sending their signature to us.
|
||||
case broadcastStateNum >= remoteStateNum:
|
||||
if err := c.dispatchRemoteClose(
|
||||
if err := c.dispatchRemoteForceClose(
|
||||
commitSpend, *remoteCommit,
|
||||
); err != nil {
|
||||
log.Errorf("unable to handle remote "+
|
||||
@ -500,12 +542,77 @@ func (c *chainWatcher) dispatchCooperativeClose(commitSpend *chainntnfs.SpendDet
|
||||
|
||||
}
|
||||
|
||||
// dispatchRemoteClose processes a detected unilateral channel closure by the
|
||||
// dispatchLocalForceClose processes a unilateral close by us being confirmed.
|
||||
func (c *chainWatcher) dispatchLocalForceClose(
|
||||
commitSpend *chainntnfs.SpendDetail,
|
||||
localCommit channeldb.ChannelCommitment) error {
|
||||
|
||||
log.Infof("Local unilateral close of ChannelPoint(%v) "+
|
||||
"detected", c.chanState.FundingOutpoint)
|
||||
|
||||
forceClose, err := lnwallet.NewLocalForceCloseSummary(
|
||||
c.chanState, c.signer, c.pCache, commitSpend.SpendingTx,
|
||||
localCommit,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// As we've detected that the channel has been closed, immediately
|
||||
// delete the state from disk, creating a close summary for future
|
||||
// usage by related sub-systems.
|
||||
chanSnapshot := forceClose.ChanSnapshot
|
||||
closeSummary := &channeldb.ChannelCloseSummary{
|
||||
ChanPoint: chanSnapshot.ChannelPoint,
|
||||
ChainHash: chanSnapshot.ChainHash,
|
||||
ClosingTXID: forceClose.CloseTx.TxHash(),
|
||||
RemotePub: &chanSnapshot.RemoteIdentity,
|
||||
Capacity: chanSnapshot.Capacity,
|
||||
CloseType: channeldb.LocalForceClose,
|
||||
IsPending: true,
|
||||
ShortChanID: c.chanState.ShortChanID,
|
||||
CloseHeight: uint32(commitSpend.SpendingHeight),
|
||||
}
|
||||
|
||||
// If our commitment output isn't dust or we have active HTLC's on the
|
||||
// commitment transaction, then we'll populate the balances on the
|
||||
// close channel summary.
|
||||
if forceClose.CommitResolution != nil {
|
||||
closeSummary.SettledBalance = chanSnapshot.LocalBalance.ToSatoshis()
|
||||
closeSummary.TimeLockedBalance = chanSnapshot.LocalBalance.ToSatoshis()
|
||||
}
|
||||
for _, htlc := range forceClose.HtlcResolutions.OutgoingHTLCs {
|
||||
htlcValue := btcutil.Amount(htlc.SweepSignDesc.Output.Value)
|
||||
closeSummary.TimeLockedBalance += htlcValue
|
||||
}
|
||||
err = c.chanState.CloseChannel(closeSummary)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to delete channel state: %v", err)
|
||||
}
|
||||
|
||||
// With the event processed, we'll now notify all subscribers of the
|
||||
// event.
|
||||
closeInfo := &LocalUnilateralCloseInfo{commitSpend, forceClose}
|
||||
c.Lock()
|
||||
for _, sub := range c.clientSubscriptions {
|
||||
select {
|
||||
case sub.LocalUnilateralClosure <- closeInfo:
|
||||
case <-c.quit:
|
||||
c.Unlock()
|
||||
return fmt.Errorf("exiting")
|
||||
}
|
||||
}
|
||||
c.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// dispatchRemoteForceClose processes a detected unilateral channel closure by the
|
||||
// remote party. This function will prepare a UnilateralCloseSummary which will
|
||||
// then be sent to any subscribers allowing them to resolve all our funds in
|
||||
// the channel on chain. Once this close summary is prepared, all registered
|
||||
// subscribers will receive a notification of this event.
|
||||
func (c *chainWatcher) dispatchRemoteClose(commitSpend *chainntnfs.SpendDetail,
|
||||
func (c *chainWatcher) dispatchRemoteForceClose(commitSpend *chainntnfs.SpendDetail,
|
||||
remoteCommit channeldb.ChannelCommitment) error {
|
||||
|
||||
log.Infof("Unilateral close of ChannelPoint(%v) "+
|
||||
@ -538,7 +645,7 @@ func (c *chainWatcher) dispatchRemoteClose(commitSpend *chainntnfs.SpendDetail,
|
||||
// * get ACK from the consumer of the ntfn before writing to disk?
|
||||
// * no harm in repeated ntfns: at least once semantics
|
||||
select {
|
||||
case sub.UnilateralClosure <- uniClose:
|
||||
case sub.RemoteUnilateralClosure <- uniClose:
|
||||
case <-c.quit:
|
||||
c.Unlock()
|
||||
return fmt.Errorf("exiting")
|
||||
|
@ -10,9 +10,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
"github.com/roasbeef/btcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -91,11 +89,9 @@ type ChannelArbitratorConfig struct {
|
||||
// eventually resolve all outputs on chain.
|
||||
ForceCloseChan func() (*lnwallet.LocalForceCloseSummary, error)
|
||||
|
||||
// CloseChannel is a function closure that marks a channel under watch
|
||||
// as "closing". In this phase, we will no longer accept any updates to
|
||||
// the channel as the commitment transaction has been broadcast, and
|
||||
// possibly fully confirmed.
|
||||
CloseChannel func(*channeldb.ChannelCloseSummary) error
|
||||
// MarkCommitmentBroadcasted should mark the channel as the commitment
|
||||
// being broadcast, and we are waiting for the commitment to confirm.
|
||||
MarkCommitmentBroadcasted func() error
|
||||
|
||||
// MarkChannelResolved is a function closure that serves to mark a
|
||||
// channel as "fully resolved". A channel itself can be considered
|
||||
@ -239,7 +235,7 @@ func (c *ChannelArbitrator) Start() error {
|
||||
log.Infof("ChannelArbitrator(%v): starting state=%v", c.cfg.ChanPoint,
|
||||
c.state)
|
||||
|
||||
bestHash, bestHeight, err := c.cfg.ChainIO.GetBestBlock()
|
||||
_, bestHeight, err := c.cfg.ChainIO.GetBestBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -248,7 +244,7 @@ func (c *ChannelArbitrator) Start() error {
|
||||
// on-chain state, and our set of active contracts.
|
||||
startingState := c.state
|
||||
nextState, _, err := c.advanceState(
|
||||
uint32(bestHeight), bestHash, chainTrigger, nil,
|
||||
uint32(bestHeight), chainTrigger, nil,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -280,7 +276,7 @@ func (c *ChannelArbitrator) Start() error {
|
||||
// TODO(roasbeef): cancel if breached
|
||||
|
||||
c.wg.Add(1)
|
||||
go c.channelAttendant(bestHeight, bestHash)
|
||||
go c.channelAttendant(bestHeight)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -320,14 +316,18 @@ const (
|
||||
// being attached.
|
||||
chainTrigger transitionTrigger = iota
|
||||
|
||||
// remotePeerTrigger is a transition trigger driven by actions of the
|
||||
// remote peer.
|
||||
remotePeerTrigger
|
||||
|
||||
// userTrigger is a transition trigger driven by user action. Examples
|
||||
// of such a trigger include a user requesting a forgive closure of the
|
||||
// of such a trigger include a user requesting a force closure of the
|
||||
// channel.
|
||||
userTrigger
|
||||
|
||||
// remoteCloseTrigger is a transition trigger driven by the remote
|
||||
// peer's commitment being confirmed.
|
||||
remoteCloseTrigger
|
||||
|
||||
// localCloseTrigger is a transition trigger driven by our commitment
|
||||
// being confirmed.
|
||||
localCloseTrigger
|
||||
)
|
||||
|
||||
// String returns a human readable string describing the passed
|
||||
@ -337,12 +337,15 @@ func (t transitionTrigger) String() string {
|
||||
case chainTrigger:
|
||||
return "chainTrigger"
|
||||
|
||||
case remotePeerTrigger:
|
||||
return "remotePeerTrigger"
|
||||
case remoteCloseTrigger:
|
||||
return "remoteCloseTrigger"
|
||||
|
||||
case userTrigger:
|
||||
return "userTrigger"
|
||||
|
||||
case localCloseTrigger:
|
||||
return "localCloseTrigger"
|
||||
|
||||
default:
|
||||
return "unknown trigger"
|
||||
}
|
||||
@ -352,7 +355,7 @@ func (t transitionTrigger) String() string {
|
||||
// the appropriate state transition if necessary. The next state we transition
|
||||
// to is returned, Additionally, if the next transition results in a commitment
|
||||
// broadcast, the commitment transaction itself is returned.
|
||||
func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Hash,
|
||||
func (c *ChannelArbitrator) stateStep(triggerHeight uint32,
|
||||
trigger transitionTrigger) (ArbitratorState, *wire.MsgTx, error) {
|
||||
|
||||
var (
|
||||
@ -364,16 +367,15 @@ func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Has
|
||||
// If we're in the default state, then we'll check our set of actions
|
||||
// to see if while we were down, conditions have changed.
|
||||
case StateDefault:
|
||||
log.Debugf("ChannelArbitrator(%v): new block (height=%v, "+
|
||||
"hash=%v) examining active HTLC's",
|
||||
c.cfg.ChanPoint, bestHeight, bestHash)
|
||||
log.Debugf("ChannelArbitrator(%v): new block (height=%v) "+
|
||||
"examining active HTLC's", c.cfg.ChanPoint,
|
||||
triggerHeight)
|
||||
|
||||
// As a new block has been connected to the end of the main
|
||||
// chain, we'll check to see if we need to make any on-chain
|
||||
// claims on behalf of the channel contract that we're
|
||||
// arbitrating for.
|
||||
chainActions := c.checkChainActions(uint32(bestHeight),
|
||||
trigger)
|
||||
chainActions := c.checkChainActions(triggerHeight, trigger)
|
||||
|
||||
// If there are no actions to be made, then we'll remain in the
|
||||
// default state. If this isn't a self initiated event (we're
|
||||
@ -409,10 +411,16 @@ func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Has
|
||||
case userTrigger:
|
||||
nextState = StateBroadcastCommit
|
||||
|
||||
// Otherwise, if this state advance was triggered by the remote
|
||||
// peer, then we'll jump straight to the state where the
|
||||
// contract has already been closed.
|
||||
case remotePeerTrigger:
|
||||
// Otherwise, if this state advance was triggered by a
|
||||
// commitment being confirmed on chain, then we'll jump
|
||||
// straight to the state where the contract has already been
|
||||
// closed.
|
||||
case localCloseTrigger:
|
||||
log.Errorf("ChannelArbitrator(%v): unexpected local "+
|
||||
"commitment confirmed while in StateDefault",
|
||||
c.cfg.ChanPoint)
|
||||
fallthrough
|
||||
case remoteCloseTrigger:
|
||||
nextState = StateContractClosed
|
||||
}
|
||||
|
||||
@ -456,60 +464,38 @@ func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Has
|
||||
}
|
||||
}
|
||||
|
||||
// As we've have broadcast the commitment transaction, we send
|
||||
// out commitment output for incubation, but only if it wasn't
|
||||
// trimmed. We'll need to wait for a CSV timeout before we can
|
||||
// reclaim the funds.
|
||||
if closeSummary.CommitResolution != nil {
|
||||
log.Infof("ChannelArbitrator(%v): sending commit "+
|
||||
"output for incubation", c.cfg.ChanPoint)
|
||||
|
||||
err = c.cfg.IncubateOutputs(
|
||||
c.cfg.ChanPoint, closeSummary.CommitResolution,
|
||||
nil, nil,
|
||||
)
|
||||
if err != nil {
|
||||
// TODO(roasbeef): check for AlreadyExists errors
|
||||
log.Errorf("unable to incubate commitment "+
|
||||
"output: %v", err)
|
||||
return StateError, closeTx, err
|
||||
}
|
||||
if err := c.cfg.MarkCommitmentBroadcasted(); err != nil {
|
||||
log.Errorf("ChannelArbitrator(%v): unable to "+
|
||||
"mark commitment broadcasted: %v",
|
||||
c.cfg.ChanPoint, err)
|
||||
}
|
||||
|
||||
contractRes := ContractResolutions{
|
||||
CommitHash: closeTx.TxHash(),
|
||||
CommitResolution: closeSummary.CommitResolution,
|
||||
HtlcResolutions: *closeSummary.HtlcResolutions,
|
||||
// We go to the StateCommitmentBroadcasted state, where we'll
|
||||
// be waiting for the commitment to be confirmed.
|
||||
nextState = StateCommitmentBroadcasted
|
||||
|
||||
// In this state we have broadcasted our own commitment, and will need
|
||||
// to wait for a commitment (not necessarily the one we broadcasted!)
|
||||
// to be confirmed.
|
||||
case StateCommitmentBroadcasted:
|
||||
switch trigger {
|
||||
// We are waiting for a commitment to be confirmed, so any
|
||||
// other trigger will be ignored.
|
||||
case chainTrigger, userTrigger:
|
||||
log.Infof("ChannelArbitrator(%v): noop state %v",
|
||||
c.cfg.ChanPoint, trigger)
|
||||
nextState = StateCommitmentBroadcasted
|
||||
|
||||
// If this state advance was triggered by any of the
|
||||
// commitments being confirmed, then we'll jump to the state
|
||||
// where the contract has been closed.
|
||||
case localCloseTrigger, remoteCloseTrigger:
|
||||
log.Infof("ChannelArbitrator(%v): state %v, "+
|
||||
" going to StateContractClosed",
|
||||
c.cfg.ChanPoint, trigger)
|
||||
nextState = StateContractClosed
|
||||
}
|
||||
|
||||
// Now that the transaction has been broadcast, we can mark
|
||||
// that it has been closed to outside sub-systems.
|
||||
err = c.markContractClosed(
|
||||
closeTx, closeSummary.ChanSnapshot, &contractRes,
|
||||
bestHeight,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to close contract: %v", err)
|
||||
return StateError, closeTx, err
|
||||
}
|
||||
|
||||
// With the channel force closed, we'll now log our
|
||||
// resolutions, then advance our state forward.
|
||||
log.Infof("ChannelArbitrator(%v): logging contract "+
|
||||
"resolutions: commit=%v, num_htlcs=%v",
|
||||
c.cfg.ChanPoint,
|
||||
closeSummary.CommitResolution != nil,
|
||||
len(closeSummary.HtlcResolutions.IncomingHTLCs)+
|
||||
len(closeSummary.HtlcResolutions.OutgoingHTLCs))
|
||||
|
||||
err = c.log.LogContractResolutions(&contractRes)
|
||||
if err != nil {
|
||||
log.Errorf("unable to write resolutions: %v", err)
|
||||
return StateError, closeTx, err
|
||||
}
|
||||
|
||||
nextState = StateContractClosed
|
||||
|
||||
// If we're in this state, then the contract has been fully closed to
|
||||
// outside sub-systems, so we'll process the prior set of on-chain
|
||||
// contract actions and launch a set of resolvers.
|
||||
@ -539,12 +525,32 @@ func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Has
|
||||
break
|
||||
}
|
||||
|
||||
// If we've have broadcast the commitment transaction, we send
|
||||
// our commitment output for incubation, but only if it wasn't
|
||||
// trimmed. We'll need to wait for a CSV timeout before we can
|
||||
// reclaim the funds.
|
||||
commitRes := contractResolutions.CommitResolution
|
||||
if commitRes != nil && commitRes.MaturityDelay > 0 {
|
||||
log.Infof("ChannelArbitrator(%v): sending commit "+
|
||||
"output for incubation", c.cfg.ChanPoint)
|
||||
|
||||
err = c.cfg.IncubateOutputs(
|
||||
c.cfg.ChanPoint, commitRes,
|
||||
nil, nil,
|
||||
)
|
||||
if err != nil {
|
||||
// TODO(roasbeef): check for AlreadyExists errors
|
||||
log.Errorf("unable to incubate commitment "+
|
||||
"output: %v", err)
|
||||
return StateError, closeTx, err
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we know we'll need to act, we'll process the htlc
|
||||
// actions, wen create the structures we need to resolve all
|
||||
// outstanding contracts.
|
||||
htlcResolvers, pktsToSend, err := c.prepContractResolutions(
|
||||
chainActions, contractResolutions, uint32(bestHeight),
|
||||
trigger,
|
||||
chainActions, contractResolutions, triggerHeight,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("ChannelArbitrator(%v): unable to "+
|
||||
@ -601,7 +607,7 @@ func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Has
|
||||
nextState = StateFullyResolved
|
||||
|
||||
log.Infof("ChannelPoint(%v) has been fully resolved "+
|
||||
"on-chain at height=%v", c.cfg.ChanPoint, bestHeight)
|
||||
"on-chain at height=%v", c.cfg.ChanPoint, triggerHeight)
|
||||
return nextState, closeTx, c.cfg.MarkChannelResolved()
|
||||
}
|
||||
|
||||
@ -622,25 +628,25 @@ func (c *ChannelArbitrator) stateStep(bestHeight uint32, bestHash *chainhash.Has
|
||||
// redundant transition, meaning that the state transition is a noop. The final
|
||||
// param is a callback that allows the caller to execute an arbitrary action
|
||||
// after each state transition.
|
||||
func (c *ChannelArbitrator) advanceState(currentHeight uint32,
|
||||
bestHash *chainhash.Hash, trigger transitionTrigger,
|
||||
stateCallback func(ArbitratorState) error) (ArbitratorState, *wire.MsgTx, error) {
|
||||
func (c *ChannelArbitrator) advanceState(triggerHeight uint32,
|
||||
trigger transitionTrigger, stateCallback func(ArbitratorState) error) (
|
||||
ArbitratorState, *wire.MsgTx, error) {
|
||||
|
||||
var (
|
||||
priorState ArbitratorState
|
||||
forceCloseTx *wire.MsgTx
|
||||
)
|
||||
|
||||
log.Tracef("ChannelArbitrator(%v): attempting state step with "+
|
||||
"trigger=%v", c.cfg.ChanPoint, trigger)
|
||||
|
||||
// We'll continue to advance our state forward until the state we
|
||||
// transition to is that same state that we started at.
|
||||
for {
|
||||
priorState = c.state
|
||||
log.Tracef("ChannelArbitrator(%v): attempting state step with "+
|
||||
"trigger=%v from state=%v", c.cfg.ChanPoint, trigger,
|
||||
priorState)
|
||||
|
||||
nextState, closeTx, err := c.stateStep(
|
||||
currentHeight, bestHash, trigger,
|
||||
triggerHeight, trigger,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to advance state: %v", err)
|
||||
@ -926,7 +932,6 @@ func (c *ChannelArbitrator) checkChainActions(height uint32,
|
||||
// are properly resolved.
|
||||
func (c *ChannelArbitrator) prepContractResolutions(htlcActions ChainActionMap,
|
||||
contractResolutions *ContractResolutions, height uint32,
|
||||
trigger transitionTrigger,
|
||||
) ([]ContractResolver, []ResolutionMsg, error) {
|
||||
|
||||
// There may be a class of HTLC's which we can fail back immediately,
|
||||
@ -1278,8 +1283,7 @@ func (c *ChannelArbitrator) UpdateContractSignals(newSignals *ContractSignals) {
|
||||
// Nursery for incubation, and ultimate sweeping.
|
||||
//
|
||||
// NOTE: This MUST be run as a goroutine.
|
||||
func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
bestHash *chainhash.Hash) {
|
||||
func (c *ChannelArbitrator) channelAttendant(bestHeight int32) {
|
||||
|
||||
// TODO(roasbeef): tell top chain arb we're done
|
||||
defer c.wg.Done()
|
||||
@ -1295,7 +1299,6 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
return
|
||||
}
|
||||
bestHeight = blockEpoch.Height
|
||||
bestHash = blockEpoch.Hash
|
||||
|
||||
// If we're not in the default state, then we can
|
||||
// ignore this signal as we're waiting for contract
|
||||
@ -1307,7 +1310,7 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
// Now that a new block has arrived, we'll attempt to
|
||||
// advance our state forward.
|
||||
nextState, _, err := c.advanceState(
|
||||
uint32(bestHeight), bestHash, chainTrigger, nil,
|
||||
uint32(bestHeight), chainTrigger, nil,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to advance state: %v", err)
|
||||
@ -1352,20 +1355,67 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
}),
|
||||
)
|
||||
|
||||
// We've cooperatively closed the channel, so we're no longer
|
||||
// needed.
|
||||
// We've cooperatively closed the channel, so we're no longer
|
||||
// needed.
|
||||
case <-c.cfg.ChainEvents.CooperativeClosure:
|
||||
log.Infof("ChannelArbitrator(%v) closing due to co-op "+
|
||||
"closure", c.cfg.ChanPoint)
|
||||
return
|
||||
|
||||
// We have broadcasted our commitment, and it is now confirmed
|
||||
// on-chain.
|
||||
case closeInfo := <-c.cfg.ChainEvents.LocalUnilateralClosure:
|
||||
log.Infof("ChannelArbitrator(%v): local on-chain "+
|
||||
"channel close", c.cfg.ChanPoint)
|
||||
|
||||
if c.state != StateCommitmentBroadcasted {
|
||||
log.Errorf("ChannelArbitrator(%v): unexpected "+
|
||||
"local on-chain channel close",
|
||||
c.cfg.ChanPoint)
|
||||
}
|
||||
closeTx := closeInfo.CloseTx
|
||||
|
||||
contractRes := &ContractResolutions{
|
||||
CommitHash: closeTx.TxHash(),
|
||||
CommitResolution: closeInfo.CommitResolution,
|
||||
HtlcResolutions: *closeInfo.HtlcResolutions,
|
||||
}
|
||||
|
||||
// When processing a unilateral close event, we'll
|
||||
// transition directly to the ContractClosed state.
|
||||
// When the state machine reaches that state, we'll log
|
||||
// out the set of resolutions.
|
||||
stateCb := func(nextState ArbitratorState) error {
|
||||
if nextState != StateContractClosed {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := c.log.LogContractResolutions(
|
||||
contractRes,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to "+
|
||||
"write resolutions: %v",
|
||||
err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// We'll now advance our state machine until it reaches
|
||||
// a terminal state.
|
||||
_, _, err := c.advanceState(
|
||||
uint32(closeInfo.SpendingHeight),
|
||||
localCloseTrigger, stateCb,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to advance state: %v", err)
|
||||
}
|
||||
|
||||
// The remote party has broadcast the commitment on-chain.
|
||||
// We'll examine our state to determine if we need to act at
|
||||
// all.
|
||||
case uniClosure := <-c.cfg.ChainEvents.UnilateralClosure:
|
||||
if c.state != StateDefault {
|
||||
continue
|
||||
}
|
||||
case uniClosure := <-c.cfg.ChainEvents.RemoteUnilateralClosure:
|
||||
|
||||
log.Infof("ChannelArbitrator(%v): remote party has "+
|
||||
"closed channel out on-chain", c.cfg.ChanPoint)
|
||||
@ -1378,17 +1428,6 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
CommitResolution: uniClosure.CommitResolution,
|
||||
HtlcResolutions: *uniClosure.HtlcResolutions,
|
||||
}
|
||||
if contractRes.IsEmpty() {
|
||||
log.Infof("ChannelArbitrator(%v): contract "+
|
||||
"resolutions empty, exiting", c.cfg.ChanPoint)
|
||||
|
||||
err := c.cfg.MarkChannelResolved()
|
||||
if err != nil {
|
||||
log.Errorf("unable to resolve "+
|
||||
"contract: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(roasbeef): modify signal to also detect
|
||||
// cooperative closures?
|
||||
@ -1399,19 +1438,21 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
// present on their commitment.
|
||||
c.activeHTLCs = newHtlcSet(uniClosure.RemoteCommit.Htlcs)
|
||||
|
||||
// When processing a remote party initiated event,
|
||||
// we'll skip the BroadcastCommit state, and transition
|
||||
// directly to the ContractClosed state. As a result,
|
||||
// we'll now manually log out set of resolutions.
|
||||
// When processing a unilateral close event, we'll
|
||||
// transition directly to the ContractClosed state.
|
||||
// When the state machine reaches that state, we'll log
|
||||
// out the set of resolutions.
|
||||
stateCb := func(nextState ArbitratorState) error {
|
||||
if nextState == StateContractClosed {
|
||||
err := c.log.LogContractResolutions(
|
||||
contractRes,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write "+
|
||||
"resolutions: %v", err)
|
||||
}
|
||||
if nextState != StateContractClosed {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := c.log.LogContractResolutions(
|
||||
contractRes,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write "+
|
||||
"resolutions: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -1420,8 +1461,8 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
// We'll now advance our state machine until it reaches
|
||||
// a terminal state.
|
||||
_, _, err := c.advanceState(
|
||||
uint32(bestHeight), bestHash,
|
||||
remotePeerTrigger, stateCb,
|
||||
uint32(uniClosure.SpendingHeight),
|
||||
remoteCloseTrigger, stateCb,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to advance state: %v", err)
|
||||
@ -1466,7 +1507,7 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
}
|
||||
|
||||
nextState, closeTx, err := c.advanceState(
|
||||
uint32(bestHeight), bestHash, userTrigger, nil,
|
||||
uint32(bestHeight), userTrigger, nil,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to advance state: %v", err)
|
||||
@ -1490,6 +1531,7 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
log.Infof("ChannelArbitrator(%v): all "+
|
||||
"contracts resolved, exiting",
|
||||
c.cfg.ChanPoint)
|
||||
return
|
||||
}
|
||||
|
||||
case <-c.quit:
|
||||
@ -1497,39 +1539,3 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// markContractClosed marks a contract as "pending closed". After this state,
|
||||
// upon restart, we'll no longer watch for updates to the set of contracts as
|
||||
// the channel cannot be updated any longer.
|
||||
func (c *ChannelArbitrator) markContractClosed(closeTx *wire.MsgTx,
|
||||
chanSnapshot channeldb.ChannelSnapshot,
|
||||
contractResolution *ContractResolutions,
|
||||
closeHeight uint32) error {
|
||||
|
||||
// TODO(roasbeef): also need height info?
|
||||
closeInfo := &channeldb.ChannelCloseSummary{
|
||||
ChanPoint: chanSnapshot.ChannelPoint,
|
||||
ChainHash: chanSnapshot.ChainHash,
|
||||
ClosingTXID: closeTx.TxHash(),
|
||||
RemotePub: &chanSnapshot.RemoteIdentity,
|
||||
Capacity: chanSnapshot.Capacity,
|
||||
CloseType: channeldb.ForceClose,
|
||||
IsPending: true,
|
||||
ShortChanID: c.cfg.ShortChanID,
|
||||
CloseHeight: closeHeight,
|
||||
}
|
||||
|
||||
// If our commitment output isn't dust or we have active HTLC's on the
|
||||
// commitment transaction, then we'll populate the balances on the
|
||||
// close channel summary.
|
||||
if contractResolution.CommitResolution != nil {
|
||||
closeInfo.SettledBalance = chanSnapshot.LocalBalance.ToSatoshis()
|
||||
closeInfo.TimeLockedBalance = chanSnapshot.LocalBalance.ToSatoshis()
|
||||
}
|
||||
for _, htlc := range contractResolution.HtlcResolutions.OutgoingHTLCs {
|
||||
htlcValue := btcutil.Amount(htlc.SweepSignDesc.Output.Value)
|
||||
closeInfo.TimeLockedBalance += htlcValue
|
||||
}
|
||||
|
||||
return c.cfg.CloseChannel(closeInfo)
|
||||
}
|
||||
|
@ -1 +1,341 @@
|
||||
package contractcourt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
)
|
||||
|
||||
type mockChainIO struct{}
|
||||
|
||||
func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) {
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
func (*mockChainIO) GetUtxo(op *wire.OutPoint,
|
||||
heightHint uint32) (*wire.TxOut, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (*mockChainIO) GetBlockHash(blockHeight int64) (*chainhash.Hash, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (*mockChainIO) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func createTestChannelArbitrator() (*ChannelArbitrator, chan struct{}, func(), error) {
|
||||
blockEpoch := &chainntnfs.BlockEpochEvent{
|
||||
Cancel: func() {},
|
||||
}
|
||||
|
||||
chanPoint := wire.OutPoint{}
|
||||
shortChanID := lnwire.ShortChannelID{}
|
||||
chanEvents := &ChainEventSubscription{
|
||||
RemoteUnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
|
||||
LocalUnilateralClosure: make(chan *LocalUnilateralCloseInfo, 1),
|
||||
CooperativeClosure: make(chan struct{}, 1),
|
||||
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
|
||||
}
|
||||
|
||||
chainIO := &mockChainIO{}
|
||||
chainArbCfg := ChainArbitratorConfig{
|
||||
ChainIO: chainIO,
|
||||
PublishTx: func(*wire.MsgTx) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// We'll use the resolvedChan to synchronize on call to
|
||||
// MarkChannelResolved.
|
||||
resolvedChan := make(chan struct{}, 1)
|
||||
|
||||
// Next we'll create the matching configuration struct that contains
|
||||
// all interfaces and methods the arbitrator needs to do its job.
|
||||
arbCfg := ChannelArbitratorConfig{
|
||||
ChanPoint: chanPoint,
|
||||
ShortChanID: shortChanID,
|
||||
BlockEpochs: blockEpoch,
|
||||
MarkChannelResolved: func() error {
|
||||
resolvedChan <- struct{}{}
|
||||
return nil
|
||||
},
|
||||
ForceCloseChan: func() (*lnwallet.LocalForceCloseSummary, error) {
|
||||
summary := &lnwallet.LocalForceCloseSummary{
|
||||
CloseTx: &wire.MsgTx{},
|
||||
HtlcResolutions: &lnwallet.HtlcResolutions{},
|
||||
}
|
||||
return summary, nil
|
||||
},
|
||||
MarkCommitmentBroadcasted: func() error {
|
||||
return nil
|
||||
},
|
||||
|
||||
ChainArbitratorConfig: chainArbCfg,
|
||||
ChainEvents: chanEvents,
|
||||
}
|
||||
testLog, cleanUp, err := newTestBoltArbLog(
|
||||
testChainHash, testChanPoint1,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("unable to create test log: %v",
|
||||
err)
|
||||
}
|
||||
|
||||
return NewChannelArbitrator(arbCfg, nil, testLog),
|
||||
resolvedChan, cleanUp, nil
|
||||
}
|
||||
|
||||
// assertState checks that the ChannelArbitrator is in the state we expect it
|
||||
// to be.
|
||||
func assertState(t *testing.T, c *ChannelArbitrator, expected ArbitratorState) {
|
||||
if c.state != expected {
|
||||
t.Fatalf("expected state %v, was %v", expected, c.state)
|
||||
}
|
||||
}
|
||||
|
||||
// TestChannelArbitratorCooperativeClose tests that the ChannelArbitertor
|
||||
// correctly does nothing in case a cooperative close is confirmed.
|
||||
func TestChannelArbitratorCooperativeClose(t *testing.T) {
|
||||
chanArb, _, cleanUp, err := createTestChannelArbitrator()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
if err := chanArb.Start(); err != nil {
|
||||
t.Fatalf("unable to start ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer chanArb.Stop()
|
||||
|
||||
// It should start out in the default state.
|
||||
assertState(t, chanArb, StateDefault)
|
||||
|
||||
// Cooperative close should do nothing.
|
||||
// TODO: this will change?
|
||||
chanArb.cfg.ChainEvents.CooperativeClosure <- struct{}{}
|
||||
assertState(t, chanArb, StateDefault)
|
||||
}
|
||||
|
||||
// TestChannelArbitratorRemoteForceClose checks that the ChannelArbitrotor goes
|
||||
// through the expected states if a remote force close is observed in the
|
||||
// chain.
|
||||
func TestChannelArbitratorRemoteForceClose(t *testing.T) {
|
||||
chanArb, resolved, cleanUp, err := createTestChannelArbitrator()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
if err := chanArb.Start(); err != nil {
|
||||
t.Fatalf("unable to start ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer chanArb.Stop()
|
||||
|
||||
// It should start out in the default state.
|
||||
assertState(t, chanArb, StateDefault)
|
||||
|
||||
// Send a remote force close event.
|
||||
commitSpend := &chainntnfs.SpendDetail{
|
||||
SpenderTxHash: &chainhash.Hash{},
|
||||
}
|
||||
|
||||
uniClose := &lnwallet.UnilateralCloseSummary{
|
||||
SpendDetail: commitSpend,
|
||||
HtlcResolutions: &lnwallet.HtlcResolutions{},
|
||||
}
|
||||
chanArb.cfg.ChainEvents.RemoteUnilateralClosure <- uniClose
|
||||
|
||||
// It should mark the channel as resolved.
|
||||
select {
|
||||
case <-resolved:
|
||||
// Expected.
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("contract was not resolved")
|
||||
}
|
||||
|
||||
// TODO: intermediate states.
|
||||
// We expect the ChannelArbitrator to end up in the the resolved state.
|
||||
assertState(t, chanArb, StateFullyResolved)
|
||||
}
|
||||
|
||||
// TestChannelArbitratorLocalForceClose tests that the ChannelArbitrator goes
|
||||
// through the expected states in case we request it to force close the channel,
|
||||
// and the local force close event is observed in chain.
|
||||
func TestChannelArbitratorLocalForceClose(t *testing.T) {
|
||||
chanArb, resolved, cleanUp, err := createTestChannelArbitrator()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
if err := chanArb.Start(); err != nil {
|
||||
t.Fatalf("unable to start ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer chanArb.Stop()
|
||||
|
||||
// It should start out in the default state.
|
||||
assertState(t, chanArb, StateDefault)
|
||||
|
||||
// We create a channel we can use to pause the ChannelArbitrator at the
|
||||
// point where it broadcasts the close tx, and check its state.
|
||||
stateChan := make(chan ArbitratorState)
|
||||
chanArb.cfg.PublishTx = func(*wire.MsgTx) error {
|
||||
// When the force close tx is being broadcasted, check that the
|
||||
// state is correct at that point.
|
||||
select {
|
||||
case stateChan <- chanArb.state:
|
||||
case <-chanArb.quit:
|
||||
return fmt.Errorf("exiting")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
respChan := make(chan *wire.MsgTx, 1)
|
||||
|
||||
// With the channel found, and the request crafted, we'll send over a
|
||||
// force close request to the arbitrator that watches this channel.
|
||||
chanArb.forceCloseReqs <- &forceCloseReq{
|
||||
errResp: errChan,
|
||||
closeTx: respChan,
|
||||
}
|
||||
|
||||
// When it is broadcasting the force close, its state should be
|
||||
// StateBroadcastCommit.
|
||||
select {
|
||||
case state := <-stateChan:
|
||||
if state != StateBroadcastCommit {
|
||||
t.Fatalf("state during PublishTx was %v", state)
|
||||
}
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("did not get state update")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-respChan:
|
||||
case err := <-errChan:
|
||||
t.Fatalf("error force closing channel: %v", err)
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("did not receive reponse")
|
||||
}
|
||||
|
||||
// After broadcasting the close tx, it should be in state
|
||||
// StateCommitmentBroadcasted.
|
||||
assertState(t, chanArb, StateCommitmentBroadcasted)
|
||||
|
||||
// Now notify about the local force close getting confirmed.
|
||||
chanArb.cfg.ChainEvents.LocalUnilateralClosure <- &LocalUnilateralCloseInfo{
|
||||
&chainntnfs.SpendDetail{},
|
||||
&lnwallet.LocalForceCloseSummary{
|
||||
CloseTx: &wire.MsgTx{},
|
||||
HtlcResolutions: &lnwallet.HtlcResolutions{},
|
||||
},
|
||||
}
|
||||
// It should mark the channel as resolved.
|
||||
select {
|
||||
case <-resolved:
|
||||
// Expected.
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("contract was not resolved")
|
||||
}
|
||||
|
||||
// And end up in the StateFullyResolved state.
|
||||
// TODO: intermediate states as well.
|
||||
assertState(t, chanArb, StateFullyResolved)
|
||||
}
|
||||
|
||||
// TestChannelArbitratorLocalForceCloseRemoteConfiremd tests that the
|
||||
// ChannelArbitrator behaves as expected in the case where we request a local
|
||||
// force close, but a remote commitment ends up being confirmed in chain.
|
||||
func TestChannelArbitratorLocalForceCloseRemoteConfirmed(t *testing.T) {
|
||||
chanArb, resolved, cleanUp, err := createTestChannelArbitrator()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
if err := chanArb.Start(); err != nil {
|
||||
t.Fatalf("unable to start ChannelArbitrator: %v", err)
|
||||
}
|
||||
defer chanArb.Stop()
|
||||
|
||||
// It should start out in the default state.
|
||||
assertState(t, chanArb, StateDefault)
|
||||
|
||||
// Create a channel we can use to assert the state when it publishes
|
||||
// the close tx.
|
||||
stateChan := make(chan ArbitratorState)
|
||||
chanArb.cfg.PublishTx = func(*wire.MsgTx) error {
|
||||
// When the force close tx is being broadcasted, check that the
|
||||
// state is correct at that point.
|
||||
select {
|
||||
case stateChan <- chanArb.state:
|
||||
case <-chanArb.quit:
|
||||
return fmt.Errorf("exiting")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
respChan := make(chan *wire.MsgTx, 1)
|
||||
|
||||
// With the channel found, and the request crafted, we'll send over a
|
||||
// force close request to the arbitrator that watches this channel.
|
||||
chanArb.forceCloseReqs <- &forceCloseReq{
|
||||
errResp: errChan,
|
||||
closeTx: respChan,
|
||||
}
|
||||
|
||||
// We expect it to be in state StateBroadcastCommit when publishing
|
||||
// the force close.
|
||||
select {
|
||||
case state := <-stateChan:
|
||||
if state != StateBroadcastCommit {
|
||||
t.Fatalf("state during PublishTx was %v", state)
|
||||
}
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("no state update received")
|
||||
}
|
||||
|
||||
// Wait for a response to the force close.
|
||||
select {
|
||||
case <-respChan:
|
||||
case err := <-errChan:
|
||||
t.Fatalf("error force closing channel: %v", err)
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("no response received")
|
||||
}
|
||||
|
||||
// The state should be StateCommitmentBroadcasted.
|
||||
assertState(t, chanArb, StateCommitmentBroadcasted)
|
||||
|
||||
// Now notify about the _REMOTE_ commitment getting confirmed.
|
||||
commitSpend := &chainntnfs.SpendDetail{
|
||||
SpenderTxHash: &chainhash.Hash{},
|
||||
}
|
||||
uniClose := &lnwallet.UnilateralCloseSummary{
|
||||
SpendDetail: commitSpend,
|
||||
HtlcResolutions: &lnwallet.HtlcResolutions{},
|
||||
}
|
||||
chanArb.cfg.ChainEvents.RemoteUnilateralClosure <- uniClose
|
||||
|
||||
// It should resolve.
|
||||
select {
|
||||
case <-resolved:
|
||||
// Expected.
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("contract was not resolved")
|
||||
}
|
||||
|
||||
// And we expect it to end up in StateFullyResolved.
|
||||
// TODO: intermediate states as well.
|
||||
assertState(t, chanArb, StateFullyResolved)
|
||||
}
|
||||
|
@ -350,16 +350,12 @@ func (cm *circuitMap) decodeCircuit(v []byte) (*PaymentCircuit, error) {
|
||||
// channels. Therefore, it must be called before any links are created to avoid
|
||||
// interfering with normal operation.
|
||||
func (cm *circuitMap) trimAllOpenCircuits() error {
|
||||
activeChannels, err := cm.cfg.DB.FetchAllChannels()
|
||||
activeChannels, err := cm.cfg.DB.FetchAllOpenChannels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, activeChannel := range activeChannels {
|
||||
if activeChannel.IsPending {
|
||||
continue
|
||||
}
|
||||
|
||||
chanID := activeChannel.ShortChanID
|
||||
start := activeChannel.LocalCommitment.LocalHtlcIndex
|
||||
if err := cm.TrimOpenCircuits(chanID, start); err != nil {
|
||||
|
@ -832,7 +832,7 @@ out:
|
||||
// the contract as fully settled. Afterwards we can exit.
|
||||
//
|
||||
// TODO(roasbeef): add force closure? also breach?
|
||||
case <-l.cfg.ChainEvents.UnilateralClosure:
|
||||
case <-l.cfg.ChainEvents.RemoteUnilateralClosure:
|
||||
log.Warnf("Remote peer has closed ChannelPoint(%v) on-chain",
|
||||
l.channel.ChannelPoint())
|
||||
|
||||
|
@ -1513,16 +1513,12 @@ func (s *Switch) Start() error {
|
||||
// forwarding packages and reforwards any Settle or Fail HTLCs found. This is
|
||||
// used to resurrect the switch's mailboxes after a restart.
|
||||
func (s *Switch) reforwardResponses() error {
|
||||
activeChannels, err := s.cfg.DB.FetchAllChannels()
|
||||
activeChannels, err := s.cfg.DB.FetchAllOpenChannels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, activeChannel := range activeChannels {
|
||||
if activeChannel.IsPending {
|
||||
continue
|
||||
}
|
||||
|
||||
shortChanID := activeChannel.ShortChanID
|
||||
fwdPkgs, err := s.loadChannelFwdPkgs(shortChanID)
|
||||
if err != nil {
|
||||
|
592
lnd_test.go
592
lnd_test.go
@ -112,7 +112,7 @@ func assertTxInBlock(t *harnessTest, block *wire.MsgBlock, txid *chainhash.Hash)
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("funding tx was not included in block")
|
||||
t.Fatalf("tx was not included in block")
|
||||
}
|
||||
|
||||
// mineBlocks mine 'num' of blocks and check that blocks are present in
|
||||
@ -1109,8 +1109,17 @@ func testDisconnectingTargetPeer(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
// Disconnect Alice-peer from Bob-peer without getting error
|
||||
// about existing channels.
|
||||
if err := net.DisconnectNodes(ctxt, net.Alice, net.Bob); err != nil {
|
||||
t.Fatalf("unable to disconnect Bob's peer from Alice's: err %v", err)
|
||||
var predErr error
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
if err := net.DisconnectNodes(ctxt, net.Alice, net.Bob); err != nil {
|
||||
predErr = err
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to disconnect Bob's peer from Alice's: err %v",
|
||||
predErr)
|
||||
}
|
||||
|
||||
// Check zero peer connections.
|
||||
@ -1353,6 +1362,27 @@ func findForceClosedChannel(t *harnessTest,
|
||||
return forceClose
|
||||
}
|
||||
|
||||
// findWaitingCloseChannel searches a pending channel response for a particular
|
||||
// channel, returning the waiting close channel upon success.
|
||||
func findWaitingCloseChannel(t *harnessTest,
|
||||
pendingChanResp *lnrpc.PendingChannelsResponse,
|
||||
op *wire.OutPoint) *lnrpc.PendingChannelsResponse_WaitingCloseChannel {
|
||||
|
||||
var found bool
|
||||
var waitingClose *lnrpc.PendingChannelsResponse_WaitingCloseChannel
|
||||
for _, waitingClose = range pendingChanResp.WaitingCloseChannels {
|
||||
if waitingClose.Channel.ChannelPoint == op.String() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("channel not marked as waiting close")
|
||||
}
|
||||
|
||||
return waitingClose
|
||||
}
|
||||
|
||||
func assertCommitmentMaturity(t *harnessTest,
|
||||
forceClose *lnrpc.PendingChannelsResponse_ForceClosedChannel,
|
||||
maturityHeight uint32, blocksTilMaturity int32) {
|
||||
@ -1394,6 +1424,18 @@ func assertNumForceClosedChannels(t *harnessTest,
|
||||
}
|
||||
}
|
||||
|
||||
// assertNumWaitingCloseChannels checks that a pending channel response has the
|
||||
// expected number of channels waiting for closing tx to confirm.
|
||||
func assertNumWaitingCloseChannels(t *harnessTest,
|
||||
pendingChanResp *lnrpc.PendingChannelsResponse, expectedNumChans int) {
|
||||
|
||||
if len(pendingChanResp.WaitingCloseChannels) != expectedNumChans {
|
||||
t.Fatalf("expected to find %d channels waiting closure, got %d",
|
||||
expectedNumChans,
|
||||
len(pendingChanResp.WaitingCloseChannels))
|
||||
}
|
||||
}
|
||||
|
||||
// assertPendingHtlcStageAndMaturity uniformly tests all pending htlc's
|
||||
// belonging to a force closed channel, testing for the expected stage number,
|
||||
// blocks till maturity, and the maturity height.
|
||||
@ -1574,13 +1616,13 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
}
|
||||
|
||||
// Now that the channel has been force closed, it should show up in the
|
||||
// PendingChannels RPC under the force close section.
|
||||
// PendingChannels RPC under the waiting close section.
|
||||
pendingChansRequest := &lnrpc.PendingChannelsRequest{}
|
||||
pendingChanResp, err := net.Alice.PendingChannels(ctxb, pendingChansRequest)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for pending channels: %v", err)
|
||||
}
|
||||
assertNumForceClosedChannels(t, pendingChanResp, 1)
|
||||
assertNumWaitingCloseChannels(t, pendingChanResp, 1)
|
||||
|
||||
// Compute the outpoint of the channel, which we will use repeatedly to
|
||||
// locate the pending channel information in the rpc responses.
|
||||
@ -1597,21 +1639,12 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
Index: chanPoint.OutputIndex,
|
||||
}
|
||||
|
||||
forceClose := findForceClosedChannel(t, pendingChanResp, &op)
|
||||
waitingClose := findWaitingCloseChannel(t, pendingChanResp, &op)
|
||||
|
||||
// Immediately after force closing, all of the funds should be in limbo,
|
||||
// and the pending channels response should not indicate that any funds
|
||||
// have been recovered.
|
||||
if forceClose.LimboBalance == 0 {
|
||||
// Immediately after force closing, all of the funds should be in limbo.
|
||||
if waitingClose.LimboBalance == 0 {
|
||||
t.Fatalf("all funds should still be in limbo")
|
||||
}
|
||||
if forceClose.RecoveredBalance != 0 {
|
||||
t.Fatalf("no funds should yet be shown as recovered")
|
||||
}
|
||||
|
||||
// The commitment transaction has not been confirmed, so we expect to
|
||||
// see a maturity height and blocks til maturity of 0.
|
||||
assertCommitmentMaturity(t, forceClose, 0, 0)
|
||||
|
||||
// The several restarts in this test are intended to ensure that when a
|
||||
// channel is force-closed, the UTXO nursery has persisted the state of
|
||||
@ -1639,13 +1672,15 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
duration := time.Millisecond * 300
|
||||
time.Sleep(duration)
|
||||
|
||||
// Now that the commitment has been confirmed, the channel should be
|
||||
// marked as force closed.
|
||||
pendingChanResp, err = net.Alice.PendingChannels(ctxb, pendingChansRequest)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for pending channels: %v", err)
|
||||
}
|
||||
assertNumForceClosedChannels(t, pendingChanResp, 1)
|
||||
|
||||
forceClose = findForceClosedChannel(t, pendingChanResp, &op)
|
||||
forceClose := findForceClosedChannel(t, pendingChanResp, &op)
|
||||
|
||||
// Now that the channel has been force closed, it should now have the
|
||||
// height and number of blocks to confirm populated.
|
||||
@ -3828,7 +3863,7 @@ func waitForNTxsInMempool(miner *rpcclient.Client, n int,
|
||||
for {
|
||||
select {
|
||||
case <-breakTimeout:
|
||||
return nil, fmt.Errorf("wanted %v, only found %v txs "+
|
||||
return nil, fmt.Errorf("wanted %v, found %v txs "+
|
||||
"in mempool", n, len(mempool))
|
||||
case <-ticker.C:
|
||||
mempool, err = miner.GetRawMempool()
|
||||
@ -4224,11 +4259,24 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness
|
||||
// commitment transaction of a prior *revoked* state, so he'll soon
|
||||
// feel the wrath of Alice's retribution.
|
||||
force := true
|
||||
closeUpdates, _, err := net.CloseChannel(ctxb, carol, chanPoint, force)
|
||||
closeUpdates, closeTxId, err := net.CloseChannel(ctxb, carol,
|
||||
chanPoint, force)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to close channel: %v", err)
|
||||
}
|
||||
|
||||
// Query the mempool for the breaching closing transaction, this should
|
||||
// be broadcast by Carol when she force closes the channel above.
|
||||
txid, err := waitForTxInMempool(net.Miner.Node, 20*time.Second)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find Carol's force close tx in mempool: %v",
|
||||
err)
|
||||
}
|
||||
if *txid != *closeTxId {
|
||||
t.Fatalf("expected closeTx(%v) in mempool, instead found %v",
|
||||
closeTxId, txid)
|
||||
}
|
||||
|
||||
// Finally, generate a single block, wait for the final close status
|
||||
// update, then ensure that the closing transaction was included in the
|
||||
// block.
|
||||
@ -4545,17 +4593,22 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
|
||||
// commitment transaction of a prior *revoked* state, so she'll soon
|
||||
// feel the wrath of Dave's retribution.
|
||||
force := true
|
||||
closeUpdates, _, err := net.CloseChannel(ctxb, carol, chanPoint, force)
|
||||
closeUpdates, closeTxId, err := net.CloseChannel(ctxb, carol,
|
||||
chanPoint, force)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to close channel: %v", err)
|
||||
}
|
||||
|
||||
// Query the mempool for Dave's justice transaction, this should be
|
||||
// broadcast as Carol's contract breaching transaction gets confirmed
|
||||
// above.
|
||||
_, err = waitForTxInMempool(net.Miner.Node, 5*time.Second)
|
||||
// Query the mempool for the breaching closing transaction, this should
|
||||
// be broadcast by Carol when she force closes the channel above.
|
||||
txid, err := waitForTxInMempool(net.Miner.Node, 20*time.Second)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find Dave's justice tx in mempool: %v", err)
|
||||
t.Fatalf("unable to find Carol's force close tx in mempool: %v",
|
||||
err)
|
||||
}
|
||||
if *txid != *closeTxId {
|
||||
t.Fatalf("expected closeTx(%v) in mempool, instead found %v",
|
||||
closeTxId, txid)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
@ -4577,14 +4630,101 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
|
||||
if err != nil {
|
||||
t.Fatalf("error while waiting for channel close: %v", err)
|
||||
}
|
||||
if *breachTXID != *closeTxId {
|
||||
t.Fatalf("expected breach ID(%v) to be equal to close ID (%v)",
|
||||
breachTXID, closeTxId)
|
||||
}
|
||||
assertTxInBlock(t, block, breachTXID)
|
||||
|
||||
// Query the mempool for Dave's justice transaction, this should be
|
||||
// broadcast as Carol's contract breaching transaction gets confirmed
|
||||
// above.
|
||||
justiceTXID, err := waitForTxInMempool(net.Miner.Node, 5*time.Second)
|
||||
// above. Since Carol might have had the time to take some of the HTLC
|
||||
// outputs to the second level before Alice broadcasts her justice tx,
|
||||
// we'll search through the mempool for a tx that matches the number of
|
||||
// expected inputs in the justice tx.
|
||||
// TODO(halseth): change to deterministic check if/when only acting on
|
||||
// confirmed second level spends?
|
||||
var predErr error
|
||||
var justiceTxid *chainhash.Hash
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
mempool, err := net.Miner.Node.GetRawMempool()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get mempool from miner: %v", err)
|
||||
}
|
||||
|
||||
for _, txid := range mempool {
|
||||
// Check that the justice tx has the appropriate number
|
||||
// of inputs.
|
||||
tx, err := net.Miner.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
predErr = fmt.Errorf("unable to query for "+
|
||||
"txs: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
exNumInputs := 2 + numInvoices
|
||||
if len(tx.MsgTx().TxIn) == exNumInputs {
|
||||
justiceTxid = txid
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
predErr = fmt.Errorf("justice tx not found")
|
||||
return false
|
||||
}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find Dave's justice tx in mempool: %v", err)
|
||||
t.Fatalf(predErr.Error())
|
||||
}
|
||||
|
||||
justiceTx, err := net.Miner.Node.GetRawTransaction(justiceTxid)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for justice tx: %v", err)
|
||||
}
|
||||
|
||||
// isSecondLevelSpend checks that the passed secondLevelTxid is a
|
||||
// potentitial second level spend spending from the commit tx.
|
||||
isSecondLevelSpend := func(commitTxid, secondLevelTxid *chainhash.Hash) bool {
|
||||
secondLevel, err := net.Miner.Node.GetRawTransaction(
|
||||
secondLevelTxid)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for tx: %v", err)
|
||||
}
|
||||
|
||||
// A second level spend should have only one input, and one
|
||||
// output.
|
||||
if len(secondLevel.MsgTx().TxIn) != 1 {
|
||||
return false
|
||||
}
|
||||
if len(secondLevel.MsgTx().TxOut) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// The sole input should be spending from the commit tx.
|
||||
txIn := secondLevel.MsgTx().TxIn[0]
|
||||
if !bytes.Equal(txIn.PreviousOutPoint.Hash[:], commitTxid[:]) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Check that all the inputs of this transaction are spending outputs
|
||||
// generated by Carol's breach transaction above.
|
||||
for _, txIn := range justiceTx.MsgTx().TxIn {
|
||||
if bytes.Equal(txIn.PreviousOutPoint.Hash[:], breachTXID[:]) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the justice tx is spending from an output that was not on
|
||||
// the breach tx, Carol might have had the time to take an
|
||||
// output to the second level. In that case, check that the
|
||||
// justice tx is spending this second level output.
|
||||
if isSecondLevelSpend(breachTXID, &txIn.PreviousOutPoint.Hash) {
|
||||
continue
|
||||
}
|
||||
t.Fatalf("justice tx not spending commitment utxo "+
|
||||
"instead is: %v", txIn.PreviousOutPoint)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
@ -4597,36 +4737,12 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
|
||||
t.Fatalf("unable to restart Dave's node: %v", err)
|
||||
}
|
||||
|
||||
// Query for the mempool transaction found above. Then assert that (1)
|
||||
// the justice tx has the appropriate number of inputs, and (2) all the
|
||||
// inputs of this transaction are spending outputs generated by Carol's
|
||||
// breach transaction above, and also the HTLCs from Carol to Dave.
|
||||
justiceTx, err := net.Miner.Node.GetRawTransaction(justiceTXID)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for justice tx: %v", err)
|
||||
}
|
||||
exNumInputs := 2 + numInvoices
|
||||
if len(justiceTx.MsgTx().TxIn) != exNumInputs {
|
||||
t.Fatalf("justice tx should have exactly 2 commitment inputs"+
|
||||
"and %v htlc inputs, expected %v in total, got %v",
|
||||
numInvoices/2, exNumInputs,
|
||||
len(justiceTx.MsgTx().TxIn))
|
||||
}
|
||||
|
||||
// Now mine a block, this transaction should include Dave's justice
|
||||
// transaction which was just accepted into the mempool.
|
||||
block = mineBlocks(t, net, 1)[0]
|
||||
assertTxInBlock(t, block, justiceTxid)
|
||||
|
||||
// The block should have exactly *two* transactions, one of which is
|
||||
// the justice transaction.
|
||||
if len(block.Transactions) != 2 {
|
||||
t.Fatalf("transaction wasn't mined")
|
||||
}
|
||||
justiceSha := block.Transactions[1].TxHash()
|
||||
if !bytes.Equal(justiceTx.Hash()[:], justiceSha[:]) {
|
||||
t.Fatalf("justice tx wasn't mined")
|
||||
}
|
||||
|
||||
// Dave should have no open channels.
|
||||
assertNodeNumChannels(t, ctxb, dave, 0)
|
||||
}
|
||||
|
||||
@ -4649,7 +4765,13 @@ func assertNodeNumChannels(t *harnessTest, ctxb context.Context,
|
||||
|
||||
// Return true if the query returned the expected number of
|
||||
// channels.
|
||||
return len(chanInfo.Channels) == numChannels
|
||||
num := len(chanInfo.Channels)
|
||||
if num != numChannels {
|
||||
predErr = fmt.Errorf("expected %v channels, got %v",
|
||||
numChannels, num)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := lntest.WaitPredicate(pred, time.Second*15); err != nil {
|
||||
@ -6020,6 +6142,9 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
},
|
||||
)
|
||||
|
||||
// Mine a block to confirm the closing transaction.
|
||||
mineBlocks(t, net, 1)
|
||||
|
||||
// At this point, Bob should have cancelled backwards the dust HTLC
|
||||
// that we sent earlier. This means Alice should now only have a single
|
||||
// HTLC on her channel.
|
||||
@ -6033,7 +6158,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
return true
|
||||
}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("htlc mismatch: %v", err)
|
||||
t.Fatalf("htlc mismatch: %v", predErr)
|
||||
}
|
||||
|
||||
// TODO(roasbeef): need to fix utxn so it can accept incubation for
|
||||
@ -6050,7 +6175,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
// The second layer HTLC timeout transaction should now have been
|
||||
// broadcast on-chain.
|
||||
_, err = waitForTxInMempool(net.Miner.Node, time.Second*10)
|
||||
secondLayerHash, err := waitForTxInMempool(net.Miner.Node, time.Second*10)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find bob's second layer transaction")
|
||||
}
|
||||
@ -6077,13 +6202,12 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
}
|
||||
|
||||
// Now we'll mine an additional block.
|
||||
if _, err := net.Miner.Node.Generate(1); err != nil {
|
||||
t.Fatalf("unable to generate blocks: %v", err)
|
||||
}
|
||||
block := mineBlocks(t, net, 1)[0]
|
||||
|
||||
// The block should have confirmed Bob's second layer sweeping
|
||||
// transaction. Therefore, at this point, there should be no active
|
||||
// HTLC's on the commitment transaction from Alice -> Bob.
|
||||
assertTxInBlock(t, block, secondLayerHash)
|
||||
nodes = []*lntest.HarnessNode{net.Alice}
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
return assertNumActiveHtlcs(nodes, 0)
|
||||
@ -6216,58 +6340,73 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest)
|
||||
|
||||
// At this point, Carol should broadcast her active commitment
|
||||
// transaction in order to go to the chain and sweep her HTLC.
|
||||
// Additionally, Carol's should have broadcast her second layer sweep
|
||||
// transaction for the HTLC as well.
|
||||
txids, err := waitForNTxsInMempool(net.Miner.Node, 2, time.Second*15)
|
||||
txids, err := waitForNTxsInMempool(net.Miner.Node, 1, time.Second*20)
|
||||
if err != nil {
|
||||
t.Fatalf("transactions not found in mempool: %v", err)
|
||||
t.Fatalf("expected transaction not found in mempool: %v", err)
|
||||
}
|
||||
|
||||
txidHash, err := getChanPointFundingTxid(bobChanPoint)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txid: %v", err)
|
||||
}
|
||||
|
||||
bobFundingTxid, err := chainhash.NewHash(txidHash)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create sha hash: %v", err)
|
||||
}
|
||||
|
||||
carolFundingPoint := wire.OutPoint{
|
||||
Hash: *bobFundingTxid,
|
||||
Index: bobChanPoint.OutputIndex,
|
||||
}
|
||||
|
||||
tx1, err := net.Miner.Node.GetRawTransaction(txids[0])
|
||||
// The commitment transaction should be spending from the funding
|
||||
// transaction.
|
||||
commitHash := txids[0]
|
||||
tx, err := net.Miner.Node.GetRawTransaction(commitHash)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
tx1Hash := tx1.MsgTx().TxHash()
|
||||
tx2, err := net.Miner.Node.GetRawTransaction(txids[1])
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
tx2Hash := tx2.MsgTx().TxHash()
|
||||
commitTx := tx.MsgTx()
|
||||
|
||||
// Of the two transactions, one should be spending from the funding
|
||||
// transaction, and the second transaction should then be spending from
|
||||
if commitTx.TxIn[0].PreviousOutPoint != carolFundingPoint {
|
||||
t.Fatalf("commit transaction not spending from expected "+
|
||||
"outpoint: %v", spew.Sdump(commitTx))
|
||||
}
|
||||
|
||||
// Confirm the commitment.
|
||||
mineBlocks(t, net, 1)
|
||||
|
||||
// After the force close transaction is mined, Carol should broadcast
|
||||
// her second level HTLC transaction. Bob will broadcast a sweep tx to
|
||||
// sweep his output in the channel with Carol. When Bob notices Carol's
|
||||
// second level transaction in the mempool, he will extract the
|
||||
// preimage and settle the HTLC back off-chain.
|
||||
secondLevelHashes, err := waitForNTxsInMempool(net.Miner.Node, 2,
|
||||
time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("transactions not found in mempool: %v", err)
|
||||
}
|
||||
|
||||
// Carol's second level transaction should be spending from
|
||||
// the commitment transaction.
|
||||
var commitHash *chainhash.Hash
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint == carolFundingPoint {
|
||||
commitHash = &tx1Hash
|
||||
if tx2.MsgTx().TxIn[0].PreviousOutPoint.Hash != *commitHash {
|
||||
t.Fatalf("second transaction not spending commit tx: %v",
|
||||
spew.Sdump(tx2))
|
||||
var secondLevelHash *chainhash.Hash
|
||||
for _, txid := range secondLevelHashes {
|
||||
tx, err := net.Miner.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
|
||||
if tx.MsgTx().TxIn[0].PreviousOutPoint.Hash == *commitHash {
|
||||
secondLevelHash = txid
|
||||
}
|
||||
}
|
||||
if tx2.MsgTx().TxIn[0].PreviousOutPoint == carolFundingPoint {
|
||||
commitHash = &tx2Hash
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint.Hash != *commitHash {
|
||||
t.Fatalf("second transaction not spending commit tx: %v",
|
||||
spew.Sdump(tx1))
|
||||
}
|
||||
}
|
||||
if commitHash == nil {
|
||||
t.Fatalf("commit tx not found in mempool")
|
||||
if secondLevelHash == nil {
|
||||
t.Fatalf("Carol's second level tx not found")
|
||||
}
|
||||
|
||||
// We'll now mine an additional block which should confirm both the
|
||||
// second layer transaction as well as the commitment transaction
|
||||
// itself.
|
||||
// second layer transactions.
|
||||
if _, err := net.Miner.Node.Generate(1); err != nil {
|
||||
t.Fatalf("unable to generate block: %v", err)
|
||||
}
|
||||
@ -6427,17 +6566,32 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
// At this point, Bob should have a pending force close channel as he
|
||||
// just went to chain.
|
||||
pendingChansRequest := &lnrpc.PendingChannelsRequest{}
|
||||
pendingChanResp, err := net.Bob.PendingChannels(ctxb, pendingChansRequest)
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
pendingChanResp, err := net.Bob.PendingChannels(ctxb,
|
||||
pendingChansRequest)
|
||||
if err != nil {
|
||||
predErr = fmt.Errorf("unable to query for pending "+
|
||||
"channels: %v", err)
|
||||
return false
|
||||
}
|
||||
if len(pendingChanResp.PendingForceClosingChannels) == 0 {
|
||||
predErr = fmt.Errorf("bob should have pending for " +
|
||||
"close chan but doesn't")
|
||||
return false
|
||||
}
|
||||
|
||||
forceCloseChan := pendingChanResp.PendingForceClosingChannels[0]
|
||||
if forceCloseChan.LimboBalance == 0 {
|
||||
predErr = fmt.Errorf("bob should have nonzero limbo "+
|
||||
"balance instead has: %v",
|
||||
forceCloseChan.LimboBalance)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for pending channels: %v", err)
|
||||
}
|
||||
if len(pendingChanResp.PendingForceClosingChannels) == 0 {
|
||||
t.Fatalf("bob should have pending for close chan but doesn't")
|
||||
}
|
||||
forceCloseChan := pendingChanResp.PendingForceClosingChannels[0]
|
||||
if forceCloseChan.LimboBalance == 0 {
|
||||
t.Fatalf("bob should have nonzero limbo balance instead "+
|
||||
"has: %v", forceCloseChan.LimboBalance)
|
||||
t.Fatalf(predErr.Error())
|
||||
}
|
||||
|
||||
// We'll now mine enough blocks for the HTLC to expire. After this, Bob
|
||||
@ -6459,12 +6613,12 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
}
|
||||
|
||||
if len(pendingChanResp.PendingForceClosingChannels) == 0 {
|
||||
predErr = fmt.Errorf("bob should have pending for " +
|
||||
predErr = fmt.Errorf("bob should have pending force " +
|
||||
"close chan but doesn't")
|
||||
return false
|
||||
}
|
||||
|
||||
forceCloseChan = pendingChanResp.PendingForceClosingChannels[0]
|
||||
forceCloseChan := pendingChanResp.PendingForceClosingChannels[0]
|
||||
if len(forceCloseChan.PendingHtlcs) != 1 {
|
||||
predErr = fmt.Errorf("bob should have pending htlc " +
|
||||
"but doesn't")
|
||||
@ -6523,7 +6677,7 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
return false
|
||||
}
|
||||
|
||||
forceCloseChan = pendingChanResp.PendingForceClosingChannels[0]
|
||||
forceCloseChan := pendingChanResp.PendingForceClosingChannels[0]
|
||||
if len(forceCloseChan.PendingHtlcs) != 1 {
|
||||
predErr = fmt.Errorf("bob should have pending htlc " +
|
||||
"but doesn't")
|
||||
@ -6559,7 +6713,7 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
// At this point, Bob should no longer show any channels as pending
|
||||
// close.
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
pendingChanResp, err = net.Bob.PendingChannels(
|
||||
pendingChanResp, err := net.Bob.PendingChannels(
|
||||
ctxb, pendingChansRequest,
|
||||
)
|
||||
if err != nil {
|
||||
@ -6642,7 +6796,7 @@ func testMultHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
return true
|
||||
}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("htlc mismatch: %v", err)
|
||||
t.Fatalf("htlc mismatch: %v", predErr)
|
||||
}
|
||||
|
||||
// At this point, we'll now instruct Carol to force close the
|
||||
@ -6654,12 +6808,25 @@ func testMultHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
// At this point, Bob should have a pending force close channel as
|
||||
// Carol has gone directly to chain.
|
||||
pendingChansRequest := &lnrpc.PendingChannelsRequest{}
|
||||
pendingChanResp, err := net.Bob.PendingChannels(ctxb, pendingChansRequest)
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
pendingChanResp, err := net.Bob.PendingChannels(
|
||||
ctxb, pendingChansRequest,
|
||||
)
|
||||
if err != nil {
|
||||
predErr = fmt.Errorf("unable to query for "+
|
||||
"pending channels: %v", err)
|
||||
return false
|
||||
}
|
||||
if len(pendingChanResp.PendingForceClosingChannels) == 0 {
|
||||
predErr = fmt.Errorf("bob should have pending " +
|
||||
"force close channels but doesn't")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query for pending channels: %v", err)
|
||||
}
|
||||
if len(pendingChanResp.PendingForceClosingChannels) == 0 {
|
||||
t.Fatalf("bob should have pending for close chan but doesn't")
|
||||
t.Fatalf(predErr.Error())
|
||||
}
|
||||
|
||||
// Next, we'll mine enough blocks for the HTLC to expire. At this
|
||||
@ -6739,7 +6906,7 @@ func testMultHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
||||
// commitment, he doesn't have to wait for any CSV delays. As a result,
|
||||
// he should show no additional pending transactions.
|
||||
err = lntest.WaitPredicate(func() bool {
|
||||
pendingChanResp, err = net.Bob.PendingChannels(
|
||||
pendingChanResp, err := net.Bob.PendingChannels(
|
||||
ctxb, pendingChansRequest,
|
||||
)
|
||||
if err != nil {
|
||||
@ -6835,9 +7002,8 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest)
|
||||
t.Fatalf("unable to generate blocks")
|
||||
}
|
||||
|
||||
// Carol's commitment transaction should now be in the mempool. She
|
||||
// should also have broadcast her second level HTLC transaction.
|
||||
txids, err := waitForNTxsInMempool(net.Miner.Node, 2, time.Second*15)
|
||||
// Carol's commitment transaction should now be in the mempool.
|
||||
txids, err := waitForNTxsInMempool(net.Miner.Node, 1, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("transactions not found in mempool: %v", err)
|
||||
}
|
||||
@ -6854,50 +7020,52 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest)
|
||||
Index: bobChanPoint.OutputIndex,
|
||||
}
|
||||
|
||||
// Of the two transactions, one should be spending from the funding
|
||||
// transaction, and the second transaction should then be spending from
|
||||
// The tx should be spending from the funding transaction,
|
||||
commitHash := txids[0]
|
||||
tx1, err := net.Miner.Node.GetRawTransaction(commitHash)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint != carolFundingPoint {
|
||||
t.Fatalf("commit transaction not spending fundingtx: %v",
|
||||
spew.Sdump(tx1))
|
||||
}
|
||||
|
||||
// Mine a block that should confirm the commit tx.
|
||||
block := mineBlocks(t, net, 1)[0]
|
||||
if len(block.Transactions) != 2 {
|
||||
t.Fatalf("expected 2 transactions in block, got %v",
|
||||
len(block.Transactions))
|
||||
}
|
||||
assertTxInBlock(t, block, commitHash)
|
||||
|
||||
// After the force close transacion is mined, Carol should broadcast
|
||||
// her second level HTLC transacion. Bob will braodcast a sweep tx to
|
||||
// sweep his output in the channel with Carol. When Bob notices Carol's
|
||||
// second level transaction in the mempool, he will extract the
|
||||
// preimage and broadcast a second level tx to claim the HTLC in his
|
||||
// (already closed) channel with Alice.
|
||||
secondLevelHashes, err := waitForNTxsInMempool(net.Miner.Node, 3,
|
||||
time.Second*20)
|
||||
if err != nil {
|
||||
t.Fatalf("transactions not found in mempool: %v", err)
|
||||
}
|
||||
|
||||
// Carol's second level transaction should be spending from
|
||||
// the commitment transaction.
|
||||
var commitHash *chainhash.Hash
|
||||
tx1, err := net.Miner.Node.GetRawTransaction(txids[0])
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
tx1Hash := tx1.MsgTx().TxHash()
|
||||
tx2, err := net.Miner.Node.GetRawTransaction(txids[1])
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
tx2Hash := tx2.MsgTx().TxHash()
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint == carolFundingPoint {
|
||||
commitHash = &tx1Hash
|
||||
if tx2.MsgTx().TxIn[0].PreviousOutPoint.Hash != *commitHash {
|
||||
t.Fatalf("second transaction not spending commit tx: %v",
|
||||
spew.Sdump(tx2))
|
||||
var secondLevelHash *chainhash.Hash
|
||||
for _, txid := range secondLevelHashes {
|
||||
tx, err := net.Miner.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
|
||||
if tx.MsgTx().TxIn[0].PreviousOutPoint.Hash == *commitHash {
|
||||
secondLevelHash = txid
|
||||
}
|
||||
}
|
||||
if tx2.MsgTx().TxIn[0].PreviousOutPoint == carolFundingPoint {
|
||||
commitHash = &tx2Hash
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint.Hash != *commitHash {
|
||||
t.Fatalf("second transaction not spending commit tx: %v",
|
||||
spew.Sdump(tx1))
|
||||
}
|
||||
}
|
||||
if commitHash == nil {
|
||||
t.Fatalf("commit tx not found in mempool")
|
||||
}
|
||||
|
||||
// We'll now mine a block which should confirm both the second layer
|
||||
// transaction as well as the commitment transaction.
|
||||
if _, err := net.Miner.Node.Generate(1); err != nil {
|
||||
t.Fatalf("unable to generate block: %v", err)
|
||||
}
|
||||
|
||||
// At this point, Bob should detect that Carol has revealed the
|
||||
// preimage on-chain. As a result, he should now attempt to broadcast
|
||||
// his second-layer claim transaction to claim the output.
|
||||
_, err = waitForTxInMempool(net.Miner.Node, time.Second*10)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find bob's sweeping transaction")
|
||||
if secondLevelHash == nil {
|
||||
t.Fatalf("Carol's second level tx not found")
|
||||
}
|
||||
|
||||
// At this point, Bob should have broadcast his second layer success
|
||||
@ -6929,9 +7097,11 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest)
|
||||
"but doesn't")
|
||||
return false
|
||||
}
|
||||
if forceCloseChan.PendingHtlcs[0].Stage != 1 {
|
||||
stage := forceCloseChan.PendingHtlcs[0].Stage
|
||||
if stage != 1 {
|
||||
predErr = fmt.Errorf("bob's htlc should have "+
|
||||
"advanced to the first stage: %v", err)
|
||||
"advanced to the first stage but was "+
|
||||
"stage: %v", stage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -6942,6 +7112,15 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest)
|
||||
t.Fatalf("bob didn't hand off time-locked HTLC: %v", predErr)
|
||||
}
|
||||
|
||||
// We'll now mine a block which should confirm the two second layer
|
||||
// transactions and the commit sweep.
|
||||
block = mineBlocks(t, net, 1)[0]
|
||||
if len(block.Transactions) != 4 {
|
||||
t.Fatalf("expected 4 transactions in block, got %v",
|
||||
len(block.Transactions))
|
||||
}
|
||||
assertTxInBlock(t, block, secondLevelHash)
|
||||
|
||||
// If we then mine 4 additional blocks, Bob should pull the output
|
||||
// destined for him.
|
||||
if _, err := net.Miner.Node.Generate(defaultCSV); err != nil {
|
||||
@ -6994,6 +7173,8 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
|
||||
timeout := time.Duration(time.Second * 15)
|
||||
ctxb := context.Background()
|
||||
|
||||
defaultCSV := uint32(4)
|
||||
|
||||
// First, we'll create a three hop network: Alice -> Bob -> Carol, with
|
||||
// Carol refusing to actually settle or directly cancel any HTLC's
|
||||
// self.
|
||||
@ -7052,9 +7233,8 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
|
||||
t.Fatalf("unable to generate blocks")
|
||||
}
|
||||
|
||||
// Carol's commitment transaction should now be in the mempool. She
|
||||
// should also have broadcast her second level HTLC transaction.
|
||||
txids, err := waitForNTxsInMempool(net.Miner.Node, 2, time.Second*15)
|
||||
// Carol's commitment transaction should now be in the mempool.
|
||||
txids, err := waitForNTxsInMempool(net.Miner.Node, 1, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("transactions not found in mempool: %v", err)
|
||||
}
|
||||
@ -7071,48 +7251,70 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
|
||||
Index: bobChanPoint.OutputIndex,
|
||||
}
|
||||
|
||||
// Of the two transactions, one should be spending from the funding
|
||||
// transaction, and the second transaction should then be spending from
|
||||
// the commitment transaction.
|
||||
var commitHash *chainhash.Hash
|
||||
tx1, err := net.Miner.Node.GetRawTransaction(txids[0])
|
||||
// The transaction should be spending from the funding transaction
|
||||
commitHash := txids[0]
|
||||
tx1, err := net.Miner.Node.GetRawTransaction(commitHash)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
tx1Hash := tx1.MsgTx().TxHash()
|
||||
tx2, err := net.Miner.Node.GetRawTransaction(txids[1])
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
tx2Hash := tx2.MsgTx().TxHash()
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint == carolFundingPoint {
|
||||
commitHash = &tx1Hash
|
||||
if tx2.MsgTx().TxIn[0].PreviousOutPoint.Hash != *commitHash {
|
||||
t.Fatalf("second transaction not spending commit tx: %v",
|
||||
spew.Sdump(tx2))
|
||||
}
|
||||
}
|
||||
if tx2.MsgTx().TxIn[0].PreviousOutPoint == carolFundingPoint {
|
||||
commitHash = &tx2Hash
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint.Hash != *commitHash {
|
||||
t.Fatalf("second transaction not spending commit tx: %v",
|
||||
spew.Sdump(tx1))
|
||||
}
|
||||
}
|
||||
if commitHash == nil {
|
||||
t.Fatalf("commit tx not found in mempool")
|
||||
if tx1.MsgTx().TxIn[0].PreviousOutPoint != carolFundingPoint {
|
||||
t.Fatalf("commit transaction not spending fundingtx: %v",
|
||||
spew.Sdump(tx1))
|
||||
}
|
||||
|
||||
// We'll now mine a block which should confirm both the second layer
|
||||
// transaction as well as the commitment transaction.
|
||||
if _, err := net.Miner.Node.Generate(1); err != nil {
|
||||
// Mine a block, which should contain the commitment.
|
||||
block := mineBlocks(t, net, 1)[0]
|
||||
if len(block.Transactions) != 2 {
|
||||
t.Fatalf("expected 2 transactions in block, got %v",
|
||||
len(block.Transactions))
|
||||
}
|
||||
assertTxInBlock(t, block, commitHash)
|
||||
|
||||
// After the force close transacion is mined, Carol should broadcast
|
||||
// her second level HTLC transacion. Bob will braodcast a sweep tx to
|
||||
// sweep his output in the channel with Carol. When Bob notices Carol's
|
||||
// second level transaction in the mempool, he will extract the
|
||||
// preimage and broadcast a second level tx to claim the HTLC in his
|
||||
// (already closed) channel with Alice.
|
||||
secondLevelHashes, err := waitForNTxsInMempool(net.Miner.Node, 3,
|
||||
time.Second*20)
|
||||
if err != nil {
|
||||
t.Fatalf("transactions not found in mempool: %v", err)
|
||||
}
|
||||
|
||||
// Carol's second level transaction should be spending from
|
||||
// the commitment transaction.
|
||||
var secondLevelHash *chainhash.Hash
|
||||
for _, txid := range secondLevelHashes {
|
||||
tx, err := net.Miner.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get txn: %v", err)
|
||||
}
|
||||
|
||||
if tx.MsgTx().TxIn[0].PreviousOutPoint.Hash == *commitHash {
|
||||
secondLevelHash = txid
|
||||
}
|
||||
}
|
||||
if secondLevelHash == nil {
|
||||
t.Fatalf("Carol's second level tx not found")
|
||||
}
|
||||
|
||||
// We'll now mine a block which should confirm the two second layer
|
||||
// transactions and the commit sweep.
|
||||
block = mineBlocks(t, net, 1)[0]
|
||||
if len(block.Transactions) != 4 {
|
||||
t.Fatalf("expected 4 transactions in block, got %v",
|
||||
len(block.Transactions))
|
||||
}
|
||||
assertTxInBlock(t, block, secondLevelHash)
|
||||
|
||||
// If we then mine 4 additional blocks, Bob should pull the output
|
||||
// destined for him.
|
||||
if _, err := net.Miner.Node.Generate(defaultCSV); err != nil {
|
||||
t.Fatalf("unable to generate block: %v", err)
|
||||
}
|
||||
|
||||
// With the block mined above, Bob should detect that Carol is
|
||||
// attempting to sweep the HTLC on-chain, and should obtain the
|
||||
// preimage.
|
||||
_, err = waitForNTxsInMempool(net.Miner.Node, 2, time.Second*15)
|
||||
_, err = waitForNTxsInMempool(net.Miner.Node, 1, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find bob's sweeping transaction")
|
||||
}
|
||||
|
763
lnrpc/rpc.pb.go
763
lnrpc/rpc.pb.go
@ -521,7 +521,9 @@ func (m *ChannelPoint) String() string { return proto.CompactTextStri
|
||||
func (*ChannelPoint) ProtoMessage() {}
|
||||
func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
|
||||
|
||||
type isChannelPoint_FundingTxid interface{ isChannelPoint_FundingTxid() }
|
||||
type isChannelPoint_FundingTxid interface {
|
||||
isChannelPoint_FundingTxid()
|
||||
}
|
||||
|
||||
type ChannelPoint_FundingTxidBytes struct {
|
||||
FundingTxidBytes []byte `protobuf:"bytes,1,opt,name=funding_txid_bytes,proto3,oneof"`
|
||||
@ -1608,7 +1610,9 @@ func (m *CloseStatusUpdate) String() string { return proto.CompactTex
|
||||
func (*CloseStatusUpdate) ProtoMessage() {}
|
||||
func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} }
|
||||
|
||||
type isCloseStatusUpdate_Update interface{ isCloseStatusUpdate_Update() }
|
||||
type isCloseStatusUpdate_Update interface {
|
||||
isCloseStatusUpdate_Update()
|
||||
}
|
||||
|
||||
type CloseStatusUpdate_ClosePending struct {
|
||||
ClosePending *PendingUpdate `protobuf:"bytes,1,opt,name=close_pending,oneof"`
|
||||
@ -1871,7 +1875,9 @@ func (m *OpenStatusUpdate) String() string { return proto.CompactText
|
||||
func (*OpenStatusUpdate) ProtoMessage() {}
|
||||
func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} }
|
||||
|
||||
type isOpenStatusUpdate_Update interface{ isOpenStatusUpdate_Update() }
|
||||
type isOpenStatusUpdate_Update interface {
|
||||
isOpenStatusUpdate_Update()
|
||||
}
|
||||
|
||||
type OpenStatusUpdate_ChanPending struct {
|
||||
ChanPending *PendingUpdate `protobuf:"bytes,1,opt,name=chan_pending,oneof"`
|
||||
@ -2090,6 +2096,8 @@ type PendingChannelsResponse struct {
|
||||
PendingClosingChannels []*PendingChannelsResponse_ClosedChannel `protobuf:"bytes,3,rep,name=pending_closing_channels" json:"pending_closing_channels,omitempty"`
|
||||
// / Channels pending force closing
|
||||
PendingForceClosingChannels []*PendingChannelsResponse_ForceClosedChannel `protobuf:"bytes,4,rep,name=pending_force_closing_channels" json:"pending_force_closing_channels,omitempty"`
|
||||
// / Channels waiting for closing tx to confirm
|
||||
WaitingCloseChannels []*PendingChannelsResponse_WaitingCloseChannel `protobuf:"bytes,5,rep,name=waiting_close_channels" json:"waiting_close_channels,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse) Reset() { *m = PendingChannelsResponse{} }
|
||||
@ -2125,6 +2133,13 @@ func (m *PendingChannelsResponse) GetPendingForceClosingChannels() []*PendingCha
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse) GetWaitingCloseChannels() []*PendingChannelsResponse_WaitingCloseChannel {
|
||||
if m != nil {
|
||||
return m.WaitingCloseChannels
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PendingChannelsResponse_PendingChannel struct {
|
||||
RemoteNodePub string `protobuf:"bytes,1,opt,name=remote_node_pub" json:"remote_node_pub,omitempty"`
|
||||
ChannelPoint string `protobuf:"bytes,2,opt,name=channel_point" json:"channel_point,omitempty"`
|
||||
@ -2244,6 +2259,38 @@ func (m *PendingChannelsResponse_PendingOpenChannel) GetFeePerKw() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type PendingChannelsResponse_WaitingCloseChannel struct {
|
||||
// / The pending channel waiting for closing tx to confirm
|
||||
Channel *PendingChannelsResponse_PendingChannel `protobuf:"bytes,1,opt,name=channel" json:"channel,omitempty"`
|
||||
// / The balance in satoshis encumbered in this channel
|
||||
LimboBalance int64 `protobuf:"varint,2,opt,name=limbo_balance" json:"limbo_balance,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse_WaitingCloseChannel) Reset() {
|
||||
*m = PendingChannelsResponse_WaitingCloseChannel{}
|
||||
}
|
||||
func (m *PendingChannelsResponse_WaitingCloseChannel) String() string {
|
||||
return proto.CompactTextString(m)
|
||||
}
|
||||
func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {}
|
||||
func (*PendingChannelsResponse_WaitingCloseChannel) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{47, 2}
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse_WaitingCloseChannel) GetChannel() *PendingChannelsResponse_PendingChannel {
|
||||
if m != nil {
|
||||
return m.Channel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse_WaitingCloseChannel) GetLimboBalance() int64 {
|
||||
if m != nil {
|
||||
return m.LimboBalance
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type PendingChannelsResponse_ClosedChannel struct {
|
||||
// / The pending channel to be closed
|
||||
Channel *PendingChannelsResponse_PendingChannel `protobuf:"bytes,1,opt,name=channel" json:"channel,omitempty"`
|
||||
@ -2255,7 +2302,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 fileDescriptor0, []int{47, 2}
|
||||
return fileDescriptor0, []int{47, 3}
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse_ClosedChannel) GetChannel() *PendingChannelsResponse_PendingChannel {
|
||||
@ -2299,7 +2346,7 @@ func (m *PendingChannelsResponse_ForceClosedChannel) String() string {
|
||||
}
|
||||
func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {}
|
||||
func (*PendingChannelsResponse_ForceClosedChannel) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{47, 3}
|
||||
return fileDescriptor0, []int{47, 4}
|
||||
}
|
||||
|
||||
func (m *PendingChannelsResponse_ForceClosedChannel) GetChannel() *PendingChannelsResponse_PendingChannel {
|
||||
@ -3916,7 +3963,9 @@ func (m *PolicyUpdateRequest) String() string { return proto.CompactT
|
||||
func (*PolicyUpdateRequest) ProtoMessage() {}
|
||||
func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} }
|
||||
|
||||
type isPolicyUpdateRequest_Scope interface{ isPolicyUpdateRequest_Scope() }
|
||||
type isPolicyUpdateRequest_Scope interface {
|
||||
isPolicyUpdateRequest_Scope()
|
||||
}
|
||||
|
||||
type PolicyUpdateRequest_Global struct {
|
||||
Global bool `protobuf:"varint,1,opt,name=global,oneof"`
|
||||
@ -4234,6 +4283,7 @@ func init() {
|
||||
proto.RegisterType((*PendingChannelsResponse)(nil), "lnrpc.PendingChannelsResponse")
|
||||
proto.RegisterType((*PendingChannelsResponse_PendingChannel)(nil), "lnrpc.PendingChannelsResponse.PendingChannel")
|
||||
proto.RegisterType((*PendingChannelsResponse_PendingOpenChannel)(nil), "lnrpc.PendingChannelsResponse.PendingOpenChannel")
|
||||
proto.RegisterType((*PendingChannelsResponse_WaitingCloseChannel)(nil), "lnrpc.PendingChannelsResponse.WaitingCloseChannel")
|
||||
proto.RegisterType((*PendingChannelsResponse_ClosedChannel)(nil), "lnrpc.PendingChannelsResponse.ClosedChannel")
|
||||
proto.RegisterType((*PendingChannelsResponse_ForceClosedChannel)(nil), "lnrpc.PendingChannelsResponse.ForceClosedChannel")
|
||||
proto.RegisterType((*WalletBalanceRequest)(nil), "lnrpc.WalletBalanceRequest")
|
||||
@ -6301,353 +6351,356 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{
|
||||
func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 5566 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0xcd, 0x93, 0x1c, 0xc9,
|
||||
0x55, 0x57, 0xf5, 0xf4, 0x7c, 0xf4, 0xeb, 0x9e, 0x9e, 0x99, 0x9c, 0xd1, 0xa8, 0xd5, 0xd2, 0x6a,
|
||||
0xb5, 0xe5, 0x8d, 0x95, 0x18, 0x16, 0x8d, 0x76, 0x6c, 0x2f, 0xeb, 0x15, 0xac, 0xd1, 0xf7, 0xac,
|
||||
0xad, 0x95, 0xc7, 0x35, 0x92, 0x17, 0xbc, 0x40, 0xbb, 0xa6, 0x3b, 0xa7, 0xa7, 0xac, 0xea, 0xaa,
|
||||
0xda, 0xaa, 0xea, 0x19, 0xf5, 0x2e, 0x8a, 0xe0, 0x23, 0x82, 0x13, 0x0e, 0x0e, 0x70, 0x31, 0x04,
|
||||
0x41, 0x84, 0x7d, 0x81, 0x03, 0x47, 0x4e, 0xe6, 0x2f, 0x70, 0x04, 0xc1, 0x61, 0x4f, 0x0e, 0x6e,
|
||||
0x7c, 0x1c, 0xc0, 0xc1, 0x85, 0x08, 0x2e, 0x1c, 0x08, 0xe2, 0xbd, 0xfc, 0xa8, 0xcc, 0xaa, 0x1a,
|
||||
0x49, 0xb6, 0xc1, 0xb7, 0xce, 0x5f, 0xbe, 0x7a, 0xf9, 0xf5, 0xde, 0xcb, 0xf7, 0x5e, 0x66, 0x36,
|
||||
0xb4, 0xd2, 0x64, 0x78, 0x2d, 0x49, 0xe3, 0x3c, 0x66, 0xf3, 0x61, 0x94, 0x26, 0xc3, 0xfe, 0xc5,
|
||||
0x71, 0x1c, 0x8f, 0x43, 0xbe, 0xed, 0x27, 0xc1, 0xb6, 0x1f, 0x45, 0x71, 0xee, 0xe7, 0x41, 0x1c,
|
||||
0x65, 0x82, 0xc8, 0xfd, 0x16, 0x74, 0xef, 0xf3, 0x68, 0x9f, 0xf3, 0x91, 0xc7, 0x3f, 0x9e, 0xf2,
|
||||
0x2c, 0x67, 0xbf, 0x08, 0x6b, 0x3e, 0xff, 0x84, 0xf3, 0xd1, 0x20, 0xf1, 0xb3, 0x2c, 0x39, 0x4a,
|
||||
0xfd, 0x8c, 0xf7, 0x9c, 0xcb, 0xce, 0xd5, 0x8e, 0xb7, 0x2a, 0x2a, 0xf6, 0x34, 0xce, 0x5e, 0x83,
|
||||
0x4e, 0x86, 0xa4, 0x3c, 0xca, 0xd3, 0x38, 0x99, 0xf5, 0x1a, 0x44, 0xd7, 0x46, 0xec, 0xae, 0x80,
|
||||
0xdc, 0x10, 0x56, 0x74, 0x0b, 0x59, 0x12, 0x47, 0x19, 0x67, 0xd7, 0x61, 0x63, 0x18, 0x24, 0x47,
|
||||
0x3c, 0x1d, 0xd0, 0xc7, 0x93, 0x88, 0x4f, 0xe2, 0x28, 0x18, 0xf6, 0x9c, 0xcb, 0x73, 0x57, 0x5b,
|
||||
0x1e, 0x13, 0x75, 0xf8, 0xc5, 0x07, 0xb2, 0x86, 0x5d, 0x81, 0x15, 0x1e, 0x09, 0x9c, 0x8f, 0xe8,
|
||||
0x2b, 0xd9, 0x54, 0xb7, 0x80, 0xf1, 0x03, 0xf7, 0xcf, 0x1d, 0x58, 0x7b, 0x3f, 0x0a, 0xf2, 0x0f,
|
||||
0xfd, 0x30, 0xe4, 0xb9, 0x1a, 0xd3, 0x15, 0x58, 0x39, 0x21, 0x80, 0xc6, 0x74, 0x12, 0xa7, 0x23,
|
||||
0x39, 0xa2, 0xae, 0x80, 0xf7, 0x24, 0x7a, 0x6a, 0xcf, 0x1a, 0xa7, 0xf6, 0xac, 0x76, 0xba, 0xe6,
|
||||
0xea, 0xa7, 0xcb, 0xdd, 0x00, 0x66, 0x76, 0x4e, 0x4c, 0x87, 0xfb, 0x1e, 0xac, 0x3f, 0x8e, 0xc2,
|
||||
0x78, 0xf8, 0xe4, 0xa7, 0xeb, 0xb4, 0xbb, 0x09, 0x1b, 0xf6, 0xf7, 0x92, 0xef, 0x77, 0x1b, 0xd0,
|
||||
0x7e, 0x94, 0xfa, 0x51, 0xe6, 0x0f, 0x71, 0xc9, 0x59, 0x0f, 0x16, 0xf3, 0xa7, 0x83, 0x23, 0x3f,
|
||||
0x3b, 0x22, 0x46, 0x2d, 0x4f, 0x15, 0xd9, 0x26, 0x2c, 0xf8, 0x93, 0x78, 0x1a, 0xe5, 0x34, 0xab,
|
||||
0x73, 0x9e, 0x2c, 0xb1, 0x37, 0x61, 0x2d, 0x9a, 0x4e, 0x06, 0xc3, 0x38, 0x3a, 0x0c, 0xd2, 0x89,
|
||||
0x10, 0x1c, 0x1a, 0xdc, 0xbc, 0x57, 0xad, 0x60, 0x97, 0x00, 0x0e, 0xb0, 0x1b, 0xa2, 0x89, 0x26,
|
||||
0x35, 0x61, 0x20, 0xcc, 0x85, 0x8e, 0x2c, 0xf1, 0x60, 0x7c, 0x94, 0xf7, 0xe6, 0x89, 0x91, 0x85,
|
||||
0x21, 0x8f, 0x3c, 0x98, 0xf0, 0x41, 0x96, 0xfb, 0x93, 0xa4, 0xb7, 0x40, 0xbd, 0x31, 0x10, 0xaa,
|
||||
0x8f, 0x73, 0x3f, 0x1c, 0x1c, 0x72, 0x9e, 0xf5, 0x16, 0x65, 0xbd, 0x46, 0xd8, 0x1b, 0xd0, 0x1d,
|
||||
0xf1, 0x2c, 0x1f, 0xf8, 0xa3, 0x51, 0xca, 0xb3, 0x8c, 0x67, 0xbd, 0x25, 0x5a, 0xba, 0x12, 0xea,
|
||||
0xf6, 0x60, 0xf3, 0x3e, 0xcf, 0x8d, 0xd9, 0xc9, 0xe4, 0xb4, 0xbb, 0x0f, 0x80, 0x19, 0xf0, 0x1d,
|
||||
0x9e, 0xfb, 0x41, 0x98, 0xb1, 0xb7, 0xa1, 0x93, 0x1b, 0xc4, 0x24, 0xaa, 0xed, 0x1d, 0x76, 0x8d,
|
||||
0x74, 0xec, 0x9a, 0xf1, 0x81, 0x67, 0xd1, 0xb9, 0xff, 0xed, 0x40, 0x7b, 0x9f, 0x47, 0x5a, 0xbb,
|
||||
0x18, 0x34, 0xb1, 0x27, 0x72, 0x25, 0xe9, 0x37, 0x7b, 0x15, 0xda, 0xd4, 0xbb, 0x2c, 0x4f, 0x83,
|
||||
0x68, 0x4c, 0x4b, 0xd0, 0xf2, 0x00, 0xa1, 0x7d, 0x42, 0xd8, 0x2a, 0xcc, 0xf9, 0x93, 0x9c, 0x26,
|
||||
0x7e, 0xce, 0xc3, 0x9f, 0xa8, 0x77, 0x89, 0x3f, 0x9b, 0xf0, 0x28, 0x2f, 0x26, 0xbb, 0xe3, 0xb5,
|
||||
0x25, 0xb6, 0x8b, 0xb3, 0x7d, 0x0d, 0xd6, 0x4d, 0x12, 0xc5, 0x7d, 0x9e, 0xb8, 0xaf, 0x19, 0x94,
|
||||
0xb2, 0x91, 0x2b, 0xb0, 0xa2, 0xe8, 0x53, 0xd1, 0x59, 0x9a, 0xfe, 0x96, 0xd7, 0x95, 0xb0, 0x1a,
|
||||
0xc2, 0x55, 0x58, 0x3d, 0x0c, 0x22, 0x3f, 0x1c, 0x0c, 0xc3, 0xfc, 0x78, 0x30, 0xe2, 0x61, 0xee,
|
||||
0xd3, 0x42, 0xcc, 0x7b, 0x5d, 0xc2, 0x6f, 0x87, 0xf9, 0xf1, 0x1d, 0x44, 0xdd, 0x3f, 0x75, 0xa0,
|
||||
0x23, 0x06, 0x2f, 0x15, 0xff, 0x75, 0x58, 0x56, 0x6d, 0xf0, 0x34, 0x8d, 0x53, 0x29, 0x87, 0x36,
|
||||
0xc8, 0xb6, 0x60, 0x55, 0x01, 0x49, 0xca, 0x83, 0x89, 0x3f, 0xe6, 0x52, 0xdb, 0x2b, 0x38, 0xdb,
|
||||
0x29, 0x38, 0xa6, 0xf1, 0x34, 0x17, 0xaa, 0xd7, 0xde, 0xe9, 0xc8, 0x85, 0xf1, 0x10, 0xf3, 0x6c,
|
||||
0x12, 0xf7, 0x7b, 0x0e, 0x74, 0x6e, 0x1f, 0xf9, 0x51, 0xc4, 0xc3, 0xbd, 0x38, 0x88, 0x72, 0x76,
|
||||
0x1d, 0xd8, 0xe1, 0x34, 0x1a, 0x05, 0xd1, 0x78, 0x90, 0x3f, 0x0d, 0x46, 0x83, 0x83, 0x59, 0xce,
|
||||
0x33, 0xb1, 0x44, 0xbb, 0x67, 0xbc, 0x9a, 0x3a, 0xf6, 0x26, 0xac, 0x5a, 0x68, 0x96, 0xa7, 0x62,
|
||||
0xdd, 0x76, 0xcf, 0x78, 0x95, 0x1a, 0x14, 0xfc, 0x78, 0x9a, 0x27, 0xd3, 0x7c, 0x10, 0x44, 0x23,
|
||||
0xfe, 0x94, 0xfa, 0xb8, 0xec, 0x59, 0xd8, 0xad, 0x2e, 0x74, 0xcc, 0xef, 0xdc, 0xf7, 0x60, 0xf5,
|
||||
0x01, 0x6a, 0x44, 0x14, 0x44, 0xe3, 0x9b, 0x42, 0x6c, 0x51, 0x4d, 0x93, 0xe9, 0xc1, 0x13, 0x3e,
|
||||
0x93, 0xf3, 0x26, 0x4b, 0x28, 0x54, 0x47, 0x71, 0x96, 0x4b, 0xc9, 0xa1, 0xdf, 0xee, 0x3f, 0x3b,
|
||||
0xb0, 0x82, 0x73, 0xff, 0x81, 0x1f, 0xcd, 0xd4, 0xca, 0x3d, 0x80, 0x0e, 0xb2, 0x7a, 0x14, 0xdf,
|
||||
0x14, 0xca, 0x2e, 0x84, 0xf8, 0xaa, 0x9c, 0xab, 0x12, 0xf5, 0x35, 0x93, 0x14, 0x8d, 0xf9, 0xcc,
|
||||
0xb3, 0xbe, 0x46, 0xb1, 0xcd, 0xfd, 0x74, 0xcc, 0x73, 0x32, 0x03, 0xd2, 0x2c, 0x80, 0x80, 0x6e,
|
||||
0xc7, 0xd1, 0x21, 0xbb, 0x0c, 0x9d, 0xcc, 0xcf, 0x07, 0x09, 0x4f, 0x69, 0xd6, 0x48, 0xf4, 0xe6,
|
||||
0x3c, 0xc8, 0xfc, 0x7c, 0x8f, 0xa7, 0xb7, 0x66, 0x39, 0xef, 0x7f, 0x19, 0xd6, 0x2a, 0xad, 0xa0,
|
||||
0xb4, 0x17, 0x43, 0xc4, 0x9f, 0x6c, 0x03, 0xe6, 0x8f, 0xfd, 0x70, 0xca, 0xa5, 0x75, 0x12, 0x85,
|
||||
0x77, 0x1b, 0xef, 0x38, 0xee, 0x1b, 0xb0, 0x5a, 0x74, 0x5b, 0x0a, 0x19, 0x83, 0x26, 0xce, 0xa0,
|
||||
0x64, 0x40, 0xbf, 0xdd, 0xdf, 0x73, 0x04, 0xe1, 0xed, 0x38, 0xd0, 0x9a, 0x8e, 0x84, 0x68, 0x10,
|
||||
0x14, 0x21, 0xfe, 0x3e, 0xd5, 0x12, 0xfe, 0xec, 0x83, 0x75, 0xaf, 0xc0, 0x9a, 0xd1, 0x85, 0xe7,
|
||||
0x74, 0xf6, 0x3b, 0x0e, 0xac, 0x3d, 0xe4, 0x27, 0x72, 0xd5, 0x55, 0x6f, 0xdf, 0x81, 0x66, 0x3e,
|
||||
0x4b, 0xc4, 0x56, 0xdc, 0xdd, 0x79, 0x5d, 0x2e, 0x5a, 0x85, 0xee, 0x9a, 0x2c, 0x3e, 0x9a, 0x25,
|
||||
0xdc, 0xa3, 0x2f, 0xdc, 0xf7, 0xa0, 0x6d, 0x80, 0xec, 0x1c, 0xac, 0x7f, 0xf8, 0xfe, 0xa3, 0x87,
|
||||
0x77, 0xf7, 0xf7, 0x07, 0x7b, 0x8f, 0x6f, 0x7d, 0xf5, 0xee, 0x6f, 0x0c, 0x76, 0x6f, 0xee, 0xef,
|
||||
0xae, 0x9e, 0x61, 0x9b, 0xc0, 0x1e, 0xde, 0xdd, 0x7f, 0x74, 0xf7, 0x8e, 0x85, 0x3b, 0x6e, 0x1f,
|
||||
0x7a, 0x0f, 0xf9, 0xc9, 0x87, 0x41, 0x1e, 0xf1, 0x2c, 0xb3, 0x5b, 0x73, 0xaf, 0x01, 0x33, 0xbb,
|
||||
0x20, 0x47, 0xd5, 0x83, 0x45, 0x69, 0x6a, 0xd5, 0x4e, 0x23, 0x8b, 0xee, 0x1b, 0xc0, 0xf6, 0x83,
|
||||
0x71, 0xf4, 0x01, 0xcf, 0x32, 0x7f, 0xcc, 0xd5, 0xd8, 0x56, 0x61, 0x6e, 0x92, 0x8d, 0xa5, 0x51,
|
||||
0xc4, 0x9f, 0xee, 0xe7, 0x61, 0xdd, 0xa2, 0x93, 0x8c, 0x2f, 0x42, 0x2b, 0x0b, 0xc6, 0x91, 0x9f,
|
||||
0x4f, 0x53, 0x2e, 0x59, 0x17, 0x80, 0x7b, 0x0f, 0x36, 0xbe, 0xc1, 0xd3, 0xe0, 0x70, 0xf6, 0x22,
|
||||
0xf6, 0x36, 0x9f, 0x46, 0x99, 0xcf, 0x5d, 0x38, 0x5b, 0xe2, 0x23, 0x9b, 0x17, 0x82, 0x28, 0x97,
|
||||
0x6b, 0xc9, 0x13, 0x05, 0x43, 0x2d, 0x1b, 0xa6, 0x5a, 0xba, 0x8f, 0x81, 0xdd, 0x8e, 0xa3, 0x88,
|
||||
0x0f, 0xf3, 0x3d, 0xce, 0xd3, 0xc2, 0xbf, 0x2a, 0xa4, 0xae, 0xbd, 0x73, 0x4e, 0xae, 0x63, 0x59,
|
||||
0xd7, 0xa5, 0x38, 0x32, 0x68, 0x26, 0x3c, 0x9d, 0x10, 0xe3, 0x25, 0x8f, 0x7e, 0xbb, 0x67, 0x61,
|
||||
0xdd, 0x62, 0x2b, 0x77, 0xfb, 0xb7, 0xe0, 0xec, 0x9d, 0x20, 0x1b, 0x56, 0x1b, 0xec, 0xc1, 0x62,
|
||||
0x32, 0x3d, 0x18, 0x14, 0x3a, 0xa5, 0x8a, 0xb8, 0x09, 0x96, 0x3f, 0x91, 0xcc, 0xfe, 0xd0, 0x81,
|
||||
0xe6, 0xee, 0xa3, 0x07, 0xb7, 0x59, 0x1f, 0x96, 0x82, 0x68, 0x18, 0x4f, 0x70, 0xeb, 0x10, 0x83,
|
||||
0xd6, 0xe5, 0x53, 0x75, 0xe5, 0x22, 0xb4, 0x68, 0xc7, 0xc1, 0x7d, 0x5d, 0xba, 0x42, 0x05, 0x80,
|
||||
0x3e, 0x05, 0x7f, 0x9a, 0x04, 0x29, 0x39, 0x0d, 0xca, 0x15, 0x68, 0x92, 0x45, 0xac, 0x56, 0xb8,
|
||||
0xff, 0xd3, 0x84, 0x45, 0x69, 0xab, 0xa9, 0xbd, 0x61, 0x1e, 0x1c, 0x73, 0xd9, 0x13, 0x59, 0xc2,
|
||||
0x5d, 0x25, 0xe5, 0x93, 0x38, 0xe7, 0x03, 0x6b, 0x19, 0x6c, 0x10, 0xa9, 0x86, 0x82, 0xd1, 0x20,
|
||||
0x41, 0xab, 0x4f, 0x3d, 0x6b, 0x79, 0x36, 0x88, 0x93, 0x85, 0xc0, 0x20, 0x18, 0x51, 0x9f, 0x9a,
|
||||
0x9e, 0x2a, 0xe2, 0x4c, 0x0c, 0xfd, 0xc4, 0x1f, 0x06, 0xf9, 0x4c, 0x2a, 0xb7, 0x2e, 0x23, 0xef,
|
||||
0x30, 0x1e, 0xfa, 0xe1, 0xe0, 0xc0, 0x0f, 0xfd, 0x68, 0xc8, 0xa5, 0xe3, 0x62, 0x83, 0xe8, 0x9b,
|
||||
0xc8, 0x2e, 0x29, 0x32, 0xe1, 0xbf, 0x94, 0x50, 0xf4, 0x71, 0x86, 0xf1, 0x64, 0x12, 0xe4, 0xe8,
|
||||
0xd2, 0xf4, 0x96, 0x84, 0x21, 0x29, 0x10, 0x1a, 0x89, 0x28, 0x9d, 0x88, 0xd9, 0x6b, 0x89, 0xd6,
|
||||
0x2c, 0x10, 0xb9, 0x1c, 0x72, 0x4e, 0x06, 0xe9, 0xc9, 0x49, 0x0f, 0x04, 0x97, 0x02, 0xc1, 0x75,
|
||||
0x98, 0x46, 0x19, 0xcf, 0xf3, 0x90, 0x8f, 0x74, 0x87, 0xda, 0x44, 0x56, 0xad, 0x60, 0xd7, 0x61,
|
||||
0x5d, 0x78, 0x59, 0x99, 0x9f, 0xc7, 0xd9, 0x51, 0x90, 0x0d, 0x32, 0x1e, 0xe5, 0xbd, 0x0e, 0xd1,
|
||||
0xd7, 0x55, 0xb1, 0x77, 0xe0, 0x5c, 0x09, 0x4e, 0xf9, 0x90, 0x07, 0xc7, 0x7c, 0xd4, 0x5b, 0xa6,
|
||||
0xaf, 0x4e, 0xab, 0x66, 0x97, 0xa1, 0x8d, 0xce, 0xe5, 0x34, 0x19, 0xf9, 0xb8, 0x0f, 0x77, 0x69,
|
||||
0x1d, 0x4c, 0x88, 0xbd, 0x05, 0xcb, 0x09, 0x17, 0x9b, 0xe5, 0x51, 0x1e, 0x0e, 0xb3, 0xde, 0x0a,
|
||||
0xed, 0x64, 0x6d, 0xa9, 0x4c, 0x28, 0xb9, 0x9e, 0x4d, 0x81, 0x42, 0x39, 0xcc, 0xc8, 0x5d, 0xf1,
|
||||
0x67, 0xbd, 0x55, 0x12, 0xb7, 0x02, 0x20, 0x1d, 0x49, 0x83, 0x63, 0x3f, 0xe7, 0xbd, 0x35, 0x92,
|
||||
0x2d, 0x55, 0x74, 0xff, 0xd2, 0x81, 0xf5, 0x07, 0x41, 0x96, 0x4b, 0x21, 0xd4, 0xe6, 0xf8, 0x55,
|
||||
0x68, 0x0b, 0xf1, 0x1b, 0xc4, 0x51, 0x38, 0x93, 0x12, 0x09, 0x02, 0xfa, 0x5a, 0x14, 0xce, 0xd8,
|
||||
0xe7, 0x60, 0x39, 0x88, 0x4c, 0x12, 0xa1, 0xc3, 0x1d, 0x05, 0x12, 0xd1, 0xab, 0xd0, 0x4e, 0xa6,
|
||||
0x07, 0x61, 0x30, 0x14, 0x24, 0x73, 0x82, 0x8b, 0x80, 0x88, 0x00, 0x1d, 0x3d, 0xd1, 0x13, 0x41,
|
||||
0xd1, 0x24, 0x8a, 0xb6, 0xc4, 0x90, 0xc4, 0xbd, 0x05, 0x1b, 0x76, 0x07, 0xa5, 0xb1, 0xda, 0x82,
|
||||
0x25, 0x29, 0xdb, 0x59, 0xaf, 0x4d, 0xf3, 0xd3, 0x95, 0xf3, 0x23, 0x49, 0x3d, 0x5d, 0xef, 0xfe,
|
||||
0xbb, 0x03, 0x4d, 0x34, 0x00, 0xa7, 0x1b, 0x0b, 0xd3, 0xa6, 0xcf, 0x59, 0x36, 0x9d, 0xfc, 0x7e,
|
||||
0xf4, 0x8a, 0x84, 0x48, 0x08, 0xb5, 0x31, 0x90, 0xa2, 0x3e, 0xe5, 0xc3, 0x63, 0xd2, 0x1d, 0x5d,
|
||||
0x8f, 0x08, 0x6a, 0x16, 0x6e, 0x9d, 0xf4, 0xb5, 0x50, 0x1c, 0x5d, 0x56, 0x75, 0xf4, 0xe5, 0x62,
|
||||
0x51, 0x47, 0xdf, 0xf5, 0x60, 0x31, 0x88, 0x0e, 0xe2, 0x69, 0x34, 0x22, 0x25, 0x59, 0xf2, 0x54,
|
||||
0x11, 0x17, 0x3b, 0x21, 0x4f, 0x2a, 0x98, 0x70, 0xa9, 0x1d, 0x05, 0xe0, 0x32, 0x74, 0xad, 0x32,
|
||||
0x32, 0x78, 0x7a, 0x1f, 0x7b, 0x1b, 0xd6, 0x0c, 0x4c, 0xce, 0xe0, 0x6b, 0x30, 0x9f, 0x20, 0x20,
|
||||
0x1d, 0x25, 0x25, 0x5e, 0x64, 0x29, 0x45, 0x8d, 0xbb, 0x8a, 0xf1, 0x73, 0xfe, 0x7e, 0x74, 0x18,
|
||||
0x2b, 0x4e, 0x3f, 0x9a, 0xc3, 0x80, 0x57, 0x42, 0x92, 0xd1, 0x55, 0x58, 0x09, 0x46, 0x3c, 0xca,
|
||||
0x83, 0x7c, 0x36, 0xb0, 0x3c, 0xb8, 0x32, 0x8c, 0x3b, 0x8c, 0x1f, 0x06, 0x7e, 0x26, 0x6d, 0x98,
|
||||
0x28, 0xb0, 0x1d, 0xd8, 0x40, 0xf1, 0x57, 0x12, 0xad, 0x97, 0x55, 0x38, 0x92, 0xb5, 0x75, 0xa8,
|
||||
0xb1, 0x88, 0x4b, 0x09, 0xd4, 0x9f, 0x08, 0x4b, 0x5b, 0x57, 0x85, 0xb3, 0x26, 0x38, 0xe1, 0x90,
|
||||
0xe7, 0x85, 0x8a, 0x68, 0xa0, 0x12, 0xbd, 0x2d, 0x08, 0x27, 0xb6, 0x1c, 0xbd, 0x19, 0x11, 0xe0,
|
||||
0x52, 0x25, 0x02, 0xbc, 0x0a, 0x2b, 0xd9, 0x2c, 0x1a, 0xf2, 0xd1, 0x20, 0x8f, 0xb1, 0xdd, 0x20,
|
||||
0xa2, 0xd5, 0x59, 0xf2, 0xca, 0x30, 0xc5, 0xaa, 0x3c, 0xcb, 0x23, 0x9e, 0x93, 0xe9, 0x5a, 0xf2,
|
||||
0x54, 0x11, 0x77, 0x01, 0x22, 0x11, 0x42, 0xdd, 0xf2, 0x64, 0x09, 0xb7, 0xca, 0x69, 0x1a, 0x64,
|
||||
0xbd, 0x0e, 0xa1, 0xf4, 0x9b, 0x7d, 0x01, 0xce, 0x1e, 0x60, 0x64, 0x75, 0xc4, 0xfd, 0x11, 0x4f,
|
||||
0x69, 0xf5, 0x45, 0x60, 0x29, 0x2c, 0x50, 0x7d, 0x25, 0xb6, 0x7d, 0xcc, 0xd3, 0x2c, 0x88, 0x23,
|
||||
0xb2, 0x3d, 0x2d, 0x4f, 0x15, 0xdd, 0x4f, 0x68, 0x47, 0xd7, 0x21, 0xef, 0x63, 0x32, 0x47, 0xec,
|
||||
0x02, 0xb4, 0xc4, 0x18, 0xb3, 0x23, 0x5f, 0x3a, 0x19, 0x4b, 0x04, 0xec, 0x1f, 0xf9, 0xa8, 0xc0,
|
||||
0xd6, 0xb4, 0x35, 0xc8, 0x73, 0x6c, 0x13, 0xb6, 0x2b, 0x66, 0xed, 0x75, 0xe8, 0xaa, 0x60, 0x3a,
|
||||
0x1b, 0x84, 0xfc, 0x30, 0x57, 0x01, 0x42, 0x34, 0x9d, 0x60, 0x73, 0xd9, 0x03, 0x7e, 0x98, 0xbb,
|
||||
0x0f, 0x61, 0x4d, 0xea, 0xed, 0xd7, 0x12, 0xae, 0x9a, 0xfe, 0x52, 0x79, 0x53, 0x13, 0x5e, 0xc5,
|
||||
0xba, 0xad, 0xe8, 0x14, 0xe5, 0x94, 0x76, 0x3a, 0xd7, 0x03, 0x26, 0xab, 0x6f, 0x87, 0x71, 0xc6,
|
||||
0x25, 0x43, 0x17, 0x3a, 0xc3, 0x30, 0xce, 0x54, 0x18, 0x22, 0x87, 0x63, 0x61, 0x38, 0x3f, 0xd9,
|
||||
0x74, 0x38, 0x44, 0x4b, 0x20, 0x6c, 0x9a, 0x2a, 0xba, 0x7f, 0xe5, 0xc0, 0x3a, 0x71, 0x53, 0x16,
|
||||
0x46, 0xfb, 0xae, 0x2f, 0xdf, 0xcd, 0xce, 0xd0, 0x0c, 0xcd, 0x36, 0x60, 0xfe, 0x30, 0x4e, 0x87,
|
||||
0x5c, 0xb6, 0x24, 0x0a, 0x3f, 0xb9, 0x37, 0xde, 0xac, 0x78, 0xe3, 0x3f, 0x72, 0x60, 0x8d, 0xba,
|
||||
0xba, 0x9f, 0xfb, 0xf9, 0x34, 0x93, 0xc3, 0xff, 0x15, 0x58, 0xc6, 0xa1, 0x72, 0xa5, 0x4e, 0xb2,
|
||||
0xa3, 0x1b, 0x5a, 0xf3, 0x09, 0x15, 0xc4, 0xbb, 0x67, 0x3c, 0x9b, 0x98, 0x7d, 0x19, 0x3a, 0x66,
|
||||
0x46, 0x84, 0xfa, 0xdc, 0xde, 0x39, 0xaf, 0x46, 0x59, 0x91, 0x9c, 0xdd, 0x33, 0x9e, 0xf5, 0x01,
|
||||
0xbb, 0x01, 0x40, 0xee, 0x06, 0xb1, 0x95, 0xa1, 0xec, 0x79, 0x7b, 0x92, 0x8c, 0xc5, 0xda, 0x3d,
|
||||
0xe3, 0x19, 0xe4, 0xb7, 0x96, 0x60, 0x41, 0xec, 0x8f, 0xee, 0x7d, 0x58, 0xb6, 0x7a, 0x6a, 0x45,
|
||||
0x19, 0x1d, 0x11, 0x65, 0x54, 0x82, 0xd2, 0x46, 0x35, 0x28, 0x75, 0xff, 0xb5, 0x01, 0x0c, 0xa5,
|
||||
0xad, 0xb4, 0x9c, 0xb8, 0x41, 0xc7, 0x23, 0xcb, 0xdd, 0xea, 0x78, 0x26, 0xc4, 0xae, 0x01, 0x33,
|
||||
0x8a, 0x2a, 0xf7, 0x20, 0xf6, 0x8d, 0x9a, 0x1a, 0x34, 0x70, 0xc2, 0x57, 0x52, 0x31, 0xb0, 0x74,
|
||||
0x2c, 0xc5, 0xba, 0xd5, 0xd6, 0xe1, 0xd6, 0x90, 0x4c, 0xb3, 0x23, 0x74, 0x20, 0x94, 0x43, 0xa6,
|
||||
0xca, 0x65, 0x01, 0x59, 0x78, 0xa1, 0x80, 0x2c, 0x96, 0x05, 0xc4, 0x74, 0x09, 0x96, 0x2c, 0x97,
|
||||
0x00, 0xfd, 0xaf, 0x49, 0x10, 0x91, 0x5f, 0x31, 0x98, 0x60, 0xeb, 0xd2, 0xff, 0xb2, 0x40, 0xb6,
|
||||
0x05, 0xab, 0xd2, 0xaf, 0x2b, 0xfc, 0x0e, 0xa0, 0x39, 0xae, 0xe0, 0xee, 0x67, 0x0e, 0xac, 0xe2,
|
||||
0x3c, 0x5b, 0xb2, 0xf8, 0x2e, 0x90, 0x2a, 0xbc, 0xa4, 0x28, 0x5a, 0xb4, 0x3f, 0xbb, 0x24, 0xbe,
|
||||
0x03, 0x2d, 0x62, 0x18, 0x27, 0x3c, 0x92, 0x82, 0xd8, 0xb3, 0x05, 0xb1, 0xb0, 0x42, 0xbb, 0x67,
|
||||
0xbc, 0x82, 0xd8, 0x10, 0xc3, 0x7f, 0x70, 0xa0, 0x2d, 0xbb, 0xf9, 0x53, 0xc7, 0x12, 0x7d, 0x58,
|
||||
0x42, 0x89, 0x34, 0x1c, 0x76, 0x5d, 0xc6, 0xdd, 0x64, 0x82, 0x01, 0x1b, 0x6e, 0x9f, 0x56, 0x1c,
|
||||
0x51, 0x86, 0x71, 0x2f, 0x24, 0x83, 0x9b, 0x0d, 0xf2, 0x20, 0x1c, 0xa8, 0x5a, 0x99, 0x80, 0xac,
|
||||
0xab, 0x42, 0xbb, 0x93, 0xe5, 0xfe, 0x98, 0xcb, 0x6d, 0x4e, 0x14, 0x30, 0x60, 0x92, 0x03, 0x2a,
|
||||
0xb9, 0x83, 0xee, 0x0f, 0x01, 0xce, 0x55, 0xaa, 0x74, 0xba, 0x5b, 0x3a, 0xc8, 0x61, 0x30, 0x39,
|
||||
0x88, 0xb5, 0xaf, 0xed, 0x98, 0xbe, 0xb3, 0x55, 0xc5, 0xc6, 0x70, 0x56, 0xed, 0xe7, 0x38, 0xa7,
|
||||
0xc5, 0xee, 0xdd, 0x20, 0x47, 0xe4, 0x2d, 0x5b, 0x06, 0xca, 0x0d, 0x2a, 0xdc, 0xd4, 0xdc, 0x7a,
|
||||
0x7e, 0xec, 0x08, 0x7a, 0xda, 0x71, 0x90, 0x26, 0xde, 0x70, 0x2e, 0xb0, 0xad, 0x37, 0x5f, 0xd0,
|
||||
0x16, 0xd9, 0xa3, 0x91, 0x6a, 0xe6, 0x54, 0x6e, 0x6c, 0x06, 0x97, 0x54, 0x1d, 0xd9, 0xf0, 0x6a,
|
||||
0x7b, 0xcd, 0x97, 0x1a, 0xdb, 0x3d, 0xfc, 0xd8, 0x6e, 0xf4, 0x05, 0x8c, 0xfb, 0x3f, 0x74, 0xa0,
|
||||
0x6b, 0xb3, 0x43, 0xd1, 0x91, 0x4a, 0xa8, 0x8c, 0x91, 0x72, 0xc8, 0x4a, 0x70, 0x35, 0x6c, 0x6c,
|
||||
0xd4, 0x85, 0x8d, 0x66, 0x70, 0x38, 0xf7, 0xa2, 0xe0, 0xb0, 0xf9, 0x72, 0xc1, 0xe1, 0x7c, 0x5d,
|
||||
0x70, 0xd8, 0xff, 0x2f, 0x07, 0x58, 0x75, 0x7d, 0xd9, 0x7d, 0x11, 0xb7, 0x46, 0x3c, 0x94, 0x76,
|
||||
0xe2, 0x97, 0x5e, 0x4e, 0x46, 0xd4, 0x1c, 0xaa, 0xaf, 0x51, 0x58, 0x4d, 0x43, 0x60, 0xba, 0x2d,
|
||||
0xcb, 0x5e, 0x5d, 0x55, 0x29, 0x5c, 0x6d, 0xbe, 0x38, 0x5c, 0x9d, 0x7f, 0x71, 0xb8, 0xba, 0x50,
|
||||
0x0e, 0x57, 0xfb, 0xbf, 0x03, 0xcb, 0xd6, 0xaa, 0xff, 0xdf, 0x8d, 0xb8, 0xec, 0xf2, 0x88, 0x05,
|
||||
0xb6, 0xb0, 0xfe, 0x8f, 0x1b, 0xc0, 0xaa, 0x92, 0xf7, 0x73, 0xed, 0x03, 0xc9, 0x91, 0x65, 0x40,
|
||||
0xe6, 0xa4, 0x1c, 0x59, 0xa6, 0xe3, 0xff, 0xd3, 0x28, 0xbe, 0x09, 0x6b, 0x29, 0x1f, 0xc6, 0xc7,
|
||||
0x74, 0x08, 0x67, 0xa7, 0x3a, 0xaa, 0x15, 0xe8, 0xf4, 0xd9, 0x41, 0xfa, 0x92, 0x75, 0x66, 0x62,
|
||||
0xec, 0x0c, 0xa5, 0x58, 0xdd, 0xdd, 0x84, 0x0d, 0x71, 0x94, 0x75, 0x4b, 0xb0, 0x52, 0x46, 0xf6,
|
||||
0x2f, 0x1c, 0x38, 0x5b, 0xaa, 0x28, 0x0e, 0x16, 0x84, 0x1d, 0xb5, 0x8d, 0xab, 0x0d, 0x62, 0xff,
|
||||
0xa5, 0x00, 0x1b, 0xfd, 0x17, 0xfb, 0x4d, 0xb5, 0x02, 0xe7, 0x67, 0x1a, 0x55, 0xe9, 0xc5, 0xac,
|
||||
0xd7, 0x55, 0xb9, 0xe7, 0xe0, 0xac, 0x5c, 0xd9, 0x52, 0xc7, 0x0f, 0x61, 0xb3, 0x5c, 0x51, 0x64,
|
||||
0x4a, 0xed, 0x2e, 0xab, 0x22, 0xba, 0x44, 0x96, 0xcd, 0xb6, 0xfb, 0x5b, 0x5b, 0xe7, 0xfe, 0x36,
|
||||
0xb0, 0xaf, 0x4f, 0x79, 0x3a, 0xa3, 0x63, 0x0f, 0x9d, 0xaa, 0x38, 0x57, 0x8e, 0xe9, 0x17, 0x92,
|
||||
0xe9, 0xc1, 0x57, 0xf9, 0x4c, 0x9d, 0x2b, 0x35, 0x8a, 0x73, 0xa5, 0x57, 0x00, 0x30, 0x14, 0xa1,
|
||||
0x73, 0x12, 0x75, 0xd2, 0x87, 0x31, 0xa0, 0x60, 0xe8, 0xde, 0x80, 0x75, 0x8b, 0xbf, 0x9e, 0xfd,
|
||||
0x05, 0xf9, 0x85, 0x08, 0x94, 0xed, 0xd3, 0x17, 0x59, 0xe7, 0xfe, 0x87, 0x03, 0x73, 0xbb, 0x71,
|
||||
0x62, 0xa6, 0xd8, 0x1c, 0x3b, 0xc5, 0x26, 0x6d, 0xed, 0x40, 0x9b, 0xd2, 0x86, 0xb4, 0x14, 0x26,
|
||||
0xc8, 0xb6, 0xa0, 0xeb, 0x4f, 0x72, 0x0c, 0x15, 0x0f, 0xe3, 0xf4, 0xc4, 0x4f, 0x47, 0x62, 0x49,
|
||||
0x6e, 0x35, 0x7a, 0x8e, 0x57, 0xaa, 0x61, 0x1b, 0x30, 0xa7, 0x8d, 0x12, 0x11, 0x60, 0x11, 0x9d,
|
||||
0x0d, 0xca, 0x34, 0xce, 0x64, 0x94, 0x2b, 0x4b, 0xb8, 0xe2, 0xf6, 0xf7, 0xc2, 0xbd, 0x13, 0x12,
|
||||
0x5e, 0x57, 0x85, 0x76, 0x1f, 0x6d, 0x14, 0x91, 0xc9, 0xf4, 0x84, 0x2a, 0xbb, 0xff, 0xe6, 0xc0,
|
||||
0x3c, 0xcd, 0x00, 0xea, 0xa4, 0x10, 0x44, 0x3a, 0xc8, 0xa4, 0xb4, 0xa8, 0x23, 0x74, 0xb2, 0x04,
|
||||
0x33, 0xd7, 0x3a, 0xde, 0x6c, 0xe8, 0x6e, 0x9b, 0x47, 0x9c, 0x97, 0xa1, 0x25, 0x4a, 0xfa, 0x4c,
|
||||
0x90, 0x48, 0x0a, 0x90, 0x5d, 0x82, 0xe6, 0x51, 0x9c, 0xa8, 0x1d, 0x15, 0x54, 0x56, 0x2c, 0x4e,
|
||||
0x3c, 0xc2, 0x8b, 0xfe, 0x20, 0x3f, 0xd1, 0x79, 0x61, 0x93, 0xcb, 0x30, 0xee, 0x4a, 0x9a, 0xad,
|
||||
0x39, 0x19, 0x25, 0xd4, 0xdd, 0x82, 0x95, 0x87, 0xf1, 0x88, 0x1b, 0x79, 0x90, 0x53, 0xa5, 0xce,
|
||||
0xfd, 0x5d, 0x07, 0x96, 0x14, 0x31, 0xbb, 0x0a, 0x4d, 0xdc, 0x6a, 0x4b, 0xce, 0xad, 0xce, 0x86,
|
||||
0x23, 0x9d, 0x47, 0x14, 0x68, 0x22, 0x29, 0x4a, 0x2e, 0x5c, 0x21, 0x15, 0x23, 0x17, 0x4e, 0x86,
|
||||
0xee, 0x6e, 0x69, 0x33, 0x2e, 0xa1, 0xee, 0x5f, 0x3b, 0xb0, 0x6c, 0xb5, 0x81, 0x21, 0x4d, 0xe8,
|
||||
0x67, 0xb9, 0xcc, 0x30, 0xca, 0xe5, 0x31, 0x21, 0x33, 0x33, 0xd6, 0xb0, 0x33, 0x63, 0x3a, 0x67,
|
||||
0x33, 0x67, 0xe6, 0x6c, 0xae, 0x43, 0xab, 0x38, 0x84, 0x6e, 0x5a, 0xa6, 0x0f, 0x5b, 0x54, 0x79,
|
||||
0xfe, 0x82, 0x08, 0xf9, 0x0c, 0xe3, 0x30, 0x4e, 0xe5, 0x19, 0xad, 0x28, 0xb8, 0x37, 0xa0, 0x6d,
|
||||
0xd0, 0x63, 0x37, 0x22, 0x9e, 0x9f, 0xc4, 0xe9, 0x13, 0x95, 0xa0, 0x93, 0x45, 0x7d, 0x9c, 0xd5,
|
||||
0x28, 0x8e, 0xb3, 0xdc, 0xbf, 0x71, 0x60, 0x19, 0x65, 0x30, 0x88, 0xc6, 0x7b, 0x71, 0x18, 0x0c,
|
||||
0x67, 0xb4, 0xf6, 0x4a, 0xdc, 0xe4, 0xe1, 0xad, 0x92, 0x45, 0x1b, 0x46, 0xd9, 0x56, 0x11, 0x8d,
|
||||
0x54, 0x44, 0x5d, 0x46, 0x4d, 0x45, 0x39, 0x3f, 0xf0, 0x33, 0x29, 0xfc, 0x72, 0x2f, 0xb2, 0x40,
|
||||
0xd4, 0x27, 0x04, 0x52, 0x3f, 0xe7, 0x83, 0x49, 0x10, 0x86, 0x81, 0xa0, 0x15, 0x2e, 0x42, 0x5d,
|
||||
0x95, 0xfb, 0x83, 0x06, 0xb4, 0xa5, 0xa5, 0xbc, 0x3b, 0x1a, 0x8b, 0x54, 0xb8, 0x74, 0xb4, 0xb4,
|
||||
0xb9, 0x30, 0x10, 0x55, 0x6f, 0xb9, 0x66, 0x06, 0x52, 0x5e, 0xd6, 0xb9, 0xea, 0xb2, 0x5e, 0x84,
|
||||
0x16, 0x8a, 0xd7, 0x5b, 0xe4, 0x03, 0x8a, 0x3b, 0x0b, 0x05, 0xa0, 0x6a, 0x77, 0xa8, 0x76, 0xbe,
|
||||
0xa8, 0x25, 0xc0, 0xf2, 0xfa, 0x16, 0x4a, 0x5e, 0xdf, 0x3b, 0xd0, 0x91, 0x6c, 0x68, 0xde, 0xc9,
|
||||
0x3a, 0x14, 0x02, 0x6e, 0xad, 0x89, 0x67, 0x51, 0xaa, 0x2f, 0x77, 0xd4, 0x97, 0x4b, 0x2f, 0xfa,
|
||||
0x52, 0x51, 0xd2, 0xc9, 0x90, 0x98, 0x9b, 0xfb, 0xa9, 0x9f, 0x1c, 0xa9, 0xdd, 0x67, 0xa4, 0x8f,
|
||||
0xbb, 0x09, 0x66, 0x5b, 0x30, 0x8f, 0x9f, 0x29, 0x6b, 0x5d, 0xaf, 0x74, 0x82, 0x84, 0x5d, 0x85,
|
||||
0x79, 0x3e, 0x1a, 0x73, 0x15, 0x79, 0x30, 0x3b, 0x06, 0xc4, 0x35, 0xf2, 0x04, 0x01, 0x9a, 0x00,
|
||||
0x44, 0x4b, 0x26, 0xc0, 0xb6, 0xf4, 0x0b, 0x58, 0x7c, 0x7f, 0xe4, 0x6e, 0x00, 0x7b, 0x28, 0xa4,
|
||||
0xd6, 0xcc, 0x9c, 0xfe, 0xc1, 0x1c, 0xb4, 0x0d, 0x18, 0xb5, 0x79, 0x8c, 0x1d, 0x1e, 0x8c, 0x02,
|
||||
0x7f, 0xc2, 0x73, 0x9e, 0x4a, 0x49, 0x2d, 0xa1, 0x48, 0xe7, 0x1f, 0x8f, 0x07, 0xf1, 0x34, 0x1f,
|
||||
0x8c, 0xf8, 0x38, 0xe5, 0x62, 0x8f, 0xc4, 0xcd, 0xc0, 0x42, 0x91, 0x6e, 0xe2, 0x3f, 0x35, 0xe9,
|
||||
0x84, 0x3c, 0x94, 0x50, 0x95, 0x07, 0x15, 0x73, 0xd4, 0x2c, 0xf2, 0xa0, 0x62, 0x46, 0xca, 0x76,
|
||||
0x68, 0xbe, 0xc6, 0x0e, 0xbd, 0x0d, 0x9b, 0xc2, 0xe2, 0x48, 0xdd, 0x1c, 0x94, 0xc4, 0xe4, 0x94,
|
||||
0x5a, 0xb6, 0x05, 0xab, 0xd8, 0x67, 0x25, 0xe0, 0x59, 0xf0, 0x89, 0xc8, 0x4c, 0x38, 0x5e, 0x05,
|
||||
0x47, 0x5a, 0x54, 0x47, 0x8b, 0x56, 0x9c, 0x15, 0x55, 0x70, 0xa2, 0xf5, 0x9f, 0xda, 0xb4, 0x2d,
|
||||
0x49, 0x5b, 0xc2, 0xdd, 0x65, 0x68, 0xef, 0xe7, 0x71, 0xa2, 0x16, 0xa5, 0x0b, 0x1d, 0x51, 0x94,
|
||||
0x27, 0x83, 0x17, 0xe0, 0x3c, 0x49, 0xd1, 0xa3, 0x38, 0x89, 0xc3, 0x78, 0x3c, 0xdb, 0x9f, 0x1e,
|
||||
0x64, 0xc3, 0x34, 0x48, 0x30, 0x22, 0x70, 0xff, 0xde, 0x81, 0x75, 0xab, 0x56, 0xa6, 0x32, 0xbe,
|
||||
0x20, 0x44, 0x5a, 0x1f, 0xe9, 0x08, 0xc1, 0x5b, 0x33, 0xcc, 0xa1, 0x20, 0x14, 0x49, 0xa4, 0xc7,
|
||||
0xf2, 0x94, 0xe7, 0x26, 0xac, 0xa8, 0x9e, 0xa9, 0x0f, 0x85, 0x14, 0xf6, 0xaa, 0x52, 0x28, 0xbf,
|
||||
0xef, 0xca, 0x0f, 0x14, 0x8b, 0x5f, 0x15, 0x7e, 0x35, 0x1f, 0xd1, 0x18, 0x55, 0x4c, 0xdb, 0x57,
|
||||
0xdf, 0x9b, 0xce, 0xbc, 0xea, 0xc1, 0x50, 0x83, 0x99, 0xfb, 0x47, 0x0e, 0x40, 0xd1, 0x3b, 0x14,
|
||||
0x8c, 0xc2, 0xa4, 0x8b, 0xcb, 0x6a, 0x86, 0xf9, 0x7e, 0x0d, 0x3a, 0x3a, 0x9b, 0x5f, 0xec, 0x12,
|
||||
0x6d, 0x85, 0xa1, 0xc3, 0x75, 0x05, 0x56, 0xc6, 0x61, 0x7c, 0x40, 0x5b, 0x2c, 0x1d, 0x35, 0x67,
|
||||
0xf2, 0x7c, 0xb4, 0x2b, 0xe0, 0x7b, 0x12, 0x2d, 0xb6, 0x94, 0xa6, 0xb1, 0xa5, 0xb8, 0xdf, 0x69,
|
||||
0xe8, 0x1c, 0x70, 0x31, 0xe6, 0x53, 0xb5, 0x8c, 0xed, 0x54, 0x8c, 0xe3, 0x29, 0x29, 0x57, 0xca,
|
||||
0xde, 0xec, 0xbd, 0x30, 0x90, 0xbd, 0x01, 0xdd, 0x54, 0x58, 0x1f, 0x65, 0x9a, 0x9a, 0xcf, 0x31,
|
||||
0x4d, 0xcb, 0xa9, 0xb5, 0xef, 0xfc, 0x02, 0xac, 0xfa, 0xa3, 0x63, 0x9e, 0xe6, 0x01, 0x45, 0x34,
|
||||
0xb4, 0xe9, 0x0b, 0x83, 0xba, 0x62, 0xe0, 0xb4, 0x17, 0x5f, 0x81, 0x15, 0x79, 0x26, 0xad, 0x29,
|
||||
0xe5, 0x4d, 0xa4, 0x02, 0x46, 0x42, 0xf7, 0xfb, 0x2a, 0xdd, 0x6c, 0xaf, 0xe1, 0xe9, 0x33, 0x62,
|
||||
0x8e, 0xae, 0x51, 0x1a, 0xdd, 0xe7, 0x64, 0xea, 0x77, 0xa4, 0xc2, 0x26, 0x99, 0x84, 0x17, 0xa0,
|
||||
0x4c, 0xd5, 0xdb, 0x53, 0xda, 0x7c, 0x99, 0x29, 0x75, 0x3f, 0x73, 0x60, 0x71, 0x37, 0x4e, 0x76,
|
||||
0xe5, 0xf1, 0x32, 0x29, 0x82, 0xbe, 0xf1, 0xa1, 0x8a, 0xa6, 0x57, 0xdc, 0xa8, 0x78, 0xc5, 0xd5,
|
||||
0xbd, 0x76, 0xb9, 0xbc, 0xd7, 0xfe, 0x1a, 0x5c, 0xa0, 0x68, 0x39, 0x8d, 0x93, 0x38, 0x45, 0x65,
|
||||
0xf4, 0x43, 0xb1, 0xb1, 0xc6, 0x51, 0x7e, 0xa4, 0xcc, 0xd8, 0xf3, 0x48, 0x28, 0x3a, 0x0a, 0xf3,
|
||||
0xe3, 0x81, 0x70, 0x86, 0xa5, 0x6f, 0x20, 0xac, 0x5b, 0xb5, 0xc2, 0xfd, 0x12, 0xb4, 0xc8, 0xb9,
|
||||
0xa5, 0x61, 0xbd, 0x09, 0xad, 0xa3, 0x38, 0x19, 0x1c, 0x05, 0x51, 0xae, 0x94, 0xbb, 0x5b, 0x78,
|
||||
0x9d, 0xbb, 0x34, 0x21, 0x9a, 0xc0, 0xfd, 0xf1, 0x1c, 0x2c, 0xbe, 0x1f, 0x1d, 0xc7, 0xc1, 0x90,
|
||||
0x32, 0xd3, 0x13, 0x3e, 0x89, 0xd5, 0xfd, 0x17, 0xfc, 0x8d, 0x53, 0x41, 0x67, 0xc1, 0x49, 0x2e,
|
||||
0x53, 0xcb, 0xaa, 0x88, 0xdb, 0x7d, 0x5a, 0xdc, 0x09, 0x13, 0xaa, 0x63, 0x20, 0xe8, 0xd8, 0xa7,
|
||||
0xe6, 0x85, 0x38, 0x59, 0x2a, 0x2e, 0x10, 0xcd, 0x1b, 0x17, 0x88, 0xe8, 0x1c, 0x43, 0x1c, 0x73,
|
||||
0x93, 0x7c, 0x2d, 0x79, 0xaa, 0x48, 0x81, 0x48, 0xca, 0x45, 0x96, 0x83, 0x1c, 0x87, 0x45, 0x19,
|
||||
0x88, 0x98, 0x20, 0x3a, 0x17, 0xe2, 0x03, 0x41, 0x23, 0x8c, 0xaf, 0x09, 0xa1, 0xb3, 0x55, 0xbe,
|
||||
0x53, 0xd7, 0x12, 0x32, 0x5f, 0x82, 0xd1, 0x42, 0x8f, 0xb8, 0x36, 0xa4, 0x62, 0x0c, 0x20, 0xee,
|
||||
0xbc, 0x95, 0x71, 0x23, 0x7c, 0x11, 0xc7, 0xf5, 0x2a, 0x7c, 0x41, 0x41, 0xf1, 0xc3, 0xf0, 0xc0,
|
||||
0x1f, 0x3e, 0xa1, 0x9b, 0x8e, 0x74, 0x3a, 0xdf, 0xf2, 0x6c, 0x10, 0x7b, 0x6d, 0xac, 0x26, 0x9d,
|
||||
0x84, 0x35, 0x3d, 0x13, 0x62, 0x3b, 0xd0, 0xa6, 0x90, 0x4d, 0xae, 0x67, 0x97, 0xd6, 0x73, 0xd5,
|
||||
0x8c, 0xe9, 0x68, 0x45, 0x4d, 0x22, 0x33, 0x5b, 0xbe, 0x62, 0x1f, 0xa0, 0x7f, 0x03, 0xd8, 0xcd,
|
||||
0xd1, 0x48, 0xae, 0xb7, 0x0e, 0x19, 0x8b, 0x95, 0x72, 0xac, 0x95, 0xaa, 0x99, 0xb1, 0x46, 0xed,
|
||||
0x8c, 0xb9, 0x77, 0xa1, 0xbd, 0x67, 0x5c, 0x77, 0x24, 0xd1, 0x50, 0x17, 0x1d, 0xa5, 0x38, 0x19,
|
||||
0x88, 0xd1, 0x60, 0xc3, 0x6c, 0xd0, 0xfd, 0x65, 0x60, 0x0f, 0x82, 0x2c, 0xd7, 0xfd, 0x13, 0xcb,
|
||||
0xf1, 0x1a, 0x74, 0x74, 0x80, 0x5d, 0x1c, 0xef, 0xb7, 0x25, 0x46, 0xc7, 0xee, 0x37, 0xc5, 0xbd,
|
||||
0x80, 0xf2, 0xc0, 0xb6, 0x60, 0x29, 0x10, 0x50, 0x59, 0x13, 0x14, 0xa5, 0xae, 0x47, 0x7f, 0x4d,
|
||||
0x82, 0xd6, 0x2e, 0xfa, 0x03, 0x07, 0x16, 0xe5, 0xd0, 0xd0, 0xdb, 0xb0, 0x2e, 0x7a, 0x8a, 0x81,
|
||||
0x59, 0x58, 0xfd, 0xf5, 0xb8, 0xaa, 0x0c, 0xcf, 0xd5, 0xc9, 0x30, 0x83, 0x66, 0xe2, 0xe7, 0x47,
|
||||
0x14, 0xa0, 0xb4, 0x3c, 0xfa, 0xcd, 0x56, 0x45, 0xd0, 0x2c, 0x74, 0x85, 0x02, 0xe6, 0xba, 0x1b,
|
||||
0x99, 0xc2, 0x24, 0x57, 0x70, 0x1c, 0x14, 0x9d, 0xa4, 0x0b, 0x5c, 0x27, 0xc8, 0xe5, 0x2d, 0x85,
|
||||
0x02, 0x2e, 0xe6, 0x4b, 0xb2, 0x28, 0xcf, 0x97, 0x24, 0xf5, 0x74, 0xbd, 0xdb, 0x87, 0xde, 0x1d,
|
||||
0x1e, 0xf2, 0x9c, 0xdf, 0x0c, 0xc3, 0x32, 0xff, 0x0b, 0x70, 0xbe, 0xa6, 0x4e, 0x3a, 0x2d, 0xf7,
|
||||
0x60, 0xed, 0x0e, 0x3f, 0x98, 0x8e, 0x1f, 0xf0, 0xe3, 0xe2, 0x14, 0x8b, 0x41, 0x33, 0x3b, 0x8a,
|
||||
0x4f, 0xe4, 0xda, 0xd2, 0x6f, 0xf6, 0x0a, 0x40, 0x88, 0x34, 0x83, 0x2c, 0xe1, 0x43, 0x75, 0x31,
|
||||
0x8c, 0x90, 0xfd, 0x84, 0x0f, 0xdd, 0xb7, 0x81, 0x99, 0x7c, 0xe4, 0x10, 0xd0, 0x0e, 0x4c, 0x0f,
|
||||
0x06, 0xd9, 0x2c, 0xcb, 0xf9, 0x44, 0xdd, 0x78, 0x33, 0x21, 0xf7, 0x0a, 0x74, 0xf6, 0xfc, 0x99,
|
||||
0xc7, 0x3f, 0x96, 0x77, 0x6d, 0x31, 0x36, 0xf6, 0x67, 0x28, 0xca, 0x3a, 0x36, 0xa6, 0x6a, 0xf7,
|
||||
0x3f, 0x1b, 0xb0, 0x20, 0x28, 0x91, 0xeb, 0x88, 0x67, 0x79, 0x10, 0x89, 0x13, 0x1c, 0xc9, 0xd5,
|
||||
0x80, 0x2a, 0xb2, 0xd1, 0xa8, 0x91, 0x0d, 0xe9, 0xad, 0xaa, 0x4b, 0x36, 0x52, 0x08, 0x2c, 0x0c,
|
||||
0xdd, 0x9a, 0xe2, 0x64, 0x5c, 0x04, 0x67, 0x05, 0x50, 0x4a, 0x96, 0x14, 0xd6, 0x46, 0xf4, 0x4f,
|
||||
0x09, 0xad, 0x14, 0x07, 0x13, 0xaa, 0xb5, 0x69, 0x8b, 0x42, 0x6a, 0x2a, 0x36, 0xad, 0x62, 0xbb,
|
||||
0x96, 0x5e, 0xc2, 0x76, 0x09, 0x17, 0xf6, 0x79, 0xb6, 0x0b, 0x5e, 0xc2, 0x76, 0xb9, 0x0c, 0x56,
|
||||
0xef, 0x71, 0xee, 0x71, 0xdc, 0x15, 0x95, 0x38, 0x7d, 0xd7, 0x81, 0x55, 0xb9, 0xa1, 0xeb, 0x3a,
|
||||
0xf6, 0x9a, 0xb5, 0xfb, 0x3b, 0x75, 0x07, 0x01, 0xaf, 0xc3, 0x32, 0xed, 0xc9, 0x3a, 0x2b, 0x24,
|
||||
0x53, 0x58, 0x16, 0x88, 0xe3, 0x50, 0xa9, 0xed, 0x49, 0x10, 0xca, 0x45, 0x31, 0x21, 0x95, 0x58,
|
||||
0xc2, 0xf8, 0x98, 0x96, 0xc4, 0xf1, 0x74, 0xd9, 0xfd, 0x3b, 0x07, 0xd6, 0x8c, 0x0e, 0x4b, 0x29,
|
||||
0xbc, 0x01, 0xea, 0xe4, 0x5c, 0x24, 0x8f, 0x84, 0x32, 0x9d, 0xb3, 0x9d, 0x93, 0xe2, 0x33, 0x8b,
|
||||
0x98, 0x16, 0xd3, 0x9f, 0x51, 0x07, 0xb3, 0xe9, 0x44, 0x7a, 0x20, 0x26, 0x84, 0x82, 0x74, 0xc2,
|
||||
0xf9, 0x13, 0x4d, 0x32, 0x47, 0x24, 0x16, 0x46, 0x07, 0xa3, 0xe8, 0x4b, 0x68, 0x22, 0x71, 0x17,
|
||||
0xc8, 0x06, 0xdd, 0x7f, 0x74, 0x60, 0x5d, 0x38, 0x85, 0xd2, 0xe5, 0xd6, 0xf7, 0x14, 0x17, 0x84,
|
||||
0x17, 0x2c, 0x34, 0x72, 0xf7, 0x8c, 0x27, 0xcb, 0xec, 0x8b, 0x2f, 0xe9, 0xc8, 0xea, 0x03, 0xf1,
|
||||
0x53, 0xd6, 0x62, 0xae, 0x6e, 0x2d, 0x9e, 0x33, 0xd3, 0x75, 0xc9, 0x92, 0xf9, 0xda, 0x64, 0xc9,
|
||||
0xad, 0x45, 0x98, 0xcf, 0x86, 0x71, 0xc2, 0xdd, 0x4d, 0xd8, 0xb0, 0x07, 0x27, 0x4d, 0xd0, 0xf7,
|
||||
0x1c, 0xe8, 0xdd, 0x13, 0xa9, 0xc3, 0x20, 0x1a, 0xef, 0x06, 0x59, 0x1e, 0xa7, 0xfa, 0x62, 0xf6,
|
||||
0x25, 0x80, 0x2c, 0xf7, 0xd3, 0x5c, 0x5c, 0x58, 0x92, 0x69, 0x8e, 0x02, 0xc1, 0x3e, 0xf2, 0x68,
|
||||
0x24, 0x6a, 0xc5, 0xda, 0xe8, 0x32, 0x2e, 0x0c, 0x1d, 0xd6, 0x0f, 0xe2, 0xc3, 0xc3, 0x8c, 0x6b,
|
||||
0xb7, 0xd5, 0xc4, 0x30, 0xf2, 0x45, 0x8d, 0xc7, 0x58, 0x8f, 0x1f, 0x93, 0xa9, 0x15, 0xfe, 0x60,
|
||||
0x09, 0x75, 0xff, 0xd6, 0x81, 0x95, 0xa2, 0x93, 0x77, 0x11, 0xb4, 0xad, 0x83, 0xe8, 0x9a, 0x61,
|
||||
0x1d, 0x54, 0x02, 0x26, 0x18, 0x0d, 0x82, 0x48, 0xf6, 0xcd, 0x40, 0x48, 0x63, 0x65, 0x29, 0x9e,
|
||||
0xaa, 0xcb, 0x61, 0x26, 0x24, 0x4e, 0x7e, 0x73, 0xfc, 0x5a, 0xdc, 0x0c, 0x93, 0x25, 0xba, 0x6f,
|
||||
0x36, 0xc9, 0xe9, 0xab, 0x05, 0xe1, 0x10, 0xcb, 0xa2, 0xda, 0x9f, 0x16, 0x09, 0xc5, 0x9f, 0xee,
|
||||
0x1f, 0x3b, 0x70, 0xbe, 0x66, 0x72, 0xa5, 0x66, 0xdc, 0x81, 0xb5, 0x43, 0x5d, 0xa9, 0x26, 0x40,
|
||||
0xa8, 0xc7, 0xa6, 0x94, 0xa2, 0xd2, 0xa0, 0xbd, 0xea, 0x07, 0xe8, 0x1e, 0x53, 0xde, 0x48, 0x4c,
|
||||
0xa9, 0x75, 0x69, 0xa2, 0x5a, 0xb1, 0xf3, 0xfd, 0x06, 0x74, 0xc5, 0x51, 0x85, 0x78, 0x9a, 0xc3,
|
||||
0x53, 0xf6, 0x01, 0x2c, 0xca, 0x87, 0x50, 0xec, 0xac, 0x6c, 0xd6, 0x7e, 0x7a, 0xd5, 0xdf, 0x2c,
|
||||
0xc3, 0x52, 0x76, 0xd6, 0x7f, 0xff, 0xb3, 0x7f, 0xf9, 0x93, 0xc6, 0x32, 0x6b, 0x6f, 0x1f, 0xbf,
|
||||
0xb5, 0x3d, 0xe6, 0x51, 0x86, 0x3c, 0x7e, 0x13, 0xa0, 0x78, 0x4b, 0xc4, 0x7a, 0xda, 0xc9, 0x28,
|
||||
0xbd, 0x7d, 0xea, 0x9f, 0xaf, 0xa9, 0x91, 0x7c, 0xcf, 0x13, 0xdf, 0x75, 0xb7, 0x8b, 0x7c, 0x83,
|
||||
0x28, 0xc8, 0xc5, 0xc3, 0xa2, 0x77, 0x9d, 0x2d, 0x36, 0x82, 0x8e, 0xf9, 0xa6, 0x88, 0xa9, 0x90,
|
||||
0xb9, 0xe6, 0xa1, 0x52, 0xff, 0x42, 0x6d, 0x9d, 0xca, 0x17, 0x50, 0x1b, 0x67, 0xdd, 0x55, 0x6c,
|
||||
0x63, 0x4a, 0x14, 0xba, 0x95, 0x9d, 0x7f, 0xba, 0x00, 0x2d, 0x9d, 0x76, 0x62, 0xdf, 0x86, 0x65,
|
||||
0xeb, 0x74, 0x87, 0x29, 0xc6, 0x75, 0x87, 0x41, 0xfd, 0x8b, 0xf5, 0x95, 0xb2, 0xd9, 0x4b, 0xd4,
|
||||
0x6c, 0x8f, 0x6d, 0x62, 0xb3, 0xf2, 0x78, 0x64, 0x9b, 0xce, 0xb4, 0xc4, 0xfd, 0xb2, 0x27, 0xd0,
|
||||
0xb5, 0x4f, 0x64, 0xd8, 0x45, 0xdb, 0xa0, 0x94, 0x5a, 0x7b, 0xe5, 0x94, 0x5a, 0xd9, 0xdc, 0x45,
|
||||
0x6a, 0x6e, 0x93, 0x6d, 0x98, 0xcd, 0xe9, 0x74, 0x10, 0xa7, 0x1b, 0x81, 0xe6, 0x63, 0x23, 0xf6,
|
||||
0x8a, 0x5e, 0xea, 0xba, 0x47, 0x48, 0x7a, 0xd1, 0xaa, 0x2f, 0x91, 0xdc, 0x1e, 0x35, 0xc5, 0x18,
|
||||
0x4d, 0xa8, 0xf9, 0xd6, 0x88, 0x7d, 0x04, 0x2d, 0xfd, 0xc0, 0x80, 0x9d, 0x33, 0x5e, 0x75, 0x98,
|
||||
0xaf, 0x1e, 0xfa, 0xbd, 0x6a, 0x45, 0xdd, 0x52, 0x99, 0x9c, 0x51, 0x20, 0x1e, 0xc0, 0x59, 0xe9,
|
||||
0xa4, 0x1e, 0xf0, 0x9f, 0x64, 0x24, 0x35, 0x4f, 0xa4, 0xae, 0x3b, 0xec, 0x06, 0x2c, 0xa9, 0x77,
|
||||
0x1b, 0x6c, 0xb3, 0xfe, 0xfd, 0x49, 0xff, 0x5c, 0x05, 0x97, 0xfa, 0x7c, 0x13, 0xa0, 0x78, 0x73,
|
||||
0xa0, 0x25, 0xbf, 0xf2, 0x12, 0x42, 0x4f, 0x62, 0xcd, 0x03, 0x85, 0x31, 0xbd, 0xb0, 0xb0, 0x9f,
|
||||
0x34, 0xb0, 0x57, 0x0b, 0xfa, 0xda, 0xc7, 0x0e, 0xcf, 0x61, 0xe8, 0x6e, 0xd2, 0xdc, 0xad, 0x32,
|
||||
0x52, 0xa5, 0x88, 0x9f, 0xa8, 0xbb, 0xb1, 0x77, 0xa0, 0x6d, 0xbc, 0x63, 0x60, 0x8a, 0x43, 0xf5,
|
||||
0x0d, 0x44, 0xbf, 0x5f, 0x57, 0x25, 0xbb, 0xfb, 0x15, 0x58, 0xb6, 0x1e, 0x24, 0x68, 0xcd, 0xa8,
|
||||
0x7b, 0xee, 0xa0, 0x35, 0xa3, 0xfe, 0x0d, 0xc3, 0x37, 0xa1, 0x6d, 0x3c, 0x1f, 0x60, 0xc6, 0x9d,
|
||||
0xa0, 0xd2, 0xc3, 0x01, 0xdd, 0xa3, 0xba, 0xd7, 0x06, 0x1b, 0x34, 0xde, 0xae, 0xdb, 0xc2, 0xf1,
|
||||
0xd2, 0x05, 0x51, 0x14, 0x92, 0x6f, 0x43, 0xd7, 0x7e, 0x50, 0xa0, 0xb5, 0xaa, 0xf6, 0x69, 0x82,
|
||||
0xd6, 0xaa, 0x53, 0x5e, 0x21, 0x48, 0x81, 0xdc, 0x5a, 0xd7, 0x8d, 0x6c, 0x7f, 0x2a, 0x0f, 0x5d,
|
||||
0x9e, 0xb1, 0xaf, 0xa3, 0xe9, 0x90, 0x37, 0x76, 0x59, 0xf1, 0x8c, 0xc2, 0xbe, 0xd7, 0xab, 0xa5,
|
||||
0xbd, 0x72, 0xb9, 0xd7, 0x5d, 0x23, 0xe6, 0x6d, 0x56, 0x8c, 0x40, 0x58, 0x68, 0xba, 0xb9, 0x6b,
|
||||
0x58, 0x68, 0xf3, 0x72, 0xaf, 0x61, 0xa1, 0xad, 0x0b, 0xbe, 0x65, 0x0b, 0x9d, 0x07, 0xc8, 0x23,
|
||||
0x82, 0x95, 0xd2, 0x3d, 0x00, 0xad, 0x2c, 0xf5, 0xb7, 0x88, 0xfa, 0x97, 0x9e, 0x7f, 0x7d, 0xc0,
|
||||
0x36, 0x33, 0xca, 0xbc, 0x6c, 0xab, 0x4b, 0x5f, 0xbf, 0x05, 0x1d, 0xf3, 0x22, 0xb8, 0xb6, 0xd9,
|
||||
0x35, 0xd7, 0xd7, 0xb5, 0xcd, 0xae, 0xbb, 0x39, 0xae, 0x16, 0x97, 0x75, 0xcc, 0x66, 0xd8, 0x37,
|
||||
0x61, 0xc5, 0xb8, 0x71, 0xb2, 0x3f, 0x8b, 0x86, 0x5a, 0x78, 0xaa, 0x77, 0x04, 0xfb, 0x75, 0xfe,
|
||||
0x99, 0x7b, 0x8e, 0x18, 0xaf, 0xb9, 0x16, 0x63, 0x14, 0x9c, 0xdb, 0xd0, 0x36, 0x6f, 0xb3, 0x3c,
|
||||
0x87, 0xef, 0x39, 0xa3, 0xca, 0xbc, 0x2e, 0x77, 0xdd, 0x61, 0x7f, 0xe6, 0x40, 0xc7, 0xbc, 0x7d,
|
||||
0xca, 0xac, 0x3c, 0x6f, 0x89, 0x4f, 0xcf, 0xac, 0x33, 0x19, 0xb9, 0x1e, 0x75, 0xf2, 0xc1, 0xd6,
|
||||
0x57, 0xac, 0x49, 0xfe, 0xd4, 0xf2, 0xf3, 0xaf, 0x95, 0xdf, 0xf8, 0x3d, 0x2b, 0x13, 0x98, 0xf7,
|
||||
0x28, 0x9f, 0x5d, 0x77, 0xd8, 0xbb, 0xe2, 0x1d, 0xa8, 0x8a, 0xeb, 0x99, 0x61, 0xdc, 0xca, 0x53,
|
||||
0x66, 0x3e, 0x99, 0xbc, 0xea, 0x5c, 0x77, 0xd8, 0xb7, 0xc4, 0x53, 0x3e, 0xf9, 0x2d, 0xcd, 0xfc,
|
||||
0xcb, 0x7e, 0xef, 0xbe, 0x4e, 0xa3, 0xb9, 0xe4, 0x9e, 0xb7, 0x46, 0x53, 0xb6, 0xee, 0x7b, 0x00,
|
||||
0x45, 0x92, 0x86, 0x95, 0x32, 0x16, 0xda, 0xee, 0x55, 0xf3, 0x38, 0xf6, 0x8a, 0xaa, 0xc4, 0x06,
|
||||
0x72, 0xfc, 0x48, 0x08, 0xa3, 0xa4, 0xcf, 0xf4, 0x92, 0x56, 0x93, 0x2d, 0xfd, 0x7e, 0x5d, 0x55,
|
||||
0x9d, 0x28, 0x2a, 0xfe, 0xec, 0x31, 0x2c, 0x3f, 0x88, 0xe3, 0x27, 0xd3, 0x44, 0xa7, 0x11, 0xed,
|
||||
0x9c, 0xc1, 0xae, 0x9f, 0x1d, 0xf5, 0x4b, 0xa3, 0x70, 0x2f, 0x13, 0xab, 0x3e, 0xeb, 0x19, 0xac,
|
||||
0xb6, 0x3f, 0x2d, 0x52, 0x44, 0xcf, 0x98, 0x0f, 0x6b, 0x7a, 0x8f, 0xd3, 0x1d, 0xef, 0xdb, 0x6c,
|
||||
0xcc, 0x4c, 0x4d, 0xa5, 0x09, 0xcb, 0xeb, 0x50, 0xbd, 0xdd, 0xce, 0x14, 0xcf, 0xeb, 0x0e, 0xdb,
|
||||
0x83, 0xce, 0x1d, 0x3e, 0x8c, 0x47, 0x5c, 0x46, 0xf9, 0xeb, 0x45, 0xc7, 0x75, 0x7a, 0xa0, 0xbf,
|
||||
0x6c, 0x81, 0xb6, 0xd6, 0x27, 0xfe, 0x2c, 0xe5, 0x1f, 0x6f, 0x7f, 0x2a, 0xf3, 0x07, 0xcf, 0x94,
|
||||
0xd6, 0xab, 0x9c, 0x87, 0xa5, 0xf5, 0xa5, 0x24, 0x89, 0xa5, 0xf5, 0x95, 0x24, 0x89, 0x35, 0xd5,
|
||||
0x2a, 0xe7, 0xc2, 0x42, 0x58, 0xab, 0xe4, 0x55, 0xf4, 0x4e, 0x79, 0x5a, 0x36, 0xa6, 0x7f, 0xf9,
|
||||
0x74, 0x02, 0xbb, 0xb5, 0x2d, 0xbb, 0xb5, 0x7d, 0x58, 0xbe, 0xc3, 0xc5, 0x64, 0x89, 0xb3, 0xca,
|
||||
0xbe, 0x6d, 0x46, 0xcc, 0x73, 0xcd, 0xb2, 0x89, 0xa1, 0x3a, 0xdb, 0xac, 0xd3, 0x41, 0x21, 0xfb,
|
||||
0x08, 0xda, 0xf7, 0x79, 0xae, 0x0e, 0x27, 0xb5, 0xbf, 0x51, 0x3a, 0xad, 0xec, 0xd7, 0x9c, 0x6d,
|
||||
0xda, 0x32, 0x43, 0xdc, 0xb6, 0xf9, 0x68, 0xcc, 0x85, 0xb2, 0x0f, 0x82, 0xd1, 0x33, 0xf6, 0xeb,
|
||||
0xc4, 0x5c, 0xdf, 0x67, 0xd8, 0x34, 0xce, 0xb4, 0x4c, 0xe6, 0x2b, 0x25, 0xbc, 0x8e, 0x73, 0x14,
|
||||
0x8f, 0xb8, 0xb1, 0xc1, 0x45, 0xd0, 0x36, 0x2e, 0xdb, 0x68, 0x05, 0xaa, 0x5e, 0xf0, 0xd1, 0x0a,
|
||||
0x54, 0x73, 0x37, 0xc7, 0xbd, 0x4a, 0xed, 0xb8, 0xec, 0x72, 0xd1, 0x8e, 0xb8, 0x8f, 0x53, 0xb4,
|
||||
0xb4, 0xfd, 0xa9, 0x3f, 0xc9, 0x9f, 0xb1, 0x0f, 0xe9, 0x29, 0x8b, 0x79, 0x00, 0x5b, 0xf8, 0x3b,
|
||||
0xe5, 0xb3, 0x5a, 0x3d, 0x59, 0x46, 0x95, 0xed, 0x03, 0x89, 0xa6, 0x68, 0x1f, 0xfc, 0x22, 0xc0,
|
||||
0x7e, 0x1e, 0x27, 0x77, 0x7c, 0x3e, 0x89, 0xa3, 0xc2, 0x72, 0x15, 0x87, 0x8c, 0x85, 0xe5, 0x32,
|
||||
0x4e, 0x1a, 0xd9, 0x87, 0x86, 0xc7, 0x69, 0x9d, 0x5f, 0x2b, 0xe1, 0x3a, 0xf5, 0x1c, 0x52, 0x4f,
|
||||
0x48, 0xcd, 0x59, 0xe4, 0x75, 0x07, 0xfd, 0xc7, 0x22, 0x8b, 0xa7, 0xfd, 0xc7, 0x4a, 0x82, 0x50,
|
||||
0x9b, 0xbd, 0x9a, 0x94, 0xdf, 0x1e, 0xb4, 0x8a, 0xb4, 0x90, 0xda, 0x92, 0xca, 0x49, 0x24, 0xbd,
|
||||
0xc7, 0x54, 0x92, 0x35, 0xee, 0x2a, 0x4d, 0x15, 0xb0, 0x25, 0x9c, 0x2a, 0xca, 0xc0, 0x04, 0xb0,
|
||||
0x2e, 0x3a, 0xa8, 0x37, 0x4c, 0x3a, 0x36, 0x53, 0x23, 0xa9, 0x49, 0x98, 0x68, 0x6d, 0xae, 0xcd,
|
||||
0x37, 0x58, 0xb1, 0x1d, 0x4a, 0xab, 0x38, 0xb2, 0x43, 0xd3, 0x3c, 0x81, 0xb5, 0x4a, 0xb0, 0xac,
|
||||
0x55, 0xfa, 0xb4, 0x1c, 0x85, 0x56, 0xe9, 0x53, 0xe3, 0x6c, 0xf7, 0x2c, 0x35, 0xb9, 0xe2, 0x02,
|
||||
0x36, 0x99, 0x9d, 0x04, 0xf9, 0xf0, 0xe8, 0x5d, 0x67, 0xeb, 0x60, 0x81, 0xfe, 0x69, 0xe4, 0xf3,
|
||||
0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x0b, 0xc7, 0xfe, 0x7f, 0x9b, 0x44, 0x00, 0x00,
|
||||
// 5611 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0xcb, 0x73, 0x1c, 0xc9,
|
||||
0x71, 0x37, 0x7b, 0x30, 0x78, 0x4c, 0xce, 0x60, 0x00, 0x14, 0x40, 0x70, 0x38, 0xe4, 0x72, 0xb9,
|
||||
0xad, 0x0d, 0x91, 0x1f, 0xbe, 0x35, 0xc1, 0x85, 0xa4, 0xf5, 0x6a, 0x69, 0x4b, 0xe6, 0x1b, 0x2b,
|
||||
0x71, 0x29, 0xa8, 0x41, 0x8a, 0xb6, 0x64, 0x7b, 0xd4, 0x98, 0x29, 0x0c, 0x7a, 0xd9, 0xd3, 0xdd,
|
||||
0xdb, 0xdd, 0x03, 0x70, 0x76, 0xcd, 0x08, 0xbf, 0xc2, 0x27, 0x2b, 0x7c, 0xb0, 0x2f, 0xb2, 0xc3,
|
||||
0xe1, 0x08, 0xe9, 0x62, 0x1f, 0x7c, 0xf4, 0x49, 0xf6, 0x3f, 0xe0, 0x08, 0x87, 0x0f, 0x7b, 0x52,
|
||||
0xf8, 0xe6, 0xc7, 0xc1, 0x56, 0xf8, 0xe2, 0x08, 0x5f, 0x7c, 0x70, 0x38, 0x32, 0xeb, 0xd1, 0x55,
|
||||
0xdd, 0x0d, 0x92, 0x7a, 0xd8, 0xb7, 0xa9, 0x5f, 0x65, 0x67, 0xbd, 0x32, 0xb3, 0x32, 0xb3, 0xaa,
|
||||
0x06, 0x5a, 0x69, 0x32, 0xbc, 0x96, 0xa4, 0x71, 0x1e, 0xb3, 0xf9, 0x30, 0x4a, 0x93, 0x61, 0xff,
|
||||
0xe2, 0x38, 0x8e, 0xc7, 0x21, 0xdf, 0xf6, 0x93, 0x60, 0xdb, 0x8f, 0xa2, 0x38, 0xf7, 0xf3, 0x20,
|
||||
0x8e, 0x32, 0x41, 0xe4, 0x7e, 0x1b, 0xba, 0xf7, 0x79, 0xb4, 0xcf, 0xf9, 0xc8, 0xe3, 0x1f, 0x4d,
|
||||
0x79, 0x96, 0xb3, 0xff, 0x0f, 0x6b, 0x3e, 0xff, 0x98, 0xf3, 0xd1, 0x20, 0xf1, 0xb3, 0x2c, 0x39,
|
||||
0x4a, 0xfd, 0x8c, 0xf7, 0x9c, 0xcb, 0xce, 0xd5, 0x8e, 0xb7, 0x2a, 0x2a, 0xf6, 0x34, 0xce, 0xde,
|
||||
0x80, 0x4e, 0x86, 0xa4, 0x3c, 0xca, 0xd3, 0x38, 0x99, 0xf5, 0x1a, 0x44, 0xd7, 0x46, 0xec, 0xae,
|
||||
0x80, 0xdc, 0x10, 0x56, 0x74, 0x0b, 0x59, 0x12, 0x47, 0x19, 0x67, 0xd7, 0x61, 0x63, 0x18, 0x24,
|
||||
0x47, 0x3c, 0x1d, 0xd0, 0xc7, 0x93, 0x88, 0x4f, 0xe2, 0x28, 0x18, 0xf6, 0x9c, 0xcb, 0x73, 0x57,
|
||||
0x5b, 0x1e, 0x13, 0x75, 0xf8, 0xc5, 0x07, 0xb2, 0x86, 0x5d, 0x81, 0x15, 0x1e, 0x09, 0x9c, 0x8f,
|
||||
0xe8, 0x2b, 0xd9, 0x54, 0xb7, 0x80, 0xf1, 0x03, 0xf7, 0x4f, 0x1c, 0x58, 0x7b, 0x3f, 0x0a, 0xf2,
|
||||
0x27, 0x7e, 0x18, 0xf2, 0x5c, 0x8d, 0xe9, 0x0a, 0xac, 0x9c, 0x10, 0x40, 0x63, 0x3a, 0x89, 0xd3,
|
||||
0x91, 0x1c, 0x51, 0x57, 0xc0, 0x7b, 0x12, 0x3d, 0xb5, 0x67, 0x8d, 0x53, 0x7b, 0x56, 0x3b, 0x5d,
|
||||
0x73, 0xf5, 0xd3, 0xe5, 0x6e, 0x00, 0x33, 0x3b, 0x27, 0xa6, 0xc3, 0xfd, 0x12, 0xac, 0x3f, 0x8e,
|
||||
0xc2, 0x78, 0xf8, 0xf4, 0x27, 0xeb, 0xb4, 0xbb, 0x09, 0x1b, 0xf6, 0xf7, 0x92, 0xef, 0x77, 0x1b,
|
||||
0xd0, 0x7e, 0x94, 0xfa, 0x51, 0xe6, 0x0f, 0x71, 0xc9, 0x59, 0x0f, 0x16, 0xf3, 0x67, 0x83, 0x23,
|
||||
0x3f, 0x3b, 0x22, 0x46, 0x2d, 0x4f, 0x15, 0xd9, 0x26, 0x2c, 0xf8, 0x93, 0x78, 0x1a, 0xe5, 0x34,
|
||||
0xab, 0x73, 0x9e, 0x2c, 0xb1, 0xb7, 0x60, 0x2d, 0x9a, 0x4e, 0x06, 0xc3, 0x38, 0x3a, 0x0c, 0xd2,
|
||||
0x89, 0x10, 0x1c, 0x1a, 0xdc, 0xbc, 0x57, 0xad, 0x60, 0x97, 0x00, 0x0e, 0xb0, 0x1b, 0xa2, 0x89,
|
||||
0x26, 0x35, 0x61, 0x20, 0xcc, 0x85, 0x8e, 0x2c, 0xf1, 0x60, 0x7c, 0x94, 0xf7, 0xe6, 0x89, 0x91,
|
||||
0x85, 0x21, 0x8f, 0x3c, 0x98, 0xf0, 0x41, 0x96, 0xfb, 0x93, 0xa4, 0xb7, 0x40, 0xbd, 0x31, 0x10,
|
||||
0xaa, 0x8f, 0x73, 0x3f, 0x1c, 0x1c, 0x72, 0x9e, 0xf5, 0x16, 0x65, 0xbd, 0x46, 0xd8, 0x67, 0xa1,
|
||||
0x3b, 0xe2, 0x59, 0x3e, 0xf0, 0x47, 0xa3, 0x94, 0x67, 0x19, 0xcf, 0x7a, 0x4b, 0xb4, 0x74, 0x25,
|
||||
0xd4, 0xed, 0xc1, 0xe6, 0x7d, 0x9e, 0x1b, 0xb3, 0x93, 0xc9, 0x69, 0x77, 0x1f, 0x00, 0x33, 0xe0,
|
||||
0x3b, 0x3c, 0xf7, 0x83, 0x30, 0x63, 0xef, 0x40, 0x27, 0x37, 0x88, 0x49, 0x54, 0xdb, 0x3b, 0xec,
|
||||
0x1a, 0xe9, 0xd8, 0x35, 0xe3, 0x03, 0xcf, 0xa2, 0x73, 0xff, 0xcb, 0x81, 0xf6, 0x3e, 0x8f, 0xb4,
|
||||
0x76, 0x31, 0x68, 0x62, 0x4f, 0xe4, 0x4a, 0xd2, 0x6f, 0xf6, 0x3a, 0xb4, 0xa9, 0x77, 0x59, 0x9e,
|
||||
0x06, 0xd1, 0x98, 0x96, 0xa0, 0xe5, 0x01, 0x42, 0xfb, 0x84, 0xb0, 0x55, 0x98, 0xf3, 0x27, 0x39,
|
||||
0x4d, 0xfc, 0x9c, 0x87, 0x3f, 0x51, 0xef, 0x12, 0x7f, 0x36, 0xe1, 0x51, 0x5e, 0x4c, 0x76, 0xc7,
|
||||
0x6b, 0x4b, 0x6c, 0x17, 0x67, 0xfb, 0x1a, 0xac, 0x9b, 0x24, 0x8a, 0xfb, 0x3c, 0x71, 0x5f, 0x33,
|
||||
0x28, 0x65, 0x23, 0x57, 0x60, 0x45, 0xd1, 0xa7, 0xa2, 0xb3, 0x34, 0xfd, 0x2d, 0xaf, 0x2b, 0x61,
|
||||
0x35, 0x84, 0xab, 0xb0, 0x7a, 0x18, 0x44, 0x7e, 0x38, 0x18, 0x86, 0xf9, 0xf1, 0x60, 0xc4, 0xc3,
|
||||
0xdc, 0xa7, 0x85, 0x98, 0xf7, 0xba, 0x84, 0xdf, 0x0e, 0xf3, 0xe3, 0x3b, 0x88, 0xba, 0x7f, 0xe4,
|
||||
0x40, 0x47, 0x0c, 0x5e, 0x2a, 0xfe, 0x9b, 0xb0, 0xac, 0xda, 0xe0, 0x69, 0x1a, 0xa7, 0x52, 0x0e,
|
||||
0x6d, 0x90, 0x6d, 0xc1, 0xaa, 0x02, 0x92, 0x94, 0x07, 0x13, 0x7f, 0xcc, 0xa5, 0xb6, 0x57, 0x70,
|
||||
0xb6, 0x53, 0x70, 0x4c, 0xe3, 0x69, 0x2e, 0x54, 0xaf, 0xbd, 0xd3, 0x91, 0x0b, 0xe3, 0x21, 0xe6,
|
||||
0xd9, 0x24, 0xee, 0xf7, 0x1c, 0xe8, 0xdc, 0x3e, 0xf2, 0xa3, 0x88, 0x87, 0x7b, 0x71, 0x10, 0xe5,
|
||||
0xec, 0x3a, 0xb0, 0xc3, 0x69, 0x34, 0x0a, 0xa2, 0xf1, 0x20, 0x7f, 0x16, 0x8c, 0x06, 0x07, 0xb3,
|
||||
0x9c, 0x67, 0x62, 0x89, 0x76, 0xcf, 0x78, 0x35, 0x75, 0xec, 0x2d, 0x58, 0xb5, 0xd0, 0x2c, 0x4f,
|
||||
0xc5, 0xba, 0xed, 0x9e, 0xf1, 0x2a, 0x35, 0x28, 0xf8, 0xf1, 0x34, 0x4f, 0xa6, 0xf9, 0x20, 0x88,
|
||||
0x46, 0xfc, 0x19, 0xf5, 0x71, 0xd9, 0xb3, 0xb0, 0x5b, 0x5d, 0xe8, 0x98, 0xdf, 0xb9, 0x5f, 0x82,
|
||||
0xd5, 0x07, 0xa8, 0x11, 0x51, 0x10, 0x8d, 0x6f, 0x0a, 0xb1, 0x45, 0x35, 0x4d, 0xa6, 0x07, 0x4f,
|
||||
0xf9, 0x4c, 0xce, 0x9b, 0x2c, 0xa1, 0x50, 0x1d, 0xc5, 0x59, 0x2e, 0x25, 0x87, 0x7e, 0xbb, 0xff,
|
||||
0xe4, 0xc0, 0x0a, 0xce, 0xfd, 0x07, 0x7e, 0x34, 0x53, 0x2b, 0xf7, 0x00, 0x3a, 0xc8, 0xea, 0x51,
|
||||
0x7c, 0x53, 0x28, 0xbb, 0x10, 0xe2, 0xab, 0x72, 0xae, 0x4a, 0xd4, 0xd7, 0x4c, 0x52, 0x34, 0xe6,
|
||||
0x33, 0xcf, 0xfa, 0x1a, 0xc5, 0x36, 0xf7, 0xd3, 0x31, 0xcf, 0xc9, 0x0c, 0x48, 0xb3, 0x00, 0x02,
|
||||
0xba, 0x1d, 0x47, 0x87, 0xec, 0x32, 0x74, 0x32, 0x3f, 0x1f, 0x24, 0x3c, 0xa5, 0x59, 0x23, 0xd1,
|
||||
0x9b, 0xf3, 0x20, 0xf3, 0xf3, 0x3d, 0x9e, 0xde, 0x9a, 0xe5, 0xbc, 0xff, 0x65, 0x58, 0xab, 0xb4,
|
||||
0x82, 0xd2, 0x5e, 0x0c, 0x11, 0x7f, 0xb2, 0x0d, 0x98, 0x3f, 0xf6, 0xc3, 0x29, 0x97, 0xd6, 0x49,
|
||||
0x14, 0xde, 0x6b, 0xbc, 0xeb, 0xb8, 0x9f, 0x85, 0xd5, 0xa2, 0xdb, 0x52, 0xc8, 0x18, 0x34, 0x71,
|
||||
0x06, 0x25, 0x03, 0xfa, 0xed, 0xfe, 0x96, 0x23, 0x08, 0x6f, 0xc7, 0x81, 0xd6, 0x74, 0x24, 0x44,
|
||||
0x83, 0xa0, 0x08, 0xf1, 0xf7, 0xa9, 0x96, 0xf0, 0xa7, 0x1f, 0xac, 0x7b, 0x05, 0xd6, 0x8c, 0x2e,
|
||||
0xbc, 0xa0, 0xb3, 0xdf, 0x71, 0x60, 0xed, 0x21, 0x3f, 0x91, 0xab, 0xae, 0x7a, 0xfb, 0x2e, 0x34,
|
||||
0xf3, 0x59, 0x22, 0xb6, 0xe2, 0xee, 0xce, 0x9b, 0x72, 0xd1, 0x2a, 0x74, 0xd7, 0x64, 0xf1, 0xd1,
|
||||
0x2c, 0xe1, 0x1e, 0x7d, 0xe1, 0x7e, 0x09, 0xda, 0x06, 0xc8, 0xce, 0xc1, 0xfa, 0x93, 0xf7, 0x1f,
|
||||
0x3d, 0xbc, 0xbb, 0xbf, 0x3f, 0xd8, 0x7b, 0x7c, 0xeb, 0xab, 0x77, 0x7f, 0x65, 0xb0, 0x7b, 0x73,
|
||||
0x7f, 0x77, 0xf5, 0x0c, 0xdb, 0x04, 0xf6, 0xf0, 0xee, 0xfe, 0xa3, 0xbb, 0x77, 0x2c, 0xdc, 0x71,
|
||||
0xfb, 0xd0, 0x7b, 0xc8, 0x4f, 0x9e, 0x04, 0x79, 0xc4, 0xb3, 0xcc, 0x6e, 0xcd, 0xbd, 0x06, 0xcc,
|
||||
0xec, 0x82, 0x1c, 0x55, 0x0f, 0x16, 0xa5, 0xa9, 0x55, 0x3b, 0x8d, 0x2c, 0xba, 0x9f, 0x05, 0xb6,
|
||||
0x1f, 0x8c, 0xa3, 0x0f, 0x78, 0x96, 0xf9, 0x63, 0xae, 0xc6, 0xb6, 0x0a, 0x73, 0x93, 0x6c, 0x2c,
|
||||
0x8d, 0x22, 0xfe, 0x74, 0x3f, 0x07, 0xeb, 0x16, 0x9d, 0x64, 0x7c, 0x11, 0x5a, 0x59, 0x30, 0x8e,
|
||||
0xfc, 0x7c, 0x9a, 0x72, 0xc9, 0xba, 0x00, 0xdc, 0x7b, 0xb0, 0xf1, 0x0d, 0x9e, 0x06, 0x87, 0xb3,
|
||||
0x97, 0xb1, 0xb7, 0xf9, 0x34, 0xca, 0x7c, 0xee, 0xc2, 0xd9, 0x12, 0x1f, 0xd9, 0xbc, 0x10, 0x44,
|
||||
0xb9, 0x5c, 0x4b, 0x9e, 0x28, 0x18, 0x6a, 0xd9, 0x30, 0xd5, 0xd2, 0x7d, 0x0c, 0xec, 0x76, 0x1c,
|
||||
0x45, 0x7c, 0x98, 0xef, 0x71, 0x9e, 0x16, 0xfe, 0x55, 0x21, 0x75, 0xed, 0x9d, 0x73, 0x72, 0x1d,
|
||||
0xcb, 0xba, 0x2e, 0xc5, 0x91, 0x41, 0x33, 0xe1, 0xe9, 0x84, 0x18, 0x2f, 0x79, 0xf4, 0xdb, 0x3d,
|
||||
0x0b, 0xeb, 0x16, 0x5b, 0xb9, 0xdb, 0xbf, 0x0d, 0x67, 0xef, 0x04, 0xd9, 0xb0, 0xda, 0x60, 0x0f,
|
||||
0x16, 0x93, 0xe9, 0xc1, 0xa0, 0xd0, 0x29, 0x55, 0xc4, 0x4d, 0xb0, 0xfc, 0x89, 0x64, 0xf6, 0x7b,
|
||||
0x0e, 0x34, 0x77, 0x1f, 0x3d, 0xb8, 0xcd, 0xfa, 0xb0, 0x14, 0x44, 0xc3, 0x78, 0x82, 0x5b, 0x87,
|
||||
0x18, 0xb4, 0x2e, 0x9f, 0xaa, 0x2b, 0x17, 0xa1, 0x45, 0x3b, 0x0e, 0xee, 0xeb, 0xd2, 0x15, 0x2a,
|
||||
0x00, 0xf4, 0x29, 0xf8, 0xb3, 0x24, 0x48, 0xc9, 0x69, 0x50, 0xae, 0x40, 0x93, 0x2c, 0x62, 0xb5,
|
||||
0xc2, 0xfd, 0xef, 0x26, 0x2c, 0x4a, 0x5b, 0x4d, 0xed, 0x0d, 0xf3, 0xe0, 0x98, 0xcb, 0x9e, 0xc8,
|
||||
0x12, 0xee, 0x2a, 0x29, 0x9f, 0xc4, 0x39, 0x1f, 0x58, 0xcb, 0x60, 0x83, 0x48, 0x35, 0x14, 0x8c,
|
||||
0x06, 0x09, 0x5a, 0x7d, 0xea, 0x59, 0xcb, 0xb3, 0x41, 0x9c, 0x2c, 0x04, 0x06, 0xc1, 0x88, 0xfa,
|
||||
0xd4, 0xf4, 0x54, 0x11, 0x67, 0x62, 0xe8, 0x27, 0xfe, 0x30, 0xc8, 0x67, 0x52, 0xb9, 0x75, 0x19,
|
||||
0x79, 0x87, 0xf1, 0xd0, 0x0f, 0x07, 0x07, 0x7e, 0xe8, 0x47, 0x43, 0x2e, 0x1d, 0x17, 0x1b, 0x44,
|
||||
0xdf, 0x44, 0x76, 0x49, 0x91, 0x09, 0xff, 0xa5, 0x84, 0xa2, 0x8f, 0x33, 0x8c, 0x27, 0x93, 0x20,
|
||||
0x47, 0x97, 0xa6, 0xb7, 0x24, 0x0c, 0x49, 0x81, 0xd0, 0x48, 0x44, 0xe9, 0x44, 0xcc, 0x5e, 0x4b,
|
||||
0xb4, 0x66, 0x81, 0xc8, 0xe5, 0x90, 0x73, 0x32, 0x48, 0x4f, 0x4f, 0x7a, 0x20, 0xb8, 0x14, 0x08,
|
||||
0xae, 0xc3, 0x34, 0xca, 0x78, 0x9e, 0x87, 0x7c, 0xa4, 0x3b, 0xd4, 0x26, 0xb2, 0x6a, 0x05, 0xbb,
|
||||
0x0e, 0xeb, 0xc2, 0xcb, 0xca, 0xfc, 0x3c, 0xce, 0x8e, 0x82, 0x6c, 0x90, 0xf1, 0x28, 0xef, 0x75,
|
||||
0x88, 0xbe, 0xae, 0x8a, 0xbd, 0x0b, 0xe7, 0x4a, 0x70, 0xca, 0x87, 0x3c, 0x38, 0xe6, 0xa3, 0xde,
|
||||
0x32, 0x7d, 0x75, 0x5a, 0x35, 0xbb, 0x0c, 0x6d, 0x74, 0x2e, 0xa7, 0xc9, 0xc8, 0xc7, 0x7d, 0xb8,
|
||||
0x4b, 0xeb, 0x60, 0x42, 0xec, 0x6d, 0x58, 0x4e, 0xb8, 0xd8, 0x2c, 0x8f, 0xf2, 0x70, 0x98, 0xf5,
|
||||
0x56, 0x68, 0x27, 0x6b, 0x4b, 0x65, 0x42, 0xc9, 0xf5, 0x6c, 0x0a, 0x14, 0xca, 0x61, 0x46, 0xee,
|
||||
0x8a, 0x3f, 0xeb, 0xad, 0x92, 0xb8, 0x15, 0x00, 0xe9, 0x48, 0x1a, 0x1c, 0xfb, 0x39, 0xef, 0xad,
|
||||
0x91, 0x6c, 0xa9, 0xa2, 0xfb, 0x67, 0x0e, 0xac, 0x3f, 0x08, 0xb2, 0x5c, 0x0a, 0xa1, 0x36, 0xc7,
|
||||
0xaf, 0x43, 0x5b, 0x88, 0xdf, 0x20, 0x8e, 0xc2, 0x99, 0x94, 0x48, 0x10, 0xd0, 0xd7, 0xa2, 0x70,
|
||||
0xc6, 0x3e, 0x03, 0xcb, 0x41, 0x64, 0x92, 0x08, 0x1d, 0xee, 0x28, 0x90, 0x88, 0x5e, 0x87, 0x76,
|
||||
0x32, 0x3d, 0x08, 0x83, 0xa1, 0x20, 0x99, 0x13, 0x5c, 0x04, 0x44, 0x04, 0xe8, 0xe8, 0x89, 0x9e,
|
||||
0x08, 0x8a, 0x26, 0x51, 0xb4, 0x25, 0x86, 0x24, 0xee, 0x2d, 0xd8, 0xb0, 0x3b, 0x28, 0x8d, 0xd5,
|
||||
0x16, 0x2c, 0x49, 0xd9, 0xce, 0x7a, 0x6d, 0x9a, 0x9f, 0xae, 0x9c, 0x1f, 0x49, 0xea, 0xe9, 0x7a,
|
||||
0xf7, 0xdf, 0x1c, 0x68, 0xa2, 0x01, 0x38, 0xdd, 0x58, 0x98, 0x36, 0x7d, 0xce, 0xb2, 0xe9, 0xe4,
|
||||
0xf7, 0xa3, 0x57, 0x24, 0x44, 0x42, 0xa8, 0x8d, 0x81, 0x14, 0xf5, 0x29, 0x1f, 0x1e, 0x93, 0xee,
|
||||
0xe8, 0x7a, 0x44, 0x50, 0xb3, 0x70, 0xeb, 0xa4, 0xaf, 0x85, 0xe2, 0xe8, 0xb2, 0xaa, 0xa3, 0x2f,
|
||||
0x17, 0x8b, 0x3a, 0xfa, 0xae, 0x07, 0x8b, 0x41, 0x74, 0x10, 0x4f, 0xa3, 0x11, 0x29, 0xc9, 0x92,
|
||||
0xa7, 0x8a, 0xb8, 0xd8, 0x09, 0x79, 0x52, 0xc1, 0x84, 0x4b, 0xed, 0x28, 0x00, 0x97, 0xa1, 0x6b,
|
||||
0x95, 0x91, 0xc1, 0xd3, 0xfb, 0xd8, 0x3b, 0xb0, 0x66, 0x60, 0x72, 0x06, 0xdf, 0x80, 0xf9, 0x04,
|
||||
0x01, 0xe9, 0x28, 0x29, 0xf1, 0x22, 0x4b, 0x29, 0x6a, 0xdc, 0x55, 0x8c, 0x9f, 0xf3, 0xf7, 0xa3,
|
||||
0xc3, 0x58, 0x71, 0xfa, 0xe1, 0x1c, 0x06, 0xbc, 0x12, 0x92, 0x8c, 0xae, 0xc2, 0x4a, 0x30, 0xe2,
|
||||
0x51, 0x1e, 0xe4, 0xb3, 0x81, 0xe5, 0xc1, 0x95, 0x61, 0xdc, 0x61, 0xfc, 0x30, 0xf0, 0x33, 0x69,
|
||||
0xc3, 0x44, 0x81, 0xed, 0xc0, 0x06, 0x8a, 0xbf, 0x92, 0x68, 0xbd, 0xac, 0xc2, 0x91, 0xac, 0xad,
|
||||
0x43, 0x8d, 0x45, 0x5c, 0x4a, 0xa0, 0xfe, 0x44, 0x58, 0xda, 0xba, 0x2a, 0x9c, 0x35, 0xc1, 0x09,
|
||||
0x87, 0x3c, 0x2f, 0x54, 0x44, 0x03, 0x95, 0xe8, 0x6d, 0x41, 0x38, 0xb1, 0xe5, 0xe8, 0xcd, 0x88,
|
||||
0x00, 0x97, 0x2a, 0x11, 0xe0, 0x55, 0x58, 0xc9, 0x66, 0xd1, 0x90, 0x8f, 0x06, 0x79, 0x8c, 0xed,
|
||||
0x06, 0x11, 0xad, 0xce, 0x92, 0x57, 0x86, 0x29, 0x56, 0xe5, 0x59, 0x1e, 0xf1, 0x9c, 0x4c, 0xd7,
|
||||
0x92, 0xa7, 0x8a, 0xb8, 0x0b, 0x10, 0x89, 0x10, 0xea, 0x96, 0x27, 0x4b, 0xb8, 0x55, 0x4e, 0xd3,
|
||||
0x20, 0xeb, 0x75, 0x08, 0xa5, 0xdf, 0xec, 0xf3, 0x70, 0xf6, 0x00, 0x23, 0xab, 0x23, 0xee, 0x8f,
|
||||
0x78, 0x4a, 0xab, 0x2f, 0x02, 0x4b, 0x61, 0x81, 0xea, 0x2b, 0xb1, 0xed, 0x63, 0x9e, 0x66, 0x41,
|
||||
0x1c, 0x91, 0xed, 0x69, 0x79, 0xaa, 0xe8, 0x7e, 0x4c, 0x3b, 0xba, 0x0e, 0x79, 0x1f, 0x93, 0x39,
|
||||
0x62, 0x17, 0xa0, 0x25, 0xc6, 0x98, 0x1d, 0xf9, 0xd2, 0xc9, 0x58, 0x22, 0x60, 0xff, 0xc8, 0x47,
|
||||
0x05, 0xb6, 0xa6, 0xad, 0x41, 0x9e, 0x63, 0x9b, 0xb0, 0x5d, 0x31, 0x6b, 0x6f, 0x42, 0x57, 0x05,
|
||||
0xd3, 0xd9, 0x20, 0xe4, 0x87, 0xb9, 0x0a, 0x10, 0xa2, 0xe9, 0x04, 0x9b, 0xcb, 0x1e, 0xf0, 0xc3,
|
||||
0xdc, 0x7d, 0x08, 0x6b, 0x52, 0x6f, 0xbf, 0x96, 0x70, 0xd5, 0xf4, 0x17, 0xcb, 0x9b, 0x9a, 0xf0,
|
||||
0x2a, 0xd6, 0x6d, 0x45, 0xa7, 0x28, 0xa7, 0xb4, 0xd3, 0xb9, 0x1e, 0x30, 0x59, 0x7d, 0x3b, 0x8c,
|
||||
0x33, 0x2e, 0x19, 0xba, 0xd0, 0x19, 0x86, 0x71, 0xa6, 0xc2, 0x10, 0x39, 0x1c, 0x0b, 0xc3, 0xf9,
|
||||
0xc9, 0xa6, 0xc3, 0x21, 0x5a, 0x02, 0x61, 0xd3, 0x54, 0xd1, 0xfd, 0x73, 0x07, 0xd6, 0x89, 0x9b,
|
||||
0xb2, 0x30, 0xda, 0x77, 0x7d, 0xf5, 0x6e, 0x76, 0x86, 0x66, 0x68, 0xb6, 0x01, 0xf3, 0x87, 0x71,
|
||||
0x3a, 0xe4, 0xb2, 0x25, 0x51, 0xf8, 0xf1, 0xbd, 0xf1, 0x66, 0xc5, 0x1b, 0xff, 0xa1, 0x03, 0x6b,
|
||||
0xd4, 0xd5, 0xfd, 0xdc, 0xcf, 0xa7, 0x99, 0x1c, 0xfe, 0x2f, 0xc0, 0x32, 0x0e, 0x95, 0x2b, 0x75,
|
||||
0x92, 0x1d, 0xdd, 0xd0, 0x9a, 0x4f, 0xa8, 0x20, 0xde, 0x3d, 0xe3, 0xd9, 0xc4, 0xec, 0xcb, 0xd0,
|
||||
0x31, 0x33, 0x22, 0xd4, 0xe7, 0xf6, 0xce, 0x79, 0x35, 0xca, 0x8a, 0xe4, 0xec, 0x9e, 0xf1, 0xac,
|
||||
0x0f, 0xd8, 0x0d, 0x00, 0x72, 0x37, 0x88, 0xad, 0x0c, 0x65, 0xcf, 0xdb, 0x93, 0x64, 0x2c, 0xd6,
|
||||
0xee, 0x19, 0xcf, 0x20, 0xbf, 0xb5, 0x04, 0x0b, 0x62, 0x7f, 0x74, 0xef, 0xc3, 0xb2, 0xd5, 0x53,
|
||||
0x2b, 0xca, 0xe8, 0x88, 0x28, 0xa3, 0x12, 0x94, 0x36, 0xaa, 0x41, 0xa9, 0xfb, 0x2f, 0x0d, 0x60,
|
||||
0x28, 0x6d, 0xa5, 0xe5, 0xc4, 0x0d, 0x3a, 0x1e, 0x59, 0xee, 0x56, 0xc7, 0x33, 0x21, 0x76, 0x0d,
|
||||
0x98, 0x51, 0x54, 0xb9, 0x07, 0xb1, 0x6f, 0xd4, 0xd4, 0xa0, 0x81, 0x13, 0xbe, 0x92, 0x8a, 0x81,
|
||||
0xa5, 0x63, 0x29, 0xd6, 0xad, 0xb6, 0x0e, 0xb7, 0x86, 0x64, 0x9a, 0x1d, 0xa1, 0x03, 0xa1, 0x1c,
|
||||
0x32, 0x55, 0x2e, 0x0b, 0xc8, 0xc2, 0x4b, 0x05, 0x64, 0xb1, 0x2c, 0x20, 0xa6, 0x4b, 0xb0, 0x64,
|
||||
0xb9, 0x04, 0xe8, 0x7f, 0x4d, 0x82, 0x88, 0xfc, 0x8a, 0xc1, 0x04, 0x5b, 0x97, 0xfe, 0x97, 0x05,
|
||||
0xb2, 0x2d, 0x58, 0x95, 0x7e, 0x5d, 0xe1, 0x77, 0x00, 0xcd, 0x71, 0x05, 0x77, 0x3f, 0x75, 0x60,
|
||||
0x15, 0xe7, 0xd9, 0x92, 0xc5, 0xf7, 0x80, 0x54, 0xe1, 0x15, 0x45, 0xd1, 0xa2, 0xfd, 0xe9, 0x25,
|
||||
0xf1, 0x5d, 0x68, 0x11, 0xc3, 0x38, 0xe1, 0x91, 0x14, 0xc4, 0x9e, 0x2d, 0x88, 0x85, 0x15, 0xda,
|
||||
0x3d, 0xe3, 0x15, 0xc4, 0x86, 0x18, 0xfe, 0xbd, 0x03, 0x6d, 0xd9, 0xcd, 0x9f, 0x38, 0x96, 0xe8,
|
||||
0xc3, 0x12, 0x4a, 0xa4, 0xe1, 0xb0, 0xeb, 0x32, 0xee, 0x26, 0x13, 0x0c, 0xd8, 0x70, 0xfb, 0xb4,
|
||||
0xe2, 0x88, 0x32, 0x8c, 0x7b, 0x21, 0x19, 0xdc, 0x6c, 0x90, 0x07, 0xe1, 0x40, 0xd5, 0xca, 0x04,
|
||||
0x64, 0x5d, 0x15, 0xda, 0x9d, 0x2c, 0xf7, 0xc7, 0x5c, 0x6e, 0x73, 0xa2, 0x80, 0x01, 0x93, 0x1c,
|
||||
0x50, 0xc9, 0x1d, 0x74, 0xff, 0xa6, 0x03, 0xe7, 0x2a, 0x55, 0x3a, 0xdd, 0x2d, 0x1d, 0xe4, 0x30,
|
||||
0x98, 0x1c, 0xc4, 0xda, 0xd7, 0x76, 0x4c, 0xdf, 0xd9, 0xaa, 0x62, 0x63, 0x38, 0xab, 0xf6, 0x73,
|
||||
0x9c, 0xd3, 0x62, 0xf7, 0x6e, 0x90, 0x23, 0xf2, 0xb6, 0x2d, 0x03, 0xe5, 0x06, 0x15, 0x6e, 0x6a,
|
||||
0x6e, 0x3d, 0x3f, 0x76, 0x04, 0x3d, 0xed, 0x38, 0x48, 0x13, 0x6f, 0x38, 0x17, 0xd8, 0xd6, 0x5b,
|
||||
0x2f, 0x69, 0x8b, 0xec, 0xd1, 0x48, 0x35, 0x73, 0x2a, 0x37, 0x36, 0x83, 0x4b, 0xaa, 0x8e, 0x6c,
|
||||
0x78, 0xb5, 0xbd, 0xe6, 0x2b, 0x8d, 0xed, 0x1e, 0x7e, 0x6c, 0x37, 0xfa, 0x12, 0xc6, 0xec, 0x43,
|
||||
0xd8, 0x3c, 0xf1, 0x83, 0x5c, 0x75, 0xcb, 0x70, 0x86, 0xe6, 0xa9, 0xc9, 0x9d, 0x97, 0x34, 0xf9,
|
||||
0x44, 0x7c, 0x6c, 0x6d, 0x6c, 0xa7, 0x70, 0xec, 0xff, 0xad, 0x03, 0x5d, 0x9b, 0x0f, 0x8a, 0xa9,
|
||||
0x54, 0x78, 0x65, 0xf8, 0x94, 0xf3, 0x57, 0x82, 0xab, 0x21, 0x6a, 0xa3, 0x2e, 0x44, 0x35, 0x03,
|
||||
0xd1, 0xb9, 0x97, 0x05, 0xa2, 0xcd, 0x57, 0x0b, 0x44, 0xe7, 0xeb, 0x02, 0xd1, 0xfe, 0x7f, 0x3a,
|
||||
0xc0, 0xaa, 0xb2, 0xc4, 0xee, 0x8b, 0x18, 0x39, 0xe2, 0xa1, 0xb4, 0x49, 0x3f, 0xf7, 0x6a, 0xf2,
|
||||
0xa8, 0xe6, 0x4e, 0x7d, 0x8d, 0x8a, 0x61, 0x1a, 0x1d, 0xd3, 0x45, 0x5a, 0xf6, 0xea, 0xaa, 0x4a,
|
||||
0xa1, 0x71, 0xf3, 0xe5, 0xa1, 0xf1, 0xfc, 0xcb, 0x43, 0xe3, 0x85, 0x72, 0x68, 0xdc, 0xff, 0x5d,
|
||||
0x07, 0xd6, 0x6b, 0x16, 0xfd, 0x67, 0x37, 0x70, 0x5c, 0x26, 0xcb, 0x16, 0x34, 0xe4, 0x32, 0x99,
|
||||
0x60, 0xff, 0x37, 0x60, 0xd9, 0x12, 0xf4, 0x9f, 0x5d, 0xfb, 0x65, 0x2f, 0x4f, 0xc8, 0x99, 0x85,
|
||||
0xf5, 0x7f, 0xd4, 0x00, 0x56, 0x55, 0xb6, 0xff, 0xd3, 0x3e, 0x54, 0xe7, 0x69, 0xae, 0x66, 0x9e,
|
||||
0xfe, 0x57, 0xf7, 0x81, 0xb7, 0x60, 0x2d, 0xe5, 0xc3, 0xf8, 0x98, 0xce, 0x1d, 0xed, 0xec, 0x4e,
|
||||
0xb5, 0x02, 0xfd, 0x5c, 0x3b, 0x2f, 0xb1, 0x64, 0x1d, 0x13, 0x19, 0x9b, 0x61, 0x29, 0x3d, 0xe1,
|
||||
0x6e, 0xc2, 0x86, 0x38, 0xbd, 0xbb, 0x25, 0x58, 0xa9, 0x7d, 0xe5, 0x4f, 0x1d, 0x38, 0x5b, 0xaa,
|
||||
0x28, 0xce, 0x52, 0xc4, 0xd6, 0x61, 0xef, 0x27, 0x36, 0x88, 0xfd, 0x97, 0x7a, 0x64, 0xf4, 0x5f,
|
||||
0x48, 0x5b, 0xb5, 0x02, 0xe7, 0x67, 0x1a, 0x55, 0xe9, 0xc5, 0xac, 0xd7, 0x55, 0xb9, 0xe7, 0xe0,
|
||||
0xac, 0x5c, 0xd9, 0x52, 0xc7, 0x0f, 0x61, 0xb3, 0x5c, 0x51, 0x24, 0x87, 0xed, 0x2e, 0xab, 0x22,
|
||||
0x7a, 0x81, 0xd6, 0x36, 0x65, 0xf7, 0xb7, 0xb6, 0xce, 0xfd, 0x75, 0x60, 0x5f, 0x9f, 0xf2, 0x74,
|
||||
0x46, 0x27, 0x3d, 0x3a, 0x3b, 0x73, 0xae, 0x9c, 0xc6, 0x58, 0x48, 0xa6, 0x07, 0x5f, 0xe5, 0x33,
|
||||
0x75, 0x94, 0xd6, 0x28, 0x8e, 0xd2, 0x5e, 0x03, 0xc0, 0xe8, 0x8b, 0x8e, 0x86, 0xd4, 0xe1, 0x26,
|
||||
0x86, 0xbd, 0x82, 0xa1, 0x7b, 0x03, 0xd6, 0x2d, 0xfe, 0x7a, 0xf6, 0x17, 0xe4, 0x17, 0x22, 0x37,
|
||||
0x60, 0x1f, 0x38, 0xc9, 0x3a, 0xf7, 0xdf, 0x1d, 0x98, 0xdb, 0x8d, 0x13, 0x33, 0xab, 0xe8, 0xd8,
|
||||
0x59, 0x45, 0x69, 0xf2, 0x07, 0xda, 0xa2, 0x4b, 0x4b, 0x60, 0x81, 0x6c, 0x0b, 0xba, 0xfe, 0x24,
|
||||
0xc7, 0xe8, 0xf8, 0x30, 0x4e, 0x4f, 0xfc, 0x74, 0x24, 0x96, 0xe4, 0x56, 0xa3, 0xe7, 0x78, 0xa5,
|
||||
0x1a, 0xb6, 0x01, 0x73, 0xda, 0x36, 0x12, 0x01, 0x16, 0xd1, 0xbf, 0xa2, 0xe4, 0xea, 0x4c, 0x06,
|
||||
0xf6, 0xb2, 0x84, 0x2b, 0x6e, 0x7f, 0x2f, 0x3c, 0x5a, 0x21, 0xe1, 0x75, 0x55, 0xb8, 0xfd, 0xa0,
|
||||
0xa9, 0x24, 0x32, 0x99, 0x91, 0x51, 0x65, 0xf7, 0x5f, 0x1d, 0x98, 0xa7, 0x19, 0x40, 0x9d, 0x14,
|
||||
0x82, 0x48, 0x67, 0xb7, 0x94, 0x09, 0x76, 0x84, 0x4e, 0x96, 0x60, 0xe6, 0x5a, 0x27, 0xba, 0x0d,
|
||||
0xdd, 0x6d, 0xf3, 0x54, 0xf7, 0x32, 0xb4, 0x44, 0x49, 0x1f, 0x83, 0x12, 0x49, 0x01, 0xb2, 0x4b,
|
||||
0xd0, 0x3c, 0x8a, 0x13, 0xe5, 0x44, 0x80, 0x4a, 0x04, 0xc6, 0x89, 0x47, 0x78, 0xd1, 0x1f, 0xe4,
|
||||
0x27, 0x3a, 0x2f, 0xb6, 0x86, 0x32, 0x8c, 0x9b, 0xa3, 0x66, 0x6b, 0x4e, 0x46, 0x09, 0x75, 0xb7,
|
||||
0x60, 0xe5, 0x61, 0x3c, 0xe2, 0x46, 0xea, 0xe7, 0x54, 0xa9, 0x73, 0x7f, 0xd3, 0x81, 0x25, 0x45,
|
||||
0xcc, 0xae, 0x42, 0x13, 0x77, 0xfc, 0x92, 0x3f, 0xaf, 0x0f, 0x00, 0x90, 0xce, 0x23, 0x0a, 0x34,
|
||||
0x91, 0x94, 0x18, 0x28, 0xbc, 0x3f, 0x95, 0x16, 0x28, 0x9c, 0x1b, 0xdd, 0xdd, 0x92, 0x4f, 0x50,
|
||||
0x42, 0xdd, 0xbf, 0x70, 0x60, 0xd9, 0x6a, 0x03, 0xa3, 0xb8, 0xd0, 0xcf, 0x72, 0x99, 0x54, 0x95,
|
||||
0xcb, 0x63, 0x42, 0x66, 0x32, 0xb0, 0x61, 0x27, 0x03, 0x75, 0x9a, 0x6a, 0xce, 0x4c, 0x53, 0x5d,
|
||||
0x87, 0x56, 0x71, 0xee, 0xde, 0xb4, 0x4c, 0x1f, 0xb6, 0xa8, 0x8e, 0x36, 0x0a, 0x22, 0xe4, 0x33,
|
||||
0x8c, 0xc3, 0x38, 0x95, 0xc7, 0xd2, 0xa2, 0xe0, 0xde, 0x80, 0xb6, 0x41, 0x8f, 0xdd, 0x88, 0x78,
|
||||
0x7e, 0x12, 0xa7, 0x4f, 0x55, 0x4e, 0x52, 0x16, 0xf5, 0x09, 0x5e, 0xa3, 0x38, 0xc1, 0x73, 0xff,
|
||||
0xd2, 0x81, 0x65, 0x94, 0xc1, 0x20, 0x1a, 0xef, 0xc5, 0x61, 0x30, 0x9c, 0xd1, 0xda, 0x2b, 0x71,
|
||||
0x93, 0xe7, 0xd5, 0x4a, 0x16, 0x6d, 0x18, 0x65, 0x5b, 0x05, 0x71, 0x52, 0x11, 0x75, 0x19, 0x35,
|
||||
0x15, 0xe5, 0xfc, 0xc0, 0xcf, 0xa4, 0xf0, 0xcb, 0xbd, 0xc8, 0x02, 0x51, 0x9f, 0x10, 0x48, 0xfd,
|
||||
0x9c, 0x0f, 0x26, 0x41, 0x18, 0x06, 0x82, 0x56, 0x78, 0x2a, 0x75, 0x55, 0xee, 0x0f, 0x1a, 0xd0,
|
||||
0x96, 0x96, 0xf2, 0xee, 0x68, 0x2c, 0xb2, 0xff, 0xd2, 0xdf, 0xd3, 0xe6, 0xc2, 0x40, 0x54, 0xbd,
|
||||
0xe5, 0x21, 0x1a, 0x48, 0x79, 0x59, 0xe7, 0xaa, 0xcb, 0x7a, 0x11, 0x5a, 0x28, 0x5e, 0x6f, 0x93,
|
||||
0x2b, 0x2a, 0xae, 0x69, 0x14, 0x80, 0xaa, 0xdd, 0xa1, 0xda, 0xf9, 0xa2, 0x96, 0x00, 0xcb, 0xf9,
|
||||
0x5c, 0x28, 0x39, 0x9f, 0xef, 0x42, 0x47, 0xb2, 0xa1, 0x79, 0x27, 0xeb, 0x50, 0x08, 0xb8, 0xb5,
|
||||
0x26, 0x9e, 0x45, 0xa9, 0xbe, 0xdc, 0x51, 0x5f, 0x2e, 0xbd, 0xec, 0x4b, 0x45, 0x49, 0x87, 0x61,
|
||||
0x62, 0x6e, 0xee, 0xa7, 0x7e, 0x72, 0xa4, 0x76, 0x9f, 0x91, 0x3e, 0xe1, 0x27, 0x98, 0x6d, 0xc1,
|
||||
0x3c, 0x7e, 0xa6, 0xac, 0x75, 0xbd, 0xd2, 0x09, 0x12, 0x76, 0x15, 0xe6, 0xf9, 0x68, 0xcc, 0x55,
|
||||
0xb0, 0xc5, 0xec, 0xb0, 0x17, 0xd7, 0xc8, 0x13, 0x04, 0x68, 0x02, 0x10, 0x2d, 0x99, 0x00, 0xdb,
|
||||
0xd2, 0x2f, 0x60, 0xf1, 0xfd, 0x91, 0xbb, 0x01, 0xec, 0xa1, 0x90, 0x5a, 0x33, 0x59, 0xfc, 0x3b,
|
||||
0x73, 0xd0, 0x36, 0x60, 0xd4, 0xe6, 0x31, 0x76, 0x78, 0x30, 0x0a, 0xfc, 0x09, 0xcf, 0x79, 0x2a,
|
||||
0x25, 0xb5, 0x84, 0x22, 0x9d, 0x7f, 0x3c, 0x1e, 0xc4, 0xd3, 0x7c, 0x30, 0xe2, 0xe3, 0x94, 0x8b,
|
||||
0x3d, 0x12, 0x37, 0x03, 0x0b, 0x45, 0xba, 0x89, 0xff, 0xcc, 0xa4, 0x13, 0xf2, 0x50, 0x42, 0x55,
|
||||
0xea, 0x57, 0xcc, 0x51, 0xb3, 0x48, 0xfd, 0x8a, 0x19, 0x29, 0xdb, 0xa1, 0xf9, 0x1a, 0x3b, 0xf4,
|
||||
0x0e, 0x6c, 0x0a, 0x8b, 0x23, 0x75, 0x73, 0x50, 0x12, 0x93, 0x53, 0x6a, 0xd9, 0x16, 0xac, 0x62,
|
||||
0x9f, 0x95, 0x80, 0x67, 0xc1, 0xc7, 0x22, 0x19, 0xe3, 0x78, 0x15, 0x1c, 0x69, 0x51, 0x1d, 0x2d,
|
||||
0x5a, 0x71, 0x3c, 0x56, 0xc1, 0x89, 0xd6, 0x7f, 0x66, 0xd3, 0xb6, 0x24, 0x6d, 0x09, 0x77, 0x97,
|
||||
0xa1, 0xbd, 0x9f, 0xc7, 0x89, 0x5a, 0x94, 0x2e, 0x74, 0x44, 0x51, 0x1e, 0x86, 0x5e, 0x80, 0xf3,
|
||||
0x24, 0x45, 0x8f, 0xe2, 0x24, 0x0e, 0xe3, 0xf1, 0x6c, 0x7f, 0x7a, 0x90, 0x0d, 0xd3, 0x20, 0xc1,
|
||||
0xc0, 0xc4, 0xfd, 0x3b, 0x07, 0xd6, 0xad, 0x5a, 0x99, 0xbd, 0xf9, 0xbc, 0x10, 0x69, 0x7d, 0x8a,
|
||||
0x25, 0x04, 0x6f, 0xcd, 0x30, 0x87, 0x82, 0x50, 0xe4, 0xcd, 0x1e, 0xcb, 0x83, 0xad, 0x9b, 0xb0,
|
||||
0xa2, 0x7a, 0xa6, 0x3e, 0x14, 0x52, 0xd8, 0xab, 0x4a, 0xa1, 0xfc, 0xbe, 0x2b, 0x3f, 0x50, 0x2c,
|
||||
0x7e, 0x51, 0xf8, 0xd5, 0x7c, 0x44, 0x63, 0x54, 0x61, 0x7c, 0x5f, 0x7d, 0x6f, 0x3a, 0xf3, 0xaa,
|
||||
0x07, 0x43, 0x0d, 0x66, 0xee, 0xef, 0x3b, 0x00, 0x45, 0xef, 0x50, 0x30, 0x0a, 0x93, 0x2e, 0xee,
|
||||
0xe7, 0x19, 0xe6, 0xfb, 0x0d, 0xe8, 0xe8, 0x03, 0x8c, 0x62, 0x97, 0x68, 0x2b, 0x0c, 0x1d, 0xae,
|
||||
0x2b, 0xb0, 0x32, 0x0e, 0xe3, 0x03, 0xda, 0x62, 0xe9, 0x74, 0x3d, 0x93, 0x47, 0xc2, 0x5d, 0x01,
|
||||
0xdf, 0x93, 0x68, 0xb1, 0xa5, 0x34, 0x8d, 0x2d, 0xc5, 0xfd, 0x4e, 0x43, 0xa7, 0xbd, 0x8b, 0x31,
|
||||
0x9f, 0xaa, 0x65, 0x6c, 0xa7, 0x62, 0x1c, 0x4f, 0xc9, 0x32, 0x53, 0xc2, 0x6a, 0xef, 0xa5, 0xf1,
|
||||
0xf4, 0x0d, 0xe8, 0xa6, 0xc2, 0xfa, 0x28, 0xd3, 0xd4, 0x7c, 0x81, 0x69, 0x5a, 0x4e, 0xad, 0x7d,
|
||||
0xe7, 0xff, 0xc1, 0xaa, 0x3f, 0x3a, 0xe6, 0x69, 0x1e, 0x50, 0x44, 0x43, 0x9b, 0xbe, 0x30, 0xa8,
|
||||
0x2b, 0x06, 0x4e, 0x7b, 0xf1, 0x15, 0x58, 0x91, 0xc7, 0xf0, 0x9a, 0x52, 0x5e, 0xbe, 0x2a, 0x60,
|
||||
0x24, 0x74, 0xbf, 0xaf, 0x32, 0xec, 0xf6, 0x1a, 0x9e, 0x3e, 0x23, 0xe6, 0xe8, 0x1a, 0xa5, 0xd1,
|
||||
0x7d, 0x46, 0x66, 0xbb, 0x47, 0x2a, 0x6c, 0x92, 0xe7, 0x0e, 0x02, 0x94, 0xa7, 0x13, 0xf6, 0x94,
|
||||
0x36, 0x5f, 0x65, 0x4a, 0xdd, 0x4f, 0x1d, 0x58, 0xdc, 0x8d, 0x93, 0x5d, 0x79, 0xa2, 0x4e, 0x8a,
|
||||
0xa0, 0x2f, 0xb9, 0xa8, 0xa2, 0xe9, 0x15, 0x37, 0x2a, 0x5e, 0x71, 0x75, 0xaf, 0x5d, 0x2e, 0xef,
|
||||
0xb5, 0xbf, 0x04, 0x17, 0x28, 0x68, 0x4f, 0xe3, 0x24, 0x4e, 0x51, 0x19, 0xfd, 0x50, 0x6c, 0xac,
|
||||
0x71, 0x94, 0x1f, 0x29, 0x33, 0xf6, 0x22, 0x12, 0x8a, 0x8e, 0xc2, 0xfc, 0x78, 0x20, 0x9c, 0x61,
|
||||
0xe9, 0x1b, 0x08, 0xeb, 0x56, 0xad, 0x70, 0xbf, 0x08, 0x2d, 0x72, 0x6e, 0x69, 0x58, 0x6f, 0x41,
|
||||
0xeb, 0x28, 0x4e, 0x06, 0x47, 0x41, 0x94, 0x2b, 0xe5, 0xee, 0x16, 0x5e, 0xe7, 0x2e, 0x4d, 0x88,
|
||||
0x26, 0x70, 0x7f, 0x34, 0x07, 0x8b, 0xef, 0x47, 0xc7, 0x71, 0x30, 0xa4, 0x64, 0xfc, 0x84, 0x4f,
|
||||
0x62, 0x75, 0xe5, 0x07, 0x7f, 0xe3, 0x54, 0xd0, 0xf1, 0x77, 0x92, 0xcb, 0x6c, 0xba, 0x2a, 0xe2,
|
||||
0x76, 0x9f, 0x16, 0xd7, 0xe0, 0x84, 0xea, 0x18, 0x08, 0x3a, 0xf6, 0xa9, 0x79, 0x07, 0x50, 0x96,
|
||||
0x8a, 0x3b, 0x53, 0xf3, 0xc6, 0x9d, 0x29, 0x3a, 0xba, 0x11, 0x27, 0xfb, 0x24, 0x5f, 0x4b, 0x9e,
|
||||
0x2a, 0x52, 0x20, 0x92, 0x72, 0x91, 0x6c, 0x21, 0xc7, 0x61, 0x51, 0x06, 0x22, 0x26, 0x88, 0xce,
|
||||
0x85, 0xf8, 0x40, 0xd0, 0x08, 0xe3, 0x6b, 0x42, 0xe8, 0x6c, 0x95, 0xaf, 0x11, 0xb6, 0x84, 0xcc,
|
||||
0x97, 0x60, 0xb4, 0xd0, 0x23, 0xae, 0x0d, 0xa9, 0x18, 0x03, 0x88, 0x6b, 0x7e, 0x65, 0xdc, 0x08,
|
||||
0x5f, 0xc4, 0x0d, 0x05, 0x15, 0xbe, 0xa0, 0xa0, 0xf8, 0x61, 0x78, 0xe0, 0x0f, 0x9f, 0xd2, 0xe5,
|
||||
0x4e, 0xba, 0x90, 0xd0, 0xf2, 0x6c, 0x10, 0x7b, 0x6d, 0xac, 0x26, 0x1d, 0xfe, 0x35, 0x3d, 0x13,
|
||||
0x62, 0x3b, 0xd0, 0xa6, 0x90, 0x4d, 0xae, 0x67, 0x97, 0xd6, 0x73, 0xd5, 0x8c, 0xe9, 0x68, 0x45,
|
||||
0x4d, 0x22, 0xf3, 0x80, 0x60, 0xc5, 0xbe, 0x33, 0xf0, 0x0d, 0x60, 0x37, 0x47, 0x23, 0xb9, 0xde,
|
||||
0x3a, 0x64, 0x2c, 0x56, 0xca, 0xb1, 0x56, 0xaa, 0x66, 0xc6, 0x1a, 0xb5, 0x33, 0xe6, 0xde, 0x85,
|
||||
0xf6, 0x9e, 0x71, 0xc3, 0x93, 0x44, 0x43, 0xdd, 0xed, 0x94, 0xe2, 0x64, 0x20, 0x46, 0x83, 0x0d,
|
||||
0xb3, 0x41, 0xf7, 0xe7, 0x81, 0x3d, 0x08, 0xb2, 0x5c, 0xf7, 0x4f, 0x2c, 0xc7, 0x1b, 0xd0, 0xd1,
|
||||
0x01, 0x76, 0x71, 0xa3, 0xa1, 0x2d, 0x31, 0xba, 0x69, 0x70, 0x53, 0x5c, 0x85, 0x28, 0x0f, 0x6c,
|
||||
0x0b, 0x96, 0x02, 0x01, 0x95, 0x35, 0x41, 0x51, 0xea, 0x7a, 0xf4, 0xd7, 0x24, 0x68, 0xed, 0xa2,
|
||||
0x3f, 0x70, 0x60, 0x51, 0x0e, 0x0d, 0xbd, 0x0d, 0xeb, 0x6e, 0xab, 0x18, 0x98, 0x85, 0xd5, 0xdf,
|
||||
0x08, 0xac, 0xca, 0xf0, 0x5c, 0x9d, 0x0c, 0x33, 0x68, 0x26, 0x7e, 0x7e, 0x44, 0x01, 0x4a, 0xcb,
|
||||
0xa3, 0xdf, 0x6c, 0x55, 0x04, 0xcd, 0x42, 0x57, 0x28, 0x60, 0xae, 0xbb, 0x84, 0x2a, 0x4c, 0x72,
|
||||
0x05, 0xc7, 0x41, 0xd1, 0xe5, 0x01, 0x81, 0xeb, 0x33, 0x01, 0x79, 0x31, 0xa3, 0x80, 0x8b, 0xf9,
|
||||
0x92, 0x2c, 0xca, 0xf3, 0x25, 0x49, 0x3d, 0x5d, 0xef, 0xf6, 0xa1, 0x77, 0x87, 0x87, 0x3c, 0xe7,
|
||||
0x37, 0xc3, 0xb0, 0xcc, 0xff, 0x02, 0x9c, 0xaf, 0xa9, 0x93, 0x4e, 0xcb, 0x3d, 0x58, 0xbb, 0xc3,
|
||||
0x0f, 0xa6, 0xe3, 0x07, 0xfc, 0xb8, 0x38, 0xb8, 0x63, 0xd0, 0xcc, 0x8e, 0xe2, 0x13, 0xb9, 0xb6,
|
||||
0xf4, 0x9b, 0xbd, 0x06, 0x10, 0x22, 0xcd, 0x20, 0x4b, 0xf8, 0x50, 0xdd, 0x85, 0x23, 0x64, 0x3f,
|
||||
0xe1, 0x43, 0xf7, 0x1d, 0x60, 0x26, 0x1f, 0x39, 0x04, 0xb4, 0x03, 0xd3, 0x83, 0x41, 0x36, 0xcb,
|
||||
0x72, 0x3e, 0x51, 0x97, 0xfc, 0x4c, 0xc8, 0xbd, 0x02, 0x9d, 0x3d, 0x7f, 0xe6, 0xf1, 0x8f, 0xe4,
|
||||
0xf5, 0x62, 0x8c, 0x8d, 0xfd, 0x19, 0x8a, 0xb2, 0x8e, 0x8d, 0xa9, 0xda, 0xfd, 0x8f, 0x06, 0x2c,
|
||||
0x08, 0x4a, 0xe4, 0x3a, 0xe2, 0x59, 0x1e, 0x44, 0xe2, 0xd0, 0x4a, 0x72, 0x35, 0xa0, 0x8a, 0x6c,
|
||||
0x34, 0x6a, 0x64, 0x43, 0x7a, 0xab, 0xea, 0x5e, 0x91, 0x14, 0x02, 0x0b, 0x43, 0xb7, 0xa6, 0xb8,
|
||||
0x0c, 0x20, 0x82, 0xb3, 0x02, 0x28, 0x25, 0x4b, 0x0a, 0x6b, 0x23, 0xfa, 0xa7, 0x84, 0x56, 0x8a,
|
||||
0x83, 0x09, 0xd5, 0xda, 0xb4, 0x45, 0x21, 0x35, 0x15, 0x9b, 0x56, 0xb1, 0x5d, 0x4b, 0xaf, 0x60,
|
||||
0xbb, 0x84, 0x0b, 0xfb, 0x22, 0xdb, 0x05, 0xaf, 0x60, 0xbb, 0x5c, 0x06, 0xab, 0xf7, 0x38, 0xf7,
|
||||
0x38, 0xee, 0x8a, 0x4a, 0x9c, 0xbe, 0xeb, 0xc0, 0xaa, 0xdc, 0xd0, 0x75, 0x1d, 0x7b, 0xc3, 0xda,
|
||||
0xfd, 0x9d, 0xba, 0xf3, 0x88, 0x37, 0x61, 0x99, 0xf6, 0x64, 0x9d, 0x15, 0x92, 0x29, 0x2c, 0x0b,
|
||||
0xc4, 0x71, 0xa8, 0x0c, 0xfb, 0x24, 0x08, 0xe5, 0xa2, 0x98, 0x90, 0x4a, 0x2c, 0x61, 0x7c, 0x4c,
|
||||
0x4b, 0xe2, 0x78, 0xba, 0xec, 0xfe, 0xb5, 0x03, 0x6b, 0x46, 0x87, 0xa5, 0x14, 0xde, 0x00, 0x75,
|
||||
0x59, 0x40, 0x24, 0x8f, 0x84, 0x32, 0x9d, 0xb3, 0x9d, 0x93, 0xe2, 0x33, 0x8b, 0x98, 0x16, 0xd3,
|
||||
0x9f, 0x51, 0x07, 0xb3, 0xe9, 0x44, 0x7a, 0x20, 0x26, 0x84, 0x82, 0x74, 0xc2, 0xf9, 0x53, 0x4d,
|
||||
0x32, 0x47, 0x24, 0x16, 0x46, 0x67, 0xc1, 0xe8, 0x4b, 0x68, 0x22, 0x71, 0xfd, 0xc9, 0x06, 0xdd,
|
||||
0x7f, 0x70, 0x60, 0x5d, 0x38, 0x85, 0xd2, 0xe5, 0xd6, 0x57, 0x33, 0x17, 0x84, 0x17, 0x2c, 0x34,
|
||||
0x72, 0xf7, 0x8c, 0x27, 0xcb, 0xec, 0x0b, 0xaf, 0xe8, 0xc8, 0xea, 0x3b, 0x00, 0xa7, 0xac, 0xc5,
|
||||
0x5c, 0xdd, 0x5a, 0xbc, 0x60, 0xa6, 0xeb, 0x92, 0x25, 0xf3, 0xb5, 0xc9, 0x92, 0x5b, 0x8b, 0x30,
|
||||
0x9f, 0x0d, 0xe3, 0x84, 0xbb, 0x9b, 0xb0, 0x61, 0x0f, 0x4e, 0x9a, 0xa0, 0xef, 0x39, 0xd0, 0xbb,
|
||||
0x27, 0x52, 0x87, 0x41, 0x34, 0xde, 0x0d, 0xb2, 0x3c, 0x4e, 0xf5, 0x5d, 0xf4, 0x4b, 0x00, 0x59,
|
||||
0xee, 0xa7, 0xb9, 0xb8, 0xa3, 0x25, 0xd3, 0x1c, 0x05, 0x82, 0x7d, 0xe4, 0xd1, 0x48, 0xd4, 0x8a,
|
||||
0xb5, 0xd1, 0x65, 0x5c, 0x18, 0xba, 0x9f, 0x30, 0x88, 0x0f, 0x0f, 0x33, 0xae, 0xdd, 0x56, 0x13,
|
||||
0xc3, 0xc8, 0x17, 0x35, 0x1e, 0x63, 0x3d, 0x7e, 0x4c, 0xa6, 0x56, 0xf8, 0x83, 0x25, 0xd4, 0xfd,
|
||||
0x2b, 0x07, 0x56, 0x8a, 0x4e, 0xde, 0x45, 0xd0, 0xb6, 0x0e, 0xa2, 0x6b, 0x86, 0x75, 0x50, 0x09,
|
||||
0x98, 0x60, 0x34, 0x08, 0x22, 0xd9, 0x37, 0x03, 0x21, 0x8d, 0x95, 0xa5, 0x78, 0xaa, 0xee, 0xc3,
|
||||
0x99, 0x90, 0x38, 0xec, 0xce, 0xf1, 0x6b, 0x71, 0x19, 0x4e, 0x96, 0xe8, 0x8a, 0xdd, 0x24, 0xa7,
|
||||
0xaf, 0x16, 0x84, 0x43, 0x2c, 0x8b, 0x6a, 0x7f, 0x5a, 0x24, 0x14, 0x7f, 0xba, 0x7f, 0xe0, 0xc0,
|
||||
0xf9, 0x9a, 0xc9, 0x95, 0x9a, 0x71, 0x07, 0xd6, 0x0e, 0x75, 0xa5, 0x9a, 0x00, 0xa1, 0x1e, 0x9b,
|
||||
0x52, 0x8a, 0x4a, 0x83, 0xf6, 0xaa, 0x1f, 0xa0, 0x7b, 0x4c, 0x79, 0x23, 0x31, 0xa5, 0xd6, 0x3d,
|
||||
0x91, 0x6a, 0xc5, 0xce, 0xf7, 0x1b, 0xd0, 0x15, 0x47, 0x15, 0xe2, 0x35, 0x12, 0x4f, 0xd9, 0x07,
|
||||
0xb0, 0x28, 0xdf, 0x7e, 0xb1, 0xb3, 0xb2, 0x59, 0xfb, 0xb5, 0x59, 0x7f, 0xb3, 0x0c, 0x4b, 0xd9,
|
||||
0x59, 0xff, 0xed, 0x4f, 0xff, 0xf9, 0x0f, 0x1b, 0xcb, 0xac, 0xbd, 0x7d, 0xfc, 0xf6, 0xf6, 0x98,
|
||||
0x47, 0x19, 0xf2, 0xf8, 0x55, 0x80, 0xe2, 0xf9, 0x14, 0xeb, 0x69, 0x27, 0xa3, 0xf4, 0xdc, 0xab,
|
||||
0x7f, 0xbe, 0xa6, 0x46, 0xf2, 0x3d, 0x4f, 0x7c, 0xd7, 0xdd, 0x2e, 0xf2, 0x0d, 0xa2, 0x20, 0x17,
|
||||
0x6f, 0xa9, 0xde, 0x73, 0xb6, 0xd8, 0x08, 0x3a, 0xe6, 0x33, 0x2a, 0xa6, 0x42, 0xe6, 0x9a, 0xb7,
|
||||
0x59, 0xfd, 0x0b, 0xb5, 0x75, 0x2a, 0x5f, 0x40, 0x6d, 0x9c, 0x75, 0x57, 0xb1, 0x8d, 0x29, 0x51,
|
||||
0xe8, 0x56, 0x76, 0xfe, 0xf1, 0x02, 0xb4, 0x74, 0xda, 0x89, 0x7d, 0x08, 0xcb, 0xd6, 0xe9, 0x0e,
|
||||
0x53, 0x8c, 0xeb, 0x0e, 0x83, 0xfa, 0x17, 0xeb, 0x2b, 0x65, 0xb3, 0x97, 0xa8, 0xd9, 0x1e, 0xdb,
|
||||
0xc4, 0x66, 0xe5, 0xf1, 0xc8, 0x36, 0x9d, 0x69, 0x89, 0x2b, 0x75, 0x4f, 0xa1, 0x6b, 0x9f, 0xc8,
|
||||
0xb0, 0x8b, 0xb6, 0x41, 0x29, 0xb5, 0xf6, 0xda, 0x29, 0xb5, 0xb2, 0xb9, 0x8b, 0xd4, 0xdc, 0x26,
|
||||
0xdb, 0x30, 0x9b, 0xd3, 0xe9, 0x20, 0x4e, 0x97, 0x20, 0xcd, 0xf7, 0x55, 0xec, 0x35, 0xbd, 0xd4,
|
||||
0x75, 0xef, 0xae, 0xf4, 0xa2, 0x55, 0x1f, 0x5f, 0xb9, 0x3d, 0x6a, 0x8a, 0x31, 0x9a, 0x50, 0xf3,
|
||||
0x79, 0x15, 0xfb, 0x16, 0xb4, 0xf4, 0x9b, 0x0a, 0x76, 0xce, 0x78, 0xc8, 0x62, 0x3e, 0xf4, 0xe8,
|
||||
0xf7, 0xaa, 0x15, 0x75, 0x4b, 0x65, 0x72, 0x46, 0x81, 0x78, 0x00, 0x67, 0xa5, 0x93, 0x7a, 0xc0,
|
||||
0x7f, 0x9c, 0x91, 0xd4, 0xbc, 0x0a, 0xbb, 0xee, 0xb0, 0x1b, 0xb0, 0xa4, 0x9e, 0xaa, 0xb0, 0xcd,
|
||||
0xfa, 0x27, 0x37, 0xfd, 0x73, 0x15, 0x5c, 0xea, 0xf3, 0x4d, 0x80, 0xe2, 0x99, 0x85, 0x96, 0xfc,
|
||||
0xca, 0xe3, 0x0f, 0x3d, 0x89, 0x35, 0x6f, 0x32, 0xc6, 0xf4, 0xa8, 0xc4, 0x7e, 0xc5, 0xc1, 0x5e,
|
||||
0x2f, 0xe8, 0x6b, 0xdf, 0x77, 0xbc, 0x80, 0xa1, 0xbb, 0x49, 0x73, 0xb7, 0xca, 0x48, 0x95, 0x22,
|
||||
0x7e, 0xa2, 0xae, 0x03, 0xdf, 0x81, 0xb6, 0xf1, 0x74, 0x83, 0x29, 0x0e, 0xd5, 0x67, 0x1f, 0xfd,
|
||||
0x7e, 0x5d, 0x95, 0xec, 0xee, 0x57, 0x60, 0xd9, 0x7a, 0x83, 0xa1, 0x35, 0xa3, 0xee, 0x85, 0x87,
|
||||
0xd6, 0x8c, 0xfa, 0x67, 0x1b, 0xdf, 0x84, 0xb6, 0xf1, 0x62, 0x82, 0x19, 0xd7, 0xa0, 0x4a, 0x6f,
|
||||
0x25, 0x74, 0x8f, 0xea, 0x1e, 0x58, 0x6c, 0xd0, 0x78, 0xbb, 0x6e, 0x0b, 0xc7, 0x4b, 0x77, 0x62,
|
||||
0x51, 0x48, 0x3e, 0x84, 0xae, 0xfd, 0x86, 0x42, 0x6b, 0x55, 0xed, 0x6b, 0x0c, 0xad, 0x55, 0xa7,
|
||||
0x3c, 0xbc, 0x90, 0x02, 0xb9, 0xb5, 0xae, 0x1b, 0xd9, 0xfe, 0x44, 0x1e, 0xba, 0x3c, 0x67, 0x5f,
|
||||
0x47, 0xd3, 0x21, 0x2f, 0x29, 0xb3, 0xe2, 0xe5, 0x88, 0x7d, 0x95, 0x59, 0x4b, 0x7b, 0xe5, 0x3e,
|
||||
0xb3, 0xbb, 0x46, 0xcc, 0xdb, 0xac, 0x18, 0x81, 0xb0, 0xd0, 0x74, 0x59, 0xd9, 0xb0, 0xd0, 0xe6,
|
||||
0x7d, 0x66, 0xc3, 0x42, 0x5b, 0x77, 0x9a, 0xcb, 0x16, 0x3a, 0x0f, 0x90, 0x47, 0x04, 0x2b, 0xa5,
|
||||
0x7b, 0x00, 0x5a, 0x59, 0xea, 0x2f, 0x4e, 0xf5, 0x2f, 0xbd, 0xf8, 0xfa, 0x80, 0x6d, 0x66, 0x94,
|
||||
0x79, 0xd9, 0x56, 0xf7, 0xdc, 0x7e, 0x0d, 0x3a, 0xe6, 0xdd, 0x77, 0x6d, 0xb3, 0x6b, 0x6e, 0xec,
|
||||
0x6b, 0x9b, 0x5d, 0x77, 0x59, 0x5e, 0x2d, 0x2e, 0xeb, 0x98, 0xcd, 0xb0, 0x6f, 0xc2, 0x8a, 0x71,
|
||||
0xf1, 0x65, 0x7f, 0x16, 0x0d, 0xb5, 0xf0, 0x54, 0xaf, 0x45, 0xf6, 0xeb, 0xfc, 0x33, 0xf7, 0x1c,
|
||||
0x31, 0x5e, 0x73, 0x2d, 0xc6, 0x28, 0x38, 0xb7, 0xa1, 0x6d, 0x5e, 0xaa, 0x79, 0x01, 0xdf, 0x73,
|
||||
0x46, 0x95, 0x79, 0x43, 0xf0, 0xba, 0xc3, 0xfe, 0xd8, 0x81, 0x8e, 0x75, 0x45, 0xc5, 0xca, 0xf3,
|
||||
0x96, 0xf8, 0xf4, 0xcc, 0x3a, 0x93, 0x91, 0xeb, 0x51, 0x27, 0x1f, 0x6c, 0x7d, 0xc5, 0x9a, 0xe4,
|
||||
0x4f, 0x2c, 0x3f, 0xff, 0x5a, 0xf9, 0x59, 0xe3, 0xf3, 0x32, 0x81, 0x79, 0x75, 0xf4, 0xf9, 0x75,
|
||||
0x87, 0xbd, 0x27, 0x9e, 0xbe, 0xaa, 0xb8, 0x9e, 0x19, 0xc6, 0xad, 0x3c, 0x65, 0xe6, 0x2b, 0xd1,
|
||||
0xab, 0xce, 0x75, 0x87, 0x7d, 0x5b, 0xbc, 0x5e, 0x94, 0xdf, 0xd2, 0xcc, 0xbf, 0xea, 0xf7, 0xee,
|
||||
0x9b, 0x34, 0x9a, 0x4b, 0xee, 0x79, 0x6b, 0x34, 0x65, 0xeb, 0xbe, 0x07, 0x50, 0x24, 0x69, 0x58,
|
||||
0x29, 0x63, 0xa1, 0xed, 0x5e, 0x35, 0x8f, 0x63, 0xaf, 0xa8, 0x4a, 0x6c, 0x20, 0xc7, 0x6f, 0x09,
|
||||
0x61, 0x94, 0xf4, 0x99, 0x5e, 0xd2, 0x6a, 0xb2, 0xa5, 0xdf, 0xaf, 0xab, 0xaa, 0x13, 0x45, 0xc5,
|
||||
0x9f, 0x3d, 0x86, 0xe5, 0x07, 0x71, 0xfc, 0x74, 0x9a, 0xe8, 0x34, 0xa2, 0x9d, 0x33, 0xd8, 0xf5,
|
||||
0xb3, 0xa3, 0x7e, 0x69, 0x14, 0xee, 0x65, 0x62, 0xd5, 0x67, 0x3d, 0x83, 0xd5, 0xf6, 0x27, 0x45,
|
||||
0x8a, 0xe8, 0x39, 0xf3, 0x61, 0x4d, 0xef, 0x71, 0xba, 0xe3, 0x7d, 0x9b, 0x8d, 0x99, 0xa9, 0xa9,
|
||||
0x34, 0x61, 0x79, 0x1d, 0xaa, 0xb7, 0xdb, 0x99, 0xe2, 0x79, 0xdd, 0x61, 0x7b, 0xd0, 0xb9, 0xc3,
|
||||
0x87, 0xf1, 0x88, 0xcb, 0x28, 0x7f, 0xbd, 0xe8, 0xb8, 0x4e, 0x0f, 0xf4, 0x97, 0x2d, 0xd0, 0xd6,
|
||||
0xfa, 0xc4, 0x9f, 0xa5, 0xfc, 0xa3, 0xed, 0x4f, 0x64, 0xfe, 0xe0, 0xb9, 0xd2, 0x7a, 0x95, 0xf3,
|
||||
0xb0, 0xb4, 0xbe, 0x94, 0x24, 0xb1, 0xb4, 0xbe, 0x92, 0x24, 0xb1, 0xa6, 0x5a, 0xe5, 0x5c, 0x58,
|
||||
0x08, 0x6b, 0x95, 0xbc, 0x8a, 0xde, 0x29, 0x4f, 0xcb, 0xc6, 0xf4, 0x2f, 0x9f, 0x4e, 0x60, 0xb7,
|
||||
0xb6, 0x65, 0xb7, 0xb6, 0x0f, 0xcb, 0x77, 0xb8, 0x98, 0x2c, 0x71, 0x56, 0xd9, 0xb7, 0xcd, 0x88,
|
||||
0x79, 0xae, 0x59, 0x36, 0x31, 0x54, 0x67, 0x9b, 0x75, 0x3a, 0x28, 0x64, 0xdf, 0x82, 0xf6, 0x7d,
|
||||
0x9e, 0xab, 0xc3, 0x49, 0xed, 0x6f, 0x94, 0x4e, 0x2b, 0xfb, 0x35, 0x67, 0x9b, 0xb6, 0xcc, 0x10,
|
||||
0xb7, 0x6d, 0x3e, 0x1a, 0x73, 0xa1, 0xec, 0x83, 0x60, 0xf4, 0x9c, 0xfd, 0x32, 0x31, 0xd7, 0xf7,
|
||||
0x19, 0x36, 0x8d, 0x33, 0x2d, 0x93, 0xf9, 0x4a, 0x09, 0xaf, 0xe3, 0x1c, 0xc5, 0x23, 0x6e, 0x6c,
|
||||
0x70, 0x11, 0xb4, 0x8d, 0xcb, 0x36, 0x5a, 0x81, 0xaa, 0x17, 0x7c, 0xb4, 0x02, 0xd5, 0xdc, 0xcd,
|
||||
0x71, 0xaf, 0x52, 0x3b, 0x2e, 0xbb, 0x5c, 0xb4, 0x23, 0xee, 0xe3, 0x14, 0x2d, 0x6d, 0x7f, 0xe2,
|
||||
0x4f, 0xf2, 0xe7, 0xec, 0x09, 0xbd, 0xde, 0x31, 0x0f, 0x60, 0x0b, 0x7f, 0xa7, 0x7c, 0x56, 0xab,
|
||||
0x27, 0xcb, 0xa8, 0xb2, 0x7d, 0x20, 0xd1, 0x14, 0xed, 0x83, 0x5f, 0x00, 0xd8, 0xcf, 0xe3, 0xe4,
|
||||
0x8e, 0xcf, 0x27, 0x71, 0x54, 0x58, 0xae, 0xe2, 0x90, 0xb1, 0xb0, 0x5c, 0xc6, 0x49, 0x23, 0x7b,
|
||||
0x62, 0x78, 0x9c, 0xd6, 0xf9, 0xb5, 0x12, 0xae, 0x53, 0xcf, 0x21, 0xf5, 0x84, 0xd4, 0x9c, 0x45,
|
||||
0x5e, 0x77, 0xd0, 0x7f, 0x2c, 0xb2, 0x78, 0xda, 0x7f, 0xac, 0x24, 0x08, 0xb5, 0xd9, 0xab, 0x49,
|
||||
0xf9, 0xed, 0x41, 0xab, 0x48, 0x0b, 0xa9, 0x2d, 0xa9, 0x9c, 0x44, 0xd2, 0x7b, 0x4c, 0x25, 0x59,
|
||||
0xe3, 0xae, 0xd2, 0x54, 0x01, 0x5b, 0xc2, 0xa9, 0xa2, 0x0c, 0x4c, 0x00, 0xeb, 0xa2, 0x83, 0x7a,
|
||||
0xc3, 0xa4, 0x63, 0x33, 0x35, 0x92, 0x9a, 0x84, 0x89, 0xd6, 0xe6, 0xda, 0x7c, 0x83, 0x15, 0xdb,
|
||||
0xa1, 0xb4, 0x8a, 0x23, 0x3b, 0x34, 0xcd, 0x13, 0x58, 0xab, 0x04, 0xcb, 0x5a, 0xa5, 0x4f, 0xcb,
|
||||
0x51, 0x68, 0x95, 0x3e, 0x35, 0xce, 0x76, 0xcf, 0x52, 0x93, 0x2b, 0x2e, 0x60, 0x93, 0xd9, 0x49,
|
||||
0x90, 0x0f, 0x8f, 0xde, 0x73, 0xb6, 0x0e, 0x16, 0xe8, 0xcf, 0x55, 0x3e, 0xf7, 0x3f, 0x01, 0x00,
|
||||
0x00, 0xff, 0xff, 0x8f, 0xec, 0x5b, 0xef, 0x8e, 0x45, 0x00, 0x00,
|
||||
}
|
||||
|
@ -1063,6 +1063,14 @@ message PendingChannelsResponse {
|
||||
int64 fee_per_kw = 6 [ json_name = "fee_per_kw" ];
|
||||
}
|
||||
|
||||
message WaitingCloseChannel {
|
||||
/// The pending channel waiting for closing tx to confirm
|
||||
PendingChannel channel = 1;
|
||||
|
||||
/// The balance in satoshis encumbered in this channel
|
||||
int64 limbo_balance = 2 [ json_name = "limbo_balance" ];
|
||||
}
|
||||
|
||||
message ClosedChannel {
|
||||
/// The pending channel to be closed
|
||||
PendingChannel channel = 1;
|
||||
@ -1108,6 +1116,9 @@ message PendingChannelsResponse {
|
||||
|
||||
/// Channels pending force closing
|
||||
repeated ForceClosedChannel pending_force_closing_channels = 4 [ json_name = "pending_force_closing_channels" ];
|
||||
|
||||
/// Channels waiting for closing tx to confirm
|
||||
repeated WaitingCloseChannel waiting_close_channels = 5 [ json_name = "waiting_close_channels" ];
|
||||
}
|
||||
|
||||
message WalletBalanceRequest {
|
||||
|
@ -893,6 +893,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PendingChannelsResponseWaitingCloseChannel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"channel": {
|
||||
"$ref": "#/definitions/PendingChannelsResponsePendingChannel",
|
||||
"title": "/ The pending channel waiting for closing tx to confirm"
|
||||
},
|
||||
"limbo_balance": {
|
||||
"type": "string",
|
||||
"format": "int64",
|
||||
"title": "/ The balance in satoshis encumbered in this channel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lnrpcAddInvoiceResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -2035,6 +2049,13 @@
|
||||
"$ref": "#/definitions/PendingChannelsResponseForceClosedChannel"
|
||||
},
|
||||
"title": "/ Channels pending force closing"
|
||||
},
|
||||
"waiting_close_channels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PendingChannelsResponseWaitingCloseChannel"
|
||||
},
|
||||
"title": "/ Channels waiting for closing tx to confirm"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -770,6 +770,7 @@ func (n *NetworkHarness) CloseChannel(ctx context.Context,
|
||||
return func() bool {
|
||||
channel, err := filterChannel(node, chanPoint)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return channel.Active
|
||||
|
@ -4650,7 +4650,7 @@ type CommitOutputResolution struct {
|
||||
// had any outgoing HTLC's within the commitment transaction, then an
|
||||
// OutgoingHtlcResolution for each output will included.
|
||||
type UnilateralCloseSummary struct {
|
||||
// SpendDetail is a struct that describes how and when the commitment
|
||||
// SpendDetail is a struct that describes how and when the funding
|
||||
// output was spent.
|
||||
*chainntnfs.SpendDetail
|
||||
|
||||
@ -4754,7 +4754,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
RemotePub: chanState.IdentityPub,
|
||||
Capacity: chanState.Capacity,
|
||||
SettledBalance: localBalance,
|
||||
CloseType: channeldb.ForceClose,
|
||||
CloseType: channeldb.RemoteForceClose,
|
||||
IsPending: true,
|
||||
}
|
||||
|
||||
|
6
peer.go
6
peer.go
@ -329,9 +329,9 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error {
|
||||
|
||||
// Skip adding any permanently irreconcilable channels to the
|
||||
// htlcswitch.
|
||||
if dbChan.IsBorked {
|
||||
peerLog.Warnf("ChannelPoint(%v) is borked, won't "+
|
||||
"start.", chanPoint)
|
||||
if dbChan.ChanStatus != channeldb.Default {
|
||||
peerLog.Warnf("ChannelPoint(%v) has status %v, won't "+
|
||||
"start.", chanPoint, dbChan.ChanStatus)
|
||||
lnChan.Stop()
|
||||
continue
|
||||
}
|
||||
|
64
rpcserver.go
64
rpcserver.go
@ -1343,18 +1343,24 @@ func (r *rpcServer) WalletBalance(ctx context.Context,
|
||||
func (r *rpcServer) ChannelBalance(ctx context.Context,
|
||||
in *lnrpc.ChannelBalanceRequest) (*lnrpc.ChannelBalanceResponse, error) {
|
||||
|
||||
channels, err := r.server.chanDB.FetchAllChannels()
|
||||
openChannels, err := r.server.chanDB.FetchAllOpenChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pendingOpenBalance, balance btcutil.Amount
|
||||
for _, channel := range channels {
|
||||
if channel.IsPending {
|
||||
pendingOpenBalance += channel.LocalCommitment.LocalBalance.ToSatoshis()
|
||||
} else {
|
||||
balance += channel.LocalCommitment.LocalBalance.ToSatoshis()
|
||||
}
|
||||
var balance btcutil.Amount
|
||||
for _, channel := range openChannels {
|
||||
balance += channel.LocalCommitment.LocalBalance.ToSatoshis()
|
||||
}
|
||||
|
||||
pendingChannels, err := r.server.chanDB.FetchPendingChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pendingOpenBalance btcutil.Amount
|
||||
for _, channel := range pendingChannels {
|
||||
pendingOpenBalance += channel.LocalCommitment.LocalBalance.ToSatoshis()
|
||||
}
|
||||
|
||||
return &lnrpc.ChannelBalanceResponse{
|
||||
@ -1457,7 +1463,8 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
|
||||
|
||||
// If the channel was force closed, then we'll need to query
|
||||
// the utxoNursery for additional information.
|
||||
case channeldb.ForceClose:
|
||||
// TODO(halseth): distinguish remote and local case?
|
||||
case channeldb.LocalForceClose, channeldb.RemoteForceClose:
|
||||
forceClose := &lnrpc.PendingChannelsResponse_ForceClosedChannel{
|
||||
Channel: channel,
|
||||
ClosingTxid: closeTXID,
|
||||
@ -1522,6 +1529,39 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
// We'll also fetch all channels that are open, but have had their
|
||||
// commitment broadcasted, meaning they are waiting for the closing
|
||||
// transaction to confirm.
|
||||
waitingCloseChans, err := r.server.chanDB.FetchWaitingCloseChannels()
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("unable to fetch channels waiting close: %v",
|
||||
err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, waitingClose := range waitingCloseChans {
|
||||
pub := waitingClose.IdentityPub.SerializeCompressed()
|
||||
chanPoint := waitingClose.FundingOutpoint
|
||||
channel := &lnrpc.PendingChannelsResponse_PendingChannel{
|
||||
RemoteNodePub: hex.EncodeToString(pub),
|
||||
ChannelPoint: chanPoint.String(),
|
||||
Capacity: int64(waitingClose.Capacity),
|
||||
LocalBalance: int64(waitingClose.LocalCommitment.LocalBalance.ToSatoshis()),
|
||||
}
|
||||
|
||||
// A close tx has been broadcasted, all our balance will be in
|
||||
// limbo until it confirms.
|
||||
resp.WaitingCloseChannels = append(
|
||||
resp.WaitingCloseChannels,
|
||||
&lnrpc.PendingChannelsResponse_WaitingCloseChannel{
|
||||
Channel: channel,
|
||||
LimboBalance: channel.LocalBalance,
|
||||
},
|
||||
)
|
||||
|
||||
resp.TotalLimboBalance += channel.LocalBalance
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@ -1544,7 +1584,7 @@ func (r *rpcServer) ListChannels(ctx context.Context,
|
||||
|
||||
graph := r.server.chanDB.ChannelGraph()
|
||||
|
||||
dbChannels, err := r.server.chanDB.FetchAllChannels()
|
||||
dbChannels, err := r.server.chanDB.FetchAllOpenChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1553,10 +1593,6 @@ func (r *rpcServer) ListChannels(ctx context.Context,
|
||||
len(dbChannels))
|
||||
|
||||
for _, dbChannel := range dbChannels {
|
||||
if dbChannel.IsPending {
|
||||
continue
|
||||
}
|
||||
|
||||
nodePub := dbChannel.IdentityPub
|
||||
nodeID := hex.EncodeToString(nodePub.SerializeCompressed())
|
||||
chanPoint := dbChannel.FundingOutpoint
|
||||
|
Loading…
Reference in New Issue
Block a user