func DecodeTx(tx *btc.Tx) (s string, missinginp bool, totinp, totout uint64, e error) { s += fmt.Sprintln("Transaction details (for your information):") s += fmt.Sprintln(len(tx.TxIn), "Input(s):") for i := range tx.TxIn { s += fmt.Sprintf(" %3d %s", i, tx.TxIn[i].Input.String()) var po *btc.TxOut inpid := btc.NewUint256(tx.TxIn[i].Input.Hash[:]) if txinmem, ok := network.TransactionsToSend[inpid.BIdx()]; ok { s += fmt.Sprint(" mempool") if int(tx.TxIn[i].Input.Vout) >= len(txinmem.TxOut) { s += fmt.Sprintf(" - Vout TOO BIG (%d/%d)!", int(tx.TxIn[i].Input.Vout), len(txinmem.TxOut)) } else { po = txinmem.TxOut[tx.TxIn[i].Input.Vout] } } else { po, _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input) if po != nil { s += fmt.Sprintf("%8d", po.BlockHeight) } } if po != nil { ok := btc.VerifyTxScript(tx.TxIn[i].ScriptSig, po.Pk_script, i, tx, true) if !ok { s += fmt.Sprintln("\nERROR: The transacion does not have a valid signature.") e = errors.New("Invalid signature") return } totinp += po.Value s += fmt.Sprintf(" %15.8f BTC @ %s\n", float64(po.Value)/1e8, btc.NewAddrFromPkScript(po.Pk_script, common.Testnet).String()) } else { s += fmt.Sprintln(" - UNKNOWN INPUT") missinginp = true } } s += fmt.Sprintln(len(tx.TxOut), "Output(s):") for i := range tx.TxOut { totout += tx.TxOut[i].Value adr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, common.Testnet) if adr != nil { s += fmt.Sprintf(" %15.8f BTC to adr %s\n", float64(tx.TxOut[i].Value)/1e8, adr.String()) } else { s += fmt.Sprintf(" %15.8f BTC to scr %s\n", float64(tx.TxOut[i].Value)/1e8, hex.EncodeToString(tx.TxOut[i].Pk_script)) } } if missinginp { s += fmt.Sprintln("WARNING: There are missing inputs and we cannot calc input BTC amount.") s += fmt.Sprintln("If there is somethign wrong with this transaction, you can loose money...") } else { s += fmt.Sprintf("All OK: %.8f BTC in -> %.8f BTC out, with %.8f BTC fee\n", float64(totinp)/1e8, float64(totout)/1e8, float64(totinp-totout)/1e8) } return }
func output_tx_xml(w http.ResponseWriter, id string) { txid := btc.NewUint256FromString(id) w.Write([]byte("<tx>")) fmt.Fprint(w, "<id>", id, "</id>") if t2s, ok := network.TransactionsToSend[txid.BIdx()]; ok { w.Write([]byte("<status>OK</status>")) tx := t2s.Tx w.Write([]byte("<inputs>")) for i := range tx.TxIn { w.Write([]byte("<input>")) var po *btc.TxOut inpid := btc.NewUint256(tx.TxIn[i].Input.Hash[:]) if txinmem, ok := network.TransactionsToSend[inpid.BIdx()]; ok { if int(tx.TxIn[i].Input.Vout) < len(txinmem.TxOut) { po = txinmem.TxOut[tx.TxIn[i].Input.Vout] } } else { po, _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input) } if po != nil { ok := btc.VerifyTxScript(tx.TxIn[i].ScriptSig, po.Pk_script, i, tx, true) if !ok { w.Write([]byte("<status>Script FAILED</status>")) } else { w.Write([]byte("<status>OK</status>")) } fmt.Fprint(w, "<value>", po.Value, "</value>") fmt.Fprint(w, "<addr>", btc.NewAddrFromPkScript(po.Pk_script, common.Testnet).String(), "</addr>") fmt.Fprint(w, "<block>", po.BlockHeight, "</block>") } else { w.Write([]byte("<status>UNKNOWN INPUT</status>")) } w.Write([]byte("</input>")) } w.Write([]byte("</inputs>")) w.Write([]byte("<outputs>")) for i := range tx.TxOut { w.Write([]byte("<output>")) fmt.Fprint(w, "<value>", tx.TxOut[i].Value, "</value>") adr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, common.Testnet) if adr != nil { fmt.Fprint(w, "<addr>", adr.String(), "</addr>") } else { fmt.Fprint(w, "<addr>", "scr:"+hex.EncodeToString(tx.TxOut[i].Pk_script), "</addr>") } w.Write([]byte("</output>")) } w.Write([]byte("</outputs>")) } else { w.Write([]byte("<status>Not found</status>")) } w.Write([]byte("</tx>")) }
// sign raw transaction with all the keys we have func dump_raw_tx() { tx := raw_tx_from_file(*dumptxfn) if tx == nil { fmt.Println("ERROR: Cannot decode the raw transaction") return } fmt.Println("Version:", tx.Version) 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 { dump_sigscript(tx.TxIn[i].ScriptSig) } } fmt.Println("TX OUT cnt:", len(tx.TxOut)) for i := range tx.TxOut { fmt.Printf("%4d) %20s BTC to ", i, btc.UintToBtc(tx.TxOut[i].Value)) addr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, *testnet) if addr != nil { fmt.Println("address", addr.String()) } else { fmt.Println("Pk_script", hex.EncodeToString(tx.TxOut[i].Pk_script)) } } fmt.Println("Lock Time:", tx.Lock_time) }
// This is called while accepting the block (from the chain's thread) func TxNotify(idx *btc.TxPrevOut, valpk *btc.TxOut) { var update_wallet bool mutex_bal.Lock() defer mutex_bal.Unlock() if valpk != nil { // Extract hash160 from pkscript adr := btc.NewAddrFromPkScript(valpk.Pk_script, common.Testnet) if adr == nil { return // We do not monitor this address } if rec, ok := CachedAddrs[adr.Hash160]; ok { rec.Value += valpk.Value utxo := new(btc.OneUnspentTx) utxo.TxPrevOut = *idx utxo.Value = valpk.Value utxo.MinedAt = valpk.BlockHeight utxo.BtcAddr = CacheUnspent[rec.CacheIndex].BtcAddr CacheUnspent[rec.CacheIndex].AllUnspentTx = append(CacheUnspent[rec.CacheIndex].AllUnspentTx, utxo) CacheUnspentIdx[po2idx(idx)] = &OneCachedUnspentIdx{Index: rec.CacheIndex, Record: utxo} if rec.InWallet { update_wallet = true } } } else { ii := po2idx(idx) if ab, present := CacheUnspentIdx[ii]; present { adrec := CacheUnspent[ab.Index] //println("removing", idx.String()) rec := CachedAddrs[adrec.BtcAddr.Hash160] if rec == nil { panic("rec not found for " + adrec.BtcAddr.String()) } rec.Value -= ab.Record.Value if rec.InWallet { update_wallet = true } for j := range adrec.AllUnspentTx { if adrec.AllUnspentTx[j] == ab.Record { //println("found it at index", j) adrec.AllUnspentTx = append(adrec.AllUnspentTx[:j], adrec.AllUnspentTx[j+1:]...) break } } delete(CacheUnspentIdx, ii) } } if MyWallet != nil && update_wallet { MyBalance = nil for i := range MyWallet.Addrs { rec, _ := CachedAddrs[MyWallet.Addrs[i].Hash160] MyBalance = append(MyBalance, CacheUnspent[rec.CacheIndex].AllUnspentTx...) } sort_and_sum() BalanceChanged = true } }
func load_tx(par string) { txd, er := hex.DecodeString(par) if er != nil { println(er.Error()) } tx, le := btc.NewTx(txd) if le != len(txd) { fmt.Println("WARNING: Tx length mismatch", le, len(txd)) } txid := btc.NewSha2Hash(txd) fmt.Println(len(tx.TxIn), "inputs:") var totinp, totout uint64 var missinginp bool for i := range tx.TxIn { fmt.Printf(" %3d %s", i, tx.TxIn[i].Input.String()) po, _ := BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input) if po != nil { totinp += po.Value fmt.Printf(" %15.8f BTC @ %s\n", float64(po.Value)/1e8, btc.NewAddrFromPkScript(po.Pk_script, AddrVersion).String()) } else { fmt.Println(" * no such unspent in the blockchain *") missinginp = true } } fmt.Println(len(tx.TxOut), "outputs:") for i := range tx.TxOut { totout += tx.TxOut[i].Value fmt.Printf(" %15.8f BTC to %s\n", float64(tx.TxOut[i].Value)/1e8, btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, AddrVersion).String()) } if missinginp { fmt.Println("WARNING: There are missing inputs, so you cannot calc input BTC amount") } else { fmt.Printf("%.8f BTC in -> %.8f BTC out, with %.8f BTC fee\n", float64(totinp)/1e8, float64(totout)/1e8, float64(totinp-totout)/1e8) } TransactionsToSend[txid.Hash] = txd fmt.Println("Transaction", txid.String(), "stored in the memory pool") fmt.Println("Execute 'stx " + txid.String() + "' to send it out") }
// 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) } pubad := btc.NewAddrFromPkScript(uo.Pk_script, *testnet) 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()) } }
// This is called while accepting the block (from teh chain's thread) func TxNotify(idx *btc.TxPrevOut, valpk *btc.TxOut) { var update_wallet bool mutex_bal.Lock() defer mutex_bal.Unlock() if valpk != nil { // Extract hash160 from pkscript adr := btc.NewAddrFromPkScript(valpk.Pk_script, common.Testnet) if adr == nil { return // We do not monitor this address } if rec, ok := CachedAddrs[adr.Hash160]; ok { rec.Value += valpk.Value utxo := btc.OneUnspentTx{TxPrevOut: *idx, Value: valpk.Value, MinedAt: valpk.BlockHeight, BtcAddr: CacheUnspent[rec.CacheIndex].BtcAddr} CacheUnspent[rec.CacheIndex].AllUnspentTx = append(CacheUnspent[rec.CacheIndex].AllUnspentTx, utxo) CacheUnspentIdx[po2idx(idx)] = [2]uint{rec.CacheIndex, uint(len(CacheUnspent[rec.CacheIndex].AllUnspentTx)) - 1} if rec.InWallet { update_wallet = true } } } else { ii := po2idx(idx) if ab, present := CacheUnspentIdx[ii]; present { adrec := CacheUnspent[ab[0]] rec := CachedAddrs[adrec.BtcAddr.Hash160] rec.Value -= adrec.AllUnspentTx[ab[1]].Value if rec.InWallet { update_wallet = true } adrec.AllUnspentTx = append(adrec.AllUnspentTx[:ab[1]], adrec.AllUnspentTx[ab[1]+1:]...) delete(CacheUnspentIdx, ii) } } if MyWallet != nil && update_wallet { MyBalance = nil for i := range MyWallet.Addrs { rec, _ := CachedAddrs[MyWallet.Addrs[i].Hash160] MyBalance = append(MyBalance, CacheUnspent[rec.CacheIndex].AllUnspentTx...) } BalanceChanged = true } }
// 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("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 { dump_sigscript(tx.TxIn[i].ScriptSig) } else { unsigned++ } } } fmt.Println("TX OUT cnt:", len(tx.TxOut)) for i := range tx.TxOut { fmt.Printf("%4d) %20s BTC to ", i, btc.UintToBtc(tx.TxOut[i].Value)) addr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, *testnet) if addr != nil { fmt.Println("address", addr.String()) } else { fmt.Println("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("Number of unsigned inputs:", unsigned) } else { fmt.Println("All the inputs seems to be signed") } } }
func main() { fmt.Println("Gocoin FetchBalnace version", btc.SourcesTag) if len(os.Args) < 2 { print_help() return } var addrs []*btc.BtcAddr if len(os.Args) == 2 { fi, er := os.Stat(os.Args[1]) if er == nil && fi.Size() > 10 && !fi.IsDir() { wal := wallet.NewWallet(os.Args[1]) if wal != nil { fmt.Println("Found", len(wal.Addrs), "address(es) in", wal.FileName) addrs = wal.Addrs } } } if len(addrs) == 0 { for i := 1; i < len(os.Args); i++ { a, e := btc.NewAddrFromString(os.Args[i]) if e != nil { println(os.Args[i], ": ", e.Error()) return } else { addrs = append(addrs, a) } } } if len(addrs) == 0 { print_help() return } url := "http://blockchain.info/unspent?active=" for i := range addrs { if i > 0 { url += "|" } url += addrs[i].String() } var sum, outcnt uint64 r, er := http.Get(url) if er == nil && r.StatusCode == 200 { defer r.Body.Close() c, _ := ioutil.ReadAll(r.Body) var r restype er = json.Unmarshal(c[:], &r) if er == nil { os.RemoveAll("balance/") os.Mkdir("balance/", 0700) unsp, _ := os.Create("balance/unspent.txt") for i := 0; i < len(r.Unspent_outputs); i++ { pkscr, _ := hex.DecodeString(r.Unspent_outputs[i].Script) b58adr := "???" if pkscr != nil { ba := btc.NewAddrFromPkScript(pkscr, btc.ADDRVER_BTC) if ba != nil { b58adr = ba.String() } } txidlsb, _ := hex.DecodeString(r.Unspent_outputs[i].Tx_hash) if txidlsb != nil { txid := btc.NewUint256(txidlsb) if GetTx(txid, int(r.Unspent_outputs[i].Tx_output_n)) { fmt.Fprintf(unsp, "%s-%03d # %.8f @ %s, %d confs\n", txid.String(), r.Unspent_outputs[i].Tx_output_n, float64(r.Unspent_outputs[i].Value)/1e8, b58adr, r.Unspent_outputs[i].Confirmations) sum += r.Unspent_outputs[i].Value outcnt++ } else { fmt.Printf(" - cannot fetch %s-%03d\n", txid.String(), r.Unspent_outputs[i].Tx_output_n) } } } unsp.Close() if outcnt > 0 { fmt.Printf("Total %.8f BTC in %d unspent outputs.\n", float64(sum)/1e8, 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.") } } else { fmt.Println("Unspent json.Unmarshal", er.Error()) } } else { if er != nil { fmt.Println("Unspent ", er.Error()) } else { fmt.Println("Unspent HTTP StatusCode", r.StatusCode) } } }