func IsMultisig(ad *btc.BtcAddr) (yes bool, rec *MultisigAddr) { yes = ad.Version == btc.AddrVerScript(common.Testnet) if !yes { return } fn := common.GocoinHomeDir + "wallet" + string(os.PathSeparator) + "multisig" + string(os.PathSeparator) + ad.String() + ".json" d, er := ioutil.ReadFile(fn) if er != nil { //println("fn", fn, er.Error()) return } var msa MultisigAddr er = json.Unmarshal(d, &msa) if er == nil { rec = &msa } else { println(fn, er.Error()) } return }
func list_unspent(addr string) { fmt.Println("Checking unspent coins for addr", addr) defer func() { // in case if ad.OutScript() would panic if r := recover(); r != nil { err := r.(error) fmt.Println("main panic recovered:", err.Error()) } }() var ad *btc.BtcAddr var e error ad, e = btc.NewAddrFromString(addr) if e != nil { println(e.Error()) return } sa := ad.StealthAddr exp_scr := ad.OutScript() var walk chain.FunctionWalkUnspent var unsp chain.AllUnspentTx if sa == nil { walk = func(db *qdb.DB, k qdb.KeyType, rec *chain.OneWalkRecord) uint32 { if bytes.Equal(rec.Script(), exp_scr) { unsp = append(unsp, rec.ToUnspent(ad)) } return 0 } } else { wallet.FetchStealthKeys() d := wallet.FindStealthSecret(sa) if d == nil { fmt.Println("No matching secret found in your wallet/stealth folder") return } walk = func(db *qdb.DB, k qdb.KeyType, rec *chain.OneWalkRecord) uint32 { if !rec.IsStealthIdx() { return 0 } fl, uo := wallet.CheckStealthRec(db, k, rec, ad, d, true) if uo != nil { unsp = append(unsp, uo) } return fl } } common.BlockChain.Unspent.BrowseUTXO(false, walk) sort.Sort(unsp) var sum uint64 for i := range unsp { if len(unsp) < 200 { fmt.Println(unsp[i].String()) } sum += unsp[i].Value } fmt.Printf("Total %.8f unspent BTC in %d outputs at address %s\n", float64(sum)/1e8, len(unsp), ad.String()) }
func (r *OneWalkRecord) ToUnspent(ad *btc.BtcAddr) (nr *OneUnspentTx) { nr = new(OneUnspentTx) copy(nr.TxPrevOut.Hash[:], r.v[0:32]) nr.TxPrevOut.Vout = binary.LittleEndian.Uint32(r.v[32:36]) nr.Value = binary.LittleEndian.Uint64(r.v[36:44]) nr.MinedAt = binary.LittleEndian.Uint32(r.v[44:48]) nr.BtcAddr = ad nr.destString = ad.String() return }
func (r *QdbRec) ToUnspent(idx uint32, ad *btc.BtcAddr) (nr *OneUnspentTx) { nr = new(OneUnspentTx) nr.TxPrevOut.Hash = r.TxID nr.TxPrevOut.Vout = idx nr.Value = r.Outs[idx].Value nr.Coinbase = r.Coinbase nr.MinedAt = r.InBlock nr.BtcAddr = ad nr.destString = ad.String() return }
// dump hashes to be signed func dump_hashes_to_sign(tx *btc.Tx) { for in := range tx.TxIn { uo := UO(unspentOuts[in]) if uo == nil { println("Unknown content of unspent input number", in) os.Exit(1) } var pubad *btc.BtcAddr if litecoin { pubad = ltc.NewAddrFromPkScript(uo.Pk_script, testnet) } else { pubad = btc.NewAddrFromPkScript(uo.Pk_script, testnet) } if pubad != nil { hash := tx.SignatureHash(uo.Pk_script, in, btc.SIGHASH_ALL) fmt.Printf("Input #%d:\n\tHash : %s\n\tAddr : %s\n", in, hex.EncodeToString(hash), pubad.String()) } else { println("Cannot decode pkscript of unspent input number", in) os.Exit(1) } } }
// make sure the version byte in the given address is what we expect func assert_address_version(a *btc.BtcAddr) { if a.Version != ver_pubkey() && a.Version != ver_script() && a.Version != ver_stealth() { println("Sending address", a.String(), "has an incorrect version", a.Version) cleanExit(1) } }
func list_unspent(addr string) { fmt.Println("Checking unspent coins for addr", addr) defer func() { // in case if ad.OutScript() would panic if r := recover(); r != nil { err := r.(error) fmt.Println("main panic recovered:", err.Error()) } }() var ad *btc.BtcAddr var e error ad, e = btc.NewAddrFromString(addr) if e != nil { println(e.Error()) return } sa := ad.StealthAddr var walk chain.FunctionWalkUnspent var unsp chain.AllUnspentTx if sa == nil { exp_scr := ad.OutScript() walk = func(tx *chain.QdbRec) { for idx, rec := range tx.Outs { if rec != nil && bytes.Equal(rec.PKScr, exp_scr) { unsp = append(unsp, tx.ToUnspent(uint32(idx), ad)) } } } } else { var c, spen_exp []byte var rec, out *chain.QdbTxOut var h160 [20]byte wallet.FetchStealthKeys() d := wallet.FindStealthSecret(sa) if d == nil { fmt.Println("No matching secret found in your wallet/stealth folder") return } walk = func(tx *chain.QdbRec) { for i := 0; i < len(tx.Outs)-1; i++ { if rec = tx.Outs[i]; rec == nil { continue } if out = tx.Outs[i+1]; out == nil { continue } if !rec.IsStealthIdx() || !out.IsP2KH() || !ad.StealthAddr.CheckNonce(rec.PKScr[3:40]) { continue } c = btc.StealthDH(rec.PKScr[7:40], d) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(i + 1) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.Extra uo.StealthC = c unsp = append(unsp, uo) } } } } common.BlockChain.Unspent.BrowseUTXO(false, walk) sort.Sort(unsp) var sum uint64 for i := range unsp { if len(unsp) < 200 { fmt.Println(unsp[i].String()) } sum += unsp[i].Value } fmt.Printf("Total %.8f unspent BTC in %d outputs at address %s\n", float64(sum)/1e8, len(unsp), ad.String()) }
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 tx := new(btc.Tx) tx.Version = 1 tx.Lock_time = 0 seq, er := strconv.ParseInt(r.Form["tx_seq"][0], 10, 64) if er != nil || seq < -2 || seq > 0xffffffff { err = "Incorrect Sequence value: " + r.Form["tx_seq"][0] goto error } outcnt, _ := strconv.ParseUint(r.Form["outcnt"][0], 10, 32) lck := new(usif.OneLock) lck.In.Add(1) lck.Out.Add(1) usif.LocksChan <- lck lck.In.Wait() defer lck.Out.Done() 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)} if res, er := common.BlockChain.Unspent.UnspentGet(&po); er == nil { addr := btc.NewAddrFromPkScript(res.Pk_script, common.Testnet) unsp := &chain.OneUnspentTx{TxPrevOut: po, Value: res.Value, MinedAt: res.BlockHeight, Coinbase: res.WasCoinbase, BtcAddr: addr} thisbal = append(thisbal, unsp) // Add the input to our tx tin := new(btc.TxIn) tin.Input = po tin.Sequence = uint32(seq) tx.TxIn = append(tx.TxIn, tin) // Add the value to total input value totalinput += res.Value // If no change specified, use the first input addr as it if change_addr == nil { change_addr = addr } } } } } } if change_addr == nil { // There werte no inputs return } //wallet.BalanceMutex.Lock() //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 } pay_cmd += fmt.Sprint(" -seq ", seq) 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") if dat, er := common.BlockChain.GetRawTx(thisbal[i].MinedAt, txid); er == nil { fz.Write(dat) } else { println(er.Error()) } } fz, _ := zi.Create("balance/unspent.txt") for i := range thisbal { fmt.Fprintln(fz, thisbal[i].UnspentTextLine()) } if pay_cmd != "" { fz, _ = zi.Create(common.CFG.WebUI.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) }
// dump raw transaction func dump_raw_tx() { tx := raw_tx_from_file(*dumptxfn) if tx == nil { fmt.Println("ERROR: Cannot decode the raw transaction") return } var unsigned int fmt.Println("ID:", tx.Hash.String()) fmt.Println("Tx Version:", tx.Version) if tx.IsCoinBase() { if len(tx.TxIn[0].ScriptSig) >= 4 && tx.TxIn[0].ScriptSig[0] == 3 { fmt.Println("Coinbase TX from block height", uint(tx.TxIn[0].ScriptSig[1])| uint(tx.TxIn[0].ScriptSig[2])<<8|uint(tx.TxIn[0].ScriptSig[3])<<16) } else { fmt.Println("Coinbase TX from an unknown block") } s := hex.EncodeToString(tx.TxIn[0].ScriptSig) for len(s) > 0 { i := len(s) if i > 64 { i = 64 } fmt.Println(" ", s[:i]) s = s[i:] } //fmt.Println() } else { fmt.Println("TX IN cnt:", len(tx.TxIn)) for i := range tx.TxIn { fmt.Printf("%4d) %s sl=%d seq=%08x\n", i, tx.TxIn[i].Input.String(), len(tx.TxIn[i].ScriptSig), tx.TxIn[i].Sequence) if len(tx.TxIn[i].ScriptSig) > 0 { if !dump_sigscript(tx.TxIn[i].ScriptSig) { unsigned++ } } else { unsigned++ } } } fmt.Println("TX OUT cnt:", len(tx.TxOut)) for i := range tx.TxOut { fmt.Printf("%4d) %20s BTC ", i, btc.UintToBtc(tx.TxOut[i].Value)) var addr *btc.BtcAddr if litecoin { addr = ltc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, testnet) } else { addr = btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, testnet) } if addr != nil { if addr.Version == AddrVerScript() { fmt.Println("to scriptH", addr.String()) } else { fmt.Println("to address", addr.String()) } } else if len(tx.TxOut[i].Pk_script) == 40 && tx.TxOut[i].Pk_script[0] == 0x6a && tx.TxOut[i].Pk_script[1] == 0x26 && tx.TxOut[i].Pk_script[2] == 0x06 { fmt.Println("Stealth", hex.EncodeToString(tx.TxOut[i].Pk_script[3:7]), hex.EncodeToString(tx.TxOut[i].Pk_script[7:])) } else { if tx.TxOut[i].Value > 0 { fmt.Println("WARNING!!! These coins go to non-standard Pk_script:") } else { fmt.Println("NULL output to Pk_script:") } ss, er := btc.ScriptToText(tx.TxOut[i].Pk_script) if er == nil { for i := range ss { fmt.Println(" ", ss[i]) } } else { fmt.Println(hex.EncodeToString(tx.TxOut[i].Pk_script)) fmt.Println(er.Error()) } } } fmt.Println("Lock Time:", tx.Lock_time) if !tx.IsCoinBase() { if unsigned > 0 { fmt.Println("WARNING:", unsigned, "out of", len(tx.TxIn), "inputs are not signed or signed only patially") } else { fmt.Println("All", len(tx.TxIn), "transaction inputs seem to be signed") } } }
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) }
func all_addrs(par string) { var ptkh_outs, ptkh_vals, ptsh_outs, ptsh_vals uint64 var best SortedWalletAddrs var cnt int = 15 if par != "" { if c, e := strconv.ParseUint(par, 10, 32); e == nil { cnt = int(c) } } wallet.BalanceMutex.Lock() defer wallet.BalanceMutex.Unlock() for k, rec := range wallet.AllBalancesP2SH { ptsh_vals += rec.Value ptsh_outs += uint64(len(rec.Unsp)) if sort_by_cnt && len(rec.Unsp) >= 1000 || !sort_by_cnt && rec.Value >= 1000e8 { best = append(best, OneWalletAddrs{P2SH: true, Key: k, rec: rec}) } } for k, rec := range wallet.AllBalancesP2KH { ptkh_vals += rec.Value ptkh_outs += uint64(len(rec.Unsp)) if sort_by_cnt && len(rec.Unsp) >= 1000 || !sort_by_cnt && rec.Value >= 1000e8 { best = append(best, OneWalletAddrs{Key: k, rec: rec}) } } fmt.Println(btc.UintToBtc(ptkh_vals), "BTC in", ptkh_outs, "unspent recs from", len(wallet.AllBalancesP2KH), "P2KH addresses") fmt.Println(btc.UintToBtc(ptsh_vals), "BTC in", ptsh_outs, "unspent recs from", len(wallet.AllBalancesP2SH), "P2SH addresses") if sort_by_cnt { fmt.Println("Addrs with at least 1000 inps:", len(best)) } else { fmt.Println("Addrs with at least 1000 BTC:", len(best)) } sort.Sort(best) var pkscr_p2sk [23]byte var pkscr_p2kh [25]byte var ad *btc.BtcAddr pkscr_p2sk[0] = 0xa9 pkscr_p2sk[1] = 20 pkscr_p2sk[22] = 0x87 pkscr_p2kh[0] = 0x76 pkscr_p2kh[1] = 0xa9 pkscr_p2kh[2] = 20 pkscr_p2kh[23] = 0x88 pkscr_p2kh[24] = 0xac for i := 0; i < len(best) && i < cnt; i++ { if best[i].P2SH { copy(pkscr_p2sk[2:22], best[i].Key[:]) ad = btc.NewAddrFromPkScript(pkscr_p2sk[:], common.CFG.Testnet) } else { copy(pkscr_p2kh[3:23], best[i].Key[:]) ad = btc.NewAddrFromPkScript(pkscr_p2kh[:], common.CFG.Testnet) } fmt.Println(i+1, ad.String(), btc.UintToBtc(best[i].rec.Value), "BTC in", len(best[i].rec.Unsp), "inputs") } }