Пример #1
0
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
}
Пример #2
0
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)
}
Пример #3
0
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
}
Пример #4
0
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
}
Пример #5
0
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
}
Пример #6
0
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
}
Пример #7
0
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
}
Пример #8
0
// 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.")
}
Пример #9
0
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}
}
Пример #10
0
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")
	}
}