The open_channel Message
- type: 32 (
open_channel
) - 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)が多い。