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_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 := 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 main() { fmt.Println("Gocoin FetchTx version", lib.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 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 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 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) params := vv[2].(string) var e error ret.ver_flags, e = decode_flags(params) // deifned in script_test.go if e != nil { ret.skip = e.Error() } return }
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 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 }
"github.com/wchh/gocoin/lib/qdb" "io/ioutil" "os" "os/signal" "runtime" "runtime/debug" "sync/atomic" "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 uint32 // CommandLineSwitches LastTrustedBlock string // -trust GocoinHomeDir string // -d OnlyStoreBlocks bool // -b MaxNetworkConns uint // -n GCPerc int // -g SeedNode string // -s MemForBlocks uint // -m (in megabytes) Testnet bool // -t ) func GlobalExit() bool {
// Download (and re-assemble) raw transaction from blockexplorer.com func GetTxFromExplorer(txid *btc.Uint256) ([]byte, []byte) { url := "http://blockexplorer.com/rawtx/" + txid.String() r, er := http.Get(url) if er == nil && r.StatusCode == 200 { defer r.Body.Close() c, _ := ioutil.ReadAll(r.Body) var txx onetx er = json.Unmarshal(c[:], &txx) if er == nil { // This part looks weird, but this is how I solved seq=FFFFFFFF, if the field not present: for i := range txx.In { txx.In[i].Sequence = 0xffffffff } json.Unmarshal(c[:], &txx) // ... end of the weird solution tx := new(btc.Tx) tx.Version = txx.Ver tx.TxIn = make([]*btc.TxIn, len(txx.In)) for i := range txx.In { tx.TxIn[i] = new(btc.TxIn) tx.TxIn[i].Input.Hash = btc.NewUint256FromString(txx.In[i].Prev_out.Hash).Hash tx.TxIn[i].Input.Vout = txx.In[i].Prev_out.N if txx.In[i].Prev_out.N == 0xffffffff && txx.In[i].Prev_out.Hash == "0000000000000000000000000000000000000000000000000000000000000000" { tx.TxIn[i].ScriptSig, _ = hex.DecodeString(txx.In[i].Coinbase) } else { tx.TxIn[i].ScriptSig, _ = btc.DecodeScript(txx.In[i].ScriptSig) } tx.TxIn[i].Sequence = txx.In[i].Sequence } tx.TxOut = make([]*btc.TxOut, len(txx.Out)) for i := range txx.Out { am, er := btc.StringToSatoshis(txx.Out[i].Value) if er != nil { fmt.Println("Incorrect BTC amount", txx.Out[i].Value, er.Error()) return nil, nil } tx.TxOut[i] = new(btc.TxOut) tx.TxOut[i].Value = am tx.TxOut[i].Pk_script, _ = btc.DecodeScript(txx.Out[i].ScriptPubKey) } tx.Lock_time = txx.Lock_time rawtx := tx.Serialize() if txx.Size != uint(len(rawtx)) { fmt.Printf("Transaction size mismatch: %d expexted, %d decoded\n", txx.Size, len(rawtx)) return nil, rawtx } curid := btc.NewSha2Hash(rawtx) if !curid.Equal(txid) { fmt.Println("The downloaded transaction does not match its ID.", txid.String()) return nil, rawtx } return rawtx, rawtx } else { fmt.Println("json.Unmarshal:", er.Error()) } } else { if er != nil { fmt.Println("http.Get:", er.Error()) } else { fmt.Println("StatusCode=", r.StatusCode) } } return nil, nil }
func 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 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) network.AlertPubKey, _ = hex.DecodeString("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a") common.MaxPeersNeeded = 100 } else { common.GenesisBlock = btc.NewUint256FromString("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") common.Magic = [4]byte{0xF9, 0xBE, 0xB4, 0xD9} common.GocoinHomeDir += common.DataSubdir() + string(os.PathSeparator) network.AlertPubKey, _ = hex.DecodeString("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284") common.MaxPeersNeeded = 1000 } // 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") } } } // Create default wallet file if does not exist println("wallet dir", common.CFG.Walletdir) os.MkdirAll(common.CFG.Walletdir+string(os.PathSeparator)+"stealth", 0770) default_wallet_fn := common.CFG.Walletdir + string(os.PathSeparator) + wallet.DefaultFileName println("default_wallet_fn", default_wallet_fn) fi, _ = os.Stat(default_wallet_fn) if fi == nil || fi.IsDir() { fmt.Println(default_wallet_fn, "not found") old_wallet_location := common.GocoinHomeDir + "wallet.txt" // If there is wallet.txt rename it to default. fi, _ := os.Stat(old_wallet_location) if fi != nil && !fi.IsDir() { fmt.Println("Taking wallet.txt as", default_wallet_fn) os.Rename(old_wallet_location, default_wallet_fn) } else { fmt.Println("Creating empty default wallet at", default_wallet_fn) ioutil.WriteFile(default_wallet_fn, []byte(fmt.Sprintln("# Put your wallet's public addresses here")), 0660) } } // 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{NotifyTxAdd: wallet.TxNotifyAdd, NotifyTxDel: wallet.TxNotifyDel, LoadWalk: wallet.NewUTXO} 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 // ... and now load the dafault wallet wallet.LoadWallet(default_wallet_fn) if wallet.MyWallet != nil { wallet.UpdateBalance() fmt.Print(wallet.DumpBalance(wallet.MyBalance, nil, false, true)) } }
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 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) }