// handleABlockMsg is invoked when a peer receives a entry credit block message. func (p *peer) handleABlockMsg(msg *wire.MsgABlock, buf []byte) { binary, _ := msg.ABlk.MarshalBinary() commonHash := common.Sha(binary) hash, _ := wire.NewShaHash(commonHash.Bytes()) iv := wire.NewInvVect(wire.InvTypeFactomAdminBlock, hash) p.AddKnownInventory(iv) inMsgQueue <- msg }
// handleFactoidMsg func (p *peer) handleFactoidMsg(msg *wire.MsgFactoidTX, buf []byte) { binary, _ := msg.Transaction.MarshalBinary() commonHash := common.Sha(binary) hash, _ := wire.NewShaHash(commonHash.Bytes()) iv := wire.NewInvVect(wire.InvTypeTx, hash) p.AddKnownInventory(iv) inMsgQueue <- msg }
// handleECBlockMsg is invoked when a peer receives a entry credit block // message. func (p *peer) handleECBlockMsg(msg *wire.MsgECBlock, buf []byte) { headerHash, err := msg.ECBlock.HeaderHash() if err != nil { panic(err) } hash := wire.FactomHashToShaHash(headerHash) iv := wire.NewInvVect(wire.InvTypeFactomEntryCreditBlock, hash) p.AddKnownInventory(iv) inMsgQueue <- msg }
// pushGetEntryDataMsg takes the passed EBlock // and return all the corresponding EBEntries func (p *peer) pushGetEntryDataMsg(eblock *common.EBlock) { binary, _ := eblock.MarshalBinary() commonHash := common.Sha(binary) hash, _ := wire.NewShaHash(commonHash.Bytes()) iv := wire.NewInvVect(wire.InvTypeFactomEntry, hash) gdmsg := wire.NewMsgGetEntryData() gdmsg.AddInvVect(iv) if len(gdmsg.InvList) > 0 { p.QueueMessage(gdmsg, nil) } }
// handleEBlockMsg is invoked when a peer receives an entry block bitcoin message. func (p *peer) handleEBlockMsg(msg *wire.MsgEBlock, buf []byte) { binary, _ := msg.EBlk.MarshalBinary() commonHash := common.Sha(binary) hash, _ := wire.NewShaHash(commonHash.Bytes()) iv := wire.NewInvVect(wire.InvTypeFactomEntryBlock, hash) p.AddKnownInventory(iv) p.pushGetEntryDataMsg(msg.EBlk) inMsgQueue <- msg }
// handleDirBlockMsg is invoked when a peer receives a dir block message. func (p *peer) handleDirBlockMsg(msg *wire.MsgDirBlock, buf []byte) { binary, _ := msg.DBlk.MarshalBinary() commonHash := common.Sha(binary) hash, _ := wire.NewShaHash(commonHash.Bytes()) iv := wire.NewInvVect(wire.InvTypeFactomDirBlock, hash) p.AddKnownInventory(iv) p.pushGetNonDirDataMsg(msg.DBlk) inMsgQueue <- msg delete(p.requestedBlocks, *hash) delete(p.server.blockManager.requestedBlocks, *hash) }
// BenchmarkMruInventoryList performs basic benchmarks on the most recently // used inventory handling. func BenchmarkMruInventoryList(b *testing.B) { // Create a bunch of fake inventory vectors to use in benchmarking // the mru inventory code. b.StopTimer() numInvVects := 100000 invVects := make([]*wire.InvVect, 0, numInvVects) for i := 0; i < numInvVects; i++ { hashBytes := make([]byte, wire.HashSize) rand.Read(hashBytes) hash, _ := wire.NewShaHash(hashBytes) iv := wire.NewInvVect(wire.InvTypeBlock, hash) invVects = append(invVects, iv) } b.StartTimer() // Benchmark the add plus evicition code. limit := 20000 mruInvMap := NewMruInventoryMap(uint(limit)) for i := 0; i < b.N; i++ { mruInvMap.Add(invVects[i%numInvVects]) } }
// pushDirBlockMsg sends a dir block message for the provided block hash to the // connected peer. An error is returned if the block hash is not known. func (p *peer) pushDirBlockMsg(sha *wire.ShaHash, doneChan, waitChan chan struct{}) error { commonhash := new(common.Hash) commonhash.SetBytes(sha.Bytes()) blk, err := db.FetchDBlockByHash(commonhash) if err != nil { peerLog.Tracef("Unable to fetch requested dir block sha %v: %v", sha, err) if doneChan != nil { doneChan <- struct{}{} } return err } // Once we have fetched data wait for any previous operation to finish. if waitChan != nil { <-waitChan } // We only send the channel for this message if we aren't sending(sha) // an inv straight after. var dc chan struct{} sendInv := p.continueHash != nil && p.continueHash.IsEqual(sha) if !sendInv { dc = doneChan } msg := wire.NewMsgDirBlock() msg.DBlk = blk p.QueueMessage(msg, dc) //blk.MsgBlock(), dc) // When the peer requests the final block that was advertised in // response to a getblocks message which requested more blocks than // would fit into a single message, send it a new inventory message // to trigger it to issue another getblocks message for the next // batch of inventory. if p.continueHash != nil && p.continueHash.IsEqual(sha) { peerLog.Debug("continueHash: " + spew.Sdump(sha)) // Sleep for 5 seconds for the peer to catch up time.Sleep(5 * time.Second) // // Note: Rather than the latest block height, we should pass // the last block height of this batch of wire.MaxBlockLocatorsPerMsg // to signal this is the end of the batch and // to trigger a client to send a new GetDirBlocks message // //hash, _, err := db.FetchBlockHeightCache() //if err == nil { invMsg := wire.NewMsgDirInvSizeHint(1) iv := wire.NewInvVect(wire.InvTypeFactomDirBlock, sha) //hash) invMsg.AddInvVect(iv) p.QueueMessage(invMsg, doneChan) p.continueHash = nil //} else if doneChan != nil { if doneChan != nil { doneChan <- struct{}{} } } return nil }
// handleGetDirBlocksMsg is invoked when a peer receives a getdirblocks factom message. func (p *peer) handleGetDirBlocksMsg(msg *wire.MsgGetDirBlocks) { // Return all block hashes to the latest one (up to max per message) if // no stop hash was specified. // Attempt to find the ending index of the stop hash if specified. endIdx := database.AllShas //factom db if !msg.HashStop.IsEqual(&zeroHash) { height, err := db.FetchBlockHeightBySha(&msg.HashStop) if err == nil { endIdx = height + 1 } } // Find the most recent known block based on the block locator. // Use the block after the genesis block if no other blocks in the // provided locator are known. This does mean the client will start // over with the genesis block if unknown block locators are provided. // This mirrors the behavior in the reference implementation. startIdx := int64(1) for _, hash := range msg.BlockLocatorHashes { height, err := db.FetchBlockHeightBySha(hash) if err == nil { // Start with the next hash since we know this one. startIdx = height + 1 break } } peerLog.Info("startIdx=", startIdx, ", endIdx=", endIdx) // Don't attempt to fetch more than we can put into a single message. autoContinue := false if endIdx-startIdx > wire.MaxBlocksPerMsg { endIdx = startIdx + wire.MaxBlocksPerMsg autoContinue = true } // Generate inventory message. // // The FetchBlockBySha call is limited to a maximum number of hashes // per invocation. Since the maximum number of inventory per message // might be larger, call it multiple times with the appropriate indices // as needed. invMsg := wire.NewMsgDirInv() for start := startIdx; start < endIdx; { // Fetch the inventory from the block database. hashList, err := db.FetchHeightRange(start, endIdx) if err != nil { peerLog.Warnf("Dir Block lookup failed: %v", err) return } // The database did not return any further hashes. Break out of // the loop now. if len(hashList) == 0 { break } // Add dir block inventory to the message. for _, hash := range hashList { hashCopy := hash iv := wire.NewInvVect(wire.InvTypeFactomDirBlock, &hashCopy) invMsg.AddInvVect(iv) } start += int64(len(hashList)) } // Send the inventory message if there is anything to send. if len(invMsg.InvList) > 0 { invListLen := len(invMsg.InvList) if autoContinue && invListLen == wire.MaxBlocksPerMsg { // Intentionally use a copy of the final hash so there // is not a reference into the inventory slice which // would prevent the entire slice from being eligible // for GC as soon as it's sent. continueHash := invMsg.InvList[invListLen-1].Hash p.continueHash = &continueHash } p.QueueMessage(invMsg, nil) } }