// 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 } }
// 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) } }
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) }
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.") } }
// 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 }
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) }