mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 01:36:24 +01:00
rpcserver: align OpenChannel+OpenChannelSync req parsing
This commit consolidates our request parsing for OpenChannel and OpenChannelSync which removes a good deal of code duplication.
This commit is contained in:
parent
c1f9c56e5b
commit
66d02504f9
1 changed files with 77 additions and 151 deletions
228
rpcserver.go
228
rpcserver.go
|
@ -1603,15 +1603,10 @@ func newPsbtAssembler(req *lnrpc.OpenChannelRequest, normalizedMinConfs int32,
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenChannel attempts to open a singly funded channel specified in the
|
// canOpenChannel returns an error if the necessary subsystems for channel
|
||||||
// request to a remote peer.
|
// funding are not ready.
|
||||||
func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
func (r *rpcServer) canOpenChannel() error {
|
||||||
updateStream lnrpc.Lightning_OpenChannelServer) error {
|
// We can't open a channel until the main server has started.
|
||||||
|
|
||||||
rpcsLog.Tracef("[openchannel] request to NodeKey(%v) "+
|
|
||||||
"allocation(us=%v, them=%v)", in.NodePubkeyString,
|
|
||||||
in.LocalFundingAmount, in.PushSat)
|
|
||||||
|
|
||||||
if !r.server.Started() {
|
if !r.server.Started() {
|
||||||
return ErrServerNotActive
|
return ErrServerNotActive
|
||||||
}
|
}
|
||||||
|
@ -1627,6 +1622,19 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
"wallet is fully synced")
|
"wallet is fully synced")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// praseOpenChannelReq parses an OpenChannelRequest message into the server's
|
||||||
|
// native openChanReq struct. The logic is abstracted so that it can be shared
|
||||||
|
// between OpenChannel and OpenChannelSync.
|
||||||
|
func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
||||||
|
isSync bool) (*openChanReq, error) {
|
||||||
|
|
||||||
|
rpcsLog.Debugf("[openchannel] request to NodeKey(%x) "+
|
||||||
|
"allocation(us=%v, them=%v)", in.NodePubkey,
|
||||||
|
in.LocalFundingAmount, in.PushSat)
|
||||||
|
|
||||||
localFundingAmt := btcutil.Amount(in.LocalFundingAmount)
|
localFundingAmt := btcutil.Amount(in.LocalFundingAmount)
|
||||||
remoteInitialBalance := btcutil.Amount(in.PushSat)
|
remoteInitialBalance := btcutil.Amount(in.PushSat)
|
||||||
minHtlcIn := lnwire.MilliSatoshi(in.MinHtlcMsat)
|
minHtlcIn := lnwire.MilliSatoshi(in.MinHtlcMsat)
|
||||||
|
@ -1638,15 +1646,15 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
//
|
//
|
||||||
// TODO(roasbeef): incorporate base fee?
|
// TODO(roasbeef): incorporate base fee?
|
||||||
if remoteInitialBalance >= localFundingAmt {
|
if remoteInitialBalance >= localFundingAmt {
|
||||||
return fmt.Errorf("amount pushed to remote peer for initial " +
|
return nil, fmt.Errorf("amount pushed to remote peer for " +
|
||||||
"state must be below the local funding amount")
|
"initial state must be below the local funding amount")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the user doesn't exceed the current soft-limit for
|
// Ensure that the user doesn't exceed the current soft-limit for
|
||||||
// channel size. If the funding amount is above the soft-limit, then
|
// channel size. If the funding amount is above the soft-limit, then
|
||||||
// we'll reject the request.
|
// we'll reject the request.
|
||||||
if localFundingAmt > MaxFundingAmount {
|
if localFundingAmt > MaxFundingAmount {
|
||||||
return fmt.Errorf("funding amount is too large, the max "+
|
return nil, fmt.Errorf("funding amount is too large, the max "+
|
||||||
"channel size is: %v", MaxFundingAmount)
|
"channel size is: %v", MaxFundingAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1654,8 +1662,8 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
// level, we'll ensure that the output we create after accounting for
|
// level, we'll ensure that the output we create after accounting for
|
||||||
// fees that a dust output isn't created.
|
// fees that a dust output isn't created.
|
||||||
if localFundingAmt < minChanFundingSize {
|
if localFundingAmt < minChanFundingSize {
|
||||||
return fmt.Errorf("channel is too small, the minimum channel "+
|
return nil, fmt.Errorf("channel is too small, the minimum "+
|
||||||
"size is: %v SAT", int64(minChanFundingSize))
|
"channel size is: %v SAT", int64(minChanFundingSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then, we'll extract the minimum number of confirmations that each
|
// Then, we'll extract the minimum number of confirmations that each
|
||||||
|
@ -1663,29 +1671,48 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
// satisfy.
|
// satisfy.
|
||||||
minConfs, err := extractOpenChannelMinConfs(in)
|
minConfs, err := extractOpenChannelMinConfs(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): also return channel ID?
|
// TODO(roasbeef): also return channel ID?
|
||||||
|
|
||||||
var nodePubKey *btcec.PublicKey
|
var nodePubKey *btcec.PublicKey
|
||||||
|
|
||||||
// Ensure that the NodePubKey is set before attempting to use it
|
// Parse the remote pubkey the NodePubkey field of the request. If it's
|
||||||
if len(in.NodePubkey) == 0 {
|
// not present, we'll fallback to the deprecated version that parses the
|
||||||
return fmt.Errorf("NodePubKey is not set")
|
// key from a hex string if this is for REST for backwards compatibility.
|
||||||
}
|
switch {
|
||||||
|
|
||||||
// Parse the raw bytes of the node key into a pubkey object so we
|
// Parse the raw bytes of the node key into a pubkey object so we can
|
||||||
// can easily manipulate it.
|
// easily manipulate it.
|
||||||
nodePubKey, err = btcec.ParsePubKey(in.NodePubkey, btcec.S256())
|
case len(in.NodePubkey) > 0:
|
||||||
if err != nil {
|
nodePubKey, err = btcec.ParsePubKey(in.NodePubkey, btcec.S256())
|
||||||
return err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the provided target node's public key, parsing it into a pub
|
||||||
|
// key object. For all sync call, byte slices are expected to be encoded
|
||||||
|
// as hex strings.
|
||||||
|
case isSync:
|
||||||
|
keyBytes, err := hex.DecodeString(in.NodePubkeyString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nodePubKey, err = btcec.ParsePubKey(keyBytes, btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("NodePubkey is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Making a channel to ourselves wouldn't be of any use, so we
|
// Making a channel to ourselves wouldn't be of any use, so we
|
||||||
// explicitly disallow them.
|
// explicitly disallow them.
|
||||||
if nodePubKey.IsEqual(r.server.identityPriv.PubKey()) {
|
if nodePubKey.IsEqual(r.server.identityPriv.PubKey()) {
|
||||||
return fmt.Errorf("cannot open channel to self")
|
return nil, fmt.Errorf("cannot open channel to self")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on the passed fee related parameters, we'll determine an
|
// Based on the passed fee related parameters, we'll determine an
|
||||||
|
@ -1698,7 +1725,7 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcsLog.Debugf("[openchannel]: using fee of %v sat/kw for funding tx",
|
rpcsLog.Debugf("[openchannel]: using fee of %v sat/kw for funding tx",
|
||||||
|
@ -1706,13 +1733,14 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
|
|
||||||
script, err := parseUpfrontShutdownAddress(in.CloseAddress)
|
script, err := parseUpfrontShutdownAddress(in.CloseAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error parsing upfront shutdown: %v", err)
|
return nil, fmt.Errorf("error parsing upfront shutdown: %v",
|
||||||
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instruct the server to trigger the necessary events to attempt to
|
// Instruct the server to trigger the necessary events to attempt to
|
||||||
// open a new channel. A stream is returned in place, this stream will
|
// open a new channel. A stream is returned in place, this stream will
|
||||||
// be used to consume updates of the state of the pending channel.
|
// be used to consume updates of the state of the pending channel.
|
||||||
req := &openChanReq{
|
return &openChanReq{
|
||||||
targetPubkey: nodePubKey,
|
targetPubkey: nodePubKey,
|
||||||
chainHash: *activeNetParams.GenesisHash,
|
chainHash: *activeNetParams.GenesisHash,
|
||||||
localFundingAmt: localFundingAmt,
|
localFundingAmt: localFundingAmt,
|
||||||
|
@ -1723,6 +1751,21 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
remoteCsvDelay: remoteCsvDelay,
|
remoteCsvDelay: remoteCsvDelay,
|
||||||
minConfs: minConfs,
|
minConfs: minConfs,
|
||||||
shutdownScript: script,
|
shutdownScript: script,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenChannel attempts to open a singly funded channel specified in the
|
||||||
|
// request to a remote peer.
|
||||||
|
func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
|
updateStream lnrpc.Lightning_OpenChannelServer) error {
|
||||||
|
|
||||||
|
if err := r.canOpenChannel(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := r.parseOpenChannelReq(in, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user has provided a shim, then we'll now augment the based
|
// If the user has provided a shim, then we'll now augment the based
|
||||||
|
@ -1758,7 +1801,7 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
||||||
// transaction.
|
// transaction.
|
||||||
copy(req.pendingChanID[:], psbtShim.PendingChanId)
|
copy(req.pendingChanID[:], psbtShim.PendingChanId)
|
||||||
req.chanFunder, err = newPsbtAssembler(
|
req.chanFunder, err = newPsbtAssembler(
|
||||||
in, minConfs, psbtShim,
|
in, req.minConfs, psbtShim,
|
||||||
&r.server.cc.wallet.Cfg.NetParams,
|
&r.server.cc.wallet.Cfg.NetParams,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1775,7 +1818,7 @@ out:
|
||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
|
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
|
||||||
nodePubKey.SerializeCompressed(), err)
|
req.targetPubkey.SerializeCompressed(), err)
|
||||||
return err
|
return err
|
||||||
case fundingUpdate := <-updateChan:
|
case fundingUpdate := <-updateChan:
|
||||||
rpcsLog.Tracef("[openchannel] sending update: %v",
|
rpcsLog.Tracef("[openchannel] sending update: %v",
|
||||||
|
@ -1807,7 +1850,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)",
|
rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)",
|
||||||
nodePubKey.SerializeCompressed(), outpoint)
|
req.targetPubkey.SerializeCompressed(), outpoint)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1818,138 +1861,21 @@ out:
|
||||||
func (r *rpcServer) OpenChannelSync(ctx context.Context,
|
func (r *rpcServer) OpenChannelSync(ctx context.Context,
|
||||||
in *lnrpc.OpenChannelRequest) (*lnrpc.ChannelPoint, error) {
|
in *lnrpc.OpenChannelRequest) (*lnrpc.ChannelPoint, error) {
|
||||||
|
|
||||||
rpcsLog.Tracef("[openchannel] request to NodeKey(%v) "+
|
if err := r.canOpenChannel(); err != nil {
|
||||||
"allocation(us=%v, them=%v)", in.NodePubkeyString,
|
|
||||||
in.LocalFundingAmount, in.PushSat)
|
|
||||||
|
|
||||||
// We don't allow new channels to be open while the server is still
|
|
||||||
// syncing, as otherwise we may not be able to obtain the relevant
|
|
||||||
// notifications.
|
|
||||||
if !r.server.Started() {
|
|
||||||
return nil, ErrServerNotActive
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creation of channels before the wallet syncs up is currently
|
|
||||||
// disallowed.
|
|
||||||
isSynced, _, err := r.server.cc.wallet.IsSynced()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !isSynced {
|
|
||||||
return nil, errors.New("channels cannot be created before the " +
|
|
||||||
"wallet is fully synced")
|
|
||||||
}
|
|
||||||
|
|
||||||
var nodePubKey *btcec.PublicKey
|
|
||||||
|
|
||||||
// Parse the remote pubkey the NodePubkey field of the request. If it's
|
|
||||||
// not present, we'll fallback to the deprecated version that parses the
|
|
||||||
// key from a hex string.
|
|
||||||
if len(in.NodePubkey) > 0 {
|
|
||||||
// Parse the raw bytes of the node key into a pubkey object so we
|
|
||||||
// can easily manipulate it.
|
|
||||||
nodePubKey, err = btcec.ParsePubKey(in.NodePubkey, btcec.S256())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Decode the provided target node's public key, parsing it into
|
|
||||||
// a pub key object. For all sync call, byte slices are expected
|
|
||||||
// to be encoded as hex strings.
|
|
||||||
keyBytes, err := hex.DecodeString(in.NodePubkeyString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nodePubKey, err = btcec.ParsePubKey(keyBytes, btcec.S256())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Making a channel to ourselves wouldn't be of any use, so we
|
|
||||||
// explicitly disallow them.
|
|
||||||
if nodePubKey.IsEqual(r.server.identityPriv.PubKey()) {
|
|
||||||
return nil, fmt.Errorf("cannot open channel to self")
|
|
||||||
}
|
|
||||||
|
|
||||||
localFundingAmt := btcutil.Amount(in.LocalFundingAmount)
|
|
||||||
remoteInitialBalance := btcutil.Amount(in.PushSat)
|
|
||||||
minHtlcIn := lnwire.MilliSatoshi(in.MinHtlcMsat)
|
|
||||||
remoteCsvDelay := uint16(in.RemoteCsvDelay)
|
|
||||||
|
|
||||||
// Ensure that the initial balance of the remote party (if pushing
|
|
||||||
// satoshis) does not exceed the amount the local party has requested
|
|
||||||
// for funding.
|
|
||||||
if remoteInitialBalance >= localFundingAmt {
|
|
||||||
return nil, fmt.Errorf("amount pushed to remote peer for " +
|
|
||||||
"initial state must be below the local funding amount")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the user doesn't exceed the current soft-limit for
|
|
||||||
// channel size. If the funding amount is above the soft-limit, then
|
|
||||||
// we'll reject the request.
|
|
||||||
if localFundingAmt > MaxFundingAmount {
|
|
||||||
return nil, fmt.Errorf("funding amount is too large, the max "+
|
|
||||||
"channel size is: %v", MaxFundingAmount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict the size of the channel we'll actually open. At a later
|
|
||||||
// level, we'll ensure that the output we create after accounting for
|
|
||||||
// fees that a dust output isn't created.
|
|
||||||
if localFundingAmt < minChanFundingSize {
|
|
||||||
return nil, fmt.Errorf("channel is too small, the minimum channel "+
|
|
||||||
"size is: %v SAT", int64(minChanFundingSize))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then, we'll extract the minimum number of confirmations that each
|
|
||||||
// output we use to fund the channel's funding transaction should
|
|
||||||
// satisfy.
|
|
||||||
minConfs, err := extractOpenChannelMinConfs(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on the passed fee related parameters, we'll determine an
|
req, err := r.parseOpenChannelReq(in, true)
|
||||||
// appropriate fee rate for the funding transaction.
|
|
||||||
satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
|
||||||
feeRate, err := sweep.DetermineFeePerKw(
|
|
||||||
r.server.cc.feeEstimator, sweep.FeePreference{
|
|
||||||
ConfTarget: uint32(in.TargetConf),
|
|
||||||
FeeRate: satPerKw,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcsLog.Tracef("[openchannel] target sat/kw for funding tx: %v",
|
|
||||||
int64(feeRate))
|
|
||||||
|
|
||||||
script, err := parseUpfrontShutdownAddress(in.CloseAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing upfront shutdown: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := &openChanReq{
|
|
||||||
targetPubkey: nodePubKey,
|
|
||||||
chainHash: *activeNetParams.GenesisHash,
|
|
||||||
localFundingAmt: localFundingAmt,
|
|
||||||
pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance),
|
|
||||||
minHtlcIn: minHtlcIn,
|
|
||||||
fundingFeePerKw: feeRate,
|
|
||||||
private: in.Private,
|
|
||||||
remoteCsvDelay: remoteCsvDelay,
|
|
||||||
minConfs: minConfs,
|
|
||||||
shutdownScript: script,
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChan, errChan := r.server.OpenChannel(req)
|
updateChan, errChan := r.server.OpenChannel(req)
|
||||||
select {
|
select {
|
||||||
// If an error occurs them immediately return the error to the client.
|
// If an error occurs them immediately return the error to the client.
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
|
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
|
||||||
nodePubKey.SerializeCompressed(), err)
|
req.targetPubkey.SerializeCompressed(), err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
||||||
// Otherwise, wait for the first channel update. The first update sent
|
// Otherwise, wait for the first channel update. The first update sent
|
||||||
|
|
Loading…
Add table
Reference in a new issue