mirror of
https://github.com/guggero/chantools.git
synced 2026-08-13 12:33:34 +02:00
multi: add triggerforceclose command
This commit is contained in:
parent
a01dd32e55
commit
083453ef5d
9 changed files with 516 additions and 5 deletions
10
README.md
10
README.md
|
|
@ -277,27 +277,34 @@ Usage:
|
|||
|
||||
Available Commands:
|
||||
chanbackup Create a channel.backup file from a channel database
|
||||
closepoolaccount Tries to close a Pool account that has expired
|
||||
compactdb Create a copy of a channel.db file in safe/read-only mode
|
||||
deletepayments Remove all (failed) payments from a channel DB
|
||||
derivekey Derive a key with a specific derivation path
|
||||
dropchannelgraph Remove all graph related data from a channel DB
|
||||
dumpbackup Dump the content of a channel.backup file
|
||||
dumpchannels Dump all channel information from an lnd channel database
|
||||
fakechanbackup Fake a channel backup file to attempt fund recovery
|
||||
filterbackup Filter an lnd channel.backup file and remove certain channels
|
||||
fixoldbackup Fixes an old channel.backup file that is affected by the lnd issue #3881 (unable to derive shachain root key)
|
||||
forceclose Force-close the last state that is in the channel.db provided
|
||||
genimportscript Generate a script containing the on-chain keys of an lnd wallet that can be imported into other software like bitcoind
|
||||
help Help about any command
|
||||
migratedb Apply all recent lnd channel database migrations
|
||||
removechannel Remove a single channel from the given channel DB
|
||||
rescueclosed Try finding the private keys for funds that are in outputs of remotely force-closed channels
|
||||
rescuefunding Rescue funds locked in a funding multisig output that never resulted in a proper channel; this is the command the initiator of the channel needs to run
|
||||
rescuetweakedkey Attempt to rescue funds locked in an address with a key that was affected by a specific bug in lnd
|
||||
showrootkey Extract and show the BIP32 HD root key from the 24 word lnd aezeed
|
||||
signrescuefunding Rescue funds locked in a funding multisig output that never resulted in a proper channel; this is the command the remote node (the non-initiator) of the channel needs to run
|
||||
summary Compile a summary about the current state of channels
|
||||
sweeptimelock Sweep the force-closed state after the time lock has expired
|
||||
sweeptimelockmanual Sweep the force-closed state of a single channel manually if only a channel backup file is available
|
||||
sweepremoteclosed Go through all the addresses that could have funds of channels that were force-closed by the remote party. A public block explorer is queried for each address and if any balance is found, all funds are swept to a given address
|
||||
triggerforceclose Connect to a peer and send a custom message to trigger a force close of the specified channel
|
||||
vanitygen Generate a seed with a custom lnd node identity public key that starts with the given prefix
|
||||
walletinfo Shows info about an lnd wallet.db file and optionally extracts the BIP32 HD root key
|
||||
zombierecovery Try rescuing funds stuck in channels with zombie nodes
|
||||
help Help about any command
|
||||
|
||||
Flags:
|
||||
-h, --help help for chantools
|
||||
|
|
@ -336,6 +343,7 @@ Quick access:
|
|||
+ [sweepremoteclosed](doc/chantools_sweepremoteclosed.md)
|
||||
+ [sweeptimelock](doc/chantools_sweeptimelock.md)
|
||||
+ [sweeptimelockmanual](doc/chantools_sweeptimelockmanual.md)
|
||||
+ [triggerforceclose](doc/chantools_triggerforceclose.md)
|
||||
+ [vanitygen](doc/chantools_vanitygen.md)
|
||||
+ [walletinfo](doc/chantools_walletinfo.md)
|
||||
+ [zombierecovery](doc/chantools_zombierecovery.md)
|
||||
|
|
|
|||
|
|
@ -89,7 +89,9 @@ func (a *ExplorerAPI) Transaction(txid string) (*TX, error) {
|
|||
|
||||
func (a *ExplorerAPI) Outpoint(addr string) (*TX, int, error) {
|
||||
var txs []*TX
|
||||
err := fetchJSON(fmt.Sprintf("%s/address/%s/txs", a.BaseURL, addr), &txs)
|
||||
err := fetchJSON(
|
||||
fmt.Sprintf("%s/address/%s/txs", a.BaseURL, addr), &txs,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
|
@ -104,6 +106,28 @@ func (a *ExplorerAPI) Outpoint(addr string) (*TX, int, error) {
|
|||
return nil, 0, fmt.Errorf("no tx found")
|
||||
}
|
||||
|
||||
func (a *ExplorerAPI) Spends(addr string) ([]*TX, error) {
|
||||
var txs []*TX
|
||||
err := fetchJSON(
|
||||
fmt.Sprintf("%s/address/%s/txs", a.BaseURL, addr), &txs,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var spends []*TX
|
||||
for txIndex := range txs {
|
||||
tx := txs[txIndex]
|
||||
for _, vin := range tx.Vin {
|
||||
if vin.Prevout.ScriptPubkeyAddr == addr {
|
||||
spends = append(spends, tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return spends, nil
|
||||
}
|
||||
|
||||
func (a *ExplorerAPI) Unspent(addr string) ([]*Vout, error) {
|
||||
var (
|
||||
stats = &AddressStats{}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ func newChanAnnouncement(localPubKey, remotePubKey *btcec.PublicKey,
|
|||
|
||||
// Our channel update message flags will signal that we support the
|
||||
// max_htlc field.
|
||||
msgFlags := lnwire.ChanUpdateOptionMaxHtlc
|
||||
msgFlags := lnwire.ChanUpdateRequiredMaxHtlc
|
||||
|
||||
// We announce the channel with the default values. Some of
|
||||
// these values can later be changed by crafting a new ChannelUpdate.
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ import (
|
|||
"github.com/lightningnetwork/lnd/build"
|
||||
"github.com/lightningnetwork/lnd/chanbackup"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/peer"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAPIURL = "https://blockstream.info/api"
|
||||
version = "0.10.6"
|
||||
version = "0.10.7"
|
||||
na = "n/a"
|
||||
|
||||
Commit = ""
|
||||
|
|
@ -104,6 +105,7 @@ func main() {
|
|||
newSweepTimeLockCommand(),
|
||||
newSweepTimeLockManualCommand(),
|
||||
newSweepRemoteClosedCommand(),
|
||||
newTriggerForceCloseCommand(),
|
||||
newVanityGenCommand(),
|
||||
newWalletInfoCommand(),
|
||||
newZombieRecoveryCommand(),
|
||||
|
|
@ -263,6 +265,7 @@ func setupLogging() {
|
|||
setSubLogger("CHAN", log)
|
||||
addSubLogger("CHDB", channeldb.UseLogger)
|
||||
addSubLogger("BCKP", chanbackup.UseLogger)
|
||||
addSubLogger("PEER", peer.UseLogger)
|
||||
err := logWriter.InitLogRotator("./results/chantools.log", 10, 3)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
|||
202
cmd/chantools/triggerforceclose.go
Normal file
202
cmd/chantools/triggerforceclose.go
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/connmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/guggero/chantools/btc"
|
||||
"github.com/guggero/chantools/lnd"
|
||||
"github.com/lightningnetwork/lnd/brontide"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/tor"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
dialTimeout = time.Minute
|
||||
)
|
||||
|
||||
type triggerForceCloseCommand struct {
|
||||
Peer string
|
||||
ChannelPoint string
|
||||
|
||||
APIURL string
|
||||
|
||||
rootKey *rootKey
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newTriggerForceCloseCommand() *cobra.Command {
|
||||
cc := &triggerForceCloseCommand{}
|
||||
cc.cmd = &cobra.Command{
|
||||
Use: "triggerforceclose",
|
||||
Short: "Connect to a peer and send a custom message to " +
|
||||
"trigger a force close of the specified channel",
|
||||
Example: `chantools triggerforceclose \
|
||||
--peer 03abce...@xx.yy.zz.aa:9735 \
|
||||
--channel_point abcdef01234...:x`,
|
||||
RunE: cc.Execute,
|
||||
}
|
||||
cc.cmd.Flags().StringVar(
|
||||
&cc.Peer, "peer", "", "remote peer address "+
|
||||
"(<pubkey>@<host>[:<port>])",
|
||||
)
|
||||
cc.cmd.Flags().StringVar(
|
||||
&cc.ChannelPoint, "channel_point", "", "funding transaction "+
|
||||
"outpoint of the channel to trigger the force close "+
|
||||
"of (<txid>:<txindex>)",
|
||||
)
|
||||
cc.cmd.Flags().StringVar(
|
||||
&cc.APIURL, "apiurl", defaultAPIURL, "API URL to use (must "+
|
||||
"be esplora compatible)",
|
||||
)
|
||||
cc.rootKey = newRootKey(cc.cmd, "deriving the identity key")
|
||||
|
||||
return cc.cmd
|
||||
}
|
||||
|
||||
func (c *triggerForceCloseCommand) Execute(_ *cobra.Command, _ []string) error {
|
||||
extendedKey, err := c.rootKey.read()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading root key: %w", err)
|
||||
}
|
||||
|
||||
identityPath := lnd.IdentityPath(chainParams)
|
||||
child, pubKey, _, err := lnd.DeriveKey(
|
||||
extendedKey, identityPath, chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not derive identity key: %w", err)
|
||||
}
|
||||
identityPriv, err := child.ECPrivKey()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get identity private key: %w", err)
|
||||
}
|
||||
identityECDH := &keychain.PrivKeyECDH{
|
||||
PrivKey: identityPriv,
|
||||
}
|
||||
|
||||
peerAddr, err := lncfg.ParseLNAddressString(
|
||||
c.Peer, "9735", net.ResolveTCPAddr,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing peer address: %w", err)
|
||||
}
|
||||
|
||||
outPoint, err := parseOutPoint(c.ChannelPoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing channel point: %w", err)
|
||||
}
|
||||
channelID := lnwire.NewChanIDFromOutPoint(outPoint)
|
||||
|
||||
conn, err := noiseDial(
|
||||
identityECDH, peerAddr, &tor.ClearNet{}, dialTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error dialing peer: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Attempting to connect to peer %x, dial timeout is %v",
|
||||
pubKey.SerializeCompressed(), dialTimeout)
|
||||
req := &connmgr.ConnReq{
|
||||
Addr: peerAddr,
|
||||
Permanent: false,
|
||||
}
|
||||
p, err := lnd.ConnectPeer(conn, req, chainParams, identityECDH)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error connecting to peer: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Connection established to peer %x",
|
||||
pubKey.SerializeCompressed())
|
||||
|
||||
// We'll wait until the peer is active.
|
||||
select {
|
||||
case <-p.ActiveSignal():
|
||||
case <-p.QuitSignal():
|
||||
return fmt.Errorf("peer %x disconnected",
|
||||
pubKey.SerializeCompressed())
|
||||
}
|
||||
|
||||
// Channel ID (32 byte) + u16 for the data length (which will be 0).
|
||||
data := make([]byte, 34)
|
||||
copy(data[:32], channelID[:])
|
||||
|
||||
log.Infof("Sending channel error message to peer to trigger force "+
|
||||
"close of channel %v", c.ChannelPoint)
|
||||
|
||||
_ = lnwire.SetCustomOverrides([]uint16{lnwire.MsgError})
|
||||
msg, err := lnwire.NewCustom(lnwire.MsgError, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = p.SendMessageLazy(true, msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error sending message: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Message sent, waiting for force close transaction to " +
|
||||
"appear in mempool")
|
||||
|
||||
api := &btc.ExplorerAPI{BaseURL: c.APIURL}
|
||||
channelAddress, err := api.Address(c.ChannelPoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting channel address: %w", err)
|
||||
}
|
||||
|
||||
spends, err := api.Spends(channelAddress)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting spends: %w", err)
|
||||
}
|
||||
for len(spends) == 0 {
|
||||
log.Infof("No spends found yet, waiting 5 seconds...")
|
||||
time.Sleep(5 * time.Second)
|
||||
spends, err = api.Spends(channelAddress)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting spends: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Found force close transaction %v", spends[0].TXID)
|
||||
log.Infof("You can now use the sweepremoteclosed command to sweep " +
|
||||
"the funds from the channel")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func noiseDial(idKey keychain.SingleKeyECDH, lnAddr *lnwire.NetAddress,
|
||||
netCfg tor.Net, timeout time.Duration) (*brontide.Conn, error) {
|
||||
|
||||
return brontide.Dial(idKey, lnAddr, timeout, netCfg.Dial)
|
||||
}
|
||||
|
||||
func parseOutPoint(s string) (*wire.OutPoint, error) {
|
||||
split := strings.Split(s, ":")
|
||||
if len(split) != 2 || len(split[0]) == 0 || len(split[1]) == 0 {
|
||||
return nil, fmt.Errorf("invalid channel point format: %v", s)
|
||||
}
|
||||
|
||||
index, err := strconv.ParseInt(split[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode output index: %v", err)
|
||||
}
|
||||
|
||||
txid, err := chainhash.NewHashFromStr(split[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse hex string: %v", err)
|
||||
}
|
||||
|
||||
return &wire.OutPoint{
|
||||
Hash: *txid,
|
||||
Index: uint32(index),
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@ Complete documentation is available at https://github.com/guggero/chantools/.
|
|||
* [chantools sweepremoteclosed](chantools_sweepremoteclosed.md) - Go through all the addresses that could have funds of channels that were force-closed by the remote party. A public block explorer is queried for each address and if any balance is found, all funds are swept to a given address
|
||||
* [chantools sweeptimelock](chantools_sweeptimelock.md) - Sweep the force-closed state after the time lock has expired
|
||||
* [chantools sweeptimelockmanual](chantools_sweeptimelockmanual.md) - Sweep the force-closed state of a single channel manually if only a channel backup file is available
|
||||
* [chantools triggerforceclose](chantools_triggerforceclose.md) - Connect to a peer and send a custom message to trigger a force close of the specified channel
|
||||
* [chantools vanitygen](chantools_vanitygen.md) - Generate a seed with a custom lnd node identity public key that starts with the given prefix
|
||||
* [chantools walletinfo](chantools_walletinfo.md) - Shows info about an lnd wallet.db file and optionally extracts the BIP32 HD root key
|
||||
* [chantools zombierecovery](chantools_zombierecovery.md) - Try rescuing funds stuck in channels with zombie nodes
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ chantools fakechanbackup --from_channel_graph lncli_describegraph.json \
|
|||
--channelpoint string funding transaction outpoint of the channel to rescue (<txid>:<txindex>) as it is displayed on 1ml.com
|
||||
--from_channel_graph string the full LN channel graph in the JSON format that the 'lncli describegraph' returns
|
||||
-h, --help help for fakechanbackup
|
||||
--multi_file string the fake channel backup file to create (default "results/fake-2022-09-11-19-20-32.backup")
|
||||
--multi_file string the fake channel backup file to create (default "results/fake-2023-02-25-14-15-10.backup")
|
||||
--remote_node_addr string the remote node connection information in the format pubkey@host:port
|
||||
--rootkey string BIP32 HD root key of the wallet to use for encrypting the backup; leave empty to prompt for lnd 24 word aezeed
|
||||
--short_channel_id string the short channel ID in the format <blockheight>x<transactionindex>x<outputindex>
|
||||
|
|
|
|||
38
doc/chantools_triggerforceclose.md
Normal file
38
doc/chantools_triggerforceclose.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
## chantools triggerforceclose
|
||||
|
||||
Connect to a peer and send a custom message to trigger a force close of the specified channel
|
||||
|
||||
```
|
||||
chantools triggerforceclose [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
chantools triggerforceclose \
|
||||
--peer 03abce...@xx.yy.zz.aa:9735 \
|
||||
--channel_point abcdef01234...:x
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
|
||||
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
|
||||
--channel_point string funding transaction outpoint of the channel to trigger the force close of (<txid>:<txindex>)
|
||||
-h, --help help for triggerforceclose
|
||||
--peer string remote peer address (<pubkey>@<host>[:<port>])
|
||||
--rootkey string BIP32 HD root key of the wallet to use for deriving the identity key; leave empty to prompt for lnd 24 word aezeed
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
-r, --regtest Indicates if regtest parameters should be used
|
||||
-t, --testnet Indicates if testnet parameters should be used
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [chantools](chantools.md) - Chantools helps recover funds from lightning channels
|
||||
|
||||
235
lnd/brontide.go
Normal file
235
lnd/brontide.go
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
package lnd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/connmgr"
|
||||
"github.com/lightningnetwork/lnd/aliasmgr"
|
||||
"github.com/lightningnetwork/lnd/brontide"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/discovery"
|
||||
"github.com/lightningnetwork/lnd/feature"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnpeer"
|
||||
"github.com/lightningnetwork/lnd/lntest/mock"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/netann"
|
||||
"github.com/lightningnetwork/lnd/peer"
|
||||
"github.com/lightningnetwork/lnd/pool"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/ticker"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultChannelCommitBatchSize = 10
|
||||
defaultCoopCloseTargetConfs = 6
|
||||
)
|
||||
|
||||
var (
|
||||
chanEnableTimeout = 19 * time.Minute
|
||||
defaultChannelCommitInterval = 50 * time.Millisecond
|
||||
defaultPendingCommitInterval = 1 * time.Minute
|
||||
)
|
||||
|
||||
func ConnectPeer(conn *brontide.Conn, connReq *connmgr.ConnReq,
|
||||
netParams *chaincfg.Params,
|
||||
identityECDH keychain.SingleKeyECDH) (*peer.Brontide, error) {
|
||||
|
||||
featureMgr, err := feature.NewManager(feature.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initFeatures := featureMgr.Get(feature.SetInit)
|
||||
legacyFeatures := featureMgr.Get(feature.SetLegacyGlobal)
|
||||
|
||||
addr := conn.RemoteAddr()
|
||||
pubKey := conn.RemotePub()
|
||||
peerAddr := &lnwire.NetAddress{
|
||||
IdentityKey: pubKey,
|
||||
Address: addr,
|
||||
ChainNet: netParams.Net,
|
||||
}
|
||||
errBuffer, err := queue.NewCircularBuffer(500)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pongBuf := make([]byte, lnwire.MaxPongBytes)
|
||||
|
||||
writeBufferPool := pool.NewWriteBuffer(
|
||||
pool.DefaultWriteBufferGCInterval,
|
||||
pool.DefaultWriteBufferExpiryInterval,
|
||||
)
|
||||
writePool := pool.NewWrite(
|
||||
writeBufferPool, lncfg.DefaultWriteWorkers,
|
||||
pool.DefaultWorkerTimeout,
|
||||
)
|
||||
|
||||
readBufferPool := pool.NewReadBuffer(
|
||||
pool.DefaultReadBufferGCInterval,
|
||||
pool.DefaultReadBufferExpiryInterval,
|
||||
)
|
||||
readPool := pool.NewRead(
|
||||
readBufferPool, lncfg.DefaultWriteWorkers,
|
||||
pool.DefaultWorkerTimeout,
|
||||
)
|
||||
commitFee := chainfee.SatPerKVByte(
|
||||
lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte * 1000,
|
||||
)
|
||||
|
||||
if err := writePool.Start(); err != nil {
|
||||
return nil, fmt.Errorf("unable to start write pool: %v", err)
|
||||
}
|
||||
if err := readPool.Start(); err != nil {
|
||||
return nil, fmt.Errorf("unable to start read pool: %v", err)
|
||||
}
|
||||
|
||||
channelDB, err := channeldb.Open(os.TempDir())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gossiper := discovery.New(discovery.Config{
|
||||
ChainHash: *netParams.GenesisHash,
|
||||
Broadcast: func(skips map[route.Vertex]struct{},
|
||||
msg ...lnwire.Message) error {
|
||||
|
||||
return nil
|
||||
},
|
||||
NotifyWhenOnline: func(peerPubKey [33]byte,
|
||||
peerChan chan<- lnpeer.Peer) {
|
||||
|
||||
},
|
||||
NotifyWhenOffline: func(peerPubKey [33]byte) <-chan struct{} {
|
||||
return make(chan struct{})
|
||||
},
|
||||
SelfNodeAnnouncement: func(
|
||||
refresh bool) (lnwire.NodeAnnouncement, error) {
|
||||
|
||||
return lnwire.NodeAnnouncement{}, nil
|
||||
},
|
||||
ProofMatureDelta: 0,
|
||||
TrickleDelay: time.Millisecond * 50,
|
||||
RetransmitTicker: ticker.New(time.Minute * 30),
|
||||
RebroadcastInterval: time.Hour * 24,
|
||||
RotateTicker: ticker.New(discovery.DefaultSyncerRotationInterval),
|
||||
HistoricalSyncTicker: ticker.New(discovery.DefaultHistoricalSyncInterval),
|
||||
NumActiveSyncers: 0,
|
||||
MinimumBatchSize: 10,
|
||||
SubBatchDelay: discovery.DefaultSubBatchDelay,
|
||||
IgnoreHistoricalFilters: true,
|
||||
PinnedSyncers: make(map[route.Vertex]struct{}),
|
||||
MaxChannelUpdateBurst: discovery.DefaultMaxChannelUpdateBurst,
|
||||
ChannelUpdateInterval: discovery.DefaultChannelUpdateInterval,
|
||||
IsAlias: aliasmgr.IsAlias,
|
||||
SignAliasUpdate: func(u *lnwire.ChannelUpdate) (*ecdsa.Signature, error) {
|
||||
return nil, fmt.Errorf("unimplemented")
|
||||
},
|
||||
FindBaseByAlias: func(alias lnwire.ShortChannelID) (lnwire.ShortChannelID, error) {
|
||||
return lnwire.ShortChannelID{}, fmt.Errorf("unimplemented")
|
||||
},
|
||||
GetAlias: func(id lnwire.ChannelID) (lnwire.ShortChannelID, error) {
|
||||
return lnwire.ShortChannelID{}, fmt.Errorf("unimplemented")
|
||||
},
|
||||
FindChannel: func(node *btcec.PublicKey,
|
||||
chanID lnwire.ChannelID) (*channeldb.OpenChannel, error) {
|
||||
|
||||
return nil, fmt.Errorf("unimplemented")
|
||||
},
|
||||
}, &keychain.KeyDescriptor{
|
||||
KeyLocator: keychain.KeyLocator{},
|
||||
PubKey: identityECDH.PubKey(),
|
||||
})
|
||||
|
||||
pCfg := peer.Config{
|
||||
Conn: conn,
|
||||
ConnReq: connReq,
|
||||
Addr: peerAddr,
|
||||
Inbound: false,
|
||||
Features: initFeatures,
|
||||
LegacyFeatures: legacyFeatures,
|
||||
OutgoingCltvRejectDelta: lncfg.DefaultOutgoingCltvRejectDelta,
|
||||
ChanActiveTimeout: chanEnableTimeout,
|
||||
ErrorBuffer: errBuffer,
|
||||
WritePool: writePool,
|
||||
ReadPool: readPool,
|
||||
ChannelDB: channelDB.ChannelStateDB(),
|
||||
AuthGossiper: gossiper,
|
||||
ChainNotifier: &mock.ChainNotifier{},
|
||||
DisconnectPeer: func(key *btcec.PublicKey) error {
|
||||
fmt.Printf("Peer %x disconnected\n",
|
||||
key.SerializeCompressed())
|
||||
return nil
|
||||
},
|
||||
GenNodeAnnouncement: func(b bool,
|
||||
modifier ...netann.NodeAnnModifier) (
|
||||
lnwire.NodeAnnouncement, error) {
|
||||
|
||||
return lnwire.NodeAnnouncement{},
|
||||
fmt.Errorf("unimplemented")
|
||||
},
|
||||
|
||||
PongBuf: pongBuf,
|
||||
|
||||
PrunePersistentPeerConnection: func(bytes [33]byte) {},
|
||||
|
||||
FetchLastChanUpdate: func(id lnwire.ShortChannelID) (
|
||||
*lnwire.ChannelUpdate, error) {
|
||||
|
||||
return nil, fmt.Errorf("unimplemented")
|
||||
},
|
||||
|
||||
Hodl: &hodl.Config{},
|
||||
UnsafeReplay: false,
|
||||
MaxOutgoingCltvExpiry: htlcswitch.DefaultMaxOutgoingCltvExpiry,
|
||||
MaxChannelFeeAllocation: htlcswitch.DefaultMaxLinkFeeAllocation,
|
||||
CoopCloseTargetConfs: defaultCoopCloseTargetConfs,
|
||||
MaxAnchorsCommitFeeRate: commitFee.FeePerKWeight(),
|
||||
ChannelCommitInterval: defaultChannelCommitInterval,
|
||||
PendingCommitInterval: defaultPendingCommitInterval,
|
||||
ChannelCommitBatchSize: defaultChannelCommitBatchSize,
|
||||
HandleCustomMessage: func(peer [33]byte,
|
||||
msg *lnwire.Custom) error {
|
||||
|
||||
fmt.Printf("Received custom message from %x: %v\n",
|
||||
peer[:], msg)
|
||||
return nil
|
||||
},
|
||||
GetAliases: func(
|
||||
base lnwire.ShortChannelID) []lnwire.ShortChannelID {
|
||||
|
||||
return nil
|
||||
},
|
||||
RequestAlias: func() (lnwire.ShortChannelID, error) {
|
||||
return lnwire.ShortChannelID{}, nil
|
||||
},
|
||||
AddLocalAlias: func(alias, base lnwire.ShortChannelID,
|
||||
gossip bool) error {
|
||||
|
||||
return nil
|
||||
},
|
||||
Quit: make(chan struct{}),
|
||||
}
|
||||
|
||||
copy(pCfg.PubKeyBytes[:], peerAddr.IdentityKey.SerializeCompressed())
|
||||
copy(pCfg.ServerPubKey[:], identityECDH.PubKey().SerializeCompressed())
|
||||
|
||||
p := peer.NewBrontide(pCfg)
|
||||
if err := p.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue