Пример #1
0
// parse the "-send ..." parameter
func parse_spend() {
	outs := strings.Split(*send, ",")

	for i := range outs {
		tmp := strings.Split(strings.Trim(outs[i], " "), "=")
		if len(tmp) != 2 {
			println("The outputs must be in a format address1=amount1[,addressN=amountN]")
			cleanExit(1)
		}

		a, e := btc.NewAddrFromString(tmp[0])
		if e != nil {
			println("NewAddrFromString:", e.Error())
			cleanExit(1)
		}
		assert_address_version(a)

		am, er := btc.StringToSatoshis(tmp[1])
		if er != nil {
			println("Incorrect amount: ", tmp[1], er.Error())
			cleanExit(1)
		}
		if *subfee {
			am -= curFee
		}

		sendTo = append(sendTo, oneSendTo{addr: a, amount: am})
		spendBtc += am
	}
}
Пример #2
0
// parse the "-batch ..." parameter
func parse_batch() {
	f, e := os.Open(*batch)
	if e == nil {
		defer f.Close()
		td := bufio.NewReader(f)
		var lcnt int
		for {
			li, _, _ := td.ReadLine()
			if li == nil {
				break
			}
			lcnt++
			tmp := strings.SplitN(strings.Trim(string(li), " "), "=", 2)
			if len(tmp) < 2 {
				println("Error in the batch file line", lcnt)
				cleanExit(1)
			}
			if tmp[0][0] == '#' {
				continue // Just a comment-line
			}

			a, e := btc.NewAddrFromString(tmp[0])
			if e != nil {
				println("NewAddrFromString:", e.Error())
				cleanExit(1)
			}
			assert_address_version(a)

			am, e := btc.StringToSatoshis(tmp[1])
			if e != nil {
				println("StringToSatoshis:", e.Error())
				cleanExit(1)
			}

			sendTo = append(sendTo, oneSendTo{addr: a, amount: am})
			spendBtc += am
		}
	} else {
		println(e.Error())
		cleanExit(1)
	}
}
Пример #3
0
// Download (and re-assemble) raw transaction from blockexplorer.com
func GetTxFromExplorer(txid *btc.Uint256) ([]byte, []byte) {
	url := "http://blockexplorer.com/rawtx/" + txid.String()
	r, er := http.Get(url)
	if er == nil && r.StatusCode == 200 {
		defer r.Body.Close()
		c, _ := ioutil.ReadAll(r.Body)
		var txx onetx
		er = json.Unmarshal(c[:], &txx)
		if er == nil {
			// This part looks weird, but this is how I solved seq=FFFFFFFF, if the field not present:
			for i := range txx.In {
				txx.In[i].Sequence = 0xffffffff
			}
			json.Unmarshal(c[:], &txx)
			// ... end of the weird solution

			tx := new(btc.Tx)
			tx.Version = txx.Ver
			tx.TxIn = make([]*btc.TxIn, len(txx.In))
			for i := range txx.In {
				tx.TxIn[i] = new(btc.TxIn)
				tx.TxIn[i].Input.Hash = btc.NewUint256FromString(txx.In[i].Prev_out.Hash).Hash
				tx.TxIn[i].Input.Vout = txx.In[i].Prev_out.N
				if txx.In[i].Prev_out.N == 0xffffffff &&
					txx.In[i].Prev_out.Hash == "0000000000000000000000000000000000000000000000000000000000000000" {
					tx.TxIn[i].ScriptSig, _ = hex.DecodeString(txx.In[i].Coinbase)
				} else {
					tx.TxIn[i].ScriptSig, _ = btc.DecodeScript(txx.In[i].ScriptSig)
				}
				tx.TxIn[i].Sequence = txx.In[i].Sequence
			}
			tx.TxOut = make([]*btc.TxOut, len(txx.Out))
			for i := range txx.Out {
				am, er := btc.StringToSatoshis(txx.Out[i].Value)
				if er != nil {
					fmt.Println("Incorrect BTC amount", txx.Out[i].Value, er.Error())
					return nil, nil
				}
				tx.TxOut[i] = new(btc.TxOut)
				tx.TxOut[i].Value = am
				tx.TxOut[i].Pk_script, _ = btc.DecodeScript(txx.Out[i].ScriptPubKey)
			}
			tx.Lock_time = txx.Lock_time
			rawtx := tx.Serialize()
			if txx.Size != uint(len(rawtx)) {
				fmt.Printf("Transaction size mismatch: %d expexted, %d decoded\n", txx.Size, len(rawtx))
				return nil, rawtx
			}
			curid := btc.NewSha2Hash(rawtx)
			if !curid.Equal(txid) {
				fmt.Println("The downloaded transaction does not match its ID.", txid.String())
				return nil, rawtx
			}
			return rawtx, rawtx
		} else {
			fmt.Println("json.Unmarshal:", er.Error())
		}
	} else {
		if er != nil {
			fmt.Println("http.Get:", er.Error())
		} else {
			fmt.Println("StatusCode=", r.StatusCode)
		}
	}
	return nil, nil
}
Пример #4
0
func main() {
	fmt.Println("Gocoin BalIO version", lib.Version)

	if len(os.Args) < 2 {
		print_help()
		return
	}

	proxy = os.Getenv("TOR")
	if proxy != "" {
		fmt.Println("Using Tor at", proxy)
		http.DefaultClient.Transport = &http.Transport{Dial: dials5}
	} else {
		fmt.Println("WARNING: not using Tor (setup TOR variable, if you want)")
	}

	var addrs []*btc.BtcAddr

	var argz []string
	for i := 1; i < len(os.Args); i++ {
		if os.Args[i] == "-ltc" {
			ltc = true
		} else if os.Args[i] == "-t" {
			tbtc = true
		} else {
			argz = append(argz, os.Args[i])
		}
	}

	if len(argz) == 1 {
		fi, er := os.Stat(argz[0])
		if er == nil && fi.Size() > 10 && !fi.IsDir() {
			addrs = load_wallet(argz[0])
			if addrs != nil {
				fmt.Println("Found", len(addrs), "address(es) in", argz[0])
			}
		}
	}

	if len(addrs) == 0 {
		for i := range argz {
			a, e := btc.NewAddrFromString(argz[i])
			if e != nil {
				println(argz[i], ": ", e.Error())
				return
			} else {
				addrs = append(addrs, a)
			}
		}
	}

	if len(addrs) == 0 {
		print_help()
		return
	}

	for i := range addrs {
		switch addrs[i].Version {
		case 48:
			ltc = true
		case 111:
			tbtc = true
		}
	}

	if tbtc && ltc {
		println("Litecoin's testnet is not suppported")
		return
	}

	url := base_url() + "address/unspent/"
	for i := range addrs {
		if i > 0 {
			url += ","
		}
		url += addrs[i].String()
	}

	if len(addrs) == 0 {
		println("No addresses to fetch balance for")
		return
	}

	var sum, outcnt uint64

	os.RemoveAll("balance/")
	os.Mkdir("balance/", 0700)
	unsp, _ := os.Create("balance/unspent.txt")
	for off := 0; off < len(addrs); off += MAX_UNSPENT_AT_ONCE {
		var r []prvout
		if off+MAX_UNSPENT_AT_ONCE < len(addrs) {
			r = get_unspent(addrs[off : off+MAX_UNSPENT_AT_ONCE])
		} else {
			r = get_unspent(addrs[off:])
		}
		if r == nil {
			return
		}
		for i := range r {
			for j := range r[i].Unspent {
				txraw := get_raw_tx(r[i].Unspent[j].Tx)
				if len(txraw) > 0 {
					ioutil.WriteFile("balance/"+r[i].Unspent[j].Tx+".tx", txraw, 0666)
				} else {
					println("ERROR: cannot fetch raw tx data for", r[i].Unspent[j].Tx)
					os.Exit(1)
				}

				val, _ := btc.StringToSatoshis(r[i].Unspent[j].Amount)
				sum += val
				outcnt++
				fmt.Fprintf(unsp, "%s-%03d # %s @ %s, %d confs", r[i].Unspent[j].Tx,
					r[i].Unspent[j].N, r[i].Unspent[j].Amount, r[i].Address, r[i].Unspent[j].Confirmations)
				fmt.Fprintln(unsp)
			}
		}
	}
	unsp.Close()
	if outcnt > 0 {
		fmt.Printf("Total %.8f %s in %d unspent outputs.\n", float64(sum)/1e8, curr_unit(), outcnt)
		fmt.Println("The data has been stored in 'balance' folder.")
		fmt.Println("Use it with the wallet app to spend any of it.")
	} else {
		fmt.Println("The fateched balance is empty.")
	}
}
Пример #5
0
func main() {
	// Print the logo to stderr
	println("Gocoin Wallet version", lib.Version)
	println("This program comes with ABSOLUTELY NO WARRANTY")
	println()

	parse_config()
	if flag.Lookup("h") != nil {
		flag.PrintDefaults()
		os.Exit(0)
	}

	flag.Parse()

	// convert string fee to uint64
	if val, e := btc.StringToSatoshis(fee); e != nil {
		println("Incorrect fee value", fee)
		os.Exit(1)
	} else {
		curFee = val
	}

	// decode raw transaction?
	if *dumptxfn != "" {
		dump_raw_tx()
		return
	}

	// dump public key or secret scan key?
	if *pubkey != "" || *scankey != "" {
		make_wallet()
		cleanExit(0)
	}

	// list public addresses?
	if *list {
		make_wallet()
		dump_addrs()
		cleanExit(0)
	}

	// dump privete key?
	if *dumppriv != "" {
		make_wallet()
		dump_prvkey()
		cleanExit(0)
	}

	// sign a message or a hash?
	if *signaddr != "" {
		make_wallet()
		sign_message()
		if *send == "" {
			// Don't load_balance if he did not want to spend coins as well
			cleanExit(0)
		}
	}

	// raw transaction?
	if *rawtx != "" {
		// add p2sh sript to it?
		if *p2sh != "" {
			make_p2sh()
			cleanExit(0)
		}

		make_wallet()

		// multisig sign with a specific key?
		if *multisign != "" {
			multisig_sign()
			cleanExit(0)
		}

		// this must be signing of a raw trasnaction
		load_balance()
		process_raw_tx()
		cleanExit(0)
	}

	// make the wallet nad print balance
	make_wallet()
	if e := load_balance(); e != nil {
		fmt.Println("ERROR:", e.Error())
		cleanExit(1)
	}

	// send command?
	if send_request() {
		make_signed_tx()
		cleanExit(0)
	}

	show_balance()
	cleanExit(0)
}
Пример #6
0
func dl_payment(w http.ResponseWriter, r *http.Request) {
	if !ipchecker(r) {
		return
	}

	var err string

	if len(r.Form["outcnt"]) == 1 {
		var thisbal chain.AllUnspentTx
		var pay_cmd string
		var totalinput, spentsofar uint64
		var change_addr *btc.BtcAddr
		var multisig_input []*wallet.MultisigAddr

		addrs_to_msign := make(map[string]bool)

		tx := new(btc.Tx)
		tx.Version = 1
		tx.Lock_time = 0

		outcnt, _ := strconv.ParseUint(r.Form["outcnt"][0], 10, 32)

		wallet.BalanceMutex.Lock()
		for i := 1; i <= int(outcnt); i++ {
			is := fmt.Sprint(i)
			if len(r.Form["txout"+is]) == 1 && r.Form["txout"+is][0] == "on" {
				hash := btc.NewUint256FromString(r.Form["txid"+is][0])
				if hash != nil {
					vout, er := strconv.ParseUint(r.Form["txvout"+is][0], 10, 32)
					if er == nil {
						var po = btc.TxPrevOut{Hash: hash.Hash, Vout: uint32(vout)}
						for j := range wallet.MyBalance {
							if wallet.MyBalance[j].TxPrevOut == po {
								thisbal = append(thisbal, wallet.MyBalance[j])

								// Add the input to our tx
								tin := new(btc.TxIn)
								tin.Input = wallet.MyBalance[j].TxPrevOut
								tin.Sequence = 0xffffffff
								tx.TxIn = append(tx.TxIn, tin)

								// Add new multisig address description
								_, msi := wallet.IsMultisig(wallet.MyBalance[j].BtcAddr)
								multisig_input = append(multisig_input, msi)
								if msi != nil {
									for ai := range msi.ListOfAddres {
										addrs_to_msign[msi.ListOfAddres[ai]] = true
									}
								}

								// Add the value to total input value
								totalinput += wallet.MyBalance[j].Value

								// If no change specified, use the first input addr as it
								if change_addr == nil {
									change_addr = wallet.MyBalance[j].BtcAddr
								}
							}
						}
					}
				}
			}
		}
		wallet.BalanceMutex.Unlock()

		for i := 1; ; i++ {
			adridx := fmt.Sprint("adr", i)
			btcidx := fmt.Sprint("btc", i)

			if len(r.Form[adridx]) != 1 || len(r.Form[btcidx]) != 1 {
				break
			}

			if len(r.Form[adridx][0]) > 1 {
				addr, er := btc.NewAddrFromString(r.Form[adridx][0])
				if er == nil {
					am, er := btc.StringToSatoshis(r.Form[btcidx][0])
					if er == nil && am > 0 {
						if pay_cmd == "" {
							pay_cmd = "wallet -useallinputs -send "
						} else {
							pay_cmd += ","
						}
						pay_cmd += addr.Enc58str + "=" + btc.UintToBtc(am)

						outs, er := btc.NewSpendOutputs(addr, am, common.CFG.Testnet)
						if er != nil {
							err = er.Error()
							goto error
						}
						tx.TxOut = append(tx.TxOut, outs...)

						spentsofar += am
					} else {
						err = "Incorrect amount (" + r.Form[btcidx][0] + ") for Output #" + fmt.Sprint(i)
						goto error
					}
				} else {
					err = "Incorrect address (" + r.Form[adridx][0] + ") for Output #" + fmt.Sprint(i)
					goto error
				}
			}
		}

		if pay_cmd == "" {
			err = "No inputs selected"
			goto error
		}

		am, er := btc.StringToSatoshis(r.Form["txfee"][0])
		if er != nil {
			err = "Incorrect fee value: " + r.Form["txfee"][0]
			goto error
		}

		pay_cmd += " -fee " + r.Form["txfee"][0]
		spentsofar += am

		if len(r.Form["change"][0]) > 1 {
			addr, er := btc.NewAddrFromString(r.Form["change"][0])
			if er != nil {
				err = "Incorrect change address: " + r.Form["change"][0]
				goto error
			}
			change_addr = addr
		}
		pay_cmd += " -change " + change_addr.String()

		if totalinput > spentsofar {
			// Add change output
			outs, er := btc.NewSpendOutputs(change_addr, totalinput-spentsofar, common.CFG.Testnet)
			if er != nil {
				err = er.Error()
				goto error
			}
			tx.TxOut = append(tx.TxOut, outs...)
		}

		buf := new(bytes.Buffer)
		zi := zip.NewWriter(buf)

		was_tx := make(map[[32]byte]bool, len(thisbal))
		for i := range thisbal {
			if was_tx[thisbal[i].TxPrevOut.Hash] {
				continue
			}
			was_tx[thisbal[i].TxPrevOut.Hash] = true
			txid := btc.NewUint256(thisbal[i].TxPrevOut.Hash[:])
			fz, _ := zi.Create("balance/" + txid.String() + ".tx")
			wallet.GetRawTransaction(thisbal[i].MinedAt, txid, fz)
		}

		fz, _ := zi.Create("balance/unspent.txt")
		for i := range thisbal {
			fmt.Fprintln(fz, thisbal[i].UnspentTextLine())
		}

		if len(addrs_to_msign) > 0 {
			// Multisig (or mixed) transaction ...
			for i := range multisig_input {
				if multisig_input[i] == nil {
					continue
				}
				d, er := hex.DecodeString(multisig_input[i].RedeemScript)
				if er != nil {
					println("ERROR parsing hex RedeemScript:", er.Error())
					continue
				}
				ms, er := btc.NewMultiSigFromP2SH(d)
				if er != nil {
					println("ERROR parsing bin RedeemScript:", er.Error())
					continue
				}
				tx.TxIn[i].ScriptSig = ms.Bytes()
			}
			fz, _ = zi.Create("multi_" + common.CFG.PayCommandName)
			fmt.Fprintln(fz, "wallet -raw tx2sign.txt")
			for k, _ := range addrs_to_msign {
				fmt.Fprintln(fz, "wallet -msign", k, "-raw ...")
			}
		} else {
			if pay_cmd != "" {
				fz, _ = zi.Create(common.CFG.PayCommandName)
				fz.Write([]byte(pay_cmd))
			}
		}

		// Non-multisig transaction ...
		fz, _ = zi.Create("tx2sign.txt")
		fz.Write([]byte(hex.EncodeToString(tx.Serialize())))

		zi.Close()
		w.Header()["Content-Type"] = []string{"application/zip"}
		w.Write(buf.Bytes())
		return
	} else {
		err = "Bad request"
	}
error:
	s := load_template("send_error.html")
	write_html_head(w, r)
	s = strings.Replace(s, "<!--ERROR_MSG-->", err, 1)
	w.Write([]byte(s))
	write_html_tail(w)
}