func raw_tx(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } defer func() { if r := recover(); r != nil { fmt.Fprintln(w, "Error") if err, ok := r.(error); ok { fmt.Fprintln(w, err.Error()) } } }() if len(r.Form["id"]) == 0 { fmt.Println("No id given") return } txid := btc.NewUint256FromString(r.Form["id"][0]) fmt.Fprintln(w, "TxID:", txid.String()) if tx, ok := network.TransactionsToSend[txid.BIdx()]; ok { s, _, _, _, _ := usif.DecodeTx(tx.Tx) w.Write([]byte(s)) } else { fmt.Fprintln(w, "Not found") } }
func output_utxo_tx_xml(w http.ResponseWriter, minedid, minedat string) { txid := btc.NewUint256FromString(minedid) if txid == nil { return } block_number, er := strconv.ParseUint(minedat, 10, 32) if er != nil { return } lck := new(usif.OneLock) lck.In.Add(1) lck.Out.Add(1) usif.LocksChan <- lck lck.In.Wait() w.Write([]byte("<tx>")) fmt.Fprint(w, "<id>", minedid, "</id>") if dat, er := common.BlockChain.GetRawTx(uint32(block_number), txid); er == nil { w.Write([]byte("<status>OK</status>")) w.Write([]byte(fmt.Sprint("<size>", len(dat), "</size>"))) tx, _ := btc.NewTx(dat) output_tx_xml(w, tx) } else { w.Write([]byte("<status>Not found</status>")) } w.Write([]byte("</tx>")) lck.Out.Done() }
func parserec(vv []interface{}) (ret *testvector) { ret = new(testvector) for i, u := range vv[0].([]interface{}) { switch uu := u.(type) { case []interface{}: txid := btc.NewUint256FromString(uu[0].(string)) newrec := oneinp{txid: txid, vout: int(uu[1].(float64)), pkscr: uu[2].(string)} if len(uu) > 3 { newrec.value = uint64(uu[3].(float64)) } ret.inps = append(ret.inps, newrec) default: fmt.Printf(" - %d is of a type %T\n", i, uu) } } ret.tx = vv[1].(string) params := vv[2].(string) var e error ret.ver_flags, e = decode_flags(params) // deifned in script_test.go if e != nil { println("skip", params) ret.skip = e.Error() } 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>")) w.Write([]byte(fmt.Sprint("<len>", len(t2s.Data), "</len>"))) 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 := script.VerifyTxScript(tx.TxIn[i].ScriptSig, po.Pk_script, i, tx, script.VER_P2SH|script.VER_DERSIG) if !ok { w.Write([]byte("<status>Script FAILED</status>")) } else { w.Write([]byte("<status>OK</status>")) } fmt.Fprint(w, "<value>", po.Value, "</value>") ads := "???" if ad := btc.NewAddrFromPkScript(po.Pk_script, common.Testnet); ad != nil { ads = ad.String() } fmt.Fprint(w, "<addr>", ads, "</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>")) }
func dec_tx(par string) { txid := btc.NewUint256FromString(par) if txid == nil { fmt.Println("You must specify a valid transaction ID for this command.") list_txs("") return } if tx, ok := network.TransactionsToSend[txid.BIdx()]; ok { s, _, _, _, _ := usif.DecodeTx(tx.Tx) fmt.Println(s) } else { fmt.Println("No such transaction ID in the memory pool.") } }
func save_tx(par string) { txid := btc.NewUint256FromString(par) if txid == nil { fmt.Println("You must specify a valid transaction ID for this command.") list_txs("") return } if tx, ok := network.TransactionsToSend[txid.BIdx()]; ok { fn := tx.Hash.String() + ".tx" ioutil.WriteFile(fn, tx.Data, 0600) fmt.Println("Saved to", fn) } else { fmt.Println("No such transaction ID in the memory pool.") } }
func main() { fmt.Println("Gocoin FetchTx version", gocoin.Version) if len(os.Args) < 2 { fmt.Println("Specify transaction id on the command line (MSB).") return } txid := btc.NewUint256FromString(os.Args[1]) rawtx := utils.GetTxFromWeb(txid) if rawtx == nil { fmt.Println("Error fetching the transaction") } else { ioutil.WriteFile(txid.String()+".tx", rawtx, 0666) } }
func parserec(vv []interface{}) (ret *testvector) { ret = new(testvector) for i, u := range vv[0].([]interface{}) { switch uu := u.(type) { case []interface{}: txid := btc.NewUint256FromString(uu[0].(string)) ret.inps = append(ret.inps, oneinp{txid: txid, vout: int(uu[1].(float64)), pkscr: uu[2].(string)}) default: fmt.Printf(" - %d is of a type %T\n", i, uu) } } ret.tx = vv[1].(string) ret.p2sh = vv[2].(bool) return }
func del_tx(par string) { txid := btc.NewUint256FromString(par) if txid == nil { fmt.Println("You must specify a valid transaction ID for this command.") list_txs("") return } network.TxMutex.Lock() if _, ok := network.TransactionsToSend[txid.BIdx()]; !ok { network.TxMutex.Unlock() fmt.Println("No such transaction ID in the memory pool.") list_txs("") return } delete(network.TransactionsToSend, txid.BIdx()) network.TxMutex.Unlock() fmt.Println("Transaction", txid.String(), "removed from the memory pool") }
func send_inv(par string) { cs := strings.Split(par, " ") if len(cs) != 2 { println("Specify hash and type") return } ha := btc.NewUint256FromString(cs[1]) if ha == nil { println("Incorrect hash") return } v, e := strconv.ParseInt(cs[0], 10, 32) if e != nil { println("Incorrect type:", e.Error()) return } network.NetRouteInv(uint32(v), ha, nil) fmt.Println("Inv sent to all peers") }
func NewUnspRec(l []byte) (uns *unspRec) { if l[64] != '-' { return nil } txid := btc.NewUint256FromString(string(l[:64])) if txid == nil { return nil } rst := strings.SplitN(string(l[65:]), " ", 2) vout, e := strconv.ParseUint(rst[0], 10, 32) if e != nil { return nil } uns = new(unspRec) uns.TxPrevOut.Hash = txid.Hash uns.TxPrevOut.Vout = uint32(vout) if len(rst) > 1 { uns.label = rst[1] } if first_determ_idx < len(keys) { str := string(l) if sti := strings.Index(str, "_StealthC:"); sti != -1 { c, e := hex.DecodeString(str[sti+10 : sti+10+64]) if e != nil { fmt.Println("ERROR at stealth", txid.String(), vout, e.Error()) } else { // add a new key to the wallet sec := btc.DeriveNextPrivate(keys[first_determ_idx].Key, c) rec := btc.NewPrivateAddr(sec, ver_secret(), true) // stealth keys are always compressed rec.BtcAddr.Extra.Label = uns.label keys = append(keys, rec) uns.stealth = true uns.key = rec } } } return }
func send1_tx(par string) { txid := btc.NewUint256FromString(par) if txid == nil { fmt.Println("You must specify a valid transaction ID for this command.") list_txs("") return } network.TxMutex.Lock() if ptx, ok := network.TransactionsToSend[txid.BIdx()]; ok { network.TxMutex.Unlock() usif.SendInvToRandomPeer(1, txid) ptx.Invsentcnt++ fmt.Println("INV for TxID", txid.String(), "sent to a random node") fmt.Println("If it does not appear in the chain, you may want to redo it.") } else { network.TxMutex.Unlock() fmt.Println("No such transaction ID in the memory pool.") list_txs("") } }
func dump_block(s string) { h := btc.NewUint256FromString(s) if h == nil { println("Specify block's hash") return } bl, _, e := common.BlockChain.Blocks.BlockGet(h) if e != nil { println(e.Error()) return } fn := h.String() + ".bin" f, e := os.Create(fn) if e != nil { println(e.Error()) return } f.Write(bl) f.Close() fmt.Println("Block saved to file:", fn) }
func dump_block(s string) { h := btc.NewUint256FromString(s) if h == nil { println("Specify block's hash") return } crec, _, er := common.BlockChain.Blocks.BlockGetExt(btc.NewUint256(h.Hash[:])) if er != nil { println(er.Error()) return } ioutil.WriteFile(h.String()+".bin", crec.Data, 0700) if crec.Block == nil { crec.Block, _ = btc.NewBlock(crec.Data) } if crec.Block.OldData == nil { crec.Block.BuildTxList() } ioutil.WriteFile(h.String()+".old", crec.Block.OldData, 0700) fmt.Println("Block saved") }
func TestSighash(t *testing.T) { var arr [][]interface{} dat, er := ioutil.ReadFile("../test/sighash.json") if er != nil { println(er.Error()) return } r := bytes.NewBuffer(dat) d := json.NewDecoder(r) d.UseNumber() er = d.Decode(&arr) if er != nil { println(er.Error()) return } for i := range arr { if len(arr[i]) == 5 { tmp, _ := hex.DecodeString(arr[i][0].(string)) tx, _ := btc.NewTx(tmp) if tx == nil { t.Error("Cannot decode tx from text number", i) continue } tmp, _ = hex.DecodeString(arr[i][1].(string)) // script iidx, _ := arr[i][2].(json.Number).Int64() htype, _ := arr[i][3].(json.Number).Int64() got := tx.SignatureHash(tmp, int(iidx), int32(htype)) exp := btc.NewUint256FromString(arr[i][4].(string)) if !bytes.Equal(exp.Hash[:], got) { t.Error("SignatureHash mismatch at index", i) } } } }
func host_init() { var e error BtcRootDir := sys.BitcoinHome() common.GocoinHomeDir = common.CFG.Datadir + string(os.PathSeparator) common.Testnet = common.CFG.Testnet // So chaging this value would will only affect the behaviour after restart if common.CFG.Testnet { // testnet3 common.GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") common.Magic = [4]byte{0x0B, 0x11, 0x09, 0x07} common.GocoinHomeDir += common.DataSubdir() + string(os.PathSeparator) BtcRootDir += "testnet3" + string(os.PathSeparator) common.MaxPeersNeeded = 2000 } else { common.GenesisBlock = btc.NewUint256FromString("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") common.Magic = [4]byte{0xF9, 0xBE, 0xB4, 0xD9} common.GocoinHomeDir += common.DataSubdir() + string(os.PathSeparator) common.MaxPeersNeeded = 5000 } // Lock the folder os.MkdirAll(common.GocoinHomeDir, 0770) sys.LockDatabaseDir(common.GocoinHomeDir) fi, e := os.Stat(common.GocoinHomeDir + "blockchain.dat") if e != nil { os.RemoveAll(common.GocoinHomeDir) fmt.Println("You seem to be running Gocoin for the fist time on this PC") fi, e = os.Stat(BtcRootDir + "blocks/blk00000.dat") if e == nil && fi.Size() > 1024*1024 { fmt.Println("There is a database from Satoshi client on your disk...") if textui.AskYesNo("Do you want to import this database into Gocoin?") { import_blockchain(BtcRootDir + "blocks") } } } fmt.Println("Loading UTXO-db and P2SH/P2KH outputs of", btc.UintToBtc(common.AllBalMinVal), "BTC or more") __exit := make(chan bool) __done := make(chan bool) go func() { for { select { case s := <-killchan: fmt.Println(s) chain.AbortNow = true case <-__exit: __done <- true return } } }() ext := &chain.NewChanOpts{NotifyTxAdd: wallet.TxNotifyAdd, NotifyTxDel: wallet.TxNotifyDel, LoadWalk: wallet.NewUTXO, UTXOVolatileMode: common.FLAG.VolatileUTXO, UndoBlocks: common.FLAG.UndoBlocks, SetBlocksDBCacheSize: true, BlocksDBCacheSize: int(common.CFG.Memory.MaxCachedBlocks)} sta := time.Now().UnixNano() common.BlockChain = chain.NewChainExt(common.GocoinHomeDir, common.GenesisBlock, common.FLAG.Rescan, ext) sto := time.Now().UnixNano() if chain.AbortNow { fmt.Printf("Blockchain opening aborted after %.3f seconds\n", float64(sto-sta)/1e9) common.BlockChain.Close() sys.UnlockDatabaseDir() os.Exit(1) } al, sy := sys.MemUsed() fmt.Printf("Blockchain open in %.3f seconds. %d + %d MB of RAM used (%d)\n", float64(sto-sta)/1e9, al>>20, qdb.ExtraMemoryConsumed>>20, sy>>20) common.StartTime = time.Now() __exit <- true _ = <-__done }
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) }
// load the content of the "balance/" folder func load_balance(showbalance bool) { var unknownInputs, multisigInputs int f, e := os.Open("balance/unspent.txt") if e != nil { println(e.Error()) return } rd := bufio.NewReader(f) for { l, _, e := rd.ReadLine() if len(l) == 0 && e != nil { break } if l[64] == '-' { txid := btc.NewUint256FromString(string(l[:64])) rst := strings.SplitN(string(l[65:]), " ", 2) vout, _ := strconv.ParseUint(rst[0], 10, 32) uns := new(btc.TxPrevOut) copy(uns.Hash[:], txid.Hash[:]) uns.Vout = uint32(vout) lab := "" if len(rst) > 1 { lab = rst[1] } str := string(l) if sti := strings.Index(str, "_StealthC:"); sti != -1 { c, e := hex.DecodeString(str[sti+10 : sti+10+64]) if e != nil { fmt.Println("ERROR at stealth", txid.String(), vout, e.Error()) } else { // add a new key to the wallet sec := btc.DeriveNextPrivate(first_seed[:], c) is_stealth[len(priv_keys)] = true priv_keys = append(priv_keys, sec) labels = append(labels, lab) pub_key := btc.PublicFromPrivate(sec, true) publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub_key, AddrVerPubkey())) compressed_key = append(compressed_key, true) // stealth keys are always compressed } } if _, ok := loadedTxs[txid.Hash]; !ok { tf, _ := os.Open("balance/" + txid.String() + ".tx") if tf != nil { siz, _ := tf.Seek(0, os.SEEK_END) tf.Seek(0, os.SEEK_SET) buf := make([]byte, siz) tf.Read(buf) tf.Close() th := btc.Sha2Sum(buf) if bytes.Equal(th[:], txid.Hash[:]) { tx, _ := btc.NewTx(buf) if tx != nil { loadedTxs[txid.Hash] = tx } else { println("transaction is corrupt:", txid.String()) } } else { println("transaction file is corrupt:", txid.String()) os.Exit(1) } } else { println("transaction file not found:", txid.String()) os.Exit(1) } } // Sum up all the balance and check if we have private key for this input uo := UO(uns) add_it := true if !btc.IsP2SH(uo.Pk_script) { fnd := false for j := range publ_addrs { if publ_addrs[j].Owns(uo.Pk_script) { fnd = true break } } if !fnd { if *onlvalid { add_it = false } if showbalance { unknownInputs++ if *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "does not belong to your wallet (cannot sign it)") } } } } else { if *onlvalid { add_it = false } if *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "belongs to a multisig address") } multisigInputs++ } if add_it { unspentOuts = append(unspentOuts, uns) unspentOutsLabel = append(unspentOutsLabel, lab) totBtc += UO(uns).Value } } } f.Close() fmt.Printf("You have %.8f BTC in %d unspent outputs. %d inputs are multisig type\n", float64(totBtc)/1e8, len(unspentOuts), multisigInputs) if showbalance { if unknownInputs > 0 { fmt.Printf("WARNING: Some inputs (%d) cannot be spent with this password (-v to print them)\n", unknownInputs) } } }
func host_init() { var e error BtcRootDir := sys.BitcoinHome() if common.CFG.Datadir == "" { common.GocoinHomeDir = BtcRootDir + "gocoin" + string(os.PathSeparator) } else { common.GocoinHomeDir = common.CFG.Datadir + string(os.PathSeparator) } common.Testnet = common.CFG.Testnet // So chaging this value would will only affect the behaviour after restart if common.CFG.Testnet { // testnet3 common.GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") common.Magic = [4]byte{0x0B, 0x11, 0x09, 0x07} common.GocoinHomeDir += "tstnet" + string(os.PathSeparator) BtcRootDir += "testnet3" + string(os.PathSeparator) network.AlertPubKey, _ = hex.DecodeString("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a") common.MaxPeersNeeded = 100 } else { common.GenesisBlock = btc.NewUint256FromString("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") common.Magic = [4]byte{0xF9, 0xBE, 0xB4, 0xD9} common.GocoinHomeDir += "btcnet" + string(os.PathSeparator) network.AlertPubKey, _ = hex.DecodeString("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284") common.MaxPeersNeeded = 1000 } // Lock the folder os.MkdirAll(common.GocoinHomeDir, 0770) os.MkdirAll(common.GocoinHomeDir+"wallet", 0770) sys.LockDatabaseDir(common.GocoinHomeDir) fi, e := os.Stat(common.GocoinHomeDir + "blockchain.dat") if e != nil { os.RemoveAll(common.GocoinHomeDir) fmt.Println("You seem to be running Gocoin for the fist time on this PC") fi, e = os.Stat(BtcRootDir + "blocks/blk00000.dat") if e == nil && fi.Size() > 1024*1024 { fmt.Println("There is a database from Satoshi client on your disk...") if textui.AskYesNo("Do you want to import this database into Gocoin?") { import_blockchain(BtcRootDir + "blocks") } } } // cache the current balance of all the addresses from the current wallet files wallet.LoadAllWallets() fmt.Println("Loading UTXO database while checking balance of", len(wallet.MyWallet.Addrs), "addresses... (press Ctrl-C to interrupt)") __exit := make(chan bool) __done := make(chan bool) go func() { for { select { case s := <-killchan: fmt.Println(s) chain.AbortNow = true case <-__exit: __done <- true return } } }() ext := &chain.NewChanOpts{NotifyTx: wallet.TxNotify, NotifyStealthTx: wallet.StealthNotify, LoadWalk: wallet.NewUTXO, LoadFlush: wallet.DoPendingStealths} sta := time.Now().UnixNano() common.BlockChain = chain.NewChainExt(common.GocoinHomeDir, common.GenesisBlock, common.FLAG.Rescan, ext) sto := time.Now().UnixNano() if chain.AbortNow { fmt.Printf("Blockchain opening aborted after %.3f seconds\n", float64(sto-sta)/1e9) common.BlockChain.Close() sys.UnlockDatabaseDir() os.Exit(1) } wallet.ChainInitDone() al, sy := sys.MemUsed() fmt.Printf("Blockchain open in %.3f seconds. %d + %d MB of RAM used (%d)\n", float64(sto-sta)/1e9, al>>20, qdb.ExtraMemoryConsumed>>20, sy>>20) common.StartTime = time.Now() __exit <- true _ = <-__done }
func xml_txs2s(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } if checksid(r) { if len(r.Form["del"]) > 0 { tid := btc.NewUint256FromString(r.Form["del"][0]) if tid != nil { network.TxMutex.Lock() delete(network.TransactionsToSend, tid.BIdx()) network.TxMutex.Unlock() } } if len(r.Form["send"]) > 0 { tid := btc.NewUint256FromString(r.Form["send"][0]) if tid != nil { network.TxMutex.Lock() if ptx, ok := network.TransactionsToSend[tid.BIdx()]; ok { network.TxMutex.Unlock() cnt := network.NetRouteInv(1, tid, nil) if cnt == 0 { usif.SendInvToRandomPeer(1, tid) } else { ptx.Invsentcnt += cnt } } else { network.TxMutex.Unlock() } } } if len(r.Form["sendone"]) > 0 { tid := btc.NewUint256FromString(r.Form["sendone"][0]) if tid != nil { network.TxMutex.Lock() if ptx, ok := network.TransactionsToSend[tid.BIdx()]; ok { network.TxMutex.Unlock() usif.SendInvToRandomPeer(1, tid) ptx.Invsentcnt++ } else { network.TxMutex.Unlock() } } } } w.Header()["Content-Type"] = []string{"text/xml"} if len(r.Form["id"]) > 0 { output_tx_xml(w, r.Form["id"][0]) return } w.Write([]byte("<txpool>")) network.TxMutex.Lock() for _, v := range network.TransactionsToSend { if len(r.Form["ownonly"]) > 0 && v.Own == 0 { continue } w.Write([]byte("<tx>")) fmt.Fprint(w, "<id>", v.Tx.Hash.String(), "</id>") fmt.Fprint(w, "<time>", v.Firstseen.Unix(), "</time>") fmt.Fprint(w, "<len>", len(v.Data), "</len>") fmt.Fprint(w, "<own>", v.Own, "</own>") fmt.Fprint(w, "<firstseen>", v.Firstseen.Unix(), "</firstseen>") fmt.Fprint(w, "<invsentcnt>", v.Invsentcnt, "</invsentcnt>") fmt.Fprint(w, "<sentcnt>", v.SentCnt, "</sentcnt>") fmt.Fprint(w, "<sentlast>", v.Lastsent.Unix(), "</sentlast>") fmt.Fprint(w, "<volume>", v.Volume, "</volume>") fmt.Fprint(w, "<fee>", v.Fee, "</fee>") fmt.Fprint(w, "<blocked>", v.Blocked, "</blocked>") w.Write([]byte("</tx>")) } network.TxMutex.Unlock() w.Write([]byte("</txpool>")) }
func xml_txs2s(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } w.Header()["Content-Type"] = []string{"text/xml"} if len(r.Form["minedid"]) > 0 && len(r.Form["minedat"]) > 0 { output_utxo_tx_xml(w, r.Form["minedid"][0], r.Form["minedat"][0]) return } if len(r.Form["id"]) > 0 { txid := btc.NewUint256FromString(r.Form["id"][0]) if txid == nil { return } network.TxMutex.Lock() defer network.TxMutex.Unlock() if t2s, ok := network.TransactionsToSend[txid.BIdx()]; ok { tx_xml(w, t2s, true) } else { w.Write([]byte("<tx>")) fmt.Fprint(w, "<id>", txid.String(), "</id>") w.Write([]byte("<status>Not found</status>")) w.Write([]byte("</tx>")) } return } if checksid(r) { if len(r.Form["del"]) > 0 { tid := btc.NewUint256FromString(r.Form["del"][0]) if tid != nil { network.TxMutex.Lock() if tts, ok := network.TransactionsToSend[tid.BIdx()]; ok { network.DeleteToSend(tts) } network.TxMutex.Unlock() } } if len(r.Form["send"]) > 0 { tid := btc.NewUint256FromString(r.Form["send"][0]) if tid != nil { network.TxMutex.Lock() if ptx, ok := network.TransactionsToSend[tid.BIdx()]; ok { network.TxMutex.Unlock() cnt := network.NetRouteInv(1, tid, nil) if cnt == 0 { usif.SendInvToRandomPeer(1, tid) } else { ptx.Invsentcnt += cnt } } else { network.TxMutex.Unlock() } } } if len(r.Form["sendone"]) > 0 { tid := btc.NewUint256FromString(r.Form["sendone"][0]) if tid != nil { network.TxMutex.Lock() if ptx, ok := network.TransactionsToSend[tid.BIdx()]; ok { network.TxMutex.Unlock() usif.SendInvToRandomPeer(1, tid) ptx.Invsentcnt++ } else { network.TxMutex.Unlock() } } } if len(r.Form["cnt"]) > 0 { u, e := strconv.ParseUint(r.Form["cnt"][0], 10, 32) if e == nil && u > 0 && u < 10e3 { txs2s_count = int(u) } } if len(r.Form["sort"]) > 0 && len(r.Form["sort"][0]) == 3 { txs2s_sort = r.Form["sort"][0] } txs2s_sort_desc = len(r.Form["descending"]) > 0 } network.TxMutex.Lock() defer network.TxMutex.Unlock() sorted := make(sortedTxList, len(network.TransactionsToSend)) var cnt int for _, v := range network.TransactionsToSend { if len(r.Form["ownonly"]) > 0 && v.Own == 0 { continue } sorted[cnt] = v cnt++ } sorted = sorted[:cnt] sort.Sort(sorted) w.Write([]byte("<txpool>")) for cnt = 0; cnt < len(sorted) && cnt < txs2s_count; cnt++ { v := sorted[cnt] tx_xml(w, v, false) } w.Write([]byte("</txpool>")) }
"github.com/piotrnar/gocoin/lib/btc" "github.com/piotrnar/gocoin/lib/chain" "github.com/piotrnar/gocoin/lib/others/sys" "os" "os/signal" "runtime" "runtime/debug" "time" ) var ( Magic [4]byte = [4]byte{0xF9, 0xBE, 0xB4, 0xD9} StartTime time.Time TheBlockChain *chain.Chain GenesisBlock *btc.Uint256 = btc.NewUint256FromString("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") TrustUpTo uint32 GlobalExit bool // CommandLineSwitches LastTrustedBlock string // -trust GocoinHomeDir string // -d OnlyStoreBlocks bool // -b MaxNetworkConns uint // -n GCPerc int // -g SeedNode string // -s DoThePings bool // -p MemForBlocks uint // -m (in megabytes) Testnet bool // -t )
func main() { flag.BoolVar(&fl_help, "h", false, "Show help") flag.UintVar(&fl_block, "block", 0, "Print details of the given block number (or start -verify from it)") flag.BoolVar(&fl_scan, "scan", false, "Scan database for first extra blocks") flag.BoolVar(&fl_defrag, "defrag", false, "Purge all the orphaned blocks") flag.UintVar(&fl_stop, "stop", 0, "Stop after so many scan errors") flag.StringVar(&fl_dir, "dir", "", "Use blockdb from this directory") flag.StringVar(&fl_split, "split", "", "Split blockdb at this block's hash") flag.UintVar(&fl_skip, "skip", 0, "Skip this many blocks when splitting") flag.StringVar(&fl_append, "append", "", "Append blocks from this folder to the database") flag.BoolVar(&fl_trunc, "trunc", false, "Truncate insted of splitting") flag.BoolVar(&fl_commit, "commit", false, "Optimize the size of the data file") flag.BoolVar(&fl_verify, "verify", false, "Verify each block inside the database") flag.StringVar(&fl_savebl, "savebl", "", "Save block with the given hash to disk") flag.BoolVar(&fl_resetflags, "resetflags", false, "Reset all Invalid and Trusted flags when defragmenting") flag.Parse() if fl_help { flag.PrintDefaults() return } if fl_dir != "" && fl_dir[len(fl_dir)-1] != os.PathSeparator { fl_dir += string(os.PathSeparator) } if fl_append != "" { if fl_append[len(fl_append)-1] != os.PathSeparator { fl_append += string(os.PathSeparator) } fmt.Println("Loading", fl_append+"blockchain.new") dat, er := ioutil.ReadFile(fl_append + "blockchain.new") if er != nil { fmt.Println(er.Error()) return } f, er := os.Open(fl_append + "blockchain.dat") if er != nil { fmt.Println(er.Error()) return } fo, er := os.OpenFile(fl_dir+"blockchain.dat", os.O_WRONLY, 0600) if er != nil { f.Close() fmt.Println(er.Error()) return } datfilelen, _ := fo.Seek(0, os.SEEK_END) fmt.Println("Appending blocks data to blockchain.dat") for { var buf [1024 * 1024]byte n, _ := f.Read(buf[:]) if n > 0 { fo.Write(buf[:n]) } if n != len(buf) { break } } fo.Close() f.Close() fmt.Println("Now appending", len(dat)/136, "records to blockchain.new") fo, er = os.OpenFile(fl_dir+"blockchain.new", os.O_WRONLY, 0600) if er != nil { f.Close() fmt.Println(er.Error()) return } fo.Seek(0, os.SEEK_END) for off := 0; off < len(dat); off += 136 { sl := dat[off : off+136] newoffs := binary.LittleEndian.Uint64(sl[40:48]) + uint64(datfilelen) binary.LittleEndian.PutUint64(sl[40:48], newoffs) fo.Write(sl) } fo.Close() return } fmt.Println("Loading", fl_dir+"blockchain.new") dat, er := ioutil.ReadFile(fl_dir + "blockchain.new") if er != nil { fmt.Println(er.Error()) return } fmt.Println(len(dat)/136, "records") if fl_scan { var scan_errs uint last_bl_height := binary.LittleEndian.Uint32(dat[36:40]) exp_offset := uint64(binary.LittleEndian.Uint32(dat[48:52])) fmt.Println("Scanning database for first extra block(s)...") fmt.Println("First block in the file has height", last_bl_height) for off := 136; off < len(dat); off += 136 { sl := dat[off : off+136] height := binary.LittleEndian.Uint32(sl[36:40]) off_in_bl := binary.LittleEndian.Uint64(sl[40:48]) if height != last_bl_height+1 { fmt.Println("Out of sequence block number", height, last_bl_height+1, "found at offset", off) print_record(dat[off-136 : off]) print_record(dat[off : off+136]) fmt.Println() scan_errs++ } if off_in_bl != exp_offset { fmt.Println("Spare data found just before block number", height, off_in_bl, exp_offset) print_record(dat[off-136 : off]) print_record(dat[off : off+136]) scan_errs++ } if fl_stop != 0 && scan_errs >= fl_stop { break } last_bl_height = height exp_offset += uint64(binary.LittleEndian.Uint32(sl[48:52])) } return } if fl_defrag { blks := make(map[[32]byte]*one_tree_node, len(dat)/136) for off := 0; off < len(dat); off += 136 { sl := new_sl(dat[off : off+136]) blks[sl.HIdx()] = &one_tree_node{off: off, one_idx_rec: sl} } var maxbl uint32 var maxblptr *one_tree_node for _, v := range blks { v.parent = blks[v.PIdx()] h := v.Height() if h > maxbl { maxbl = h maxblptr = v } else if h == maxbl { maxblptr = nil } } fmt.Println("Max block height =", maxbl) if maxblptr == nil { fmt.Println("More than one block at maximum height - cannot continue") return } used := make(map[[32]byte]bool) var first_block *one_tree_node var total_data_size uint64 for n := maxblptr; n != nil; n = n.parent { if n.parent != nil { n.parent.next = n } used[n.PIdx()] = true if first_block == nil || first_block.Height() > n.Height() { first_block = n } total_data_size += uint64(n.DLen()) } if len(used) < len(blks) || fl_resetflags { fmt.Println("Purge", len(blks)-len(used), "blocks from the index file...") f, e := os.Create(fl_dir + "blockchain.tmp") if e != nil { println(e.Error()) return } var off int for n := first_block; n != nil; n = n.next { n.off = off n.sl[0] = n.sl[0] & 0xfc f.Write(n.sl) off += len(n.sl) } f.Close() os.Rename(fl_dir+"blockchain.tmp", fl_dir+"blockchain.new") } else { fmt.Println("The index file looks perfect") } for n := first_block; n != nil && n.next != nil; n = n.next { if n.next.DPos() < n.DPos() { fmt.Println("There is a problem... swapped order in the data file!", n.off) return } } fdat, er := os.OpenFile(fl_dir+"blockchain.dat", os.O_RDWR, 0600) if er != nil { println(er.Error()) return } if fl, _ := fdat.Seek(0, os.SEEK_END); uint64(fl) == total_data_size { fdat.Close() fmt.Println("All good - blockchain.dat has an optimal length") return } if !fl_commit { fdat.Close() fmt.Println("Warning: blockchain.dat shall be defragmented. Use \"-defrag -commit\"") return } fidx, er := os.OpenFile(fl_dir+"blockchain.new", os.O_RDWR, 0600) if er != nil { println(er.Error()) return } // Capture Ctrl+C killchan := make(chan os.Signal, 1) signal.Notify(killchan, os.Interrupt, os.Kill) var doff uint64 var prv_perc uint64 = 101 buf := make([]byte, 0x100000) for n := first_block; n != nil; n = n.next { perc := 1000 * doff / total_data_size dp := n.DPos() dl := n.DLen() if perc != prv_perc { fmt.Printf("\rDefragmenting data file - %.1f%% (%d bytes saved so far)...", float64(perc)/10.0, dp-doff) prv_perc = perc } if dp > doff { if len(buf) < int(dl) { println("WARNIGN: grow block buffer to ") buf = make([]byte, dl) } fdat.Seek(int64(dp), os.SEEK_SET) fdat.Read(buf[:int(dl)]) n.SetDPos(doff) fdat.Seek(int64(doff), os.SEEK_SET) fdat.Write(buf[:int(dl)]) fidx.Seek(int64(n.off), os.SEEK_SET) fidx.Write(n.sl) } doff += uint64(dl) select { case <-killchan: fmt.Println("interrupted") fidx.Close() fdat.Close() fmt.Println("Database closed - should be still usable, but no space saved") return default: } } fidx.Close() fdat.Close() fmt.Println() fmt.Println("Truncating blockchain.dat at position", doff) os.Truncate(fl_dir+"blockchain.dat", int64(doff)) return } if fl_verify { fdat, er := os.OpenFile(fl_dir+"blockchain.dat", os.O_RDWR, 0600) if er != nil { println(er.Error()) return } dat_file_size, _ := fdat.Seek(0, os.SEEK_END) buf := make([]byte, 0x100000) var prv_perc int64 = -1 var totlen uint64 var done sync.WaitGroup for off := 0; off < len(dat); off += 136 { sl := new_sl(dat[off : off+136]) dp := int64(sl.DPos()) le := int(sl.DLen()) hei := uint(sl.Height()) perc := 1000 * dp / dat_file_size if perc != prv_perc { fmt.Printf("\rVerifying blocks data - %.1f%% @ %d / %dMB processed...", float64(perc)/10.0, hei, totlen>>20) prv_perc = perc } if fl_block != 0 && hei < fl_block { continue } fdat.Seek(dp, os.SEEK_SET) fdat.Read(buf[:le]) blk := decomp_block(sl.Flags(), buf[:le]) done.Add(1) go func(blk []byte, sl one_idx_rec, off int) { verify_block(blk, sl, off) done.Done() }(blk, sl, off) totlen += uint64(len(blk)) } done.Wait() // wait for all the goroutines to complete return } if fl_block != 0 { for off := 0; off < len(dat); off += 136 { sl := dat[off : off+136] height := binary.LittleEndian.Uint32(sl[36:40]) if uint(height) == fl_block { print_record(dat[off : off+136]) } } return } if fl_split != "" { th := btc.NewUint256FromString(fl_split) if th == nil { println("incorrect block hash") return } for off := 0; off < len(dat); off += 136 { sl := dat[off : off+136] height := binary.LittleEndian.Uint32(sl[36:40]) bh := btc.NewSha2Hash(sl[56:136]) if bh.Hash == th.Hash { trunc_idx_offs := int64(off) trunc_dat_offs := int64(binary.LittleEndian.Uint64(sl[40:48])) fmt.Println("Truncate blockchain.new at offset", trunc_idx_offs) fmt.Println("Truncate blockchain.dat at offset", trunc_dat_offs) if !fl_trunc { new_dir := fl_dir + fmt.Sprint(height) + string(os.PathSeparator) os.Mkdir(new_dir, os.ModePerm) f, e := os.Open(fl_dir + "blockchain.dat") if e != nil { fmt.Println(e.Error()) return } df, e := os.Create(new_dir + "blockchain.dat") if e != nil { f.Close() fmt.Println(e.Error()) return } f.Seek(trunc_dat_offs, os.SEEK_SET) fmt.Println("But fist save the rest in", new_dir, "...") if fl_skip != 0 { fmt.Println("Skip", fl_skip, "blocks in the output file") for fl_skip > 0 { skipbytes := binary.LittleEndian.Uint32(sl[48:52]) fmt.Println(" -", skipbytes, "bytes of block", binary.LittleEndian.Uint32(sl[36:40])) off += 136 if off < len(dat) { sl = dat[off : off+136] fl_skip-- } else { break } } } for { var buf [1024 * 1024]byte n, _ := f.Read(buf[:]) if n > 0 { df.Write(buf[:n]) } if n != len(buf) { break } } df.Close() f.Close() df, e = os.Create(new_dir + "blockchain.new") if e != nil { f.Close() fmt.Println(e.Error()) return } var off2 int for off2 = off; off2 < len(dat); off2 += 136 { sl := dat[off2 : off2+136] newoffs := binary.LittleEndian.Uint64(sl[40:48]) - uint64(trunc_dat_offs) binary.LittleEndian.PutUint64(sl[40:48], newoffs) df.Write(sl) } df.Close() } os.Truncate(fl_dir+"blockchain.new", trunc_idx_offs) os.Truncate(fl_dir+"blockchain.dat", trunc_dat_offs) return } } fmt.Println("Block not found - nothing truncated") } if fl_savebl != "" { bh := btc.NewUint256FromString(fl_savebl) if bh == nil { println("Incortrect block hash:", fl_savebl) return } for off := 0; off < len(dat); off += 136 { sl := new_sl(dat[off : off+136]) if bytes.Equal(sl.Hash(), bh.Hash[:]) { f, er := os.Open(fl_dir + "blockchain.dat") if er != nil { println(er.Error()) return } buf := make([]byte, int(sl.DLen())) f.Seek(int64(sl.DPos()), os.SEEK_SET) f.Read(buf) f.Close() ioutil.WriteFile(bh.String()+".bin", decomp_block(sl.Flags(), buf), 0600) fmt.Println(bh.String()+".bin written to disk. It has height", sl.Height()) return } } fmt.Println("Block", bh.String(), "not found in the database") return } var minbh, maxbh uint32 minbh = binary.LittleEndian.Uint32(dat[36:40]) maxbh = minbh for off := 136; off < len(dat); off += 136 { sl := new_sl(dat[off : off+136]) bh := sl.Height() if bh > maxbh { maxbh = bh } else if bh < minbh { minbh = bh } } fmt.Println("Block heights from", minbh, "to", maxbh) }
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) }
func main() { fmt.Println("Gocoin blockchain downloader version", lib.Version) parse_command_line() setup_runtime_vars() if len(GocoinHomeDir) > 0 && GocoinHomeDir[len(GocoinHomeDir)-1] != os.PathSeparator { GocoinHomeDir += string(os.PathSeparator) } if Testnet { GocoinHomeDir += "tstnet" + string(os.PathSeparator) Magic = [4]byte{0x0B, 0x11, 0x09, 0x07} GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") fmt.Println("Using testnet3") } else { GocoinHomeDir += "btcnet" + string(os.PathSeparator) } fmt.Println("GocoinHomeDir:", GocoinHomeDir) sys.LockDatabaseDir(GocoinHomeDir) defer sys.UnlockDatabaseDir() peersdb.Testnet = Testnet peersdb.InitPeers(GocoinHomeDir) StartTime = time.Now() if open_blockchain() { fmt.Printf("Blockchain opening aborted\n") return } fmt.Println("Blockchain open in", time.Now().Sub(StartTime)) go do_usif() download_headers() if GlobalExit() { TheBlockChain.Close() return } var HighestTrustedBlock *btc.Uint256 if LastTrustedBlock == "all" { HighestTrustedBlock = TheBlockChain.BlockTreeEnd.BlockHash fmt.Println("Assume all blocks trusted") } else if LastTrustedBlock == "auto" { if LastBlockHeight > 6 { use := LastBlockHeight - 6 ha := BlocksToGet[use] HighestTrustedBlock = btc.NewUint256(ha[:]) fmt.Println("Assume last trusted block as", HighestTrustedBlock.String(), "at", use) } else { fmt.Println("-t=auto ignored since LastBlockHeight is only", LastBlockHeight) } } else if LastTrustedBlock != "" { HighestTrustedBlock = btc.NewUint256FromString(LastTrustedBlock) } if HighestTrustedBlock != nil { for k, h := range BlocksToGet { if bytes.Equal(h[:], HighestTrustedBlock.Hash[:]) { TrustUpTo = k break } } } else { fmt.Println("WARNING: The trusted block not found (it will be very slow).") } for n := TheBlockChain.BlockTreeEnd; n != nil && n.Height > TheBlockChain.BlockTreeEnd.Height-BSLEN; n = n.Parent { blocksize_update(int(n.BlockSize)) } fmt.Println("Downloading blocks - BlocksToGet:", len(BlocksToGet), " avg_size:", avg_block_size()) usif_prompt() StartTime = time.Now() get_blocks() fmt.Println("Up to block", TheBlockChain.BlockTreeEnd.Height, "in", time.Now().Sub(StartTime).String()) close_all_connections() peersdb.ClosePeerDB() StartTime = time.Now() fmt.Print("All blocks done - defrag unspent") qdb.SetDefragPercent(100) for { if !TheBlockChain.Unspent.Idle() { break } fmt.Print(".") } fmt.Println("\nDefrag unspent done in", time.Now().Sub(StartTime).String()) TheBlockChain.Close() return }
func main() { if len(os.Args) < 2 { fmt.Println("Specify at least one parameter - a path to the blk0000?.dat files.") fmt.Println("By default it should be:", sys.BitcoinHome()+"blocks") fmt.Println() fmt.Println("If you specify a second parameter, that's where output data will be stored.") fmt.Println("Otherwise the output data will go to Gocoin's default data folder.") return } BtcRootDir = RemoveLastSlash(os.Args[1]) fn := BtcRootDir + string(os.PathSeparator) + "blk00000.dat" fmt.Println("Looking for file", fn, "...") f, e := os.Open(fn) if e != nil { println(e.Error()) os.Exit(1) } _, e = f.Read(Magic[:]) f.Close() if e != nil { println(e.Error()) os.Exit(1) } if len(os.Args) > 2 { GocoinHomeDir = RemoveLastSlash(os.Args[2]) + string(os.PathSeparator) } else { GocoinHomeDir = sys.BitcoinHome() + "gocoin" + string(os.PathSeparator) } if Magic == [4]byte{0x0B, 0x11, 0x09, 0x07} { // testnet3 fmt.Println("There are Testnet3 blocks") GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") GocoinHomeDir += "tstnet" + string(os.PathSeparator) } else if Magic == [4]byte{0xF9, 0xBE, 0xB4, 0xD9} { fmt.Println("There are valid Bitcoin blocks") GenesisBlock = btc.NewUint256FromString("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") GocoinHomeDir += "btcnet" + string(os.PathSeparator) } else { println("blk00000.dat has an unexpected magic") os.Exit(1) } fmt.Println("Importing blockchain data into", GocoinHomeDir, "...") if exists(GocoinHomeDir+"blockchain.dat") || exists(GocoinHomeDir+"blockchain.idx") || exists(GocoinHomeDir+"unspent") { println("Destination folder contains some database files.") println("Either move them somewhere else or delete manually.") println("None of the following files/folders must exist before you proceed:") println(" *", GocoinHomeDir+"blockchain.dat") println(" *", GocoinHomeDir+"blockchain.idx") println(" *", GocoinHomeDir+"unspent") os.Exit(1) } import_blockchain(BtcRootDir) }
func main() { fmt.Println("Gocoin blockchain downloader version", lib.Version) parse_command_line() setup_runtime_vars() if !add_ip_str(SeedNode) { println("You need to specify IP address of a fast seed node.") println("For example run it like this: downloader -s 89.31.102.237") return } load_ips() // other seed nodes if len(GocoinHomeDir) > 0 && GocoinHomeDir[len(GocoinHomeDir)-1] != os.PathSeparator { GocoinHomeDir += string(os.PathSeparator) } if Testnet { GocoinHomeDir += "tstnet" + string(os.PathSeparator) Magic = [4]byte{0x0B, 0x11, 0x09, 0x07} DefaultTcpPort = 18333 GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") fmt.Println("Using testnet3") } else { GocoinHomeDir += "btcnet" + string(os.PathSeparator) } fmt.Println("GocoinHomeDir:", GocoinHomeDir) sys.LockDatabaseDir(GocoinHomeDir) defer sys.UnlockDatabaseDir() StartTime = time.Now() if open_blockchain() { fmt.Printf("Blockchain opening aborted\n") close_blockchain() return } fmt.Println("Blockchain open in", time.Now().Sub(StartTime)) go do_usif() fmt.Println("Downloading headers from the seed peer", SeedNode) download_headers() if GlobalExit { close_blockchain() return } if DoThePings { fmt.Println("Tuning to other peers and trying to find the fastest ones.") fmt.Println("Execute command 'g' to continue to block chain download.") fmt.Println("Otherwise it will auto-continue after 15 minutes.") usif_prompt() do_pings() fmt.Println("Pings done.") usif_prompt() } var HighestTrustedBlock *btc.Uint256 if LastTrustedBlock == "all" { HighestTrustedBlock = TheBlockChain.BlockTreeEnd.BlockHash fmt.Println("Assume all blocks trusted") } else if LastTrustedBlock == "auto" { if LastBlockHeight > 6 { ha := BlocksToGet[LastBlockHeight] HighestTrustedBlock = btc.NewUint256(ha[:]) fmt.Println("Assume last trusted block as", HighestTrustedBlock.String()) } else { fmt.Println("-t=auto ignored since LastBlockHeight is only", LastBlockHeight) } } else if LastTrustedBlock != "" { HighestTrustedBlock = btc.NewUint256FromString(LastTrustedBlock) } if HighestTrustedBlock != nil { for k, h := range BlocksToGet { if bytes.Equal(h[:], HighestTrustedBlock.Hash[:]) { TrustUpTo = k fmt.Println("All the blocks up to", TrustUpTo, "are assumed trusted") break } } } else { fmt.Println("None of the blocks is to be assumed trusted (it will be very slow).") } for n := TheBlockChain.BlockTreeEnd; n != nil && n.Height > TheBlockChain.BlockTreeEnd.Height-BSLEN; n = n.Parent { blocksize_update(int(n.BlockSize)) } fmt.Println("Downloading blocks - BlocksToGet:", len(BlocksToGet), " avg_size:", avg_block_size()) usif_prompt() StartTime = time.Now() get_blocks() fmt.Println("Up to block", TheBlockChain.BlockTreeEnd.Height, "in", time.Now().Sub(StartTime).String()) close_all_connections() close_blockchain() return }
// 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 }