func (c *OneConnection) HandleVersion(pl []byte) error { if len(pl) >= 80 /*Up to, includiong, the nonce */ { c.Mutex.Lock() c.Node.Version = binary.LittleEndian.Uint32(pl[0:4]) if bytes.Equal(pl[72:80], nonce[:]) { c.Mutex.Unlock() return errors.New("Connecting to ourselves") } if c.Node.Version < MIN_PROTO_VERSION { c.Mutex.Unlock() return errors.New("Client version too low") } c.Node.Services = binary.LittleEndian.Uint64(pl[4:12]) c.Node.Timestamp = binary.LittleEndian.Uint64(pl[12:20]) c.Node.ReportedIp4 = binary.BigEndian.Uint32(pl[40:44]) if len(pl) >= 86 { le, of := btc.VLen(pl[80:]) of += 80 c.Node.Agent = string(pl[of : of+le]) of += le if len(pl) >= of+4 { c.Node.Height = binary.LittleEndian.Uint32(pl[of : of+4]) c.X.GetBlocksDataNow = true of += 4 if len(pl) > of && pl[of] == 0 { c.Node.DoNotRelayTxs = true } } } c.Mutex.Unlock() if sys.ValidIp4(pl[40:44]) { ExternalIpMutex.Lock() _, use_this_ip := ExternalIp4[c.Node.ReportedIp4] if !use_this_ip { // New IP use_this_ip = true for x, v := range IgnoreExternalIpFrom { if c.Node.Agent == v { use_this_ip = false common.CountSafe(fmt.Sprint("IgnoreExtIP", x)) break } } if use_this_ip { fmt.Printf("New external IP %d.%d.%d.%d from %s\n> ", pl[40], pl[41], pl[42], pl[43], c.Node.Agent) } } if use_this_ip { ExternalIp4[c.Node.ReportedIp4] = [2]uint{ExternalIp4[c.Node.ReportedIp4][0] + 1, uint(time.Now().Unix())} } ExternalIpMutex.Unlock() } } else { return errors.New("version message too short") } c.SendRawMsg("verack", []byte{}) return nil }
func (db *UnspentDB) UndoBlockTxs(bl *btc.Block, newhash []byte) { for _, tx := range bl.Txs { lst := make([]bool, len(tx.TxOut)) for i := range lst { lst[i] = true } db.del(tx.Hash.Hash[:], lst) } fn := fmt.Sprint(db.dir, db.LastBlockHeight) var addback []*QdbRec if _, er := os.Stat(fn); er != nil { fn += ".tmp" } dat, er := ioutil.ReadFile(fn) if er != nil { panic(er.Error()) } off := 32 // ship the block hash for off < len(dat) { le, n := btc.VLen(dat[off:]) off += n qr := FullQdbRec(dat[off : off+le]) off += le addback = append(addback, qr) } for _, tx := range addback { if db.ch.CB.NotifyTxAdd != nil { db.ch.CB.NotifyTxAdd(tx) } ind := qdb.KeyType(binary.LittleEndian.Uint64(tx.TxID[:8])) _db := db.DbN(int(tx.TxID[31]) % NumberOfUnspentSubDBs) v := _db.Get(ind) if v != nil { oldrec := NewQdbRec(ind, v) for a := range tx.Outs { if tx.Outs[a] == nil { tx.Outs[a] = oldrec.Outs[a] } } } _db.PutExt(ind, tx.Bytes(), 0) } os.Remove(fn) db.LastBlockHeight-- copy(db.LastBlockHash, newhash) }
func (c *OneConnection) HandleVersion(pl []byte) error { if len(pl) >= 80 /*Up to, includiong, the nonce */ { var new_ext_ip bool c.Mutex.Lock() c.Node.Version = binary.LittleEndian.Uint32(pl[0:4]) if bytes.Equal(pl[72:80], nonce[:]) { c.Mutex.Unlock() return errors.New("Connecting to ourselves") } if c.Node.Version < MIN_PROTO_VERSION { c.Mutex.Unlock() return errors.New("Client version too low") } c.Node.Services = binary.LittleEndian.Uint64(pl[4:12]) c.Node.Timestamp = binary.LittleEndian.Uint64(pl[12:20]) c.Mutex.Unlock() if sys.ValidIp4(pl[40:44]) { ExternalIpMutex.Lock() c.Node.ReportedIp4 = binary.BigEndian.Uint32(pl[40:44]) _, new_ext_ip = ExternalIp4[c.Node.ReportedIp4] new_ext_ip = !new_ext_ip ExternalIp4[c.Node.ReportedIp4] = [2]uint{ExternalIp4[c.Node.ReportedIp4][0] + 1, uint(time.Now().Unix())} ExternalIpMutex.Unlock() } if len(pl) >= 86 { c.Mutex.Lock() le, of := btc.VLen(pl[80:]) of += 80 c.Node.Agent = string(pl[of : of+le]) of += le if len(pl) >= of+4 { c.Node.Height = binary.LittleEndian.Uint32(pl[of : of+4]) of += 4 if len(pl) > of && pl[of] == 0 { c.Node.DoNotRelayTxs = true } } c.Mutex.Unlock() } if new_ext_ip { print("New external IP from ", c.Node.Agent, "\n> ") } } else { return errors.New("version message too short") } c.SendRawMsg("verack", []byte{}) return nil }
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 NewQdbRecStatic(key qdb.KeyType, dat []byte) *QdbRec { var off, n, i int var u64, idx uint64 binary.LittleEndian.PutUint64(sta_rec.TxID[:8], uint64(key)) copy(sta_rec.TxID[8:], dat[:24]) off = 24 u64, n = btc.VULe(dat[off:]) off += n sta_rec.InBlock = uint32(u64) u64, n = btc.VULe(dat[off:]) off += n sta_rec.Coinbase = (u64 & 1) != 0 u64 >>= 1 if len(rec_outs) < int(u64) { rec_outs = make([]*QdbTxOut, u64) rec_pool = make([]QdbTxOut, u64) } sta_rec.Outs = rec_outs[:u64] for i := range sta_rec.Outs { sta_rec.Outs[i] = nil } for off < len(dat) { idx, n = btc.VULe(dat[off:]) off += n sta_rec.Outs[idx] = &rec_pool[idx] u64, n = btc.VULe(dat[off:]) off += n sta_rec.Outs[idx].Value = uint64(u64) i, n = btc.VLen(dat[off:]) off += n sta_rec.Outs[idx].PKScr = dat[off : off+i] off += i } return &sta_rec }
func NewQdbRec(key qdb.KeyType, dat []byte) *QdbRec { var off, n, i int var u64, idx uint64 var rec QdbRec binary.LittleEndian.PutUint64(rec.TxID[:8], uint64(key)) copy(rec.TxID[8:], dat[:24]) off = 24 u64, n = btc.VULe(dat[off:]) off += n rec.InBlock = uint32(u64) u64, n = btc.VULe(dat[off:]) off += n rec.Coinbase = (u64 & 1) != 0 rec.Outs = make([]*QdbTxOut, u64>>1) for off < len(dat) { idx, n = btc.VULe(dat[off:]) off += n rec.Outs[idx] = new(QdbTxOut) u64, n = btc.VULe(dat[off:]) off += n rec.Outs[idx].Value = uint64(u64) i, n = btc.VLen(dat[off:]) off += n rec.Outs[idx].PKScr = dat[off : off+i] off += i } return &rec }
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.X.InvsRecieved++ cnt, of := btc.VLen(pl) if len(pl) != of+36*cnt { println("inv payload length mismatch", len(pl), of, cnt) } for i := 0; i < cnt; i++ { typ := binary.LittleEndian.Uint32(pl[of : of+4]) c.Mutex.Lock() c.InvStore(typ, pl[of+4:of+36]) ahr := c.X.AllHeadersReceived c.Mutex.Unlock() common.CountSafe(fmt.Sprint("InvGot-", typ)) if typ == MSG_BLOCK { bhash := btc.NewUint256(pl[of+4 : of+36]) if !ahr { common.CountSafe("InvBlockIgnored") } else { if !blockReceived(bhash) { MutexRcv.Lock() if b2g, ok := BlocksToGet[bhash.BIdx()]; ok { if c.Node.Height < b2g.Block.Height { c.Node.Height = b2g.Block.Height } common.CountSafe("InvBlockFresh") //println(c.PeerAddr.Ip(), c.Node.Version, "also knows the block", b2g.Block.Height, bhash.String()) c.X.GetBlocksDataNow = true } else { common.CountSafe("InvBlockNew") c.ReceiveHeadersNow() //println(c.PeerAddr.Ip(), c.Node.Version, "possibly new block", bhash.String()) } MutexRcv.Unlock() } else { common.CountSafe("InvBlockOld") } } } else if typ == MSG_TX { if common.CFG.TXPool.Enabled { MutexRcv.Lock() pending_blocks := len(BlocksToGet) + len(CachedBlocks) + len(NetBlocks) MutexRcv.Unlock() if pending_blocks > 10 { common.CountSafe("InvTxIgnored") // do not process TXs if the chain is not synchronized } else { c.TxInvNotify(pl[of+4 : of+36]) } } } of += 36 } return }
// TODO: at some point this function will become obsolete func BlockDBConvertIndexFile(dir string) { f, _ := os.Open(dir + "blockchain.idx") if f == nil { if fi, _ := os.Stat(dir + "blockchain_backup.idx"); fi != nil && fi.Size() > 0 { fmt.Println("If you don't plan to go back to a version prior 0.9.8, delete this file:\n", dir+"blockchain_backup.idx") } return // nothing to convert } fmt.Println("Converting btc.Block Database to the new format - please be patient!") id, _ := ioutil.ReadAll(f) f.Close() fmt.Println(len(id)/92, "blocks in the index") f, _ = os.Open(dir + "blockchain.dat") if f == nil { panic("blockchain.dat not found") } defer f.Close() var ( datlen, sofar, sf2, tmp int64 fl, le, he uint32 po uint64 buf [2 * 1024 * 1024]byte // pre-allocate two 2MB buffers blk []byte ) if fi, _ := f.Stat(); fi != nil { datlen = fi.Size() } else { panic("Stat() failed on blockchain.dat") } nidx := new(bytes.Buffer) for i := 0; i+92 <= len(id); i += 92 { fl = binary.LittleEndian.Uint32(id[i : i+4]) he = binary.LittleEndian.Uint32(id[i+68 : i+72]) po = binary.LittleEndian.Uint64(id[i+80 : i+88]) le = binary.LittleEndian.Uint32(id[i+88 : i+92]) f.Seek(int64(po), os.SEEK_SET) if _, er := f.Read(buf[:le]); er != nil { panic(er.Error()) } if (fl & BLOCK_COMPRSD) != 0 { if (fl & BLOCK_SNAPPED) != 0 { blk, _ = snappy.Decode(nil, buf[:le]) } else { gz, _ := gzip.NewReader(bytes.NewReader(buf[:le])) blk, _ = ioutil.ReadAll(gz) gz.Close() } } else { blk = buf[:le] } tx_n, _ := btc.VLen(blk[80:]) binary.Write(nidx, binary.LittleEndian, fl) nidx.Write(id[i+4 : i+36]) binary.Write(nidx, binary.LittleEndian, he) binary.Write(nidx, binary.LittleEndian, po) binary.Write(nidx, binary.LittleEndian, le) binary.Write(nidx, binary.LittleEndian, uint32(tx_n)) nidx.Write(blk[:80]) sf2 += int64(len(blk)) tmp = sofar + int64(le) if ((tmp ^ sofar) >> 20) != 0 { fmt.Printf("\r%d / %d MB processed so far (%d) ", tmp>>20, datlen>>20, sf2>>20) } sofar = tmp } fmt.Println() fmt.Println("Almost there - just save the new index file... don't you dare to stop now!") ioutil.WriteFile(dir+"blockchain.new", nidx.Bytes(), 0666) os.Rename(dir+"blockchain.idx", dir+"blockchain_backup.idx") fmt.Println("The old index backed up at blockchain_backup.dat") fmt.Println("Conversion done and will not be neded again, unless you downgrade.") }
func (c *OneConnection) ProcessBlockTxn(pl []byte) { if len(pl) < 33 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn error A", hex.EncodeToString(pl)) c.DoS("BlkTxnErrLen") return } hash := btc.NewUint256(pl[:32]) le, n := btc.VLen(pl[32:]) if le < 0 || n > 3 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn error B", hex.EncodeToString(pl)) c.DoS("BlkTxnErrCnt") return } MutexRcv.Lock() defer MutexRcv.Unlock() idx := hash.BIdx() c.Mutex.Lock() bip := c.GetBlockInProgress[idx] if bip == nil { c.Mutex.Unlock() println(c.ConnID, "Unexpected BlkTxn1 received from", c.PeerAddr.Ip()) common.CountSafe("BlkTxnUnexp1") c.DoS("BlkTxnErrBip") return } col := bip.col if col == nil { c.Mutex.Unlock() println("Unexpected BlockTxn2 not expected from this peer", c.PeerAddr.Ip()) common.CountSafe("UnxpectedBlockTxn") c.DoS("BlkTxnErrCol") return } delete(c.GetBlockInProgress, idx) c.Mutex.Unlock() // the blocks seems to be fine if rb, got := ReceivedBlocks[idx]; got { rb.Cnt++ common.CountSafe("BlkTxnSameRcvd") //fmt.Println(c.ConnID, "BlkTxn size", len(pl), "for", hash.String()[48:],"- already have") return } b2g := BlocksToGet[idx] if b2g == nil { panic("BlockTxn: Block missing from BlocksToGet") return } //b2g.InProgress-- //fmt.Println(c.ConnID, "BlockTxn size", len(pl), "-", le, "new txs for block #", b2g.Block.Height) offs := 32 + n for offs < len(pl) { n = btc.TxSize(pl[offs:]) if n == 0 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn corrupt TX") c.DoS("BlkTxnErrTx") return } raw_tx := pl[offs : offs+n] tx_hash := btc.NewSha2Hash(raw_tx) offs += n sid := siphash.Hash(col.K0, col.K1, tx_hash.Hash[:]) & 0xffffffffffff if idx, ok := col.Sid2idx[sid]; ok { col.Txs[idx] = raw_tx } else { common.CountSafe("ShortIDUnknown") println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn TX (short) ID unknown") return } } //println(c.ConnID, "Received the rest of compact block version", c.Node.SendCmpctVer) //sta := time.Now() b2g.Block.UpdateContent(col.Assemble()) //sto := time.Now() er := common.BlockChain.PostCheckBlock(b2g.Block) if er != nil { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "Corrupt CmpctBlkB") //c.DoS("BadCmpctBlockB") ioutil.WriteFile(b2g.Hash.String()+".bin", b2g.Block.Raw, 0700) return } DelB2G(idx) //fmt.Println(c.ConnID, "PostCheckBlock OK #", b2g.Block.Height, sto.Sub(sta), time.Now().Sub(sta)) c.Mutex.Lock() c.counters["NewTBlock"]++ c.blocksreceived = append(c.blocksreceived, time.Now()) c.Mutex.Unlock() orb := &OneReceivedBlock{TmStart: b2g.Started, TmPreproc: b2g.TmPreproc, TmDownload: c.LastMsgTime, TxMissing: col.Missing, FromConID: c.ConnID} ReceivedBlocks[idx] = orb NetBlocks <- &BlockRcvd{Conn: c, Block: b2g.Block, BlockTreeNode: b2g.BlockTreeNode, OneReceivedBlock: orb} }
func (c *OneConnection) ProcessCmpctBlock(pl []byte) { if len(pl) < 90 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error A", hex.EncodeToString(pl)) c.DoS("CmpctBlkErrA") return } MutexRcv.Lock() defer MutexRcv.Unlock() var tmp_hdr [81]byte copy(tmp_hdr[:80], pl[:80]) sta, b2g := c.ProcessNewHeader(tmp_hdr[:]) // ProcessNewHeader() needs byte(0) after the header, // but don't try to change it to ProcessNewHeader(append(pl[:80], 0)) as it'd overwrite pl[80] if b2g == nil { /*fmt.Println(c.ConnID, "Don't process CompactBlk", btc.NewSha2Hash(pl[:80]), hex.EncodeToString(pl[80:88]), "->", sta)*/ common.CountSafe("CmpctBlockHdrNo") if sta == PH_STATUS_ERROR { c.ReceiveHeadersNow() // block doesn't connect so ask for the headers c.Misbehave("BadCmpct", 50) // do it 20 times and you are banned } else if sta == PH_STATUS_FATAL { c.DoS("BadCmpct") } return } /*fmt.Println() fmt.Println(c.ConnID, "Received CmpctBlock enf:", common.BlockChain.Consensus.Enforce_SEGWIT, " serwice:", (c.Node.Services&SERVICE_SEGWIT)!=0, " height:", b2g.Block.Height, " ver:", c.Node.SendCmpctVer) */ if common.BlockChain.Consensus.Enforce_SEGWIT != 0 && c.Node.SendCmpctVer < 2 { if b2g.Block.Height >= common.BlockChain.Consensus.Enforce_SEGWIT { common.CountSafe("CmpctBlockIgnore") println("Ignore compact block", b2g.Block.Height, "from non-segwit node", c.ConnID) if (c.Node.Services & SERVICE_SEGWIT) != 0 { // it only makes sense to ask this node for block's data, if it supports segwit c.X.GetBlocksDataNow = true } return } } /* var sta_s = []string{"???", "NEW", "FRESH", "OLD", "ERROR", "FATAL"} fmt.Println(c.ConnID, "Compact Block len", len(pl), "for", btc.NewSha2Hash(pl[:80]).String()[48:], "#", b2g.Block.Height, sta_s[sta], " inp:", b2g.InProgress) */ // if we got here, we shall download this block if c.Node.Height < b2g.Block.Height { c.Node.Height = b2g.Block.Height } if b2g.InProgress >= uint(common.CFG.Net.MaxBlockAtOnce) { common.CountSafe("CmpctBlockMaxInProg") //fmt.Println(c.ConnID, " - too many in progress") return } var n, idx, shortidscnt, shortidx_idx, prefilledcnt int col := new(CmpctBlockCollector) col.Header = b2g.Block.Raw[:80] offs := 88 shortidscnt, n = btc.VLen(pl[offs:]) if shortidscnt < 0 || n > 3 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error B", hex.EncodeToString(pl)) c.DoS("CmpctBlkErrB") return } offs += n shortidx_idx = offs shortids := make(map[uint64]*OneTxToSend, shortidscnt) for i := 0; i < int(shortidscnt); i++ { if len(pl[offs:offs+6]) < 6 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error B2", hex.EncodeToString(pl)) c.DoS("CmpctBlkErrB2") return } shortids[ShortIDToU64(pl[offs:offs+6])] = nil offs += 6 } prefilledcnt, n = btc.VLen(pl[offs:]) if prefilledcnt < 0 || n > 3 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error C", hex.EncodeToString(pl)) c.DoS("CmpctBlkErrC") return } offs += n col.Txs = make([]interface{}, prefilledcnt+shortidscnt) exp := 0 for i := 0; i < int(prefilledcnt); i++ { idx, n = btc.VLen(pl[offs:]) if idx < 0 || n > 3 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error D", hex.EncodeToString(pl)) c.DoS("CmpctBlkErrD") return } idx += exp offs += n n = btc.TxSize(pl[offs:]) if n == 0 { println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error E", hex.EncodeToString(pl)) c.DoS("CmpctBlkErrE") return } col.Txs[idx] = pl[offs : offs+n] //fmt.Println(" prefilledtxn", i, idx, ":", hex.EncodeToString(pl[offs:offs+n])) //btc.NewSha2Hash(pl[offs:offs+n]).String()) offs += n exp = int(idx) + 1 } // calculate K0 and K1 params for siphash-4-2 sha := sha256.New() sha.Write(pl[:88]) kks := sha.Sum(nil) col.K0 = binary.LittleEndian.Uint64(kks[0:8]) col.K1 = binary.LittleEndian.Uint64(kks[8:16]) var cnt_found int TxMutex.Lock() for _, v := range TransactionsToSend { var hash2take *btc.Uint256 if c.Node.SendCmpctVer == 2 { hash2take = v.Tx.WTxID() } else { hash2take = v.Tx.Hash } sid := siphash.Hash(col.K0, col.K1, hash2take.Hash[:]) & 0xffffffffffff if ptr, ok := shortids[sid]; ok { if ptr != nil { common.CountSafe("ShortIDSame") println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "Same short ID - abort") return } shortids[sid] = v cnt_found++ } } var msg *bytes.Buffer missing := len(shortids) - cnt_found //fmt.Println(c.ConnID, c.Node.SendCmpctVer, "ShortIDs", cnt_found, "/", shortidscnt, " Prefilled", prefilledcnt, " Missing", missing, " MemPool:", len(TransactionsToSend)) col.Missing = missing if missing > 0 { msg = new(bytes.Buffer) msg.Write(b2g.Block.Hash.Hash[:]) btc.WriteVlen(msg, uint64(missing)) exp = 0 col.Sid2idx = make(map[uint64]int, missing) } for n = 0; n < len(col.Txs); n++ { switch col.Txs[n].(type) { case []byte: // prefilled transaction default: sid := ShortIDToU64(pl[shortidx_idx : shortidx_idx+6]) if t2s, ok := shortids[sid]; ok { if t2s != nil { col.Txs[n] = t2s.Data } else { col.Txs[n] = sid col.Sid2idx[sid] = n if missing > 0 { btc.WriteVlen(msg, uint64(n-exp)) exp = n + 1 } } } else { panic(fmt.Sprint("Tx idx ", n, " is missing - this should not happen!!!")) } shortidx_idx += 6 } } TxMutex.Unlock() if missing == 0 { //sta := time.Now() b2g.Block.UpdateContent(col.Assemble()) //sto := time.Now() er := common.BlockChain.PostCheckBlock(b2g.Block) if er != nil { println(c.ConnID, "Corrupt CmpctBlkA") ioutil.WriteFile(b2g.Hash.String()+".bin", b2g.Block.Raw, 0700) //c.DoS("BadCmpctBlockA") return } //fmt.Println(c.ConnID, "Instatnt PostCheckBlock OK #", b2g.Block.Height, sto.Sub(sta), time.Now().Sub(sta)) idx := b2g.Block.Hash.BIdx() c.Mutex.Lock() c.counters["NewCBlock"]++ c.blocksreceived = append(c.blocksreceived, time.Now()) c.Mutex.Unlock() orb := &OneReceivedBlock{TmStart: b2g.Started, TmPreproc: time.Now(), FromConID: c.ConnID} ReceivedBlocks[idx] = orb DelB2G(idx) //remove it from BlocksToGet if no more pending downloads NetBlocks <- &BlockRcvd{Conn: c, Block: b2g.Block, BlockTreeNode: b2g.BlockTreeNode, OneReceivedBlock: orb} } else { b2g.TmPreproc = time.Now() b2g.InProgress++ c.Mutex.Lock() c.GetBlockInProgress[b2g.Block.Hash.BIdx()] = &oneBlockDl{hash: b2g.Block.Hash, start: time.Now(), col: col} c.Mutex.Unlock() c.SendRawMsg("getblocktxn", msg.Bytes()) //fmt.Println(c.ConnID, "Send getblocktxn for", col.Missing, "/", shortidscnt, "missing txs. ", msg.Len(), "bytes") } }