github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/network/cblk.go (about)

     1  package network
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"encoding/binary"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/piotrnar/gocoin/client/common"
    15  	"github.com/piotrnar/gocoin/lib/btc"
    16  	"github.com/piotrnar/gocoin/lib/chain"
    17  	"github.com/piotrnar/gocoin/lib/others/siphash"
    18  )
    19  
    20  var (
    21  	CompactBlocksMutex sync.Mutex
    22  )
    23  
    24  type CmpctBlockCollector struct {
    25  	Header  []byte
    26  	Txs     []interface{} // either []byte of uint64
    27  	K0, K1  uint64
    28  	Sid2idx map[uint64]int
    29  	Missing int
    30  }
    31  
    32  func ShortIDToU64(d []byte) uint64 {
    33  	return uint64(d[0]) | (uint64(d[1]) << 8) | (uint64(d[2]) << 16) |
    34  		(uint64(d[3]) << 24) | (uint64(d[4]) << 32) | (uint64(d[5]) << 40)
    35  }
    36  
    37  func (col *CmpctBlockCollector) Assemble() []byte {
    38  	bdat := new(bytes.Buffer)
    39  	bdat.Write(col.Header)
    40  	btc.WriteVlen(bdat, uint64(len(col.Txs)))
    41  	for _, txd := range col.Txs {
    42  		bdat.Write(txd.([]byte))
    43  	}
    44  	return bdat.Bytes()
    45  }
    46  
    47  func GetchBlockForBIP152(hash *btc.Uint256) (crec *chain.BlckCachRec) {
    48  	CompactBlocksMutex.Lock()
    49  	defer CompactBlocksMutex.Unlock()
    50  
    51  	crec, _, _ = common.BlockChain.Blocks.BlockGetExt(hash)
    52  	if crec == nil {
    53  		//fmt.Println("BlockGetExt failed for", hash.String(), er.Error())
    54  		return
    55  	}
    56  
    57  	if crec.Block == nil {
    58  		crec.Block, _ = btc.NewBlock(crec.Data)
    59  		if crec.Block == nil {
    60  			fmt.Println("GetchBlockForBIP152: btc.NewBlock() failed for", hash.String())
    61  			return
    62  		}
    63  	}
    64  
    65  	if len(crec.Block.Txs) == 0 {
    66  		if crec.Block.BuildTxList() != nil {
    67  			fmt.Println("GetchBlockForBIP152: bl.BuildTxList() failed for", hash.String())
    68  			return
    69  		}
    70  	}
    71  
    72  	if len(crec.BIP152) != 24 {
    73  		crec.BIP152 = make([]byte, 24)
    74  		copy(crec.BIP152[:8], crec.Data[48:56]) // set the nonce to 8 middle-bytes of block's merkle_root
    75  		sha := sha256.New()
    76  		sha.Write(crec.Data[:80])
    77  		sha.Write(crec.BIP152[:8])
    78  		copy(crec.BIP152[8:24], sha.Sum(nil)[0:16])
    79  	}
    80  
    81  	return
    82  }
    83  
    84  func (c *OneConnection) SendCmpctBlk(hash *btc.Uint256) bool {
    85  	crec := GetchBlockForBIP152(hash)
    86  	if crec == nil {
    87  		//fmt.Println(c.ConnID, "cmpctblock not sent:", c.Node.Agent, hash.String())
    88  		return false
    89  	}
    90  
    91  	k0 := binary.LittleEndian.Uint64(crec.BIP152[8:16])
    92  	k1 := binary.LittleEndian.Uint64(crec.BIP152[16:24])
    93  
    94  	msg := new(bytes.Buffer)
    95  	msg.Write(crec.Data[:80])
    96  	msg.Write(crec.BIP152[:8])
    97  	btc.WriteVlen(msg, uint64(len(crec.Block.Txs)-1)) // all except coinbase
    98  	for i := 1; i < len(crec.Block.Txs); i++ {
    99  		var lsb [8]byte
   100  		var hasz *btc.Uint256
   101  		if c.Node.SendCmpctVer == 2 {
   102  			hasz = crec.Block.Txs[i].WTxID()
   103  		} else {
   104  			hasz = &crec.Block.Txs[i].Hash
   105  		}
   106  		binary.LittleEndian.PutUint64(lsb[:], siphash.Hash(k0, k1, hasz.Hash[:]))
   107  		msg.Write(lsb[:6])
   108  	}
   109  	msg.Write([]byte{1}) // one preffiled tx
   110  	msg.Write([]byte{0}) // coinbase - index 0
   111  	if c.Node.SendCmpctVer == 2 {
   112  		msg.Write(crec.Block.Txs[0].Raw) // coinbase - index 0
   113  	} else {
   114  		crec.Block.Txs[0].WriteSerialized(msg) // coinbase - index 0
   115  	}
   116  	c.SendRawMsg("cmpctblock", msg.Bytes())
   117  	return true
   118  }
   119  
   120  func (c *OneConnection) ProcessGetBlockTxn(pl []byte) {
   121  	if len(pl) < 34 {
   122  		println(c.ConnID, "GetBlockTxnShort")
   123  		c.DoS("GetBlockTxnShort")
   124  		return
   125  	}
   126  	hash := btc.NewUint256(pl[:32])
   127  	crec := GetchBlockForBIP152(hash)
   128  	if crec == nil {
   129  		fmt.Println(c.ConnID, "GetBlockTxn aborting for", hash.String())
   130  		return
   131  	}
   132  
   133  	req := bytes.NewReader(pl[32:])
   134  	indexes_length, _ := btc.ReadVLen(req)
   135  	if indexes_length == 0 {
   136  		println(c.ConnID, "GetBlockTxnEmpty")
   137  		c.DoS("GetBlockTxnEmpty")
   138  		return
   139  	}
   140  
   141  	var exp_idx uint64
   142  	msg := new(bytes.Buffer)
   143  
   144  	msg.Write(hash.Hash[:])
   145  	btc.WriteVlen(msg, indexes_length)
   146  
   147  	for {
   148  		idx, er := btc.ReadVLen(req)
   149  		if er != nil {
   150  			println(c.ConnID, "GetBlockTxnERR")
   151  			c.DoS("GetBlockTxnERR")
   152  			return
   153  		}
   154  		idx += exp_idx
   155  		if int(idx) >= len(crec.Block.Txs) {
   156  			println(c.ConnID, "GetBlockTxnIdx+")
   157  			c.DoS("GetBlockTxnIdx+")
   158  			return
   159  		}
   160  		if c.Node.SendCmpctVer == 2 {
   161  			msg.Write(crec.Block.Txs[idx].Raw) // coinbase - index 0
   162  		} else {
   163  			crec.Block.Txs[idx].WriteSerialized(msg) // coinbase - index 0
   164  		}
   165  		if indexes_length == 1 {
   166  			break
   167  		}
   168  		indexes_length--
   169  		exp_idx = idx + 1
   170  	}
   171  
   172  	c.SendRawMsg("blocktxn", msg.Bytes())
   173  }
   174  
   175  func delB2G_callback(hash *btc.Uint256) {
   176  	DelB2G(hash.BIdx())
   177  }
   178  
   179  func (c *OneConnection) ProcessCmpctBlock(pl []byte) {
   180  	if len(pl) < 90 {
   181  		println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error A", hex.EncodeToString(pl))
   182  		c.DoS("CmpctBlkErrA")
   183  		return
   184  	}
   185  
   186  	MutexRcv.Lock()
   187  	defer MutexRcv.Unlock()
   188  
   189  	sta, b2g := c.ProcessNewHeader(pl[:80])
   190  
   191  	if b2g == nil {
   192  		common.CountSafe("CmpctBlockHdrNo")
   193  		if sta == PH_STATUS_ERROR {
   194  			c.ReceiveHeadersNow()       // block doesn't connect so ask for the headers
   195  			c.Misbehave("BadCmpct", 50) // do it 20 times and you are banned
   196  		} else if sta == PH_STATUS_FATAL {
   197  			c.DoS("BadCmpct")
   198  		}
   199  		return
   200  	}
   201  	if sta == PH_STATUS_NEW {
   202  		b2g.SendInvs = true
   203  	}
   204  
   205  	if common.BlockChain.Consensus.Enforce_SEGWIT != 0 && c.Node.SendCmpctVer < 2 {
   206  		if b2g.Block.Height >= common.BlockChain.Consensus.Enforce_SEGWIT {
   207  			common.CountSafe("CmpctBlockIgnore")
   208  			println("Ignore compact block", b2g.Block.Height, "from non-segwit node", c.ConnID)
   209  			if (c.Node.Services & btc.SERVICE_SEGWIT) != 0 {
   210  				// it only makes sense to ask this node for block's data, if it supports segwit
   211  				c.MutexSetBool(&c.X.GetBlocksDataNow, true)
   212  			}
   213  			return
   214  		}
   215  	}
   216  
   217  	// if we got here, we shall download this block
   218  	if c.Node.Height < b2g.Block.Height {
   219  		c.Mutex.Lock()
   220  		c.Node.Height = b2g.Block.Height
   221  		c.Mutex.Unlock()
   222  	}
   223  
   224  	if b2g.InProgress >= uint(common.CFG.Net.MaxBlockAtOnce) {
   225  		common.CountSafe("CmpctBlockMaxInProg")
   226  		//fmt.Println(c.ConnID, " - too many in progress")
   227  		return
   228  	}
   229  
   230  	var n, idx, shortidscnt, shortidx_idx, prefilledcnt int
   231  
   232  	col := new(CmpctBlockCollector)
   233  	col.Header = b2g.Block.Raw[:80]
   234  
   235  	offs := 88
   236  	shortidscnt, n = btc.VLen(pl[offs:])
   237  	if n == 0 || shortidscnt < 0 || n > 3 {
   238  		println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error B", hex.EncodeToString(pl))
   239  		c.DoS("CmpctBlkErrB")
   240  		return
   241  	}
   242  	offs += n
   243  	shortidx_idx = offs
   244  	shortids := make(map[uint64][]byte, shortidscnt)
   245  	for i := 0; i < int(shortidscnt); i++ {
   246  		if len(pl[offs:offs+6]) < 6 {
   247  			println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error B2", hex.EncodeToString(pl))
   248  			c.DoS("CmpctBlkErrB2")
   249  			return
   250  		}
   251  		shortids[ShortIDToU64(pl[offs:offs+6])] = nil
   252  		offs += 6
   253  	}
   254  
   255  	prefilledcnt, n = btc.VLen(pl[offs:])
   256  	if n == 0 || prefilledcnt < 0 || n > 3 {
   257  		println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error C", hex.EncodeToString(pl))
   258  		c.DoS("CmpctBlkErrC")
   259  		return
   260  	}
   261  	offs += n
   262  
   263  	col.Txs = make([]interface{}, prefilledcnt+shortidscnt)
   264  
   265  	exp := 0
   266  	for i := 0; i < int(prefilledcnt); i++ {
   267  		idx, n = btc.VLen(pl[offs:])
   268  		if n == 0 || idx < 0 || n > 3 {
   269  			println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error D", hex.EncodeToString(pl))
   270  			c.DoS("CmpctBlkErrD")
   271  			return
   272  		}
   273  		idx += exp
   274  		offs += n
   275  		n = btc.TxSize(pl[offs:])
   276  		if n == 0 {
   277  			println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "cmpctblock error E", hex.EncodeToString(pl))
   278  			c.DoS("CmpctBlkErrE")
   279  			return
   280  		}
   281  		col.Txs[idx] = pl[offs : offs+n]
   282  		offs += n
   283  		exp = int(idx) + 1
   284  	}
   285  
   286  	// calculate K0 and K1 params for siphash-4-2
   287  	sha := sha256.New()
   288  	sha.Write(pl[:88])
   289  	kks := sha.Sum(nil)
   290  	col.K0 = binary.LittleEndian.Uint64(kks[0:8])
   291  	col.K1 = binary.LittleEndian.Uint64(kks[8:16])
   292  
   293  	var cnt_found int
   294  
   295  	TxMutex.Lock()
   296  
   297  	for _, v := range TransactionsToSend {
   298  		var hash2take *btc.Uint256
   299  		if c.Node.SendCmpctVer == 2 {
   300  			hash2take = v.Tx.WTxID()
   301  		} else {
   302  			hash2take = &v.Tx.Hash
   303  		}
   304  		sid := siphash.Hash(col.K0, col.K1, hash2take.Hash[:]) & 0xffffffffffff
   305  		if ptr, ok := shortids[sid]; ok {
   306  			if ptr != nil {
   307  				common.CountSafe("ShortIDSame")
   308  				println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "Same short ID - abort")
   309  				return
   310  			}
   311  			shortids[sid] = v.Raw
   312  			cnt_found++
   313  		}
   314  	}
   315  
   316  	for _, v := range TransactionsRejected {
   317  		if v.Tx == nil {
   318  			continue
   319  		}
   320  		var hash2take *btc.Uint256
   321  		if c.Node.SendCmpctVer == 2 {
   322  			hash2take = v.WTxID()
   323  		} else {
   324  			hash2take = &v.Hash
   325  		}
   326  		sid := siphash.Hash(col.K0, col.K1, hash2take.Hash[:]) & 0xffffffffffff
   327  		if ptr, ok := shortids[sid]; ok {
   328  			if ptr != nil {
   329  				common.CountSafe("ShortIDSame")
   330  				println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "Same short ID - abort")
   331  				return
   332  			}
   333  			shortids[sid] = v.Raw
   334  			cnt_found++
   335  			common.CountSafe(fmt.Sprint("CmpctBlkUseRej-", v.Reason))
   336  		}
   337  	}
   338  
   339  	var msg *bytes.Buffer
   340  
   341  	missing := len(shortids) - cnt_found
   342  	//fmt.Println(c.ConnID, c.Node.SendCmpctVer, "ShortIDs", cnt_found, "/", shortidscnt, "  Prefilled", prefilledcnt, "  Missing", missing, "  MemPool:", len(TransactionsToSend))
   343  	col.Missing = missing
   344  	if missing > 0 {
   345  		msg = new(bytes.Buffer)
   346  		msg.Write(b2g.Block.Hash.Hash[:])
   347  		btc.WriteVlen(msg, uint64(missing))
   348  		exp = 0
   349  		col.Sid2idx = make(map[uint64]int, missing)
   350  	}
   351  	for n = 0; n < len(col.Txs); n++ {
   352  		switch col.Txs[n].(type) {
   353  		case []byte: // prefilled transaction
   354  
   355  		default:
   356  			sid := ShortIDToU64(pl[shortidx_idx : shortidx_idx+6])
   357  			if ptr, ok := shortids[sid]; ok {
   358  				if ptr != nil {
   359  					col.Txs[n] = ptr
   360  				} else {
   361  					col.Txs[n] = sid
   362  					col.Sid2idx[sid] = n
   363  					if missing > 0 {
   364  						btc.WriteVlen(msg, uint64(n-exp))
   365  						exp = n + 1
   366  					}
   367  				}
   368  			} else {
   369  				panic(fmt.Sprint("Tx idx ", n, " is missing - this should not happen!!!"))
   370  			}
   371  			shortidx_idx += 6
   372  		}
   373  	}
   374  	TxMutex.Unlock()
   375  
   376  	if missing == 0 {
   377  		//sta := time.Now()
   378  		b2g.Block.UpdateContent(col.Assemble())
   379  		//sto := time.Now()
   380  		bidx := b2g.Block.Hash.BIdx()
   381  		er := common.BlockChain.PostCheckBlock(b2g.Block)
   382  		if er != nil {
   383  			println(c.ConnID, "Corrupt CmpctBlkA")
   384  			ioutil.WriteFile(b2g.Hash.String()+".bin", b2g.Block.Raw, 0700)
   385  
   386  			if b2g.Block.MerkleRootMatch() {
   387  				println("It was a wrongly mined one - clean it up")
   388  				DelB2G(bidx) //remove it from BlocksToGet
   389  				if b2g.BlockTreeNode == LastCommitedHeader {
   390  					LastCommitedHeader = LastCommitedHeader.Parent
   391  				}
   392  				common.BlockChain.DeleteBranch(b2g.BlockTreeNode, delB2G_callback)
   393  			}
   394  
   395  			//c.DoS("BadCmpctBlockA")
   396  			return
   397  		}
   398  		//fmt.Println(c.ConnID, "Instatnt PostCheckBlock OK #", b2g.Block.Height, sto.Sub(sta), time.Now().Sub(sta))
   399  		c.Mutex.Lock()
   400  		c.cntInc("NewCBlock")
   401  		c.blocksreceived = append(c.blocksreceived, time.Now())
   402  		c.Mutex.Unlock()
   403  		orb := &OneReceivedBlock{TmStart: b2g.Started, TmPreproc: time.Now(), FromConID: c.ConnID, DoInvs: b2g.SendInvs}
   404  		ReceivedBlocks[bidx] = orb
   405  		DelB2G(bidx) //remove it from BlocksToGet if no more pending downloads
   406  		if c.X.Authorized {
   407  			b2g.Block.Trusted.Set()
   408  		}
   409  		NetBlocks <- &BlockRcvd{Conn: c, Block: b2g.Block, BlockTreeNode: b2g.BlockTreeNode, OneReceivedBlock: orb}
   410  	} else {
   411  		if b2g.TmPreproc.IsZero() { // do not overwrite TmPreproc if already set
   412  			b2g.TmPreproc = time.Now()
   413  		}
   414  		b2g.InProgress++
   415  		c.Mutex.Lock()
   416  		c.GetBlockInProgress[b2g.Block.Hash.BIdx()] = &oneBlockDl{hash: b2g.Block.Hash, start: time.Now(), col: col, SentAtPingCnt: c.X.PingSentCnt}
   417  		c.Mutex.Unlock()
   418  		c.SendRawMsg("getblocktxn", msg.Bytes())
   419  		//fmt.Println(c.ConnID, "Send getblocktxn for", col.Missing, "/", shortidscnt, "missing txs.  ", msg.Len(), "bytes")
   420  	}
   421  }
   422  
   423  func (c *OneConnection) ProcessBlockTxn(pl []byte) {
   424  	if len(pl) < 33 {
   425  		println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn error A", hex.EncodeToString(pl))
   426  		c.DoS("BlkTxnErrLen")
   427  		return
   428  	}
   429  	hash := btc.NewUint256(pl[:32])
   430  	le, n := btc.VLen(pl[32:])
   431  	if n == 0 || le < 0 || n > 3 {
   432  		println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn error B", hex.EncodeToString(pl))
   433  		c.DoS("BlkTxnErrCnt")
   434  		return
   435  	}
   436  	MutexRcv.Lock()
   437  	defer MutexRcv.Unlock()
   438  
   439  	idx := hash.BIdx()
   440  
   441  	c.Mutex.Lock()
   442  	bip := c.GetBlockInProgress[idx]
   443  	if bip == nil {
   444  		//println(time.Now().Format("2006-01-02 15:04:05"), c.ConnID, "BlkTxnNoBIP:", c.PeerAddr.Ip(), c.Node.Agent, hash.String())
   445  		c.Mutex.Unlock()
   446  		common.CountSafe("UnxpBlockTxnA")
   447  		c.cntInc("BlkTxnNoBIP")
   448  		c.Misbehave("BlkTxnErrBip", 100)
   449  		return
   450  	}
   451  	col := bip.col
   452  	if col == nil {
   453  		c.Mutex.Unlock()
   454  		println("BlkTxnNoCOL:", c.PeerAddr.Ip(), c.Node.Agent, hash.String())
   455  		common.CountSafe("UnxpBlockTxnB")
   456  		c.cntInc("BlkTxnNoCOL")
   457  		c.Misbehave("BlkTxnNoCOL", 100)
   458  		return
   459  	}
   460  	delete(c.GetBlockInProgress, idx)
   461  	c.Mutex.Unlock()
   462  
   463  	// the blocks seems to be fine
   464  	if rb, got := ReceivedBlocks[idx]; got {
   465  		rb.Cnt++
   466  		common.CountSafe("BlkTxnSameRcvd")
   467  		//fmt.Println(c.ConnID, "BlkTxn size", len(pl), "for", hash.String()[48:],"- already have")
   468  		return
   469  	}
   470  
   471  	b2g := BlocksToGet[idx]
   472  	if b2g == nil {
   473  		// This may happen if we received this block already and it was invalid
   474  		println("BlockTxn: Block isn't in BlocksToGet anymore", hash.String())
   475  		common.CountSafe("BlkTxnNoB2G")
   476  		return
   477  	}
   478  	//b2g.InProgress--
   479  
   480  	//fmt.Println(c.ConnID, "BlockTxn size", len(pl), "-", le, "new txs for block #", b2g.Block.Height)
   481  
   482  	offs := 32 + n
   483  	for offs < len(pl) {
   484  		n = btc.TxSize(pl[offs:])
   485  		if n == 0 {
   486  			println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn corrupt TX")
   487  			c.DoS("BlkTxnErrTx")
   488  			return
   489  		}
   490  		raw_tx := pl[offs : offs+n]
   491  		var tx_hash btc.Uint256
   492  		tx_hash.Calc(raw_tx)
   493  		if common.GetBool(&common.CFG.TXPool.Debug) {
   494  			if f, _ := os.OpenFile("missing_txs.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660); f != nil {
   495  				_tx, _ := btc.NewTx(raw_tx)
   496  				_tx.SetHash(raw_tx)
   497  				fmt.Fprintf(f, "%s: Tx %s was missing in bock %d\n",
   498  					time.Now().Format("2006-01-02 15:04:05"), _tx.Hash.String(), b2g.Block.Height)
   499  				f.Close()
   500  			}
   501  		}
   502  		offs += n
   503  
   504  		sid := siphash.Hash(col.K0, col.K1, tx_hash.Hash[:]) & 0xffffffffffff
   505  		if idx, ok := col.Sid2idx[sid]; ok {
   506  			col.Txs[idx] = raw_tx
   507  		} else {
   508  			common.CountSafe("ShortIDUnknown")
   509  			println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn TX (short) ID unknown")
   510  			return
   511  		}
   512  	}
   513  
   514  	//println(c.ConnID, "Received the rest of compact block version", c.Node.SendCmpctVer)
   515  
   516  	//sta := time.Now()
   517  	b2g.Block.UpdateContent(col.Assemble())
   518  	//sto := time.Now()
   519  	er := common.BlockChain.PostCheckBlock(b2g.Block)
   520  	if er != nil {
   521  		println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "Corrupt CmpctBlkB")
   522  		//c.DoS("BadCmpctBlockB")
   523  		ioutil.WriteFile(b2g.Hash.String()+".bin", b2g.Block.Raw, 0700)
   524  
   525  		if b2g.Block.MerkleRootMatch() {
   526  			println("It was a wrongly mined one - clean it up")
   527  			DelB2G(idx) //remove it from BlocksToGet
   528  			if b2g.BlockTreeNode == LastCommitedHeader {
   529  				LastCommitedHeader = LastCommitedHeader.Parent
   530  			}
   531  			common.BlockChain.DeleteBranch(b2g.BlockTreeNode, delB2G_callback)
   532  		}
   533  
   534  		return
   535  	}
   536  	DelB2G(idx)
   537  	//fmt.Println(c.ConnID, "PostCheckBlock OK #", b2g.Block.Height, sto.Sub(sta), time.Now().Sub(sta))
   538  	c.Mutex.Lock()
   539  	c.cntInc("NewTBlock")
   540  	c.blocksreceived = append(c.blocksreceived, time.Now())
   541  	c.Mutex.Unlock()
   542  	orb := &OneReceivedBlock{TmStart: b2g.Started, TmPreproc: b2g.TmPreproc,
   543  		TmDownload: c.LastMsgTime, TxMissing: col.Missing, FromConID: c.ConnID, DoInvs: b2g.SendInvs}
   544  	ReceivedBlocks[idx] = orb
   545  	if c.X.Authorized {
   546  		b2g.Block.Trusted.Set()
   547  	}
   548  	NetBlocks <- &BlockRcvd{Conn: c, Block: b2g.Block, BlockTreeNode: b2g.BlockTreeNode, OneReceivedBlock: orb}
   549  }