Beispiel #1
0
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
}
Beispiel #2
0
// LTC signing uses different seed string
func HashFromMessage(msg []byte, out []byte) {
	const MessageMagic = "Litecoin Signed Message:\n"
	b := new(bytes.Buffer)
	btc.WriteVlen(b, uint32(len(MessageMagic)))
	b.Write([]byte(MessageMagic))
	btc.WriteVlen(b, uint32(len(msg)))
	b.Write(msg)
	btc.ShaHash(b.Bytes(), out)
}
Beispiel #3
0
func (c *OneConnection) SendCmpctBlk(hash *btc.Uint256) {
	crec := GetchBlockForBIP152(hash)
	if crec == nil {
		fmt.Println(c.ConnID, "cmpctblock not sent for", hash.String())
		return
	}

	k0 := binary.LittleEndian.Uint64(crec.BIP152[8:16])
	k1 := binary.LittleEndian.Uint64(crec.BIP152[16:24])

	msg := new(bytes.Buffer)
	msg.Write(crec.Data[:80])
	msg.Write(crec.BIP152[:8])
	btc.WriteVlen(msg, uint64(len(crec.Block.Txs)-1)) // all except coinbase
	for i := 1; i < len(crec.Block.Txs); i++ {
		var lsb [8]byte
		var hasz *btc.Uint256
		if c.Node.SendCmpctVer == 2 {
			hasz = crec.Block.Txs[i].WTxID()
		} else {
			hasz = crec.Block.Txs[i].Hash
		}
		binary.LittleEndian.PutUint64(lsb[:], siphash.Hash(k0, k1, hasz.Hash[:]))
		msg.Write(lsb[:6])
	}
	msg.Write([]byte{1}) // one preffiled tx
	msg.Write([]byte{0}) // coinbase - index 0
	if c.Node.SendCmpctVer == 2 {
		msg.Write(crec.Block.Txs[0].Raw) // coinbase - index 0
	} else {
		crec.Block.Txs[0].WriteSerialized(msg) // coinbase - index 0
	}
	c.SendRawMsg("cmpctblock", msg.Bytes())
}
Beispiel #4
0
func main() {
	if len(os.Args) != 5 {
		fmt.Println("This tool needs to be executed with 4 arguments:")
		fmt.Println(" 1) Name of the unsigned transaction file")
		fmt.Println(" 2) Input index to add the key & signature to")
		fmt.Println(" 3) Hex dump of the canonical signature")
		fmt.Println(" 4) Hex dump of the public key")
		return
	}
	tx := raw_tx_from_file(os.Args[1])
	if tx == nil {
		return
	}

	in, er := strconv.ParseUint(os.Args[2], 10, 32)
	if er != nil {
		println("Input index:", er.Error())
		return
	}

	if int(in) >= len(tx.TxIn) {
		println("Input index too big:", int(in), "/", len(tx.TxIn))
		return
	}

	sig, er := hex.DecodeString(os.Args[3])
	if er != nil {
		println("Signature:", er.Error())
		return
	}

	pk, er := hex.DecodeString(os.Args[4])
	if er != nil {
		println("Public key:", er.Error())
		return
	}

	buf := new(bytes.Buffer)
	btc.WriteVlen(buf, uint64(len(sig)))
	buf.Write(sig)
	btc.WriteVlen(buf, uint64(len(pk)))
	buf.Write(pk)

	tx.TxIn[in].ScriptSig = buf.Bytes()

	write_tx_file(tx)
}
Beispiel #5
0
func (c *OneConnection) SendOwnAddr() {
	if ExternalAddrLen() > 0 {
		buf := new(bytes.Buffer)
		btc.WriteVlen(buf, uint64(1))
		binary.Write(buf, binary.LittleEndian, uint32(time.Now().Unix()))
		buf.Write(BestExternalAddr())
		c.SendRawMsg("addr", buf.Bytes())
	}
}
Beispiel #6
0
func (col *CmpctBlockCollector) Assemble() []byte {
	bdat := new(bytes.Buffer)
	bdat.Write(col.Header)
	btc.WriteVlen(bdat, uint64(len(col.Txs)))
	for _, txd := range col.Txs {
		bdat.Write(txd.([]byte))
	}
	return bdat.Bytes()
}
Beispiel #7
0
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())
}
Beispiel #8
0
func (c *OneConnection) SendAddr() {
	pers := peersdb.GetBestPeers(MaxAddrsPerMessage, nil)
	if len(pers) > 0 {
		buf := new(bytes.Buffer)
		btc.WriteVlen(buf, uint64(len(pers)))
		for i := range pers {
			binary.Write(buf, binary.LittleEndian, pers[i].Time)
			buf.Write(pers[i].NetAddr.Bytes())
		}
		c.SendRawMsg("addr", buf.Bytes())
	}
}
Beispiel #9
0
func (c *OneConnection) GetBlocks(pl []byte) {
	h2get, hashstop, e := parseLocatorsPayload(pl)

	if e != nil || len(h2get) < 1 || hashstop == nil {
		println("GetBlocks: error parsing payload from", c.PeerAddr.Ip())
		c.DoS("BadGetBlks")
		return
	}

	invs := make(map[[32]byte]bool, 500)
	for i := range h2get {
		common.BlockChain.BlockIndexAccess.Lock()
		if bl, ok := common.BlockChain.BlockIndex[h2get[i].BIdx()]; ok {
			// make sure that this block is in our main chain
			common.Last.Mutex.Lock()
			end := common.Last.Block
			common.Last.Mutex.Unlock()
			for ; end != nil && end.Height >= bl.Height; end = end.Parent {
				if end == bl {
					addInvBlockBranch(invs, bl, hashstop) // Yes - this is the main chain
					if common.DebugLevel > 0 {
						fmt.Println(c.PeerAddr.Ip(), "getblocks from", bl.Height,
							"stop at", hashstop.String(), "->", len(invs), "invs")
					}

					if len(invs) > 0 {
						common.BlockChain.BlockIndexAccess.Unlock()

						inv := new(bytes.Buffer)
						btc.WriteVlen(inv, uint32(len(invs)))
						for k, _ := range invs {
							binary.Write(inv, binary.LittleEndian, uint32(2))
							inv.Write(k[:])
						}
						c.SendRawMsg("inv", inv.Bytes())
						return
					}
				}
			}
		}
		common.BlockChain.BlockIndexAccess.Unlock()
	}

	common.CountSafe("GetblksMissed")
	return
}
Beispiel #10
0
// Handle getheaders protocol command
// https://en.bitcoin.it/wiki/Protocol_specification#getheaders
func (c *OneConnection) GetHeaders(pl []byte) {
	h2get, hashstop, e := parseLocatorsPayload(pl)
	if e != nil || hashstop == nil {
		println("GetHeaders: error parsing payload from", c.PeerAddr.Ip())
		c.DoS("BadGetHdrs")
		return
	}

	if common.DebugLevel > 1 {
		println("GetHeaders", len(h2get), hashstop.String())
	}

	var best_block, last_block *chain.BlockTreeNode

	common.BlockChain.BlockIndexAccess.Lock()
	if len(h2get) > 0 {
		for i := range h2get {
			if bl, ok := common.BlockChain.BlockIndex[h2get[i].BIdx()]; ok {
				if best_block == nil || bl.Height > best_block.Height {
					best_block = bl
				}
			}
		}
	} else {
		best_block = common.BlockChain.BlockIndex[hashstop.BIdx()]
	}
	last_block = common.BlockChain.BlockTreeEnd
	common.BlockChain.BlockIndexAccess.Unlock()

	var resp []byte
	var cnt uint32
	for cnt < 2000 {
		best_block = best_block.FindPathTo(last_block)
		if best_block == nil {
			break
		}
		resp = append(resp, append(best_block.BlockHeader[:], 0)...) // 81st byte is always zero
		cnt++
	}

	out := new(bytes.Buffer)
	btc.WriteVlen(out, cnt)
	out.Write(resp)
	c.SendRawMsg("headers", out.Bytes())
	return
}
Beispiel #11
0
func (c *OneConnection) SendInvs() (res bool) {
	b := new(bytes.Buffer)
	c.Mutex.Lock()
	if len(c.PendingInvs) > 0 {
		btc.WriteVlen(b, uint32(len(c.PendingInvs)))
		for i := range c.PendingInvs {
			b.Write((*c.PendingInvs[i])[:])
		}
		res = true
	}
	c.PendingInvs = nil
	c.Mutex.Unlock()
	if res {
		c.SendRawMsg("inv", b.Bytes())
	}
	return
}
Beispiel #12
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
}
Beispiel #13
0
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)
	}
}
Beispiel #14
0
func (c *OneConnection) sendGetHeaders() {
	MutexRcv.Lock()
	lb := LastCommitedHeader
	MutexRcv.Unlock()
	min_height := int(lb.Height) - chain.MovingCheckopintDepth
	if min_height < 0 {
		min_height = 0
	}

	blks := new(bytes.Buffer)
	var cnt uint64
	var step int
	step = 1
	for cnt < 50 /*it shoudl never get that far, but just in case...*/ {
		blks.Write(lb.BlockHash.Hash[:])
		cnt++
		//println(" geth", cnt, "height", lb.Height, lb.BlockHash.String())
		if int(lb.Height) <= min_height {
			break
		}
		for tmp := 0; tmp < step && lb != nil && int(lb.Height) > min_height; tmp++ {
			lb = lb.Parent
		}
		if lb == nil {
			break
		}
		if cnt >= 10 {
			step = step * 2
		}
	}
	var null_stop [32]byte
	blks.Write(null_stop[:])

	bhdr := new(bytes.Buffer)
	binary.Write(bhdr, binary.LittleEndian, common.Version)
	btc.WriteVlen(bhdr, cnt)

	c.SendRawMsg("getheaders", append(bhdr.Bytes(), blks.Bytes()...))
	c.X.LastHeadersHeightAsk = lb.Height
	c.X.GetHeadersInProgress = true
	c.X.GetHeadersTimeout = time.Now().Add(NO_DATA_TIMEOUT)
}
Beispiel #15
0
// Commit the given add/del transactions to UTXO and Wnwind DBs
func (db *UnspentDB) CommitBlockTxs(changes *BlockChanges, blhash []byte) (e error) {
	undo_fn := fmt.Sprint(db.dir, changes.Height)

	if changes.UndoData != nil || (changes.Height%db.UnwindBufLen) == 0 {
		bu := new(bytes.Buffer)
		bu.Write(blhash)
		if changes.UndoData != nil {
			for _, xx := range changes.UndoData {
				bin := xx.Serialize(true)
				btc.WriteVlen(bu, uint64(len(bin)))
				bu.Write(bin)
			}
		}
		ioutil.WriteFile(db.dir+"tmp", bu.Bytes(), 0666)
		os.Rename(db.dir+"tmp", undo_fn+".tmp")
	}

	db.nosync()
	db.commit(changes)
	if changes.LastKnownHeight <= changes.Height {
		db.Sync()
	}

	os.Rename(undo_fn+".tmp", undo_fn)

	if db.LastBlockHash == nil {
		db.LastBlockHash = make([]byte, 32)
	}
	copy(db.LastBlockHash, blhash)
	db.LastBlockHeight = changes.Height

	if changes.Height > db.UnwindBufLen {
		os.Remove(fmt.Sprint(db.dir, changes.Height-db.UnwindBufLen))
	}
	return
}
Beispiel #16
0
// Handle getheaders protocol command
// https://en.bitcoin.it/wiki/Protocol_specification#getheaders
func (c *OneConnection) GetHeaders(pl []byte) {
	h2get, hashstop, e := parseLocatorsPayload(pl)
	if e != nil || hashstop == nil {
		println("GetHeaders: error parsing payload from", c.PeerAddr.Ip())
		c.DoS("BadGetHdrs")
		return
	}

	if common.DebugLevel > 1 {
		println("GetHeaders", len(h2get), hashstop.String())
	}

	var best_block, last_block *chain.BlockTreeNode

	//common.Last.Mutex.Lock()
	MutexRcv.Lock()
	last_block = LastCommitedHeader
	MutexRcv.Unlock()
	//common.Last.Mutex.Unlock()

	common.BlockChain.BlockIndexAccess.Lock()

	//println("GetHeaders", len(h2get), hashstop.String())
	if len(h2get) > 0 {
		for i := range h2get {
			if bl, ok := common.BlockChain.BlockIndex[h2get[i].BIdx()]; ok {
				if best_block == nil || bl.Height > best_block.Height {
					//println(" ... bbl", i, bl.Height, bl.BlockHash.String())
					best_block = bl
				}
			}
		}
	} else {
		best_block = common.BlockChain.BlockIndex[hashstop.BIdx()]
	}

	if best_block == nil {
		common.CountSafe("GetHeadersBadBlock")
		best_block = common.BlockChain.BlockTreeRoot
	}

	//best_bl_ch := len(best_block.Childs)
	//last_block = common.BlockChain.BlockTreeEnd

	var resp []byte
	var cnt uint32

	defer func() {
		// If we get a hash of an old orphaned blocks, FindPathTo() will panic, so...
		if r := recover(); r != nil {
			common.CountSafe("GetHeadersOrphBlk")
			/*
				err, ok := r.(error)
				if !ok {
					err = fmt.Errorf("pkg: %v", r)
				}
				// This happens the you receive request for headers from an orphaned block
				fmt.Println("GetHeaders panic recovered:", err.Error())
				fmt.Println("Cnt:", cnt, "  len(h2get):", len(h2get))
				if best_block!=nil {
					fmt.Println("BestBlock:", best_block.Height, best_block.BlockHash.String(),
						len(best_block.Childs), best_bl_ch)
				}
				if last_block!=nil {
					fmt.Println("LastBlock:", last_block.Height, last_block.BlockHash.String(), len(last_block.Childs))
				}
			*/
		}

		common.BlockChain.BlockIndexAccess.Unlock()

		// send the response
		out := new(bytes.Buffer)
		btc.WriteVlen(out, uint64(cnt))
		out.Write(resp)
		c.SendRawMsg("headers", out.Bytes())
	}()

	for cnt < 2000 {
		if last_block.Height <= best_block.Height {
			break
		}
		best_block = best_block.FindPathTo(last_block)
		if best_block == nil {
			//println("FindPathTo failed", last_block.BlockHash.String(), cnt)
			//println("resp:", hex.EncodeToString(resp))
			break
		}
		resp = append(resp, append(best_block.BlockHeader[:], 0)...) // 81st byte is always zero
		cnt++
	}

	// Note: the deferred function will be called before exiting

	return
}
Beispiel #17
0
func (c *one_net_conn) getnextblock() {
	var cnt, lensofar int
	b := new(bytes.Buffer)
	vl := new(bytes.Buffer)

	BlocksMutex.Lock()

	if BlocksComplete > BlocksIndex {
		fmt.Println("dupa", BlocksComplete, BlocksIndex)
		BlocksIndex = BlocksComplete
	}

	blocks_from := BlocksIndex

	avg_len := avg_block_size()
	max_block_forward := uint32((MemForBlocks - BlocksCachedSize) / uint(avg_len))
	if max_block_forward < MIN_BLOCKS_AHEAD {
		max_block_forward = MIN_BLOCKS_AHEAD
	} else if max_block_forward > MAX_BLOCKS_AHEAD {
		max_block_forward = MAX_BLOCKS_AHEAD
	}

	if BlocksComplete+max_block_forward < blocks_from {
		COUNTER("BGAP")
		max_block_forward = blocks_from - BlocksComplete + 1
	}

	var prot int
	for secondloop := false; cnt < 10e3 && lensofar < GETBLOCKS_BYTES_ONCE; secondloop = true {
		if prot == 20e3 {
			println("stuck in getnextblock()", BlocksIndex, blocks_from, max_block_forward,
				BlocksComplete, LastBlockHeight, _DoBlocks, secondloop)
			break
		}
		prot++

		if secondloop && BlocksIndex == blocks_from {
			if BlocksComplete == LastBlockHeight {
				_DoBlocks = false
			} else {
				COUNTER("WRAP")
				time.Sleep(1e8)
			}
			break
		}

		BlocksIndex++
		if BlocksIndex > BlocksComplete+max_block_forward || BlocksIndex > LastBlockHeight {
			//fmt.Println("wrap", BlocksIndex, BlocksComplete)
			BlocksIndex = BlocksComplete
		}

		if _, done := BlocksCached[BlocksIndex]; done {
			//fmt.Println(" cached ->", BlocksIndex)
			continue
		}

		bh, ok := BlocksToGet[BlocksIndex]
		if !ok {
			//fmt.Println(" toget ->", BlocksIndex)
			continue
		}

		cbip := BlocksInProgress[bh]
		if cbip == nil {
			cbip = &one_bip{Height: BlocksIndex, Count: 1}
			cbip.Conns = make(map[uint32]bool, MaxNetworkConns)
		} else {
			if cbip.Conns[c.id] {
				//fmt.Println(" cbip.Conns ->", c.id)
				continue
			}
			cbip.Count++
		}
		cbip.Conns[c.id] = true
		c.inprogress++
		BlocksInProgress[bh] = cbip

		b.Write([]byte{2, 0, 0, 0})
		b.Write(bh[:])
		cnt++
		lensofar += avg_len
	}
	BlocksMutex.Unlock()

	btc.WriteVlen(vl, uint32(cnt))

	c.sendmsg("getdata", append(vl.Bytes(), b.Bytes()...))
	c.last_blk_rcvd = time.Now()
}
Beispiel #18
0
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])
		c.Mutex.Lock()
		c.InvStore(typ, h[4:36])
		c.Mutex.Unlock()

		common.CountSafe(fmt.Sprintf("GetdataType-%x", typ))
		if typ == MSG_BLOCK || typ == MSG_WITNESS_BLOCK {
			crec, _, er := common.BlockChain.Blocks.BlockGetExt(btc.NewUint256(h[4:]))
			//bl, _, er := common.BlockChain.Blocks.BlockGet(btc.NewUint256(h[4:]))
			if er == nil {
				bl := crec.Data
				if typ == MSG_BLOCK {
					// remove witness data from the block
					if crec.Block == nil {
						crec.Block, _ = btc.NewBlock(bl)
					}
					if crec.Block.OldData == nil {
						crec.Block.BuildTxList()
					}
					//println("block size", len(crec.Data), "->", len(bl))
					bl = crec.Block.OldData
				}
				c.SendRawMsg("block", bl)
			} else {
				notfound = append(notfound, h[:]...)
			}
		} else if typ == MSG_TX || typ == MSG_WITNESS_TX {
			// transaction
			TxMutex.Lock()
			if tx, ok := TransactionsToSend[btc.NewUint256(h[4:]).BIdx()]; ok && tx.Blocked == 0 {
				tx.SentCnt++
				tx.Lastsent = time.Now()
				TxMutex.Unlock()
				if tx.SegWit == nil || typ == MSG_WITNESS_TX {
					c.SendRawMsg("tx", tx.Data)
				} else {
					c.SendRawMsg("tx", tx.Serialize())
				}
			} else {
				TxMutex.Unlock()
				notfound = append(notfound, h[:]...)
			}
		} else if typ == MSG_CMPCT_BLOCK {
			c.SendCmpctBlk(btc.NewUint256(h[4:]))
		} 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())
	}
}
Beispiel #19
0
func (c *one_net_conn) getnextblock() {
	if len(BlockQueue)*avg_block_size() > MEM_CACHE {
		COUNTER("GDFU")
		time.Sleep(100 * time.Millisecond)
		return
	}

	var cnt int
	b := new(bytes.Buffer)
	vl := new(bytes.Buffer)

	avs := avg_block_size()
	blks_to_get := uint32(MEM_CACHE / avs)
	max_cnt_to_get := (MAX_GET_FROM_PEER / avs) + 1
	if max_cnt_to_get > MAX_BLOCKS_AT_ONCE {
		max_cnt_to_get = MAX_BLOCKS_AT_ONCE
	}

	BlocksMutex.Lock()

	FetchBlocksTo = BlocksComplete + blks_to_get
	if FetchBlocksTo > LastBlockHeight {
		FetchBlocksTo = LastBlockHeight
	}

	bl_stage := uint32(0)
	for curblk := BlocksComplete; cnt < max_cnt_to_get; curblk++ {
		if curblk > FetchBlocksTo {
			if bl_stage == MAX_SAME_BLOCKS_AT_ONCE {
				break
			}
			bl_stage++
			curblk = BlocksComplete
		}
		if _, done := BlocksCached[curblk]; done {
			continue
		}

		bh, ok := BlocksToGet[curblk]
		if !ok {
			continue
		}

		cbip := BlocksInProgress[bh]
		if cbip == nil {
			// if not in progress then we always take it
			cbip = &one_bip{Height: curblk}
			cbip.Conns = make(map[uint32]bool, MaxNetworkConns)
		} else if cbip.Count != bl_stage || cbip.Conns[c.id] {
			continue
		}
		if LastBlockAsked < curblk {
			LastBlockAsked = curblk
		}

		cbip.Count = bl_stage + 1
		cbip.Conns[c.id] = true
		c.inprogress++
		BlocksInProgress[bh] = cbip

		b.Write([]byte{2, 0, 0, 0})
		b.Write(bh[:])
		cnt++
	}
	BlocksMutex.Unlock()

	if cnt > 0 {
		btc.WriteVlen(vl, uint64(cnt))
		c.sendmsg("getdata", append(vl.Bytes(), b.Bytes()...))
		COUNTER("GDYE")
	} else {
		COUNTER("GDNO")
		time.Sleep(100 * time.Millisecond)
	}
	c.Lock()
	c.last_blk_rcvd = time.Now()
	c.Unlock()
}
Beispiel #20
0
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, uint32(len(notfound)/36))
		buf.Write(notfound)
		c.SendRawMsg("notfound", buf.Bytes())
	}
}
Beispiel #21
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")
	}
}
Beispiel #22
0
func (c *OneConnection) GetBlockData() (yes bool) {
	//MAX_GETDATA_FORWARD
	// Need to send getdata...?
	MutexRcv.Lock()
	defer MutexRcv.Unlock()

	if LowestIndexToBlocksToGet == 0 || len(BlocksToGet) == 0 {
		c.IncCnt("FetchNoBlocksToGet", 1)
		// wake up in one minute, just in case
		c.nextGetData = time.Now().Add(60 * time.Second)
		return
	}

	cbip := c.BlksInProgress()
	if cbip >= MAX_PEERS_BLOCKS_IN_PROGRESS {
		c.IncCnt("FetchMaxCountInProgress", 1)
		// wake up in a few seconds, maybe some blocks will complete by then
		c.nextGetData = time.Now().Add(5 * time.Second)
		return
	}

	avg_block_size := int(common.GetAverageBlockSize())
	block_data_in_progress := cbip * avg_block_size

	if block_data_in_progress+avg_block_size > MAX_GETDATA_FORWARD {
		c.IncCnt("FetchMaxBytesInProgress", 1)
		// wake up in a few seconds, maybe some blocks will complete by then
		c.nextGetData = time.Now().Add(5 * time.Second) // wait for some blocks to complete
		return
	}

	var cnt uint64
	var block_type uint32

	if (c.Node.Services & SERVICE_SEGWIT) != 0 {
		block_type = MSG_WITNESS_BLOCK
	} else {
		block_type = MSG_BLOCK
	}

	// We can issue getdata for this peer
	// Let's look for the lowest height block in BlocksToGet that isn't being downloaded yet

	common.Last.Mutex.Lock()
	max_height := common.Last.Block.Height + uint32(MAX_BLOCKS_FORWARD_SIZ/avg_block_size)
	if max_height > common.Last.Block.Height+MAX_BLOCKS_FORWARD_CNT {
		max_height = common.Last.Block.Height + MAX_BLOCKS_FORWARD_CNT
	}
	common.Last.Mutex.Unlock()
	if max_height > c.Node.Height {
		max_height = c.Node.Height
	}
	if max_height > LastCommitedHeader.Height {
		max_height = LastCommitedHeader.Height
	}

	if common.BlockChain.Consensus.Enforce_SEGWIT != 0 && (c.Node.Services&SERVICE_SEGWIT) == 0 { // no segwit node
		if max_height >= common.BlockChain.Consensus.Enforce_SEGWIT-1 {
			max_height = common.BlockChain.Consensus.Enforce_SEGWIT - 1
			if max_height <= common.Last.Block.Height {
				c.IncCnt("FetchNoWitness", 1)
				c.nextGetData = time.Now().Add(3600 * time.Second) // never do getdata
				return
			}
		}
	}

	invs := new(bytes.Buffer)
	var cnt_in_progress uint

	for {
		var lowest_found *OneBlockToGet

		// Get block to fetch:

		for bh := LowestIndexToBlocksToGet; bh <= max_height; bh++ {
			if idxlst, ok := IndexToBlocksToGet[bh]; ok {
				for _, idx := range idxlst {
					v := BlocksToGet[idx]
					if v.InProgress == cnt_in_progress && (lowest_found == nil || v.Block.Height < lowest_found.Block.Height) {
						c.Mutex.Lock()
						if _, ok := c.GetBlockInProgress[idx]; !ok {
							lowest_found = v
						}
						c.Mutex.Unlock()
					}
				}
			}
		}

		if lowest_found == nil {
			cnt_in_progress++
			if cnt_in_progress >= uint(common.CFG.Net.MaxBlockAtOnce) {
				break
			}
			continue
		}

		binary.Write(invs, binary.LittleEndian, block_type)
		invs.Write(lowest_found.BlockHash.Hash[:])
		lowest_found.InProgress++
		cnt++

		c.Mutex.Lock()
		c.GetBlockInProgress[lowest_found.BlockHash.BIdx()] =
			&oneBlockDl{hash: lowest_found.BlockHash, start: time.Now()}
		cbip = len(c.GetBlockInProgress)
		c.Mutex.Unlock()

		if cbip >= MAX_PEERS_BLOCKS_IN_PROGRESS {
			break // no more than 2000 blocks in progress / peer
		}
		block_data_in_progress += avg_block_size
		if block_data_in_progress > MAX_GETDATA_FORWARD {
			break
		}
	}

	if cnt == 0 {
		//println(c.ConnID, "fetch nothing", cbip, block_data_in_progress, max_height-common.Last.Block.Height, cnt_in_progress)
		c.IncCnt("FetchNothing", 1)
		// wake up in a few seconds, maybe it will be different next time
		c.nextGetData = time.Now().Add(5 * time.Second)
		return
	}

	bu := new(bytes.Buffer)
	btc.WriteVlen(bu, uint64(cnt))
	pl := append(bu.Bytes(), invs.Bytes()...)
	//println(c.ConnID, "fetching", cnt, "new blocks ->", cbip)
	c.SendRawMsg("getdata", pl)
	yes = true

	return
}