rpc+lnwallet: implement new FundingStateStep RPC method

In this commit, we implement the currently defined transition methods
for the new `FundingStateStep` method. At this point, we're now able to
serve the "responder" of the externally initiated channel funding flow
by being able to register and cancel a funding flow according to its
expected pending channel ID.
This commit is contained in:
Olaoluwa Osuntokun 2019-11-13 21:00:30 -08:00
parent 91bd56dbd1
commit bc176b5aa3
No known key found for this signature in database
GPG Key ID: BC13F65E2DC84465
3 changed files with 95 additions and 11 deletions

View File

@ -154,15 +154,9 @@ func NewCannedAssembler(chanPoint wire.OutPoint, fundingAmt btcutil.Amount,
//
// NOTE: This method satisfies the chanfunding.Assembler interface.
func (c *CannedAssembler) ProvisionChannel(req *Request) (Intent, error) {
switch {
// A simple sanity check to ensure the provision request matches the
// re-made shim intent.
case req.LocalAmt != c.fundingAmt:
return nil, fmt.Errorf("intent doesn't match canned assembler")
// We'll exit out if this field is set as the funding transaction has
// already been assembled, so we don't influence coin selection..
case req.SubtractFees:
if req.SubtractFees {
return nil, fmt.Errorf("SubtractFees ignored, funding " +
"transaction is frozen")
}
@ -179,6 +173,14 @@ func (c *CannedAssembler) ProvisionChannel(req *Request) (Intent, error) {
intent.remoteFundingAmt = c.fundingAmt
}
// A simple sanity check to ensure the provisioned request matches the
// re-made shim intent.
if req.LocalAmt+req.RemoteAmt != c.fundingAmt {
return nil, fmt.Errorf("intent doesn't match canned "+
"assembler: local_amt=%v, remote_amt=%v, funding_amt=%v",
req.LocalAmt, req.RemoteAmt, c.fundingAmt)
}
return intent, nil
}

View File

@ -450,8 +450,30 @@ func (l *LightningWallet) RegisterFundingIntent(expectedID [32]byte,
shimIntent chanfunding.Intent) error {
l.intentMtx.Lock()
defer l.intentMtx.Unlock()
if _, ok := l.fundingIntents[expectedID]; ok {
return fmt.Errorf("pendingChanID(%x) already has intent "+
"registered", expectedID[:])
}
l.fundingIntents[expectedID] = shimIntent
l.intentMtx.Unlock()
return nil
}
// CancelFundingIntent allows a caller to cancel a previously registered
// funding intent. If no intent was found, then an error will be returned.
func (l *LightningWallet) CancelFundingIntent(pid [32]byte) error {
l.intentMtx.Lock()
defer l.intentMtx.Unlock()
if _, ok := l.fundingIntents[pid]; !ok {
return fmt.Errorf("no funding intent found for "+
"pendingChannelID(%x)", pid[:])
}
delete(l.fundingIntents, pid)
return nil
}

View File

@ -5814,8 +5814,68 @@ func (r *rpcServer) BakeMacaroon(ctx context.Context,
// ID, for which we need to use specific parameters. Alternatively, this can
// be used to interactively drive PSBT signing for funding for partially
// complete funding transactions.
func (r *rpcServer) FundingStateStep(context.Context,
*lnrpc.FundingTransitionMsg) (*lnrpc.FundingStateStepResp, error) {
func (r *rpcServer) FundingStateStep(ctx context.Context,
in *lnrpc.FundingTransitionMsg) (*lnrpc.FundingStateStepResp, error) {
return nil, fmt.Errorf("not implemented")
switch {
// If this is a message to register a new shim that is an external
// channel point, then we'll contact the wallet to register this new
// shim. A user will use this method to register a new channel funding
// workflow which has already been partially negotiated outside of the
// core protocol.
case in.GetShimRegister() != nil &&
in.GetShimRegister().GetChanPointShim() != nil:
rpcShimIntent := in.GetShimRegister().GetChanPointShim()
// Using the rpc shim as a template, we'll construct a new
// chanfunding.Assembler that is able to express proper
// formulation of this expected channel.
shimAssembler, err := newFundingShimAssembler(
rpcShimIntent, false, r.server.cc.keyRing,
)
if err != nil {
return nil, err
}
req := &chanfunding.Request{
RemoteAmt: btcutil.Amount(rpcShimIntent.Amt),
}
shimIntent, err := shimAssembler.ProvisionChannel(req)
if err != nil {
return nil, err
}
// Once we have the intent, we'll register it with the wallet.
// Once we receive an incoming funding request that uses this
// pending channel ID, then this shim will be dispatched in
// place of our regular funding workflow.
var pendingChanID [32]byte
copy(pendingChanID[:], rpcShimIntent.PendingChanId)
err = r.server.cc.wallet.RegisterFundingIntent(
pendingChanID, shimIntent,
)
if err != nil {
return nil, err
}
// If this is a transition to cancel an existing shim, then we'll pass
// this message along to the wallet.
case in.GetShimCancel() != nil:
pid := in.GetShimCancel().PendingChanId
var pendingChanID [32]byte
copy(pendingChanID[:], pid)
err := r.server.cc.wallet.CancelFundingIntent(pendingChanID)
if err != nil {
return nil, err
}
}
// TODO(roasbeef): extend PendingChannels to also show shims
// TODO(roasbeef): return resulting state? also add a method to query
// current state?
return &lnrpc.FundingStateStepResp{}, nil
}