func xml_balance(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } w.Header()["Content-Type"] = []string{"text/xml"} w.Write([]byte("<unspent>")) wallet.BalanceMutex.Lock() for i := range wallet.MyBalance { w.Write([]byte("<output>")) fmt.Fprint(w, "<txid>", btc.NewUint256(wallet.MyBalance[i].TxPrevOut.Hash[:]).String(), "</txid>") fmt.Fprint(w, "<vout>", wallet.MyBalance[i].TxPrevOut.Vout, "</vout>") fmt.Fprint(w, "<value>", wallet.MyBalance[i].Value, "</value>") fmt.Fprint(w, "<inblock>", wallet.MyBalance[i].MinedAt, "</inblock>") fmt.Fprint(w, "<blocktime>", get_block_time(wallet.MyBalance[i].MinedAt), "</blocktime>") fmt.Fprint(w, "<addr>", wallet.MyBalance[i].DestAddr(), "</addr>") fmt.Fprint(w, "<addrorg>", wallet.MyBalance[i].BtcAddr.String(), "</addrorg>") fmt.Fprint(w, "<wallet>", html.EscapeString(wallet.MyBalance[i].BtcAddr.Extra.Wallet), "</wallet>") fmt.Fprint(w, "<label>", html.EscapeString(wallet.MyBalance[i].BtcAddr.Extra.Label), "</label>") fmt.Fprint(w, "<virgin>", fmt.Sprint(wallet.MyBalance[i].BtcAddr.Extra.Virgin), "</virgin>") w.Write([]byte("</output>")) } wallet.BalanceMutex.Unlock() w.Write([]byte("</unspent>")) }
// This function either appends a new block at the end of the existing chain // in which case it also applies all the transactions to the unspent database. // If the block does is not the heighest, it is added to the chain, but maked // as an orphan - its transaction will be verified only if the chain would swap // to its branch later on. func (ch *Chain) AcceptBlock(bl *btc.Block) (e error) { prevblk, ok := ch.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()] if !ok { panic("This should not happen") } // create new BlockTreeNode cur := new(BlockTreeNode) cur.BlockHash = bl.Hash cur.Parent = prevblk cur.Height = prevblk.Height + 1 cur.BlockSize = uint32(len(bl.Raw)) cur.TxCount = uint32(bl.TxCount) copy(cur.BlockHeader[:], bl.Raw[:80]) // Add this block to the block index ch.BlockIndexAccess.Lock() prevblk.addChild(cur) ch.BlockIndex[cur.BlockHash.BIdx()] = cur ch.BlockIndexAccess.Unlock() if ch.BlockTreeEnd == prevblk { // The head of out chain - apply the transactions var changes *BlockChanges changes, e = ch.ProcessBlockTransactions(bl, cur.Height, bl.LastKnownHeight) if e != nil { // ProcessBlockTransactions failed, so trash the block. println("ProcessBlockTransactions ", cur.BlockHash.String(), cur.Height, e.Error()) ch.BlockIndexAccess.Lock() cur.Parent.delChild(cur) delete(ch.BlockIndex, cur.BlockHash.BIdx()) ch.BlockIndexAccess.Unlock() } else { // ProcessBlockTransactions succeeded, so save the block as "trusted". bl.Trusted = true ch.Blocks.BlockAdd(cur.Height, bl) // Apply the block's trabnsactions to the unspent database: ch.Unspent.CommitBlockTxs(changes, bl.Hash.Hash[:]) if !ch.DoNotSync { ch.Blocks.Sync() } ch.BlockTreeEnd = cur // Advance the head } } else { // The block's parent is not the current head of the chain... // Save the block, though do not makt it as "trusted" just yet ch.Blocks.BlockAdd(cur.Height, bl) // If it has a bigger height than the current head, // ... move the coin state into a new branch. if cur.Height > ch.BlockTreeEnd.Height { ch.MoveToBlock(cur) } } return }
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 := script.VerifyTxScript(tx.TxIn[i].ScriptSig, po.Pk_script, i, tx, script.VER_P2SH|script.VER_DERSIG) if !ok { s += fmt.Sprintln("\nERROR: The transacion does not have a valid signature.") e = errors.New("Invalid signature") return } totinp += po.Value ads := "???" if ad := btc.NewAddrFromPkScript(po.Pk_script, common.Testnet); ad != nil { ads = ad.String() } s += fmt.Sprintf(" %15.8f BTC @ %s\n", float64(po.Value)/1e8, ads) } 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 := 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>")) }
// Handle tx-inv notifications func (c *OneConnection) TxInvNotify(hash []byte) { if NeedThisTx(btc.NewUint256(hash), nil) { var b [1 + 4 + 32]byte b[0] = 1 // One inv b[1] = 1 // Tx copy(b[5:37], hash) c.SendRawMsg("getdata", b[:]) } }
// Call it only from the Chain thread func DumpBalance(mybal chain.AllUnspentTx, utxt *os.File, details, update_balance bool) (s string) { var sum uint64 BalanceMutex.Lock() for i := range mybal { sum += mybal[i].Value if details { if i < 100 { s += fmt.Sprintf("%7d %s\n", 1+common.Last.Block.Height-mybal[i].MinedAt, mybal[i].String()) } else if i == 100 { s += fmt.Sprintln("List of unspent outputs truncated to 100 records") } } // update the balance/ folder if utxt != nil { po, e := common.BlockChain.Unspent.UnspentGet(&mybal[i].TxPrevOut) if e != nil { println("UnspentGet:", e.Error()) println("This should not happen - please, report a bug.") println("You can probably fix it by launching the client with -rescan") os.Exit(1) } txid := btc.NewUint256(mybal[i].TxPrevOut.Hash[:]) // Store the unspent line in balance/unspent.txt fmt.Fprintln(utxt, mybal[i].UnspentTextLine()) // store the entire transactiojn in balance/<txid>.tx fn := "balance/" + txid.String()[:64] + ".tx" txf, _ := os.Open(fn) if txf == nil { // Do it only once per txid txf, _ = os.Create(fn) if txf == nil { println("Cannot create ", fn) os.Exit(1) } GetRawTransaction(po.BlockHeight, txid, txf) } txf.Close() } } if update_balance { LastBalance = sum } BalanceMutex.Unlock() s += fmt.Sprintf("Total balance: %.8f BTC in %d unspent outputs\n", float64(sum)/1e8, len(mybal)) if utxt != nil { utxt.Close() } return }
func baned_txs(par string) { fmt.Println("Rejected transactions:") cnt := 0 network.TxMutex.Lock() for k, v := range network.TransactionsRejected { cnt++ fmt.Println("", cnt, btc.NewUint256(k[:]).String(), "-", v.Size, "bytes", "-", v.Reason, "-", time.Now().Sub(v.Time).String(), "ago") } network.TxMutex.Unlock() }
func send_all_tx(par string) { network.TxMutex.Lock() for k, v := range network.TransactionsToSend { if v.Own != 0 { cnt := network.NetRouteInv(1, btc.NewUint256(k[:]), nil) v.Invsentcnt += cnt fmt.Println("INV for TxID", v.Hash.String(), "sent to", cnt, "node(s)") } } network.TxMutex.Unlock() }
// Loads block index from the disk func (ch *Chain) loadBlockIndex() { ch.BlockIndex = make(map[[btc.Uint256IdxLen]byte]*BlockTreeNode, BlockMapInitLen) ch.BlockTreeRoot = new(BlockTreeNode) ch.BlockTreeRoot.BlockHash = ch.Genesis ch.BlockIndex[ch.Genesis.BIdx()] = ch.BlockTreeRoot ch.Blocks.LoadBlockIndex(ch, nextBlock) tlb := ch.Unspent.LastBlockHash //println("Building tree from", len(ch.BlockIndex), "nodes") for _, v := range ch.BlockIndex { if AbortNow { return } if v == ch.BlockTreeRoot { // skip root block (should be only one) continue } par, ok := ch.BlockIndex[btc.NewUint256(v.BlockHeader[4:36]).BIdx()] if !ok { panic(v.BlockHash.String() + " has no Parent " + btc.NewUint256(v.BlockHeader[4:36]).String()) } /*if par.Height+1 != v.Height { panic("height mismatch") }*/ v.Parent = par v.Parent.addChild(v) } if tlb == nil { //println("No last block - full rescan will be needed") ch.BlockTreeEnd = ch.BlockTreeRoot return } else { //println("Last Block Hash:", btc.NewUint256(tlb).String()) var ok bool ch.BlockTreeEnd, ok = ch.BlockIndex[btc.NewUint256(tlb).BIdx()] if !ok { panic("Last btc.Block Hash not found") } } }
func chkblock(bl *btc.Block) (er error) { // Check timestamp (must not be higher than now +2 hours) if int64(bl.BlockTime()) > time.Now().Unix()+2*60*60 { er = errors.New("CheckBlock() : block timestamp too far in the future") return } MemBlockChainMutex.Lock() if prv, pres := MemBlockChain.BlockIndex[bl.Hash.BIdx()]; pres { MemBlockChainMutex.Unlock() if prv.Parent == nil { // This is genesis block er = errors.New("Genesis") return } else { return } } prevblk, ok := MemBlockChain.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()] if !ok { er = errors.New("CheckBlock: " + bl.Hash.String() + " parent not found") return } // Check proof of work gnwr := MemBlockChain.GetNextWorkRequired(prevblk, bl.BlockTime()) if bl.Bits() != gnwr { if !Testnet || ((prevblk.Height+1)%2016) != 0 { MemBlockChainMutex.Unlock() er = errors.New(fmt.Sprint("CheckBlock: Incorrect proof of work at block", prevblk.Height+1)) return } } cur := new(chain.BlockTreeNode) cur.BlockHash = bl.Hash cur.Parent = prevblk cur.Height = prevblk.Height + 1 cur.TxCount = uint32(bl.TxCount) copy(cur.BlockHeader[:], bl.Raw[:80]) prevblk.Childs = append(prevblk.Childs, cur) MemBlockChain.BlockIndex[cur.BlockHash.BIdx()] = cur MemBlockChainMutex.Unlock() LastBlock.Mutex.Lock() if cur.Height > LastBlock.node.Height { LastBlock.node = cur } LastBlock.Mutex.Unlock() return }
func execute_test_tx(t *testing.T, tv *testvector) bool { if len(tv.inps) == 0 { t.Error("Vector has no inputs") return false } rd, er := hex.DecodeString(tv.tx) if er != nil { t.Error(er.Error()) return false } tx, _ := btc.NewTx(rd) if tx == nil { t.Error("Canot decode tx") return false } tx.Size = uint32(len(rd)) ha := btc.Sha2Sum(rd) tx.Hash = btc.NewUint256(ha[:]) if skip_broken_tests(tx) { return false } oks := 0 for i := range tx.TxIn { var j int for j = range tv.inps { if bytes.Equal(tx.TxIn[i].Input.Hash[:], tv.inps[j].txid.Hash[:]) && tx.TxIn[i].Input.Vout == uint32(tv.inps[j].vout) { break } } if j >= len(tv.inps) { t.Error("Matching input not found") continue } pk, er := btc.DecodeScript(tv.inps[j].pkscr) if er != nil { t.Error(er.Error()) continue } var ss []byte if tv.inps[j].vout >= 0 { ss = tx.TxIn[i].ScriptSig } if VerifyTxScript(ss, pk, i, tx, tv.ver_flags) { oks++ } } return oks == len(tx.TxIn) }
func nextBlock(ch *Chain, hash, header []byte, height, blen, txs uint32) { bh := btc.NewUint256(hash[:]) if _, ok := ch.BlockIndex[bh.BIdx()]; ok { println("nextBlock:", bh.String(), "- already in") return } v := new(BlockTreeNode) v.BlockHash = bh v.Height = height v.BlockSize = blen v.TxCount = txs copy(v.BlockHeader[:], header) ch.BlockIndex[v.BlockHash.BIdx()] = v }
// Read VLen followed by the number of locators // parse the payload of getblocks and getheaders messages func parseLocatorsPayload(pl []byte) (h2get []*btc.Uint256, hashstop *btc.Uint256, er error) { var cnt uint64 var h [32]byte var ver uint32 b := bytes.NewReader(pl) // version if er = binary.Read(b, binary.LittleEndian, &ver); er != nil { return } // hash count cnt, er = btc.ReadVLen(b) if er != nil { return } // block locator hashes if cnt > 0 { h2get = make([]*btc.Uint256, cnt) for i := 0; i < int(cnt); i++ { if _, er = b.Read(h[:]); er != nil { return } h2get[i] = btc.NewUint256(h[:]) } } // hash_stop if _, er = b.Read(h[:]); er != nil { return } hashstop = btc.NewUint256(h[:]) return }
func (db *BlockDB) BlockTrusted(hash []byte) { idx := btc.NewUint256(hash).BIdx() db.mutex.Lock() cur, ok := db.blockIndex[idx] if !ok { db.mutex.Unlock() println("BlockTrusted: no such block") return } if !cur.trusted { //fmt.Println("mark", btc.NewUint256(hash).String(), "as trusted") db.setBlockFlag(cur, BLOCK_TRUSTED) } db.mutex.Unlock() }
func walk(ch *chain.Chain, hash, hdr []byte, height, blen, txs uint32) { bh := btc.NewUint256(hash) if _, ok := bidx[bh.Hash]; ok { println("walk: ", bh.String(), "already in") return } v := new(chain.BlockTreeNode) v.BlockHash = bh v.Height = height v.BlockSize = blen v.TxCount = txs copy(v.BlockHeader[:], hdr) bidx[bh.Hash] = v cnt++ }
// Return DB statistics func (db *UnspentDB) GetStats() (s string) { var tot, outcnt, sum, sumcb, stealth_uns, stealth_tot uint64 var mincnt, maxcnt, totdatasize, unspendable uint64 for i := range db.tdb { dbcnt := uint64(db.dbN(i).Count()) if i == 0 { mincnt, maxcnt = dbcnt, dbcnt } else if dbcnt < mincnt { mincnt = dbcnt } else if dbcnt > maxcnt { maxcnt = dbcnt } tot += dbcnt db.dbN(i).Browse(func(k qdb.KeyType, v []byte) uint32 { totdatasize += uint64(len(v) + 8) rec := NewQdbRecStatic(k, v) for idx, r := range rec.Outs { if r != nil { outcnt++ sum += r.Value if rec.Coinbase { sumcb += r.Value } if len(r.PKScr) > 0 && r.PKScr[0] == 0x6a { unspendable++ } if r.IsStealthIdx() && idx+1 < len(rec.Outs) { if rec.Outs[idx+1] != nil { stealth_uns++ } stealth_tot++ } } } return 0 }) } s = fmt.Sprintf("UNSPENT: %.8f BTC in %d outs from %d txs. %.8f BTC in coinbase.\n", float64(sum)/1e8, outcnt, tot, float64(sumcb)/1e8) s += fmt.Sprintf(" Defrags:%d Recs/db : %d..%d TotalData:%.1fMB MaxTxOutCnt:%d \n", db.defragCount, mincnt, maxcnt, float64(totdatasize)/1e6, len(rec_outs)) s += fmt.Sprintf(" Last Block : %s @ %d\n", btc.NewUint256(db.LastBlockHash).String(), db.LastBlockHeight) s += fmt.Sprintf(" Number of unspendable outputs: %d. Number of stealth indexes: %d / %d spent\n", unspendable, stealth_uns, stealth_tot) return }
// Called from network threads func blockWanted(h []byte) (yes bool) { idx := btc.NewUint256(h).BIdx() MutexRcv.Lock() _, ok := ReceivedBlocks[idx] MutexRcv.Unlock() if !ok { if atomic.LoadUint32(&common.CFG.Net.MaxBlockAtOnce) == 0 || !blocksLimitReached(idx) { yes = true common.CountSafe("BlockWanted") } else { common.CountSafe("BlockInProgress") } } else { common.CountSafe("BlockUnwanted") } return }
func (c *OneConnection) ProcessInv(pl []byte) { if len(pl) < 37 { //println(c.PeerAddr.Ip(), "inv payload too short", len(pl)) c.DoS("InvEmpty") return } c.InvsRecieved++ cnt, of := btc.VLen(pl) if len(pl) != of+36*cnt { println("inv payload length mismatch", len(pl), of, cnt) } var blinv2ask []byte for i := 0; i < cnt; i++ { typ := binary.LittleEndian.Uint32(pl[of : of+4]) common.CountSafe(fmt.Sprint("InvGot", typ)) if typ == 2 { if blockWanted(pl[of+4 : of+36]) { blinv2ask = append(blinv2ask, pl[of+4:of+36]...) } } else if typ == 1 { if common.CFG.TXPool.Enabled { c.TxInvNotify(pl[of+4 : of+36]) } } of += 36 } if len(blinv2ask) > 0 { bu := new(bytes.Buffer) btc.WriteVlen(bu, uint64(len(blinv2ask)/32)) for i := 0; i < len(blinv2ask); i += 32 { bh := btc.NewUint256(blinv2ask[i : i+32]) c.Mutex.Lock() c.GetBlockInProgress[bh.BIdx()] = &oneBlockDl{hash: bh, start: time.Now()} c.Mutex.Unlock() binary.Write(bu, binary.LittleEndian, uint32(2)) bu.Write(bh.Hash[:]) } c.SendRawMsg("getdata", bu.Bytes()) } return }
func (db *BlockDB) BlockInvalid(hash []byte) { idx := btc.NewUint256(hash).BIdx() db.mutex.Lock() cur, ok := db.blockIndex[idx] if !ok { db.mutex.Unlock() println("BlockInvalid: no such block") return } if cur.trusted { println("Looks like your UTXO database is corrupt") println("To rebuild it, remove folder: " + db.dirname + "unspent4") panic("Trusted block cannot be invalid") } //println("mark", btc.NewUint256(hash).String(), "as invalid") db.setBlockFlag(cur, BLOCK_INVALID) delete(db.blockIndex, idx) db.mutex.Unlock() }
func (db *BlockDB) LoadBlockIndex(ch *Chain, walk func(ch *Chain, hash, hdr []byte, height, blen, txs uint32)) (e error) { var b [136]byte var bh, txs uint32 var maxdatfilepos int64 validpos, _ := db.blockindx.Seek(0, os.SEEK_SET) for !AbortNow { _, e := db.blockindx.Read(b[:]) if e != nil { break } if (b[0] & BLOCK_INVALID) != 0 { // just ignore it continue } ob := new(oneBl) ob.trusted = (b[0] & BLOCK_TRUSTED) != 0 ob.compressed = (b[0] & BLOCK_COMPRSD) != 0 ob.snappied = (b[0] & BLOCK_SNAPPED) != 0 bh = binary.LittleEndian.Uint32(b[36:40]) ob.fpos = binary.LittleEndian.Uint64(b[40:48]) ob.blen = binary.LittleEndian.Uint32(b[48:52]) txs = binary.LittleEndian.Uint32(b[52:56]) ob.ipos = validpos BlockHash := b[4:36] db.blockIndex[btc.NewUint256(BlockHash).BIdx()] = ob if int64(ob.fpos)+int64(ob.blen) > maxdatfilepos { maxdatfilepos = int64(ob.fpos) + int64(ob.blen) } walk(ch, b[4:36], b[56:136], bh, ob.blen, txs) validpos += 136 } // In case if there was some trash at the end of data or index file, this should truncate it: db.blockindx.Seek(validpos, os.SEEK_SET) db.blockdata.Seek(maxdatfilepos, os.SEEK_SET) return }
// Look for specific TxPrevOut in the balance folder func getUO(pto *btc.TxPrevOut) *btc.TxOut { if _, ok := loadedTxs[pto.Hash]; !ok { loadedTxs[pto.Hash] = tx_from_balance(btc.NewUint256(pto.Hash[:]), true) } return loadedTxs[pto.Hash].TxOut[pto.Vout] }
func (ch *Chain) CheckBlock(bl *btc.Block) (er error, dos bool, maybelater bool) { // Size limits if len(bl.Raw) < 81 || len(bl.Raw) > btc.MAX_BLOCK_SIZE { er = errors.New("CheckBlock() : size limits failed") dos = true return } if bl.Version() == 0 { er = errors.New("CheckBlock() : Block version 0 not allowed") dos = true return } // Check timestamp (must not be higher than now +2 hours) if int64(bl.BlockTime()) > time.Now().Unix()+2*60*60 { er = errors.New("CheckBlock() : block timestamp too far in the future") dos = true return } if prv, pres := ch.BlockIndex[bl.Hash.BIdx()]; pres { if prv.Parent == nil { // This is genesis block er = errors.New("Genesis") return } else { er = errors.New("CheckBlock: " + bl.Hash.String() + " already in") return } } prevblk, ok := ch.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()] if !ok { er = errors.New("CheckBlock: " + bl.Hash.String() + " parent not found") maybelater = true return } height := prevblk.Height + 1 // Reject the block if it reaches into the chain deeper than our unwind buffer if prevblk != ch.BlockTreeEnd && int(ch.BlockTreeEnd.Height)-int(height) >= MovingCheckopintDepth { er = errors.New(fmt.Sprint("CheckBlock: btc.Block ", bl.Hash.String(), " hooks too deep into the chain: ", height, "/", ch.BlockTreeEnd.Height, " ", btc.NewUint256(bl.ParentHash()).String())) return } // Check proof of work gnwr := ch.GetNextWorkRequired(prevblk, bl.BlockTime()) if bl.Bits() != gnwr { println("AcceptBlock() : incorrect proof of work ", bl.Bits, " at block", height, " exp:", gnwr) // Here is a "solution" for whatever shit there is in testnet3, that nobody can explain me: if !ch.testnet() || (height%2016) != 0 { er = errors.New("CheckBlock: incorrect proof of work") dos = true return } } // Count block versions within the Majority Window var majority_v2, majority_v3 uint n := prevblk for cnt := uint(0); cnt < ch.Consensus.Window && n != nil; cnt++ { ver := binary.LittleEndian.Uint32(n.BlockHeader[0:4]) if ver >= 2 { majority_v2++ if ver >= 3 { majority_v3++ } } n = n.Parent } if bl.Version() < 2 && majority_v2 >= ch.Consensus.RejectBlock { er = errors.New("CheckBlock() : Rejected nVersion=1 block") dos = true return } if bl.Version() < 3 && majority_v3 >= ch.Consensus.RejectBlock { er = errors.New("CheckBlock() : Rejected nVersion=2 block") dos = true return } if bl.Txs == nil { er = bl.BuildTxList() if er != nil { dos = true return } } if !bl.Trusted { if bl.Version() >= 2 && majority_v2 >= ch.Consensus.EnforceUpgrade { var exp []byte if height >= 0x800000 { if height >= 0x80000000 { exp = []byte{5, byte(height), byte(height >> 8), byte(height >> 16), byte(height >> 24), 0} } else { exp = []byte{4, byte(height), byte(height >> 8), byte(height >> 16), byte(height >> 24)} } } else { exp = []byte{3, byte(height), byte(height >> 8), byte(height >> 16)} } if len(bl.Txs[0].TxIn[0].ScriptSig) < len(exp) || !bytes.Equal(exp, bl.Txs[0].TxIn[0].ScriptSig[:len(exp)]) { er = errors.New("CheckBlock() : Unexpected block number in coinbase: " + bl.Hash.String()) dos = true return } } // This is a stupid check, but well, we need to be satoshi compatible if len(bl.Txs) == 0 || !bl.Txs[0].IsCoinBase() { er = errors.New("CheckBlock() : first tx is not coinbase: " + bl.Hash.String()) dos = true return } // Check Merkle Root - that's importnant if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) { er = errors.New("CheckBlock() : Merkle Root mismatch") dos = true return } // Check transactions - this is the most time consuming task if !CheckTransactions(bl.Txs, height, bl.BlockTime()) { er = errors.New("CheckBlock() : CheckTransactions() failed") dos = true return } } if bl.BlockTime() >= BIP16SwitchTime { bl.VerifyFlags = script.VER_P2SH } else { bl.VerifyFlags = 0 } if majority_v3 >= ch.Consensus.EnforceUpgrade { bl.VerifyFlags |= script.VER_DERSIG } return }
func main() { fmt.Println("Gocoin FetchBal version", lib.Version) fmt.Println("NOTE: This tool is deprecated. Use balio instead.") proxy = os.Getenv("TOR") if proxy != "" { fmt.Println("Using Tor at", proxy) http.DefaultClient.Transport = &http.Transport{Dial: dials5} } else { fmt.Println("WARNING: not using Tor (setup TOR variable, if you want)") } 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) //println(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, false) if ba != nil { b58adr = ba.String() } } txidlsb, _ := hex.DecodeString(r.Unspent_outputs[i].Tx_hash) if txidlsb != nil { txid := btc.NewUint256(txidlsb) rawtx := utils.GetTxFromWeb(txid) if rawtx != nil { ioutil.WriteFile("balance/"+txid.String()+".tx", rawtx, 0666) 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) } } }
func show_cached(par string) { for _, v := range network.CachedBlocks { fmt.Printf(" * %s -> %s\n", v.Hash.String(), btc.NewUint256(v.ParentHash()).String()) } }
// This isusually the most time consuming process when applying a new block func (ch *Chain) commitTxs(bl *btc.Block, changes *BlockChanges) (e error) { sumblockin := btc.GetBlockReward(changes.Height) var txoutsum, txinsum, sumblockout uint64 if int(changes.Height)+UnwindBufferMaxHistory >= int(changes.LastKnownHeight) { changes.UndoData = make(map[[32]byte]*QdbRec) } // Add each tx outs from the current block to the temporary pool blUnsp := make(map[[32]byte][]*btc.TxOut, 4*len(bl.Txs)) for i := range bl.Txs { outs := make([]*btc.TxOut, len(bl.Txs[i].TxOut)) copy(outs, bl.Txs[i].TxOut) blUnsp[bl.Txs[i].Hash.Hash] = outs } // create a channnel to receive results from VerifyScript threads: done := make(chan bool, sys.UseThreads) for i := range bl.Txs { txoutsum, txinsum = 0, 0 // Check each tx for a valid input, except from the first one if i > 0 { tx_trusted := bl.Trusted if !tx_trusted && TrustedTxChecker != nil && TrustedTxChecker(bl.Txs[i].Hash) { tx_trusted = true } scripts_ok := true for j := 0; j < sys.UseThreads; j++ { done <- true } for j := 0; j < len(bl.Txs[i].TxIn); /*&& e==nil*/ j++ { inp := &bl.Txs[i].TxIn[j].Input spendrec, waspent := changes.DeledTxs[inp.Hash] if waspent && spendrec[inp.Vout] { println("txin", inp.String(), "already spent in this block") e = errors.New("Input spent more then once in same block") break } tout := ch.PickUnspent(inp) if tout == nil { t, ok := blUnsp[inp.Hash] if !ok { e = errors.New("Unknown input TxID: " + btc.NewUint256(inp.Hash[:]).String()) break } if inp.Vout >= uint32(len(t)) { println("Vout too big", len(t), inp.String()) e = errors.New("Vout too big") break } if t[inp.Vout] == nil { println("Vout already spent", inp.String()) e = errors.New("Vout already spent") break } if t[inp.Vout].WasCoinbase { e = errors.New("Cannot spend block's own coinbase in TxID: " + btc.NewUint256(inp.Hash[:]).String()) break } tout = t[inp.Vout] t[inp.Vout] = nil // and now mark it as spent: } else { if tout.WasCoinbase && changes.Height-tout.BlockHeight < COINBASE_MATURITY { e = errors.New("Trying to spend prematured coinbase: " + btc.NewUint256(inp.Hash[:]).String()) break } // it is confirmed already so delete it later if !waspent { spendrec = make([]bool, tout.VoutCount) changes.DeledTxs[inp.Hash] = spendrec } spendrec[inp.Vout] = true if changes.UndoData != nil { var urec *QdbRec urec = changes.UndoData[inp.Hash] if urec == nil { urec = new(QdbRec) urec.TxID = inp.Hash urec.Coinbase = tout.WasCoinbase urec.InBlock = tout.BlockHeight urec.Outs = make([]*QdbTxOut, tout.VoutCount) changes.UndoData[inp.Hash] = urec } tmp := new(QdbTxOut) tmp.Value = tout.Value tmp.PKScr = make([]byte, len(tout.Pk_script)) copy(tmp.PKScr, tout.Pk_script) urec.Outs[inp.Vout] = tmp } } if !(<-done) { println("VerifyScript error 1") scripts_ok = false break } if tx_trusted { done <- true } else { go func(sig []byte, prv []byte, i int, tx *btc.Tx) { done <- script.VerifyTxScript(sig, prv, i, tx, bl.VerifyFlags) }(bl.Txs[i].TxIn[j].ScriptSig, tout.Pk_script, j, bl.Txs[i]) } txinsum += tout.Value } if scripts_ok { scripts_ok = <-done } for j := 1; j < sys.UseThreads; j++ { if !(<-done) { println("VerifyScript error 2") scripts_ok = false } } if len(done) != 0 { panic("ASSERT: The channel should be empty gere") } if !scripts_ok { return errors.New("VerifyScripts failed") } } else { // For coinbase tx we need to check (like satoshi) whether the script size is between 2 and 100 bytes // (Previously we made sure in CheckBlock() that this was a coinbase type tx) if len(bl.Txs[0].TxIn[0].ScriptSig) < 2 || len(bl.Txs[0].TxIn[0].ScriptSig) > 100 { return errors.New(fmt.Sprint("Coinbase script has a wrong length", len(bl.Txs[0].TxIn[0].ScriptSig))) } } sumblockin += txinsum for j := range bl.Txs[i].TxOut { txoutsum += bl.Txs[i].TxOut[j].Value } sumblockout += txoutsum if e != nil { return // If any input fails, do not continue } if i > 0 && txoutsum > txinsum { return errors.New(fmt.Sprintf("More spent (%.8f) than at the input (%.8f) in TX %s", float64(txoutsum)/1e8, float64(txinsum)/1e8, bl.Txs[i].Hash.String())) } } if sumblockin < sumblockout { return errors.New(fmt.Sprintf("Out:%d > In:%d", sumblockout, sumblockin)) } var rec *QdbRec for k, v := range blUnsp { for i := range v { if v[i] != nil { if rec == nil { rec = new(QdbRec) rec.TxID = k rec.Coinbase = v[i].WasCoinbase rec.InBlock = changes.Height rec.Outs = make([]*QdbTxOut, len(v)) } rec.Outs[i] = &QdbTxOut{Value: v[i].Value, PKScr: v[i].Pk_script} } } if rec != nil { changes.AddList = append(changes.AddList, rec) rec = nil } } return nil }
func main() { if len(os.Args) < 2 { fmt.Println("Specify a path to folder containig blockchain.dat and blockchain.new") fmt.Println("Output bootstrap.dat file will be written in the current folder.") return } blks := chain.NewBlockDB(os.Args[1]) if blks == nil { return } fmt.Println("Loading block index...") bidx = make(map[[32]byte]*chain.BlockTreeNode, 300e3) blks.LoadBlockIndex(nil, walk) var tail, nd *chain.BlockTreeNode var genesis_block_hash *btc.Uint256 for _, v := range bidx { if v == tail { // skip root block (should be only one) continue } par_hash := btc.NewUint256(v.BlockHeader[4:36]) par, ok := bidx[par_hash.Hash] if !ok { genesis_block_hash = par_hash } else { v.Parent = par if tail == nil || v.Height > tail.Height { tail = v } } } if genesis_block_hash == nil { println("genesis_block_hash not found") return } var magic []byte gen_bin, _ := hex.DecodeString(GenesisBitcoin) tmp := btc.NewSha2Hash(gen_bin[:80]) if genesis_block_hash.Equal(tmp) { println("Bitcoin genesis block") magic = []byte{0xF9, 0xBE, 0xB4, 0xD9} } if magic == nil { gen_bin, _ := hex.DecodeString(GenesisTestnet) tmp = btc.NewSha2Hash(gen_bin[:80]) if genesis_block_hash.Equal(tmp) { println("Testnet3 genesis block") magic = []byte{0x0B, 0x11, 0x09, 0x07} } } if magic == nil { println("Unknow genesis block", genesis_block_hash.String()) println("Aborting since cannot figure out the magic bytes") return } var total_data, curr_data int64 for nd = tail; nd.Parent != nil; { nd.Parent.Childs = []*chain.BlockTreeNode{nd} total_data += int64(nd.BlockSize) nd = nd.Parent } fmt.Println("Writting bootstrap.dat, height", tail.Height, " magic", hex.EncodeToString(magic)) f, _ := os.Create("bootstrap.dat") f.Write(magic) binary.Write(f, binary.LittleEndian, uint32(len(gen_bin))) f.Write(gen_bin) for { bl, _, _ := blks.BlockGet(nd.BlockHash) f.Write(magic) binary.Write(f, binary.LittleEndian, uint32(len(bl))) f.Write(bl) curr_data += int64(nd.BlockSize) if (nd.Height & 0xfff) == 0 { fmt.Printf("\r%.1f%%...", 100*float64(curr_data)/float64(total_data)) } if len(nd.Childs) == 0 { break } nd = nd.Childs[0] } fmt.Println("\rDone ") }
// dump raw transaction func dump_raw_tx() { tx := raw_tx_from_file(*dumptxfn) if tx == nil { fmt.Println("ERROR: Cannot decode the raw transaction") return } var unsigned, totin, totout, noins uint64 fmt.Println("ID:", tx.Hash.String()) fmt.Println("Tx Version:", tx.Version) if tx.IsCoinBase() { if len(tx.TxIn[0].ScriptSig) >= 4 && tx.TxIn[0].ScriptSig[0] == 3 { fmt.Println("Coinbase TX from block height", uint(tx.TxIn[0].ScriptSig[1])| uint(tx.TxIn[0].ScriptSig[2])<<8|uint(tx.TxIn[0].ScriptSig[3])<<16) } else { fmt.Println("Coinbase TX from an unknown block") } s := hex.EncodeToString(tx.TxIn[0].ScriptSig) for len(s) > 0 { i := len(s) if i > 64 { i = 64 } fmt.Println(" ", s[:i]) s = s[i:] } //fmt.Println() } else { fmt.Println("TX IN cnt:", len(tx.TxIn)) for i := range tx.TxIn { fmt.Printf("%4d) %s sl=%d seq=%08x\n", i, tx.TxIn[i].Input.String(), len(tx.TxIn[i].ScriptSig), tx.TxIn[i].Sequence) if intx := tx_from_balance(btc.NewUint256(tx.TxIn[i].Input.Hash[:]), false); intx != nil { val := intx.TxOut[tx.TxIn[i].Input.Vout].Value totin += val fmt.Printf("%15s BTC\n", btc.UintToBtc(val)) } else { noins++ } if len(tx.TxIn[i].ScriptSig) > 0 { if !dump_sigscript(tx.TxIn[i].ScriptSig) { unsigned++ } } else { unsigned++ } } } fmt.Println("TX OUT cnt:", len(tx.TxOut)) for i := range tx.TxOut { totout += tx.TxOut[i].Value fmt.Printf("%4d) %20s BTC ", i, btc.UintToBtc(tx.TxOut[i].Value)) addr := addr_from_pkscr(tx.TxOut[i].Pk_script) if addr != nil { if addr.Version == ver_script() { fmt.Println("to scriptH", addr.String()) } else { fmt.Println("to address", addr.String()) } } else if len(tx.TxOut[i].Pk_script) == 40 && tx.TxOut[i].Pk_script[0] == 0x6a && tx.TxOut[i].Pk_script[1] == 0x26 && tx.TxOut[i].Pk_script[2] == 0x06 { sha := sha256.New() sha.Write(tx.TxOut[i].Pk_script[3:40]) fmt.Println("Stealth", hex.EncodeToString(sha.Sum(nil)[:4]), hex.EncodeToString(tx.TxOut[i].Pk_script[7:])) } else { if tx.TxOut[i].Value > 0 { fmt.Println("WARNING!!! These coins go to non-standard Pk_script:") } else { fmt.Println("NULL output to Pk_script:") } ss, er := btc.ScriptToText(tx.TxOut[i].Pk_script) if er == nil { for i := range ss { fmt.Println(" ", ss[i]) } } else { fmt.Println(hex.EncodeToString(tx.TxOut[i].Pk_script)) fmt.Println(er.Error()) } } } fmt.Println("Lock Time:", tx.Lock_time) fmt.Println("Output volume:", btc.UintToBtc(totout), "BTC") if noins == 0 { fmt.Println("Input volume :", btc.UintToBtc(totin), "BTC") fmt.Println("Transact. fee:", btc.UintToBtc(totin-totout), "BTC") } else { fmt.Println("WARNING: Unable to figure out what the fee is") } if !tx.IsCoinBase() { if unsigned > 0 { fmt.Println("WARNING:", unsigned, "out of", len(tx.TxIn), "inputs are not signed or signed only patially") } else { fmt.Println("All", len(tx.TxIn), "transaction inputs seem to be signed") } } }
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 }
// Must be called from the chain's thread func HandleNetTx(ntx *TxRcvd, retry bool) (accepted bool) { common.CountSafe("HandleNetTx") tx := ntx.tx var totinp, totout uint64 var frommem bool TxMutex.Lock() if !retry { if _, present := TransactionsPending[tx.Hash.BIdx()]; !present { // It had to be mined in the meantime, so just drop it now TxMutex.Unlock() common.CountSafe("TxNotPending") return } delete(TransactionsPending, ntx.tx.Hash.BIdx()) } else { // In case case of retry, it is on the rejected list, // ... so remove it now to free any tied WaitingForInputs deleteRejected(tx.Hash.BIdx()) } pos := make([]*btc.TxOut, len(tx.TxIn)) spent := make([]uint64, len(tx.TxIn)) // Check if all the inputs exist in the chain for i := range tx.TxIn { spent[i] = tx.TxIn[i].Input.UIdx() if _, ok := SpentOutputs[spent[i]]; ok { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_DOUBLE_SPEND) TxMutex.Unlock() common.CountSafe("TxRejectedDoubleSpnd") return } inptx := btc.NewUint256(tx.TxIn[i].Input.Hash[:]) if txinmem, ok := TransactionsToSend[inptx.BIdx()]; common.CFG.TXPool.AllowMemInputs && ok { if int(tx.TxIn[i].Input.Vout) >= len(txinmem.TxOut) { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_BAD_INPUT) TxMutex.Unlock() common.CountSafe("TxRejectedBadInput") return } pos[i] = txinmem.TxOut[tx.TxIn[i].Input.Vout] common.CountSafe("TxInputInMemory") frommem = true } else { pos[i], _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input) if pos[i] == nil { var newone bool if !common.CFG.TXPool.AllowMemInputs { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_NOT_MINED) TxMutex.Unlock() common.CountSafe("TxRejectedMemInput") return } // In this case, let's "save" it for later... missingid := btc.NewUint256(tx.TxIn[i].Input.Hash[:]) nrtx := RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_NO_TXOU) if nrtx != nil { nrtx.Wait4Input = &Wait4Input{missingTx: missingid, TxRcvd: ntx} // Add to waiting list: var rec *OneWaitingList if rec, _ = WaitingForInputs[nrtx.Wait4Input.missingTx.BIdx()]; rec == nil { rec = new(OneWaitingList) rec.TxID = nrtx.Wait4Input.missingTx rec.Ids = make(map[[btc.Uint256IdxLen]byte]time.Time) newone = true } rec.Ids[tx.Hash.BIdx()] = time.Now() WaitingForInputs[nrtx.Wait4Input.missingTx.BIdx()] = rec } TxMutex.Unlock() if newone { common.CountSafe("TxRejectedNoInpNew") } else { common.CountSafe("TxRejectedNoInpOld") } return } } totinp += pos[i].Value } // Check if total output value does not exceed total input minout := uint64(btc.MAX_MONEY) for i := range tx.TxOut { if tx.TxOut[i].Value < atomic.LoadUint64(&common.CFG.TXPool.MinVoutValue) { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_DUST) TxMutex.Unlock() common.CountSafe("TxRejectedDust") return } if tx.TxOut[i].Value < minout { minout = tx.TxOut[i].Value } totout += tx.TxOut[i].Value } if totout > totinp { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_OVERSPEND) TxMutex.Unlock() ntx.conn.DoS("TxOverspend") return } // Check for a proper fee fee := totinp - totout if fee < (uint64(len(ntx.raw)) * atomic.LoadUint64(&common.CFG.TXPool.FeePerByte)) { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_LOW_FEE) TxMutex.Unlock() common.CountSafe("TxRejectedLowFee") return } // Verify scripts for i := range tx.TxIn { if !script.VerifyTxScript(tx.TxIn[i].ScriptSig, pos[i].Pk_script, i, tx, script.VER_P2SH|script.VER_DERSIG) { RejectTx(ntx.tx.Hash, len(ntx.raw), TX_REJECTED_SCRIPT_FAIL) TxMutex.Unlock() ntx.conn.DoS("TxScriptFail") return } } rec := &OneTxToSend{Data: ntx.raw, Spent: spent, Volume: totinp, Fee: fee, Firstseen: time.Now(), Tx: tx, Minout: minout} TransactionsToSend[tx.Hash.BIdx()] = rec TransactionsToSendSize += uint64(len(rec.Data)) for i := range spent { SpentOutputs[spent[i]] = tx.Hash.BIdx() } wtg := WaitingForInputs[tx.Hash.BIdx()] if wtg != nil { defer RetryWaitingForInput(wtg) // Redo waiting txs when leaving this function } TxMutex.Unlock() common.CountSafe("TxAccepted") if frommem { // Gocoin does not route txs that need unconfirmed inputs rec.Blocked = TX_REJECTED_NOT_MINED common.CountSafe("TxRouteNotMined") } else if isRoutable(rec) { rec.Invsentcnt += NetRouteInv(1, tx.Hash, ntx.conn) common.CountSafe("TxRouteOK") } accepted = true return }
func (c *OneConnection) ProcessGetData(pl []byte) { var notfound []byte //println(c.PeerAddr.Ip(), "getdata") b := bytes.NewReader(pl) cnt, e := btc.ReadVLen(b) if e != nil { println("ProcessGetData:", e.Error(), c.PeerAddr.Ip()) return } for i := 0; i < int(cnt); i++ { var typ uint32 var h [36]byte n, _ := b.Read(h[:]) if n != 36 { println("ProcessGetData: pl too short", c.PeerAddr.Ip()) return } typ = binary.LittleEndian.Uint32(h[:4]) common.CountSafe(fmt.Sprint("GetdataType", typ)) if typ == 2 { uh := btc.NewUint256(h[4:]) bl, _, er := common.BlockChain.Blocks.BlockGet(uh) if er == nil { c.SendRawMsg("block", bl) } else { notfound = append(notfound, h[:]...) } } else if typ == 1 { // transaction uh := btc.NewUint256(h[4:]) TxMutex.Lock() if tx, ok := TransactionsToSend[uh.BIdx()]; ok && tx.Blocked == 0 { tx.SentCnt++ tx.Lastsent = time.Now() TxMutex.Unlock() c.SendRawMsg("tx", tx.Data) } else { TxMutex.Unlock() notfound = append(notfound, h[:]...) } } else { if common.DebugLevel > 0 { println("getdata for type", typ, "not supported yet") } if typ > 0 && typ <= 3 /*3 is a filtered block(we dont support it)*/ { notfound = append(notfound, h[:]...) } } } if len(notfound) > 0 { buf := new(bytes.Buffer) btc.WriteVlen(buf, uint64(len(notfound)/36)) buf.Write(notfound) c.SendRawMsg("notfound", buf.Bytes()) } }