func LoadRawTx(buf []byte) (s string) { txd, er := hex.DecodeString(string(buf)) if er != nil { txd = buf } // At this place we should have raw transaction in txd tx, le := btc.NewTx(txd) if tx == nil || le != len(txd) { s += fmt.Sprintln("Could not decode transaction file or it has some extra data") return } tx.Hash = btc.NewSha2Hash(txd) var missinginp bool var totinp, totout uint64 s, missinginp, totinp, totout, er = DecodeTx(tx) if er != nil { return } network.TxMutex.Lock() if missinginp { network.TransactionsToSend[tx.Hash.Hash] = &network.OneTxToSend{Tx: tx, Data: txd, Own: 2, Firstseen: time.Now(), Volume: totout} } else { network.TransactionsToSend[tx.Hash.Hash] = &network.OneTxToSend{Tx: tx, Data: txd, Own: 1, Firstseen: time.Now(), Volume: totinp, Fee: totinp - totout} } network.TxMutex.Unlock() s += fmt.Sprintln("Transaction added to the memory pool. Please double check its details above.") s += fmt.Sprintln("If it does what you intended, you can send it the network.\nUse TxID:", tx.Hash.String()) return }
// Handle incoming "tx" msg func (c *OneConnection) ParseTxNet(pl []byte) { tid := btc.NewSha2Hash(pl) NeedThisTx(tid, func() { // This body is called with a locked TxMutex if uint32(len(pl)) > atomic.LoadUint32(&common.CFG.TXPool.MaxTxSize) { common.CountSafe("TxTooBig") RejectTx(tid, len(pl), TX_REJECTED_TOO_BIG) return } tx, le := btc.NewTx(pl) if tx == nil { RejectTx(tid, len(pl), TX_REJECTED_FORMAT) c.DoS("TxBroken") return } if le != len(pl) { RejectTx(tid, len(pl), TX_REJECTED_LEN_MISMATCH) c.DoS("TxLenMismatch") return } if len(tx.TxIn) < 1 { RejectTx(tid, len(pl), TX_REJECTED_EMPTY_INPUT) c.DoS("TxNoInputs") return } tx.Hash = tid select { case NetTxs <- &TxRcvd{conn: c, tx: tx, raw: pl}: TransactionsPending[tid.BIdx()] = true default: common.CountSafe("NetTxsFULL") } }) }
// Download raw transaction from a web server (try one after another) func GetTxFromWeb(txid *btc.Uint256) (raw []byte) { if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) { //println("GetTxFromWebBTC - OK") return } raw = GetTxFromBlockrIo(txid) if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) { //println("GetTxFromBlockrIo - OK") return } raw, _ = GetTxFromExplorer(txid) if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) { //println("GetTxFromExplorer - OK") return } return }
func write_tx_file(tx *btc.Tx) { signedrawtx := tx.Serialize() tx.Hash = btc.NewSha2Hash(signedrawtx) hs := tx.Hash.String() fmt.Println("TxID", hs) f, _ := os.Create(hs[:8] + ".txt") if f != nil { f.Write([]byte(hex.EncodeToString(signedrawtx))) f.Close() fmt.Println("Transaction data stored in", hs[:8]+".txt") } }
func (c *one_net_conn) block_pong(d []byte) { if len(d) > 80 { c.ping.Lock() defer c.ping.Unlock() if c.ping.lastBlock != nil { c.ping.bytes += uint(len(d)) h := btc.NewSha2Hash(d[:80]) if h.Equal(c.ping.lastBlock) { //fmt.Println(c.peerip, "bl_pong", c.ping.seq, c.ping.bytes, time.Now().Sub(c.ping.timeSent)) c.ping.lastBlock = nil c.ping.bytes = 0 c.store_ping_result() } } } }
func GetTx(txid *btc.Uint256, vout int) bool { r, er := http.Get("http://blockexplorer.com/rawtx/" + txid.String()) 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 { 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 tx.TxIn[i].ScriptSig, _ = btc.DecodeScript(txx.In[i].ScriptSig) tx.TxIn[i].Sequence = 0xffffffff } tx.TxOut = make([]*btc.TxOut, len(txx.Out)) for i := range txx.Out { tx.TxOut[i] = new(btc.TxOut) tx.TxOut[i].Value = btc.ParseValue(txx.Out[i].Value) tx.TxOut[i].Pk_script, _ = btc.DecodeScript(txx.Out[i].ScriptPubKey) } tx.Lock_time = txx.Lock_time rawtx := tx.Serialize() curid := btc.NewSha2Hash(rawtx) if !curid.Equal(txid) { fmt.Println("The downloaded transaction does not match its ID.") return false } ioutil.WriteFile("balance/"+curid.String()+".tx", rawtx, 0666) return true } else { fmt.Println("json.Unmarshal:", er.Error()) } } else { if er != nil { fmt.Println("http.Get:", er.Error()) } else { fmt.Println("StatusCode=", r.StatusCode) } } return false }
func (c *one_net_conn) block(d []byte) { BlocksMutex.Lock() defer BlocksMutex.Unlock() h := btc.NewSha2Hash(d[:80]) c.Lock() c.last_blk_rcvd = time.Now() c.Unlock() bip := BlocksInProgress[h.Hash] if bip == nil || !bip.Conns[c.id] { COUNTER("UNEX") //fmt.Println(h.String(), "- already received", bip) return } delete(bip.Conns, c.id) c.Lock() c.inprogress-- c.Unlock() atomic.AddUint64(&DlBytesDownloaded, uint64(len(d))) blocksize_update(len(d)) bl, er := btc.NewBlock(d) if er != nil { fmt.Println(c.peerip, "-", er.Error()) c.setbroken(true) return } bl.BuildTxList() if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) { fmt.Println(c.peerip, " - MerkleRoot mismatch at block", bip.Height) c.setbroken(true) return } BlocksCachedSize += uint(len(d)) BlocksCached[bip.Height] = bl delete(BlocksToGet, bip.Height) delete(BlocksInProgress, h.Hash) //fmt.Println(" got block", height) }
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") }
// Handle incomming "tx" msg func (c *OneConnection) ParseTxNet(pl []byte) { tid := btc.NewSha2Hash(pl) if uint32(len(pl)) > atomic.LoadUint32(&common.CFG.TXPool.MaxTxSize) { common.CountSafe("TxTooBig") TransactionsRejected[tid.BIdx()] = NewRejectedTx(tid, len(pl), TX_REJECTED_TOO_BIG) return } NeedThisTx(tid, func() { tx, le := btc.NewTx(pl) if tx == nil { common.CountSafe("TxParseError") TransactionsRejected[tid.BIdx()] = NewRejectedTx(tid, len(pl), TX_REJECTED_FORMAT) c.DoS() return } if le != len(pl) { common.CountSafe("TxParseLength") TransactionsRejected[tid.BIdx()] = NewRejectedTx(tid, len(pl), TX_REJECTED_LEN_MISMATCH) c.DoS() return } if len(tx.TxIn) < 1 { common.CountSafe("TxParseEmpty") TransactionsRejected[tid.BIdx()] = NewRejectedTx(tid, len(pl), TX_REJECTED_EMPTY_INPUT) c.DoS() return } tx.Hash = tid select { case NetTxs <- &TxRcvd{conn: c, tx: tx, raw: pl}: TransactionsPending[tid.Hash] = true default: common.CountSafe("NetTxsFULL") } }) }
func push_tx(rawtx string) { dat := utils.GetRawData(rawtx) if dat == nil { println("Cannot fetch the raw transaction data (specify hexdump or filename)") return } val := make(url.Values) val["rawtx"] = []string{hex.EncodeToString(dat)} r, er := http.PostForm(HOST+"txs", val) if er != nil { println(er.Error()) os.Exit(1) } if r.StatusCode == 200 { defer r.Body.Close() res, _ := ioutil.ReadAll(r.Body) if len(res) > 100 { txid := btc.NewSha2Hash(dat) fmt.Println("TxID", txid.String(), "loaded") http_get(HOST + "cfg") // get SID //fmt.Println("sid", SID) u, _ := url.Parse(HOST + "txs2s.xml") ps := url.Values{} ps.Add("sid", SID) ps.Add("send", txid.String()) u.RawQuery = ps.Encode() http_get(u.String()) } } else { println("http.Post returned code", r.StatusCode) os.Exit(1) } }
// 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 }
// 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 var inpcnt uint for inpcnt = 0; inpcnt < uint(len(unspentOuts)); inpcnt++ { uo := UO(unspentOuts[inpcnt]) // add the input to our transaction: tin := new(btc.TxIn) tin.Input = *unspentOuts[inpcnt] tin.Sequence = 0xffffffff tx.TxIn = append(tx.TxIn, tin) btcsofar += uo.Value if btcsofar >= spendBtc+feeBtc { break } } changeBtc = btcsofar - (spendBtc + feeBtc) fmt.Printf("Spending %d out of %d outputs...\n", inpcnt+1, len(unspentOuts)) // Build transaction outputs: tx.TxOut = make([]*btc.TxOut, len(sendTo)) for o := range sendTo { tx.TxOut[o] = &btc.TxOut{Value: sendTo[o].amount, Pk_script: sendTo[o].addr.OutScript()} } if changeBtc > 0 { // Add one more output (with the change) tx.TxOut = append(tx.TxOut, &btc.TxOut{Value: changeBtc, Pk_script: get_change_addr().OutScript()}) } //fmt.Println("Unsigned:", hex.EncodeToString(tx.Serialize())) for in := range tx.TxIn { uo := UO(unspentOuts[in]) var found bool for j := range publ_addrs { if publ_addrs[j].Owns(uo.Pk_script) { pub_key, e := btc.NewPublicKey(publ_addrs[j].Pubkey) if e != nil { println("NewPublicKey:", e.Error(), "\007") os.Exit(1) } // Load the key (private and public) var key ecdsa.PrivateKey key.D = new(big.Int).SetBytes(priv_keys[j][:]) key.PublicKey = pub_key.PublicKey //Calculate proper transaction hash h := tx.SignatureHash(uo.Pk_script, in, btc.SIGHASH_ALL) //fmt.Println("SignatureHash:", btc.NewUint256(h).String()) // Sign r, s, err := ecdsa.Sign(rand.Reader, &key, h) if err != nil { println("Sign:", err.Error(), "\007") os.Exit(1) } rb := r.Bytes() sb := s.Bytes() if rb[0] >= 0x80 { // I thinnk this is needed, thought I am not quite sure... :P rb = append([]byte{0x00}, rb...) } if sb[0] >= 0x80 { // I thinnk this is needed, thought I am not quite sure... :P sb = append([]byte{0x00}, sb...) } // Output the signing result into a buffer, in format expected by bitcoin protocol busig := new(bytes.Buffer) busig.WriteByte(0x30) busig.WriteByte(byte(4 + len(rb) + len(sb))) busig.WriteByte(0x02) busig.WriteByte(byte(len(rb))) busig.Write(rb) busig.WriteByte(0x02) busig.WriteByte(byte(len(sb))) busig.Write(sb) busig.WriteByte(0x01) // hash type // Output the signature and the public key into tx.ScriptSig buscr := new(bytes.Buffer) buscr.WriteByte(byte(busig.Len())) buscr.Write(busig.Bytes()) buscr.WriteByte(byte(len(publ_addrs[j].Pubkey))) buscr.Write(publ_addrs[j].Pubkey) // assign: tx.TxIn[in].ScriptSig = buscr.Bytes() found = true break } } if !found { fmt.Println("You do not have private key for input number", hex.EncodeToString(uo.Pk_script), "\007") os.Exit(1) } } rawtx := tx.Serialize() tx.Hash = btc.NewSha2Hash(rawtx) hs := tx.Hash.String() fmt.Println(hs) f, _ := os.Create(hs[:8] + ".txt") if f != nil { f.Write([]byte(hex.EncodeToString(rawtx))) f.Close() fmt.Println("Transaction data stored in", hs[:8]+".txt") } f, _ = os.Create("balance/unspent.txt") if f != nil { for j := uint(0); j < uint(len(unspentOuts)); j++ { if j > inpcnt { fmt.Fprintln(f, unspentOuts[j], unspentOutsLabel[j]) } } fmt.Println(inpcnt, "spent output(s) removed from 'balance/unspent.txt'") var addback int for out := range tx.TxOut { for j := range publ_addrs { if publ_addrs[j].Owns(tx.TxOut[out].Pk_script) { fmt.Fprintf(f, "%s-%03d # %.8f / %s\n", tx.Hash.String(), out, float64(tx.TxOut[out].Value)/1e8, publ_addrs[j].String()) addback++ } } } f.Close() if addback > 0 { f, _ = os.Create("balance/" + hs + ".tx") if f != nil { f.Write(rawtx) f.Close() } fmt.Println(addback, "new output(s) appended to 'balance/unspent.txt'") } } }