// apply the chnages to the balance folder func apply_to_balance(tx *btc.Tx) { f, _ := os.Create("balance/unspent.txt") if f != nil { // append new outputs at the end of unspentOuts ioutil.WriteFile("balance/"+tx.Hash.String()+".tx", tx.Serialize(), 0600) fmt.Println("Adding", len(tx.TxOut), "new output(s) to the balance/ folder...") for out := range tx.TxOut { if k := pkscr_to_key(tx.TxOut[out].Pk_script); k != nil { uns := new(unspRec) uns.key = k uns.TxPrevOut.Hash = tx.Hash.Hash uns.TxPrevOut.Vout = uint32(out) uns.label = fmt.Sprint("# ", btc.UintToBtc(tx.TxOut[out].Value), " BTC @ ", k.BtcAddr.String()) //stealth bool TODO: maybe we can fix it... unspentOuts = append(unspentOuts, uns) } } for j := range unspentOuts { if !unspentOuts[j].spent { fmt.Fprintln(f, unspentOuts[j].String()) } } f.Close() } else { println("ERROR: Cannot create balance/unspent.txt") } }
func (db *UnspentDB) PrintCoinAge() { const chunk = 10000 var maxbl uint32 type onerec struct { cnt, bts, val, valcb uint64 } age := make(map[uint32]*onerec) for i := range db.tdb { db.dbN(i).BrowseAll(func(k qdb.KeyType, v []byte) uint32 { rec := NewQdbRecStatic(k, v) a := rec.InBlock if a > maxbl { maxbl = a } a /= chunk tmp := age[a] if tmp == nil { tmp = new(onerec) } for _, ou := range rec.Outs { if ou != nil { tmp.val += ou.Value if rec.Coinbase { tmp.valcb += ou.Value } tmp.cnt++ } } tmp.bts += uint64(len(v)) age[a] = tmp return 0 }) } for i := uint32(0); i <= (maxbl / chunk); i++ { tb := (i+1)*chunk - 1 if tb > maxbl { tb = maxbl } cnt := uint64(tb-i*chunk) + 1 fmt.Printf(" Blocks %6d ... %6d: %9d records, %5d MB, %18s/%16s BTC. Per block:%7.1f records,%8d,%15s BTC\n", i*chunk, tb, age[i].cnt, age[i].bts>>20, btc.UintToBtc(age[i].val), btc.UintToBtc(age[i].valcb), float64(age[i].cnt)/float64(cnt), (age[i].bts / cnt), btc.UintToBtc(age[i].val/cnt)) } }
func show_balance_stats(p string) { println("CachedAddrs count:", len(wallet.CachedAddrs)) println("CacheUnspentIdx count:", len(wallet.CacheUnspentIdx)) println("CacheUnspent count:", len(wallet.CacheUnspent)) println("StealthAddrs count:", len(wallet.StealthAdCache)) println("StealthSecrets:", len(wallet.StealthSecrets)) if p != "" { wallet.BalanceMutex.Lock() for i := range wallet.CacheUnspent { if len(wallet.CacheUnspent[i].AllUnspentTx) == 0 { fmt.Printf("%5d) %s: empty\n", i, wallet.CacheUnspent[i].BtcAddr.String()) } else { var val uint64 for j := range wallet.CacheUnspent[i].AllUnspentTx { val += wallet.CacheUnspent[i].AllUnspentTx[j].Value } fmt.Printf("%5d) %s: %s BTC in %d\n", i, wallet.CacheUnspent[i].BtcAddr.String(), btc.UintToBtc(val), len(wallet.CacheUnspent[i].AllUnspentTx)) } } wallet.BalanceMutex.Unlock() } }
// prepare a signed transaction func make_signed_tx() { // Make an empty transaction tx := new(btc.Tx) tx.Version = 1 tx.Lock_time = 0 // Select as many inputs as we need to pay the full amount (with the fee) var btcsofar uint64 for i := range unspentOuts { if unspentOuts[i].key == nil { continue } uo := getUO(&unspentOuts[i].TxPrevOut) // add the input to our transaction: tin := new(btc.TxIn) tin.Input = unspentOuts[i].TxPrevOut tin.Sequence = 0xffffffff tx.TxIn = append(tx.TxIn, tin) btcsofar += uo.Value unspentOuts[i].spent = true if !*useallinputs && (btcsofar >= spendBtc+feeBtc) { break } } if btcsofar < (spendBtc + feeBtc) { fmt.Println("ERROR: You have", btc.UintToBtc(btcsofar), "BTC, but you need", btc.UintToBtc(spendBtc+feeBtc), "BTC for the transaction") cleanExit(1) } changeBtc = btcsofar - (spendBtc + feeBtc) if *verbose { fmt.Printf("Spending %d out of %d outputs...\n", len(tx.TxIn), len(unspentOuts)) } // Build transaction outputs: for o := range sendTo { outs, er := btc.NewSpendOutputs(sendTo[o].addr, sendTo[o].amount, testnet) if er != nil { fmt.Println("ERROR:", er.Error()) cleanExit(1) } tx.TxOut = append(tx.TxOut, outs...) } if changeBtc > 0 { // Add one more output (with the change) chad := get_change_addr() if *verbose { fmt.Println("Sending change", changeBtc, "to", chad.String()) } outs, er := btc.NewSpendOutputs(chad, changeBtc, testnet) if er != nil { fmt.Println("ERROR:", er.Error()) cleanExit(1) } tx.TxOut = append(tx.TxOut, outs...) } if *message != "" { // Add NULL output with an arbitrary message scr := new(bytes.Buffer) scr.WriteByte(0x6a) // OP_RETURN btc.WritePutLen(scr, uint32(len(*message))) scr.Write([]byte(*message)) tx.TxOut = append(tx.TxOut, &btc.TxOut{Value: 0, Pk_script: scr.Bytes()}) } signed := sign_tx(tx) write_tx_file(tx) if apply2bal && signed { apply_to_balance(tx) } }
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) }
// 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, totin, totout, noins uint64 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 intx := tx_from_balance(btc.NewUint256(tx.TxIn[i].Input.Hash[:]), false); intx != nil { val := intx.TxOut[tx.TxIn[i].Input.Vout].Value totin += val fmt.Printf("%15s BTC\n", btc.UintToBtc(val)) } else { noins++ } 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 { totout += tx.TxOut[i].Value fmt.Printf("%4d) %20s BTC ", i, btc.UintToBtc(tx.TxOut[i].Value)) addr := addr_from_pkscr(tx.TxOut[i].Pk_script) if addr != nil { if addr.Version == ver_script() { 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 { sha := sha256.New() sha.Write(tx.TxOut[i].Pk_script[3:40]) fmt.Println("Stealth", hex.EncodeToString(sha.Sum(nil)[:4]), 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) fmt.Println("Output volume:", btc.UintToBtc(totout), "BTC") if noins == 0 { fmt.Println("Input volume :", btc.UintToBtc(totin), "BTC") fmt.Println("Transact. fee:", btc.UintToBtc(totin-totout), "BTC") } else { fmt.Println("WARNING: Unable to figure out what the fee is") } 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") } } }