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") } }