Пример #1
0
// Uncompressed private key
func sec2b58unc(pk []byte) string {
	var dat [37]byte
	dat[0] = privver
	copy(dat[1:33], pk)
	sh := btc.Sha2Sum(dat[0:33])
	copy(dat[33:37], sh[:4])
	return btc.Encodeb58(dat[:])
}
Пример #2
0
// Compressed private key
func sec2b58com(pk []byte) string {
	var dat [38]byte
	dat[0] = privver
	copy(dat[1:33], pk)
	dat[33] = 1 // compressed
	sh := btc.Sha2Sum(dat[0:34])
	copy(dat[34:38], sh[:4])
	return btc.Encodeb58(dat[:])
}
Пример #3
0
// Get the secret seed and generate "*keycnt" key pairs (both private and public)
func make_wallet() {
	var verbyte byte // normally it will be zero (means: normal bitcoin network)
	if *testnet {
		verbyte = 0x6f // .. but for testnet we need 0x6f
	}
	pass := getpass()
	curv := btc.S256()
	seed_key := btc.Sha2Sum([]byte(pass))
	priv_keys = make([][32]byte, *keycnt)
	publ_addrs = make([]*btc.BtcAddr, *keycnt)
	fmt.Println("Generating", *keycnt, "keys, version", verbyte, "...")
	for i := uint(0); i < *keycnt; i++ {
		seed_key = btc.Sha2Sum(seed_key[:])
		priv_keys[i] = seed_key
		publ_addrs[i] = btc.NewAddrFromPubkey(getPubKey(curv, seed_key[:]), verbyte)
	}
	fmt.Println("Private keys re-generated")
}
Пример #4
0
func (c *oneConnection) FetchMessage() *BCmsg {
	var e error
	var n int

	// Try for 1 millisecond and timeout if full msg not received
	c.TCPConn.SetReadDeadline(time.Now().Add(time.Millisecond))

	for c.hdr_len < 24 {
		n, e = SockRead(c.TCPConn, c.hdr[c.hdr_len:24])
		c.hdr_len += n
		if e != nil {
			c.HandleError(e)
			return nil
		}
		if c.hdr_len >= 4 && !bytes.Equal(c.hdr[:4], Magic[:]) {
			println("FetchMessage: Proto out of sync")
			c.broken = true
			return nil
		}
	}

	dlen := binary.LittleEndian.Uint32(c.hdr[16:20])
	if dlen > 0 {
		if c.dat == nil {
			c.dat = make([]byte, dlen)
			c.datlen = 0
		}
		for c.datlen < dlen {
			n, e = SockRead(c.TCPConn, c.dat[c.datlen:])
			c.datlen += uint32(n)
			if e != nil {
				c.HandleError(e)
				return nil
			}
		}
	}

	sh := btc.Sha2Sum(c.dat)
	if !bytes.Equal(c.hdr[20:24], sh[:4]) {
		println("Msg checksum error")
		c.hdr_len = 0
		c.dat = nil
		c.broken = true
		return nil
	}

	ret := new(BCmsg)
	ret.cmd = strings.TrimRight(string(c.hdr[4:16]), "\000")
	ret.pl = c.dat
	c.dat = nil
	c.hdr_len = 0

	c.BytesReceived += uint64(24 + len(ret.pl))

	return ret
}
Пример #5
0
func (c *one_net_conn) readmsg() *one_net_cmd {
	var (
		hdr     [24]byte
		hdr_len int
		pl_len  uint32 // length taken from the message header
		cmd     string
		dat     []byte
		datlen  uint32
	)

	for hdr_len < 24 {
		n, e := c.Read(hdr[hdr_len:])
		if e != nil {
			return nil
		}
		hdr_len += n
		if hdr_len >= 4 && !bytes.Equal(hdr[:4], Magic[:]) {
			println(c.peerip, "NetBadMagic")
			return nil
		}
	}
	pl_len = binary.LittleEndian.Uint32(hdr[16:20])
	cmd = strings.TrimRight(string(hdr[4:16]), "\000")

	if pl_len > 0 {
		dat = make([]byte, pl_len)
		for datlen < pl_len {
			n, e := c.Read(dat[datlen:])
			if e != nil {
				return nil
			}
			if n > 0 {
				datlen += uint32(n)
			}
		}
	}

	sh := btc.Sha2Sum(dat)
	if !bytes.Equal(hdr[20:24], sh[:4]) {
		println(c.peerip, "Msg checksum error")
		return nil
	}

	res := new(one_net_cmd)
	res.cmd = cmd
	res.pl = dat
	return res
}
Пример #6
0
func (c *one_net_conn) sendmsg(cmd string, pl []byte) (e error) {
	sbuf := make([]byte, 24+len(pl))

	binary.LittleEndian.PutUint32(sbuf[0:4], Version)
	copy(sbuf[0:4], Magic[:])
	copy(sbuf[4:16], cmd)
	binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl)))

	sh := btc.Sha2Sum(pl[:])
	copy(sbuf[20:24], sh[:4])
	copy(sbuf[24:], pl)

	//println("send", cmd, len(sbuf), "...")
	c.send.buf = append(c.send.buf, sbuf...)
	return
}
Пример #7
0
func (c *oneConnection) SendRawMsg(cmd string, pl []byte) (e error) {
	var b [20]byte

	c.last_cmd = cmd + "*"
	c.writing = true

	binary.LittleEndian.PutUint32(b[0:4], Version)
	copy(b[0:4], Magic[:])
	copy(b[4:16], cmd)
	binary.LittleEndian.PutUint32(b[16:20], uint32(len(pl)))
	e = SockWrite(c.TCPConn, b[:20])
	if e != nil {
		if dbg > 0 {
			println("SendRawMsg 1", e.Error())
		}
		c.broken = true
		c.writing = false
		return
	}

	sh := btc.Sha2Sum(pl[:])
	e = SockWrite(c.TCPConn, sh[:4])
	if e != nil {
		if dbg > 0 {
			println("SendRawMsg 2", e.Error())
		}
		c.broken = true
		c.writing = false
		return
	}

	e = SockWrite(c.TCPConn, pl[:])
	if e != nil {
		if dbg > 0 {
			println("SendRawMsg 3", e.Error())
		}
		c.broken = true
	}

	c.BytesSent += uint64(24 + len(pl))
	c.last_cmd = cmd

	c.writing = false
	return
}
Пример #8
0
func (c *OneConnection) SendRawMsg(cmd string, pl []byte) (e error) {
	c.Mutex.Lock()

	if c.Send.Buf != nil {
		// Before adding more data to the buffer, check the limit
		if len(c.Send.Buf) > MaxSendBufferSize {
			c.Mutex.Unlock()
			if common.DebugLevel > 0 {
				println(c.PeerAddr.Ip(), "Peer Send Buffer Overflow")
			}
			c.Disconnect()
			common.CountSafe("PeerSendOverflow")
			return errors.New("Send buffer overflow")
		}
	} else {
		c.Send.LastSent = time.Now()
	}

	common.CountSafe("sent_" + cmd)
	common.CountSafeAdd("sbts_"+cmd, uint64(len(pl)))
	sbuf := make([]byte, 24+len(pl))

	c.LastCmdSent = cmd
	c.LastBtsSent = uint32(len(pl))

	binary.LittleEndian.PutUint32(sbuf[0:4], common.Version)
	copy(sbuf[0:4], common.Magic[:])
	copy(sbuf[4:16], cmd)
	binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl)))

	sh := btc.Sha2Sum(pl[:])
	copy(sbuf[20:24], sh[:4])
	copy(sbuf[24:], pl)

	c.Send.Buf = append(c.Send.Buf, sbuf...)

	if common.DebugLevel < 0 {
		fmt.Println(cmd, len(c.Send.Buf), "->", c.PeerAddr.Ip())
	}
	c.Mutex.Unlock()
	//println(len(c.Send.Buf), "queued for seding to", c.PeerAddr.Ip())
	return
}
Пример #9
0
// Verify the secret key's range and al if a test message signed with it verifies OK
func verify_key(priv []byte, publ []byte) bool {
	const TestMessage = "Just some test message..."
	hash := btc.Sha2Sum([]byte(TestMessage))

	pub_key, e := btc.NewPublicKey(publ)
	if e != nil {
		println("NewPublicKey:", e.Error(), "\007")
		os.Exit(1)
	}

	var key ecdsa.PrivateKey
	key.D = new(big.Int).SetBytes(priv)
	key.PublicKey = pub_key.PublicKey

	if key.D.Cmp(big.NewInt(0)) == 0 {
		println("pubkey value is zero")
		return false
	}

	if key.D.Cmp(maxKeyVal) != -1 {
		println("pubkey value is too big", hex.EncodeToString(publ))
		return false
	}

	r, s, err := ecdsa.Sign(rand.Reader, &key, hash[:])
	if err != nil {
		println("ecdsa.Sign:", err.Error())
		return false
	}

	ok := ecdsa.Verify(&key.PublicKey, hash[:], r, s)
	if !ok {
		println("The key pair does not verify!")
		return false
	}
	return true
}
Пример #10
0
// load the content of the "balance/" folder
func load_balance() {
	var unknownInputs int
	f, e := os.Open("balance/unspent.txt")
	if e != nil {
		println(e.Error())
		os.Exit(1)
	}
	rd := bufio.NewReader(f)
	for {
		l, _, e := rd.ReadLine()
		if len(l) == 0 && e != nil {
			break
		}
		if l[64] == '-' {
			txid := btc.NewUint256FromString(string(l[:64]))
			rst := strings.SplitN(string(l[65:]), " ", 2)
			vout, _ := strconv.ParseUint(rst[0], 10, 32)
			uns := new(btc.TxPrevOut)
			copy(uns.Hash[:], txid.Hash[:])
			uns.Vout = uint32(vout)
			lab := ""
			if len(rst) > 1 {
				lab = rst[1]
			}

			if _, ok := loadedTxs[txid.Hash]; !ok {
				tf, _ := os.Open("balance/" + txid.String() + ".tx")
				if tf != nil {
					siz, _ := tf.Seek(0, os.SEEK_END)
					tf.Seek(0, os.SEEK_SET)
					buf := make([]byte, siz)
					tf.Read(buf)
					tf.Close()
					th := btc.Sha2Sum(buf)
					if bytes.Equal(th[:], txid.Hash[:]) {
						tx, _ := btc.NewTx(buf)
						if tx != nil {
							loadedTxs[txid.Hash] = tx
						} else {
							println("transaction is corrupt:", txid.String())
						}
					} else {
						println("transaction file is corrupt:", txid.String())
						os.Exit(1)
					}
				} else {
					println("transaction file not found:", txid.String())
					os.Exit(1)
				}
			}

			uo := UO(uns)
			fnd := false
			for j := range publ_addrs {
				if publ_addrs[j].Owns(uo.Pk_script) {
					unspentOuts = append(unspentOuts, uns)
					unspentOutsLabel = append(unspentOutsLabel, lab)
					totBtc += UO(uns).Value
					fnd = true
					break
				}
			}

			if !fnd {
				unknownInputs++
				if *verbose {
					fmt.Println(uns.String(), "does not belogn to your wallet - ignore it")
				}
			}

		}
	}
	f.Close()
	fmt.Printf("You have %.8f BTC in %d unspent outputs\n", float64(totBtc)/1e8, len(unspentOuts))
	if unknownInputs > 0 {
		fmt.Printf("WARNING: Some inputs (%d) cannot be spent (-v to print them)\n", unknownInputs)
	}
}
Пример #11
0
func (c *OneConnection) FetchMessage() *BCmsg {
	var e error
	var n int

	for c.recv.hdr_len < 24 {
		n, e = common.SockRead(c.NetConn, c.recv.hdr[c.recv.hdr_len:24])
		c.Mutex.Lock()
		c.recv.hdr_len += n
		if e != nil {
			c.Mutex.Unlock()
			c.HandleError(e)
			return nil
		}
		if c.recv.hdr_len >= 4 && !bytes.Equal(c.recv.hdr[:4], common.Magic[:]) {
			c.Mutex.Unlock()
			if common.DebugLevel > 0 {
				println("FetchMessage: Proto out of sync")
			}
			common.CountSafe("NetBadMagic")
			c.Disconnect()
			return nil
		}
		if c.broken {
			c.Mutex.Unlock()
			return nil
		}
		if c.recv.hdr_len >= 24 {
			c.recv.pl_len = binary.LittleEndian.Uint32(c.recv.hdr[16:20])
			c.recv.cmd = strings.TrimRight(string(c.recv.hdr[4:16]), "\000")
		}
		c.Mutex.Unlock()
	}

	if c.recv.pl_len > 0 {
		if c.recv.dat == nil {
			msi := maxmsgsize(c.recv.cmd)
			if c.recv.pl_len > msi {
				//println(c.PeerAddr.Ip(), "Command", c.recv.cmd, "is going to be too big", c.recv.pl_len, msi)
				c.DoS("MsgTooBig")
				return nil
			}
			c.Mutex.Lock()
			c.recv.dat = make([]byte, c.recv.pl_len)
			c.recv.datlen = 0
			c.Mutex.Unlock()
		}
		for c.recv.datlen < c.recv.pl_len {
			n, e = common.SockRead(c.NetConn, c.recv.dat[c.recv.datlen:])
			if n > 0 {
				c.Mutex.Lock()
				c.recv.datlen += uint32(n)
				c.Mutex.Unlock()
				if c.recv.datlen > c.recv.pl_len {
					println(c.PeerAddr.Ip(), "is sending more of", c.recv.cmd, "then it should have", c.recv.datlen, c.recv.pl_len)
					c.DoS("MsgSizeMismatch")
					return nil
				}
			}
			if e != nil {
				c.HandleError(e)
				return nil
			}
			if c.broken {
				return nil
			}
		}
	}

	sh := btc.Sha2Sum(c.recv.dat)
	if !bytes.Equal(c.recv.hdr[20:24], sh[:4]) {
		//println(c.PeerAddr.Ip(), "Msg checksum error")
		c.DoS("MsgBadChksum")
		return nil
	}

	ret := new(BCmsg)
	ret.cmd = c.recv.cmd
	ret.pl = c.recv.dat

	c.Mutex.Lock()
	c.recv.dat = nil
	c.recv.hdr_len = 0
	c.BytesReceived += uint64(24 + len(ret.pl))
	c.Mutex.Unlock()

	return ret
}
Пример #12
0
func (c *one_net_conn) readmsg() *one_net_cmd {
	c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
	if c.recv.hdr_len < 24 {
		for {
			n, e := c.Read(c.recv.hdr[c.recv.hdr_len:])
			if e != nil {
				if nerr, ok := e.(net.Error); ok && nerr.Timeout() {
					//COUNTER("HDRT")
				} else {
					c.setbroken(true)
				}
				return nil
			}
			c.Lock()
			c.bytes_received += uint64(n)
			c.Unlock()
			c.recv.hdr_len += n
			if c.recv.hdr_len >= 4 {
				if !bytes.Equal(c.recv.hdr[:4], Magic[:]) {
					fmt.Println(c.peerip, "NetBadMagic")
					c.setbroken(true)
					return nil
				}
				if c.recv.hdr_len == 24 {
					c.recv.cmd = strings.TrimRight(string(c.recv.hdr[4:16]), "\000")
					c.recv.pl_len = binary.LittleEndian.Uint32(c.recv.hdr[16:20])
					c.recv.datlen = 0
					if c.recv.pl_len > 0 {
						c.recv.dat = make([]byte, c.recv.pl_len)
					}
					break
				}
			}
		}
	}

	for c.recv.datlen < c.recv.pl_len {
		n, e := c.Read(c.recv.dat[c.recv.datlen:])
		if e != nil {
			if nerr, ok := e.(net.Error); ok && nerr.Timeout() {
				//COUNTER("HDRT")
			} else {
				c.setbroken(true)
			}
			return nil
		}
		if n > 0 {
			c.recv.datlen += uint32(n)
			c.Lock()
			c.bytes_received += uint64(n)
			c.Unlock()
		}
	}

	sh := btc.Sha2Sum(c.recv.dat)
	if !bytes.Equal(c.recv.hdr[20:24], sh[:4]) {
		fmt.Println(c.peerip, "Msg checksum error")
		c.setbroken(true)
		return nil
	}

	res := new(one_net_cmd)
	res.cmd = c.recv.cmd
	res.pl = c.recv.dat

	c.recv.hdr_len = 0
	c.recv.dat = nil

	return res
}
Пример #13
0
func load_others() {
	f, e := os.Open(RawKeysFilename)
	if e == nil {
		defer f.Close()
		td := bufio.NewReader(f)
		for {
			li, _, _ := td.ReadLine()
			if li == nil {
				break
			}
			pk := strings.SplitN(strings.Trim(string(li), " "), " ", 2)
			if pk[0][0] == '#' {
				continue // Just a comment-line
			}

			pkb := btc.Decodeb58(pk[0])

			if pkb == nil {
				println("Decodeb58 failed:", pk[0][:6])
				continue
			}

			if len(pkb) != 37 && len(pkb) != 38 {
				println(pk[0][:6], "has wrong key", len(pkb))
				println(hex.EncodeToString(pkb))
				continue
			}

			if pkb[0] != privver {
				println(pk[0][:6], "has version", pkb[0], "while we expect", privver)
				if pkb[0] == 0xef {
					fmt.Println("You probably meant testnet, so use -t switch")
					os.Exit(0)
				} else {
					continue
				}
			}

			var sh [32]byte
			var compr bool

			if len(pkb) == 37 {
				// compressed key
				sh = btc.Sha2Sum(pkb[0:33])
				if !bytes.Equal(sh[:4], pkb[33:37]) {
					println(pk[0][:6], "checksum error")
					continue
				}
				compr = false
			} else {
				if pkb[33] != 1 {
					println(pk[0][:6], "a key of length 38 bytes must be compressed")
					continue
				}

				sh = btc.Sha2Sum(pkb[0:34])
				if !bytes.Equal(sh[:4], pkb[34:38]) {
					println(pk[0][:6], "checksum error")
					continue
				}
				compr = true
			}

			key := pkb[1:33]
			pub, er := btc.PublicFromPrivate(key, compr)
			if er != nil {
				println("PublicFromPrivate:", e.Error())
				os.Exit(1)
			}

			priv_keys = append(priv_keys, key)
			publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub, verbyte))
			if len(pk) > 1 {
				labels = append(labels, pk[1])
			} else {
				labels = append(labels, fmt.Sprint("Other ", len(priv_keys)))
			}
		}
		if *verbose {
			fmt.Println(len(priv_keys), "keys imported from", RawKeysFilename)
		}
	} else {
		if *verbose {
			fmt.Println("You can also have some dumped (b58 encoded) priv keys in file", RawKeysFilename)
		}
	}
}
Пример #14
0
// load the content of the "balance/" folder
func load_balance(showbalance bool) {
	var unknownInputs, multisigInputs int
	f, e := os.Open("balance/unspent.txt")
	if e != nil {
		println(e.Error())
		return
	}
	rd := bufio.NewReader(f)
	for {
		l, _, e := rd.ReadLine()
		if len(l) == 0 && e != nil {
			break
		}
		if l[64] == '-' {
			txid := btc.NewUint256FromString(string(l[:64]))
			rst := strings.SplitN(string(l[65:]), " ", 2)
			vout, _ := strconv.ParseUint(rst[0], 10, 32)
			uns := new(btc.TxPrevOut)
			copy(uns.Hash[:], txid.Hash[:])
			uns.Vout = uint32(vout)
			lab := ""
			if len(rst) > 1 {
				lab = rst[1]
			}

			if _, ok := loadedTxs[txid.Hash]; !ok {
				tf, _ := os.Open("balance/" + txid.String() + ".tx")
				if tf != nil {
					siz, _ := tf.Seek(0, os.SEEK_END)
					tf.Seek(0, os.SEEK_SET)
					buf := make([]byte, siz)
					tf.Read(buf)
					tf.Close()
					th := btc.Sha2Sum(buf)
					if bytes.Equal(th[:], txid.Hash[:]) {
						tx, _ := btc.NewTx(buf)
						if tx != nil {
							loadedTxs[txid.Hash] = tx
						} else {
							println("transaction is corrupt:", txid.String())
						}
					} else {
						println("transaction file is corrupt:", txid.String())
						os.Exit(1)
					}
				} else {
					println("transaction file not found:", txid.String())
					os.Exit(1)
				}
			}

			unspentOuts = append(unspentOuts, uns)
			unspentOutsLabel = append(unspentOutsLabel, lab)

			// Sum up all the balance and check if we have private key for this input
			uo := UO(uns)
			totBtc += UO(uns).Value

			if !btc.IsP2SH(uo.Pk_script) {
				fnd := false
				for j := range publ_addrs {
					if publ_addrs[j].Owns(uo.Pk_script) {
						fnd = true
						break
					}
				}

				if showbalance && !fnd {
					unknownInputs++
					if *verbose {
						ss := uns.String()
						ss = ss[:8] + "..." + ss[len(ss)-12:]
						fmt.Println(ss, "does not belong to your wallet (cannot sign it)")
					}
				}
			} else {
				if *verbose {
					ss := uns.String()
					ss = ss[:8] + "..." + ss[len(ss)-12:]
					fmt.Println(ss, "belongs to a multisig address")
				}
				multisigInputs++
			}
		}
	}
	f.Close()
	fmt.Printf("You have %.8f BTC in %d unspent outputs. %d inputs are multisig type\n",
		float64(totBtc)/1e8, len(unspentOuts), multisigInputs)
	if showbalance {
		if unknownInputs > 0 {
			fmt.Printf("WARNING: Some inputs (%d) cannot be spent with this password (-v to print them)\n", unknownInputs)
		}
	}
}
Пример #15
0
// load the content of the "balance/" folder
func load_balance(showbalance bool) {
	var unknownInputs, multisigInputs int
	f, e := os.Open("balance/unspent.txt")
	if e != nil {
		println(e.Error())
		return
	}
	rd := bufio.NewReader(f)
	for {
		l, _, e := rd.ReadLine()
		if len(l) == 0 && e != nil {
			break
		}
		if l[64] == '-' {
			txid := btc.NewUint256FromString(string(l[:64]))
			rst := strings.SplitN(string(l[65:]), " ", 2)
			vout, _ := strconv.ParseUint(rst[0], 10, 32)
			uns := new(btc.TxPrevOut)
			copy(uns.Hash[:], txid.Hash[:])
			uns.Vout = uint32(vout)
			lab := ""
			if len(rst) > 1 {
				lab = rst[1]
			}

			str := string(l)
			if sti := strings.Index(str, "_StealthC:"); sti != -1 {
				c, e := hex.DecodeString(str[sti+10 : sti+10+64])
				if e != nil {
					fmt.Println("ERROR at stealth", txid.String(), vout, e.Error())
				} else {
					// add a new key to the wallet
					sec := btc.DeriveNextPrivate(first_seed[:], c)
					is_stealth[len(priv_keys)] = true
					priv_keys = append(priv_keys, sec)
					labels = append(labels, lab)
					pub_key := btc.PublicFromPrivate(sec, true)
					publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub_key, btc.AddrVerPubkey(*testnet)))
					compressed_key = append(compressed_key, true) // stealth keys are always compressed
				}
			}

			if _, ok := loadedTxs[txid.Hash]; !ok {
				tf, _ := os.Open("balance/" + txid.String() + ".tx")
				if tf != nil {
					siz, _ := tf.Seek(0, os.SEEK_END)
					tf.Seek(0, os.SEEK_SET)
					buf := make([]byte, siz)
					tf.Read(buf)
					tf.Close()
					th := btc.Sha2Sum(buf)
					if bytes.Equal(th[:], txid.Hash[:]) {
						tx, _ := btc.NewTx(buf)
						if tx != nil {
							loadedTxs[txid.Hash] = tx
						} else {
							println("transaction is corrupt:", txid.String())
						}
					} else {
						println("transaction file is corrupt:", txid.String())
						os.Exit(1)
					}
				} else {
					println("transaction file not found:", txid.String())
					os.Exit(1)
				}
			}

			// Sum up all the balance and check if we have private key for this input
			uo := UO(uns)

			add_it := true

			if !btc.IsP2SH(uo.Pk_script) {
				fnd := false
				for j := range publ_addrs {
					if publ_addrs[j].Owns(uo.Pk_script) {
						fnd = true
						break
					}
				}

				if !fnd {
					if *onlvalid {
						add_it = false
					}
					if showbalance {
						unknownInputs++
						if *verbose {
							ss := uns.String()
							ss = ss[:8] + "..." + ss[len(ss)-12:]
							fmt.Println(ss, "does not belong to your wallet (cannot sign it)")
						}
					}
				}
			} else {
				if *onlvalid {
					add_it = false
				}
				if *verbose {
					ss := uns.String()
					ss = ss[:8] + "..." + ss[len(ss)-12:]
					fmt.Println(ss, "belongs to a multisig address")
				}
				multisigInputs++
			}

			if add_it {
				unspentOuts = append(unspentOuts, uns)
				unspentOutsLabel = append(unspentOutsLabel, lab)
				totBtc += UO(uns).Value
			}
		}
	}
	f.Close()
	fmt.Printf("You have %.8f BTC in %d unspent outputs. %d inputs are multisig type\n",
		float64(totBtc)/1e8, len(unspentOuts), multisigInputs)
	if showbalance {
		if unknownInputs > 0 {
			fmt.Printf("WARNING: Some inputs (%d) cannot be spent with this password (-v to print them)\n", unknownInputs)
		}
	}
}