func (c *OneConnection) SendInvs() (res bool) { b_txs := new(bytes.Buffer) b_blk := new(bytes.Buffer) var c_blk []*btc.Uint256 c.Mutex.Lock() if len(c.PendingInvs) > 0 { for i := range c.PendingInvs { var inv_sent_otherwise bool typ := binary.LittleEndian.Uint32((*c.PendingInvs[i])[:4]) c.InvStore(typ, (*c.PendingInvs[i])[4:36]) if typ == MSG_BLOCK { if c.Node.SendCmpctVer >= 1 && c.Node.HighBandwidth { c_blk = append(c_blk, btc.NewUint256((*c.PendingInvs[i])[4:])) inv_sent_otherwise = true } else if c.Node.SendHeaders { // convert block inv to block header common.BlockChain.BlockIndexAccess.Lock() bl := common.BlockChain.BlockIndex[btc.NewUint256((*c.PendingInvs[i])[4:]).BIdx()] if bl != nil { b_blk.Write(bl.BlockHeader[:]) b_blk.Write([]byte{0}) // 0 txs } common.BlockChain.BlockIndexAccess.Unlock() inv_sent_otherwise = true } } if !inv_sent_otherwise { b_txs.Write((*c.PendingInvs[i])[:]) } } res = true } c.PendingInvs = nil c.Mutex.Unlock() if len(c_blk) > 0 { for _, h := range c_blk { c.SendCmpctBlk(h) } } if b_blk.Len() > 0 { common.CountSafe("InvSentAsHeader") b := new(bytes.Buffer) btc.WriteVlen(b, uint64(b_blk.Len()/81)) c.SendRawMsg("headers", append(b.Bytes(), b_blk.Bytes()...)) //println("sent block's header(s)", b_blk.Len(), uint64(b_blk.Len()/81)) } if b_txs.Len() > 0 { b := new(bytes.Buffer) btc.WriteVlen(b, uint64(b_txs.Len()/36)) c.SendRawMsg("inv", append(b.Bytes(), b_txs.Bytes()...)) } return }
func (c *OneConnection) GetBlockData(h []byte) { var b [1 + 4 + 32]byte b[0] = 1 // One inv b[1] = 2 // Block copy(b[5:37], h[:32]) if common.DebugLevel > 1 { println("GetBlockData", btc.NewUint256(h).String()) } bh := btc.NewUint256(h) c.Mutex.Lock() c.GetBlockInProgress[bh.BIdx()] = &oneBlockDl{hash: bh, start: time.Now()} c.Mutex.Unlock() c.SendRawMsg("getdata", b[:]) }
func init() { rd, _ := hex.DecodeString("0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000") dummy_tx, _ := btc.NewTx(rd) dummy_tx.Size = uint32(len(rd)) ha := btc.Sha2Sum(rd) dummy_tx.Hash = btc.NewUint256(ha[:]) }
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 } if !tx.IsCoinBase() { for i := range tx.TxIn { if tx.TxIn[i].Input.IsNull() { 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 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>")) }
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 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, true) 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 }
// 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.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) 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: changes.LastKnownHeight = bl.LastKnownHeight 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 (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 } println("mark", btc.NewUint256(hash).String(), "as invalid") if cur.trusted { panic("if it is trusted - how can be invalid?") } db.setBlockFlag(cur, BLOCK_INVALID) delete(db.blockIndex, idx) db.mutex.Unlock() }
func print_record(sl []byte) { bh := btc.NewSha2Hash(sl[56:136]) fmt.Print("Block ", bh.String(), " Height ", binary.LittleEndian.Uint32(sl[36:40])) fmt.Println() fmt.Println(" ...", binary.LittleEndian.Uint32(sl[48:52]), " Bytes @ ", binary.LittleEndian.Uint64(sl[40:48]), " in dat file") hdr := sl[56:136] fmt.Println(" ->", btc.NewUint256(hdr[4:36]).String()) }
// 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[:]) } }
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", btc.NewUint256(hash).String()) 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() }
// 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 }
// 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.RebuildGenesisHeader() 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 k, 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 { println("ERROR: Block", v.Height, v.BlockHash.String(), "has no Parent") println("...", btc.NewUint256(v.BlockHeader[4:36]).String(), "- removing it from blocksDB") delete(ch.BlockIndex, k) continue } 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 (c *OneConnection) ProcessGetBlockTxn(pl []byte) { if len(pl) < 34 { println(c.ConnID, "GetBlockTxnShort") c.DoS("GetBlockTxnShort") return } hash := btc.NewUint256(pl[:32]) crec := GetchBlockForBIP152(hash) if crec == nil { fmt.Println(c.ConnID, "GetBlockTxn aborting for", hash.String()) return } req := bytes.NewReader(pl[32:]) indexes_length, _ := btc.ReadVLen(req) if indexes_length == 0 { println(c.ConnID, "GetBlockTxnEmpty") c.DoS("GetBlockTxnEmpty") return } var exp_idx uint64 msg := new(bytes.Buffer) msg.Write(hash.Hash[:]) btc.WriteVlen(msg, indexes_length) for { idx, er := btc.ReadVLen(req) if er != nil { println(c.ConnID, "GetBlockTxnERR") c.DoS("GetBlockTxnERR") return } idx += exp_idx if int(idx) >= len(crec.Block.Txs) { println(c.ConnID, "GetBlockTxnIdx+") c.DoS("GetBlockTxnIdx+") return } if c.Node.SendCmpctVer == 2 { msg.Write(crec.Block.Txs[idx].Raw) // coinbase - index 0 } else { crec.Block.Txs[idx].WriteSerialized(msg) // coinbase - index 0 } if indexes_length == 1 { break } indexes_length-- exp_idx = idx + 1 } c.SendRawMsg("blocktxn", msg.Bytes()) }
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() }
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 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 }
// 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.GetLastBlockHash() //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 { var ok bool ch.BlockTreeEnd, ok = ch.BlockIndex[btc.NewUint256(tlb).BIdx()] if !ok { panic("Last btc.Block Hash not found") } } }
// 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 if (c.Node.Services & SERVICE_SEGWIT) != 0 { binary.LittleEndian.PutUint32(b[1:5], MSG_WITNESS_TX) // SegWit Tx //println(c.ConnID, "getdata", btc.NewUint256(hash).String()) } else { b[1] = 1 // Tx } copy(b[5:37], hash) c.SendRawMsg("getdata", b[:]) } }
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 *unwindDb) stats() (s string) { var cnt int var totdatasize uint64 for i := range db.tdb { cnt += db.dbH(i).Count() db.dbH(i).Browse(func(k qdb.KeyType, v []byte) uint32 { totdatasize += uint64(len(v)) return 0 }) } s = fmt.Sprintf("UNWIND: len:%d last:%d defrags:%d/%d TotalData:%dMB\n", cnt, db.lastBlockHeight, db.defragCount, db.defragIndex, totdatasize>>20) s += "Last block: " + btc.NewUint256(db.lastBlockHash[:]).String() + "\n" return }
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++ }
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() }
// 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 }
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 }
// 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 *one_net_conn) ping_idle() { c.ping.Lock() if c.ping.inProgress { if time.Now().After(c.ping.timeSent.Add(PING_TIMEOUT)) { c.store_ping_result() c.ping.Unlock() //fmt.Println(c.peerip, "ping timeout", c.ping.seq) } else { c.ping.Unlock() time.Sleep(time.Millisecond) } } else if c.ping.now { //fmt.Println("ping", c.peerip, c.ping.seq) c.ping.inProgress = true c.ping.timeSent = time.Now() c.ping.now = false if false { rand.Read(c.ping.pattern[:]) c.ping.Unlock() c.sendmsg("ping", c.ping.pattern[:]) } else { b := new(bytes.Buffer) btc.WriteVlen(b, PING_FETCH_BLOCKS) BlocksMutex.Lock() for i := uint32(1); ; i++ { binary.Write(b, binary.LittleEndian, uint32(2)) btg := BlocksToGet[i] b.Write(btg[:]) if i == PING_FETCH_BLOCKS { c.ping.lastBlock = btc.NewUint256(btg[:]) break } } BlocksMutex.Unlock() c.ping.bytes = 0 c.ping.Unlock() c.sendmsg("getdata", b.Bytes()) //fmt.Println("ping sent", c.ping.lastBlock.String()) } } else { c.ping.Unlock() time.Sleep(10 * time.Millisecond) } }
// Make sure to call this function with ch.BlockIndexAccess locked func (ch *Chain) AcceptHeader(bl *btc.Block) (cur *BlockTreeNode) { 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 copy(cur.BlockHeader[:], bl.Raw[:80]) // Add this block to the block index prevblk.addChild(cur) ch.BlockIndex[cur.BlockHash.BIdx()] = cur return }