github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/qln/fund.go (about)

     1  package qln
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/mit-dci/lit/consts"
     8  	"github.com/mit-dci/lit/crypto/koblitz"
     9  	"github.com/mit-dci/lit/elkrem"
    10  	"github.com/mit-dci/lit/lnutil"
    11  	"github.com/mit-dci/lit/logging"
    12  	"github.com/mit-dci/lit/portxo"
    13  	"github.com/mit-dci/lit/wire"
    14  )
    15  
    16  /*
    17  right now fund makes a channel without actually building commit
    18  transactions before signing and broadcasting the fund transaction.
    19  Once state update push/pull messages work that will be added on to
    20  this process
    21  
    22  Note that the first elkrem exchange revokes state 0, which was never actually
    23  committed to  (there are no HAKDpubs for state 0; those start at state 1.)
    24  So it's kindof pointless, but you still have to send the right one, because
    25  elkrem 2 is the parent of elkrems 0 and 1, so that checks 0.
    26  
    27  */
    28  
    29  /*
    30  New funding process.
    31  No fancy curve stuff.  Just ask the other node for a point on a curve, which
    32  will be their channel pubkey.
    33  There are 2 ways to then change to a channel-proof-y method later.
    34  One way is to construct the channel pubkey FROM that point, by having
    35  ID:A
    36  Random point:B
    37  Channel point:C
    38  and set C = hash(A, B)*(A + B)
    39  or you could do it 4-way so that
    40  C = hash(A1, B1, A2, B2)*(A + B)
    41  to commit to both sides' creation process.  This is a little more complex,
    42  but the proof of ownership for the channel just consists of the point B so
    43  it's compact.
    44  
    45  Another way to do it, after the fact with arbitrary points.
    46  ID:A, Channel pub:C
    47  B = A + C
    48  sign B with b.  That signature is proof that someone / something knew
    49  a and c at the same time.
    50  
    51  Either of these can be added later without changing much.  The messages
    52  don't have to change at all, and in the first case you'd change the channel
    53  pubkey calculation.  In the second it's independent of the fund process.
    54  
    55  For now though:
    56  funding --
    57  A -> B point request
    58  
    59  A channel point (33) (channel pubkey for now)
    60  A refund (33)
    61  
    62  B -> A point response
    63  B replies with channel point and refund pubkey
    64  
    65  B channel point (32) (channel pubkey for now)
    66  B refund (33)
    67  
    68  A -> B Channel Description:
    69  ---
    70  outpoint (36)
    71  capacity (8)
    72  initial push (8)
    73  B's HAKD pub #1 (33)
    74  signature (~70)
    75  ---
    76  
    77  add next:
    78  timeout (2)
    79  fee? fee can
    80  (fee / timeout...?  hardcoded for now)
    81  
    82  B -> A  Channel Acknowledge:
    83  A's HAKD pub #1 (33)
    84  signature (~70)
    85  
    86  === time passes, fund tx gets in a block ===
    87  
    88  A -> B SigProof
    89  SPV proof of the outpoint (block height, tree depth, tx index, hashes)
    90  signature (~70)
    91  
    92  
    93  B knows the channel is open and he got paid when he receives the sigproof.
    94  A's got B's signature already.  So "payment happened" is sortof the same as
    95  bitcoin now; wait for confirmations.
    96  
    97  Alternatively A can open a channel with no initial funding going to B, then
    98  update the state once the channel is open.  If for whatever reason you want
    99  an exact timing for the payment.
   100  
   101  */
   102  
   103  // FundChannel opens a channel with a peer.  Doesn't return until the channel
   104  // has been created.  Maybe timeout if it takes too long?
   105  func (nd *LitNode) FundChannel(
   106  	peerIdx, cointype uint32, ccap, initSend int64, data [32]byte) (uint32, error) {
   107  
   108  	_, ok := nd.SubWallet[cointype]
   109  	if !ok {
   110  		return 0, fmt.Errorf("No wallet of type %d connected", cointype)
   111  	}
   112  
   113  	nd.InProg.mtx.Lock()
   114  	//	defer nd.InProg.mtx.Lock()
   115  
   116  	_, ok = nd.ConnectedCoinTypes[cointype]
   117  	if !ok {
   118  		nd.InProg.mtx.Unlock()
   119  		return 0, fmt.Errorf("No daemon of type %d connected. Can't fund, only receive", cointype)
   120  	}
   121  
   122  	fee := nd.SubWallet[cointype].Fee() * 1000
   123  
   124  	if nd.InProg.PeerIdx != 0 {
   125  		nd.InProg.mtx.Unlock()
   126  		return 0, fmt.Errorf("fund with peer %d not done yet", nd.InProg.PeerIdx)
   127  	}
   128  
   129  	if initSend < 0 || ccap < 0 {
   130  		nd.InProg.mtx.Unlock()
   131  		return 0, fmt.Errorf("Can't have negative send or capacity")
   132  	}
   133  	if ccap < consts.MinChanCapacity { // limit for now
   134  		nd.InProg.mtx.Unlock()
   135  		return 0, fmt.Errorf("Min channel capacity 1M sat")
   136  	}
   137  	if initSend > ccap {
   138  		nd.InProg.mtx.Unlock()
   139  		return 0, fmt.Errorf("Can't send %d in %d capacity channel", initSend, ccap)
   140  	}
   141  
   142  	if initSend != 0 && initSend < consts.MinOutput+fee {
   143  		nd.InProg.mtx.Unlock()
   144  		return 0, fmt.Errorf("Can't send %d as initial send because MinOutput is %d", initSend, consts.MinOutput+fee)
   145  	}
   146  
   147  	if ccap-initSend < consts.MinOutput+fee {
   148  		nd.InProg.mtx.Unlock()
   149  		return 0, fmt.Errorf("Can't send %d as initial send because MinOutput is %d and you would only have %d", initSend, consts.MinOutput+fee, ccap-initSend)
   150  	}
   151  
   152  	// TODO - would be convenient if it auto connected to the peer huh
   153  	if !nd.ConnectedToPeer(peerIdx) {
   154  		nd.InProg.mtx.Unlock()
   155  		return 0, fmt.Errorf("Not connected to peer %d. Do that yourself.", peerIdx)
   156  	}
   157  
   158  	cIdx, err := nd.NextChannelIdx()
   159  	if err != nil {
   160  		nd.InProg.mtx.Unlock()
   161  		return 0, err
   162  	}
   163  
   164  	logging.Infof("next channel idx: %d", cIdx)
   165  
   166  	nd.InProg.ChanIdx = cIdx
   167  	nd.InProg.PeerIdx = peerIdx
   168  	nd.InProg.Amt = ccap
   169  	nd.InProg.InitSend = initSend
   170  	nd.InProg.Data = data
   171  
   172  	nd.InProg.Coin = cointype
   173  	nd.InProg.mtx.Unlock() // switch to defer
   174  
   175  	outMsg := lnutil.NewPointReqMsg(peerIdx, cointype)
   176  
   177  	nd.tmpSendLitMsg(outMsg)
   178  
   179  	// wait until it's done!
   180  	idx := <-nd.InProg.done
   181  
   182  	return idx, nil
   183  }
   184  
   185  // RECIPIENT
   186  // PubReqHandler gets a (content-less) pubkey request.  Respond with a pubkey
   187  // and a refund pubkey hash. (currently makes pubkey hash, need to only make 1)
   188  // so if someone sends 10 pubkeyreqs, they'll get the same pubkey back 10 times.
   189  // they have to provide an actual tx before the next pubkey will come out.
   190  func (nd *LitNode) PointReqHandler(msg lnutil.PointReqMsg) {
   191  
   192  	/* shouldn't be possible to get this error...
   193  	if nd.RemoteCon == nil || nd.RemoteCon.RemotePub == nil {
   194  		logging.Errorf("Not connected to anyone\n")
   195  		return
   196  	}*/
   197  
   198  	// pub req; check that idx matches next idx of ours and create pubkey
   199  	// peerArr, _ := nd.GetPubHostFromPeerIdx(msg.Peer())
   200  
   201  	cIdx, err := nd.NextChannelIdx()
   202  	if err != nil {
   203  		logging.Errorf("PointReqHandler err %s", err.Error())
   204  		return
   205  	}
   206  
   207  	_, ok := nd.SubWallet[msg.Cointype]
   208  	if !ok {
   209  		logging.Errorf("PointReqHandler err no wallet for type %d", msg.Cointype)
   210  		return
   211  	}
   212  
   213  	var kg portxo.KeyGen
   214  	kg.Depth = 5
   215  	kg.Step[0] = 44 | 1<<31
   216  	kg.Step[1] = msg.Cointype | 1<<31
   217  	kg.Step[2] = UseChannelFund
   218  	kg.Step[3] = msg.Peer() | 1<<31
   219  	kg.Step[4] = cIdx | 1<<31
   220  
   221  	myChanPub, _ := nd.GetUsePub(kg, UseChannelFund)
   222  	myRefundPub, _ := nd.GetUsePub(kg, UseChannelRefund)
   223  	myHAKDbase, err := nd.GetUsePub(kg, UseChannelHAKDBase)
   224  	if err != nil {
   225  		logging.Errorf("PointReqHandler err %s", err.Error())
   226  		return
   227  	}
   228  
   229  	logging.Infof("Generated channel pubkey %x\n", myChanPub)
   230  
   231  	var keyGen portxo.KeyGen
   232  	keyGen.Depth = 5
   233  	keyGen.Step[0] = 44 | 1<<31
   234  	keyGen.Step[1] = msg.Cointype | 1<<31
   235  	keyGen.Step[2] = UseHTLCBase
   236  	keyGen.Step[3] = 0 | 1<<31
   237  	keyGen.Step[4] = cIdx | 1<<31
   238  
   239  	myNextHTLCBase, err := nd.GetUsePub(keyGen, UseHTLCBase)
   240  	if err != nil {
   241  		logging.Errorf("error generating NextHTLCBase %v", err)
   242  		return
   243  	}
   244  
   245  	keyGen.Step[3] = 1 | 1<<31
   246  	myN2HTLCBase, err := nd.GetUsePub(keyGen, UseHTLCBase)
   247  	if err != nil {
   248  		logging.Errorf("error generating N2HTLCBase %v", err)
   249  		return
   250  	}
   251  
   252  	outMsg := lnutil.NewPointRespMsg(msg.Peer(), myChanPub, myRefundPub, myHAKDbase,
   253  		myNextHTLCBase, myN2HTLCBase)
   254  	nd.tmpSendLitMsg(outMsg)
   255  
   256  	return
   257  }
   258  
   259  // FUNDER
   260  // PointRespHandler takes in a point response, and returns a channel description
   261  func (nd *LitNode) PointRespHandler(msg lnutil.PointRespMsg) error {
   262  	var err error
   263  	logging.Infof("Got PointResponse")
   264  
   265  	nd.InProg.mtx.Lock()
   266  	defer nd.InProg.mtx.Unlock()
   267  
   268  	if nd.InProg.PeerIdx == 0 {
   269  		return fmt.Errorf("Got point response but no channel creation in progress")
   270  	}
   271  
   272  	if nd.InProg.PeerIdx != msg.Peer() {
   273  		return fmt.Errorf(
   274  			"making channel with peer %d but got PointResp from %d",
   275  			nd.InProg.PeerIdx, msg.Peer())
   276  	}
   277  
   278  	if nd.SubWallet[nd.InProg.Coin] == nil {
   279  		return fmt.Errorf("Not connected to coin type %d\n", nd.InProg.Coin)
   280  	}
   281  
   282  	// make channel (not in db) just for keys / elk
   283  	q := new(Qchan)
   284  
   285  	q.Height = -1
   286  
   287  	q.Value = nd.InProg.Amt
   288  
   289  	q.KeyGen.Depth = 5
   290  	q.KeyGen.Step[0] = 44 | 1<<31
   291  	q.KeyGen.Step[1] = nd.InProg.Coin | 1<<31
   292  	q.KeyGen.Step[2] = UseChannelFund
   293  	q.KeyGen.Step[3] = nd.InProg.PeerIdx | 1<<31
   294  	q.KeyGen.Step[4] = nd.InProg.ChanIdx | 1<<31
   295  
   296  	q.MyPub, _ = nd.GetUsePub(q.KeyGen, UseChannelFund)
   297  	q.MyRefundPub, _ = nd.GetUsePub(q.KeyGen, UseChannelRefund)
   298  	q.MyHAKDBase, _ = nd.GetUsePub(q.KeyGen, UseChannelHAKDBase)
   299  	q.ElkRcv = elkrem.NewElkremReceiver()
   300  
   301  	// chop up incoming message, save points to channel struct
   302  	copy(q.TheirPub[:], msg.ChannelPub[:])
   303  	copy(q.TheirRefundPub[:], msg.RefundPub[:])
   304  	copy(q.TheirHAKDBase[:], msg.HAKDbase[:])
   305  
   306  	// make sure their pubkeys are real pubkeys
   307  	_, err = koblitz.ParsePubKey(q.TheirPub[:], koblitz.S256())
   308  	if err != nil {
   309  		return fmt.Errorf("PubRespHandler TheirPub err %s", err.Error())
   310  	}
   311  	_, err = koblitz.ParsePubKey(q.TheirRefundPub[:], koblitz.S256())
   312  	if err != nil {
   313  		return fmt.Errorf("PubRespHandler TheirRefundPub err %s", err.Error())
   314  	}
   315  	_, err = koblitz.ParsePubKey(q.TheirHAKDBase[:], koblitz.S256())
   316  	if err != nil {
   317  		return fmt.Errorf("PubRespHandler TheirHAKDBase err %s", err.Error())
   318  	}
   319  
   320  	// derive elkrem sender root from HD keychain
   321  	elkRoot, _ := nd.GetElkremRoot(q.KeyGen)
   322  	q.ElkSnd = elkrem.NewElkremSender(elkRoot)
   323  
   324  	// set the time
   325  	q.LastUpdate = uint64(time.Now().UnixNano() / 1000)
   326  
   327  	// get txo for channel
   328  	txo, err := lnutil.FundTxOut(q.MyPub, q.TheirPub, nd.InProg.Amt)
   329  	if err != nil {
   330  		return err
   331  	}
   332  
   333  	// call MaybeSend, freezing inputs and learning the txid of the channel
   334  	// here, we require only witness inputs
   335  	outPoints, err := nd.SubWallet[q.Coin()].MaybeSend([]*wire.TxOut{txo}, true)
   336  	if err != nil {
   337  		return err
   338  	}
   339  
   340  	// should only have 1 txout index from MaybeSend, which we use
   341  	if len(outPoints) != 1 {
   342  		return fmt.Errorf("got %d OPs from MaybeSend (expect 1)", len(outPoints))
   343  	}
   344  
   345  	// save fund outpoint to inProg
   346  	nd.InProg.op = outPoints[0]
   347  	// also set outpoint in channel
   348  	q.Op = *nd.InProg.op
   349  
   350  	// create initial state for elkrem points
   351  	q.State = new(StatCom)
   352  	q.State.StateIdx = 0
   353  	q.State.MyAmt = nd.InProg.Amt - nd.InProg.InitSend
   354  	// get fee from sub wallet.  Later should make fee per channel and update state
   355  	// based on size
   356  	q.State.Fee = nd.SubWallet[q.Coin()].Fee() * consts.QcStateFee
   357  
   358  	q.State.Data = nd.InProg.Data
   359  
   360  	_, err = koblitz.ParsePubKey(msg.NextHTLCBase[:], koblitz.S256())
   361  	if err != nil {
   362  		return fmt.Errorf("PubRespHandler NextHTLCBase err %s", err.Error())
   363  	}
   364  	_, err = koblitz.ParsePubKey(msg.N2HTLCBase[:], koblitz.S256())
   365  	if err != nil {
   366  		return fmt.Errorf("PubRespHandler N2HTLCBase err %s", err.Error())
   367  	}
   368  
   369  	var keyGen portxo.KeyGen
   370  	keyGen.Depth = 5
   371  	keyGen.Step[0] = 44 | 1<<31
   372  	keyGen.Step[1] = nd.InProg.Coin | 1<<31
   373  	keyGen.Step[2] = UseHTLCBase
   374  	keyGen.Step[3] = 0 | 1<<31
   375  	keyGen.Step[4] = nd.InProg.ChanIdx | 1<<31
   376  
   377  	q.State.MyNextHTLCBase, err = nd.GetUsePub(keyGen, UseHTLCBase)
   378  	if err != nil {
   379  		return fmt.Errorf("error generating NextHTLCBase %v", err)
   380  	}
   381  
   382  	keyGen.Step[3] = 1 | 1<<31
   383  	q.State.MyN2HTLCBase, err = nd.GetUsePub(keyGen, UseHTLCBase)
   384  	if err != nil {
   385  		return fmt.Errorf("error generating N2HTLCBase %v", err)
   386  	}
   387  
   388  	q.State.NextHTLCBase = msg.NextHTLCBase
   389  	q.State.N2HTLCBase = msg.N2HTLCBase
   390  
   391  	// save channel to db
   392  	err = nd.SaveQChan(q)
   393  	if err != nil {
   394  		nd.FailChannel(q)
   395  		return fmt.Errorf("PointRespHandler SaveQchanState err %s", err.Error())
   396  	}
   397  
   398  	// when funding a channel, give them the first *3* elkpoints.
   399  	elkPointZero, err := q.ElkPoint(false, 0)
   400  	if err != nil {
   401  		nd.FailChannel(q)
   402  		return err
   403  	}
   404  	elkPointOne, err := q.ElkPoint(false, 1)
   405  	if err != nil {
   406  		nd.FailChannel(q)
   407  		return err
   408  	}
   409  
   410  	elkPointTwo, err := q.N2ElkPointForThem()
   411  	if err != nil {
   412  		nd.FailChannel(q)
   413  		return err
   414  	}
   415  
   416  	// description is outpoint (36), mypub(33), myrefund(33),
   417  	// myHAKDbase(33), capacity (8),
   418  	// initial payment (8), ElkPoint0,1,2 (99)
   419  
   420  	outMsg := lnutil.NewChanDescMsg(
   421  		msg.Peer(), *nd.InProg.op, q.MyPub, q.MyRefundPub, q.MyHAKDBase,
   422  		q.State.MyNextHTLCBase, q.State.MyN2HTLCBase,
   423  		nd.InProg.Coin, nd.InProg.Amt, nd.InProg.InitSend,
   424  		elkPointZero, elkPointOne, elkPointTwo, nd.InProg.Data)
   425  
   426  	nd.tmpSendLitMsg(outMsg)
   427  
   428  	return nil
   429  }
   430  
   431  // RECIPIENT
   432  // QChanDescHandler takes in a description of a channel output.  It then
   433  // saves it to the local db, and returns a channel acknowledgement
   434  func (nd *LitNode) QChanDescHandler(msg lnutil.ChanDescMsg) error {
   435  
   436  	wal, ok := nd.SubWallet[msg.CoinType]
   437  	if !ok {
   438  		return fmt.Errorf("QChanDescHandler err no wallet for type %d", msg.CoinType)
   439  	}
   440  
   441  	// deserialize desc
   442  	op := msg.Outpoint
   443  	opArr := lnutil.OutPointToBytes(op)
   444  	amt := msg.Capacity
   445  
   446  	cIdx, err := nd.NextChannelIdx()
   447  	if err != nil {
   448  		return fmt.Errorf("QChanDescHandler err %s", err.Error())
   449  	}
   450  
   451  	qc := new(Qchan)
   452  
   453  	qc.Height = -1
   454  	qc.KeyGen.Depth = 5
   455  	qc.KeyGen.Step[0] = 44 | 1<<31
   456  	qc.KeyGen.Step[1] = msg.CoinType | 1<<31
   457  	qc.KeyGen.Step[2] = UseChannelFund
   458  	qc.KeyGen.Step[3] = msg.Peer() | 1<<31
   459  	qc.KeyGen.Step[4] = cIdx | 1<<31
   460  	qc.Value = amt
   461  	qc.Mode = portxo.TxoP2WSHComp
   462  	qc.Op = op
   463  
   464  	qc.TheirPub = msg.PubKey
   465  	qc.TheirRefundPub = msg.RefundPub
   466  	qc.TheirHAKDBase = msg.HAKDbase
   467  	qc.MyPub, _ = nd.GetUsePub(qc.KeyGen, UseChannelFund)
   468  	qc.MyRefundPub, _ = nd.GetUsePub(qc.KeyGen, UseChannelRefund)
   469  	qc.MyHAKDBase, _ = nd.GetUsePub(qc.KeyGen, UseChannelHAKDBase)
   470  
   471  	// it should go into the next bucket and get the right key index.
   472  	// but we can't actually check that.
   473  	//	qc, err := nd.SaveFundTx(
   474  	//		op, amt, peerArr, theirPub, theirRefundPub, theirHAKDbase)
   475  	//	if err != nil {
   476  	//		logging.Errorf("QChanDescHandler SaveFundTx err %s", err.Error())
   477  	//		return
   478  	//	}
   479  	logging.Infof("got multisig output %s amt %d\n", op.String(), amt)
   480  
   481  	// create initial state
   482  	qc.State = new(StatCom)
   483  	// similar to SIGREV in pushpull
   484  
   485  	// TODO assumes both parties use same fee
   486  	qc.State.Fee = wal.Fee() * consts.QcStateFee
   487  	qc.State.MyAmt = msg.InitPayment
   488  
   489  	qc.State.Data = msg.Data
   490  
   491  	qc.State.StateIdx = 0
   492  	// use new ElkPoint for signing
   493  	qc.State.ElkPoint = msg.ElkZero
   494  	qc.State.NextElkPoint = msg.ElkOne
   495  	qc.State.N2ElkPoint = msg.ElkTwo
   496  
   497  	_, err = koblitz.ParsePubKey(msg.NextHTLCBase[:], koblitz.S256())
   498  	if err != nil {
   499  		return fmt.Errorf("QChanDescHandler NextHTLCBase err %s", err.Error())
   500  	}
   501  	_, err = koblitz.ParsePubKey(msg.N2HTLCBase[:], koblitz.S256())
   502  	if err != nil {
   503  		return fmt.Errorf("QChanDescHandler N2HTLCBase err %s", err.Error())
   504  	}
   505  
   506  	var keyGen portxo.KeyGen
   507  	keyGen.Depth = 5
   508  	keyGen.Step[0] = 44 | 1<<31
   509  	keyGen.Step[1] = msg.CoinType | 1<<31
   510  	keyGen.Step[2] = UseHTLCBase
   511  	keyGen.Step[3] = 0 | 1<<31
   512  	keyGen.Step[4] = cIdx | 1<<31
   513  
   514  	qc.State.MyNextHTLCBase, err = nd.GetUsePub(keyGen, UseHTLCBase)
   515  	if err != nil {
   516  		return fmt.Errorf("error generating NextHTLCBase %v", err)
   517  	}
   518  
   519  	keyGen.Step[3] = 1 | 1<<31
   520  	qc.State.MyN2HTLCBase, err = nd.GetUsePub(keyGen, UseHTLCBase)
   521  	if err != nil {
   522  		return fmt.Errorf("error generating N2HTLCBase %v", err)
   523  	}
   524  
   525  	qc.State.NextHTLCBase = msg.NextHTLCBase
   526  	qc.State.N2HTLCBase = msg.N2HTLCBase
   527  
   528  	// save new channel to db
   529  	err = nd.SaveQChan(qc)
   530  	if err != nil {
   531  		nd.FailChannel(qc)
   532  		logging.Errorf("QChanDescHandler err %s", err.Error())
   533  		return err
   534  	}
   535  
   536  	// load ... the thing I just saved.  why?
   537  	qc, err = nd.GetQchan(opArr)
   538  	if err != nil {
   539  		nd.FailChannel(qc)
   540  		logging.Errorf("QChanDescHandler GetQchan err %s", err.Error())
   541  		return err
   542  	}
   543  
   544  	// when funding a channel, give them the first *2* elkpoints.
   545  	theirElkPointZero, err := qc.ElkPoint(false, 0)
   546  	if err != nil {
   547  		nd.FailChannel(qc)
   548  		logging.Errorf("QChanDescHandler err %s", err.Error())
   549  		return err
   550  	}
   551  	theirElkPointOne, err := qc.ElkPoint(false, 1)
   552  	if err != nil {
   553  		nd.FailChannel(qc)
   554  		logging.Errorf("QChanDescHandler err %s", err.Error())
   555  		return err
   556  	}
   557  
   558  	theirElkPointTwo, err := qc.N2ElkPointForThem()
   559  	if err != nil {
   560  		nd.FailChannel(qc)
   561  		logging.Errorf("QChanDescHandler err %s", err.Error())
   562  		return err
   563  	}
   564  
   565  	sig, _, err := nd.SignState(qc)
   566  	if err != nil {
   567  		nd.FailChannel(qc)
   568  		logging.Errorf("QChanDescHandler SignState err %s", err.Error())
   569  		return err
   570  	}
   571  
   572  	outMsg := lnutil.NewChanAckMsg(
   573  		msg.Peer(), op,
   574  		theirElkPointZero, theirElkPointOne, theirElkPointTwo,
   575  		sig)
   576  	outMsg.Bytes()
   577  
   578  	nd.tmpSendLitMsg(outMsg)
   579  
   580  	return nil
   581  }
   582  
   583  // FUNDER
   584  // QChanAckHandler takes in an acknowledgement multisig description.
   585  // when a multisig outpoint is ackd, that causes the funder to sign and broadcast.
   586  func (nd *LitNode) QChanAckHandler(msg lnutil.ChanAckMsg, peer *RemotePeer) {
   587  	opArr := lnutil.OutPointToBytes(msg.Outpoint)
   588  	sig := msg.Signature
   589  
   590  	// load channel to save their refund address
   591  	qc, err := nd.GetQchan(opArr)
   592  	if err != nil {
   593  		nd.FailChannel(qc)
   594  		logging.Errorf("QChanAckHandler GetQchan err %s", err.Error())
   595  		return
   596  	}
   597  
   598  	//	err = qc.IngestElkrem(revElk)
   599  	//	if err != nil { // this can't happen because it's the first elk... remove?
   600  	//		logging.Errorf("QChanAckHandler IngestElkrem err %s", err.Error())
   601  	//		return
   602  	//	}
   603  	qc.State.ElkPoint = msg.ElkZero
   604  	qc.State.NextElkPoint = msg.ElkOne
   605  	qc.State.N2ElkPoint = msg.ElkTwo
   606  
   607  	err = qc.VerifySigs(sig, nil)
   608  	if err != nil {
   609  		nd.FailChannel(qc)
   610  		logging.Errorf("QChanAckHandler VerifySig err %s", err.Error())
   611  		return
   612  	}
   613  
   614  	// verify worked; Save state 1 to DB
   615  	err = nd.SaveQchanState(qc)
   616  	if err != nil {
   617  		nd.FailChannel(qc)
   618  		logging.Errorf("QChanAckHandler SaveQchanState err %s", err.Error())
   619  		return
   620  	}
   621  
   622  	// Make sure everything works & is saved, then clear InProg.
   623  
   624  	// sign their com tx to send
   625  	sig, _, err = nd.SignState(qc)
   626  	if err != nil {
   627  		nd.FailChannel(qc)
   628  		logging.Errorf("QChanAckHandler SignState err %s", err.Error())
   629  		return
   630  	}
   631  
   632  	// OK to fund.
   633  	err = nd.SubWallet[qc.Coin()].ReallySend(&qc.Op.Hash)
   634  	if err != nil {
   635  		nd.FailChannel(qc)
   636  		logging.Errorf("QChanAckHandler ReallySend err %s", err.Error())
   637  		return
   638  	}
   639  
   640  	err = nd.SubWallet[qc.Coin()].WatchThis(qc.Op)
   641  	if err != nil {
   642  		nd.FailChannel(qc)
   643  		logging.Errorf("QChanAckHandler WatchThis err %s", err.Error())
   644  		return
   645  	}
   646  
   647  	// tell base wallet about watcher refund address in case that happens
   648  	// TODO this is weird & ugly... maybe have an export keypath func?
   649  	nullTxo := new(portxo.PorTxo)
   650  	nullTxo.Value = 0 // redundant, but explicitly show that this is just for adr
   651  	nullTxo.KeyGen = qc.KeyGen
   652  	nullTxo.KeyGen.Step[2] = UseChannelWatchRefund
   653  	nd.SubWallet[qc.Coin()].ExportUtxo(nullTxo)
   654  
   655  	// channel creation is ~complete, clear InProg.
   656  	// We may be asked to re-send the sig-proof
   657  
   658  	nd.InProg.mtx.Lock()
   659  	nd.InProg.done <- qc.KeyGen.Step[4] & 0x7fffffff
   660  	nd.InProg.Clear()
   661  	nd.InProg.mtx.Unlock()
   662  
   663  	peer.QCs[qc.Idx()] = qc
   664  	peer.OpMap[opArr] = qc.Idx()
   665  
   666  	// sig proof should be sent later once there are confirmations.
   667  	// it'll have an spv proof of the fund tx.
   668  	// but for now just send the sig.
   669  
   670  	outMsg := lnutil.NewSigProofMsg(msg.Peer(), msg.Outpoint, sig)
   671  
   672  	nd.tmpSendLitMsg(outMsg)
   673  
   674  	return
   675  }
   676  
   677  // RECIPIENT
   678  // SigProofHandler saves the signature the recipient stores.
   679  // In some cases you don't need this message.
   680  func (nd *LitNode) SigProofHandler(msg lnutil.SigProofMsg, peer *RemotePeer) {
   681  
   682  	op := msg.Outpoint
   683  	opArr := lnutil.OutPointToBytes(op)
   684  
   685  	qc, err := nd.GetQchan(opArr)
   686  	if err != nil {
   687  		nd.FailChannel(qc)
   688  		logging.Errorf("SigProofHandler err %s", err.Error())
   689  		return
   690  	}
   691  
   692  	wal, ok := nd.SubWallet[qc.Coin()]
   693  	if !ok {
   694  		nd.FailChannel(qc)
   695  		logging.Errorf("Not connected to coin type %d\n", qc.Coin())
   696  		return
   697  	}
   698  
   699  	err = qc.VerifySigs(msg.Signature, nil)
   700  	if err != nil {
   701  		nd.FailChannel(qc)
   702  		logging.Errorf("SigProofHandler err %s", err.Error())
   703  		return
   704  	}
   705  
   706  	// sig OK, save
   707  	err = nd.SaveQchanState(qc)
   708  	if err != nil {
   709  		nd.FailChannel(qc)
   710  		logging.Errorf("SigProofHandler err %s", err.Error())
   711  		return
   712  	}
   713  
   714  	err = wal.WatchThis(op)
   715  
   716  	if err != nil {
   717  		nd.FailChannel(qc)
   718  		logging.Errorf("SigProofHandler err %s", err.Error())
   719  		return
   720  	}
   721  
   722  	// tell base wallet about watcher refund address in case that happens
   723  	nullTxo := new(portxo.PorTxo)
   724  	nullTxo.Value = 0 // redundant, but explicitly show that this is just for adr
   725  	nullTxo.KeyGen = qc.KeyGen
   726  	nullTxo.KeyGen.Step[2] = UseChannelWatchRefund
   727  	wal.ExportUtxo(nullTxo)
   728  
   729  	peer.QCs[qc.Idx()] = qc
   730  	peer.OpMap[opArr] = qc.Idx()
   731  
   732  	// sig OK; in terms of UI here's where you can say "payment received"
   733  	// "channel online" etc
   734  
   735  	peerIdx := qc.Peer()
   736  	existingPeer := nd.PeerMan.GetPeerByIdx(int32(peerIdx))
   737  
   738  	sigProofEvent := ChannelStateUpdateEvent{
   739  		Action:   "sigproof",
   740  		ChanIdx:  qc.Idx(),
   741  		State:    qc.State,
   742  		TheirPub: existingPeer.GetPubkey(),
   743  		CoinType: qc.Coin(),
   744  	}
   745  
   746  	if succeed, err := nd.Events.Publish(sigProofEvent); err != nil {
   747  		logging.Errorf("SigProofHandler publish err %s", err)
   748  		return
   749  	} else if !succeed {
   750  		logging.Errorf("SigProofHandler publish did not succeed")
   751  		return
   752  	}
   753  
   754  	return
   755  }