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

     1  package qln
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/mit-dci/lit/logging"
     8  
     9  	"github.com/mit-dci/lit/btcutil/txscript"
    10  	"github.com/mit-dci/lit/lnutil"
    11  	"github.com/mit-dci/lit/portxo"
    12  	"github.com/mit-dci/lit/wire"
    13  )
    14  
    15  func (nd *LitNode) registerHandlers() {
    16  
    17  	mp := nd.PeerMan.GetMessageProcessor()
    18  	hf := makeNeoOmniHandler(nd)
    19  
    20  	// I used the following command to generate these calls below:
    21  	// grep -E '^.MSGID_[A-Z_]+ += ' lnutil/msglib.go | awk '{ print $1 }' | while read m; do echo "mp.DefineMessage(lnutil.$m, makeNeoOmniParser(lnutil.$m), hf)" ; done
    22  
    23  	mp.DefineMessage(lnutil.MSGID_TEXTCHAT, makeNeoOmniParser(lnutil.MSGID_TEXTCHAT), hf)
    24  	mp.DefineMessage(lnutil.MSGID_POINTREQ, makeNeoOmniParser(lnutil.MSGID_POINTREQ), hf)
    25  	mp.DefineMessage(lnutil.MSGID_POINTRESP, makeNeoOmniParser(lnutil.MSGID_POINTRESP), hf)
    26  	mp.DefineMessage(lnutil.MSGID_CHANDESC, makeNeoOmniParser(lnutil.MSGID_CHANDESC), hf)
    27  	mp.DefineMessage(lnutil.MSGID_CHANACK, makeNeoOmniParser(lnutil.MSGID_CHANACK), hf)
    28  	mp.DefineMessage(lnutil.MSGID_SIGPROOF, makeNeoOmniParser(lnutil.MSGID_SIGPROOF), hf)
    29  	mp.DefineMessage(lnutil.MSGID_CLOSEREQ, makeNeoOmniParser(lnutil.MSGID_CLOSEREQ), hf)
    30  	mp.DefineMessage(lnutil.MSGID_CLOSERESP, makeNeoOmniParser(lnutil.MSGID_CLOSERESP), hf)
    31  	mp.DefineMessage(lnutil.MSGID_DELTASIG, makeNeoOmniParser(lnutil.MSGID_DELTASIG), hf)
    32  	mp.DefineMessage(lnutil.MSGID_SIGREV, makeNeoOmniParser(lnutil.MSGID_SIGREV), hf)
    33  	mp.DefineMessage(lnutil.MSGID_GAPSIGREV, makeNeoOmniParser(lnutil.MSGID_GAPSIGREV), hf)
    34  	mp.DefineMessage(lnutil.MSGID_REV, makeNeoOmniParser(lnutil.MSGID_REV), hf)
    35  	mp.DefineMessage(lnutil.MSGID_HASHSIG, makeNeoOmniParser(lnutil.MSGID_HASHSIG), hf)
    36  	mp.DefineMessage(lnutil.MSGID_PREIMAGESIG, makeNeoOmniParser(lnutil.MSGID_PREIMAGESIG), hf)
    37  	mp.DefineMessage(lnutil.MSGID_FWDMSG, makeNeoOmniParser(lnutil.MSGID_FWDMSG), hf)
    38  	mp.DefineMessage(lnutil.MSGID_FWDAUTHREQ, makeNeoOmniParser(lnutil.MSGID_FWDAUTHREQ), hf)
    39  	mp.DefineMessage(lnutil.MSGID_SELFPUSH, makeNeoOmniParser(lnutil.MSGID_SELFPUSH), hf)
    40  	mp.DefineMessage(lnutil.MSGID_WATCH_DESC, makeNeoOmniParser(lnutil.MSGID_WATCH_DESC), hf)
    41  	mp.DefineMessage(lnutil.MSGID_WATCH_STATEMSG, makeNeoOmniParser(lnutil.MSGID_WATCH_STATEMSG), hf)
    42  	mp.DefineMessage(lnutil.MSGID_WATCH_DELETE, makeNeoOmniParser(lnutil.MSGID_WATCH_DELETE), hf)
    43  	mp.DefineMessage(lnutil.MSGID_LINK_DESC, makeNeoOmniParser(lnutil.MSGID_LINK_DESC), hf)
    44  	mp.DefineMessage(lnutil.MSGID_DLC_OFFER, makeNeoOmniParser(lnutil.MSGID_DLC_OFFER), hf)
    45  	mp.DefineMessage(lnutil.MSGID_DLC_ACCEPTOFFER, makeNeoOmniParser(lnutil.MSGID_DLC_ACCEPTOFFER), hf)
    46  	mp.DefineMessage(lnutil.MSGID_DLC_DECLINEOFFER, makeNeoOmniParser(lnutil.MSGID_DLC_DECLINEOFFER), hf)
    47  	mp.DefineMessage(lnutil.MSGID_DLC_CONTRACTACK, makeNeoOmniParser(lnutil.MSGID_DLC_CONTRACTACK), hf)
    48  	mp.DefineMessage(lnutil.MSGID_DLC_CONTRACTFUNDINGSIGS, makeNeoOmniParser(lnutil.MSGID_DLC_CONTRACTFUNDINGSIGS), hf)
    49  	mp.DefineMessage(lnutil.MSGID_DLC_SIGPROOF, makeNeoOmniParser(lnutil.MSGID_DLC_SIGPROOF), hf)
    50  	mp.DefineMessage(lnutil.MSGID_DUALFUNDINGREQ, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGREQ), hf)
    51  	mp.DefineMessage(lnutil.MSGID_DUALFUNDINGACCEPT, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGACCEPT), hf)
    52  	mp.DefineMessage(lnutil.MSGID_DUALFUNDINGDECL, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGDECL), hf)
    53  	mp.DefineMessage(lnutil.MSGID_DUALFUNDINGCHANACK, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGCHANACK), hf)
    54  	mp.DefineMessage(lnutil.MSGID_REMOTE_RPCREQUEST, makeNeoOmniParser(lnutil.MSGID_REMOTE_RPCREQUEST), hf)
    55  	mp.DefineMessage(lnutil.MSGID_REMOTE_RPCRESPONSE, makeNeoOmniParser(lnutil.MSGID_REMOTE_RPCRESPONSE), hf)
    56  	mp.DefineMessage(lnutil.MSGID_PAY_REQ, makeNeoOmniParser(lnutil.MSGID_PAY_REQ), hf)
    57  	mp.DefineMessage(lnutil.MSGID_PAY_ACK, makeNeoOmniParser(lnutil.MSGID_PAY_ACK), hf)
    58  	mp.DefineMessage(lnutil.MSGID_PAY_SETUP, makeNeoOmniParser(lnutil.MSGID_PAY_SETUP), hf)
    59  
    60  }
    61  
    62  // handles stuff that comes in over the wire.  Not user-initiated.
    63  func (nd *LitNode) PeerHandler(msg lnutil.LitMsg, q *Qchan, peer *RemotePeer) error {
    64  	logging.Infof("Message from %d type %x", msg.Peer(), msg.MsgType())
    65  	switch msg.MsgType() & 0xf0 {
    66  	case 0x00: // TEXT MESSAGE.  SIMPLE
    67  		chat, ok := msg.(lnutil.ChatMsg)
    68  		if !ok {
    69  			return fmt.Errorf("can't cast to chat message")
    70  		}
    71  		nd.UserMessageBox <- fmt.Sprintf(
    72  			"\nmsg from %s: %s", lnutil.White(msg.Peer()), lnutil.Green(chat.Text))
    73  		return nil // no error
    74  
    75  	case 0x10: //Making Channel, or using
    76  		return nd.ChannelHandler(msg, peer)
    77  
    78  	case 0x20: //Closing
    79  		return nd.CloseHandler(msg)
    80  
    81  	case 0x30: //PushPull
    82  		if q == nil {
    83  			return fmt.Errorf("pushpull message but no matching channel")
    84  		}
    85  		return nd.PushPullHandler(msg, q)
    86  
    87  	/* not yet implemented
    88  	case 0x40:
    89  		return nd.FWDHandler(msg)
    90  	*/
    91  	/* not yet implemented
    92  	case 0x50:
    93  		return nd.SelfPushHandler(msg)
    94  	*/
    95  
    96  	case 0x60: //Tower Messages
    97  		if msg.MsgType() == lnutil.MSGID_WATCH_DESC {
    98  			return nd.Tower.NewChannel(msg.(lnutil.WatchDescMsg))
    99  		}
   100  		if msg.MsgType() == lnutil.MSGID_WATCH_STATEMSG {
   101  			return nd.Tower.UpdateChannel(msg.(lnutil.WatchStateMsg))
   102  		}
   103  		if msg.MsgType() == lnutil.MSGID_WATCH_DELETE {
   104  			return nd.Tower.DeleteChannel(msg.(lnutil.WatchDelMsg))
   105  		}
   106  
   107  	case 0x70: // Routing messages
   108  		if msg.MsgType() == lnutil.MSGID_LINK_DESC {
   109  			nd.LinkMsgHandler(msg.(lnutil.LinkMsg))
   110  		}
   111  		if msg.MsgType() == lnutil.MSGID_PAY_REQ {
   112  			return nd.MultihopPaymentRequestHandler(msg.(lnutil.MultihopPaymentRequestMsg))
   113  		}
   114  		if msg.MsgType() == lnutil.MSGID_PAY_ACK {
   115  			return nd.MultihopPaymentAckHandler(msg.(lnutil.MultihopPaymentAckMsg))
   116  		}
   117  		if msg.MsgType() == lnutil.MSGID_PAY_SETUP {
   118  			return nd.MultihopPaymentSetupHandler(msg.(lnutil.MultihopPaymentSetupMsg))
   119  		}
   120  
   121  	case 0xA0: // Dual Funding messages
   122  		return nd.DualFundingHandler(msg, peer)
   123  
   124  	case 0x90: // Discreet log contract messages
   125  		if msg.MsgType() == lnutil.MSGID_DLC_OFFER {
   126  			nd.DlcOfferHandler(msg.(lnutil.DlcOfferMsg), peer)
   127  		}
   128  		if msg.MsgType() == lnutil.MSGID_DLC_ACCEPTOFFER {
   129  			return nd.DlcAcceptHandler(msg.(lnutil.DlcOfferAcceptMsg), peer)
   130  		}
   131  		if msg.MsgType() == lnutil.MSGID_DLC_DECLINEOFFER {
   132  			nd.DlcDeclineHandler(msg.(lnutil.DlcOfferDeclineMsg), peer)
   133  		}
   134  		if msg.MsgType() == lnutil.MSGID_DLC_CONTRACTACK {
   135  			nd.DlcContractAckHandler(msg.(lnutil.DlcContractAckMsg), peer)
   136  		}
   137  		if msg.MsgType() == lnutil.MSGID_DLC_CONTRACTFUNDINGSIGS {
   138  			nd.DlcFundingSigsHandler(
   139  				msg.(lnutil.DlcContractFundingSigsMsg), peer)
   140  		}
   141  		if msg.MsgType() == lnutil.MSGID_DLC_SIGPROOF {
   142  			nd.DlcSigProofHandler(msg.(lnutil.DlcContractSigProofMsg), peer)
   143  		}
   144  
   145  	case 0xB0: // remote control
   146  		if msg.MsgType() == lnutil.MSGID_REMOTE_RPCREQUEST {
   147  			nd.RemoteControlRequestHandler(msg.(lnutil.RemoteControlRpcRequestMsg), peer)
   148  		}
   149  		if msg.MsgType() == lnutil.MSGID_REMOTE_RPCRESPONSE {
   150  			nd.RemoteControlResponseHandler(msg.(lnutil.RemoteControlRpcResponseMsg), peer)
   151  		}
   152  	default:
   153  		return fmt.Errorf("Unknown message id byte %x &f0", msg.MsgType())
   154  
   155  	}
   156  	return nil
   157  }
   158  
   159  func (nd *LitNode) PopulateQchanMap(peer *RemotePeer) error {
   160  	allQs, err := nd.GetAllQchans()
   161  	if err != nil {
   162  		return err
   163  	}
   164  	// initialize map
   165  	nd.RemoteMtx.Lock()
   166  	peer.QCs = make(map[uint32]*Qchan)
   167  	// populate from all channels (inefficient)
   168  	for i, q := range allQs {
   169  		if q.Peer() == peer.Idx {
   170  			peer.QCs[q.Idx()] = allQs[i]
   171  		}
   172  	}
   173  	nd.RemoteMtx.Unlock()
   174  	return nil
   175  }
   176  
   177  func (nd *LitNode) ChannelHandler(msg lnutil.LitMsg, peer *RemotePeer) error {
   178  	if nd.InProgDual.PeerIdx != 0 { // a dual funding is in progress
   179  		nd.DualFundingHandler(msg, peer)
   180  		return nil
   181  	}
   182  
   183  	switch message := msg.(type) {
   184  	case lnutil.PointReqMsg: // POINT REQUEST
   185  		logging.Infof("Got point request from %x\n", message.Peer())
   186  		nd.PointReqHandler(message)
   187  		return nil
   188  
   189  	case lnutil.PointRespMsg: // POINT RESPONSE
   190  		logging.Infof("Got point response from %x\n", msg.Peer())
   191  		return nd.PointRespHandler(message)
   192  
   193  	case lnutil.ChanDescMsg: // CHANNEL DESCRIPTION
   194  		logging.Infof("Got channel description from %x\n", msg.Peer())
   195  
   196  		return nd.QChanDescHandler(message)
   197  
   198  	case lnutil.ChanAckMsg: // CHANNEL ACKNOWLEDGE
   199  		logging.Infof("Got channel acknowledgement from %x\n", msg.Peer())
   200  
   201  		nd.QChanAckHandler(message, peer)
   202  		return nil
   203  
   204  	case lnutil.SigProofMsg: // HERE'S YOUR CHANNEL
   205  		logging.Infof("Got channel proof from %x\n", msg.Peer())
   206  		nd.SigProofHandler(message, peer)
   207  		return nil
   208  
   209  	default:
   210  		return fmt.Errorf("Unknown message type %x", msg.MsgType())
   211  	}
   212  
   213  }
   214  
   215  func (nd *LitNode) DualFundingHandler(msg lnutil.LitMsg, peer *RemotePeer) error {
   216  	switch message := msg.(type) {
   217  	case lnutil.DualFundingReqMsg: // DUAL FUNDING REQUEST
   218  		logging.Infof("Got dual funding request from %x\n", message.Peer())
   219  		nd.DualFundingReqHandler(message)
   220  		return nil
   221  
   222  	case lnutil.DualFundingAcceptMsg: // DUAL FUNDING ACCEPT
   223  		logging.Infof("Got dual funding acceptance from %x\n", msg.Peer())
   224  		nd.DualFundingAcceptHandler(message)
   225  		return nil
   226  
   227  	case lnutil.DualFundingDeclMsg: // DUAL FUNDING DECLINE
   228  		logging.Infof("Got dual funding decline from %x\n", msg.Peer())
   229  		nd.DualFundingDeclHandler(message)
   230  		return nil
   231  
   232  	case lnutil.ChanDescMsg: // CHANNEL DESCRIPTION
   233  		logging.Infof("Got (dual funding) channel description from %x\n", msg.Peer())
   234  		nd.DualFundChanDescHandler(message)
   235  		return nil
   236  
   237  	case lnutil.DualFundingChanAckMsg: // CHANNEL ACKNOWLEDGE
   238  		logging.Infof("Got (dual funding) channel acknowledgement from %x\n", msg.Peer())
   239  
   240  		nd.DualFundChanAckHandler(message, peer)
   241  		return nil
   242  
   243  	case lnutil.SigProofMsg: // HERE'S YOUR CHANNEL
   244  		logging.Infof("Got (dual funding) channel proof from %x\n", msg.Peer())
   245  		nd.DualFundSigProofHandler(message, peer)
   246  		return nil
   247  
   248  	default:
   249  		return fmt.Errorf("Unknown message type %x", msg.MsgType())
   250  	}
   251  
   252  }
   253  
   254  func (nd *LitNode) CloseHandler(msg lnutil.LitMsg) error {
   255  	switch message := msg.(type) { // CLOSE REQ
   256  
   257  	case lnutil.CloseReqMsg:
   258  		logging.Infof("Got close request from %x\n", msg.Peer())
   259  		nd.CloseReqHandler(message)
   260  		return nil
   261  
   262  	/* - not yet implemented
   263  	case lnutil.MSGID_CLOSERESP: // CLOSE RESP
   264  		logging.Infof("Got close response from %x\n", from)
   265  		nd.CloseRespHandler(from, msg[1:])
   266  		continue
   267  		return nil
   268  	*/
   269  	default:
   270  		return fmt.Errorf("Unknown message type %x", msg.MsgType())
   271  	}
   272  
   273  }
   274  
   275  // need a go routine for each qchan.
   276  
   277  func (nd *LitNode) PushPullHandler(routedMsg lnutil.LitMsg, q *Qchan) error {
   278  	q.ChanMtx.Lock()
   279  	defer q.ChanMtx.Unlock()
   280  	switch message := routedMsg.(type) {
   281  	case lnutil.DeltaSigMsg:
   282  		logging.Infof("Got DELTASIG from %x\n", routedMsg.Peer())
   283  		return nd.DeltaSigHandler(message, q)
   284  
   285  	case lnutil.SigRevMsg: // SIGNATURE AND REVOCATION
   286  		logging.Infof("Got SIGREV from %x\n", routedMsg.Peer())
   287  		return nd.SigRevHandler(message, q)
   288  
   289  	case lnutil.GapSigRevMsg: // GAP SIGNATURE AND REVOCATION
   290  		logging.Infof("Got GapSigRev from %x\n", routedMsg.Peer())
   291  		return nd.GapSigRevHandler(message, q)
   292  
   293  	case lnutil.RevMsg: // REVOCATION
   294  		logging.Infof("Got REV from %x\n", routedMsg.Peer())
   295  		return nd.RevHandler(message, q)
   296  
   297  	case lnutil.HashSigMsg: // Offer HTLC
   298  		logging.Infof("Got HashSig from %d", routedMsg.Peer())
   299  		return nd.HashSigHandler(message, q)
   300  
   301  	case lnutil.PreimageSigMsg: // Clear HTLC
   302  		logging.Infof("Got PreimageSig from %d", routedMsg.Peer())
   303  		return nd.PreimageSigHandler(message, q)
   304  
   305  	default:
   306  		return fmt.Errorf("Unknown message type %x", routedMsg.MsgType())
   307  
   308  	}
   309  
   310  }
   311  
   312  func (nd *LitNode) FWDHandler(msg lnutil.LitMsg) error { // not yet implemented
   313  	switch message := msg.(type) {
   314  	default:
   315  		return fmt.Errorf("Unknown message type %x", message.MsgType())
   316  	}
   317  }
   318  
   319  func (nd *LitNode) SelfPushHandler(msg lnutil.LitMsg) error { // not yet implemented
   320  	switch message := msg.(type) {
   321  	default:
   322  		return fmt.Errorf("Unknown message type %x", message.MsgType())
   323  	}
   324  }
   325  
   326  // OPEventHandler gets outpoint events from the base wallet,
   327  // and modifies the ln node db to reflect confirmations.  Can also respond
   328  // with exporting txos to the base wallet, or penalty txs.
   329  func (nd *LitNode) OPEventHandler(OPEventChan chan lnutil.OutPointEvent) {
   330  	for {
   331  		curOPEvent := <-OPEventChan
   332  		// get all channels each time.  This is very inefficient!
   333  		qcs, err := nd.GetAllQchans()
   334  		if err != nil {
   335  			logging.Errorf("ln db error: %s", err.Error())
   336  			continue
   337  		}
   338  		var theQ *Qchan
   339  		for _, q := range qcs {
   340  			if lnutil.OutPointsEqual(q.Op, curOPEvent.Op) {
   341  				theQ = q
   342  			}
   343  		}
   344  
   345  		var theC *lnutil.DlcContract
   346  
   347  		if theQ == nil {
   348  			// Check if this is a contract output
   349  			contracts, err := nd.DlcManager.ListContracts()
   350  			if err != nil {
   351  				logging.Errorf("contract db error: %s\n", err.Error())
   352  				continue
   353  			}
   354  			for _, c := range contracts {
   355  				if lnutil.OutPointsEqual(c.FundingOutpoint, curOPEvent.Op) {
   356  					theC = c
   357  				}
   358  			}
   359  		}
   360  
   361  		if theC != nil {
   362  			err := nd.HandleContractOPEvent(theC, &curOPEvent)
   363  			if err != nil {
   364  				logging.Errorf("HandleContractOPEvent error: %s\n", err.Error())
   365  			}
   366  			continue
   367  		}
   368  
   369  		if theQ == nil && curOPEvent.Tx != nil {
   370  			// Check if this is a HTLC output we're watching
   371  			h, _, err := nd.GetHTLC(&curOPEvent.Op)
   372  			if err != nil {
   373  				logging.Errorf("Error Getting HTLC OPHash: %s\n", err.Error())
   374  			}
   375  			if h.Idx == 0 && h.Amt == 0 { // empty HTLC, so none found
   376  				continue
   377  			}
   378  
   379  			logging.Infof("Got OP event for HTLC output %s [Incoming: %t]\n", curOPEvent.Op.String(), h.Incoming)
   380  			// Check the witness stack for a preimage
   381  			for _, txi := range curOPEvent.Tx.TxIn {
   382  
   383  				var preimage [16]byte
   384  				preimageFound := false
   385  				if len(txi.Witness) == 5 && len(txi.Witness[0]) == 0 && len(txi.Witness[3]) == 16 {
   386  					// Success transaction from their break TX, multisig. Preimage is fourth on the witness stack.
   387  					copy(preimage[:], txi.Witness[3])
   388  					preimageFound = true
   389  				}
   390  				if len(txi.Witness) == 3 && len(txi.Witness[1]) == 16 {
   391  					// Success transaction from their break TX, multisig. Preimage is fourth on the witness stack.
   392  					copy(preimage[:], txi.Witness[1])
   393  					preimageFound = true
   394  				}
   395  
   396  				if preimageFound {
   397  					logging.Infof("Found preimage [%x] in this TX, looking for HTLCs i have that are claimable with that\n", preimage)
   398  					// try claiming it!
   399  					nd.ClaimHTLC(preimage)
   400  				}
   401  			}
   402  
   403  			continue
   404  		}
   405  
   406  		// end if no associated channel
   407  		if theQ == nil {
   408  			logging.Infof("OPEvent %s doesn't match any channel\n",
   409  				curOPEvent.Op.String())
   410  			continue
   411  		}
   412  
   413  		// confirmation event
   414  		if curOPEvent.Tx == nil {
   415  			logging.Infof("OP %s Confirmation event\n", curOPEvent.Op.String())
   416  			theQ.Height = curOPEvent.Height
   417  			err = nd.SaveQchanUtxoData(theQ)
   418  			if err != nil {
   419  				logging.Errorf("SaveQchanUtxoData error: %s", err.Error())
   420  				continue
   421  			}
   422  			// spend event (note: happens twice!)
   423  
   424  			if theQ.Height > 0 {
   425  				logging.Debugf("Second time this is confirmed, send out real confirm event")
   426  
   427  				// TODO: abstract important channel things into a channel manager type of thing
   428  				peerIdx := theQ.Peer()
   429  				peer := nd.PeerMan.GetPeerByIdx(int32(peerIdx))
   430  				if peer == nil {
   431  					logging.Errorf("Please use errors in peermanager rather than just returning could be nil or 0 or something else")
   432  				} else {
   433  					confirmEvent := ChannelStateUpdateEvent{
   434  						Action:   "opconfirm",
   435  						ChanIdx:  theQ.Idx(),
   436  						State:    theQ.State,
   437  						TheirPub: peer.GetPubkey(),
   438  						CoinType: theQ.Coin(),
   439  					}
   440  
   441  					if succeed, err := nd.Events.Publish(confirmEvent); err != nil {
   442  						logging.Errorf("ConfirmHandler publish err %s", err)
   443  						return
   444  					} else if !succeed {
   445  						logging.Errorf("ConfirmHandler publish did not succeed")
   446  						return
   447  					}
   448  				}
   449  			}
   450  
   451  		} else {
   452  			logging.Infof("OP %s Spend event\n", curOPEvent.Op.String())
   453  			// mark channel as closed
   454  			theQ.CloseData.Closed = true
   455  			theQ.CloseData.CloseTxid = curOPEvent.Tx.TxHash()
   456  			theQ.CloseData.CloseHeight = curOPEvent.Height
   457  			err = nd.SaveQchanUtxoData(theQ)
   458  			if err != nil {
   459  				logging.Errorf("SaveQchanUtxoData error: %s", err.Error())
   460  				continue
   461  			}
   462  
   463  			// detect close tx outs.
   464  			txos, err := theQ.GetCloseTxos(curOPEvent.Tx)
   465  			if err != nil {
   466  				logging.Errorf("GetCloseTxos error: %s", err.Error())
   467  				continue
   468  			}
   469  
   470  			// if you have seq=1 txos, modify the privkey...
   471  			// pretty ugly as we need the private key to do that.
   472  			for _, ptxo := range txos {
   473  				if ptxo.Seq == 1 { // revoked key
   474  					// GetCloseTxos returns a porTxo with the elk scalar in the
   475  					// privkey field.  It isn't just added though; it needs to
   476  					// be combined with the private key in a way porTxo isn't
   477  					// aware of, so derive and subtract that here.
   478  					var elkScalar [32]byte
   479  					// swap out elkscalar, leaving privkey empty
   480  					elkScalar, ptxo.KeyGen.PrivKey =
   481  						ptxo.KeyGen.PrivKey, elkScalar
   482  
   483  					privBase, err := nd.SubWallet[theQ.Coin()].GetPriv(ptxo.KeyGen)
   484  					if err != nil {
   485  						continue // or return?
   486  					}
   487  
   488  					ptxo.PrivKey = lnutil.CombinePrivKeyAndSubtract(
   489  						privBase, elkScalar[:])
   490  				}
   491  				// make this concurrent to avoid circular locking
   492  				go func(porTxo portxo.PorTxo) {
   493  					nd.SubWallet[theQ.Coin()].ExportUtxo(&porTxo)
   494  				}(ptxo)
   495  			}
   496  
   497  			// Fetch the indexes of HTLC outputs, and then register them to be watched
   498  			// We can monitor this for spends from an HTLC output that contains a preimage
   499  			// and then use that preimage to claim any HTLCs we have outstanding.
   500  			_, htlcIdxes, err := theQ.GetHtlcTxos(curOPEvent.Tx, false)
   501  			if err != nil {
   502  				logging.Errorf("GetHtlcTxos error: %s", err.Error())
   503  				continue
   504  			}
   505  			_, htlcOurIdxes, err := theQ.GetHtlcTxos(curOPEvent.Tx, true)
   506  			if err != nil {
   507  				logging.Errorf("GetHtlcTxos error: %s", err.Error())
   508  				continue
   509  			}
   510  			htlcIdxes = append(htlcIdxes, htlcOurIdxes...)
   511  			txHash := curOPEvent.Tx.TxHash()
   512  			for _, i := range htlcIdxes {
   513  				op := wire.NewOutPoint(&txHash, i)
   514  				logging.Infof("Watching for spends from [%s] (HTLC)\n", op.String())
   515  				nd.SubWallet[theQ.Coin()].WatchThis(*op)
   516  			}
   517  		}
   518  	}
   519  }
   520  
   521  func (nd *LitNode) HeightEventHandler(HeightEventChan chan lnutil.HeightEvent) {
   522  	for {
   523  		event := <-HeightEventChan
   524  		txs, err := nd.ClaimHTLCTimeouts(event.CoinType, event.Height)
   525  		if err != nil {
   526  			logging.Errorf("Error while claiming HTLC timeouts for coin %d at height %d : %s\n", event.CoinType, event.Height, err.Error())
   527  		} else {
   528  			for _, tx := range txs {
   529  				logging.Infof("Claimed timeout HTLC using TXID %x\n", tx)
   530  			}
   531  		}
   532  	}
   533  }
   534  
   535  func (nd *LitNode) HandleContractOPEvent(c *lnutil.DlcContract,
   536  	opEvent *lnutil.OutPointEvent) error {
   537  
   538  	logging.Infof("Received OPEvent for contract %d!\n", c.Idx)
   539  	if opEvent.Tx != nil {
   540  		wal, ok := nd.SubWallet[c.CoinType]
   541  		if !ok {
   542  			return fmt.Errorf("Could not find associated wallet"+
   543  				" for type %d", c.CoinType)
   544  		}
   545  
   546  		pkhIsMine := false
   547  		pkhIdx := uint32(0)
   548  		value := int64(0)
   549  		myPKHPkSript := lnutil.DirectWPKHScriptFromPKH(c.OurPayoutPKH)
   550  		for i, out := range opEvent.Tx.TxOut {
   551  			if bytes.Equal(myPKHPkSript, out.PkScript) {
   552  				pkhIdx = uint32(i)
   553  				pkhIsMine = true
   554  				value = out.Value
   555  			}
   556  		}
   557  
   558  		if pkhIsMine {
   559  			c.Status = lnutil.ContractStatusSettling
   560  			err := nd.DlcManager.SaveContract(c)
   561  			if err != nil {
   562  				logging.Errorf("HandleContractOPEvent SaveContract err %s\n", err.Error())
   563  				return err
   564  			}
   565  
   566  			// We need to claim this.
   567  			txClaim := wire.NewMsgTx()
   568  			txClaim.Version = 2
   569  
   570  			settleOutpoint := wire.OutPoint{Hash: opEvent.Tx.TxHash(), Index: pkhIdx}
   571  			txClaim.AddTxIn(wire.NewTxIn(&settleOutpoint, nil, nil))
   572  
   573  			addr, err := wal.NewAdr()
   574  			if err != nil {
   575  				return err
   576  			}
   577  			txClaim.AddTxOut(wire.NewTxOut(value-500,
   578  				lnutil.DirectWPKHScriptFromPKH(addr))) // todo calc fee
   579  
   580  			var kg portxo.KeyGen
   581  			kg.Depth = 5
   582  			kg.Step[0] = 44 | 1<<31
   583  			kg.Step[1] = c.CoinType | 1<<31
   584  			kg.Step[2] = UseContractPayoutPKH
   585  			kg.Step[3] = c.PeerIdx | 1<<31
   586  			kg.Step[4] = uint32(c.Idx) | 1<<31
   587  			priv, _ := wal.GetPriv(kg)
   588  
   589  			// make hash cache
   590  			hCache := txscript.NewTxSigHashes(txClaim)
   591  
   592  			// generate sig
   593  			txClaim.TxIn[0].Witness, err = txscript.WitnessScript(txClaim,
   594  				hCache, 0, value, myPKHPkSript, txscript.SigHashAll, priv, true)
   595  
   596  			if err != nil {
   597  				return err
   598  			}
   599  			wal.DirectSendTx(txClaim)
   600  
   601  			c.Status = lnutil.ContractStatusClosed
   602  			err = nd.DlcManager.SaveContract(c)
   603  			if err != nil {
   604  				return err
   605  			}
   606  		}
   607  
   608  	}
   609  	return nil
   610  }