code: func (tm *transactionManager) query(q *query, try int) {
  	transID := q.data["t"].(string)
  	trans := tm.newTransaction(transID, q)
  
  	tm.insert(trans)
  	defer tm.delete(trans.id)
  
  	success := false
  	for i := 0; i < try; i++ {
  		if err := send(tm.dht, q.node.addr, q.data); err != nil {
  			break
  		}
  
  		select {
  		case <-trans.response:
  			success = true
  			break
  		case <-time.After(time.Second * 15):
  		}
  	}
  
  	if !success && q.node.id != nil {
  		tm.dht.blackList.insert(q.node.addr.IP.String(), q.node.addr.Port)
  		tm.dht.routingTable.RemoveByAddr(q.node.addr.String())
  	}
  }
docs: // query sends the query-formed data to udp and wait for the response.
  // When timeout, it will retry `try - 1` times, which means it will query
  // `try` times totally.