The open_channel Message

  1. type: 32 (open_channel)
  2. data:
    • [32:chain_hash]
    • [32:temporary_channel_id]
    • [8:funding_satoshis]
    • [8:push_msat]
    • [8:dust_limit_satoshis]
    • [8:max_htlc_value_in_flight_msat]
    • [8:channel_reserve_satoshis]
    • [8:htlc_minimum_msat]
    • [4:feerate_per_kw]
    • [2:to_self_delay]
    • [2:max_accepted_htlcs]
    • [33:funding_pubkey]
    • [33:revocation_basepoint]
    • [33:payment_basepoint]
    • [33:delayed_payment_basepoint]
    • [33:htlc_basepoint]
    • [33:first_per_commitment_point]
    • [1:channel_flags]
    • [2:shutdown_len] (option_upfront_shutdown_script)
    • [shutdown_len:shutdown_scriptpubkey] (option_upfront_shutdown_script)

これらがパラメータ。

重要なのは、funding pub keyとhtlc_basepointかな。これらがよく説明で出てきているものだと思う。本当は鍵はもっとたくさんあって、説明は簡素化されている。

トランザクションの項目に”local”と”remote”があり、自分が作るトランザクションの場合は「local=自分」「remote=相手」になり、相手が作るトランザクションの場合は「local=相手」「remote=自分」になるためである。

func openChannel(ctx *cli.Context) error {  
    // TODO(roasbeef): add deadline to context
    ctxb := context.Background()
    client, cleanUp := getClient(ctx)

様々なチェックのあとに、open channelが呼ばれる。

stream, err := client.OpenChannel(ctxb, req)  
if err != nil {  
  return err
}

このclientは、gRPC clientのことで、内部的にはserverのopen channelが呼ばれることになる。

// OpenChannel sends a request to the server to open a channel to the specified
// peer identified by nodeKey with the passed channel funding parameters.
//
// NOTE: This function is safe for concurrent access.
func (s *server) OpenChannel(  
    req *openChanReq) (chan *lnrpc.OpenStatusUpdate, chan error) {

このあとに、funding managerが使われる。

// Spawn a goroutine to send the funding workflow request to the funding
// manager. This allows the server to continue handling queries instead
// of blocking on this request which is exported as a synchronous
// request to the outside world.
go s.fundingMgr.initFundingWorkflow(peer, req)

return req.updates, req.err  
}

ここで、funding managerのworkflowに登録されて、

// initFundingWorkflow sends a message to the funding manager instructing it
// to initiate a single funder workflow with the source peer.
// TODO(roasbeef): re-visit blocking nature..
func (f *fundingManager) initFundingWorkflow(peer lnpeer.Peer, req *openChanReq) {  
    f.fundingRequests <- &initFundingMsg{
        peer:        peer,
        openChanReq: req,
    }
}

ここにはいったリクエストは、

// handleInitFundingMsg creates a channel reservation within the daemon's
// wallet, then sends a funding request to the remote peer kicking off the
// funding workflow.
func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {  
    var (
        peerKey        = msg.peer.IdentityKey()
        localAmt       = msg.localFundingAmt
        remoteAmt      = msg.remoteFundingAmt
        capacity       = localAmt + remoteAmt
        minHtlc        = msg.minHtlc
        remoteCsvDelay = msg.remoteCsvDelay
    )

に回る。

最終的には、peerに対してfundingTXが送信される。

fundingOpen := lnwire.OpenChannel{  
  ChainHash:            *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
  PendingChannelID:     chanID,
  FundingAmount:        capacity,
  PushAmount:           msg.pushAmt,
  DustLimit:            ourContribution.DustLimit,
  MaxValueInFlight:     maxValue,
  ChannelReserve:       chanReserve,
  HtlcMinimum:          minHtlc,
  FeePerKiloWeight:     uint32(commitFeePerKw),
  CsvDelay:             remoteCsvDelay,
  MaxAcceptedHTLCs:     maxHtlcs,
  FundingKey:           ourContribution.MultiSigKey.PubKey,
  RevocationPoint:      ourContribution.RevocationBasePoint.PubKey,
  PaymentPoint:         ourContribution.PaymentBasePoint.PubKey,
  HtlcPoint:            ourContribution.HtlcBasePoint.PubKey,
  DelayedPaymentPoint:  ourContribution.DelayBasePoint.PubKey,
  FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
  ChannelFlags:         channelFlags,
}
if err := msg.peer.SendMessage(false, &fundingOpen); err != nil {  
  e := fmt.Errorf("Unable to send funding request message: %v",
    err)
  fndgLog.Errorf(e.Error())

  // Since we were unable to send the initial message to the peer
  // and start the funding flow, we'll cancel this reservation.
  if _, err := f.cancelReservationCtx(peerKey, chanID); err != nil {
    fndgLog.Errorf("unable to cancel reservation: %v", err)
  }

ソースコードを追っていくと、TODO(roasbeef)が多い。