// GetBlock attempts to retrieve a particular block from peers, within timeout. func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) ( *blocks.Block, error) { u.DOut("Bitswap GetBlock: '%s'\n", k.Pretty()) begin := time.Now() tleft := timeout - time.Now().Sub(begin) provs_ch := bs.routing.FindProvidersAsync(k, 20, timeout) valchan := make(chan []byte) after := time.After(tleft) // TODO: when the data is received, shut down this for loop ASAP go func() { for p := range provs_ch { go func(pr *peer.Peer) { blk, err := bs.getBlock(k, pr, tleft) if err != nil { u.PErr("getBlock returned: %v\n", err) return } select { case valchan <- blk: default: } }(p) } }() select { case blkdata := <-valchan: close(valchan) return blocks.NewBlock(blkdata) case <-after: return nil, u.ErrTimeout } }
// peerWantsBlock will check if we have the block in question, // and then if we do, check the ledger for whether or not we should send it. func (bs *BitSwap) peerWantsBlock(p *peer.Peer, want string) { u.DOut("peer [%s] wants block [%s]\n", p.ID.Pretty(), u.Key(want).Pretty()) ledger := bs.getLedger(p) dsk := ds.NewKey(want) blk_i, err := bs.datastore.Get(dsk) if err != nil { if err == ds.ErrNotFound { ledger.Wants(u.Key(want)) } u.PErr("datastore get error: %v\n", err) return } blk, ok := blk_i.([]byte) if !ok { u.PErr("data conversion error.\n") return } if ledger.ShouldSend() { u.DOut("Sending block to peer.\n") bblk, err := blocks.NewBlock(blk) if err != nil { u.PErr("newBlock error: %v\n", err) return } bs.SendBlock(p, bblk) ledger.SentBytes(len(blk)) } else { u.DOut("Decided not to send block.") } }
func (bs *BitSwap) handleMessages() { for { select { case mes := <-bs.meschan.Incoming: pmes := new(PBMessage) err := proto.Unmarshal(mes.Data, pmes) if err != nil { u.PErr("%v\n", err) continue } if pmes.Blocks != nil { for _, blkData := range pmes.Blocks { blk, err := blocks.NewBlock(blkData) if err != nil { u.PErr("%v\n", err) continue } go bs.blockReceive(mes.Peer, blk) } } if pmes.Wantlist != nil { for _, want := range pmes.Wantlist { go bs.peerWantsBlock(mes.Peer, want) } } case <-bs.haltChan: return } } }
func TestBlocks(t *testing.T) { d := ds.NewMapDatastore() bs, err := NewBlockService(d, nil) if err != nil { t.Error("failed to construct block service", err) return } b, err := blocks.NewBlock([]byte("beep boop")) if err != nil { t.Error("failed to construct block", err) return } h, err := u.Hash([]byte("beep boop")) if err != nil { t.Error("failed to hash data", err) return } if !bytes.Equal(b.Multihash, h) { t.Error("Block Multihash and data multihash not equal") } if b.Key() != u.Key(h) { t.Error("Block key and data multihash key not equal") } k, err := bs.AddBlock(b) if err != nil { t.Error("failed to add block to BlockService", err) return } if k != b.Key() { t.Error("returned key is not equal to block key", err) } b2, err := bs.GetBlock(b.Key()) if err != nil { t.Error("failed to retrieve block from BlockService", err) return } if b.Key() != b2.Key() { t.Error("Block keys not equal.") } if !bytes.Equal(b.Data, b2.Data) { t.Error("Block data is not equal.") } }
// Put adds a node to the DAGService, storing the block in the BlockService func (n *DAGService) Put(nd *Node) (u.Key, error) { if n == nil { return "", fmt.Errorf("DAGService is nil") } d, err := nd.Encoded(false) if err != nil { return "", err } b, err := blocks.NewBlock(d) if err != nil { return "", err } return n.Blocks.AddBlock(b) }
// Add adds a node to the DAGService, storing the block in the BlockService func (n *DAGService) Add(nd *Node) (u.Key, error) { k, _ := nd.Key() u.DOut("DagService Add [%s]\n", k.Pretty()) if n == nil { return "", fmt.Errorf("DAGService is nil") } d, err := nd.Encoded(false) if err != nil { return "", err } b, err := blocks.NewBlock(d) if err != nil { return "", err } return n.Blocks.AddBlock(b) }
func TestAppendBlock(t *testing.T) { strs := make([]string, 2) strs = append(strs, "Celeritas") strs = append(strs, "Incendia") m := newMessage() for _, str := range strs { block, err := blocks.NewBlock([]byte(str)) if err != nil { t.Fail() } m.AppendBlock(block) } // assert strings are in proto message for _, blockbytes := range m.ToProto().GetBlocks() { s := bytes.NewBuffer(blockbytes).String() if !contains(strs, s) { t.Fail() } } }