github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/wallet/unspent.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/piotrnar/gocoin/lib/btc"
    12  )
    13  
    14  type unspRec struct {
    15  	btc.TxPrevOut
    16  	label string
    17  	key   *btc.PrivateAddr
    18  	spent bool
    19  }
    20  
    21  var (
    22  	// set in load_balance():
    23  	unspentOuts []*unspRec
    24  )
    25  
    26  func (u *unspRec) String() string {
    27  	return fmt.Sprint(u.TxPrevOut.String(), " ", u.label)
    28  }
    29  
    30  func NewUnspRec(l []byte) (uns *unspRec) {
    31  	if len(l) < 65 || l[64] != '-' {
    32  		return nil
    33  	}
    34  
    35  	txid := btc.NewUint256FromString(string(l[:64]))
    36  	if txid == nil {
    37  		return nil
    38  	}
    39  
    40  	rst := strings.SplitN(string(l[65:]), " ", 2)
    41  	vout, e := strconv.ParseUint(rst[0], 10, 32)
    42  	if e != nil {
    43  		return nil
    44  	}
    45  
    46  	uns = new(unspRec)
    47  	uns.TxPrevOut.Hash = txid.Hash
    48  	uns.TxPrevOut.Vout = uint32(vout)
    49  	if len(rst) > 1 {
    50  		uns.label = rst[1]
    51  	}
    52  
    53  	return
    54  }
    55  
    56  // load_balance loads the content of the "balance/" folder.
    57  func load_balance() error {
    58  	f, e := os.Open("balance/unspent.txt")
    59  	if e != nil {
    60  		return e
    61  	}
    62  	rd := bufio.NewReader(f)
    63  	for {
    64  		l, _, e := rd.ReadLine()
    65  		if len(l) == 0 && e != nil {
    66  			break
    67  		}
    68  		if uns := NewUnspRec(l); uns != nil {
    69  			if uns.key == nil {
    70  				uns.key = pkscr_to_key(getUO(&uns.TxPrevOut).Pk_script)
    71  			}
    72  			unspentOuts = append(unspentOuts, uns)
    73  		} else {
    74  			println("ERROR in unspent.txt: ", string(l))
    75  		}
    76  	}
    77  	f.Close()
    78  	return nil
    79  }
    80  
    81  func show_balance() {
    82  	var totBtc, msBtc, knownInputs, unknownInputs, multisigInputs uint64
    83  	for i := range unspentOuts {
    84  		uo := getUO(&unspentOuts[i].TxPrevOut)
    85  
    86  		if unspentOuts[i].key != nil {
    87  			totBtc += uo.Value
    88  			knownInputs++
    89  			continue
    90  		}
    91  
    92  		if btc.IsP2SH(uo.Pk_script) {
    93  			msBtc += uo.Value
    94  			multisigInputs++
    95  			continue
    96  		}
    97  
    98  		unknownInputs++
    99  		if *verbose {
   100  			fmt.Println("WARNING: Don't know how to sign", unspentOuts[i].TxPrevOut.String())
   101  		}
   102  	}
   103  	fmt.Printf("You have %.8f BTC in %d keyhash outputs\n", float64(totBtc)/1e8, knownInputs)
   104  	if multisigInputs > 0 {
   105  		fmt.Printf("There is %.8f BTC in %d multisig outputs\n", float64(msBtc)/1e8, multisigInputs)
   106  	}
   107  	if unknownInputs > 0 {
   108  		fmt.Println("WARNING:", unknownInputs, "unspendable inputs (-v to print them).")
   109  	}
   110  }
   111  
   112  // apply_to_balance applies the changes to the balance folder.
   113  func apply_to_balance(tx *btc.Tx) {
   114  	f, _ := os.Create("balance/unspent.txt")
   115  	if f != nil {
   116  		// append new outputs at the end of unspentOuts
   117  		ioutil.WriteFile("balance/"+tx.Hash.String()+".tx", tx.Serialize(), 0600)
   118  
   119  		fmt.Println("Adding", len(tx.TxOut), "new output(s) to the balance/ folder...")
   120  		for out := range tx.TxOut {
   121  			if k := pkscr_to_key(tx.TxOut[out].Pk_script); k != nil {
   122  				uns := new(unspRec)
   123  				uns.key = k
   124  				uns.TxPrevOut.Hash = tx.Hash.Hash
   125  				uns.TxPrevOut.Vout = uint32(out)
   126  				uns.label = fmt.Sprint("# ", btc.UintToBtc(tx.TxOut[out].Value), " BTC @ ", k.BtcAddr.String())
   127  				unspentOuts = append(unspentOuts, uns)
   128  			}
   129  		}
   130  
   131  		for j := range unspentOuts {
   132  			if !unspentOuts[j].spent {
   133  				fmt.Fprintln(f, unspentOuts[j].String())
   134  			}
   135  		}
   136  		f.Close()
   137  	} else {
   138  		println("ERROR: Cannot create balance/unspent.txt")
   139  	}
   140  }