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

     1  package wallit
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"sync"
     8  
     9  	"github.com/boltdb/bolt"
    10  	"github.com/mit-dci/lit/btcutil"
    11  	"github.com/mit-dci/lit/btcutil/blockchain"
    12  	"github.com/mit-dci/lit/btcutil/chaincfg/chainhash"
    13  	"github.com/mit-dci/lit/btcutil/hdkeychain"
    14  	"github.com/mit-dci/lit/coinparam"
    15  	"github.com/mit-dci/lit/lnutil"
    16  	"github.com/mit-dci/lit/logging"
    17  	"github.com/mit-dci/lit/portxo"
    18  	"github.com/mit-dci/lit/uspv"
    19  	"github.com/mit-dci/lit/wire"
    20  )
    21  
    22  // The Wallit is lit's main wallet struct.  It's got the root key, the dbs, and
    23  // contains the SPVhooks into the network.
    24  type Wallit struct {
    25  	// could get rid of adr slice, it's just an in-ram cache...
    26  	StateDB *bolt.DB // place to write all this down
    27  
    28  	// Set of frozen utxos not to use... they point to the tx using em
    29  	FreezeSet   map[wire.OutPoint]*FrozenTx
    30  	FreezeMutex sync.Mutex
    31  
    32  	// OPEventChan sends events to the LN wallet.
    33  	// Gets initialized and activates when called by qln
    34  	OPEventChan chan lnutil.OutPointEvent
    35  
    36  	// HeightEventChan sends block height changes to the LN wallet.
    37  	// Gets initialized and activates when called by qln
    38  	HeightEventChan chan lnutil.HeightEvent
    39  
    40  	// Params live here...
    41  	Param *coinparam.Params // network parameters (testnet3, segnet, etc)
    42  
    43  	// Hook is the connection to a blockchain.
    44  	// imports the uspv interface.  Could put that somewhere else.
    45  	// like an interfaces library, ... lnutil?
    46  	Hook uspv.ChainHook
    47  
    48  	// current fee per byte
    49  	FeeRate int64
    50  
    51  	// From here, comes everything. It's a secret to everybody.
    52  	rootPrivKey *hdkeychain.ExtendedKey
    53  }
    54  
    55  type FrozenTx struct {
    56  	Ins       []*portxo.PorTxo `json:"ins"`
    57  	Outs      []*wire.TxOut    `json:"outs"`
    58  	ChangeOut *wire.TxOut      `json:"changeout"`
    59  	Nlock     uint32           `json:"nlocktime"`
    60  	Txid      chainhash.Hash   `json:"txid"`
    61  }
    62  
    63  // Stxo is a utxo that has moved on.
    64  type Stxo struct {
    65  	PorTxo      portxo.PorTxo  `json:"txo"`    // when it used to be a utxo
    66  	SpendHeight int32          `json:"height"` // height at which it met its demise
    67  	SpendTxid   chainhash.Hash `json:"txid"`   // the tx that consumed it
    68  }
    69  
    70  // TxToString prints out some info about a transaction. for testing / debugging
    71  func TxToString(tx *wire.MsgTx) string {
    72  	utx := btcutil.NewTx(tx)
    73  	str := fmt.Sprintf("size %d vsize %d wsize %d locktime %d wit: %t txid %s\n",
    74  		tx.SerializeSizeStripped(), blockchain.GetTxVirtualSize(utx),
    75  		tx.SerializeSize(), tx.LockTime, tx.HasWitness(), tx.TxHash().String())
    76  	for i, in := range tx.TxIn {
    77  		str += fmt.Sprintf("Input %d spends %s seq %d\n",
    78  			i, in.PreviousOutPoint.String(), in.Sequence)
    79  		str += fmt.Sprintf("\tSigScript: %x\n", in.SignatureScript)
    80  		for j, wit := range in.Witness {
    81  			str += fmt.Sprintf("\twitness %d: %x\n", j, wit)
    82  		}
    83  	}
    84  	for i, out := range tx.TxOut {
    85  		if out != nil {
    86  			str += fmt.Sprintf("output %d script: %x amt: %d\n",
    87  				i, out.PkScript, out.Value)
    88  		} else {
    89  			str += fmt.Sprintf("output %d nil (WARNING)\n", i)
    90  		}
    91  	}
    92  	return str
    93  }
    94  
    95  /*----- serialization for stxos ------- */
    96  /* Stxo serialization:
    97  bytelength   desc   at offset
    98  
    99  53			portxo		0
   100  4			sheight		53
   101  32			stxid		57
   102  
   103  end len 	89
   104  */
   105  
   106  // ToBytes turns an Stxo into some bytes.
   107  // prevUtxo serialization, then spendheight [4], spendtxid [32]
   108  func (s *Stxo) ToBytes() ([]byte, error) {
   109  	var buf bytes.Buffer
   110  
   111  	// serialize the utxo part
   112  	uBytes, err := s.PorTxo.Bytes()
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	// write that into the buffer
   117  	_, err = buf.Write(uBytes)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	// write 4 byte height where the txo was spent
   123  	err = binary.Write(&buf, binary.BigEndian, s.SpendHeight)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	// write 32 byte txid of the spending transaction
   128  	_, err = buf.Write(s.SpendTxid.CloneBytes())
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	return buf.Bytes(), nil
   134  }
   135  
   136  // StxoFromBytes turns bytes into a Stxo.
   137  // it's a portxo with a spendHeight and spendTxid at the end.
   138  func StxoFromBytes(b []byte) (Stxo, error) {
   139  	var s Stxo
   140  
   141  	l := len(b)
   142  	if l < 96 {
   143  		return s, fmt.Errorf("Got %d bytes for stxo, expect a bunch", len(b))
   144  	}
   145  
   146  	// last 36 bytes are height & spend txid.
   147  	u, err := portxo.PorTxoFromBytes(b[:l-36])
   148  	if err != nil {
   149  		logging.Errorf(" eof? ")
   150  		return s, err
   151  	}
   152  
   153  	buf := bytes.NewBuffer(b[l-36:])
   154  	// read 4 byte spend height
   155  	err = binary.Read(buf, binary.BigEndian, &s.SpendHeight)
   156  	if err != nil {
   157  		return s, err
   158  	}
   159  	// read 32 byte txid
   160  	err = s.SpendTxid.SetBytes(buf.Next(32))
   161  	if err != nil {
   162  		return s, err
   163  	}
   164  
   165  	s.PorTxo = *u // assign the utxo
   166  
   167  	return s, nil
   168  }