예제 #1
0
파일: cblk.go 프로젝트: piotrnar/gocoin
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}
}
예제 #2
0
파일: cblk.go 프로젝트: piotrnar/gocoin
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")
	}
}