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

     1  package qln
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/boltdb/bolt"
    11  	"github.com/mit-dci/lit/crypto/koblitz"
    12  	"github.com/mit-dci/lit/dlc"
    13  	"github.com/mit-dci/lit/eventbus"
    14  	"github.com/mit-dci/lit/lncore"
    15  	"github.com/mit-dci/lit/lndc"
    16  	"github.com/mit-dci/lit/lnp2p"
    17  	"github.com/mit-dci/lit/lnutil"
    18  	"github.com/mit-dci/lit/logging"
    19  	"github.com/mit-dci/lit/watchtower"
    20  	"github.com/mit-dci/lit/wire"
    21  )
    22  
    23  /*
    24  Channels (& multisig) go in the DB here.
    25  first there's the peer bucket.
    26  
    27  Here's the structure:
    28  
    29  Peers
    30  |
    31  |- peerID (33 byte pubkey)
    32  	|
    33  	|- index (4 bytes)
    34  	|
    35  	|- hostname...?
    36  	|
    37  	|- channels..?
    38  
    39  
    40  PeerMap
    41  |
    42  |-peerIdx(4) : peerPubkey(33)
    43  
    44  ChannelMap
    45  |
    46  |-chanIdx(4) : channelID (36 byte outpoint)
    47  
    48  
    49  Right now these buckets are all in one boltDB.  This limits it to one db write
    50  at a time, which for super high thoughput could be too slow.
    51  Later on we can chop it up so that each channel gets it's own db file.
    52  
    53  
    54  MultiWallit:
    55  
    56  One LitNode can have a bunch of SubWallets.  This is useful if you want to
    57  have both testnet3 and regtest channels active simultaneously.
    58  The SubWallet is a map of uint32s to Uwallet interfaces.  The identifier for the
    59  channel is the coin's HDCoinType, which is available from the params.
    60  
    61  I said regtest is 257 because it's not defined in a BIP, and set to 1
    62  (collision w/ testnet3) in the btcsuite code.
    63  
    64  Other coins could use SLIP-44, which will be IPV4 all over again as people
    65  make millions of pointless altcoins to grab that address space.
    66  
    67  Since usually there is only 1 wallit connected, there is a DefaultWallet
    68  which functions can use if the wallet is not specified.  The first wallet
    69  to get attached to DefaultWallet.  There is also a bool MultiWallet which is
    70  false while there is only 1 wallet, and true once there are more than one
    71  wallets connected.
    72  
    73  You can't remove wallets once they're attached; just restart instead.
    74  
    75  */
    76  
    77  // LitNode is the main struct for the node, keeping track of all channel state and
    78  // communicating with the underlying UWallet
    79  type LitNode struct {
    80  	LitDB *bolt.DB // place to write all this down
    81  
    82  	NewLitDB lncore.LitStorage
    83  
    84  	LitFolder string // path to save stuff
    85  
    86  	IdentityKey *koblitz.PrivateKey
    87  
    88  	// p2p remote control key
    89  	DefaultRemoteControlKey *koblitz.PublicKey
    90  
    91  	// event bus
    92  	Events *eventbus.EventBus
    93  
    94  	// Networking
    95  	PeerMan *lnp2p.PeerManager
    96  
    97  	// all nodes have a watchtower.  but could have a tower without a node
    98  	Tower watchtower.Watcher
    99  
   100  	// discreet log contract manager
   101  	DlcManager *dlc.DlcManager
   102  
   103  	// BaseWallet is the underlying wallet which keeps track of utxos, secrets,
   104  	// and network i/o
   105  	// map of cointypes to wallets
   106  	SubWallet map[uint32]UWallet
   107  	// indicates if multiple wallets are connected
   108  	MultiWallet bool
   109  	// cointype of the first (possibly only) wallet connected
   110  	DefaultCoin uint32
   111  
   112  	ConnectedCoinTypes map[uint32]bool
   113  	RemoteCons         map[uint32]*RemotePeer
   114  	RemoteMtx          sync.Mutex
   115  
   116  	// the current channel that in the process of being created
   117  	// (1 at a time for now)
   118  	InProg *InFlightFund
   119  
   120  	// the current channel in process of being dual funded
   121  	InProgDual *InFlightDualFund
   122  
   123  	// Nodes don't have Params; their SubWallets do
   124  	// Param *coinparam.Params // network parameters (testnet3, segnet, etc)
   125  
   126  	// queue for async messages to RPC user
   127  	UserMessageBox chan string
   128  
   129  	// The URL from which lit attempts to resolve the LN address
   130  	TrackerURL string
   131  
   132  	ChannelMap    map[[20]byte][]LinkDesc
   133  	ChannelMapMtx sync.Mutex
   134  	AdvTimeout    *time.Ticker
   135  
   136  	RPC interface{}
   137  
   138  	// Contains the URL string to connect to a SOCKS5 proxy, if provided
   139  	ProxyURL string
   140  	Nat      string
   141  
   142  	InProgMultihop []*InFlightMultihop
   143  	MultihopMutex  sync.Mutex
   144  
   145  	ExchangeRates map[uint32][]lnutil.RateDesc
   146  
   147  	// REFACTORING FIELDS
   148  	PeerMap    map[*lnp2p.Peer]*RemotePeer // we never remove things from here, so this is a memory leak
   149  	PeerMapMtx *sync.Mutex
   150  }
   151  
   152  type LinkDesc struct {
   153  	Link  lnutil.LinkMsg
   154  	Dirty bool
   155  }
   156  
   157  type InFlightMultihop struct {
   158  	Path      []lnutil.RouteHop
   159  	Amt       int64
   160  	HHash     [32]byte
   161  	PreImage  [16]byte
   162  	Succeeded bool
   163  }
   164  
   165  func (p *InFlightMultihop) Bytes() []byte {
   166  	var buf bytes.Buffer
   167  
   168  	wire.WriteVarInt(&buf, 0, uint64(len(p.Path)))
   169  	for _, nd := range p.Path {
   170  		buf.Write(nd.Bytes())
   171  	}
   172  
   173  	wire.WriteVarInt(&buf, 0, uint64(p.Amt))
   174  
   175  	buf.Write(p.HHash[:])
   176  	buf.Write(p.PreImage[:])
   177  
   178  	binary.Write(&buf, binary.BigEndian, p.Succeeded)
   179  
   180  	return buf.Bytes()
   181  }
   182  
   183  func InFlightMultihopFromBytes(b []byte) (*InFlightMultihop, error) {
   184  	mh := new(InFlightMultihop)
   185  
   186  	buf := bytes.NewBuffer(b) // get rid of messageType
   187  
   188  	hops, _ := wire.ReadVarInt(buf, 0)
   189  	for i := uint64(0); i < hops; i++ {
   190  		hop, err := lnutil.NewRouteHopFromBytes(buf.Next(24))
   191  		if err != nil {
   192  			return nil, err
   193  		}
   194  
   195  		mh.Path = append(mh.Path, *hop)
   196  	}
   197  	amount, _ := wire.ReadVarInt(buf, 0)
   198  	mh.Amt = int64(amount)
   199  
   200  	copy(mh.HHash[:], buf.Next(32))
   201  	copy(mh.PreImage[:], buf.Next(16))
   202  
   203  	err := binary.Read(buf, binary.BigEndian, &mh.Succeeded)
   204  	if err != nil {
   205  		return mh, err
   206  	}
   207  
   208  	return mh, nil
   209  }
   210  
   211  type RemotePeer struct {
   212  	Idx      uint32 // the peer index
   213  	Nickname string
   214  	Con      *lndc.Conn
   215  	QCs      map[uint32]*Qchan   // keep map of all peer's channels in ram
   216  	OpMap    map[[36]byte]uint32 // quick lookup for channels
   217  }
   218  
   219  // InFlightFund is a funding transaction that has not yet been broadcast
   220  type InFlightFund struct {
   221  	PeerIdx, ChanIdx, Coin uint32
   222  	Amt, InitSend          int64
   223  
   224  	op *wire.OutPoint
   225  
   226  	done chan uint32
   227  	// use this to avoid crashiness
   228  	mtx sync.Mutex
   229  
   230  	Data [32]byte
   231  }
   232  
   233  func (inff *InFlightFund) Clear() {
   234  	inff.PeerIdx = 0
   235  	inff.ChanIdx = 0
   236  
   237  	inff.Amt = 0
   238  	inff.InitSend = 0
   239  }
   240  
   241  // InFlightDualFund is a dual funding transaction that has not yet been broadcast
   242  type InFlightDualFund struct {
   243  	PeerIdx, ChanIdx, CoinType              uint32
   244  	OurAmount, TheirAmount                  int64
   245  	OurInputs, TheirInputs                  []lnutil.DualFundingInput
   246  	OurChangeAddress, TheirChangeAddress    [20]byte
   247  	OurPub, OurRefundPub, OurHAKDBase       [33]byte
   248  	TheirPub, TheirRefundPub, TheirHAKDBase [33]byte
   249  	OurNextHTLCBase, OurN2HTLCBase          [33]byte
   250  	TheirNextHTLCBase, TheirN2HTLCBase      [33]byte
   251  	OurSignatures, TheirSignatures          [][60]byte
   252  	InitiatedByUs                           bool
   253  	OutPoint                                *wire.OutPoint
   254  	done                                    chan *DualFundingResult
   255  	mtx                                     sync.Mutex
   256  }
   257  
   258  type DualFundingResult struct {
   259  	ChannelId     uint32
   260  	Error         bool
   261  	Accepted      bool
   262  	DeclineReason uint8
   263  }
   264  
   265  func (inff *InFlightDualFund) Clear() {
   266  	inff.PeerIdx = 0
   267  	inff.ChanIdx = 0
   268  	inff.OurAmount = 0
   269  	inff.TheirAmount = 0
   270  	inff.OurInputs = nil
   271  	inff.TheirInputs = nil
   272  	inff.OurChangeAddress = [20]byte{}
   273  	inff.TheirChangeAddress = [20]byte{}
   274  	inff.OurPub = [33]byte{}
   275  	inff.OurRefundPub = [33]byte{}
   276  	inff.OurHAKDBase = [33]byte{}
   277  	inff.TheirPub = [33]byte{}
   278  	inff.TheirRefundPub = [33]byte{}
   279  	inff.TheirHAKDBase = [33]byte{}
   280  	inff.OurNextHTLCBase = [33]byte{}
   281  	inff.OurN2HTLCBase = [33]byte{}
   282  	inff.TheirNextHTLCBase = [33]byte{}
   283  	inff.TheirN2HTLCBase = [33]byte{}
   284  
   285  	inff.OurSignatures = nil
   286  	inff.TheirSignatures = nil
   287  	inff.InitiatedByUs = false
   288  }
   289  
   290  // GetLnAddr gets the lightning address for this node.
   291  func (nd *LitNode) GetLnAddr() string {
   292  	return nd.PeerMan.GetExternalAddress()
   293  }
   294  
   295  // GetPubHostFromPeerIdx gets the pubkey and internet host name for a peer
   296  func (nd *LitNode) GetPubHostFromPeerIdx(idx uint32) ([33]byte, string) {
   297  	var pub [33]byte
   298  	var host string
   299  
   300  	p := nd.PeerMan.GetPeerByIdx(int32(idx))
   301  	if p != nil {
   302  		pk := p.GetPubkey()
   303  		copy(pub[:], pk.SerializeCompressed())
   304  		host = p.GetRemoteAddr()
   305  	}
   306  
   307  	return pub, host
   308  }
   309  
   310  // GetNicknameFromPeerIdx gets the nickname for a peer
   311  func (nd *LitNode) GetNicknameFromPeerIdx(idx uint32) string {
   312  	var nickname string
   313  
   314  	p := nd.PeerMan.GetPeerByIdx(int32(idx))
   315  	if p != nil {
   316  		nickname = p.GetNickname()
   317  	}
   318  
   319  	return nickname
   320  }
   321  
   322  // NextIdx returns the next channel index to use.
   323  func (nd *LitNode) NextChannelIdx() (uint32, error) {
   324  	var cIdx uint32
   325  	err := nd.LitDB.View(func(btx *bolt.Tx) error {
   326  		cmp := btx.Bucket(BKTChanMap)
   327  		if cmp == nil {
   328  			return fmt.Errorf("NextIdxForPeer: no ChanMap")
   329  		}
   330  
   331  		cIdx = uint32(cmp.Stats().KeyN + 1)
   332  		return nil
   333  	})
   334  	if err != nil {
   335  		return 0, err
   336  	}
   337  
   338  	return cIdx, nil
   339  }
   340  
   341  // SaveNicknameForPeerIdx saves/overwrites a nickname for a given peer idx
   342  func (nd *LitNode) SaveNicknameForPeerIdx(nickname string, idx uint32) error {
   343  
   344  	peer := nd.PeerMan.GetPeerByIdx(int32(idx))
   345  	if peer == nil {
   346  		return fmt.Errorf("invalid peer ID %d", idx)
   347  	}
   348  
   349  	// Actually go and set it.
   350  	pi := peer.IntoPeerInfo()
   351  	err := nd.NewLitDB.GetPeerDB().AddPeer(peer.GetLnAddr(), pi)
   352  
   353  	return err // same as if err != nil { return err } ; return nil
   354  }
   355  
   356  // SaveQchanUtxoData saves utxo data such as outpoint and close tx / status.
   357  func (nd *LitNode) SaveQchanUtxoData(q *Qchan) error {
   358  	logging.Warnln("someone tried to SaveQchanUtxoData, doing some hacks to make it save only parts of it")
   359  
   360  	// XXX This is a horrible hack and we need to change other code to not be
   361  	// dependent on the way this data is saved/loaded.
   362  	opArr := lnutil.OutPointToBytes(q.Op)
   363  	fq, err := nd.GetQchan(opArr)
   364  	if err != nil {
   365  		return nil
   366  	}
   367  	fq.PorTxo = q.PorTxo
   368  
   369  	// we also quietly save close data when we call this function
   370  	if q.CloseData.Closed {
   371  		fq.CloseData = q.CloseData
   372  	}
   373  
   374  	return nd.SaveQChan(fq)
   375  }
   376  
   377  // register a new Qchan in the db
   378  func (nd *LitNode) SaveQChan(q *Qchan) error {
   379  	if q == nil {
   380  		return fmt.Errorf("SaveQChan: nil qchan")
   381  	}
   382  
   383  	opArr := lnutil.OutPointToBytes(q.Op)
   384  	cIdBytes := lnutil.U32tB(q.Idx())
   385  
   386  	qdata := nd.QchanSerializeToBytes(q)
   387  
   388  	// save channel to db.  It has no state, and has no outpoint yet
   389  	err := nd.LitDB.Update(func(btx *bolt.Tx) error {
   390  		var err error
   391  
   392  		cdb := btx.Bucket(BKTChannelData)
   393  		if cdb == nil {
   394  			return fmt.Errorf("channel data bucket not found")
   395  		}
   396  
   397  		cmb := btx.Bucket(BKTChanMap)
   398  		if cmb == nil {
   399  			return fmt.Errorf("channel map bucket not found")
   400  		}
   401  
   402  		// Save both the channel...
   403  		err = cdb.Put(opArr[:], qdata)
   404  		if err != nil {
   405  			return err
   406  		}
   407  
   408  		// ...and the channel ID mapping.
   409  		err = cmb.Put(cIdBytes[:], opArr[:])
   410  		if err != nil {
   411  			return err
   412  		}
   413  
   414  		return nil
   415  	})
   416  	if err != nil {
   417  		return err
   418  	}
   419  
   420  	return nil
   421  }
   422  
   423  // ReloadQchan loads updated data from the db into the qchan.  Loads elkrem
   424  // and state, but does not change qchan info itself.  Faster than GetQchan()
   425  // also reload the channel close state
   426  func (nd *LitNode) ReloadQchanState(qc *Qchan) error {
   427  	opArr := lnutil.OutPointToBytes(qc.Op)
   428  
   429  	return nd.LitDB.View(func(btx *bolt.Tx) error {
   430  		b := btx.Bucket(BKTChannelData)
   431  		if b == nil {
   432  			return fmt.Errorf("channel data bucket not found")
   433  		}
   434  
   435  		buf := b.Get(opArr[:])
   436  		if buf == nil {
   437  			return fmt.Errorf("channel not found in DB")
   438  		}
   439  		return nd.QchanUpdateFromBytes(qc, buf)
   440  	})
   441  }
   442  
   443  // Save / overwrite state of qChan in db
   444  // the descent into the qchan bucket is boilerplate and it'd be nice
   445  // if we can make that it's own function.  Get channel bucket maybe?  But then
   446  // you have to close it...
   447  func (nd *LitNode) SaveQchanState(q *Qchan) error {
   448  	logging.Warnln("someone called SaveQchanState, but this is deprecated.  doing some hacks to make it save just that.")
   449  
   450  	// XXX This is a horrible hack and we need to change other code to not be
   451  	// dependent on the way this data is saved/loaded.
   452  	opArr := lnutil.OutPointToBytes(q.Op)
   453  	fq, err := nd.GetQchan(opArr)
   454  	if err != nil {
   455  		return nil
   456  	}
   457  	fq.State = q.State
   458  
   459  	return nd.SaveQChan(fq)
   460  }
   461  
   462  // GetAllQchans returns a slice of all channels. empty slice is OK.
   463  func (nd *LitNode) GetAllQchans() ([]*Qchan, error) {
   464  	var qChans []*Qchan
   465  	err := nd.LitDB.View(func(btx *bolt.Tx) error {
   466  		b := btx.Bucket(BKTChannelData)
   467  		if b == nil {
   468  			return fmt.Errorf("channel data bucket not found")
   469  		}
   470  		return b.ForEach(func(_, buf []byte) error {
   471  			newQc, err := nd.QchanDeserializeFromBytes(buf)
   472  			if err != nil {
   473  				return err // should we not return this?
   474  			}
   475  
   476  			qChans = append(qChans, newQc)
   477  			return nil
   478  		})
   479  	})
   480  	if err != nil {
   481  		return nil, err
   482  	}
   483  	return qChans, nil
   484  }
   485  
   486  // GetQchan returns a single channel.
   487  // pubkey and outpoint bytes.
   488  func (nd *LitNode) GetQchan(opArr [36]byte) (*Qchan, error) {
   489  
   490  	var qc *Qchan
   491  	var err error
   492  	err = nd.LitDB.View(func(btx *bolt.Tx) error {
   493  
   494  		var err error
   495  
   496  		b := btx.Bucket(BKTChannelData)
   497  		if b == nil {
   498  			return fmt.Errorf("channel data bucket not found")
   499  		}
   500  
   501  		buf := b.Get(opArr[:])
   502  		if buf == nil {
   503  			return fmt.Errorf("channel not found in DB")
   504  		}
   505  
   506  		// Go has weird scoping rules, I hope this doesn't break things.
   507  		qc, err = nd.QchanDeserializeFromBytes(buf)
   508  		if err != nil {
   509  			return err
   510  		}
   511  
   512  		return nil
   513  	})
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  
   518  	return qc, nil
   519  }
   520  
   521  func (nd *LitNode) GetQchanOPfromIdx(cIdx uint32) ([36]byte, error) {
   522  	var rOp [36]byte
   523  	err := nd.LitDB.View(func(btx *bolt.Tx) error {
   524  		cmp := btx.Bucket(BKTChanMap)
   525  		if cmp == nil {
   526  			return fmt.Errorf("no channel map")
   527  		}
   528  		op := cmp.Get(lnutil.U32tB(cIdx))
   529  		if op == nil {
   530  			return fmt.Errorf("no channel %d in db", cIdx)
   531  		}
   532  		copy(rOp[:], op)
   533  		return nil
   534  	})
   535  	return rOp, err
   536  }
   537  
   538  // GetQchanByIdx is a gets the channel when you don't know the peer bytes and
   539  // outpoint.  Probably shouldn't have to use this if the UI is done right though.
   540  func (nd *LitNode) GetQchanByIdx(cIdx uint32) (*Qchan, error) {
   541  	op, err := nd.GetQchanOPfromIdx(cIdx)
   542  	if err != nil {
   543  		return nil, err
   544  	}
   545  	logging.Infof("got op %x\n", op)
   546  	qc, err := nd.GetQchan(op)
   547  	if err != nil {
   548  		return nil, err
   549  	}
   550  	return qc, nil
   551  }
   552  
   553  // SaveMultihopPayment saves a new (or updates an existing) multihop payment in the database
   554  func (nd *LitNode) SaveMultihopPayment(p *InFlightMultihop) error {
   555  	err := nd.LitDB.Update(func(btx *bolt.Tx) error {
   556  		cmp := btx.Bucket(BKTPayments)
   557  		if cmp == nil {
   558  			return fmt.Errorf("SaveMultihopPayment: no payments bucket")
   559  		}
   560  
   561  		// save hash : payment
   562  		err := cmp.Put(p.HHash[:], p.Bytes())
   563  		if err != nil {
   564  			return err
   565  		}
   566  
   567  		return nil
   568  	})
   569  	if err != nil {
   570  		return err
   571  	}
   572  
   573  	return nil
   574  }
   575  
   576  func (nd *LitNode) GetAllMultihopPayments() ([]*InFlightMultihop, error) {
   577  	var payments []*InFlightMultihop
   578  
   579  	err := nd.LitDB.View(func(btx *bolt.Tx) error {
   580  		bkt := btx.Bucket(BKTPayments)
   581  		if bkt == nil {
   582  			return fmt.Errorf("no payments bucket")
   583  		}
   584  
   585  		return bkt.ForEach(func(RHash []byte, paymentBytes []byte) error {
   586  			payment, err := InFlightMultihopFromBytes(paymentBytes)
   587  			if err != nil {
   588  				return err
   589  			}
   590  
   591  			// add to slice
   592  			payments = append(payments, payment)
   593  			return nil
   594  		})
   595  	})
   596  
   597  	return payments, err
   598  }